VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c@ 17095

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

#2957: VBoxNetAdp: Fixes in generic and darwin parts. No traffic yet.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.8 KB
Line 
1/* $Id: VBoxNetAdp.c 17095 2009-02-24 20:08:20Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Common Code.
4 */
5
6/*
7 * Copyright (C) 2008-2009 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#define LOG_GROUP LOG_GROUP_NET_TAP_DRV
26#include "VBoxNetAdpInternal.h"
27
28#include <VBox/sup.h>
29#include <VBox/log.h>
30#include <VBox/err.h>
31#include <VBox/version.h>
32#include <iprt/assert.h>
33#include <iprt/string.h>
34#include <iprt/spinlock.h>
35#include <iprt/uuid.h>
36
37#ifndef RT_OS_SOLARIS
38#include <net/ethernet.h>
39#include <net/if_ether.h>
40#include <net/if_types.h>
41#include <sys/socket.h>
42#include <net/if.h>
43#include <net/if_dl.h>
44#include <sys/errno.h>
45#include <sys/param.h>
46#endif
47
48
49/*******************************************************************************
50* Defined Constants And Macros *
51*******************************************************************************/
52#define IFPORT_2_VBOXNETADP(pIfPort) \
53 ( (PVBOXNETADP)((uint8_t *)pIfPort - RT_OFFSETOF(VBOXNETADP, MyPort)) )
54
55
56
57/**
58 * Generate a suitable MAC address.
59 *
60 * @param pThis The instance.
61 * @param pMac Where to return the MAC address.
62 */
63DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac)
64{
65#if 0 /* Use a locally administered version of the OUI we use for the guest NICs. */
66 pMac->au8[0] = 0x08 | 2;
67 pMac->au8[1] = 0x00;
68 pMac->au8[2] = 0x27;
69#else /* this is what \0vb comes down to. It seems to be unassigned atm. */
70 pMac->au8[0] = 0;
71 pMac->au8[1] = 0x76;
72 pMac->au8[2] = 0x62;
73#endif
74
75 pMac->au8[3] = pThis->uUnit >> 16;
76 pMac->au8[4] = pThis->uUnit >> 8;
77 pMac->au8[5] = pThis->uUnit;
78}
79
80
81
82/**
83 * Gets the enmState member atomically.
84 *
85 * Used for all reads.
86 *
87 * @returns The enmState value.
88 * @param pThis The instance.
89 */
90DECLINLINE(VBOXNETADPSTATE) vboxNetAdpGetState(PVBOXNETADP pThis)
91{
92 return (VBOXNETADPSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState);
93}
94
95
96/**
97 * Sets the enmState member atomically.
98 *
99 * Used for all updates.
100 *
101 * @param pThis The instance.
102 * @param enmNewState The new value.
103 */
104DECLINLINE(void) vboxNetAdpSetState(PVBOXNETADP pThis, VBOXNETADPSTATE enmNewState)
105{
106 Log(("vboxNetAdpSetState: pThis=%p, state change: %d -> %d.\n", pThis, vboxNetAdpGetState(pThis), enmNewState));
107 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, enmNewState);
108}
109
110/**
111 * Sets the enmState member atomically.
112 *
113 * Used for all updates.
114 *
115 * @param pThis The instance.
116 * @param enmNewState The new value.
117 */
118DECLINLINE(void) vboxNetAdpSetStateWithLock(PVBOXNETADP pThis, VBOXNETADPSTATE enmNewState)
119{
120 VBOXNETADPSTATE enmState;
121 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
122 Log(("vboxNetAdpSetStateWithLock: pThis=%p, state=%d.\n", pThis, enmState));
123 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
124 vboxNetAdpSetState(pThis, enmNewState);
125 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
126}
127
128
129
130/**
131 * Gets the enmState member with locking.
132 *
133 * Used for all reads.
134 *
135 * @returns The enmState value.
136 * @param pThis The instance.
137 */
138DECLINLINE(VBOXNETADPSTATE) vboxNetAdpGetStateWithLock(PVBOXNETADP pThis)
139{
140 VBOXNETADPSTATE enmState;
141 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
142 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
143 enmState = vboxNetAdpGetState(pThis);
144 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
145 Log(("vboxNetAdpGetStateWithLock: pThis=%p, state=%d.\n", pThis, enmState));
146 return enmState;
147}
148
149/**
150 * Checks and sets the enmState member atomically.
151 *
152 * Used for all updates.
153 *
154 * @returns true if the state has been changed.
155 * @param pThis The instance.
156 * @param enmNewState The new value.
157 */
158DECLINLINE(bool) vboxNetAdpCheckAndSetState(PVBOXNETADP pThis, VBOXNETADPSTATE enmOldState, VBOXNETADPSTATE enmNewState)
159{
160 VBOXNETADPSTATE enmActualState;
161 bool fRc = true; /* be optimistic */
162 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
163 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
164 enmActualState = vboxNetAdpGetState(pThis);
165 if (enmActualState == enmOldState)
166 vboxNetAdpSetState(pThis, enmNewState);
167 else
168 fRc = false;
169 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
170 if (fRc)
171 Log(("vboxNetAdpCheckAndSetState: pThis=%p, state changed: %d -> %d.\n", pThis, enmOldState, enmNewState));
172 else
173 Log(("vboxNetAdpCheckAndSetState: pThis=%p, no state change: %d != %d (expected).\n", pThis, enmActualState, enmOldState));
174 return fRc;
175}
176
177
178
179static PVBOXNETADP vboxNetAdpFind(PVBOXNETADPGLOBALS pGlobals, const char *pszName)
180{
181 unsigned i;
182
183 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
184 {
185 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
186 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
187 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
188 if (vboxNetAdpGetState(pThis)
189 && !strcmp(pThis->szName, pszName))
190 {
191 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
192 return pThis;
193 }
194 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
195 }
196 return NULL;
197}
198
199/**
200 * Releases a reference to the specified instance.
201 *
202 * @param pThis The instance.
203 * @param fBusy Whether the busy counter should be decremented too.
204 */
205DECLHIDDEN(void) vboxNetAdpRelease(PVBOXNETADP pThis)
206{
207 uint32_t cRefs;
208
209 /*
210 * Paranoid Android.
211 */
212 AssertPtr(pThis);
213 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
214 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
215 Assert(vboxNetAdpGetState(pThis) > kVBoxNetAdpState_Invalid);
216 AssertPtr(pThis->pGlobals);
217 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
218 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
219 Assert(pThis->szName[0]);
220
221 /*
222 * The object reference counting.
223 */
224 cRefs = ASMAtomicDecU32(&pThis->cRefs);
225 Assert(cRefs < UINT32_MAX / 2);
226}
227
228/**
229 * Decrements the busy counter and does idle wakeup.
230 *
231 * @param pThis The instance.
232 */
233DECLHIDDEN(void) vboxNetAdpIdle(PVBOXNETADP pThis)
234{
235 uint32_t cBusy;
236
237 /*
238 * Paranoid Android.
239 */
240 AssertPtr(pThis);
241 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
242 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
243 Assert(vboxNetAdpGetState(pThis) >= kVBoxNetAdpState_Connected);
244 AssertPtr(pThis->pGlobals);
245 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
246
247 cBusy = ASMAtomicDecU32(&pThis->cBusy);
248 if (!cBusy)
249 {
250 int rc = RTSemEventSignal(pThis->hEventIdle);
251 AssertRC(rc);
252 }
253 else
254 Assert(cBusy < UINT32_MAX / 2);
255}
256
257/**
258 * Retains a reference to the specified instance.
259 *
260 * @param pThis The instance.
261 */
262DECLHIDDEN(void) vboxNetAdpRetain(PVBOXNETADP pThis)
263{
264 uint32_t cRefs;
265
266 /*
267 * Paranoid Android.
268 */
269 AssertPtr(pThis);
270 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
271 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
272 Assert(vboxNetAdpGetState(pThis) > kVBoxNetAdpState_Invalid);
273 AssertPtr(pThis->pGlobals);
274 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
275 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
276 Assert(pThis->szName[0]);
277
278 /*
279 * Retain the object.
280 */
281 cRefs = ASMAtomicIncU32(&pThis->cRefs);
282 Assert(cRefs > 1 && cRefs < UINT32_MAX / 2);
283
284 NOREF(cRefs);
285}
286
287/**
288 * Increments busy counter.
289 *
290 * @param pThis The instance.
291 */
292DECLHIDDEN(void) vboxNetAdpBusy(PVBOXNETADP pThis)
293{
294 uint32_t cBusy;
295
296 /*
297 * Are we vigilant enough?
298 */
299 AssertPtr(pThis);
300 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
301 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
302 Assert(vboxNetAdpGetState(pThis) >= kVBoxNetAdpState_Connected);
303 AssertPtr(pThis->pGlobals);
304 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
305 cBusy = ASMAtomicIncU32(&pThis->cBusy);
306 Assert(cBusy > 0 && cBusy < UINT32_MAX / 2);
307
308 NOREF(cBusy);
309}
310
311/**
312 * Checks if receive is possible and increases busy and ref counters if so.
313 *
314 * @param pThis The instance.
315 */
316DECLHIDDEN(bool) vboxNetAdpPrepareToReceive(PVBOXNETADP pThis)
317{
318 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
319 bool fCanReceive = false;
320 /*
321 * Input validation.
322 */
323 AssertPtr(pThis);
324 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
325 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
326 if (vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Active)
327 {
328 fCanReceive = true;
329 vboxNetAdpRetain(pThis);
330 vboxNetAdpBusy(pThis);
331 }
332 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
333
334 return fCanReceive;
335}
336
337/**
338 * Forwards scatter/gather list to internal network and decreases busy and ref counters.
339 *
340 * @param pThis The instance.
341 */
342DECLHIDDEN(void) vboxNetAdpReceive(PVBOXNETADP pThis, PINTNETSG pSG)
343{
344 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
345 /*
346 * Input validation.
347 */
348 AssertPtr(pThis);
349 AssertPtr(pSG);
350 AssertPtr(pThis->pSwitchPort);
351 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
352 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
353 vboxNetAdpIdle(pThis);
354 vboxNetAdpRelease(pThis);
355}
356
357/**
358 * Decreases busy and ref counters.
359 *
360 * @param pThis The instance.
361 */
362DECLHIDDEN(void) vboxNetAdpCancelReceive(PVBOXNETADP pThis)
363{
364 vboxNetAdpIdle(pThis);
365 vboxNetAdpRelease(pThis);
366}
367
368#ifdef RT_WITH_W64_UNWIND_HACK
369# if defined(RT_OS_WINDOWS) && defined(RT_ARCH_AMD64)
370# define NETADP_DECL_CALLBACK(type) DECLASM(DECLHIDDEN(type))
371# define NETADP_CALLBACK(_n) netfltNtWrap##_n
372
373NETADP_DECL_CALLBACK(int) NETADP_CALLBACK(vboxNetAdpPortXmit)(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst);
374NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortIsPromiscuous)(PINTNETTRUNKIFPORT pIfPort);
375NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortGetMacAddress)(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac);
376NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortIsHostMac)(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac);
377NETADP_DECL_CALLBACK(int) NETADP_CALLBACK(vboxNetAdpPortWaitForIdle)(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies);
378NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortSetActive)(PINTNETTRUNKIFPORT pIfPort, bool fActive);
379NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortDisconnectAndRelease)(PINTNETTRUNKIFPORT pIfPort);
380NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortRetain)(PINTNETTRUNKIFPORT pIfPort);
381NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortRelease)(PINTNETTRUNKIFPORT pIfPort);
382
383# else
384# error "UNSUPPORTED (RT_WITH_W64_UNWIND_HACK)"
385# endif
386#else
387# define NETADP_DECL_CALLBACK(type) static DECLCALLBACK(type)
388# define NETADP_CALLBACK(_n) _n
389#endif
390
391/**
392 * @copydoc INTNETTRUNKIFPORT::pfnXmit
393 */
394NETADP_DECL_CALLBACK(int) vboxNetAdpPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
395{
396 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
397 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
398 int rc = VINF_SUCCESS;
399
400 /*
401 * Input validation.
402 */
403 AssertPtr(pThis);
404 AssertPtr(pSG);
405 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
406
407 /*
408 * Do a retain/busy, invoke the OS specific code.
409 */
410 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
411 if (vboxNetAdpGetState(pThis) != kVBoxNetAdpState_Active)
412 {
413 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
414 Log(("vboxNetAdpReceive: Dropping incoming packet for inactive interface %s.\n",
415 pThis->szName));
416 return VERR_INVALID_STATE;
417 }
418 vboxNetAdpRetain(pThis);
419 vboxNetAdpBusy(pThis);
420 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
421 rc = vboxNetAdpPortOsXmit(pThis, pSG, fDst);
422 vboxNetAdpIdle(pThis);
423 vboxNetAdpRelease(pThis);
424
425 return rc;
426}
427
428
429/**
430 * @copydoc INTNETTRUNKIFPORT::pfnIsPromiscuous
431 */
432NETADP_DECL_CALLBACK(bool) vboxNetAdpPortIsPromiscuous(PINTNETTRUNKIFPORT pIfPort)
433{
434 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
435
436 /*
437 * Input validation.
438 */
439 AssertPtr(pThis);
440 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
441 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Connected);
442
443 /*
444 * Ask the OS specific code.
445 */
446 return vboxNetAdpPortOsIsPromiscuous(pThis);
447}
448
449
450/**
451 * @copydoc INTNETTRUNKIFPORT::pfnGetMacAddress
452 */
453NETADP_DECL_CALLBACK(void) vboxNetAdpPortGetMacAddress(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac)
454{
455 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
456
457 /*
458 * Input validation.
459 */
460 AssertPtr(pThis);
461 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
462 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Connected);
463
464 /*
465 * Forward the question to the OS specific code.
466 */
467 vboxNetAdpPortOsGetMacAddress(pThis, pMac);
468}
469
470
471/**
472 * @copydoc INTNETTRUNKIFPORT::pfnIsHostMac
473 */
474NETADP_DECL_CALLBACK(bool) vboxNetAdpPortIsHostMac(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac)
475{
476 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
477
478 /*
479 * Input validation.
480 */
481 AssertPtr(pThis);
482 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
483 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Active);
484
485 /*
486 * Ask the OS specific code.
487 */
488 return vboxNetAdpPortOsIsHostMac(pThis, pMac);
489}
490
491
492/**
493 * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
494 */
495NETADP_DECL_CALLBACK(int) vboxNetAdpPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
496{
497 int rc;
498 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
499
500 /*
501 * Input validation.
502 */
503 AssertPtr(pThis);
504 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
505 AssertReturn(vboxNetAdpGetStateWithLock(pThis) >= kVBoxNetAdpState_Connected, VERR_INVALID_STATE);
506
507 /*
508 * Go to sleep on the semaphore after checking the busy count.
509 */
510 vboxNetAdpRetain(pThis);
511
512 rc = VINF_SUCCESS;
513 while (pThis->cBusy && RT_SUCCESS(rc))
514 rc = RTSemEventWait(pThis->hEventIdle, cMillies); /** @todo make interruptible? */
515
516 vboxNetAdpRelease(pThis);
517
518 return rc;
519}
520
521
522/**
523 * @copydoc INTNETTRUNKIFPORT::pfnSetActive
524 */
525NETADP_DECL_CALLBACK(bool) vboxNetAdpPortSetActive(PINTNETTRUNKIFPORT pIfPort, bool fActive)
526{
527 bool fPreviouslyActive;
528 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
529 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
530
531 /*
532 * Input validation.
533 */
534 AssertPtr(pThis);
535 AssertPtr(pThis->pGlobals);
536 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
537
538 Log(("vboxNetAdpPortSetActive: pThis=%p, fActive=%d, state before: %d.\n", pThis, fActive, vboxNetAdpGetState(pThis)));
539 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
540 fPreviouslyActive = vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Active;
541 if (fPreviouslyActive != fActive)
542 {
543 switch (vboxNetAdpGetState(pThis))
544 {
545 case kVBoxNetAdpState_Connected:
546 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Active);
547 break;
548 case kVBoxNetAdpState_Active:
549 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Connected);
550 break;
551 }
552 }
553 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
554 Log(("vboxNetAdpPortSetActive: state after: %d.\n", vboxNetAdpGetState(pThis)));
555 return fPreviouslyActive;
556}
557
558
559/**
560 * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
561 */
562NETADP_DECL_CALLBACK(void) vboxNetAdpPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
563{
564 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
565 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
566
567 /*
568 * Serious paranoia.
569 */
570 AssertPtr(pThis);
571 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
572 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
573 AssertPtr(pThis->pGlobals);
574 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
575 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
576
577
578 /*
579 * Disconnect and release it.
580 */
581 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
582 //Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Connected);
583 Assert(!pThis->cBusy);
584 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Transitional);
585 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
586
587 vboxNetAdpOsDisconnectIt(pThis);
588 pThis->pSwitchPort = NULL;
589
590 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
591 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Available);
592 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
593
594 vboxNetAdpRelease(pThis);
595}
596
597
598/**
599 * @copydoc INTNETTRUNKIFPORT::pfnRelease
600 */
601NETADP_DECL_CALLBACK(void) vboxNetAdpPortRelease(PINTNETTRUNKIFPORT pIfPort)
602{
603 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
604 vboxNetAdpRelease(pThis);
605}
606
607
608/**
609 * @copydoc INTNETTRUNKIFPORT::pfnRetain
610 */
611NETADP_DECL_CALLBACK(void) vboxNetAdpPortRetain(PINTNETTRUNKIFPORT pIfPort)
612{
613 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
614 vboxNetAdpRetain(pThis);
615}
616
617
618int vboxNetAdpCreate (PINTNETTRUNKFACTORY pIfFactory, PVBOXNETADP *ppNew)
619{
620 int rc;
621 unsigned i;
622 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
623
624 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
625 {
626 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
627 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
628
629 if (vboxNetAdpCheckAndSetState(pThis, kVBoxNetAdpState_Invalid, kVBoxNetAdpState_Transitional))
630 {
631 /* Found an empty slot -- use it. */
632 RTMAC Mac;
633 Assert(ASMAtomicIncU32(&pThis->cRefs) == 1);
634 vboxNetAdpComposeMACAddress(pThis, &Mac);
635 rc = vboxNetAdpOsCreate(pThis, &Mac);
636 *ppNew = pThis;
637 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
638 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Available);
639 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
640 return rc;
641 }
642 }
643
644 /* All slots in adapter array are busy. */
645 return VERR_OUT_OF_RESOURCES;
646}
647
648int vboxNetAdpDestroy (PVBOXNETADP pThis)
649{
650 int rc = VINF_SUCCESS;
651 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
652
653 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
654 if (vboxNetAdpGetState(pThis) != kVBoxNetAdpState_Available || pThis->cBusy)
655 {
656 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
657 return VERR_INTNET_FLT_IF_BUSY;
658 }
659 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Transitional);
660 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
661 vboxNetAdpRelease(pThis);
662
663 vboxNetAdpOsDestroy(pThis);
664
665 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
666 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Invalid);
667 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
668
669 return rc;
670}
671
672/**
673 * Connects the instance to the specified switch port.
674 *
675 * Called while owning the lock. We're ASSUMING that the internal
676 * networking code is already owning an recursive mutex, so, there
677 * will be no deadlocks when vboxNetAdpOsConnectIt calls back into
678 * it for setting preferences.
679 *
680 * @returns VBox status code.
681 * @param pThis The instance.
682 * @param pSwitchPort The port on the internal network 'switch'.
683 * @param ppIfPort Where to return our port interface.
684 */
685static int vboxNetAdpConnectIt(PVBOXNETADP pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
686{
687 int rc;
688
689 /*
690 * Validate state.
691 */
692 Assert(!pThis->cBusy);
693 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Transitional);
694
695 /*
696 * Do the job.
697 * Note that we're calling the os stuff while owning the semaphore here.
698 */
699 pThis->pSwitchPort = pSwitchPort;
700 rc = vboxNetAdpOsConnectIt(pThis);
701 if (RT_SUCCESS(rc))
702 {
703 *ppIfPort = &pThis->MyPort;
704 }
705 else
706 pThis->pSwitchPort = NULL;
707
708 return rc;
709}
710
711/**
712 * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
713 */
714static DECLCALLBACK(int) vboxNetAdpFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
715 PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort, bool fNoPromisc)
716{
717 PVBOXNETADP pThis;
718 int rc;
719 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
720
721 LogFlow(("vboxNetAdpFactoryCreateAndConnect: pszName=%p:{%s}\n", pszName, pszName));
722 Assert(pGlobals->cFactoryRefs > 0);
723
724 /*
725 * Find instance, check if busy, connect if not.
726 */
727 pThis = vboxNetAdpFind(pGlobals, pszName);
728 if (pThis)
729 {
730 if (vboxNetAdpCheckAndSetState(pThis, kVBoxNetAdpState_Available, kVBoxNetAdpState_Transitional))
731 {
732 vboxNetAdpRetain(pThis);
733 rc = vboxNetAdpConnectIt(pThis, pSwitchPort, ppIfPort);
734 vboxNetAdpSetStateWithLock(pThis, RT_SUCCESS(rc) ? kVBoxNetAdpState_Connected : kVBoxNetAdpState_Available);
735 }
736 else
737 rc = VERR_INTNET_FLT_IF_BUSY;
738 }
739 else
740 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
741
742 return rc;
743}
744
745/**
746 * @copydoc INTNETTRUNKFACTORY::pfnRelease
747 */
748static DECLCALLBACK(void) vboxNetAdpFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
749{
750 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
751
752 int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
753 Assert(cRefs >= 0); NOREF(cRefs);
754 LogFlow(("vboxNetAdpFactoryRelease: cRefs=%d (new)\n", cRefs));
755}
756
757
758/**
759 * Implements the SUPDRV component factor interface query method.
760 *
761 * @returns Pointer to an interface. NULL if not supported.
762 *
763 * @param pSupDrvFactory Pointer to the component factory registration structure.
764 * @param pSession The session - unused.
765 * @param pszInterfaceUuid The factory interface id.
766 */
767static DECLCALLBACK(void *) vboxNetAdpQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
768{
769 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, SupDrvFactory));
770
771 /*
772 * Convert the UUID strings and compare them.
773 */
774 RTUUID UuidReq;
775 int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
776 if (RT_SUCCESS(rc))
777 {
778 if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
779 {
780 ASMAtomicIncS32(&pGlobals->cFactoryRefs);
781 return &pGlobals->TrunkFactory;
782 }
783#ifdef LOG_ENABLED
784 else
785 Log(("VBoxNetAdp: unknown factory interface query (%s)\n", pszInterfaceUuid));
786#endif
787 }
788 else
789 Log(("VBoxNetAdp: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
790
791 return NULL;
792}
793
794
795/**
796 * Checks whether the VBoxNetAdp wossname can be unloaded.
797 *
798 * This will return false if someone is currently using the module.
799 *
800 * @returns true if it's relatively safe to unload it, otherwise false.
801 * @param pGlobals Pointer to the globals.
802 */
803DECLHIDDEN(bool) vboxNetAdpCanUnload(PVBOXNETADPGLOBALS pGlobals)
804{
805 int rc;
806 unsigned i;
807 bool fRc = true; /* Assume it can be unloaded. */
808
809 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
810 {
811 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
812 if (vboxNetAdpGetStateWithLock(&pGlobals->aAdapters[i]) >= kVBoxNetAdpState_Connected)
813 {
814 fRc = false;
815 break; /* We already know the answer. */
816 }
817 }
818 return fRc && ASMAtomicUoReadS32((int32_t volatile *)&pGlobals->cFactoryRefs) <= 0;
819}
820
821/**
822 * tries to deinitialize Idc
823 * we separate the globals settings "base" which is actually
824 * "general" globals settings except for Idc, and idc.
825 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
826 * thus it's not possible to make idc initialization from the driver startup routine for it,
827 * though the "base is still needed for the driver to functions".
828 * @param pGlobals
829 * @return VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
830 */
831DECLHIDDEN(int) vboxNetAdpTryDeleteIdc(PVBOXNETADPGLOBALS pGlobals)
832{
833 int rc;
834
835 Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
836
837 /*
838 * Check before trying to deregister the factory.
839 */
840 if (!vboxNetAdpCanUnload(pGlobals))
841 return VERR_WRONG_ORDER;
842
843 /*
844 * Disconnect from SUPDRV and check that nobody raced us,
845 * reconnect if that should happen.
846 */
847 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
848 AssertRC(rc);
849 if (!vboxNetAdpCanUnload(pGlobals))
850 {
851 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
852 AssertRC(rc);
853 return VERR_WRONG_ORDER;
854 }
855
856 SUPR0IdcClose(&pGlobals->SupDrvIDC);
857
858 return rc;
859}
860
861static int vboxNetAdpSlotCreate(PVBOXNETADPGLOBALS pGlobals, unsigned uUnit, PVBOXNETADP pNew)
862{
863 int rc;
864
865 pNew->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
866 pNew->MyPort.pfnRetain = NETADP_CALLBACK(vboxNetAdpPortRetain);
867 pNew->MyPort.pfnRelease = NETADP_CALLBACK(vboxNetAdpPortRelease);
868 pNew->MyPort.pfnDisconnectAndRelease= NETADP_CALLBACK(vboxNetAdpPortDisconnectAndRelease);
869 pNew->MyPort.pfnSetActive = NETADP_CALLBACK(vboxNetAdpPortSetActive);
870 pNew->MyPort.pfnWaitForIdle = NETADP_CALLBACK(vboxNetAdpPortWaitForIdle);
871 pNew->MyPort.pfnGetMacAddress = NETADP_CALLBACK(vboxNetAdpPortGetMacAddress);
872 pNew->MyPort.pfnIsHostMac = NETADP_CALLBACK(vboxNetAdpPortIsHostMac);
873 pNew->MyPort.pfnIsPromiscuous = NETADP_CALLBACK(vboxNetAdpPortIsPromiscuous);
874 pNew->MyPort.pfnXmit = NETADP_CALLBACK(vboxNetAdpPortXmit);
875 pNew->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
876 pNew->pSwitchPort = NULL;
877 pNew->pGlobals = pGlobals;
878 pNew->hSpinlock = NIL_RTSPINLOCK;
879 pNew->enmState = kVBoxNetAdpState_Invalid;
880 pNew->cRefs = 0;
881 pNew->cBusy = 0;
882 pNew->hEventIdle = NIL_RTSEMEVENT;
883
884 rc = RTSpinlockCreate(&pNew->hSpinlock);
885 if (RT_SUCCESS(rc))
886 {
887 rc = RTSemEventCreate(&pNew->hEventIdle);
888 if (RT_SUCCESS(rc))
889 {
890 rc = vboxNetAdpOsInit(pNew);
891 if (RT_SUCCESS(rc))
892 {
893 return rc;
894 }
895 RTSemEventDestroy(pNew->hEventIdle);
896 pNew->hEventIdle = NIL_RTSEMEVENT;
897 }
898 RTSpinlockDestroy(pNew->hSpinlock);
899 pNew->hSpinlock = NIL_RTSPINLOCK;
900 }
901 return rc;
902}
903
904static void vboxNetAdpSlotDestroy(PVBOXNETADP pThis)
905{
906 Assert(pThis->cRefs == 0);
907 Assert(pThis->cBusy == 0);
908 Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Invalid);
909 if (pThis->hEventIdle != NIL_RTSEMEVENT)
910 {
911 RTSemEventDestroy(pThis->hEventIdle);
912 pThis->hEventIdle = NIL_RTSEMEVENT;
913 }
914 if (pThis->hSpinlock != NIL_RTSPINLOCK)
915 {
916 RTSpinlockDestroy(pThis->hSpinlock);
917 pThis->hSpinlock = NIL_RTSPINLOCK;
918 }
919}
920
921/**
922 * performs "base" globals deinitialization
923 * we separate the globals settings "base" which is actually
924 * "general" globals settings except for Idc, and idc.
925 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
926 * thus it's not possible to make idc initialization from the driver startup routine for it,
927 * though the "base is still needed for the driver to functions".
928 * @param pGlobals
929 * @return none
930 */
931DECLHIDDEN(void) vboxNetAdpDeleteGlobalsBase(PVBOXNETADPGLOBALS pGlobals)
932{
933 int i;
934 /*
935 * Release resources.
936 */
937 for (i = 0; i < (int)RT_ELEMENTS(pGlobals->aAdapters); i++)
938 if (RT_SUCCESS(vboxNetAdpDestroy(&pGlobals->aAdapters[i])))
939 vboxNetAdpSlotDestroy(&pGlobals->aAdapters[i]);
940
941 RTSemFastMutexDestroy(pGlobals->hFastMtx);
942 pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
943
944#ifdef VBOXNETADP_STATIC_CONFIG
945 RTSemEventDestroy(pGlobals->hTimerEvent);
946 pGlobals->hTimerEvent = NIL_RTSEMEVENT;
947#endif
948
949}
950
951/**
952 * Called by the native part when the OS wants the driver to unload.
953 *
954 * @returns VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
955 *
956 * @param pGlobals Pointer to the globals.
957 */
958DECLHIDDEN(int) vboxNetAdpTryDeleteGlobals(PVBOXNETADPGLOBALS pGlobals)
959{
960 int rc = vboxNetAdpTryDeleteIdc(pGlobals);
961 if(RT_SUCCESS(rc))
962 {
963 vboxNetAdpDeleteGlobalsBase(pGlobals);
964 }
965 return rc;
966}
967
968
969/**
970 * performs the "base" globals initialization
971 * we separate the globals initialization to globals "base" initialization which is actually
972 * "general" globals initialization except for Idc not being initialized, and idc initialization.
973 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
974 * thus it's not possible to make idc initialization from the driver startup routine for it.
975 *
976 * @returns VBox status code.
977 * @param pGlobals Pointer to the globals. */
978DECLHIDDEN(int) vboxNetAdpInitGlobalsBase(PVBOXNETADPGLOBALS pGlobals)
979{
980 /*
981 * Initialize the common portions of the structure.
982 */
983 int i;
984 int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
985 if (RT_SUCCESS(rc))
986 {
987 memset(pGlobals->aAdapters, 0, sizeof(pGlobals->aAdapters));
988 for (i = 0; i < (int)RT_ELEMENTS(pGlobals->aAdapters); i++)
989 {
990 rc = vboxNetAdpSlotCreate(pGlobals, i, &pGlobals->aAdapters[i]);
991 if (RT_FAILURE(rc))
992 {
993 /* Clean up. */
994 while (--i >= 0)
995 vboxNetAdpSlotDestroy(&pGlobals->aAdapters[i]);
996 Log(("vboxNetAdpInitGlobalsBase: Failed to create fast mutex (rc=%Rrc).\n", rc));
997 RTSemFastMutexDestroy(pGlobals->hFastMtx);
998 return rc;
999 }
1000 }
1001 pGlobals->TrunkFactory.pfnRelease = vboxNetAdpFactoryRelease;
1002 pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetAdpFactoryCreateAndConnect;
1003
1004 strcpy(pGlobals->SupDrvFactory.szName, "VBoxNetAdp");
1005 pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetAdpQueryFactoryInterface;
1006 }
1007
1008 return rc;
1009}
1010
1011/**
1012 * performs the Idc initialization
1013 * we separate the globals initialization to globals "base" initialization which is actually
1014 * "general" globals initialization except for Idc not being initialized, and idc initialization.
1015 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
1016 * thus it's not possible to make idc initialization from the driver startup routine for it.
1017 *
1018 * @returns VBox status code.
1019 * @param pGlobals Pointer to the globals. */
1020DECLHIDDEN(int) vboxNetAdpInitIdc(PVBOXNETADPGLOBALS pGlobals)
1021{
1022 int rc;
1023 /*
1024 * Establish a connection to SUPDRV and register our component factory.
1025 */
1026 rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
1027 if (RT_SUCCESS(rc))
1028 {
1029 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1030 if (RT_SUCCESS(rc))
1031 {
1032 /* @todo REMOVE ME! */
1033 PVBOXNETADP pTmp;
1034 rc = vboxNetAdpCreate(&pGlobals->TrunkFactory, &pTmp);
1035 if (RT_FAILURE(rc))
1036 Log(("Failed to create vboxnet0, rc=%Rrc.\n", rc));
1037 Log(("VBoxNetAdp: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
1038 return rc;
1039 }
1040
1041 /* bail out. */
1042 LogRel(("VBoxNetAdp: Failed to register component factory, rc=%Rrc\n", rc));
1043 SUPR0IdcClose(&pGlobals->SupDrvIDC);
1044 }
1045
1046 return rc;
1047}
1048
1049/**
1050 * Called by the native driver/kext module initialization routine.
1051 *
1052 * It will initialize the common parts of the globals, assuming the caller
1053 * has already taken care of the OS specific bits.
1054 *
1055 * @returns VBox status code.
1056 * @param pGlobals Pointer to the globals.
1057 */
1058DECLHIDDEN(int) vboxNetAdpInitGlobals(PVBOXNETADPGLOBALS pGlobals)
1059{
1060 /*
1061 * Initialize the common portions of the structure.
1062 */
1063 int rc = vboxNetAdpInitGlobalsBase(pGlobals);
1064 if (RT_SUCCESS(rc))
1065 {
1066 rc = vboxNetAdpInitIdc(pGlobals);
1067 if (RT_SUCCESS(rc))
1068 {
1069 return rc;
1070 }
1071
1072 /* bail out. */
1073 vboxNetAdpDeleteGlobalsBase(pGlobals);
1074 }
1075
1076 return rc;
1077}
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