VirtualBox

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

Last change on this file since 65979 was 63514, checked in by vboxsync, 8 years ago

VBoxNetAdp: warnings (clang)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 KB
Line 
1/* $Id: VBoxNetAdp-darwin.cpp 63514 2016-08-15 23:18:48Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008-2016 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 = */(void *)(uintptr_t)&enodev, //eno_getc,
127 /*.d_putc = */(void *)(uintptr_t)&enodev, //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 /* Bring down the interface */
307 int rc = VINF_SUCCESS;
308 errno_t err;
309
310 AssertPtr(pThis->u.s.pIface);
311 Assert(pThis->u.s.hEvtDetached != NIL_RTSEMEVENT);
312
313 err = ifnet_set_flags(pThis->u.s.pIface, 0, IFF_UP | IFF_RUNNING);
314 if (err)
315 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to bring down interface "
316 "(err=%d).\n", err));
317 err = ifnet_detach(pThis->u.s.pIface);
318 if (err)
319 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to detach interface "
320 "(err=%d).\n", err));
321 Log2(("vboxNetAdpDarwinUnregisterDevice: Waiting for 'detached' event...\n"));
322 /* Wait until we get a signal from detach callback. */
323 rc = RTSemEventWait(pThis->u.s.hEvtDetached, VBOXNETADP_DETACH_TIMEOUT);
324 if (rc == VERR_TIMEOUT)
325 LogRel(("VBoxAdpDrv: Failed to detach interface %s%d\n.",
326 VBOXNETADP_NAME, pThis->iUnit));
327 err = ifnet_release(pThis->u.s.pIface);
328 if (err)
329 Log(("vboxNetAdpUnregisterDevice: Failed to release interface (err=%d).\n", err));
330
331 RTSemEventDestroy(pThis->u.s.hEvtDetached);
332 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
333}
334
335/**
336 * Device open. Called on open /dev/vboxnetctl
337 *
338 * @param Dev The device number.
339 * @param fFlags ???.
340 * @param fDevType ???.
341 * @param pProcess The process issuing this request.
342 */
343static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
344{
345 RT_NOREF(Dev, fFlags, fDevType, pProcess);
346#ifdef LOG_ENABLED
347 char szName[128];
348 szName[0] = '\0';
349 proc_name(proc_pid(pProcess), szName, sizeof(szName));
350 Log(("VBoxNetAdpDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
351#endif
352 return 0;
353}
354
355/**
356 * Close device.
357 */
358static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
359{
360 RT_NOREF(Dev, fFlags, fDevType, pProcess);
361 Log(("VBoxNetAdpDarwinClose: pid=%d\n", proc_pid(pProcess)));
362 return 0;
363}
364
365/**
366 * Device I/O Control entry point.
367 *
368 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
369 * @param Dev The device number (major+minor).
370 * @param iCmd The IOCtl command.
371 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
372 * @param fFlags Flag saying we're a character device (like we didn't know already).
373 * @param pProcess The process issuing this request.
374 */
375static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
376{
377 RT_NOREF(Dev, fFlags, pProcess);
378 uint32_t cbReq = IOCPARM_LEN(iCmd);
379 PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
380 int rc;
381
382 Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
383 switch (IOCBASECMD(iCmd))
384 {
385 case IOCBASECMD(VBOXNETADP_CTL_ADD):
386 {
387 if ( (IOC_DIRMASK & iCmd) != IOC_INOUT
388 || cbReq < sizeof(VBOXNETADPREQ))
389 return EINVAL;
390
391 PVBOXNETADP pNew;
392 Log(("VBoxNetAdpDarwinIOCtl: szName=%s\n", pReq->szName));
393 rc = vboxNetAdpCreate(&pNew,
394 pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))) ?
395 pReq->szName : NULL);
396 if (RT_FAILURE(rc))
397 return rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL;
398
399 Assert(strlen(pReq->szName) < sizeof(pReq->szName));
400 strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1);
401 pReq->szName[sizeof(pReq->szName) - 1] = '\0';
402 Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName));
403 break;
404 }
405
406 case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
407 {
408 if (!RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))))
409 return EINVAL;
410
411 PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName);
412 if (!pAdp)
413 return EINVAL;
414
415 rc = vboxNetAdpDestroy(pAdp);
416 if (RT_FAILURE(rc))
417 return EINVAL;
418 Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName));
419 break;
420 }
421
422 default:
423 printf("VBoxNetAdpDarwinIOCtl: unknown command %lx.\n", IOCBASECMD(iCmd));
424 return EINVAL;
425 }
426
427 return 0;
428}
429
430int vboxNetAdpOsInit(PVBOXNETADP pThis)
431{
432 /*
433 * Init the darwin specific members.
434 */
435 pThis->u.s.pIface = NULL;
436 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
437
438 return VINF_SUCCESS;
439}
440
441/**
442 * Start the kernel module.
443 */
444static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData)
445{
446 RT_NOREF(pKModInfo, pvData);
447 int rc;
448
449 /*
450 * Initialize IPRT and find our module tag id.
451 * (IPRT is shared with VBoxDrv, it creates the loggers.)
452 */
453 rc = RTR0Init(0);
454 if (RT_SUCCESS(rc))
455 {
456 Log(("VBoxNetAdpDarwinStart\n"));
457 rc = vboxNetAdpInit();
458 if (RT_SUCCESS(rc))
459 {
460 g_nCtlDev = cdevsw_add(-1, &g_ChDev);
461 if (g_nCtlDev < 0)
462 {
463 LogRel(("VBoxAdp: failed to register control device."));
464 rc = VERR_CANT_CREATE;
465 }
466 else
467 {
468 g_hCtlDev = devfs_make_node(makedev(g_nCtlDev, 0), DEVFS_CHAR,
469 UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
470 if (!g_hCtlDev)
471 {
472 LogRel(("VBoxAdp: failed to create FS node for control device."));
473 rc = VERR_CANT_CREATE;
474 }
475 }
476 }
477
478 if (RT_SUCCESS(rc))
479 {
480 LogRel(("VBoxAdpDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
481 return KMOD_RETURN_SUCCESS;
482 }
483
484 LogRel(("VBoxAdpDrv: failed to initialize device extension (rc=%d)\n", rc));
485 RTR0Term();
486 }
487 else
488 printf("VBoxAdpDrv: failed to initialize IPRT (rc=%d)\n", rc);
489
490 return KMOD_RETURN_FAILURE;
491}
492
493
494/**
495 * Stop the kernel module.
496 */
497static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData)
498{
499 RT_NOREF(pKModInfo, pvData);
500 Log(("VBoxNetAdpDarwinStop\n"));
501
502 vboxNetAdpShutdown();
503 /* Remove control device */
504 devfs_remove(g_hCtlDev);
505 cdevsw_remove(g_nCtlDev, &g_ChDev);
506
507 RTR0Term();
508
509 return KMOD_RETURN_SUCCESS;
510}
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