VirtualBox

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

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

#2954: Dynamic add/remove for virtual adapters. Moved all adapter-related code to vboxnetadp.ko

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.8 KB
Line 
1/* $Id: VBoxNetAdp.c 18973 2009-04-17 06:59:16Z 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#ifdef RT_WITH_W64_UNWIND_HACK
401# if defined(RT_OS_WINDOWS) && defined(RT_ARCH_AMD64)
402# define NETADP_DECL_CALLBACK(type) DECLASM(DECLHIDDEN(type))
403# define NETADP_CALLBACK(_n) netfltNtWrap##_n
404
405NETADP_DECL_CALLBACK(int) NETADP_CALLBACK(vboxNetAdpPortXmit)(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst);
406NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortIsPromiscuous)(PINTNETTRUNKIFPORT pIfPort);
407NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortGetMacAddress)(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac);
408NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortIsHostMac)(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac);
409NETADP_DECL_CALLBACK(int) NETADP_CALLBACK(vboxNetAdpPortWaitForIdle)(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies);
410NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortSetActive)(PINTNETTRUNKIFPORT pIfPort, bool fActive);
411NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortDisconnectAndRelease)(PINTNETTRUNKIFPORT pIfPort);
412NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortRetain)(PINTNETTRUNKIFPORT pIfPort);
413NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortRelease)(PINTNETTRUNKIFPORT pIfPort);
414
415# else
416# error "UNSUPPORTED (RT_WITH_W64_UNWIND_HACK)"
417# endif
418#else
419# define NETADP_DECL_CALLBACK(type) static DECLCALLBACK(type)
420# define NETADP_CALLBACK(_n) _n
421#endif
422
423/**
424 * @copydoc INTNETTRUNKIFPORT::pfnXmit
425 */
426NETADP_DECL_CALLBACK(int) vboxNetAdpPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
427{
428 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
429 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
430 int rc = VINF_SUCCESS;
431
432 /*
433 * Input validation.
434 */
435 AssertPtr(pThis);
436 AssertPtr(pSG);
437 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
438
439 Log(("vboxNetAdpPortXmit: outgoing packet (len=%d)\n", pSG->cbTotal));
440
441 /*
442 * Do a retain/busy, invoke the OS specific code.
443 */
444 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
445 if (vboxNetAdpGetState(pThis) != kVBoxNetAdpState_Active)
446 {
447 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
448 Log(("vboxNetAdpReceive: Dropping incoming packet for inactive interface %s.\n",
449 pThis->szName));
450 return VERR_INVALID_STATE;
451 }
452 vboxNetAdpRetain(pThis);
453 vboxNetAdpBusy(pThis);
454 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
455
456 rc = vboxNetAdpPortOsXmit(pThis, pSG, fDst);
457 vboxNetAdpIdle(pThis);
458 vboxNetAdpRelease(pThis);
459
460 return rc;
461}
462
463
464/**
465 * @copydoc INTNETTRUNKIFPORT::pfnIsPromiscuous
466 */
467NETADP_DECL_CALLBACK(bool) vboxNetAdpPortIsPromiscuous(PINTNETTRUNKIFPORT pIfPort)
468{
469 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
470
471 /*
472 * Input validation.
473 */
474 AssertPtr(pThis);
475 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
476 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Active);
477
478 /*
479 * Ask the OS specific code.
480 */
481 return vboxNetAdpPortOsIsPromiscuous(pThis);
482}
483
484
485/**
486 * @copydoc INTNETTRUNKIFPORT::pfnGetMacAddress
487 */
488NETADP_DECL_CALLBACK(void) vboxNetAdpPortGetMacAddress(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac)
489{
490 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
491
492 /*
493 * Input validation.
494 */
495 AssertPtr(pThis);
496 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
497 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Active);
498
499 /*
500 * Forward the question to the OS specific code.
501 */
502 vboxNetAdpPortOsGetMacAddress(pThis, pMac);
503}
504
505
506/**
507 * @copydoc INTNETTRUNKIFPORT::pfnIsHostMac
508 */
509NETADP_DECL_CALLBACK(bool) vboxNetAdpPortIsHostMac(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac)
510{
511 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
512
513 /*
514 * Input validation.
515 */
516 AssertPtr(pThis);
517 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
518 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Active);
519
520 /*
521 * Ask the OS specific code.
522 */
523 return vboxNetAdpPortOsIsHostMac(pThis, pMac);
524}
525
526
527/**
528 * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
529 */
530NETADP_DECL_CALLBACK(int) vboxNetAdpPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
531{
532 int rc;
533 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
534
535 /*
536 * Input validation.
537 */
538 AssertPtr(pThis);
539 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
540 AssertReturn(vboxNetAdpGetStateWithLock(pThis) >= kVBoxNetAdpState_Connected, VERR_INVALID_STATE);
541
542 /*
543 * Go to sleep on the semaphore after checking the busy count.
544 */
545 vboxNetAdpRetain(pThis);
546
547 rc = VINF_SUCCESS;
548 while (pThis->cBusy && RT_SUCCESS(rc))
549 rc = RTSemEventWait(pThis->hEventIdle, cMillies); /** @todo make interruptible? */
550
551 vboxNetAdpRelease(pThis);
552
553 return rc;
554}
555
556
557/**
558 * @copydoc INTNETTRUNKIFPORT::pfnSetActive
559 */
560NETADP_DECL_CALLBACK(bool) vboxNetAdpPortSetActive(PINTNETTRUNKIFPORT pIfPort, bool fActive)
561{
562 bool fPreviouslyActive;
563 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
564 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
565
566 /*
567 * Input validation.
568 */
569 AssertPtr(pThis);
570 AssertPtr(pThis->pGlobals);
571 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
572
573 Log(("vboxNetAdpPortSetActive: pThis=%p, fActive=%d, state before: %d.\n", pThis, fActive, vboxNetAdpGetState(pThis)));
574 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
575
576 fPreviouslyActive = vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Active;
577 if (fPreviouslyActive != fActive)
578 {
579 switch (vboxNetAdpGetState(pThis))
580 {
581 case kVBoxNetAdpState_Connected:
582 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Active);
583 break;
584 case kVBoxNetAdpState_Active:
585 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Connected);
586 break;
587 default:
588 break;
589 }
590 }
591
592 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
593 Log(("vboxNetAdpPortSetActive: state after: %RTbool.\n", vboxNetAdpGetState(pThis)));
594 return fPreviouslyActive;
595}
596
597
598/**
599 * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
600 */
601NETADP_DECL_CALLBACK(void) vboxNetAdpPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
602{
603 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
604 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
605
606 /*
607 * Serious paranoia.
608 */
609 AssertPtr(pThis);
610 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
611 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
612 AssertPtr(pThis->pGlobals);
613 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
614 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
615
616
617 /*
618 * Disconnect and release it.
619 */
620 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
621 //Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Connected);
622 Assert(!pThis->cBusy);
623 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Transitional);
624 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
625
626 vboxNetAdpOsDisconnectIt(pThis);
627 pThis->pSwitchPort = NULL;
628
629 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
630 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Available);
631 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
632
633 vboxNetAdpRelease(pThis);
634}
635
636
637/**
638 * @copydoc INTNETTRUNKIFPORT::pfnRelease
639 */
640NETADP_DECL_CALLBACK(void) vboxNetAdpPortRelease(PINTNETTRUNKIFPORT pIfPort)
641{
642 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
643 vboxNetAdpRelease(pThis);
644}
645
646
647/**
648 * @copydoc INTNETTRUNKIFPORT::pfnRetain
649 */
650NETADP_DECL_CALLBACK(void) vboxNetAdpPortRetain(PINTNETTRUNKIFPORT pIfPort)
651{
652 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
653 vboxNetAdpRetain(pThis);
654}
655
656
657int vboxNetAdpCreate (PINTNETTRUNKFACTORY pIfFactory, PVBOXNETADP *ppNew)
658{
659 int rc;
660 unsigned i;
661 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
662
663 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
664 {
665 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
666 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
667
668 if (vboxNetAdpCheckAndSetState(pThis, kVBoxNetAdpState_Invalid, kVBoxNetAdpState_Transitional))
669 {
670 /* Found an empty slot -- use it. */
671 RTMAC Mac;
672 Assert(ASMAtomicIncU32(&pThis->cRefs) == 1);
673 vboxNetAdpComposeMACAddress(pThis, &Mac);
674 rc = vboxNetAdpOsCreate(pThis, &Mac);
675 *ppNew = pThis;
676 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
677 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Available);
678 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
679 return rc;
680 }
681 }
682
683 /* All slots in adapter array are busy. */
684 return VERR_OUT_OF_RESOURCES;
685}
686
687int vboxNetAdpDestroy (PVBOXNETADP pThis)
688{
689 int rc = VINF_SUCCESS;
690 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
691
692 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
693 if (vboxNetAdpGetState(pThis) != kVBoxNetAdpState_Available || pThis->cBusy)
694 {
695 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
696 return VERR_INTNET_FLT_IF_BUSY;
697 }
698 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Transitional);
699 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
700 vboxNetAdpRelease(pThis);
701
702 vboxNetAdpOsDestroy(pThis);
703
704 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
705 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Invalid);
706 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
707
708 return rc;
709}
710
711/**
712 * Connects the instance to the specified switch port.
713 *
714 * Called while owning the lock. We're ASSUMING that the internal
715 * networking code is already owning an recursive mutex, so, there
716 * will be no deadlocks when vboxNetAdpOsConnectIt calls back into
717 * it for setting preferences.
718 *
719 * @returns VBox status code.
720 * @param pThis The instance.
721 * @param pSwitchPort The port on the internal network 'switch'.
722 * @param ppIfPort Where to return our port interface.
723 */
724static int vboxNetAdpConnectIt(PVBOXNETADP pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
725{
726 int rc;
727
728 /*
729 * Validate state.
730 */
731 Assert(!pThis->cBusy);
732 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Transitional);
733
734 /*
735 * Do the job.
736 * Note that we're calling the os stuff while owning the semaphore here.
737 */
738 pThis->pSwitchPort = pSwitchPort;
739 rc = vboxNetAdpOsConnectIt(pThis);
740 if (RT_SUCCESS(rc))
741 {
742 *ppIfPort = &pThis->MyPort;
743 }
744 else
745 pThis->pSwitchPort = NULL;
746
747 return rc;
748}
749
750
751/**
752 * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
753 */
754static DECLCALLBACK(int) vboxNetAdpFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
755 PINTNETTRUNKSWPORT pSwitchPort, uint32_t fFlags,
756 PINTNETTRUNKIFPORT *ppIfPort)
757{
758 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
759 PVBOXNETADP pThis;
760 int rc;
761
762 LogFlow(("vboxNetAdpFactoryCreateAndConnect: pszName=%p:{%s} fFlags=%#x\n", pszName, pszName, fFlags));
763 Assert(pGlobals->cFactoryRefs > 0);
764 AssertMsgReturn(!fFlags,
765 ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
766
767 /*
768 * Find instance, check if busy, connect if not.
769 */
770 pThis = vboxNetAdpFind(pGlobals, pszName);
771 if (pThis)
772 {
773 if (vboxNetAdpCheckAndSetState(pThis, kVBoxNetAdpState_Available, kVBoxNetAdpState_Transitional))
774 {
775 vboxNetAdpRetain(pThis);
776 rc = vboxNetAdpConnectIt(pThis, pSwitchPort, ppIfPort);
777 vboxNetAdpSetStateWithLock(pThis, RT_SUCCESS(rc) ? kVBoxNetAdpState_Connected : kVBoxNetAdpState_Available);
778 }
779 else
780 rc = VERR_INTNET_FLT_IF_BUSY;
781 }
782 else
783 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
784
785 return rc;
786}
787
788
789/**
790 * @copydoc INTNETTRUNKFACTORY::pfnRelease
791 */
792static DECLCALLBACK(void) vboxNetAdpFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
793{
794 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
795
796 int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
797 Assert(cRefs >= 0); NOREF(cRefs);
798 LogFlow(("vboxNetAdpFactoryRelease: cRefs=%d (new)\n", cRefs));
799}
800
801
802/**
803 * Implements the SUPDRV component factor interface query method.
804 *
805 * @returns Pointer to an interface. NULL if not supported.
806 *
807 * @param pSupDrvFactory Pointer to the component factory registration structure.
808 * @param pSession The session - unused.
809 * @param pszInterfaceUuid The factory interface id.
810 */
811static DECLCALLBACK(void *) vboxNetAdpQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
812{
813 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, SupDrvFactory));
814
815 /*
816 * Convert the UUID strings and compare them.
817 */
818 RTUUID UuidReq;
819 int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
820 if (RT_SUCCESS(rc))
821 {
822 if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
823 {
824 ASMAtomicIncS32(&pGlobals->cFactoryRefs);
825 return &pGlobals->TrunkFactory;
826 }
827#ifdef LOG_ENABLED
828 else
829 Log(("VBoxNetAdp: unknown factory interface query (%s)\n", pszInterfaceUuid));
830#endif
831 }
832 else
833 Log(("VBoxNetAdp: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
834
835 return NULL;
836}
837
838
839/**
840 * Checks whether the VBoxNetAdp wossname can be unloaded.
841 *
842 * This will return false if someone is currently using the module.
843 *
844 * @returns true if it's relatively safe to unload it, otherwise false.
845 * @param pGlobals Pointer to the globals.
846 */
847DECLHIDDEN(bool) vboxNetAdpCanUnload(PVBOXNETADPGLOBALS pGlobals)
848{
849 bool fRc = true; /* Assume it can be unloaded. */
850 unsigned i;
851
852 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
853 {
854 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
855 if (vboxNetAdpGetStateWithLock(&pGlobals->aAdapters[i]) >= kVBoxNetAdpState_Connected)
856 {
857 fRc = false;
858 break; /* We already know the answer. */
859 }
860 }
861 return fRc && ASMAtomicUoReadS32((int32_t volatile *)&pGlobals->cFactoryRefs) <= 0;
862}
863
864/**
865 * tries to deinitialize Idc
866 * we separate the globals settings "base" which is actually
867 * "general" globals settings except for Idc, and idc.
868 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
869 * thus it's not possible to make idc initialization from the driver startup routine for it,
870 * though the "base is still needed for the driver to functions".
871 * @param pGlobals
872 * @return VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
873 */
874DECLHIDDEN(int) vboxNetAdpTryDeleteIdc(PVBOXNETADPGLOBALS pGlobals)
875{
876 int rc;
877
878 Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
879
880 /*
881 * Check before trying to deregister the factory.
882 */
883 if (!vboxNetAdpCanUnload(pGlobals))
884 return VERR_WRONG_ORDER;
885
886 /*
887 * Disconnect from SUPDRV and check that nobody raced us,
888 * reconnect if that should happen.
889 */
890 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
891 AssertRC(rc);
892 if (!vboxNetAdpCanUnload(pGlobals))
893 {
894 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
895 AssertRC(rc);
896 return VERR_WRONG_ORDER;
897 }
898
899 SUPR0IdcClose(&pGlobals->SupDrvIDC);
900
901 return rc;
902}
903
904static int vboxNetAdpSlotCreate(PVBOXNETADPGLOBALS pGlobals, unsigned uUnit, PVBOXNETADP pNew)
905{
906 int rc;
907
908 pNew->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
909 pNew->MyPort.pfnRetain = NETADP_CALLBACK(vboxNetAdpPortRetain);
910 pNew->MyPort.pfnRelease = NETADP_CALLBACK(vboxNetAdpPortRelease);
911 pNew->MyPort.pfnDisconnectAndRelease= NETADP_CALLBACK(vboxNetAdpPortDisconnectAndRelease);
912 pNew->MyPort.pfnSetActive = NETADP_CALLBACK(vboxNetAdpPortSetActive);
913 pNew->MyPort.pfnWaitForIdle = NETADP_CALLBACK(vboxNetAdpPortWaitForIdle);
914 pNew->MyPort.pfnGetMacAddress = NETADP_CALLBACK(vboxNetAdpPortGetMacAddress);
915 pNew->MyPort.pfnIsHostMac = NETADP_CALLBACK(vboxNetAdpPortIsHostMac);
916 pNew->MyPort.pfnIsPromiscuous = NETADP_CALLBACK(vboxNetAdpPortIsPromiscuous);
917 pNew->MyPort.pfnXmit = NETADP_CALLBACK(vboxNetAdpPortXmit);
918 pNew->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
919 pNew->pSwitchPort = NULL;
920 pNew->pGlobals = pGlobals;
921 pNew->hSpinlock = NIL_RTSPINLOCK;
922 pNew->enmState = kVBoxNetAdpState_Invalid;
923 pNew->cRefs = 0;
924 pNew->cBusy = 0;
925 pNew->hEventIdle = NIL_RTSEMEVENT;
926
927 rc = RTSpinlockCreate(&pNew->hSpinlock);
928 if (RT_SUCCESS(rc))
929 {
930 rc = RTSemEventCreate(&pNew->hEventIdle);
931 if (RT_SUCCESS(rc))
932 {
933 rc = vboxNetAdpOsInit(pNew);
934 if (RT_SUCCESS(rc))
935 {
936 return rc;
937 }
938 RTSemEventDestroy(pNew->hEventIdle);
939 pNew->hEventIdle = NIL_RTSEMEVENT;
940 }
941 RTSpinlockDestroy(pNew->hSpinlock);
942 pNew->hSpinlock = NIL_RTSPINLOCK;
943 }
944 return rc;
945}
946
947static void vboxNetAdpSlotDestroy(PVBOXNETADP pThis)
948{
949 Assert(pThis->cRefs == 0);
950 Assert(pThis->cBusy == 0);
951 Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Invalid);
952 if (pThis->hEventIdle != NIL_RTSEMEVENT)
953 {
954 RTSemEventDestroy(pThis->hEventIdle);
955 pThis->hEventIdle = NIL_RTSEMEVENT;
956 }
957 if (pThis->hSpinlock != NIL_RTSPINLOCK)
958 {
959 RTSpinlockDestroy(pThis->hSpinlock);
960 pThis->hSpinlock = NIL_RTSPINLOCK;
961 }
962}
963
964/**
965 * performs "base" globals deinitialization
966 * we separate the globals settings "base" which is actually
967 * "general" globals settings except for Idc, and idc.
968 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
969 * thus it's not possible to make idc initialization from the driver startup routine for it,
970 * though the "base is still needed for the driver to functions".
971 * @param pGlobals
972 * @return none
973 */
974DECLHIDDEN(void) vboxNetAdpDeleteGlobalsBase(PVBOXNETADPGLOBALS pGlobals)
975{
976 int i;
977 /*
978 * Release resources.
979 */
980 for (i = 0; i < (int)RT_ELEMENTS(pGlobals->aAdapters); i++)
981 if (RT_SUCCESS(vboxNetAdpDestroy(&pGlobals->aAdapters[i])))
982 vboxNetAdpSlotDestroy(&pGlobals->aAdapters[i]);
983
984 RTSemFastMutexDestroy(pGlobals->hFastMtx);
985 pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
986
987#ifdef VBOXNETADP_STATIC_CONFIG
988 RTSemEventDestroy(pGlobals->hTimerEvent);
989 pGlobals->hTimerEvent = NIL_RTSEMEVENT;
990#endif
991
992}
993
994
995/**
996 * Called by the native part when the OS wants the driver to unload.
997 *
998 * @returns VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
999 *
1000 * @param pGlobals Pointer to the globals.
1001 */
1002DECLHIDDEN(int) vboxNetAdpTryDeleteGlobals(PVBOXNETADPGLOBALS pGlobals)
1003{
1004 int rc = vboxNetAdpTryDeleteIdc(pGlobals);
1005 if (RT_SUCCESS(rc))
1006 {
1007 vboxNetAdpDeleteGlobalsBase(pGlobals);
1008 }
1009 return rc;
1010}
1011
1012
1013/**
1014 * performs the "base" globals initialization
1015 * we separate the globals initialization to globals "base" initialization which is actually
1016 * "general" globals initialization except for Idc not being initialized, and idc initialization.
1017 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
1018 * thus it's not possible to make idc initialization from the driver startup routine for it.
1019 *
1020 * @returns VBox status code.
1021 * @param pGlobals Pointer to the globals. */
1022DECLHIDDEN(int) vboxNetAdpInitGlobalsBase(PVBOXNETADPGLOBALS pGlobals)
1023{
1024 /*
1025 * Initialize the common portions of the structure.
1026 */
1027 int i;
1028 int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
1029 if (RT_SUCCESS(rc))
1030 {
1031 memset(pGlobals->aAdapters, 0, sizeof(pGlobals->aAdapters));
1032 for (i = 0; i < (int)RT_ELEMENTS(pGlobals->aAdapters); i++)
1033 {
1034 rc = vboxNetAdpSlotCreate(pGlobals, i, &pGlobals->aAdapters[i]);
1035 if (RT_FAILURE(rc))
1036 {
1037 /* Clean up. */
1038 while (--i >= 0)
1039 vboxNetAdpSlotDestroy(&pGlobals->aAdapters[i]);
1040 Log(("vboxNetAdpInitGlobalsBase: Failed to create fast mutex (rc=%Rrc).\n", rc));
1041 RTSemFastMutexDestroy(pGlobals->hFastMtx);
1042 return rc;
1043 }
1044 }
1045 pGlobals->TrunkFactory.pfnRelease = vboxNetAdpFactoryRelease;
1046 pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetAdpFactoryCreateAndConnect;
1047
1048 strcpy(pGlobals->SupDrvFactory.szName, "VBoxNetAdp");
1049 pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetAdpQueryFactoryInterface;
1050 }
1051
1052 return rc;
1053}
1054
1055/**
1056 * performs the Idc initialization
1057 * we separate the globals initialization to globals "base" initialization which is actually
1058 * "general" globals initialization except for Idc not being initialized, and idc initialization.
1059 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
1060 * thus it's not possible to make idc initialization from the driver startup routine for it.
1061 *
1062 * @returns VBox status code.
1063 * @param pGlobals Pointer to the globals. */
1064DECLHIDDEN(int) vboxNetAdpInitIdc(PVBOXNETADPGLOBALS pGlobals)
1065{
1066 int rc;
1067 /*
1068 * Establish a connection to SUPDRV and register our component factory.
1069 */
1070 rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
1071 if (RT_SUCCESS(rc))
1072 {
1073 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1074 if (RT_SUCCESS(rc))
1075 {
1076#if 1 /** @todo REMOVE ME! */
1077 PVBOXNETADP pTmp;
1078 rc = vboxNetAdpCreate(&pGlobals->TrunkFactory, &pTmp);
1079 if (RT_FAILURE(rc))
1080 Log(("Failed to create vboxnet0, rc=%Rrc.\n", rc));
1081#endif
1082 Log(("VBoxNetAdp: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
1083 return rc;
1084 }
1085
1086 /* bail out. */
1087 LogRel(("VBoxNetAdp: Failed to register component factory, rc=%Rrc\n", rc));
1088 SUPR0IdcClose(&pGlobals->SupDrvIDC);
1089 }
1090
1091 return rc;
1092}
1093
1094/**
1095 * Called by the native driver/kext module initialization routine.
1096 *
1097 * It will initialize the common parts of the globals, assuming the caller
1098 * has already taken care of the OS specific bits.
1099 *
1100 * @returns VBox status code.
1101 * @param pGlobals Pointer to the globals.
1102 */
1103DECLHIDDEN(int) vboxNetAdpInitGlobals(PVBOXNETADPGLOBALS pGlobals)
1104{
1105 /*
1106 * Initialize the common portions of the structure.
1107 */
1108 int rc = vboxNetAdpInitGlobalsBase(pGlobals);
1109 if (RT_SUCCESS(rc))
1110 {
1111 rc = vboxNetAdpInitIdc(pGlobals);
1112 if (RT_SUCCESS(rc))
1113 {
1114 return rc;
1115 }
1116
1117 /* bail out. */
1118 vboxNetAdpDeleteGlobalsBase(pGlobals);
1119 }
1120
1121 return rc;
1122}
1123
1124#else /* !VBOXANETADP_DO_NOT_USE_NETFLT */
1125
1126
1127VBOXNETADP g_aAdapters[VBOXNETADP_MAX_INSTANCES];
1128
1129
1130
1131/**
1132 * Generate a suitable MAC address.
1133 *
1134 * @param pThis The instance.
1135 * @param pMac Where to return the MAC address.
1136 */
1137DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac)
1138{
1139 /* Use a locally administered version of the OUI we use for the guest NICs. */
1140 pMac->au8[0] = 0x08 | 2;
1141 pMac->au8[1] = 0x00;
1142 pMac->au8[2] = 0x27;
1143
1144 pMac->au8[3] = 0; /* pThis->uUnit >> 16; */
1145 pMac->au8[4] = 0; /* pThis->uUnit >> 8; */
1146 pMac->au8[5] = pThis->uUnit;
1147}
1148
1149int vboxNetAdpCreate (PVBOXNETADP *ppNew)
1150{
1151 int rc;
1152 unsigned i;
1153 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1154 {
1155 PVBOXNETADP pThis = &g_aAdapters[i];
1156
1157 if (ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Invalid))
1158 {
1159 RTMAC Mac;
1160 /* Found an empty slot -- use it. */
1161 Log(("vboxNetAdpCreate: found empty slot: %d\n", i));
1162 vboxNetAdpComposeMACAddress(pThis, &Mac);
1163 rc = vboxNetAdpOsCreate(pThis, &Mac);
1164 Log(("vboxNetAdpCreate: pThis=%p pThis->szName=%p\n", pThis, pThis->szName));
1165 if (RT_SUCCESS(rc))
1166 {
1167 *ppNew = pThis;
1168 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Active);
1169 }
1170 else
1171 {
1172 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
1173 Log(("vboxNetAdpCreate: vboxNetAdpOsCreate failed with '%Rrc'.\n", rc));
1174 }
1175 Log2(("VBoxNetAdpCreate: Created %s\n", g_aAdapters[i].szName));
1176 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1177 Log2(("VBoxNetAdpCreate: Scanning entry: state=%d name=%s\n", g_aAdapters[i].enmState, g_aAdapters[i].szName));
1178 return rc;
1179 }
1180 }
1181 Log(("vboxNetAdpCreate: no empty slots!\n"));
1182
1183 /* All slots in adapter array are busy. */
1184 return VERR_OUT_OF_RESOURCES;
1185}
1186
1187int vboxNetAdpDestroy (PVBOXNETADP pThis)
1188{
1189 int rc = VINF_SUCCESS;
1190
1191 if (!ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Active))
1192 return VERR_INTNET_FLT_IF_BUSY;
1193
1194 vboxNetAdpOsDestroy(pThis);
1195
1196 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
1197
1198 return rc;
1199}
1200
1201int vboxNetAdpInit(void)
1202{
1203 unsigned i;
1204 PVBOXNETADP pVboxnet0;
1205 /*
1206 * Init common members and call OS-specific init.
1207 */
1208 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1209 {
1210 g_aAdapters[i].enmState = kVBoxNetAdpState_Invalid;
1211 g_aAdapters[i].uUnit = i;
1212 vboxNetAdpOsInit(&g_aAdapters[i]);
1213 }
1214
1215 /* Create vboxnet0 */
1216 return vboxNetAdpCreate(&pVboxnet0);
1217}
1218
1219/**
1220 * Finds an adapter by its name.
1221 *
1222 * @returns Pointer to the instance by the given name. NULL if not found.
1223 * @param pGlobals The globals.
1224 * @param pszName The name of the instance.
1225 */
1226PVBOXNETADP vboxNetAdpFindByName(const char *pszName)
1227{
1228 unsigned i;
1229
1230 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1231 {
1232 PVBOXNETADP pThis = &g_aAdapters[i];
1233 Log2(("VBoxNetAdp: Scanning entry: state=%d name=%s\n", pThis->enmState, pThis->szName));
1234 if (strncmp(pThis->szName, pszName, VBOXNETADP_MAX_NAME_LEN) == 0)
1235 if (ASMAtomicReadU32((uint32_t volatile *)&pThis->enmState) == kVBoxNetAdpState_Active)
1236 return pThis;
1237 }
1238 return NULL;
1239}
1240
1241void vboxNetAdpShutdown(void)
1242{
1243 unsigned i;
1244
1245 /* Remove virtual adapters */
1246 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1247 vboxNetAdpDestroy(&g_aAdapters[i]);
1248}
1249#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