VirtualBox

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

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

VBoxNetAdp: Build fix and other bits.

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