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