VirtualBox

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

Last change on this file since 58340 was 58340, checked in by vboxsync, 9 years ago

HostDrivers: Doxygen fixes

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