VirtualBox

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

Last change on this file since 30084 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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