VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp@ 62484

Last change on this file since 62484 was 58340, checked in by vboxsync, 9 years ago

HostDrivers: Doxygen fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.1 KB
Line 
1/* $Id: VBoxNetAdp-darwin.cpp 58340 2015-10-20 13:58:41Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
23#include "../../../Runtime/r0drv/darwin/the-darwin-kernel.h"
24
25#include <VBox/log.h>
26#include <VBox/err.h>
27#include <VBox/version.h>
28#include <iprt/assert.h>
29#include <iprt/initterm.h>
30#include <iprt/semaphore.h>
31#include <iprt/spinlock.h>
32#include <iprt/string.h>
33#include <iprt/uuid.h>
34#include <iprt/alloca.h>
35
36#include "../../darwin/VBoxNetSend.h"
37
38#include <sys/systm.h>
39RT_C_DECLS_BEGIN /* Buggy 10.4 headers, fixed in 10.5. */
40#include <sys/kpi_mbuf.h>
41RT_C_DECLS_END
42
43#include <net/ethernet.h>
44#include <net/if_ether.h>
45#include <net/if_types.h>
46#include <sys/socket.h>
47#include <net/if.h>
48#include <net/if_dl.h>
49#include <sys/errno.h>
50#include <sys/param.h>
51#include <sys/conf.h>
52#include <miscfs/devfs/devfs.h>
53RT_C_DECLS_BEGIN
54#include <net/bpf.h>
55RT_C_DECLS_END
56
57#define VBOXNETADP_OS_SPECFIC 1
58#include "../VBoxNetAdpInternal.h"
59
60
61/*********************************************************************************************************************************
62* Defined Constants And Macros *
63*********************************************************************************************************************************/
64/** The maximum number of SG segments.
65 * Used to prevent stack overflow and similar bad stuff. */
66#define VBOXNETADP_DARWIN_MAX_SEGS 32
67#define VBOXNETADP_DARWIN_MAX_FAMILIES 4
68#define VBOXNETADP_DARWIN_NAME "vboxnet"
69#define VBOXNETADP_DARWIN_MTU 1500
70#define VBOXNETADP_DARWIN_DETACH_TIMEOUT 500
71
72#define VBOXNETADP_FROM_IFACE(iface) ((PVBOXNETADP) ifnet_softc(iface))
73
74
75/*********************************************************************************************************************************
76* Internal Functions *
77*********************************************************************************************************************************/
78RT_C_DECLS_BEGIN
79static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData);
80static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData);
81RT_C_DECLS_END
82
83static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
84static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
85static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
86
87
88/*********************************************************************************************************************************
89* Global Variables *
90*********************************************************************************************************************************/
91/**
92 * Declare the module stuff.
93 */
94RT_C_DECLS_BEGIN
95extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
96extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
97
98KMOD_EXPLICIT_DECL(VBoxNetAdp, VBOX_VERSION_STRING, _start, _stop)
99DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxNetAdpDarwinStart;
100DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxNetAdpDarwinStop;
101DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
102RT_C_DECLS_END
103
104/**
105 * The (common) global data.
106 */
107static int g_nCtlDev = -1; /* Major dev number */
108static void *g_hCtlDev = 0; /* FS dev handle */
109
110/**
111 * The character device switch table for the driver.
112 */
113static struct cdevsw g_ChDev =
114{
115 /*.d_open = */VBoxNetAdpDarwinOpen,
116 /*.d_close = */VBoxNetAdpDarwinClose,
117 /*.d_read = */eno_rdwrt,
118 /*.d_write = */eno_rdwrt,
119 /*.d_ioctl = */VBoxNetAdpDarwinIOCtl,
120 /*.d_stop = */eno_stop,
121 /*.d_reset = */eno_reset,
122 /*.d_ttys = */NULL,
123 /*.d_select = */eno_select,
124 /*.d_mmap = */eno_mmap,
125 /*.d_strategy = */eno_strat,
126 /*.d_getc = */eno_getc,
127 /*.d_putc = */eno_putc,
128 /*.d_type = */0
129};
130
131
132
133static void vboxNetAdpDarwinComposeUUID(PVBOXNETADP pThis, PRTUUID pUuid)
134{
135 /* Generate UUID from name and MAC address. */
136 RTUuidClear(pUuid);
137 memcpy(pUuid->au8, "vboxnet", 7);
138 pUuid->Gen.u8ClockSeqHiAndReserved = (pUuid->Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
139 pUuid->Gen.u16TimeHiAndVersion = (pUuid->Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
140 pUuid->Gen.u8ClockSeqLow = pThis->iUnit;
141 vboxNetAdpComposeMACAddress(pThis, (PRTMAC)pUuid->Gen.au8Node);
142}
143
144static errno_t vboxNetAdpDarwinOutput(ifnet_t pIface, mbuf_t pMBuf)
145{
146 /*
147 * We are a dummy interface with all the real work done in
148 * VBoxNetFlt bridged networking filter. If anything makes it
149 * this far, it must be a broadcast or a packet for an unknown
150 * guest that intnet didn't know where to dispatch. In that case
151 * we must still do the BPF tap and stats.
152 */
153 bpf_tap_out(pIface, DLT_EN10MB, pMBuf, NULL, 0);
154 ifnet_stat_increment_out(pIface, 1, mbuf_len(pMBuf), 0);
155
156 mbuf_freem_list(pMBuf);
157 return 0;
158}
159
160static void vboxNetAdpDarwinDetach(ifnet_t pIface)
161{
162 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
163 Assert(pThis);
164 Log2(("vboxNetAdpDarwinDetach: Signaling detach to vboxNetAdpUnregisterDevice.\n"));
165 /* Let vboxNetAdpDarwinUnregisterDevice know that the interface has been detached. */
166 RTSemEventSignal(pThis->u.s.hEvtDetached);
167}
168
169static errno_t vboxNetAdpDarwinDemux(ifnet_t pIface, mbuf_t pMBuf,
170 char *pFrameHeader,
171 protocol_family_t *pProtocolFamily)
172{
173 /*
174 * Anything we get here comes from VBoxNetFlt bridged networking
175 * filter where it has already been accounted for and fed to bpf.
176 */
177 return ether_demux(pIface, pMBuf, pFrameHeader, pProtocolFamily);
178}
179
180
181static errno_t vboxNetAdpDarwinIfIOCtl(ifnet_t pIface, unsigned long uCmd, void *pvData)
182{
183 errno_t error = 0;
184
185 if (pvData == NULL)
186 {
187 /*
188 * Common pattern in the kernel code is to make changes in the
189 * net layer and then notify the device driver by calling its
190 * ioctl function with NULL parameter, e.g.:
191 *
192 * ifnet_set_flags(interface, ...);
193 * ifnet_ioctl(interface, 0, SIOCSIFFLAGS, NULL);
194 *
195 * These are no-ops for us, so tell the caller we succeeded
196 * because some callers do check that return value.
197 */
198 switch (uCmd)
199 {
200 case SIOCSIFFLAGS:
201 Log2(("VBoxNetAdp: %s%d: SIOCSIFFLAGS (null): flags = 0x%04hx\n",
202 ifnet_name(pIface), ifnet_unit(pIface),
203 (uint16_t)ifnet_flags(pIface)));
204 return 0;
205
206 case SIOCADDMULTI:
207 case SIOCDELMULTI:
208 Log2(("VBoxNetAdp: %s%d: SIOC%sMULTI (null)\n",
209 ifnet_name(pIface), ifnet_unit(pIface),
210 uCmd == SIOCADDMULTI ? "ADD" : "DEL"));
211 return 0;
212 }
213 }
214
215 Log2(("VBoxNetAdp: %s%d: %c%c '%c' %u len %u\n",
216 ifnet_name(pIface), ifnet_unit(pIface),
217 uCmd & IOC_OUT ? '<' : '-',
218 uCmd & IOC_IN ? '>' : '-',
219 IOCGROUP(uCmd),
220 uCmd & 0xff,
221 IOCPARM_LEN(uCmd)));
222
223 error = ether_ioctl(pIface, uCmd, pvData);
224 return error;
225}
226
227
228int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
229{
230 int rc;
231 struct ifnet_init_params Params;
232 RTUUID uuid;
233 struct sockaddr_dl mac;
234
235 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
236 rc = RTSemEventCreate(&pThis->u.s.hEvtDetached);
237 if (RT_FAILURE(rc))
238 {
239 printf("vboxNetAdpOsCreate: failed to create semaphore (rc=%d).\n", rc);
240 return rc;
241 }
242
243 mac.sdl_len = sizeof(mac);
244 mac.sdl_family = AF_LINK;
245 mac.sdl_alen = ETHER_ADDR_LEN;
246 mac.sdl_nlen = 0;
247 mac.sdl_slen = 0;
248 memcpy(LLADDR(&mac), pMACAddress->au8, mac.sdl_alen);
249
250 RTStrPrintf(pThis->szName, VBOXNETADP_MAX_NAME_LEN, "%s%d", VBOXNETADP_NAME, pThis->iUnit);
251 vboxNetAdpDarwinComposeUUID(pThis, &uuid);
252 Params.uniqueid = uuid.au8;
253 Params.uniqueid_len = sizeof(uuid);
254 Params.name = VBOXNETADP_NAME;
255 Params.unit = pThis->iUnit;
256 Params.family = IFNET_FAMILY_ETHERNET;
257 Params.type = IFT_ETHER;
258 Params.output = vboxNetAdpDarwinOutput;
259 Params.demux = vboxNetAdpDarwinDemux;
260 Params.add_proto = ether_add_proto;
261 Params.del_proto = ether_del_proto;
262 Params.check_multi = ether_check_multi;
263 Params.framer = ether_frameout;
264 Params.softc = pThis;
265 Params.ioctl = vboxNetAdpDarwinIfIOCtl;
266 Params.set_bpf_tap = NULL;
267 Params.detach = vboxNetAdpDarwinDetach;
268 Params.event = NULL;
269 Params.broadcast_addr = "\xFF\xFF\xFF\xFF\xFF\xFF";
270 Params.broadcast_len = ETHER_ADDR_LEN;
271
272 errno_t err = ifnet_allocate(&Params, &pThis->u.s.pIface);
273 if (!err)
274 {
275 err = ifnet_attach(pThis->u.s.pIface, &mac);
276 if (!err)
277 {
278 bpfattach(pThis->u.s.pIface, DLT_EN10MB, ETHER_HDR_LEN);
279
280 err = ifnet_set_flags(pThis->u.s.pIface, IFF_RUNNING | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST, 0xFFFF);
281 if (!err)
282 {
283 ifnet_set_mtu(pThis->u.s.pIface, VBOXNETADP_MTU);
284 VBoxNetSendDummy(pThis->u.s.pIface);
285 return VINF_SUCCESS;
286 }
287 else
288 Log(("vboxNetAdpDarwinRegisterDevice: Failed to set flags (err=%d).\n", err));
289 ifnet_detach(pThis->u.s.pIface);
290 }
291 else
292 Log(("vboxNetAdpDarwinRegisterDevice: Failed to attach to interface (err=%d).\n", err));
293 ifnet_release(pThis->u.s.pIface);
294 }
295 else
296 Log(("vboxNetAdpDarwinRegisterDevice: Failed to allocate interface (err=%d).\n", err));
297
298 RTSemEventDestroy(pThis->u.s.hEvtDetached);
299 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
300
301 return RTErrConvertFromErrno(err);
302}
303
304void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
305{
306 u_int32_t i;
307 /* Bring down the interface */
308 int rc = VINF_SUCCESS;
309 errno_t err;
310
311 AssertPtr(pThis->u.s.pIface);
312 Assert(pThis->u.s.hEvtDetached != NIL_RTSEMEVENT);
313
314 err = ifnet_set_flags(pThis->u.s.pIface, 0, IFF_UP | IFF_RUNNING);
315 if (err)
316 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to bring down interface "
317 "(err=%d).\n", err));
318 err = ifnet_detach(pThis->u.s.pIface);
319 if (err)
320 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to detach interface "
321 "(err=%d).\n", err));
322 Log2(("vboxNetAdpDarwinUnregisterDevice: Waiting for 'detached' event...\n"));
323 /* Wait until we get a signal from detach callback. */
324 rc = RTSemEventWait(pThis->u.s.hEvtDetached, VBOXNETADP_DETACH_TIMEOUT);
325 if (rc == VERR_TIMEOUT)
326 LogRel(("VBoxAdpDrv: Failed to detach interface %s%d\n.",
327 VBOXNETADP_NAME, pThis->iUnit));
328 err = ifnet_release(pThis->u.s.pIface);
329 if (err)
330 Log(("vboxNetAdpUnregisterDevice: Failed to release interface (err=%d).\n", err));
331
332 RTSemEventDestroy(pThis->u.s.hEvtDetached);
333 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
334}
335
336/**
337 * Device open. Called on open /dev/vboxnetctl
338 *
339 * @param Dev The device number.
340 * @param fFlags ???.
341 * @param fDevType ???.
342 * @param pProcess The process issuing this request.
343 */
344static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
345{
346 char szName[128];
347 szName[0] = '\0';
348 proc_name(proc_pid(pProcess), szName, sizeof(szName));
349 Log(("VBoxNetAdpDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
350 return 0;
351}
352
353/**
354 * Close device.
355 */
356static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
357{
358 Log(("VBoxNetAdpDarwinClose: pid=%d\n", proc_pid(pProcess)));
359 return 0;
360}
361
362/**
363 * Device I/O Control entry point.
364 *
365 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
366 * @param Dev The device number (major+minor).
367 * @param iCmd The IOCtl command.
368 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
369 * @param fFlags Flag saying we're a character device (like we didn't know already).
370 * @param pProcess The process issuing this request.
371 */
372static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
373{
374 uint32_t cbReq = IOCPARM_LEN(iCmd);
375 PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
376 int rc;
377
378 Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
379 switch (IOCBASECMD(iCmd))
380 {
381 case IOCBASECMD(VBOXNETADP_CTL_ADD):
382 {
383 if ( (IOC_DIRMASK & iCmd) != IOC_INOUT
384 || cbReq < sizeof(VBOXNETADPREQ))
385 return EINVAL;
386
387 PVBOXNETADP pNew;
388 Log(("VBoxNetAdpDarwinIOCtl: szName=%s\n", pReq->szName));
389 rc = vboxNetAdpCreate(&pNew,
390 pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))) ?
391 pReq->szName : NULL);
392 if (RT_FAILURE(rc))
393 return rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL;
394
395 Assert(strlen(pReq->szName) < sizeof(pReq->szName));
396 strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1);
397 pReq->szName[sizeof(pReq->szName) - 1] = '\0';
398 Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName));
399 break;
400 }
401
402 case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
403 {
404 if (!RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))))
405 return EINVAL;
406
407 PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName);
408 if (!pAdp)
409 return EINVAL;
410
411 rc = vboxNetAdpDestroy(pAdp);
412 if (RT_FAILURE(rc))
413 return EINVAL;
414 Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName));
415 break;
416 }
417
418 default:
419 printf("VBoxNetAdpDarwinIOCtl: unknown command %lx.\n", IOCBASECMD(iCmd));
420 return EINVAL;
421 }
422
423 return 0;
424}
425
426int vboxNetAdpOsInit(PVBOXNETADP pThis)
427{
428 /*
429 * Init the darwin specific members.
430 */
431 pThis->u.s.pIface = NULL;
432 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
433
434 return VINF_SUCCESS;
435}
436
437/**
438 * Start the kernel module.
439 */
440static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData)
441{
442 int rc;
443
444 /*
445 * Initialize IPRT and find our module tag id.
446 * (IPRT is shared with VBoxDrv, it creates the loggers.)
447 */
448 rc = RTR0Init(0);
449 if (RT_SUCCESS(rc))
450 {
451 Log(("VBoxNetAdpDarwinStart\n"));
452 rc = vboxNetAdpInit();
453 if (RT_SUCCESS(rc))
454 {
455 g_nCtlDev = cdevsw_add(-1, &g_ChDev);
456 if (g_nCtlDev < 0)
457 {
458 LogRel(("VBoxAdp: failed to register control device."));
459 rc = VERR_CANT_CREATE;
460 }
461 else
462 {
463 g_hCtlDev = devfs_make_node(makedev(g_nCtlDev, 0), DEVFS_CHAR,
464 UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
465 if (!g_hCtlDev)
466 {
467 LogRel(("VBoxAdp: failed to create FS node for control device."));
468 rc = VERR_CANT_CREATE;
469 }
470 }
471 }
472
473 if (RT_SUCCESS(rc))
474 {
475 LogRel(("VBoxAdpDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
476 return KMOD_RETURN_SUCCESS;
477 }
478
479 LogRel(("VBoxAdpDrv: failed to initialize device extension (rc=%d)\n", rc));
480 RTR0Term();
481 }
482 else
483 printf("VBoxAdpDrv: failed to initialize IPRT (rc=%d)\n", rc);
484
485 return KMOD_RETURN_FAILURE;
486}
487
488
489/**
490 * Stop the kernel module.
491 */
492static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData)
493{
494 Log(("VBoxNetAdpDarwinStop\n"));
495
496 vboxNetAdpShutdown();
497 /* Remove control device */
498 devfs_remove(g_hCtlDev);
499 cdevsw_remove(g_nCtlDev, &g_ChDev);
500
501 RTR0Term();
502
503 return KMOD_RETURN_SUCCESS;
504}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette