VirtualBox

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

Last change on this file since 53627 was 50410, checked in by vboxsync, 11 years ago

OS X host: stuck-in-dock: move include/VBox/VBoxNetSend.h to src/VBox/HostDrivers/darwin/VBoxNetSend.h.

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