VirtualBox

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

Last change on this file since 57252 was 57252, checked in by vboxsync, 10 years ago

SUPDrv,VBoxNetFlt,VBoxNetAdp: Include the-darwin-kernel.h to avoid duplicating workarounds and EFLAGS.AC macros.

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