VirtualBox

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

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

VBoxNetAdp/darwin: we still need to call bpf_tap_out() on outgoing
packets as filter driver relies on the interface driver to handle that
for packets we let out to the wire, like broadcasts.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: VBoxNetAdp-darwin.cpp 57911 2015-09-27 00:29:22Z 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
155 mbuf_freem_list(pMBuf);
156 return 0;
157}
158
159static void vboxNetAdpDarwinAttachFamily(PVBOXNETADP pThis, protocol_family_t Family)
160{
161 u_int32_t i;
162 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
163 if (pThis->u.s.aAttachedFamilies[i] == 0)
164 {
165 pThis->u.s.aAttachedFamilies[i] = Family;
166 break;
167 }
168}
169
170static void vboxNetAdpDarwinDetachFamily(PVBOXNETADP pThis, protocol_family_t Family)
171{
172 u_int32_t i;
173 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
174 if (pThis->u.s.aAttachedFamilies[i] == Family)
175 pThis->u.s.aAttachedFamilies[i] = 0;
176}
177
178static errno_t vboxNetAdpDarwinAddProto(ifnet_t pIface, protocol_family_t Family, const struct ifnet_demux_desc *pDemuxDesc, u_int32_t nDesc)
179{
180 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
181 Assert(pThis);
182 vboxNetAdpDarwinAttachFamily(pThis, Family);
183 LogFlow(("vboxNetAdpAddProto: Family=%d.\n", Family));
184 return ether_add_proto(pIface, Family, pDemuxDesc, nDesc);
185}
186
187static errno_t vboxNetAdpDarwinDelProto(ifnet_t pIface, protocol_family_t Family)
188{
189 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
190 Assert(pThis);
191 LogFlow(("vboxNetAdpDelProto: Family=%d.\n", Family));
192 vboxNetAdpDarwinDetachFamily(pThis, Family);
193 return ether_del_proto(pIface, Family);
194}
195
196static void vboxNetAdpDarwinDetach(ifnet_t pIface)
197{
198 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
199 Assert(pThis);
200 Log2(("vboxNetAdpDarwinDetach: Signaling detach to vboxNetAdpUnregisterDevice.\n"));
201 /* Let vboxNetAdpDarwinUnregisterDevice know that the interface has been detached. */
202 RTSemEventSignal(pThis->u.s.hEvtDetached);
203}
204
205static errno_t vboxNetAdpDarwinDemux(ifnet_t pIface, mbuf_t pMBuf,
206 char *pFrameHeader,
207 protocol_family_t *pProtocolFamily)
208{
209 /*
210 * Anything we get here comes from VBoxNetFlt bridged networking
211 * filter where it has already been accounted for and fed to bpf.
212 */
213 return ether_demux(pIface, pMBuf, pFrameHeader, pProtocolFamily);
214}
215
216int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
217{
218 int rc;
219 struct ifnet_init_params Params;
220 RTUUID uuid;
221 struct sockaddr_dl mac;
222
223 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
224 rc = RTSemEventCreate(&pThis->u.s.hEvtDetached);
225 if (RT_FAILURE(rc))
226 {
227 printf("vboxNetAdpOsCreate: failed to create semaphore (rc=%d).\n", rc);
228 return rc;
229 }
230
231 mac.sdl_len = sizeof(mac);
232 mac.sdl_family = AF_LINK;
233 mac.sdl_alen = ETHER_ADDR_LEN;
234 mac.sdl_nlen = 0;
235 mac.sdl_slen = 0;
236 memcpy(LLADDR(&mac), pMACAddress->au8, mac.sdl_alen);
237
238 RTStrPrintf(pThis->szName, VBOXNETADP_MAX_NAME_LEN, "%s%d", VBOXNETADP_NAME, pThis->iUnit);
239 vboxNetAdpDarwinComposeUUID(pThis, &uuid);
240 Params.uniqueid = uuid.au8;
241 Params.uniqueid_len = sizeof(uuid);
242 Params.name = VBOXNETADP_NAME;
243 Params.unit = pThis->iUnit;
244 Params.family = IFNET_FAMILY_ETHERNET;
245 Params.type = IFT_ETHER;
246 Params.output = vboxNetAdpDarwinOutput;
247 Params.demux = vboxNetAdpDarwinDemux;
248 Params.add_proto = vboxNetAdpDarwinAddProto;
249 Params.del_proto = vboxNetAdpDarwinDelProto;
250 Params.check_multi = ether_check_multi;
251 Params.framer = ether_frameout;
252 Params.softc = pThis;
253 Params.ioctl = (ifnet_ioctl_func)ether_ioctl;
254 Params.set_bpf_tap = NULL;
255 Params.detach = vboxNetAdpDarwinDetach;
256 Params.event = NULL;
257 Params.broadcast_addr = "\xFF\xFF\xFF\xFF\xFF\xFF";
258 Params.broadcast_len = ETHER_ADDR_LEN;
259
260 errno_t err = ifnet_allocate(&Params, &pThis->u.s.pIface);
261 if (!err)
262 {
263 err = ifnet_attach(pThis->u.s.pIface, &mac);
264 if (!err)
265 {
266 bpfattach(pThis->u.s.pIface, DLT_EN10MB, ETHER_HDR_LEN);
267
268 err = ifnet_set_flags(pThis->u.s.pIface, IFF_RUNNING | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST, 0xFFFF);
269 if (!err)
270 {
271 ifnet_set_mtu(pThis->u.s.pIface, VBOXNETADP_MTU);
272 VBoxNetSendDummy(pThis->u.s.pIface);
273 return VINF_SUCCESS;
274 }
275 else
276 Log(("vboxNetAdpDarwinRegisterDevice: Failed to set flags (err=%d).\n", err));
277 ifnet_detach(pThis->u.s.pIface);
278 }
279 else
280 Log(("vboxNetAdpDarwinRegisterDevice: Failed to attach to interface (err=%d).\n", err));
281 ifnet_release(pThis->u.s.pIface);
282 }
283 else
284 Log(("vboxNetAdpDarwinRegisterDevice: Failed to allocate interface (err=%d).\n", err));
285
286 RTSemEventDestroy(pThis->u.s.hEvtDetached);
287 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
288
289 return RTErrConvertFromErrno(err);
290}
291
292void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
293{
294 u_int32_t i;
295 /* Bring down the interface */
296 int rc = VINF_SUCCESS;
297 errno_t err;
298
299 AssertPtr(pThis->u.s.pIface);
300 Assert(pThis->u.s.hEvtDetached != NIL_RTSEMEVENT);
301
302 err = ifnet_set_flags(pThis->u.s.pIface, 0, IFF_UP | IFF_RUNNING);
303 if (err)
304 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to bring down interface "
305 "(err=%d).\n", err));
306 /* Detach all protocols. */
307 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
308 if (pThis->u.s.aAttachedFamilies[i])
309 ifnet_detach_protocol(pThis->u.s.pIface, pThis->u.s.aAttachedFamilies[i]);
310 err = ifnet_detach(pThis->u.s.pIface);
311 if (err)
312 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to detach interface "
313 "(err=%d).\n", err));
314 Log2(("vboxNetAdpDarwinUnregisterDevice: Waiting for 'detached' event...\n"));
315 /* Wait until we get a signal from detach callback. */
316 rc = RTSemEventWait(pThis->u.s.hEvtDetached, VBOXNETADP_DETACH_TIMEOUT);
317 if (rc == VERR_TIMEOUT)
318 LogRel(("VBoxAdpDrv: Failed to detach interface %s%d\n.",
319 VBOXNETADP_NAME, pThis->iUnit));
320 err = ifnet_release(pThis->u.s.pIface);
321 if (err)
322 Log(("vboxNetAdpUnregisterDevice: Failed to release interface (err=%d).\n", err));
323
324 RTSemEventDestroy(pThis->u.s.hEvtDetached);
325 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
326}
327
328/**
329 * Device open. Called on open /dev/vboxnetctl
330 *
331 * @param pInode Pointer to inode info structure.
332 * @param pFilp Associated file pointer.
333 */
334static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
335{
336 char szName[128];
337 szName[0] = '\0';
338 proc_name(proc_pid(pProcess), szName, sizeof(szName));
339 Log(("VBoxNetAdpDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
340 return 0;
341}
342
343/**
344 * Close device.
345 */
346static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
347{
348 Log(("VBoxNetAdpDarwinClose: pid=%d\n", proc_pid(pProcess)));
349 return 0;
350}
351
352/**
353 * Device I/O Control entry point.
354 *
355 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
356 * @param Dev The device number (major+minor).
357 * @param iCmd The IOCtl command.
358 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
359 * @param fFlags Flag saying we're a character device (like we didn't know already).
360 * @param pProcess The process issuing this request.
361 */
362static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
363{
364 uint32_t cbReq = IOCPARM_LEN(iCmd);
365 PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
366 int rc;
367
368 Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
369 switch (IOCBASECMD(iCmd))
370 {
371 case IOCBASECMD(VBOXNETADP_CTL_ADD):
372 {
373 if ( (IOC_DIRMASK & iCmd) != IOC_INOUT
374 || cbReq < sizeof(VBOXNETADPREQ))
375 return EINVAL;
376
377 PVBOXNETADP pNew;
378 Log(("VBoxNetAdpDarwinIOCtl: szName=%s\n", pReq->szName));
379 rc = vboxNetAdpCreate(&pNew,
380 pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))) ?
381 pReq->szName : NULL);
382 if (RT_FAILURE(rc))
383 return rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL;
384
385 Assert(strlen(pReq->szName) < sizeof(pReq->szName));
386 strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1);
387 pReq->szName[sizeof(pReq->szName) - 1] = '\0';
388 Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName));
389 break;
390 }
391
392 case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
393 {
394 if (!RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))))
395 return EINVAL;
396
397 PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName);
398 if (!pAdp)
399 return EINVAL;
400
401 rc = vboxNetAdpDestroy(pAdp);
402 if (RT_FAILURE(rc))
403 return EINVAL;
404 Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName));
405 break;
406 }
407
408 default:
409 printf("VBoxNetAdpDarwinIOCtl: unknown command %lx.\n", IOCBASECMD(iCmd));
410 return EINVAL;
411 }
412
413 return 0;
414}
415
416int vboxNetAdpOsInit(PVBOXNETADP pThis)
417{
418 /*
419 * Init the darwin specific members.
420 */
421 pThis->u.s.pIface = NULL;
422 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
423 memset(pThis->u.s.aAttachedFamilies, 0, sizeof(pThis->u.s.aAttachedFamilies));
424
425 return VINF_SUCCESS;
426}
427
428/**
429 * Start the kernel module.
430 */
431static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData)
432{
433 int rc;
434
435 /*
436 * Initialize IPRT and find our module tag id.
437 * (IPRT is shared with VBoxDrv, it creates the loggers.)
438 */
439 rc = RTR0Init(0);
440 if (RT_SUCCESS(rc))
441 {
442 Log(("VBoxNetAdpDarwinStart\n"));
443 rc = vboxNetAdpInit();
444 if (RT_SUCCESS(rc))
445 {
446 g_nCtlDev = cdevsw_add(-1, &g_ChDev);
447 if (g_nCtlDev < 0)
448 {
449 LogRel(("VBoxAdp: failed to register control device."));
450 rc = VERR_CANT_CREATE;
451 }
452 else
453 {
454 g_hCtlDev = devfs_make_node(makedev(g_nCtlDev, 0), DEVFS_CHAR,
455 UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
456 if (!g_hCtlDev)
457 {
458 LogRel(("VBoxAdp: failed to create FS node for control device."));
459 rc = VERR_CANT_CREATE;
460 }
461 }
462 }
463
464 if (RT_SUCCESS(rc))
465 {
466 LogRel(("VBoxAdpDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
467 return KMOD_RETURN_SUCCESS;
468 }
469
470 LogRel(("VBoxAdpDrv: failed to initialize device extension (rc=%d)\n", rc));
471 RTR0Term();
472 }
473 else
474 printf("VBoxAdpDrv: failed to initialize IPRT (rc=%d)\n", rc);
475
476 return KMOD_RETURN_FAILURE;
477}
478
479
480/**
481 * Stop the kernel module.
482 */
483static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData)
484{
485 Log(("VBoxNetAdpDarwinStop\n"));
486
487 vboxNetAdpShutdown();
488 /* Remove control device */
489 devfs_remove(g_hCtlDev);
490 cdevsw_remove(g_nCtlDev, &g_ChDev);
491
492 RTR0Term();
493
494 return KMOD_RETURN_SUCCESS;
495}
Note: See TracBrowser for help on using the repository browser.

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