VirtualBox

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

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

HostDrivers,SrvIntNetR0,iprt/ntwrap.mac: Removed all the RT_WITH_W64_UNWIND_HACK fun.

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