VirtualBox

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

Last change on this file since 18802 was 18802, checked in by vboxsync, 16 years ago

2957: Dynamic add/remove via /dev/vboxnetctl ioctls.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.4 KB
Line 
1/* $Id: VBoxNetAdp-darwin.cpp 18802 2009-04-07 11:06:41Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25/*
26 * Deal with conflicts first.
27 * PVM - BSD mess, that FreeBSD has correct a long time ago.
28 * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
29 */
30#include <iprt/types.h>
31#include <sys/param.h>
32#undef PVM
33
34#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
35#include <VBox/log.h>
36#include <VBox/err.h>
37#include <VBox/version.h>
38#include <iprt/assert.h>
39#include <iprt/initterm.h>
40#include <iprt/semaphore.h>
41#include <iprt/spinlock.h>
42#include <iprt/string.h>
43#include <iprt/uuid.h>
44#include <iprt/alloca.h>
45
46#include <sys/systm.h>
47__BEGIN_DECLS /* Buggy 10.4 headers, fixed in 10.5. */
48#include <sys/kpi_mbuf.h>
49__END_DECLS
50
51#include <net/ethernet.h>
52#include <net/if_ether.h>
53#include <net/if_types.h>
54#include <sys/socket.h>
55#include <net/if.h>
56#include <net/if_dl.h>
57#include <sys/errno.h>
58#include <sys/param.h>
59#include <sys/conf.h>
60#include <miscfs/devfs/devfs.h>
61
62#define VBOXNETADP_OS_SPECFIC 1
63#include "../VBoxNetAdpInternal.h"
64
65/*******************************************************************************
66* Defined Constants And Macros *
67*******************************************************************************/
68/** The maximum number of SG segments.
69 * Used to prevent stack overflow and similar bad stuff. */
70#define VBOXNETADP_DARWIN_MAX_SEGS 32
71#define VBOXNETADP_DARWIN_MAX_FAMILIES 4
72#define VBOXNETADP_DARWIN_NAME "vboxnet"
73#define VBOXNETADP_DARWIN_MTU 1500
74#define VBOXNETADP_DARWIN_DETACH_TIMEOUT 500
75
76#define VBOXNETADP_FROM_IFACE(iface) ((PVBOXNETADP) ifnet_softc(iface))
77
78/* debug printf */
79#if defined(RT_OS_WINDOWS)
80# define OSDBGPRINT(a) DbgPrint a
81#elif defined(RT_OS_LINUX)
82# define OSDBGPRINT(a) printk a
83#elif defined(RT_OS_DARWIN)
84# define OSDBGPRINT(a) printf a
85#elif defined(RT_OS_OS2)
86# define OSDBGPRINT(a) SUPR0Printf a
87#elif defined(RT_OS_FREEBSD)
88# define OSDBGPRINT(a) printf a
89#elif defined(RT_OS_SOLARIS)
90# define OSDBGPRINT(a) SUPR0Printf a
91#else
92# define OSDBGPRINT(a)
93#endif
94
95/*******************************************************************************
96* Internal Functions *
97*******************************************************************************/
98__BEGIN_DECLS
99static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData);
100static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData);
101__END_DECLS
102
103static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
104static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
105static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
106
107/*******************************************************************************
108* Global Variables *
109*******************************************************************************/
110/**
111 * Declare the module stuff.
112 */
113__BEGIN_DECLS
114extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
115extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
116
117KMOD_EXPLICIT_DECL(VBoxNetAdp, VBOX_VERSION_STRING, _start, _stop)
118DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxNetAdpDarwinStart;
119DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxNetAdpDarwinStop;
120DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
121__END_DECLS
122
123/**
124 * The (common) global data.
125 */
126#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
127static VBOXNETADPGLOBALS g_VBoxNetAdpGlobals;
128
129#else /* !VBOXANETADP_DO_NOT_USE_NETFLT */
130
131static int g_nCtlDev = -1; /* Major dev number */
132static void *g_hCtlDev = 0; /* FS dev handle */
133
134/**
135 * The character device switch table for the driver.
136 */
137static struct cdevsw g_ChDev =
138{
139 /*.d_open = */VBoxNetAdpDarwinOpen,
140 /*.d_close = */VBoxNetAdpDarwinClose,
141 /*.d_read = */eno_rdwrt,
142 /*.d_write = */eno_rdwrt,
143 /*.d_ioctl = */VBoxNetAdpDarwinIOCtl,
144 /*.d_stop = */eno_stop,
145 /*.d_reset = */eno_reset,
146 /*.d_ttys = */NULL,
147 /*.d_select = */eno_select,
148 /*.d_mmap = */eno_mmap,
149 /*.d_strategy = */eno_strat,
150 /*.d_getc = */eno_getc,
151 /*.d_putc = */eno_putc,
152 /*.d_type = */0
153};
154
155/**
156 * Generate a suitable MAC address.
157 *
158 * @param pThis The instance.
159 * @param pMac Where to return the MAC address.
160 */
161DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac)
162{
163#if 0 /* Use a locally administered version of the OUI we use for the guest NICs. */
164 pMac->au8[0] = 0x08 | 2;
165 pMac->au8[1] = 0x00;
166 pMac->au8[2] = 0x27;
167#else /* this is what \0vb comes down to. It seems to be unassigned atm. */
168 pMac->au8[0] = 0;
169 pMac->au8[1] = 0x76;
170 pMac->au8[2] = 0x62;
171#endif
172
173 pMac->au8[3] = 0; /* pThis->uUnit >> 16; */
174 pMac->au8[4] = 0; /* pThis->uUnit >> 8; */
175 pMac->au8[5] = pThis->uUnit;
176}
177
178#endif /* !VBOXANETADP_DO_NOT_USE_NETFLT */
179
180
181
182
183static void vboxNetAdpDarwinComposeUUID(PVBOXNETADP pThis, PRTUUID pUuid)
184{
185 /* Generate UUID from name and MAC address. */
186 RTUuidClear(pUuid);
187 memcpy(pUuid->au8, "vboxnet", 7);
188 pUuid->Gen.u8ClockSeqHiAndReserved = (pUuid->Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
189 pUuid->Gen.u16TimeHiAndVersion = (pUuid->Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
190 pUuid->Gen.u8ClockSeqLow = pThis->uUnit;
191 vboxNetAdpComposeMACAddress(pThis, (PRTMAC)pUuid->Gen.au8Node);
192}
193
194#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
195/**
196 * Reads and retains the host interface handle.
197 *
198 * @returns The handle, NULL if detached.
199 * @param pThis
200 */
201DECLINLINE(ifnet_t) vboxNetAdpDarwinRetainIfNet(PVBOXNETADP pThis)
202{
203 if (pThis->u.s.pIface)
204 ifnet_reference(pThis->u.s.pIface);
205
206 return pThis->u.s.pIface;
207}
208
209
210/**
211 * Release the host interface handle previously retained
212 * by vboxNetAdpDarwinRetainIfNet.
213 *
214 * @param pThis The instance.
215 * @param pIfNet The vboxNetAdpDarwinRetainIfNet return value, NULL is fine.
216 */
217DECLINLINE(void) vboxNetAdpDarwinReleaseIfNet(PVBOXNETADP pThis, ifnet_t pIfNet)
218{
219 NOREF(pThis);
220 if (pIfNet)
221 ifnet_release(pIfNet);
222}
223
224/**
225 * Internal worker that create a darwin mbuf for a (scatter/)gather list.
226 *
227 * Taken from VBoxNetAdp-darwin.cpp.
228 *
229 * @returns Pointer to the mbuf.
230 * @param pThis The instance.
231 * @param pSG The (scatter/)gather list.
232 */
233static mbuf_t vboxNetAdpDarwinMBufFromSG(PVBOXNETADP pThis, PINTNETSG pSG)
234{
235 /// @todo future? mbuf_how_t How = preemtion enabled ? MBUF_DONTWAIT : MBUF_WAITOK;
236 mbuf_how_t How = MBUF_WAITOK;
237
238 /*
239 * We can't make use of the physical addresses on darwin because the way the
240 * mbuf / cluster stuffe works (see mbuf_data_to_physical and mcl_to_paddr).
241 * So, because we're lazy, we will ASSUME that all SGs coming from INTNET
242 * will only contain one single segment.
243 */
244 Assert(pSG->cSegsUsed == 1);
245 Assert(pSG->cbTotal == pSG->aSegs[0].cb);
246 Assert(pSG->cbTotal > 0);
247
248 /*
249 * We need some way of getting back to our instance data when
250 * the mbuf is freed, so use pvUserData for this.
251 * -- this is not relevant anylonger! --
252 */
253 Assert(!pSG->pvUserData || pSG->pvUserData == pThis);
254 Assert(!pSG->pvUserData2);
255 pSG->pvUserData = pThis;
256
257 /*
258 * Allocate a packet and copy over the data.
259 *
260 * Using mbuf_attachcluster() here would've been nice but there are two
261 * issues with it: (1) it's 10.5.x only, and (2) the documentation indicates
262 * that it's not supposed to be used for really external buffers. The 2nd
263 * point might be argued against considering that the only m_clattach user
264 * is mallocs memory for the ext mbuf and not doing what's stated in the docs.
265 * However, it's hard to tell if these m_clattach buffers actually makes it
266 * to the NICs or not, and even if they did, the NIC would need the physical
267 * addresses for the pages they contain and might end up copying the data
268 * to a new mbuf anyway.
269 *
270 * So, in the end it's better to just do it the simple way that will work
271 * 100%, even if it involes some extra work (alloc + copy) we really wished
272 * to avoid.
273 */
274 mbuf_t pPkt = NULL;
275 errno_t err = mbuf_allocpacket(How, pSG->cbTotal, NULL, &pPkt);
276 if (!err)
277 {
278 /* Skip zero sized memory buffers (paranoia). */
279 mbuf_t pCur = pPkt;
280 while (pCur && !mbuf_maxlen(pCur))
281 pCur = mbuf_next(pCur);
282 Assert(pCur);
283
284 /* Set the required packet header attributes. */
285 mbuf_pkthdr_setlen(pPkt, pSG->cbTotal);
286 mbuf_pkthdr_setheader(pPkt, mbuf_data(pCur));
287
288 /* Special case the single buffer copy. */
289 if ( mbuf_next(pCur)
290 && mbuf_maxlen(pCur) >= pSG->cbTotal)
291 {
292 mbuf_setlen(pCur, pSG->cbTotal);
293 memcpy(mbuf_data(pCur), pSG->aSegs[0].pv, pSG->cbTotal);
294 }
295 else
296 {
297 /* Multi buffer copying. */
298 size_t cbSrc = pSG->cbTotal;
299 uint8_t const *pbSrc = (uint8_t const *)pSG->aSegs[0].pv;
300 while (cbSrc > 0 && pCur)
301 {
302 size_t cb = mbuf_maxlen(pCur);
303 if (cbSrc < cb)
304 cb = cbSrc;
305 mbuf_setlen(pCur, cb);
306 memcpy(mbuf_data(pCur), pbSrc, cb);
307
308 /* advance */
309 pbSrc += cb;
310 cbSrc -= cb;
311 pCur = mbuf_next(pCur);
312 }
313 }
314 if (!err)
315 return pPkt;
316
317 mbuf_freem(pPkt);
318 }
319 else
320 AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
321 pSG->pvUserData = NULL;
322
323 return NULL;
324}
325
326
327/**
328 * Calculates the number of segments required to represent the mbuf.
329 *
330 * Taken from VBoxNetAdp-darwin.cpp.
331 *
332 * @returns Number of segments.
333 * @param pThis The instance.
334 * @param pMBuf The mbuf.
335 * @param pvFrame The frame pointer, optional.
336 */
337DECLINLINE(unsigned) vboxNetAdpDarwinMBufCalcSGSegs(PVBOXNETADP pThis, mbuf_t pMBuf, void *pvFrame)
338{
339 NOREF(pThis);
340
341 /*
342 * Count the buffers in the chain.
343 */
344 unsigned cSegs = 0;
345 for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
346 if (mbuf_len(pCur))
347 cSegs++;
348 else if ( !cSegs
349 && pvFrame
350 && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
351 cSegs++;
352
353#ifdef PADD_RUNT_FRAMES_FROM_HOST
354 /*
355 * Add one buffer if the total is less than the ethernet minimum 60 bytes.
356 * This may allocate a segment too much if the ethernet header is separated,
357 * but that shouldn't harm us much.
358 */
359 if (mbuf_pkthdr_len(pMBuf) < 60)
360 cSegs++;
361#endif
362
363#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
364 /* maximize the number of segments. */
365 cSegs = RT_MAX(VBOXNETFLT_DARWIN_MAX_SEGS - 1, cSegs);
366#endif
367
368 return cSegs ? cSegs : 1;
369}
370
371
372/**
373 * Initializes a SG list from an mbuf.
374 *
375 * Taken from VBoxNetAdp-darwin.cpp.
376 *
377 * @returns Number of segments.
378 * @param pThis The instance.
379 * @param pMBuf The mbuf.
380 * @param pSG The SG.
381 * @param pvFrame The frame pointer, optional.
382 * @param cSegs The number of segments allocated for the SG.
383 * This should match the number in the mbuf exactly!
384 * @param fSrc The source of the frame.
385 */
386DECLINLINE(void) vboxNetAdpDarwinMBufToSG(PVBOXNETADP pThis, mbuf_t pMBuf, void *pvFrame, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
387{
388 NOREF(pThis);
389
390 pSG->pvOwnerData = NULL;
391 pSG->pvUserData = NULL;
392 pSG->pvUserData2 = NULL;
393 pSG->cUsers = 1;
394 pSG->fFlags = INTNETSG_FLAGS_TEMP;
395 pSG->cSegsAlloc = cSegs;
396
397 /*
398 * Walk the chain and convert the buffers to segments.
399 */
400 unsigned iSeg = 0;
401 pSG->cbTotal = 0;
402 for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
403 {
404 size_t cbSeg = mbuf_len(pCur);
405 if (cbSeg)
406 {
407 void *pvSeg = mbuf_data(pCur);
408
409 /* deal with pvFrame */
410 if (!iSeg && pvFrame && pvFrame != pvSeg)
411 {
412 void *pvStart = mbuf_datastart(pMBuf);
413 uintptr_t offSeg = (uintptr_t)pvSeg - (uintptr_t)pvStart;
414 uintptr_t offSegEnd = offSeg + cbSeg;
415 Assert(pvStart && pvSeg && offSeg < mbuf_maxlen(pMBuf) && offSegEnd <= mbuf_maxlen(pMBuf)); NOREF(offSegEnd);
416 uintptr_t offFrame = (uintptr_t)pvFrame - (uintptr_t)pvStart;
417 if (RT_LIKELY(offFrame < offSeg))
418 {
419 pvSeg = pvFrame;
420 cbSeg += offSeg - offFrame;
421 }
422 else
423 AssertMsgFailed(("pvFrame=%p pvStart=%p pvSeg=%p offSeg=%p cbSeg=%#zx offSegEnd=%p offFrame=%p maxlen=%#zx\n",
424 pvFrame, pvStart, pvSeg, offSeg, cbSeg, offSegEnd, offFrame, mbuf_maxlen(pMBuf)));
425 pvFrame = NULL;
426 }
427
428 AssertBreak(iSeg < cSegs);
429 pSG->cbTotal += cbSeg;
430 pSG->aSegs[iSeg].cb = cbSeg;
431 pSG->aSegs[iSeg].pv = pvSeg;
432 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
433 iSeg++;
434 }
435 /* The pvFrame might be in a now empty buffer. */
436 else if ( !iSeg
437 && pvFrame
438 && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
439 {
440 cbSeg = (uintptr_t)mbuf_datastart(pMBuf) + mbuf_maxlen(pMBuf) - (uintptr_t)pvFrame;
441 pSG->cbTotal += cbSeg;
442 pSG->aSegs[iSeg].cb = cbSeg;
443 pSG->aSegs[iSeg].pv = pvFrame;
444 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
445 iSeg++;
446 pvFrame = NULL;
447 }
448 }
449
450 Assert(iSeg && iSeg <= cSegs);
451 pSG->cSegsUsed = iSeg;
452
453#ifdef PADD_RUNT_FRAMES_FROM_HOST
454 /*
455 * Add a trailer if the frame is too small.
456 *
457 * Since we're getting to the packet before it is framed, it has not
458 * yet been padded. The current solution is to add a segment pointing
459 * to a buffer containing all zeros and pray that works for all frames...
460 */
461 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
462 {
463 AssertReturnVoid(iSeg < cSegs);
464
465 static uint8_t const s_abZero[128] = {0};
466 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
467 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
468 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
469 pSG->cbTotal = 60;
470 pSG->cSegsUsed++;
471 }
472#endif
473
474#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
475 /*
476 * Redistribute the segments.
477 */
478 if (pSG->cSegsUsed < pSG->cSegsAlloc)
479 {
480 /* copy the segments to the end. */
481 int iSrc = pSG->cSegsUsed;
482 int iDst = pSG->cSegsAlloc;
483 while (iSrc > 0)
484 {
485 iDst--;
486 iSrc--;
487 pSG->aSegs[iDst] = pSG->aSegs[iSrc];
488 }
489
490 /* create small segments from the start. */
491 pSG->cSegsUsed = pSG->cSegsAlloc;
492 iSrc = iDst;
493 iDst = 0;
494 while ( iDst < iSrc
495 && iDst < pSG->cSegsAlloc)
496 {
497 pSG->aSegs[iDst].Phys = NIL_RTHCPHYS;
498 pSG->aSegs[iDst].pv = pSG->aSegs[iSrc].pv;
499 pSG->aSegs[iDst].cb = RT_MIN(pSG->aSegs[iSrc].cb, VBOXNETFLT_DARWIN_TEST_SEG_SIZE);
500 if (pSG->aSegs[iDst].cb != pSG->aSegs[iSrc].cb)
501 {
502 pSG->aSegs[iSrc].cb -= pSG->aSegs[iDst].cb;
503 pSG->aSegs[iSrc].pv = (uint8_t *)pSG->aSegs[iSrc].pv + pSG->aSegs[iDst].cb;
504 }
505 else if (++iSrc >= pSG->cSegsAlloc)
506 {
507 pSG->cSegsUsed = iDst + 1;
508 break;
509 }
510 iDst++;
511 }
512 }
513#endif
514
515 AssertMsg(!pvFrame, ("pvFrame=%p pMBuf=%p iSeg=%d\n", pvFrame, pMBuf, iSeg));
516}
517
518#endif /* VBOXANETADP_DO_NOT_USE_NETFLT */
519static errno_t vboxNetAdpDarwinOutput(ifnet_t pIface, mbuf_t pMBuf)
520{
521#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
522 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
523 Assert(pThis);
524 if (vboxNetAdpPrepareToReceive(pThis))
525 {
526 unsigned cSegs = vboxNetAdpDarwinMBufCalcSGSegs(pThis, pMBuf, NULL);
527 if (cSegs < VBOXNETADP_DARWIN_MAX_SEGS)
528 {
529 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
530 vboxNetAdpDarwinMBufToSG(pThis, pMBuf, NULL, pSG, cSegs, INTNETTRUNKDIR_HOST);
531 vboxNetAdpReceive(pThis, pSG);
532 }
533 else
534 vboxNetAdpCancelReceive(pThis);
535 }
536#endif /* VBOXANETADP_DO_NOT_USE_NETFLT */
537 mbuf_freem_list(pMBuf);
538 return 0;
539}
540
541static void vboxNetAdpDarwinAttachFamily(PVBOXNETADP pThis, protocol_family_t Family)
542{
543 u_int32_t i;
544 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
545 if (pThis->u.s.aAttachedFamilies[i] == 0)
546 {
547 pThis->u.s.aAttachedFamilies[i] = Family;
548 break;
549 }
550}
551
552static void vboxNetAdpDarwinDetachFamily(PVBOXNETADP pThis, protocol_family_t Family)
553{
554 u_int32_t i;
555 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
556 if (pThis->u.s.aAttachedFamilies[i] == Family)
557 pThis->u.s.aAttachedFamilies[i] = 0;
558}
559
560static errno_t vboxNetAdpDarwinAddProto(ifnet_t pIface, protocol_family_t Family, const struct ifnet_demux_desc *pDemuxDesc, u_int32_t nDesc)
561{
562 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
563 Assert(pThis);
564 vboxNetAdpDarwinAttachFamily(pThis, Family);
565 LogFlow(("vboxNetAdpAddProto: Family=%d.\n", Family));
566 return ether_add_proto(pIface, Family, pDemuxDesc, nDesc);
567}
568
569static errno_t vboxNetAdpDarwinDelProto(ifnet_t pIface, protocol_family_t Family)
570{
571 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
572 Assert(pThis);
573 LogFlow(("vboxNetAdpDelProto: Family=%d.\n", Family));
574 vboxNetAdpDarwinDetachFamily(pThis, Family);
575 return ether_del_proto(pIface, Family);
576}
577
578static void vboxNetAdpDarwinDetach(ifnet_t pIface)
579{
580 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
581 Assert(pThis);
582 Log2(("vboxNetAdpDarwinDetach: Signaling detach to vboxNetAdpUnregisterDevice.\n"));
583 /* Let vboxNetAdpDarwinUnregisterDevice know that the interface has been detached. */
584 RTSemEventSignal(pThis->u.s.hEvtDetached);
585}
586
587
588#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
589
590int vboxNetAdpPortOsXmit(PVBOXNETADP pThis, PINTNETSG pSG, uint32_t fDst)
591{
592 int rc = VINF_SUCCESS;
593 ifnet_t pIfNet = vboxNetAdpDarwinRetainIfNet(pThis); // Really need a wrapper?
594 if (pIfNet)
595 {
596 /*
597 * Create a mbuf for the gather list and push it onto the host stack.
598 */
599 mbuf_t pMBuf = vboxNetAdpDarwinMBufFromSG(pThis, pSG);
600 if (pMBuf)
601 {
602 /* This is what IONetworkInterface::inputPacket does. */
603 unsigned const cbEthHdr = 14;
604 mbuf_pkthdr_setheader(pMBuf, mbuf_data(pMBuf));
605 mbuf_pkthdr_setlen(pMBuf, mbuf_pkthdr_len(pMBuf) - cbEthHdr);
606 mbuf_setdata(pMBuf, (uint8_t *)mbuf_data(pMBuf) + cbEthHdr, mbuf_len(pMBuf) - cbEthHdr);
607 mbuf_pkthdr_setrcvif(pMBuf, pIfNet); /* will crash without this. */
608
609 Log(("vboxNetAdpPortOsXmit: calling ifnet_input()\n"));
610 errno_t err = ifnet_input(pIfNet, pMBuf, NULL);
611 if (err)
612 rc = RTErrConvertFromErrno(err);
613 }
614 else
615 {
616 Log(("vboxNetAdpPortOsXmit: failed to convert SG to mbuf.\n"));
617 rc = VERR_NO_MEMORY;
618 }
619
620 vboxNetAdpDarwinReleaseIfNet(pThis, pIfNet);
621 }
622 else
623 Log(("vboxNetAdpPortOsXmit: failed to retain the interface.\n"));
624
625 return rc;
626}
627
628bool vboxNetAdpPortOsIsPromiscuous(PVBOXNETADP pThis)
629{
630 uint16_t fIf = 0;
631 ifnet_t pIfNet = vboxNetAdpDarwinRetainIfNet(pThis);
632 if (pIfNet)
633 {
634 /* gather the data */
635 fIf = ifnet_flags(pIfNet);
636 vboxNetAdpDarwinReleaseIfNet(pThis, pIfNet);
637 }
638 return fIf & IFF_PROMISC;
639}
640
641
642void vboxNetAdpPortOsGetMacAddress(PVBOXNETADP pThis, PRTMAC pMac)
643{
644 *pMac = pThis->u.s.Mac;
645}
646
647
648bool vboxNetAdpPortOsIsHostMac(PVBOXNETADP pThis, PCRTMAC pMac)
649{
650 /* ASSUMES that the MAC address never changes. */
651 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
652 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
653 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
654}
655
656int vboxNetAdpOsDisconnectIt(PVBOXNETADP pThis)
657{
658 /* Nothing to do here. */
659 return VINF_SUCCESS;
660}
661
662
663int vboxNetAdpOsConnectIt(PVBOXNETADP pThis)
664{
665 /* Nothing to do here. */
666 return VINF_SUCCESS;
667}
668#else /* !VBOXANETADP_DO_NOT_USE_NETFLT */
669//VBOXNETADP g_vboxnet0;
670VBOXNETADP g_aAdapters[VBOXNETADP_MAX_INSTANCES];
671
672#endif /* !VBOXANETADP_DO_NOT_USE_NETFLT */
673
674
675
676int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
677{
678 int rc;
679 struct ifnet_init_params Params;
680 RTUUID uuid;
681 struct sockaddr_dl mac;
682
683 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
684 rc = RTSemEventCreate(&pThis->u.s.hEvtDetached);
685 if (RT_FAILURE(rc))
686 {
687 OSDBGPRINT(("vboxNetAdpOsCreate: failed to create semaphore (rc=%d).\n", rc));
688 return rc;
689 }
690
691 mac.sdl_len = sizeof(mac);
692 mac.sdl_family = AF_LINK;
693 mac.sdl_alen = ETHER_ADDR_LEN;
694 mac.sdl_nlen = 0;
695 mac.sdl_slen = 0;
696 memcpy(LLADDR(&mac), pMACAddress->au8, mac.sdl_alen);
697
698 RTStrPrintf(pThis->szName, VBOXNETADP_MAX_NAME_LEN, "%s%d", VBOXNETADP_NAME, pThis->uUnit);
699 vboxNetAdpDarwinComposeUUID(pThis, &uuid);
700 Params.uniqueid = uuid.au8;
701 Params.uniqueid_len = sizeof(uuid);
702 Params.name = VBOXNETADP_NAME;
703 Params.unit = pThis->uUnit;
704 Params.family = IFNET_FAMILY_ETHERNET;
705 Params.type = IFT_ETHER;
706 Params.output = vboxNetAdpDarwinOutput;
707 Params.demux = ether_demux;
708 Params.add_proto = vboxNetAdpDarwinAddProto;
709 Params.del_proto = vboxNetAdpDarwinDelProto;
710 Params.check_multi = ether_check_multi;
711 Params.framer = ether_frameout;
712 Params.softc = pThis;
713 Params.ioctl = (ifnet_ioctl_func)ether_ioctl;
714 Params.set_bpf_tap = NULL;
715 Params.detach = vboxNetAdpDarwinDetach;
716 Params.event = NULL;
717 Params.broadcast_addr = "\xFF\xFF\xFF\xFF\xFF\xFF";
718 Params.broadcast_len = ETHER_ADDR_LEN;
719
720 errno_t err = ifnet_allocate(&Params, &pThis->u.s.pIface);
721 if (!err)
722 {
723 err = ifnet_attach(pThis->u.s.pIface, &mac);
724 if (!err)
725 {
726 err = ifnet_set_flags(pThis->u.s.pIface, IFF_RUNNING | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST, 0xFFFF);
727 if (!err)
728 {
729 ifnet_set_mtu(pThis->u.s.pIface, VBOXNETADP_MTU);
730 return VINF_SUCCESS;
731 }
732 else
733 Log(("vboxNetAdpDarwinRegisterDevice: Failed to set flags (err=%d).\n", err));
734 ifnet_detach(pThis->u.s.pIface);
735 }
736 else
737 Log(("vboxNetAdpDarwinRegisterDevice: Failed to attach to interface (err=%d).\n", err));
738 ifnet_release(pThis->u.s.pIface);
739 }
740 else
741 Log(("vboxNetAdpDarwinRegisterDevice: Failed to allocate interface (err=%d).\n", err));
742
743 RTSemEventDestroy(pThis->u.s.hEvtDetached);
744 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
745
746 return RTErrConvertFromErrno(err);
747}
748
749void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
750{
751 u_int32_t i;
752 /* Bring down the interface */
753 int rc = VINF_SUCCESS;
754 errno_t err;
755
756 AssertPtr(pThis->u.s.pIface);
757 Assert(pThis->u.s.hEvtDetached != NIL_RTSEMEVENT);
758
759 err = ifnet_set_flags(pThis->u.s.pIface, 0, IFF_UP | IFF_RUNNING);
760 if (err)
761 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to bring down interface "
762 "(err=%d).\n", err));
763 /* Detach all protocols. */
764 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
765 if (pThis->u.s.aAttachedFamilies[i])
766 ifnet_detach_protocol(pThis->u.s.pIface, pThis->u.s.aAttachedFamilies[i]);
767 err = ifnet_detach(pThis->u.s.pIface);
768 if (err)
769 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to detach interface "
770 "(err=%d).\n", err));
771 Log2(("vboxNetAdpDarwinUnregisterDevice: Waiting for 'detached' event...\n"));
772 /* Wait until we get a signal from detach callback. */
773 rc = RTSemEventWait(pThis->u.s.hEvtDetached, VBOXNETADP_DETACH_TIMEOUT);
774 if (rc == VERR_TIMEOUT)
775 LogRel(("VBoxAdpDrv: Failed to detach interface %s%d\n.",
776 VBOXNETADP_NAME, pThis->uUnit));
777 err = ifnet_release(pThis->u.s.pIface);
778 if (err)
779 Log(("vboxNetAdpUnregisterDevice: Failed to release interface (err=%d).\n", err));
780
781 RTSemEventDestroy(pThis->u.s.hEvtDetached);
782 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
783}
784
785int vboxNetAdpCreate (PVBOXNETADP *ppNew)
786{
787 int rc;
788 unsigned i;
789 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
790 {
791 PVBOXNETADP pThis = &g_aAdapters[i];
792
793 if (ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Invalid))
794 {
795 /* Found an empty slot -- use it. */
796 Log(("vboxNetAdpCreate: found empty slot: %d\n", i));
797 RTMAC Mac;
798 vboxNetAdpComposeMACAddress(pThis, &Mac);
799 rc = vboxNetAdpOsCreate(pThis, &Mac);
800 if (RT_SUCCESS(rc))
801 {
802 *ppNew = pThis;
803 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Active);
804 }
805 else
806 {
807 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
808 Log(("vboxNetAdpCreate: vboxNetAdpOsCreate failed with '%Rrc'.\n", rc));
809 }
810 return rc;
811 }
812 }
813 Log(("vboxNetAdpCreate: no empty slots!\n"));
814
815 /* All slots in adapter array are busy. */
816 return VERR_OUT_OF_RESOURCES;
817}
818
819int vboxNetAdpDestroy (PVBOXNETADP pThis)
820{
821 int rc = VINF_SUCCESS;
822
823 if (!ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Active))
824 return VERR_INTNET_FLT_IF_BUSY;
825
826 vboxNetAdpOsDestroy(pThis);
827
828 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
829
830 return rc;
831}
832
833/**
834 * Device open. Called on open /dev/vboxnetctl
835 *
836 * @param pInode Pointer to inode info structure.
837 * @param pFilp Associated file pointer.
838 */
839static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
840{
841 char szName[128];
842 szName[0] = '\0';
843 proc_name(proc_pid(pProcess), szName, sizeof(szName));
844 Log(("VBoxNetAdpDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
845 return 0;
846}
847
848/**
849 * Close device.
850 */
851static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
852{
853 Log(("VBoxNetAdpDarwinClose: pid=%d\n", proc_pid(pProcess)));
854 return 0;
855}
856
857/**
858 * Device I/O Control entry point.
859 *
860 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
861 * @param Dev The device number (major+minor).
862 * @param iCmd The IOCtl command.
863 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
864 * @param fFlags Flag saying we're a character device (like we didn't know already).
865 * @param pProcess The process issuing this request.
866 */
867static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
868{
869 int rc = VINF_SUCCESS;
870 uint32_t cbReq = IOCPARM_LEN(iCmd);
871 PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
872
873 Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
874 switch (IOCBASECMD(iCmd))
875 {
876 case IOCBASECMD(VBOXNETADP_CTL_ADD):
877 if ((IOC_DIRMASK & iCmd) == IOC_OUT)
878 {
879 PVBOXNETADP pNew;
880 rc = vboxNetAdpCreate(&pNew);
881 if (RT_SUCCESS(rc))
882 {
883 if (cbReq < sizeof(VBOXNETADPREQ))
884 {
885 OSDBGPRINT(("VBoxNetAdpDarwinIOCtl: param len %#x < req size %#x; iCmd=%#lx\n", cbReq, sizeof(VBOXNETADPREQ), iCmd));
886 return EINVAL;
887 }
888 strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName));
889 }
890 }
891 break;
892
893 case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
894 for (unsigned i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
895 {
896 PVBOXNETADP pThis = &g_aAdapters[i];
897 rc = VERR_NOT_FOUND;
898 if (strncmp(pThis->szName, pReq->szName, VBOXNETADP_MAX_NAME_LEN) == 0)
899 if (ASMAtomicReadU32((uint32_t volatile *)&pThis->enmState) == kVBoxNetAdpState_Active)
900 {
901 rc = vboxNetAdpDestroy(pThis);
902 break;
903 }
904 }
905 break;
906 default:
907 OSDBGPRINT(("VBoxNetAdpDarwinIOCtl: unknown command %x.\n", IOCBASECMD(iCmd)));
908 rc = VERR_INVALID_PARAMETER;
909 break;
910 }
911
912 return RT_SUCCESS(rc) ? 0 : EINVAL;
913}
914
915int vboxNetAdpOsInit(PVBOXNETADP pThis)
916{
917 /*
918 * Init the darwin specific members.
919 */
920 pThis->enmState = kVBoxNetAdpState_Invalid;
921 pThis->u.s.pIface = NULL;
922 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
923 memset(pThis->u.s.aAttachedFamilies, 0, sizeof(pThis->u.s.aAttachedFamilies));
924
925 return VINF_SUCCESS;
926}
927
928/**
929 * Start the kernel module.
930 */
931static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData)
932{
933 int rc;
934
935 /*
936 * Initialize IPRT and find our module tag id.
937 * (IPRT is shared with VBoxDrv, it creates the loggers.)
938 */
939 rc = RTR0Init(0);
940 if (RT_SUCCESS(rc))
941 {
942 Log(("VBoxNetAdpDarwinStart\n"));
943 /*
944 * Initialize the globals and connect to the support driver.
945 *
946 * This will call back vboxNetAdpOsOpenSupDrv (and maybe vboxNetAdpOsCloseSupDrv)
947 * for establishing the connect to the support driver.
948 */
949#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
950 memset(&g_VBoxNetAdpGlobals, 0, sizeof(g_VBoxNetAdpGlobals));
951 rc = vboxNetAdpInitGlobals(&g_VBoxNetAdpGlobals);
952#else /* !VBOXANETADP_DO_NOT_USE_NETFLT */
953 for (unsigned i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
954 {
955 g_aAdapters[i].uUnit = i;
956 vboxNetAdpOsInit(&g_aAdapters[i]);
957 }
958
959 PVBOXNETADP pVboxnet0;
960 rc = vboxNetAdpCreate(&pVboxnet0);
961 if (RT_SUCCESS(rc))
962 {
963 g_nCtlDev = cdevsw_add(-1, &g_ChDev);
964 if (g_nCtlDev < 0)
965 {
966 LogRel(("VBoxAdp: failed to register control device."));
967 rc = VERR_CANT_CREATE;
968 }
969 else
970 {
971 g_hCtlDev = devfs_make_node(makedev(g_nCtlDev, 0), DEVFS_CHAR,
972 UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
973 if (!g_hCtlDev)
974 {
975 LogRel(("VBoxAdp: failed to create FS node for control device."));
976 rc = VERR_CANT_CREATE;
977 }
978 }
979 }
980
981#endif /* !VBOXANETADP_DO_NOT_USE_NETFLT */
982 if (RT_SUCCESS(rc))
983 {
984 LogRel(("VBoxAdpDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
985 return KMOD_RETURN_SUCCESS;
986 }
987
988 LogRel(("VBoxAdpDrv: failed to initialize device extension (rc=%d)\n", rc));
989 RTR0Term();
990 }
991 else
992 printf("VBoxAdpDrv: failed to initialize IPRT (rc=%d)\n", rc);
993
994#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
995 memset(&g_VBoxNetAdpGlobals, 0, sizeof(g_VBoxNetAdpGlobals));
996#endif /* VBOXANETADP_DO_NOT_USE_NETFLT */
997 return KMOD_RETURN_FAILURE;
998}
999
1000
1001/**
1002 * Stop the kernel module.
1003 */
1004static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData)
1005{
1006 Log(("VBoxNetAdpDarwinStop\n"));
1007
1008 /*
1009 * Refuse to unload if anyone is currently using the filter driver.
1010 * This is important as I/O kit / xnu will to be able to do usage
1011 * tracking for us!
1012 */
1013#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
1014 int rc = vboxNetAdpTryDeleteGlobals(&g_VBoxNetAdpGlobals);
1015 if (RT_FAILURE(rc))
1016 {
1017 Log(("VBoxNetAdpDarwinStop - failed, busy.\n"));
1018 return KMOD_RETURN_FAILURE;
1019 }
1020
1021 /*
1022 * Undo the work done during start (in reverse order).
1023 */
1024 memset(&g_VBoxNetAdpGlobals, 0, sizeof(g_VBoxNetAdpGlobals));
1025#else /* !VBOXANETADP_DO_NOT_USE_NETFLT */
1026 /* Remove virtual adapters */
1027 for (unsigned i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1028 vboxNetAdpDestroy(&g_aAdapters[i]);
1029 /* Remove control device */
1030 devfs_remove(g_hCtlDev);
1031 cdevsw_remove(g_nCtlDev, &g_ChDev);
1032#endif /* !VBOXANETADP_DO_NOT_USE_NETFLT */
1033
1034 RTR0Term();
1035
1036 return KMOD_RETURN_SUCCESS;
1037}
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