VirtualBox

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

Last change on this file since 85124 was 85124, checked in by vboxsync, 4 years ago

*: Use DECL_HIDDEN_DATA for data, DECLHIDDEN will soon be exclusively for functions. bugref:9794

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