VirtualBox

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

Last change on this file since 40107 was 38408, checked in by vboxsync, 13 years ago

vboxnetflt: partial BPF support for bridged interfaces (#5817)

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