VirtualBox

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

Last change on this file since 35942 was 35824, checked in by vboxsync, 14 years ago

netadp: coding style

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.5 KB
Line 
1/* $Id: VBoxNetAdp-darwin.cpp 35824 2011-02-02 13:32:03Z 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->iUnit;
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
195
196int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
197{
198 int rc;
199 struct ifnet_init_params Params;
200 RTUUID uuid;
201 struct sockaddr_dl mac;
202
203 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
204 rc = RTSemEventCreate(&pThis->u.s.hEvtDetached);
205 if (RT_FAILURE(rc))
206 {
207 printf("vboxNetAdpOsCreate: failed to create semaphore (rc=%d).\n", rc);
208 return rc;
209 }
210
211 mac.sdl_len = sizeof(mac);
212 mac.sdl_family = AF_LINK;
213 mac.sdl_alen = ETHER_ADDR_LEN;
214 mac.sdl_nlen = 0;
215 mac.sdl_slen = 0;
216 memcpy(LLADDR(&mac), pMACAddress->au8, mac.sdl_alen);
217
218 RTStrPrintf(pThis->szName, VBOXNETADP_MAX_NAME_LEN, "%s%d", VBOXNETADP_NAME, pThis->iUnit);
219 vboxNetAdpDarwinComposeUUID(pThis, &uuid);
220 Params.uniqueid = uuid.au8;
221 Params.uniqueid_len = sizeof(uuid);
222 Params.name = VBOXNETADP_NAME;
223 Params.unit = pThis->iUnit;
224 Params.family = IFNET_FAMILY_ETHERNET;
225 Params.type = IFT_ETHER;
226 Params.output = vboxNetAdpDarwinOutput;
227 Params.demux = ether_demux;
228 Params.add_proto = vboxNetAdpDarwinAddProto;
229 Params.del_proto = vboxNetAdpDarwinDelProto;
230 Params.check_multi = ether_check_multi;
231 Params.framer = ether_frameout;
232 Params.softc = pThis;
233 Params.ioctl = (ifnet_ioctl_func)ether_ioctl;
234 Params.set_bpf_tap = NULL;
235 Params.detach = vboxNetAdpDarwinDetach;
236 Params.event = NULL;
237 Params.broadcast_addr = "\xFF\xFF\xFF\xFF\xFF\xFF";
238 Params.broadcast_len = ETHER_ADDR_LEN;
239
240 errno_t err = ifnet_allocate(&Params, &pThis->u.s.pIface);
241 if (!err)
242 {
243 err = ifnet_attach(pThis->u.s.pIface, &mac);
244 if (!err)
245 {
246 err = ifnet_set_flags(pThis->u.s.pIface, IFF_RUNNING | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST, 0xFFFF);
247 if (!err)
248 {
249 ifnet_set_mtu(pThis->u.s.pIface, VBOXNETADP_MTU);
250 return VINF_SUCCESS;
251 }
252 else
253 Log(("vboxNetAdpDarwinRegisterDevice: Failed to set flags (err=%d).\n", err));
254 ifnet_detach(pThis->u.s.pIface);
255 }
256 else
257 Log(("vboxNetAdpDarwinRegisterDevice: Failed to attach to interface (err=%d).\n", err));
258 ifnet_release(pThis->u.s.pIface);
259 }
260 else
261 Log(("vboxNetAdpDarwinRegisterDevice: Failed to allocate interface (err=%d).\n", err));
262
263 RTSemEventDestroy(pThis->u.s.hEvtDetached);
264 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
265
266 return RTErrConvertFromErrno(err);
267}
268
269void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
270{
271 u_int32_t i;
272 /* Bring down the interface */
273 int rc = VINF_SUCCESS;
274 errno_t err;
275
276 AssertPtr(pThis->u.s.pIface);
277 Assert(pThis->u.s.hEvtDetached != NIL_RTSEMEVENT);
278
279 err = ifnet_set_flags(pThis->u.s.pIface, 0, IFF_UP | IFF_RUNNING);
280 if (err)
281 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to bring down interface "
282 "(err=%d).\n", err));
283 /* Detach all protocols. */
284 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
285 if (pThis->u.s.aAttachedFamilies[i])
286 ifnet_detach_protocol(pThis->u.s.pIface, pThis->u.s.aAttachedFamilies[i]);
287 err = ifnet_detach(pThis->u.s.pIface);
288 if (err)
289 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to detach interface "
290 "(err=%d).\n", err));
291 Log2(("vboxNetAdpDarwinUnregisterDevice: Waiting for 'detached' event...\n"));
292 /* Wait until we get a signal from detach callback. */
293 rc = RTSemEventWait(pThis->u.s.hEvtDetached, VBOXNETADP_DETACH_TIMEOUT);
294 if (rc == VERR_TIMEOUT)
295 LogRel(("VBoxAdpDrv: Failed to detach interface %s%d\n.",
296 VBOXNETADP_NAME, pThis->iUnit));
297 err = ifnet_release(pThis->u.s.pIface);
298 if (err)
299 Log(("vboxNetAdpUnregisterDevice: Failed to release interface (err=%d).\n", err));
300
301 RTSemEventDestroy(pThis->u.s.hEvtDetached);
302 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
303}
304
305/**
306 * Device open. Called on open /dev/vboxnetctl
307 *
308 * @param pInode Pointer to inode info structure.
309 * @param pFilp Associated file pointer.
310 */
311static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
312{
313 char szName[128];
314 szName[0] = '\0';
315 proc_name(proc_pid(pProcess), szName, sizeof(szName));
316 Log(("VBoxNetAdpDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
317 return 0;
318}
319
320/**
321 * Close device.
322 */
323static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
324{
325 Log(("VBoxNetAdpDarwinClose: pid=%d\n", proc_pid(pProcess)));
326 return 0;
327}
328
329/**
330 * Device I/O Control entry point.
331 *
332 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
333 * @param Dev The device number (major+minor).
334 * @param iCmd The IOCtl command.
335 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
336 * @param fFlags Flag saying we're a character device (like we didn't know already).
337 * @param pProcess The process issuing this request.
338 */
339static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
340{
341 uint32_t cbReq = IOCPARM_LEN(iCmd);
342 PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
343 int rc;
344
345 Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
346 switch (IOCBASECMD(iCmd))
347 {
348 case IOCBASECMD(VBOXNETADP_CTL_ADD):
349 {
350 if ( (IOC_DIRMASK & iCmd) != IOC_INOUT
351 || cbReq < sizeof(VBOXNETADPREQ))
352 return EINVAL;
353
354 PVBOXNETADP pNew;
355 Log(("VBoxNetAdpDarwinIOCtl: szName=%s\n", pReq->szName));
356 rc = vboxNetAdpCreate(&pNew,
357 pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))) ?
358 pReq->szName : NULL);
359 if (RT_FAILURE(rc))
360 return EINVAL;
361
362 Assert(strlen(pReq->szName) < sizeof(pReq->szName));
363 strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1);
364 pReq->szName[sizeof(pReq->szName) - 1] = '\0';
365 Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName));
366 break;
367 }
368
369 case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
370 {
371 if (!RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))))
372 return EINVAL;
373
374 PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName);
375 if (!pAdp)
376 return EINVAL;
377
378 rc = vboxNetAdpDestroy(pAdp);
379 if (RT_FAILURE(rc))
380 return EINVAL;
381 Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName));
382 break;
383 }
384
385 default:
386 printf("VBoxNetAdpDarwinIOCtl: unknown command %lx.\n", IOCBASECMD(iCmd));
387 return EINVAL;
388 }
389
390 return 0;
391}
392
393int vboxNetAdpOsInit(PVBOXNETADP pThis)
394{
395 /*
396 * Init the darwin specific members.
397 */
398 pThis->u.s.pIface = NULL;
399 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
400 memset(pThis->u.s.aAttachedFamilies, 0, sizeof(pThis->u.s.aAttachedFamilies));
401
402 return VINF_SUCCESS;
403}
404
405/**
406 * Start the kernel module.
407 */
408static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData)
409{
410 int rc;
411
412 /*
413 * Initialize IPRT and find our module tag id.
414 * (IPRT is shared with VBoxDrv, it creates the loggers.)
415 */
416 rc = RTR0Init(0);
417 if (RT_SUCCESS(rc))
418 {
419 Log(("VBoxNetAdpDarwinStart\n"));
420 rc = vboxNetAdpInit();
421 if (RT_SUCCESS(rc))
422 {
423 g_nCtlDev = cdevsw_add(-1, &g_ChDev);
424 if (g_nCtlDev < 0)
425 {
426 LogRel(("VBoxAdp: failed to register control device."));
427 rc = VERR_CANT_CREATE;
428 }
429 else
430 {
431 g_hCtlDev = devfs_make_node(makedev(g_nCtlDev, 0), DEVFS_CHAR,
432 UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
433 if (!g_hCtlDev)
434 {
435 LogRel(("VBoxAdp: failed to create FS node for control device."));
436 rc = VERR_CANT_CREATE;
437 }
438 }
439 }
440
441 if (RT_SUCCESS(rc))
442 {
443 LogRel(("VBoxAdpDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
444 return KMOD_RETURN_SUCCESS;
445 }
446
447 LogRel(("VBoxAdpDrv: failed to initialize device extension (rc=%d)\n", rc));
448 RTR0Term();
449 }
450 else
451 printf("VBoxAdpDrv: failed to initialize IPRT (rc=%d)\n", rc);
452
453 return KMOD_RETURN_FAILURE;
454}
455
456
457/**
458 * Stop the kernel module.
459 */
460static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData)
461{
462 Log(("VBoxNetAdpDarwinStop\n"));
463
464 vboxNetAdpShutdown();
465 /* Remove control device */
466 devfs_remove(g_hCtlDev);
467 cdevsw_remove(g_nCtlDev, &g_ChDev);
468
469 RTR0Term();
470
471 return KMOD_RETURN_SUCCESS;
472}
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