VirtualBox

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

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

vboxNetAdpComposeMACAddress: readable code, pleease.

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