VirtualBox

Changeset 28623 in vbox


Ignore:
Timestamp:
Apr 23, 2010 12:34:14 AM (15 years ago)
Author:
vboxsync
Message:

SrvIntNetR0,VBoxNetFlt: Main body of the internal locking rewrite.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/intnet.h

    r28208 r28623  
    366366    /** Only for the trunk (host/wire). */
    367367    INTNETSWDECISION_TRUNK,
     368    /** Used internally to indicate that the packet cannot be handled in the
     369     * current context. */
     370    INTNETSWDECISION_BAD_CONTEXT,
     371    /** Used internally to indicate that the packet should be dropped. */
     372    INTNETSWDECISION_DROP,
    368373    /** The usual 32-bit type expansion. */
    369374    INTNETSWDECISION_32BIT_HACK = 0x7fffffff
     
    721726
    722727/** The UUID for the (current) trunk factory. (case sensitive) */
    723 #define INTNETTRUNKFACTORY_UUID_STR     "b010afb2-cb4c-44b7-9da9-1e113cfcd47c"
     728#define INTNETTRUNKFACTORY_UUID_STR     "daeaf07b-9974-48be-843e-b9afd763c2ff"
    724729
    725730/** @name INTNETTRUNKFACTORY::pfnCreateAndConnect flags.
  • trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp

    r28488 r28623  
    3131#include <VBox/pdm.h>
    3232#include <VBox/log.h>
     33
    3334#include <iprt/asm.h>
    34 #include <iprt/alloc.h>
     35#include <iprt/assert.h>
     36#include <iprt/handletable.h>
     37#include <iprt/mp.h>
     38#include <iprt/mem.h>
     39#include <iprt/net.h>
    3540#include <iprt/semaphore.h>
    3641#include <iprt/spinlock.h>
     42#include <iprt/string.h>
    3743#include <iprt/thread.h>
    38 #include <iprt/assert.h>
    39 #include <iprt/string.h>
    4044#include <iprt/time.h>
    41 #include <iprt/handletable.h>
    42 #include <iprt/net.h>
    4345
    4446
     
    5052#define INTNET_WITH_DHCP_SNOOPING
    5153
     54/** The maximum number of interface in a network. */
     55#define INTNET_MAX_IFS              (1023 + 1 + 16)
     56
     57/** The number of entries to grow the destination tables with. */
    5258#if 0
    53 /** Enables the new code - temporarily while doing the rewrite. */
    54 # define WITH_NEW_STUFF
     59# define INTNET_GROW_DSTTAB_SIZE    16
     60#else
     61# define INTNET_GROW_DSTTAB_SIZE    1
    5562#endif
    5663
     64/** The wakeup bit in the INTNETIF::cBusy and INTNETRUNKIF::cBusy counters. */
     65#define INTNET_BUSY_WAKEUP_MASK     RT_BIT_32(30)
    5766
    5867
     
    6069*   Structures and Typedefs                                                    *
    6170*******************************************************************************/
    62 #ifdef WITH_NEW_STUFF
    6371/**
    6472 * MAC address lookup table entry.
     
    8088/** Pointer to a MAC address lookup table entry. */
    8189typedef INTNETMACTABENTRY *PINTNETMACTABENTRY;
    82 /** Pointer to a const MAC address lookup table entry. */
    83 typedef INTNETMACTABENTRY const *PCINTNETMACTABENTRY;
    8490
    8591/**
    8692 * MAC address lookup table.
     93 *
     94 * @todo Having this in a separate structure didn't work out as well as it
     95 *       should.  Consider merging it into INTNETNETWORK.
    8796 */
    8897typedef struct INTNETMACTAB
    8998{
    90     /** The spinlock protecting the table, interrupt safe. */
    91     RTSPINLOCK              hSpinlock;
    9299    /** The current number of entries. */
    93100    uint32_t                cEntries;
     
    95102    uint32_t                cEntriesAllocated;
    96103    /** Table entries. */
    97     PCINTNETMACTABENTRY     paEntries;
    98 
    99     /** The host MAC address. */
     104    PINTNETMACTABENTRY      paEntries;
     105
     106    /** The host MAC address (reported). */
    100107    RTMAC                   HostMac;
    101     /** The host promiscous setting. */
     108    /** The host promisucous setting (reported). */
    102109    bool                    fHostPromiscuous;
    103110    /** Whether the host is active. */
    104111    bool                    fHostActive;
    105112
    106     /** Whether the wire is promiscuous. */
     113    /** Whether the wire is promiscuous (config). */
    107114    bool                    fWirePromiscuous;
    108115    /** Whether the wire is active. */
     
    127134    uint32_t                cIfs;
    128135    /** The interfaces (referenced).  Variable sized array. */
    129     struct INTNETIF        *apIfs[1];
     136    struct
     137    {
     138        /** The destination interface. */
     139        struct INTNETIF    *pIf;
     140        /** Whether to replace the destination MAC address.
     141         * This is used when sharing MAC address with the host on the wire(less).  */
     142        bool                fReplaceDstMac;
     143    }                       aIfs[1];
    130144} INTNETDSTTAB;
    131145/** Pointer to a destination table. */
    132146typedef INTNETDSTTAB *PINTNETDSTTAB;
    133 #endif /* WITH_NEW_STUFF */
     147/** Pointer to a const destination table. */
     148typedef INTNETDSTTAB const *PCINTNETDSTTAB;
    134149
    135150
     
    199214typedef struct INTNETIF
    200215{
    201     /** Pointer to the next interface.
    202      * This is protected by the INTNET::FastMutex. */
    203     struct INTNETIF        *pNext;
    204     /** The current MAC address for the interface. (reported or learned)
    205      * Updated while owning the switch table spinlock.  */
    206     RTMAC                   Mac;
    207     /** Set if the INTNET::Mac member is valid. */
     216    /** The MAC address.
     217     * This is shadowed by INTNETMACTABENTRY::MacAddr. */
     218    RTMAC                   MacAddr;
     219    /** Set if the INTNET::MacAddr member has been explicitly set. */
    208220    bool                    fMacSet;
    209221    /** Set if the interface is in promiscuous mode.
    210      * In promiscuous mode the interface will receive all packages except the one it's sending. */
     222     * This is shadowed by INTNETMACTABENTRY::fPromiscuous. */
    211223    bool                    fPromiscuous;
    212     /** Whether the interface is active or not. */
     224    /** Whether the interface is active or not.
     225     * This is shadowed by INTNETMACTABENTRY::fActive. */
    213226    bool                    fActive;
    214227    /** Whether someone is currently in the destructor. */
     
    227240    /** Pointer to ring-3 mapping of the default exchange buffer. */
    228241    R3PTRTYPE(PINTNETBUF)   pIntBufDefaultR3;
    229     /** Event semaphore which a receiver thread will sleep on while waiting
    230      * for data to arrive. */
    231     RTSEMEVENT volatile     Event;
    232     /** Number of threads sleeping on the Event semaphore. */
     242    /** Event semaphore which a receiver/consumer thread will sleep on while
     243     * waiting for data to arrive. */
     244    RTSEMEVENT volatile     hRecvEvent;
     245    /** Number of threads sleeping on the event semaphore. */
    233246    uint32_t                cSleepers;
    234247    /** The interface handle.
     
    237250    INTNETIFHANDLE volatile hIf;
    238251    /** Pointer to the network this interface is connected to.
    239      * This is protected by the INTNET::FastMutex. */
     252     * This is protected by the INTNET::hMtxCreateOpenDestroy. */
    240253    struct INTNETNETWORK   *pNetwork;
    241254    /** The session this interface is associated with. */
     
    243256    /** The SUPR0 object id. */
    244257    void                   *pvObj;
    245     /** The network layer address cache. (Indexed by type, 0 entry isn't used.) */
     258    /** The network layer address cache. (Indexed by type, 0 entry isn't used.)
     259     * This is protected by the address spinlock of the network. */
    246260    INTNETADDRCACHE         aAddrCache[kIntNetAddrType_End];
    247 #ifdef WITH_NEW_STUFF
    248261    /** Spinlock protecting the input (producer) side of the receive ring. */
    249262    RTSPINLOCK              hRecvInSpinlock;
    250263    /** Busy count for tracking destination table references and active sends.
    251      * Incremented while owning the switch table spinlock. */
     264     * Usually incremented while owning the switch table spinlock.  The 30th bit
     265     * is used to indicate wakeup. */
    252266    uint32_t volatile       cBusy;
    253     /** Set if a someone is waiting on INTNETNETWORK::hEvtBusyIf for cBusy to
    254      * reach zero. */
    255     bool volatile           fBusyZeroWakeup;
    256267    /** The preallocated destination table.
    257268     * This is NULL when it's in use as a precaution against unserialized
    258269     * transmitting.  This is grown when new interfaces are added to the network. */
    259270    PINTNETDSTTAB volatile  pDstTab;
    260 #endif /* WITH_NEW_STUFF */
    261271} INTNETIF;
    262272/** Pointer to an internal network interface. */
     
    273283    /** The port interface we get from the component. */
    274284    PINTNETTRUNKIFPORT      pIfPort;
    275 #ifdef WITH_NEW_STUFF
     285    /** The trunk mutex that serializes all calls <b>to</b> the component. */
    276286    /** @todo This won't quite cut the mustard any longer.  That said, GSO
    277287     *        segmentation needs to be serialized because of the header buffer. */
    278     RTSEMFASTMUTEX          FastMutex;
    279 #else
    280     /** The trunk mutex that serializes all calls <b>to</b> the component. */
    281     RTSEMFASTMUTEX          FastMutex;
    282 #endif
     288    RTSEMFASTMUTEX          FastMutex3;
    283289    /** Pointer to the network we're connect to.
    284290     * This may be NULL if we're orphaned? */
    285291    struct INTNETNETWORK   *pNetwork;
    286 #ifdef WITH_NEW_STUFF
    287292    /** The current MAC address for the interface. (reported)
    288      * Updated while owning the switch table spinlock.
    289      * @todo rename to Mac  */
    290     RTMAC                   CachedMac;
    291 #else
    292     /** The cached MAC address of the interface the trunk is attached to.
    293      * This is for the situations where we cannot take the out-bound
    294      * semaphore (the recv case) but need to make frame edits (ARP). */
    295     RTMAC                   CachedMac;
    296 #endif
    297 #ifndef WITH_NEW_STUFF
    298     /** Whether to supply physical addresses with the outbound SGs. (reported) */
    299     bool volatile           fPhysSG;
    300     /** Set if the 'wire' is in promiscuous mode.
    301      * The state of the 'host' is queried each time. */
    302     bool                    fWirePromiscuous;
    303 #else  /* WITH_NEW_STUFF */
    304     /** Set if the 'wire' is in promiscuous mode. (config) */
    305     bool                    fWirePromiscuous;
    306     /** Set if the 'host' is in promiscuous mode. (reported) */
    307     bool volatile           fHostPromiscuous;
     293     * Updated while owning the switch table spinlock.  */
     294    RTMAC                   MacAddr;
    308295    /** Can pfnXmit cope with disabled preemption for the 'wire'. (reported) */
    309296    bool                    fWireNoPreempt;
     
    312299    /** Whether to supply physical addresses with the outbound SGs. (reported) */
    313300    bool                    fPhysSG;
    314     /** Set if a someone is waiting on INTNETNETWORK::hEvtBusyIf for cBusy to
    315      * reach zero. */
    316     bool volatile           fBusyZeroWakeup;
    317301    /** Busy count for tracking destination table references and active sends.
    318      * Incremented while owning the switch table spinlock. */
     302     * Usually incremented while owning the switch table spinlock.  The 30th bit
     303     * is used to indicate wakeup. */
    319304    uint32_t volatile       cBusy;
    320 #endif /* WITH_NEW_STUFF */
    321305    /** The GSO capabilities of the wire destination. (reported) */
    322306    uint32_t                fWireGsoCapabilites;
     
    327311    /** Header buffer for when we're carving GSO frames. */
    328312    uint8_t                 abGsoHdrs[256];
    329 #ifdef WITH_NEW_STUFF
    330     /** @todo what exactly to do about the destination tables here? how many do
    331      *        we need / want? One? One per CPU? */
    332 #endif
     313    /** The destination table spinlock, interrupt safe.
     314     * Protects apTaskDstTabs and apIntDstTabs. */
     315    RTSPINLOCK              hDstTabSpinlock;
     316    /** The number of entries in apIntDstTabs. */
     317    uint32_t                cIntDstTabs;
     318    /** The task time destination tables.
     319     * @remarks intnetR0NetworkEnsureTabSpace and others ASSUMES this immediately
     320     *          preceeds apIntDstTabs so that these two tables can be used as one
     321     *          contiguous one. */
     322    PINTNETDSTTAB           apTaskDstTabs[2];
     323    /** The interrupt / disabled-preemption time destination tables.
     324     * This is a variable sized array.  */
     325    PINTNETDSTTAB           apIntDstTabs[1];
    333326} INTNETTRUNKIF;
    334327/** Pointer to a trunk interface. */
     
    345338{
    346339    /** The Next network in the chain.
    347      * This is protected by the INTNET::FastMutex. */
     340     * This is protected by the INTNET::hMtxCreateOpenDestroy. */
    348341    struct INTNETNETWORK   *pNext;
    349     /** List of interfaces connected to the network.
    350      * This is protected by the INTNET::FastMutex. */
    351     PINTNETIF               pIfs;
    352     /** Pointer to the trunk interface.
    353      * Can be NULL if there is no trunk connection. */
    354     PINTNETTRUNKIF          pTrunkIF;
    355     /** The network mutex.
    356      * It protects everything dealing with this network. */
    357 #ifdef WITH_NEW_STUFF
    358     /** @todo Make this a mutex so we can block on the event semaphore while holding
    359      *        it. Requires fixing the mutex code on linux...  Or maybe add
    360      *        another mutex for creation / destruction serilization. */
    361 #endif
    362     RTSEMFASTMUTEX          FastMutex2;
    363 #ifdef WITH_NEW_STUFF
     342
     343    /** The spinlock protecting MacTab and INTNETTRUNKIF::aAddrCache.
     344     *  Interrupt safe. */
     345    RTSPINLOCK              hAddrSpinlock;
     346    /** MAC address table.
     347     * This doubles as interface collection. */
     348    INTNETMACTAB            MacTab;
     349
    364350    /** Wait for an interface to stop being busy so it can be removed or have its
    365351     * destination table replaced.  We have to wait upon this while owning the
    366      * network mutex. */
     352     * network mutex.  Will only ever have one waiter because of the big mutex. */
    367353    RTSEMEVENT              hEvtBusyIf;
    368 #endif
    369354    /** Pointer to the instance data. */
    370355    struct INTNET          *pIntNet;
     
    606591
    607592
    608 #ifdef WITH_NEW_STUFF
    609 
    610 /**
    611  * Compares two MAC addresses.
    612  *
    613  * @returns true if equal, false if not.
    614  * @param   pDstAddr1           Address 1.
    615  * @param   pDstAddr2           Address 2.
    616  */
    617 DECL_FORCE_INLINE(bool) intnetR0AreMacAddrsEqual(PCRTMAC pDstAddr1, PCRTMAC pDstAddr2)
    618 {
    619     return pDstAddr1->au16[2] == pDstAddr2->au16[2]
    620         && pDstAddr1->au16[1] == pDstAddr2->au16[1]
    621         && pDstAddr1->au16[0] == pDstAddr2->au16[0];
    622 }
    623 
    624 
    625 /**
    626  * Switch a MAC address and return a destination table.
    627  *
    628  * @returns Destination table or NULL if *ppDstTab is NULL.
    629  * @param   pTab                The MAC address table to work on.
    630  * @param   pDstAddr            The destination address of the packet.
    631  * @param   ppDstTab            Where to get the destination table from.
    632  * @param   pcBusy              The busy counter to increment if *ppDstTab isn't
    633  *                              NULL.
    634  */
    635 static PINTNETDSTTAB intnetR0MacTabSwitch(PINTNETMACTAB pTab, PCRTMAC pDstAddr,
    636                                           PINTNETDSTTAB volatile *ppDstTab, uint32_t volatile *pcBusy)
    637 {
    638     /*
    639      * Grab the spinlock first, then get the destination table and increment
    640      * the busy counter (to indicate that we're using the dst tab and it cannot
    641      * be freed yet).
    642      */
    643     RTSPINLOCKTMP   Tmp     = RTSPINLOCKTMP_INITIALIZER;
    644     RTSpinlockAcquire(pTab->hSpinlock, &Tmp);
    645     PINTNETDSTTAB   pDstTab = (PINTNETDSTTAB)ASMAtomicXchgPtr((void * volatile *)ppDstTab, NULL);
    646     if (pDstTab)
    647     {
    648         ASMAtomicIncU32(pcBusy);
    649 
    650         /*
    651          * Do the switching.
    652          */
    653         pDstTab->fTrunkDst = 0;
    654         pDstTab->pTrunk    = 0;
    655         pDstTab->cIfs      = 0;
    656 
    657         uint32_t i = pTab->cEntries;
    658         if (pDstAddr->au8[0] & 1) /* multicast or broadcast address */
    659         {
    660             /* Broadcast/multicast - add all active interfaces. */
    661             while (i-- > 0)
    662             {
    663                 if (pTab->paEntries[i].fActive)
    664                 {
    665                     PINTNETIF pIf = pTab->paEntries[i].pIf;
    666                     pDstTab->apIfs[i] = pIf;
    667                     ASMAtomicIncU32(&pIf->cBusy);
    668                     pDstTab->cIfs++;
    669                 }
    670             }
    671 
    672             if (pTab->fHostActive)
    673                 pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
    674             if (pTab->fWireActive)
    675                 pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
    676         }
    677         else
    678         {
    679             /* Find exactly matching or promiscuous interfaces. */
    680             uint32_t cExactHits = 0;
    681             while (i-- > 0)
    682             {
    683                 if (pTab->paEntries[i].fActive)
    684                 {
    685                     bool fExact = intnetR0AreMacAddrsEqual(&pTab->paEntries[i].MacAddr, pDstAddr);
    686                     if (fExact || pTab->paEntries[i].fPromiscuous)
    687                     {
    688                         cExactHits += fExact;
    689 
    690                         PINTNETIF pIf = pTab->paEntries[i].pIf;
    691                         pDstTab->apIfs[i] = pIf;
    692                         ASMAtomicIncU32(&pIf->cBusy);
    693                         pDstTab->cIfs++;
    694                     }
    695                 }
    696             }
    697 
    698             /* Does it match the host, or is the host promiscuous? */
    699             if (pTab->fHostActive)
    700             {
    701                 bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstAddr);
    702                 if (pTab->fHostPromiscuous)
    703                 {
    704                     cExactHits += fExact;
    705                     pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
    706                 }
    707             }
    708 
    709             /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */
    710             if (pTab->fWireActive && (!cExactHits || pTab->fWirePromiscuous))
    711                 pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
    712         }
    713 
    714         /* Grab the trunk if we're sending to it. */
    715         if (pDstTab->fTrunkDst)
    716         {
    717             PINTNETTRUNKIF pTrunkIf = pTab->pTrunk;
    718             pDstTab->pTrunk = pTrunkIf;
    719             ASMAtomicIncU32(&pTrunkIf->cBusy);
    720         }
    721     }
    722 
    723     RTSpinlockRelease(pTab->hSpinlock, &Tmp);
    724     return pDstTab;
    725 }
    726 
    727 
    728 #endif /* WITH_NEW_STUFF */
     593/**
     594 * Wait for a busy counter to reach zero.
     595 *
     596 * @param   pNetwork            The network.
     597 * @param   pcBusy              The busy counter.
     598 */
     599static void intnetR0BusyWait(PINTNETNETWORK pNetwork, uint32_t volatile *pcBusy)
     600{
     601    if (ASMAtomicReadU32(pcBusy) == 0)
     602        return;
     603
     604    /*
     605     * We have to be a bit cautious here so we don't destroy the network or the
     606     * semaphore before intnetR0BusyDec has signalled us.
     607     */
     608
     609    /* Reset the semaphore and flip the wakeup bit. */
     610    RTSemEventWait(pNetwork->hEvtBusyIf, 0); /* clear it */
     611    uint32_t cCurBusy = ASMAtomicReadU32(pcBusy);
     612    do
     613    {
     614        if (cCurBusy == 0)
     615            return;
     616        AssertMsg(!(cCurBusy & INTNET_BUSY_WAKEUP_MASK), ("%#x\n", cCurBusy));
     617        AssertMsg((cCurBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cCurBusy));
     618    } while (!ASMAtomicCmpXchgExU32(pcBusy, cCurBusy | INTNET_BUSY_WAKEUP_MASK, cCurBusy, &cCurBusy));
     619
     620    /* Wait for the count to reach zero. */
     621    do
     622    {
     623        int rc2 = RTSemEventWait(pNetwork->hEvtBusyIf, 30000); NOREF(rc2);
     624        //AssertMsg(RT_SUCCESS(rc2),  ("rc=%Rrc *pcBusy=%#x (%#x)\n", rc2, ASMAtomicReadU32(pcBusy), cCurBusy ));
     625        cCurBusy = ASMAtomicReadU32(pcBusy);
     626        AssertMsg((cCurBusy & INTNET_BUSY_WAKEUP_MASK), ("%#x\n", cCurBusy));
     627        AssertMsg((cCurBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cCurBusy));
     628    } while (   cCurBusy != INTNET_BUSY_WAKEUP_MASK
     629             || ASMAtomicCmpXchgU32(pcBusy, 0, INTNET_BUSY_WAKEUP_MASK));
     630}
     631
     632
     633/**
     634 * Decrements the busy counter and maybe wakes up any threads waiting for it to
     635 * reach zero.
     636 *
     637 * @param   pNetwork            The network.
     638 * @param   pcBusy              The busy counter.
     639 */
     640DECLINLINE(void) intnetR0BusyDec(PINTNETNETWORK pNetwork, uint32_t volatile *pcBusy)
     641{
     642    uint32_t cNewBusy = ASMAtomicDecU32(pcBusy);
     643    if (RT_UNLIKELY(   cNewBusy == INTNET_BUSY_WAKEUP_MASK
     644                    && pNetwork))
     645        RTSemEventSignal(pNetwork->hEvtBusyIf);
     646    AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy));
     647}
     648
     649
     650/**
     651 * Increments the busy count of the specified interface.
     652 *
     653 * The caller must own the MAC address table spinlock.
     654 *
     655 * @param   pIf                 The interface.
     656 */
     657DECLINLINE(void) intnetR0BusyDecIf(PINTNETIF pIf)
     658{
     659    intnetR0BusyDec(pIf->pNetwork, &pIf->cBusy);
     660}
     661
     662
     663/**
     664 * Increments the busy count of the specified interface.
     665 *
     666 * The caller must own the MAC address table spinlock or an explicity reference.
     667 *
     668 * @param   pTrunk              The trunk.
     669 */
     670DECLINLINE(void) intnetR0BusyDecTrunk(PINTNETTRUNKIF pTrunk)
     671{
     672    intnetR0BusyDec(pTrunk->pNetwork, &pTrunk->cBusy);
     673}
     674
     675
     676/**
     677 * Increments the busy count of the specified interface.
     678 *
     679 * The caller must own the MAC address table spinlock or an explicity reference.
     680 *
     681 * @param   pIf                 The interface.
     682 */
     683DECLINLINE(void) intnetR0BusyIncIf(PINTNETIF pIf)
     684{
     685    uint32_t cNewBusy = ASMAtomicIncU32(&pIf->cBusy);
     686    AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy));
     687    NOREF(cNewBusy);
     688}
     689
     690
     691/**
     692 * Increments the busy count of the specified interface.
     693 *
     694 * The caller must own the MAC address table spinlock or an explicity reference.
     695 *
     696 * @param   pTrunk              The trunk.
     697 */
     698DECLINLINE(void) intnetR0BusyIncTrunk(PINTNETTRUNKIF pTrunk)
     699{
     700    uint32_t cNewBusy = ASMAtomicIncU32(&pTrunk->cBusy);
     701    AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy));
     702    NOREF(cNewBusy);
     703}
    729704
    730705
     
    784759
    785760
    786 
     761/**
     762 * Checks if the interface has a usable MAC address or not.
     763 *
     764 * @returns true if MacAddr is usable, false if not.
     765 * @param   pIf                 The interface.
     766 */
     767DECL_FORCE_INLINE(bool) intnetR0IfHasMacAddr(PINTNETIF pIf)
     768{
     769    return pIf->fMacSet || !(pIf->MacAddr.au8[0] & 1);
     770}
     771
     772
     773/**
     774 * Locates the MAC address table entry for the given interface.
     775 *
     776 * The caller holds the MAC address table spinlock, obviously.
     777 *
     778 * @returns Pointer to the entry on if found, NULL if not.
     779 * @param   pNetwork        The network.
     780 * @param   pIf             The interface.
     781 */
     782DECLINLINE(PINTNETMACTABENTRY) intnetR0NetworkFindMacAddrEntry(PINTNETNETWORK pNetwork, PINTNETIF pIf)
     783{
     784    uint32_t iIf = pNetwork->MacTab.cEntries;
     785    while (iIf-- > 0)
     786    {
     787        if (pNetwork->MacTab.paEntries[iIf].pIf == pIf)
     788            return &pNetwork->MacTab.paEntries[iIf];
     789    }
     790    return NULL;
     791}
    787792
    788793
     
    10211026        case kIntNetAddrType_IPv4:
    10221027            Log(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",
    1023                  pIf->hIf, &pIf->Mac, iEntry, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
     1028                 pIf->hIf, &pIf->MacAddr, iEntry, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
    10241029            break;
    10251030        default:
    10261031            Log(("intnetR0IfAddrCacheDeleteIt: hIf=%RX32 MAC=%.6Rhxs type=%d #%d %.*Rhxs %s\n",
    1027                  pIf->hIf, &pIf->Mac, enmAddrType, iEntry, pCache->cbAddress, pAddr, pszMsg));
     1032                 pIf->hIf, &pIf->MacAddr, enmAddrType, iEntry, pCache->cbAddress, pAddr, pszMsg));
    10281033            break;
    10291034    }
     
    10411046 * Deletes an address from the cache, assuming it isn't actually in the cache.
    10421047 *
     1048 * May or may not own the spinlock when calling this.
     1049 *
    10431050 * @param   pIf             The interface (for logging).
    10441051 * @param   pCache          The cache.
     
    10691076                                                uint8_t const cbAddr, const char *pszMsg)
    10701077{
    1071     for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext)
    1072     {
     1078    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     1079    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1080
     1081    uint32_t iIf = pNetwork->MacTab.cEntries;
     1082    while (iIf--)
     1083    {
     1084        PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf;
    10731085        int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
    10741086        if (RT_UNLIKELY(i >= 0))
    10751087            intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg);
    10761088    }
     1089
     1090    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
    10771091}
    10781092
     
    10931107                                                       INTNETADDRTYPE const enmType, uint8_t const cbAddr, const char *pszMsg)
    10941108{
    1095     for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext)
     1109    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     1110    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1111
     1112    uint32_t iIf = pNetwork->MacTab.cEntries;
     1113    while (iIf--)
     1114    {
     1115        PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf;
    10961116        if (pIf != pIfSender)
    10971117        {
     
    11001120                intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg);
    11011121        }
     1122    }
     1123
     1124    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
    11021125}
    11031126
     
    11071130 * having it in its address cache.
    11081131 *
    1109  * @returns Pointer to the interface on success, NULL if not found.
     1132 * @returns Pointer to the interface on success, NULL if not found.  The caller
     1133 *          must release the interface by calling intnetR0BusyDecIf.
    11101134 * @param   pNetwork        The network.
    11111135 * @param   pAddr           The address to lookup.
     
    11151139DECLINLINE(PINTNETIF) intnetR0NetworkAddrCacheLookupIf(PINTNETNETWORK pNetwork, PCRTNETADDRU pAddr, INTNETADDRTYPE const enmType, uint8_t const cbAddr)
    11161140{
    1117     for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext)
    1118     {
     1141    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     1142    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1143
     1144    uint32_t iIf = pNetwork->MacTab.cEntries;
     1145    while (iIf--)
     1146    {
     1147        PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf;
    11191148        int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
    11201149        if (i >= 0)
     1150        {
     1151            intnetR0BusyIncIf(pIf);
     1152            RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
    11211153            return pIf;
    1122     }
     1154        }
     1155    }
     1156
     1157    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
    11231158    return NULL;
    11241159}
     
    11261161
    11271162/**
    1128  * Adds an address to the cache, the caller is responsible for making sure it'
    1129  * s not already in the cache.
     1163 * Adds an address to the cache, the caller is responsible for making sure it's
     1164 * not already in the cache.
     1165 *
     1166 * The caller must not
    11301167 *
    11311168 * @param   pIf         The interface (for logging).
     
    11361173static void intnetR0IfAddrCacheAddIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, const char *pszMsg)
    11371174{
     1175    PINTNETNETWORK  pNetwork = pIf->pNetwork;
     1176    AssertReturnVoid(pNetwork);
     1177    RTSPINLOCKTMP   Tmp      = RTSPINLOCKTMP_INITIALIZER;
     1178    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1179
    11381180    if (!pCache->cEntriesAlloc)
    11391181    {
    1140         /* Allocate the first array */
    1141         pCache->pbEntries = (uint8_t *)RTMemAllocZ(pCache->cbEntry * 16);
    1142         if (!pCache->pbEntries)
     1182        /* Allocate the table - 64 entries. */
     1183        RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1184        uint8_t *pbEntries = (uint8_t *)RTMemAllocZ(pCache->cbEntry * 64);
     1185        if (!pbEntries)
    11431186            return;
    1144         pCache->cEntriesAlloc = 16;
    1145     }
    1146     else if (pCache->cEntries >= pCache->cEntriesAlloc)
    1147     {
    1148         bool fReplace = true;
    1149         if (pCache->cEntriesAlloc < 64)
     1187        RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1188        if (!pCache->cEntriesAlloc)
    11501189        {
    1151             uint8_t cEntriesAlloc = pCache->cEntriesAlloc + 16;
    1152             void *pvNew = RTMemRealloc(pCache->pbEntries, pCache->cbEntry * cEntriesAlloc);
    1153             if (pvNew)
    1154             {
    1155                 pCache->pbEntries = (uint8_t *)pvNew;
    1156                 pCache->cEntriesAlloc = cEntriesAlloc;
    1157                 fReplace = false;
    1158             }
     1190            pCache->pbEntries     = pbEntries;
     1191            pCache->cEntriesAlloc = 64;
    11591192        }
    1160         if (fReplace)
     1193        else
    11611194        {
    1162             /* simple FIFO, might consider usage/ageing here... */
    1163             Log(("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n",
    1164                  (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cbAddress, pCache->pbEntries));
    1165             memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1));
    1166             pCache->cEntries--;
     1195            RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1196            RTMemFree(pbEntries);
     1197            RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
    11671198        }
     1199    }
     1200    else
     1201    {
     1202        /* simple FIFO, might consider usage/ageing here... */
     1203        Log(("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n",
     1204             (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cbAddress, pCache->pbEntries));
     1205        memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1));
     1206        pCache->cEntries--;
    11681207    }
    11691208
     
    11801219        case kIntNetAddrType_IPv4:
    11811220            Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",
    1182                  pIf->hIf, &pIf->Mac, pCache->cEntries, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
     1221                 pIf->hIf, &pIf->MacAddr, pCache->cEntries, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
    11831222            break;
    11841223        default:
    11851224            Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs type=%d added #%d %.*Rhxs %s\n",
    1186                  pIf->hIf, &pIf->Mac, enmAddrType, pCache->cEntries, pCache->cbAddress, pAddr, pszMsg));
     1225                 pIf->hIf, &pIf->MacAddr, enmAddrType, pCache->cEntries, pCache->cbAddress, pAddr, pszMsg));
    11871226            break;
    11881227    }
     
    11901229    pCache->cEntries++;
    11911230    Assert(pCache->cEntries <= pCache->cEntriesAlloc);
     1231
     1232    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
    11921233}
    11931234
     
    12281269 * Adds an address to the cache if it's not already there.
    12291270 *
     1271 * Must not own any spinlocks when calling this function.
     1272 *
    12301273 * @param   pIf         The interface (for logging).
    12311274 * @param   pCache      The address cache.
     
    12341277 * @param   pszMsg      Log message.
    12351278 */
    1236 DECLINLINE(void) intnetR0IfAddrCacheAdd(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr, const char *pszMsg)
     1279DECLINLINE(void) intnetR0IfAddrCacheAdd(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr,
     1280                                        uint8_t const cbAddr, const char *pszMsg)
    12371281{
    12381282    Assert(pCache->cbAddress == cbAddr);
     
    12491293    intnetR0IfAddrCacheAddSlow(pIf, pCache, pAddr, cbAddr, pszMsg);
    12501294}
     1295
     1296
     1297/**
     1298 * Is it a multicast or broadcast MAC address?
     1299 *
     1300 * @returns true if multicast, false if not.
     1301 * @param   pMacAddr            The address to inspect.
     1302 */
     1303DECL_FORCE_INLINE(bool) intnetR0IsMacAddrMulticast(PCRTMAC pMacAddr)
     1304{
     1305    return !!(pMacAddr->au8[0] & 0x01);
     1306}
     1307
     1308
     1309/**
     1310 * Is it a dummy MAC address?
     1311 *
     1312 * We use dummy MAC addresses for interfaces which we don't know the MAC
     1313 * address of because they haven't sent anything (learning) or explicitly set
     1314 * it.
     1315 *
     1316 * @returns true if dummy, false if not.
     1317 * @param   pMacAddr            The address to inspect.
     1318 */
     1319DECL_FORCE_INLINE(bool) intnetR0IsMacAddrDummy(PCRTMAC pMacAddr)
     1320{
     1321    /* The dummy address are broadcast addresses, don't bother check it all. */
     1322    return pMacAddr->au16[0] == 0xffff;
     1323}
     1324
     1325
     1326/**
     1327 * Compares two MAC addresses.
     1328 *
     1329 * @returns true if equal, false if not.
     1330 * @param   pDstAddr1           Address 1.
     1331 * @param   pDstAddr2           Address 2.
     1332 */
     1333DECL_FORCE_INLINE(bool) intnetR0AreMacAddrsEqual(PCRTMAC pDstAddr1, PCRTMAC pDstAddr2)
     1334{
     1335    return pDstAddr1->au16[2] == pDstAddr2->au16[2]
     1336        && pDstAddr1->au16[1] == pDstAddr2->au16[1]
     1337        && pDstAddr1->au16[0] == pDstAddr2->au16[0];
     1338}
     1339
     1340
     1341/**
     1342 * Switch a unicast frame based on the network layer address (OSI level 3) and
     1343 * return a destination table.
     1344 *
     1345 * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
     1346 *          INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
     1347 * @param   pNetwork            The network to switch on.
     1348 * @param   pDstMacAddr         The destination MAC address.
     1349 * @param   enmL3AddrType       The level-3 destination address type.
     1350 * @param   pL3Addr             The level-3 destination address.
     1351 * @param   cbL3Addr            The size of the level-3 destination address.
     1352 * @param   fSrc                The frame source (INTNETTRUNKDIR_WIRE).
     1353 * @param   pDstTab             The destination output table.
     1354 */
     1355static INTNETSWDECISION intnetR0NetworkSwitchLevel3(PINTNETNETWORK pNetwork, PCRTMAC pDstMacAddr,
     1356                                                    INTNETADDRTYPE enmL3AddrType, PCRTNETADDRU pL3Addr, uint8_t cbL3Addr,
     1357                                                    uint32_t fSrc, PINTNETDSTTAB pDstTab)
     1358{
     1359    Assert(fSrc == INTNETTRUNKDIR_WIRE);
     1360
     1361    /*
     1362     * Grab the spinlock first and do the switching.
     1363     */
     1364    PINTNETMACTAB   pTab    = &pNetwork->MacTab;
     1365    RTSPINLOCKTMP   Tmp     = RTSPINLOCKTMP_INITIALIZER;
     1366    RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp);
     1367
     1368    pDstTab->fTrunkDst  = 0;
     1369    pDstTab->pTrunk     = 0;
     1370    pDstTab->cIfs       = 0;
     1371
     1372    /* Find exactly matching or promiscuous interfaces. */
     1373    uint32_t cExactHits = 0;
     1374    uint32_t iIfMac     = pTab->cEntries;
     1375    while (iIfMac-- > 0)
     1376    {
     1377        if (pTab->paEntries[iIfMac].fActive)
     1378        {
     1379            PINTNETIF pIf    = pTab->paEntries[iIfMac].pIf;         AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
     1380            bool      fExact = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmL3AddrType], pL3Addr, cbL3Addr);
     1381            if (fExact || pTab->paEntries[iIfMac].fPromiscuous)
     1382            {
     1383                cExactHits += fExact;
     1384
     1385                uint32_t iIfDst = pDstTab->cIfs++;
     1386                pDstTab->aIfs[iIfDst].pIf            = pIf;
     1387                pDstTab->aIfs[iIfDst].fReplaceDstMac = fExact;
     1388                intnetR0BusyIncIf(pIf);
     1389            }
     1390        }
     1391    }
     1392
     1393    /* Does it match the host, or is the host promiscuous? */
     1394    if (pTab->fHostActive)
     1395    {
     1396        bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstMacAddr);
     1397        if (   fExact
     1398            || intnetR0IsMacAddrDummy(&pTab->HostMac)
     1399            || pTab->fHostPromiscuous)
     1400        {
     1401            cExactHits += fExact;
     1402            pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
     1403        }
     1404    }
     1405
     1406    /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */
     1407    if (pTab->fWireActive && (!cExactHits || pTab->fWirePromiscuous))
     1408        pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
     1409    pDstTab->fTrunkDst &= ~fSrc;
     1410    if (pDstTab->fTrunkDst)
     1411    {
     1412        PINTNETTRUNKIF pTrunk = pTab->pTrunk;
     1413        pDstTab->pTrunk = pTrunk;
     1414        intnetR0BusyIncTrunk(pTrunk);
     1415    }
     1416
     1417    RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp);
     1418    return pDstTab->cIfs
     1419         ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST)
     1420         : (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP   : INTNETSWDECISION_TRUNK);
     1421}
     1422
     1423
     1424/**
     1425 * Switch a unicast MAC address and return a destination table.
     1426 *
     1427 * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
     1428 *          INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
     1429 * @param   pNetwork            The network to switch on.
     1430 * @param   fSrc                The frame source.
     1431 * @param   pIfSender           The sender interface, NULL if trunk.  Used to
     1432 *                              prevent sending an echo to the sender.
     1433 * @param   pDstAddr            The destination address of the frame.
     1434 * @param   pDstTab             The destination output table.
     1435 */
     1436static INTNETSWDECISION intnetR0NetworkSwitchUnicast(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETIF pIfSender,
     1437                                                     PCRTMAC pDstAddr, PINTNETDSTTAB pDstTab)
     1438{
     1439    AssertPtr(pDstTab);
     1440    Assert(!intnetR0IsMacAddrMulticast(pDstAddr));
     1441
     1442    /*
     1443     * Grab the spinlock first and do the switching.
     1444     */
     1445    PINTNETMACTAB   pTab    = &pNetwork->MacTab;
     1446    RTSPINLOCKTMP   Tmp     = RTSPINLOCKTMP_INITIALIZER;
     1447    RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp);
     1448
     1449    pDstTab->fTrunkDst  = 0;
     1450    pDstTab->pTrunk     = 0;
     1451    pDstTab->cIfs       = 0;
     1452
     1453    /* Find exactly matching or promiscuous interfaces. */
     1454    uint32_t cExactHits = 0;
     1455    uint32_t iIfMac     = pTab->cEntries;
     1456    while (iIfMac-- > 0)
     1457    {
     1458        if (pTab->paEntries[iIfMac].fActive)
     1459        {
     1460            bool fExact = intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pDstAddr);
     1461            if (   fExact
     1462                || intnetR0IsMacAddrDummy(&pTab->paEntries[iIfMac].MacAddr)
     1463                || pTab->paEntries[iIfMac].fPromiscuous)
     1464            {
     1465                cExactHits += fExact;
     1466
     1467                PINTNETIF pIf = pTab->paEntries[iIfMac].pIf;        AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
     1468                if (RT_LIKELY(pIf != pIfSender)) /* paranoia */
     1469                {
     1470                    uint32_t iIfDst = pDstTab->cIfs++;
     1471                    pDstTab->aIfs[iIfDst].pIf            = pIf;
     1472                    pDstTab->aIfs[iIfDst].fReplaceDstMac = false;
     1473                    intnetR0BusyIncIf(pIf);
     1474                }
     1475            }
     1476        }
     1477    }
     1478
     1479    /* Does it match the host, or is the host promiscuous? */
     1480    if (   fSrc != INTNETTRUNKDIR_HOST
     1481        && pTab->fHostActive)
     1482    {
     1483        bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstAddr);
     1484        if (   fExact
     1485            || intnetR0IsMacAddrDummy(&pTab->HostMac)
     1486            || pTab->fHostPromiscuous)
     1487        {
     1488            cExactHits += fExact;
     1489            pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
     1490        }
     1491    }
     1492
     1493    /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */
     1494    if (   fSrc != INTNETTRUNKDIR_WIRE
     1495        && pTab->fWireActive
     1496        && (!cExactHits || pTab->fWirePromiscuous)
     1497       )
     1498        pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
     1499
     1500    /* Grab the trunk if we're sending to it. */
     1501    if (pDstTab->fTrunkDst)
     1502    {
     1503        PINTNETTRUNKIF pTrunk = pTab->pTrunk;
     1504        pDstTab->pTrunk = pTrunk;
     1505        intnetR0BusyIncTrunk(pTrunk);
     1506    }
     1507
     1508    RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp);
     1509    return pDstTab->cIfs
     1510         ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST)
     1511         : (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP   : INTNETSWDECISION_TRUNK);
     1512}
     1513
     1514
     1515/**
     1516 * Create a destination table for a broadcast frame.
     1517 *
     1518 * @returns INTNETSWDECISION_BROADCAST.
     1519 * @param   pNetwork            The network to switch on.
     1520 * @param   fSrc                The frame source.
     1521 * @param   pIfSender           The sender interface, NULL if trunk.  Used to
     1522 *                              prevent sending an echo to the sender.
     1523 * @param   pDstTab             The destination output table.
     1524 */
     1525static INTNETSWDECISION intnetR0NetworkSwitchBroadcast(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETIF pIfSender,
     1526                                                       PINTNETDSTTAB pDstTab)
     1527{
     1528    AssertPtr(pDstTab);
     1529
     1530    /*
     1531     * Grab the spinlock first and record all active interfaces.
     1532     */
     1533    PINTNETMACTAB   pTab    = &pNetwork->MacTab;
     1534    RTSPINLOCKTMP   Tmp     = RTSPINLOCKTMP_INITIALIZER;
     1535    RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp);
     1536
     1537    pDstTab->fTrunkDst  = 0;
     1538    pDstTab->pTrunk     = 0;
     1539    pDstTab->cIfs       = 0;
     1540
     1541    /* Regular interfaces. */
     1542    uint32_t iIfMac = pTab->cEntries;
     1543    while (iIfMac-- > 0)
     1544    {
     1545        if (pTab->paEntries[iIfMac].fActive)
     1546        {
     1547            PINTNETIF pIf = pTab->paEntries[iIfMac].pIf;            AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
     1548            if (pIf != pIfSender)
     1549            {
     1550                uint32_t iIfDst = pDstTab->cIfs++;
     1551                pDstTab->aIfs[iIfDst].pIf            = pIf;
     1552                pDstTab->aIfs[iIfDst].fReplaceDstMac = false;
     1553                intnetR0BusyIncIf(pIf);
     1554            }
     1555        }
     1556    }
     1557
     1558    /* The trunk interface. */
     1559    if (pTab->fHostActive)
     1560        pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
     1561    if (pTab->fWireActive)
     1562        pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
     1563    pDstTab->fTrunkDst &= ~fSrc;
     1564    if (pDstTab->fTrunkDst)
     1565    {
     1566        PINTNETTRUNKIF pTrunk = pTab->pTrunk;
     1567        pDstTab->pTrunk = pTrunk;
     1568        intnetR0BusyIncTrunk(pTrunk);
     1569    }
     1570
     1571    RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp);
     1572    return INTNETSWDECISION_BROADCAST;
     1573}
     1574
     1575
     1576/**
     1577 * Create a destination table with the trunk and any promiscuous interfaces.
     1578 *
     1579 * This is only used in a fallback case of the level-3 switching, so we can
     1580 * assume the wire as source and skip the sender interface filtering.
     1581 *
     1582 * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
     1583 *          INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
     1584 * @param   pNetwork            The network to switch on.
     1585 * @param   fSrc                The frame source.
     1586 * @param   pDstTab             The destination output table.
     1587 */
     1588static INTNETSWDECISION intnetR0NetworkSwitchTrunkAndPromisc(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETDSTTAB pDstTab)
     1589{
     1590    Assert(fSrc == INTNETTRUNKDIR_WIRE);
     1591
     1592    /*
     1593     * Grab the spinlock first and do the switching.
     1594     */
     1595    PINTNETMACTAB   pTab    = &pNetwork->MacTab;
     1596    RTSPINLOCKTMP   Tmp     = RTSPINLOCKTMP_INITIALIZER;
     1597    RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp);
     1598
     1599    pDstTab->fTrunkDst  = 0;
     1600    pDstTab->pTrunk     = 0;
     1601    pDstTab->cIfs       = 0;
     1602
     1603    /* Find promiscuous interfaces. */
     1604    uint32_t iIfMac = pTab->cEntries;
     1605    while (iIfMac-- > 0)
     1606    {
     1607        if (   pTab->paEntries[iIfMac].fActive
     1608            && pTab->paEntries[iIfMac].fPromiscuous)
     1609        {
     1610            PINTNETIF pIf    = pTab->paEntries[iIfMac].pIf;         AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
     1611            uint32_t  iIfDst = pDstTab->cIfs++;
     1612            pDstTab->aIfs[iIfDst].pIf            = pIf;
     1613            pDstTab->aIfs[iIfDst].fReplaceDstMac = false;
     1614            intnetR0BusyIncIf(pIf);
     1615        }
     1616    }
     1617
     1618    /* The trunk interface. */
     1619    if (pTab->fHostActive)
     1620        pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
     1621    if (pTab->fWireActive)
     1622        pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
     1623    pDstTab->fTrunkDst &= ~fSrc;
     1624    if (pDstTab->fTrunkDst)
     1625    {
     1626        PINTNETTRUNKIF pTrunk = pTab->pTrunk;
     1627        pDstTab->pTrunk = pTrunk;
     1628        intnetR0BusyIncTrunk(pTrunk);
     1629    }
     1630
     1631    RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp);
     1632    return !pDstTab->cIfs
     1633        ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP   : INTNETSWDECISION_TRUNK)
     1634        : (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST);
     1635}
     1636
     1637
     1638/**
     1639 * Create a destination table for a trunk frame.
     1640 *
     1641 * @returns INTNETSWDECISION_BROADCAST.
     1642 * @param   pNetwork            The network to switch on.
     1643 * @param   fSrc                The frame source.
     1644 * @param   pDstTab             The destination output table.
     1645 */
     1646static INTNETSWDECISION intnetR0NetworkSwitchTrunk(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETDSTTAB pDstTab)
     1647{
     1648    AssertPtr(pDstTab);
     1649
     1650    /*
     1651     * Grab the spinlock first and record all active interfaces.
     1652     */
     1653    PINTNETMACTAB   pTab= &pNetwork->MacTab;
     1654    RTSPINLOCKTMP   Tmp = RTSPINLOCKTMP_INITIALIZER;
     1655    RTSpinlockAcquire(pNetwork->hAddrSpinlock, &Tmp);
     1656
     1657    pDstTab->fTrunkDst  = 0;
     1658    pDstTab->pTrunk     = 0;
     1659    pDstTab->cIfs       = 0;
     1660
     1661    /* The trunk interface. */
     1662    if (pTab->fHostActive)
     1663        pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
     1664    if (pTab->fWireActive)
     1665        pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
     1666    pDstTab->fTrunkDst &= ~fSrc;
     1667    if (pDstTab->fTrunkDst)
     1668    {
     1669        PINTNETTRUNKIF pTrunk = pTab->pTrunk;
     1670        pDstTab->pTrunk = pTrunk;
     1671        intnetR0BusyIncTrunk(pTrunk);
     1672    }
     1673
     1674    RTSpinlockRelease(pNetwork->hAddrSpinlock, &Tmp);
     1675    return pDstTab->fTrunkDst ? INTNETSWDECISION_TRUNK : INTNETSWDECISION_DROP;
     1676}
     1677
     1678
     1679/**
     1680 * Wrapper around RTMemAlloc for allocating a destination table.
     1681 *
     1682 * @returns VINF_SUCCESS or VERR_NO_MEMORY.
     1683 * @param   cEntries            The size given as an entry count.
     1684 * @param   ppDstTab            Where to store the pointer (always).
     1685 */
     1686DECLINLINE(int) intnetR0AllocDstTab(uint32_t cEntries, PINTNETDSTTAB *ppDstTab)
     1687{
     1688    PINTNETDSTTAB pDstTab;
     1689    *ppDstTab = pDstTab = (PINTNETDSTTAB)RTMemAlloc(RT_OFFSETOF(INTNETDSTTAB, aIfs[cEntries]));
     1690    if (RT_UNLIKELY(!pDstTab))
     1691        return VERR_NO_MEMORY;
     1692    return VINF_SUCCESS;
     1693}
     1694
     1695
     1696/**
     1697 * Ensures that there is space for another interface in the MAC address lookup
     1698 * table as well as all the destination tables.
     1699 *
     1700 * The caller must own the create/open/destroy mutex.
     1701 *
     1702 * @returns VINF_SUCCESS, VERR_NO_MEMORY or VERR_OUT_OF_RANGE.
     1703 * @param   pNetwork        The network to operate on.
     1704 */
     1705static int intnetR0NetworkEnsureTabSpace(PINTNETNETWORK pNetwork)
     1706{
     1707    /*
     1708     * The cEntries and cEntriesAllocated members are only updated while
     1709     * owning the big mutex, so we only need the spinlock when doing the
     1710     * actual table replacing.
     1711     */
     1712    PINTNETMACTAB pTab = &pNetwork->MacTab;
     1713    int rc = VINF_SUCCESS;
     1714    AssertReturn(pTab->cEntries <= pTab->cEntriesAllocated, VERR_INTERNAL_ERROR_2);
     1715    if (pTab->cEntries + 1 > pTab->cEntriesAllocated)
     1716    {
     1717        uint32_t const cAllocated = pTab->cEntriesAllocated + INTNET_GROW_DSTTAB_SIZE;
     1718        if (cAllocated <= INTNET_MAX_IFS)
     1719        {
     1720            RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     1721
     1722            /*
     1723             * Resize the destination tables first, this can be kind of tedious.
     1724             */
     1725            for (uint32_t i = 0; i < pTab->cEntries; i++)
     1726            {
     1727                PINTNETIF       pIf = pTab->paEntries[i].pIf; AssertPtr(pIf);
     1728                PINTNETDSTTAB   pNew;
     1729                rc = intnetR0AllocDstTab(cAllocated, &pNew);
     1730                if (RT_FAILURE(rc))
     1731                    break;
     1732
     1733                for (;;)
     1734                {
     1735                    PINTNETDSTTAB pOld = pIf->pDstTab;
     1736                    if (   pOld
     1737                        && ASMAtomicCmpXchgPtr((void * volatile *)&pIf->pDstTab, pNew, pOld))
     1738                    {
     1739                        RTMemFree(pOld);
     1740                        break;
     1741                    }
     1742                    intnetR0BusyWait(pNetwork, &pIf->cBusy);
     1743                }
     1744            }
     1745
     1746            /*
     1747             * The trunk.
     1748             */
     1749            if (    RT_SUCCESS(rc)
     1750                &&  pNetwork->MacTab.pTrunk)
     1751            {
     1752                AssertCompileAdjacentMembers(INTNETTRUNKIF, apTaskDstTabs, apIntDstTabs);
     1753                PINTNETTRUNKIF          pTrunk      = pNetwork->MacTab.pTrunk;
     1754                PINTNETDSTTAB * const   ppEndDstTab = &pTrunk->apIntDstTabs[pTrunk->cIntDstTabs];
     1755                for (PINTNETDSTTAB     *ppDstTab    = &pTrunk->apTaskDstTabs[0];
     1756                     ppDstTab != ppEndDstTab && RT_SUCCESS(rc);
     1757                     ppDstTab++)
     1758                {
     1759                    PINTNETDSTTAB pNew;
     1760                    rc = intnetR0AllocDstTab(cAllocated, &pNew);
     1761                    if (RT_FAILURE(rc))
     1762                        break;
     1763
     1764                    for (;;)
     1765                    {
     1766                        RTSpinlockAcquireNoInts(pTrunk->hDstTabSpinlock, &Tmp);
     1767                        void *pvOld = *ppDstTab;
     1768                        if (pvOld)
     1769                            *ppDstTab = pNew;
     1770                        RTSpinlockReleaseNoInts(pTrunk->hDstTabSpinlock, &Tmp);
     1771                        if (pvOld)
     1772                        {
     1773                            RTMemFree(pvOld);
     1774                            break;
     1775                        }
     1776                        intnetR0BusyWait(pNetwork, &pTrunk->cBusy);
     1777                    }
     1778                }
     1779            }
     1780
     1781            /*
     1782             * The MAC Address table itself.
     1783             */
     1784            if (RT_SUCCESS(rc))
     1785            {
     1786                PINTNETMACTABENTRY paNew = (PINTNETMACTABENTRY)RTMemAlloc(sizeof(INTNETMACTABENTRY) * cAllocated);
     1787                if (paNew)
     1788                {
     1789                    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1790
     1791                    PINTNETMACTABENTRY  paOld = pTab->paEntries;
     1792                    uint32_t            i     = pTab->cEntries;
     1793                    while (i-- > 0)
     1794                    {
     1795                        paNew[i] = paOld[i];
     1796
     1797                        paOld[i].fActive = false;
     1798                        paOld[i].pIf     = NULL;
     1799                    }
     1800
     1801                    pTab->paEntries         = paNew;
     1802                    pTab->cEntriesAllocated = cAllocated;
     1803
     1804                    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1805
     1806                    RTMemFree(paOld);
     1807                }
     1808                else
     1809                    rc = VERR_NO_MEMORY;
     1810            }
     1811        }
     1812        else
     1813            rc = VERR_OUT_OF_RANGE;
     1814    }
     1815    return rc;
     1816}
     1817
     1818
    12511819
    12521820
     
    13261894        case RTNET_DHCP_MT_ACK:
    13271895            if (intnetR0IPv4AddrIsGood(pDhcp->bp_yiaddr))
    1328                 for (PINTNETIF pCur = pNetwork->pIfs; pCur; pCur = pCur->pNext)
    1329                     if (    pCur->fMacSet
    1330                         &&  !memcmp(&pCur->Mac, &pDhcp->bp_chaddr, sizeof(RTMAC)))
     1896            {
     1897                PINTNETIF       pMatchingIf = NULL;
     1898                RTSPINLOCKTMP   Tmp         = RTSPINLOCKTMP_INITIALIZER;
     1899                RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1900
     1901                uint32_t iIf = pNetwork->MacTab.cEntries;
     1902                while (iIf-- > 0)
     1903                {
     1904                    PINTNETIF pCur = pNetwork->MacTab.paEntries[iIf].pIf;
     1905                    if (    intnetR0IfHasMacAddr(pCur)
     1906                        &&  !memcmp(&pCur->MacAddr, &pDhcp->bp_chaddr, sizeof(RTMAC)))
    13311907                    {
    13321908                        intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4],
    13331909                                                  (PCRTNETADDRU)&pDhcp->bp_ciaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_ACK");
    1334                         intnetR0IfAddrCacheAdd(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4],
    1335                                                (PCRTNETADDRU)&pDhcp->bp_yiaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_ACK");
    1336                         break;
     1910                        if (!pMatchingIf)
     1911                        {
     1912                            pMatchingIf = pCur;
     1913                            intnetR0BusyIncIf(pMatchingIf);
     1914                        }
    13371915                    }
    1338             break;
     1916                }
     1917
     1918                RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1919
     1920                if (pMatchingIf)
     1921                {
     1922                    intnetR0IfAddrCacheAdd(pMatchingIf, &pMatchingIf->aAddrCache[kIntNetAddrType_IPv4],
     1923                                           (PCRTNETADDRU)&pDhcp->bp_yiaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_ACK");
     1924                    intnetR0BusyDecIf(pMatchingIf);
     1925                }
     1926            }
     1927            return;
    13391928
    13401929
     
    13441933        case RTNET_DHCP_MT_RELEASE:
    13451934        {
    1346             for (PINTNETIF pCur = pNetwork->pIfs; pCur; pCur = pCur->pNext)
    1347                 if (    pCur->fMacSet
    1348                     &&  !memcmp(&pCur->Mac, &pDhcp->bp_chaddr, sizeof(RTMAC)))
     1935            RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     1936            RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     1937
     1938            uint32_t iIf = pNetwork->MacTab.cEntries;
     1939            while (iIf-- > 0)
     1940            {
     1941                PINTNETIF pCur = pNetwork->MacTab.paEntries[iIf].pIf;
     1942                if (    intnetR0IfHasMacAddr(pCur)
     1943                    &&  !memcmp(&pCur->MacAddr, &pDhcp->bp_chaddr, sizeof(RTMAC)))
    13491944                {
    13501945                    intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4],
     
    13531948                                              (PCRTNETADDRU)&pDhcp->bp_yiaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_RELEASE");
    13541949                }
     1950            }
     1951
     1952            RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
    13551953            break;
    13561954        }
     
    14082006
    14092007/**
    1410  * Snoops up source addresses from ARP requests and purge these
    1411  * from the address caches.
     2008 * Snoops up source addresses from ARP requests and purge these from the address
     2009 * caches.
    14122010 *
    14132011 * The purpose of this purging is to get rid of stale addresses.
     
    14582056     * Delete the source address if it's OK.
    14592057     */
    1460     if (    !(pArpIPv4->ar_sha.au8[0] & 1)
     2058    if (    !intnetR0IsMacAddrMulticast(&pArpIPv4->ar_sha)
    14612059        &&  (   pArpIPv4->ar_sha.au16[0]
    14622060             || pArpIPv4->ar_sha.au16[1]
     
    16782276
    16792277    if (    ar_oper == RTNET_ARPOP_REPLY
    1680         &&  !(pArpIPv4->ar_tha.au8[0] & 1)
     2278        &&  !intnetR0IsMacAddrMulticast(&pArpIPv4->ar_tha)
    16812279        &&  (   pArpIPv4->ar_tha.au16[0]
    16822280             || pArpIPv4->ar_tha.au16[1]
     
    16862284                                  (PCRTNETADDRU)&pArpIPv4->ar_tpa, sizeof(RTNETADDRIPV4), "if/arp");
    16872285
    1688     if (    !memcmp(&pArpIPv4->ar_sha, &pIf->Mac, sizeof(RTMAC))
     2286    if (    !memcmp(&pArpIPv4->ar_sha, &pIf->MacAddr, sizeof(RTMAC))
    16892287        &&  intnetR0IPv4AddrIsGood(pArpIPv4->ar_spa))
    16902288        intnetR0IfAddrCacheAdd(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4],
     
    17822380static void intnetR0IfSend(PINTNETIF pIf, PINTNETIF pIfSender, PINTNETSG pSG, PCRTMAC pNewDstMac)
    17832381{
    1784 //    LogFlow(("intnetR0IfSend: pIf=%p:{.hIf=%RX32}\n", pIf, pIf->hIf));
     2382    /*
     2383     * Grab the receive/producer lock and copy over the frame.
     2384     */
     2385    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     2386    RTSpinlockAcquireNoInts(pIf->hRecvInSpinlock, &Tmp);
    17852387    int rc = intnetR0RingWriteFrame(&pIf->pIntBuf->Recv, pSG, pNewDstMac);
     2388    RTSpinlockReleaseNoInts(pIf->hRecvInSpinlock, &Tmp);
    17862389    if (RT_SUCCESS(rc))
    17872390    {
    17882391        pIf->cYields = 0;
    1789         RTSemEventSignal(pIf->Event);
     2392        RTSemEventSignal(pIf->hRecvEvent);
    17902393        return;
    17912394    }
     
    17932396    Log(("intnetR0IfSend: overflow cb=%d hIf=%RX32\n", pSG->cbTotal, pIf->hIf));
    17942397
    1795 #if 0 /* This is bad stuff now as we're blocking while locking down the network.
    1796          we really shouldn't delay the network traffic on the host just because
    1797          some bugger isn't responding. Will have to deal with this in a different
    1798          manner if required. */
    1799     /*
    1800      * Retry a few times, yielding the CPU in between.
    1801      * But don't let a unresponsive VM harm performance, so give up after a couple of tries.
    1802      */
    1803     if (    pIf->fActive
    1804         &&  pIf->cYields < 100)
    1805     {
    1806         unsigned cYields = 10;
    1807 #else
    18082398    /*
    18092399     * Scheduling hack, for unicore machines primarily.
     
    18112401    if (    pIf->fActive
    18122402        &&  pIf->cYields < 4 /* just twice */
    1813         &&  pIfSender /* but not if it's from the trunk */)
     2403        &&  pIfSender /* but not if it's from the trunk */
     2404        &&  RTThreadPreemptIsEnabled(NIL_RTTHREAD)
     2405       )
    18142406    {
    18152407        unsigned cYields = 2;
    1816 #endif
    18172408        while (--cYields > 0)
    18182409        {
    1819             RTSemEventSignal(pIf->Event);
     2410            RTSemEventSignal(pIf->hRecvEvent);
    18202411            RTThreadYield();
     2412
     2413            RTSpinlockAcquireNoInts(pIf->hRecvInSpinlock, &Tmp);
    18212414            rc = intnetR0RingWriteFrame(&pIf->pIntBuf->Recv, pSG, pNewDstMac);
     2415            RTSpinlockReleaseNoInts(pIf->hRecvInSpinlock, &Tmp);
    18222416            if (RT_SUCCESS(rc))
    18232417            {
    18242418                STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsOk);
    1825                 RTSemEventSignal(pIf->Event);
     2419                RTSemEventSignal(pIf->hRecvEvent);
    18262420                return;
    18272421            }
     
    18332427    /* ok, the frame is lost. */
    18342428    STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatLost);
    1835     RTSemEventSignal(pIf->Event);
     2429    RTSemEventSignal(pIf->hRecvEvent);
    18362430}
    18372431
     
    18962490 * @param   pThis               The trunk.
    18972491 * @param   pSG                 The scatter / gather buffer.
    1898  * @param   fDst                The desitination mask.
     2492 * @param   fDst                The destination mask.
    18992493 */
    19002494DECLINLINE(bool) intnetR0TrunkIfCanHandleGsoFrame(PINTNETTRUNKIF pThis, PINTNETSG pSG, uint32_t fDst)
     
    19162510 * Sends a frame down the trunk.
    19172511 *
    1918  * The caller must own the network mutex, might be abandond temporarily.
    1919  * The fTrunkLock parameter indicates whether the trunk lock is held.
    1920  *
    19212512 * @param   pThis           The trunk.
    19222513 * @param   pNetwork        The network the frame is being sent to.
    1923  * @param   pIfSender       The IF sending the frame. Used for MAC address checks in shared MAC mode.
     2514 * @param   pIfSender       The IF sending the frame.  Used for MAC address
     2515 *                          checks in shared MAC mode.
    19242516 * @param   fDst            The destination flags.
    19252517 * @param   pSG             Pointer to the gather list.
    1926  * @param   fTrunkLocked    Whether the caller owns the out-bound trunk lock.
    19272518 */
    19282519static void intnetR0TrunkIfSend(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork, PINTNETIF pIfSender,
    1929                                 uint32_t fDst, PINTNETSG pSG, bool fTrunkLocked)
     2520                                uint32_t fDst, PINTNETSG pSG)
    19302521{
    19312522    /*
     
    19492540        &&  (fDst & INTNETTRUNKDIR_WIRE))
    19502541    {
    1951         /* Dispatch it to the host before making changes. */
     2542        /*
     2543         * Dispatch it to the host before making changes.
     2544         */
    19522545        if (fDst & INTNETTRUNKDIR_HOST)
    19532546        {
    19542547            Assert(pSG->fFlags & INTNETSG_FLAGS_TEMP); /* make sure copy is forced */
    1955             intnetR0TrunkIfSend(pThis, pNetwork, pIfSender, INTNETTRUNKDIR_HOST, pSG, fTrunkLocked);
     2548            intnetR0TrunkIfSend(pThis, pNetwork, pIfSender, INTNETTRUNKDIR_HOST, pSG);
    19562549            fDst &= ~INTNETTRUNKDIR_HOST;
    19572550        }
    19582551
     2552        /*
     2553         * Edit the source address so that it it's the same as the host.
     2554         */
    19592555        /* ASSUME frame from INTNETR0IfSend! */
    19602556        AssertReturnVoid(pSG->cSegsUsed == 1);
    19612557        AssertReturnVoid(pSG->cbTotal >= sizeof(RTNETETHERHDR));
    1962         AssertReturnVoid(fTrunkLocked);
    19632558        AssertReturnVoid(pIfSender);
    19642559        PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pSG->aSegs[0].pv;
    19652560
    1966         /*
    1967          * Get the host mac address and update the ethernet header.
    1968          *
    1969          * The reason for caching it in the trunk structure is because
    1970          * we cannot take the trunk out-bound semaphore when we make
    1971          * edits in the intnetR0TrunkIfPortRecv path.
    1972          */
    1973         pThis->pIfPort->pfnGetMacAddress(pThis->pIfPort, &pThis->CachedMac);
    1974         if (!memcmp(&pEthHdr->SrcMac, &pIfSender->Mac, sizeof(RTMAC)))
    1975             pEthHdr->SrcMac = pThis->CachedMac;
     2561        pEthHdr->SrcMac = pThis->MacAddr;
    19762562
    19772563        /*
     
    19882574             */
    19892575            PRTNETARPIPV4 pArp = (PRTNETARPIPV4)(pEthHdr + 1);
    1990             if (!memcmp(&pArp->ar_sha, &pIfSender->Mac, sizeof(RTMAC)))
     2576            if (!memcmp(&pArp->ar_sha, &pIfSender->MacAddr, sizeof(RTMAC)))
    19912577            {
    1992                 Log6(("tw: ar_sha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_sha, &pThis->CachedMac));
    1993                 pArp->ar_sha = pThis->CachedMac;
     2578                Log6(("tw: ar_sha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_sha, &pThis->MacAddr));
     2579                pArp->ar_sha = pThis->MacAddr;
    19942580            }
    1995             if (!memcmp(&pArp->ar_tha, &pIfSender->Mac, sizeof(RTMAC))) /* just in case... */
     2581            if (!memcmp(&pArp->ar_tha, &pIfSender->MacAddr, sizeof(RTMAC))) /* just in case... */
    19962582            {
    1997                 Log6(("tw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_tha, &pThis->CachedMac));
    1998                 pArp->ar_tha = pThis->CachedMac;
     2583                Log6(("tw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_tha, &pThis->MacAddr));
     2584                pArp->ar_tha = pThis->MacAddr;
    19992585            }
    20002586        }
     
    20052591
    20062592    /*
    2007      * Temporarily leave the network lock while transmitting the frame.
    2008      *
    2009      * Note that we're relying on the out-bound lock to serialize threads down
    2010      * in INTNETR0IfSend.  It's theoretically possible for there to be race now
    2011      * because I didn't implement async SG handling yet.  Which is why we
    2012      * currently require the trunk to be locked, well, one of the reasons.
    2013      *
    2014      * Another reason is that the intnetR0NetworkSendUnicast code may have to
    2015      * call into the trunk interface component to do package switching.
    2016      */
    2017     AssertReturnVoid(fTrunkLocked); /* to be removed. */
    2018 
     2593     * Grab the out-bound lock and send the frame.
     2594     */
    20192595    int rc;
    2020     if (    fTrunkLocked
    2021         ||  intnetR0TrunkIfRetain(pThis))
    2022     {
    2023         rc = RTSemFastMutexRelease(pNetwork->FastMutex2);
    2024         AssertRC(rc);
    2025         if (RT_SUCCESS(rc))
    2026         {
    2027             if (    fTrunkLocked
    2028                 ||  intnetR0TrunkIfOutLock(pThis))
    2029             {
    2030                 if (   pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID
    2031                     || intnetR0TrunkIfCanHandleGsoFrame(pThis, pSG, fDst) )
    2032                     rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pSG, fDst);
    2033                 else
    2034                     rc = intnetR0TrunkIfSendGsoFallback(pThis, pSG, fDst);
    2035 
    2036                 if (!fTrunkLocked)
    2037                     intnetR0TrunkIfOutUnlock(pThis);
    2038             }
    2039             else
    2040             {
    2041                 AssertFailed();
    2042                 rc = VERR_SEM_DESTROYED;
    2043             }
    2044 
    2045             int rc2 = RTSemFastMutexRequest(pNetwork->FastMutex2);
    2046             AssertRC(rc2);
    2047         }
    2048 
    2049         if (!fTrunkLocked)
    2050             intnetR0TrunkIfRelease(pThis);
     2596    if (intnetR0TrunkIfOutLock(pThis))
     2597    {
     2598        if (   pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID
     2599            || intnetR0TrunkIfCanHandleGsoFrame(pThis, pSG, fDst) )
     2600            rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pSG, fDst);
     2601        else
     2602            rc = intnetR0TrunkIfSendGsoFallback(pThis, pSG, fDst);
     2603        intnetR0TrunkIfOutUnlock(pThis);
    20512604    }
    20522605    else
     
    20572610
    20582611    /** @todo failure statistics? */
    2059     Log2(("intnetR0TrunkIfSend: %Rrc fDst=%d\n", rc, fDst));
     2612    Log2(("intnetR0TrunkIfSend: %Rrc fDst=%d\n", rc, fDst)); NOREF(rc);
    20602613}
    20612614
     
    21132666     */
    21142667    if (    ar_oper == RTNET_ARPOP_REPLY
    2115         &&  !memcmp(&pArpIPv4->ar_tha, &pNetwork->pTrunkIF->CachedMac, sizeof(RTMAC)))
     2668        &&  !memcmp(&pArpIPv4->ar_tha, &pNetwork->MacTab.pTrunk->MacAddr, sizeof(RTMAC)))
    21162669    {
    21172670        PINTNETIF pIf = intnetR0NetworkAddrCacheLookupIf(pNetwork, (PCRTNETADDRU)&pArpIPv4->ar_tpa,
     
    21192672        if (pIf)
    21202673        {
    2121             Log6(("fw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArpIPv4->ar_tha, &pIf->Mac));
    2122             pArpIPv4->ar_tha = pIf->Mac;
    2123             if (!memcmp(&pEthHdr->DstMac, &pNetwork->pTrunkIF->CachedMac, sizeof(RTMAC)))
     2674            Log6(("fw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArpIPv4->ar_tha, &pIf->MacAddr));
     2675            pArpIPv4->ar_tha = pIf->MacAddr;
     2676            if (!memcmp(&pEthHdr->DstMac, &pNetwork->MacTab.pTrunk->MacAddr, sizeof(RTMAC)))
    21242677            {
    2125                 Log6(("fw: DstMac %.6Rhxs -> %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac));
    2126                 pEthHdr->DstMac = pIf->Mac;
     2678                Log6(("fw: DstMac %.6Rhxs -> %.6Rhxs\n", &pEthHdr->DstMac, &pIf->MacAddr));
     2679                pEthHdr->DstMac = pIf->MacAddr;
    21272680                if ((void *)pEthHdr != pSG->aSegs[0].pv)
    2128                     intnetR0SgWritePart(pSG, RT_OFFSETOF(RTNETETHERHDR, DstMac), sizeof(RTMAC), &pIf->Mac);
     2681                    intnetR0SgWritePart(pSG, RT_OFFSETOF(RTNETETHERHDR, DstMac), sizeof(RTMAC), &pIf->MacAddr);
    21292682            }
     2683            intnetR0BusyDecIf(pIf);
    21302684
    21312685            /* Write back the packet if we've been making changes to a buffered copy. */
     
    22292783
    22302784/**
    2231  * Sends a broadcast frame.
    2232  *
    2233  * The caller must own the network mutex, might be abandond temporarily.
    2234  * When pIfSender is not NULL, the caller must also own the trunk semaphore.
    2235  *
    2236  * @returns true if it's addressed to someone on the network, otherwise false.
    2237  * @param   pNetwork        The network the frame is being sent to.
    2238  * @param   pIfSender       The interface sending the frame. This is NULL if it's the trunk.
    2239  * @param   fSrc            The source flags. This 0 if it's not from the trunk.
    2240  * @param   pSG             Pointer to the gather list.
    2241  * @param   fTrunkLocked    Whether the caller owns the out-bound trunk lock.
    2242  * @param   pEthHdr         Pointer to the ethernet header.
    2243  */
    2244 static bool intnetR0NetworkSendBroadcast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc,
    2245                                          PINTNETSG pSG, bool fTrunkLocked, PRTNETETHERHDR pEthHdr)
    2246 {
     2785 * Checks if the callers context is okay for sending to the specified
     2786 * destinations.
     2787 *
     2788 * @returns true if it's okay, false if it isn't.
     2789 * @param   pNetwork            The network.
     2790 * @param   pDstTab             The destination table.
     2791 */
     2792DECLINLINE(bool) intnetR0NetworkIsContextOk(PINTNETNETWORK pNetwork, PCINTNETDSTTAB pDstTab)
     2793{
     2794    uint32_t const  fTrunkDst = pDstTab->fTrunkDst;
     2795    if (!fTrunkDst)
     2796        return true;
     2797
     2798    /* ASSUMES: that the trunk won't change its report while we're checking. */
     2799    PINTNETTRUNKIF  pTrunk = pDstTab->pTrunk;
     2800    if (    ((fTrunkDst & INTNETTRUNKDIR_HOST) && (pTrunk->fHostNoPreempt || !pNetwork->MacTab.fHostActive))
     2801        &&  ((fTrunkDst & INTNETTRUNKDIR_WIRE) && (pTrunk->fWireNoPreempt || !pNetwork->MacTab.fWireActive))
     2802       )
     2803        return true;
     2804
     2805    /* ASSUMES: That a preemption test detects HWACCM contexts. (Will work on
     2806                non-preemptive systems as well.) */
     2807    if (RTThreadPreemptIsEnabled(NIL_RTTHREAD))
     2808        return true;
     2809    return false;
     2810}
     2811
     2812
     2813/**
     2814 * Checks if the callers context is okay for doing a broadcast given the
     2815 * specified source.
     2816 *
     2817 * @returns true if it's okay, false if it isn't.
     2818 * @param   pNetwork            The network.
     2819 * @param   fSrc                The source of the packet.  (0 (intnet),
     2820 *                              INTNETTRUNKDIR_HOST or INTNETTRUNKDIR_WIRE).
     2821 */
     2822DECLINLINE(bool) intnetR0NetworkIsContextOkForBroadcast(PINTNETNETWORK pNetwork, uint32_t fSrc)
     2823{
     2824    if (   (!pNetwork->MacTab.fHostActive || fSrc == INTNETTRUNKDIR_HOST)
     2825        && (!pNetwork->MacTab.fWireActive || fSrc == INTNETTRUNKDIR_WIRE) )
     2826        return true;
     2827
     2828    /* ASSUMES: That a preemption test detects HWACCM contexts. (Will work on
     2829                non-preemptive systems as well.) */
     2830    if (RTThreadPreemptIsEnabled(NIL_RTTHREAD))
     2831        return true;
     2832
     2833    /* PARANOIA: Grab the spinlock to make sure the trunk structure cannot be
     2834                 freed while we're touching it. */
     2835    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     2836    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     2837    PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk;
     2838
     2839    bool fRc = !pTrunk
     2840            || (   (!pNetwork->MacTab.fHostActive || pTrunk->fHostNoPreempt || fSrc == INTNETTRUNKDIR_HOST)
     2841                && (!pNetwork->MacTab.fWireActive || pTrunk->fWireNoPreempt || fSrc == INTNETTRUNKDIR_WIRE) );
     2842
     2843    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     2844
     2845    return fRc;
     2846}
     2847
     2848
     2849/**
     2850 * Check context, edit, snoop and switch a broadcast frame when sharing MAC
     2851 * address on the wire.
     2852 *
     2853 * The caller must hold at least one interface on the network busy to prevent it
     2854 * from destructing beath us.
     2855 *
     2856 * @param   pNetwork            The network the frame is being sent to.
     2857 * @param   fSrc                The source of the packet.  (0 (intnet),
     2858 *                              INTNETTRUNKDIR_HOST or INTNETTRUNKDIR_WIRE).
     2859 * @param   pIfSender           The sender interface, NULL if trunk.  Used to
     2860 *                              prevent sending an echo to the sender.
     2861 * @param   pSG                 Pointer to the gather list.
     2862 * @param   pEthHdr             Pointer to the ethernet header.
     2863 * @param   pDstTab             The destination output table.
     2864 */
     2865static INTNETSWDECISION intnetR0NetworkSharedMacFixAndSwitchBroadcast(PINTNETNETWORK pNetwork,
     2866                                                                      uint32_t fSrc, PINTNETIF pIfSender,
     2867                                                                      PINTNETSG pSG, PRTNETETHERHDR pEthHdr,
     2868                                                                      PINTNETDSTTAB pDstTab)
     2869{
     2870    /*
     2871     * Before doing any work here, we need to figure out if we can handle it
     2872     * in the current context.  The restrictions are solely on the trunk.
     2873     *
     2874     * Note! Since at least one interface is busy, there won't be any changes
     2875     *       to the parameters here (unless the trunk changes its capability
     2876     *       report, which it shouldn't).
     2877     */
     2878    if (!intnetR0NetworkIsContextOkForBroadcast(pNetwork, fSrc))
     2879        return INTNETSWDECISION_BAD_CONTEXT;
     2880
    22472881    /*
    22482882     * Check for ARP packets from the wire since we'll have to make
    22492883     * modification to them if we're sharing the MAC address with the host.
    22502884     */
    2251     if (    (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
    2252         &&  (fSrc & INTNETTRUNKDIR_WIRE)
    2253         &&  RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_ARP)
     2885    if (    (fSrc & INTNETTRUNKDIR_WIRE)
     2886        &&  RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_ARP
     2887        &&  pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID)
    22542888        intnetR0NetworkEditArpFromWire(pNetwork, pSG, pEthHdr);
    22552889
    2256      /*
     2890    /*
    22572891     * Check for DHCP packets from the internal net since we'll have to set
    22582892     * broadcast flag in DHCP requests if we're sharing the MAC address with
    22592893     * the host.  GSO is not applicable to DHCP traffic.
    22602894     */
    2261     if (    (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
    2262         &&  !fSrc
     2895    if (    !fSrc
    22632896        &&  RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_IPV4
    22642897        &&  pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID)
     
    22662899
    22672900    /*
    2268      * This is a broadcast or multicast address. For the present we treat those
    2269      * two as the same - investigating multicast is left for later.
    2270      *
    2271      * Write the packet to all the interfaces and signal them.
    2272      */
    2273     for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext)
    2274         if (pIf != pIfSender)
    2275             intnetR0IfSend(pIf, pIfSender, pSG, NULL);
    2276 
    2277     /*
    2278      * Unless the trunk is the origin, broadcast it to both the wire
    2279      * and the host as well.
    2280      */
    2281     PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
    2282     if (    pIfSender
    2283         &&  pTrunkIf)
    2284         intnetR0TrunkIfSend(pTrunkIf, pNetwork, pIfSender, INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE, pSG, fTrunkLocked);
    2285 
    2286     /*
    22872901     * Snoop address info from packet orginating from the trunk connection.
    22882902     */
    2289     else if (   (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
    2290              && !pIfSender)
     2903    if (fSrc)
    22912904    {
    22922905#ifdef INTNET_WITH_DHCP_SNOOPING
     
    22952908                 && pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN
    22962909                 && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID )
    2297             ||  (pSG->fFlags & (INTNETSG_FLAGS_ARP_IPV4)) )
     2910            ||  (pSG->fFlags & INTNETSG_FLAGS_ARP_IPV4) )
    22982911            intnetR0TrunkIfSnoopAddr(pNetwork, pSG, EtherType);
    22992912#else
    2300        if (pSG->fFlags & (INTNETSG_FLAGS_ARP_IPV4))
     2913       if (pSG->fFlags & INTNETSG_FLAGS_ARP_IPV4)
    23012914           intnetR0TrunkIfSnoopArp(pNetwork, pSG);
    23022915#endif
    23032916    }
    23042917
    2305     return false; /* broadcast frames are never dropped */
    2306 }
    2307 
    2308 
    2309 /**
    2310  * Sends a multicast frame.
    2311  *
    2312  * The caller must own the network mutex, might be abandond temporarily.
    2313  *
    2314  * @returns true if it's addressed to someone on the network, otherwise false.
    2315  * @param   pNetwork        The network the frame is being sent to.
    2316  * @param   pIfSender       The interface sending the frame. This is NULL if it's the trunk.
    2317  * @param   fSrc            The source flags. This 0 if it's not from the trunk.
    2318  * @param   pSG             Pointer to the gather list.
    2319  * @param   fTrunkLocked    Whether the caller owns the out-bound trunk lock.
    2320  * @param   pEthHdr         Pointer to the ethernet header.
    2321  */
    2322 static bool intnetR0NetworkSendMulticast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PRTNETETHERHDR pEthHdr)
    2323 {
    2324     /** @todo implement multicast */
    2325     return intnetR0NetworkSendBroadcast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, pEthHdr);
    2326 }
    2327 
    2328 
    2329 /**
    2330  * Sends a unicast frame using the network layer address instead
    2331  * of the link layer one.
    2332  *
    2333  * This function is only used for frames comming from the write (trunk).
    2334  *
    2335  * The caller must own the network mutex, might be abandond temporarily.
     2918    /*
     2919     * Create the broadcast destination table.
     2920     */
     2921    return intnetR0NetworkSwitchBroadcast(pNetwork, fSrc, pIfSender, pDstTab);
     2922}
     2923
     2924
     2925/**
     2926 * Check context, snoop and switch a unicast frame using the network layer
     2927 * address of the link layer one (when sharing MAC address on the wire).
     2928 *
     2929 * This function is only used for frames comming from the wire (trunk).
    23362930 *
    23372931 * @returns true if it's addressed to someone on the network, otherwise false.
    23382932 * @param   pNetwork        The network the frame is being sent to.
    23392933 * @param   pSG             Pointer to the gather list.
    2340  * @param   fTrunkLocked    Whether the caller owns the out-bound trunk lock.
    23412934 * @param   pEthHdr         Pointer to the ethernet header.
    2342  */
    2343 static bool intnetR0NetworkSendUnicastWithSharedMac(PINTNETNETWORK pNetwork, PINTNETSG pSG, bool fTrunkLocked, PRTNETETHERHDR pEthHdr)
     2935 * @param   pDstTab         The destination output table.
     2936 */
     2937static INTNETSWDECISION intnetR0NetworkSharedMacFixAndSwitchUnicast(PINTNETNETWORK pNetwork, PINTNETSG pSG,
     2938                                                                    PRTNETETHERHDR pEthHdr, PINTNETDSTTAB pDstTab)
    23442939{
    23452940    /*
     
    23552950            {
    23562951                Log(("intnetshareduni: failed to read ip_dst! cbTotal=%#x\n", pSG->cbTotal));
    2357                 return false;
     2952                return intnetR0NetworkSwitchTrunk(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab);
    23582953            }
    23592954            enmAddrType = kIntNetAddrType_IPv4;
     
    23672962            {
    23682963                Log(("intnetshareduni: failed to read ip6_dst! cbTotal=%#x\n", pSG->cbTotal));
    2369                 return false;
     2964                return intnetR0NetworkSwitchTrunk(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab);
    23702965            }
    23712966            enmAddrType = kIntNetAddrType_IPv6;
     
    23802975            {
    23812976                Log(("intnetshareduni: failed to read ipx_dstnet! cbTotal=%#x\n", pSG->cbTotal));
    2382                 return false;
     2977                return intnetR0NetworkSwitchTrunk(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab);
    23832978            }
    23842979            enmAddrType = kIntNetAddrType_IPX;
     
    23942989            Log6(("intnetshareduni: ARP\n"));
    23952990            /** @todo revisit this broadcasting of unicast ARP frames! */
    2396             return intnetR0NetworkSendBroadcast(pNetwork, NULL, INTNETTRUNKDIR_WIRE, pSG, fTrunkLocked, pEthHdr);
     2991            return intnetR0NetworkSwitchBroadcast(pNetwork, INTNETTRUNKDIR_WIRE, NULL, pDstTab);
    23972992
    23982993        /*
    2399          * Unknown packets are sent do all interfaces that are in promiscuous mode.
     2994         * Unknown packets are sent to the trunk and any promiscuous interfaces.
    24002995         */
    24012996        default:
    24022997        {
    24032998            Log6(("intnetshareduni: unknown ethertype=%#x\n", RT_BE2H_U16(pEthHdr->EtherType)));
    2404             if (!(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC)))
    2405             {
    2406                 for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext)
    2407                     if (pIf->fPromiscuous)
    2408                     {
    2409                         Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac));
    2410                         intnetR0IfSend(pIf, NULL, pSG, NULL);
    2411                     }
    2412             }
    2413             return false;
     2999            return intnetR0NetworkSwitchTrunkAndPromisc(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab);
    24143000        }
    24153001    }
    24163002
    24173003    /*
    2418      * Send it to interfaces with matching network addresses.
    2419      */
    2420     bool fExactIntNetRecipient = false;
    2421     for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext)
    2422     {
    2423         bool fIt = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmAddrType], &Addr, cbAddr) >= 0;
    2424         if (    fIt
    2425             ||  (   pIf->fPromiscuous
    2426                  && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))))
    2427         {
    2428             Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac));
    2429             fExactIntNetRecipient |= fIt;
    2430             intnetR0IfSend(pIf, NULL, pSG, fIt ? &pIf->Mac : NULL);
    2431         }
    2432     }
     3004     * Do level-3 switching.
     3005     */
     3006    INTNETSWDECISION enmSwDecision = intnetR0NetworkSwitchLevel3(pNetwork, &pEthHdr->DstMac,
     3007                                                                 enmAddrType, &Addr, cbAddr,
     3008                                                                 INTNETTRUNKDIR_WIRE, pDstTab);
    24333009
    24343010#ifdef INTNET_WITH_DHCP_SNOOPING
     
    24423018#endif /* INTNET_WITH_DHCP_SNOOPING */
    24433019
    2444     return fExactIntNetRecipient;
    2445 }
    2446 
    2447 
    2448 /**
    2449  * Sends a unicast frame.
    2450  *
    2451  * The caller must own the network mutex, might be abandond temporarily.
    2452  *
    2453  * @returns true if it's addressed to someone on the network, otherwise false.
     3020    return enmSwDecision;
     3021}
     3022
     3023
     3024/**
     3025 * Release all the interfaces in the destination table when we realize that
     3026 * we're in a context where we cannot get the job done.
     3027 *
     3028 * @param   pNetwork            The network.
     3029 * @param   pDstTab             The destination table.
     3030 */
     3031static void intnetR0NetworkReleaseDstTab(PINTNETNETWORK pNetwork, PINTNETDSTTAB pDstTab)
     3032{
     3033    /* The trunk interface. */
     3034    if (pDstTab->fTrunkDst)
     3035    {
     3036        PINTNETTRUNKIF pTrunk = pDstTab->pTrunk;
     3037        intnetR0BusyDec(pNetwork, &pTrunk->cBusy);
     3038        pDstTab->pTrunk    = NULL;
     3039        pDstTab->fTrunkDst = 0;
     3040    }
     3041
     3042    /* Regular interfaces. */
     3043    uint32_t iIf = pDstTab->cIfs;
     3044    while (iIf-- > 0)
     3045    {
     3046        PINTNETIF pIf = pDstTab->aIfs[iIf].pIf;
     3047        intnetR0BusyDecIf(pIf);
     3048        pDstTab->aIfs[iIf].pIf = NULL;
     3049    }
     3050    pDstTab->cIfs = 0;
     3051}
     3052
     3053
     3054/**
     3055 * Deliver the frame to the interfaces specified in the destination table.
     3056 *
     3057 * @param   pNetwork            The network.
     3058 * @param   pDstTab             The destination table.
     3059 * @param   pSG                 The frame to send.
     3060 * @param   pIfSender           The sender interface.  NULL if it origined via
     3061 *                              the trunk.
     3062 */
     3063static void intnetR0NetworkDeliver(PINTNETNETWORK pNetwork, PINTNETDSTTAB pDstTab, PINTNETSG pSG, PINTNETIF pIfSender)
     3064{
     3065    /*
     3066     * Trunk first so we don't wast any more time before hitting the wire.
     3067     *
     3068     * Note! The switching functions will include the trunk even when the frame
     3069     *       source is the trunk.  This is because we need it to figure out
     3070     *       whether the other half of the trunk should see the frame or not
     3071     *       and let the caller know.
     3072     *
     3073     *       So, we'll ignore trunk sends here if the frame origin is
     3074     *       INTNETTRUNKSWPORT::pfnRecv.
     3075     */
     3076    if (pDstTab->fTrunkDst)
     3077    {
     3078        PINTNETTRUNKIF pTrunk = pDstTab->pTrunk;
     3079        if (pIfSender)
     3080            intnetR0TrunkIfSend(pTrunk, pNetwork, pIfSender, pDstTab->fTrunkDst, pSG);
     3081        intnetR0BusyDec(pNetwork, &pTrunk->cBusy);
     3082        pDstTab->pTrunk    = NULL;
     3083        pDstTab->fTrunkDst = 0;
     3084    }
     3085
     3086    /*
     3087     * Do the interfaces.
     3088     */
     3089    uint32_t iIf = pDstTab->cIfs;
     3090    while (iIf-- > 0)
     3091    {
     3092        PINTNETIF pIf = pDstTab->aIfs[iIf].pIf;
     3093        intnetR0IfSend(pIf, pIfSender, pSG,
     3094                       pDstTab->aIfs[iIf].fReplaceDstMac ? &pIf->MacAddr: NULL);
     3095        intnetR0BusyDecIf(pIf);
     3096        pDstTab->aIfs[iIf].pIf = NULL;
     3097    }
     3098    pDstTab->cIfs = 0;
     3099}
     3100
     3101
     3102/**
     3103 * Sends a frame.
     3104 *
     3105 * This function will distribute the frame to the interfaces it is addressed to.
     3106 * It will also update the MAC address of the sender.
     3107 *
     3108 * The caller must own the network mutex.
     3109 *
     3110 * @returns The switching decision.
    24543111 * @param   pNetwork        The network the frame is being sent to.
    24553112 * @param   pIfSender       The interface sending the frame. This is NULL if it's the trunk.
    24563113 * @param   fSrc            The source flags. This 0 if it's not from the trunk.
    24573114 * @param   pSG             Pointer to the gather list.
    2458  * @param   fTrunkLocked    Whether the caller owns the out-bound trunk lock.
    2459  * @param   pEthHdr         Pointer to the ethernet header.
    2460  */
    2461 static bool intnetR0NetworkSendUnicast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PCRTNETETHERHDR pEthHdr)
    2462 {
    2463     /*
    2464      * Only send to the interfaces with matching a MAC address.
    2465      */
    2466     bool fExactIntNetRecipient = false;
    2467     for (PINTNETIF pIf = pNetwork->pIfs; pIf; pIf = pIf->pNext)
    2468     {
    2469         bool fIt = false;
    2470         if (    (   !pIf->fMacSet
    2471                  || (fIt = !memcmp(&pIf->Mac, &pEthHdr->DstMac, sizeof(pIf->Mac))) )
    2472             ||  (   pIf->fPromiscuous
    2473                  && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))
    2474                  && pIf != pIfSender /* promiscuous mode: omit the sender */))
    2475         {
    2476             Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->DstMac, &pIf->Mac));
    2477             fExactIntNetRecipient |= fIt;
    2478             intnetR0IfSend(pIf, pIfSender, pSG, NULL);
    2479         }
    2480     }
    2481 
    2482     /*
    2483      * Send it to the trunk?
    2484      * If we didn't find the recipient on the internal network the
    2485      * frame will hit the wire.
    2486      */
    2487     uint32_t fDst = 0;
    2488     PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
    2489     if (    pIfSender
    2490         &&  pTrunkIf
    2491         &&  pTrunkIf->pIfPort)
    2492     {
    2493         Assert(!fSrc);
    2494 
    2495         /* promiscuous checks first as they are cheaper than pfnIsHostMac. */
    2496         if (    pTrunkIf->fWirePromiscuous
    2497             &&  !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE)) )
    2498             fDst |= INTNETTRUNKDIR_WIRE;
    2499         if (    !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST))
    2500             &&  pTrunkIf->pIfPort->pfnIsPromiscuous(pTrunkIf->pIfPort) )
    2501             fDst |= INTNETTRUNKDIR_HOST;
    2502 
    2503         if (    fDst != (INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE)
    2504             &&  !fExactIntNetRecipient  /* if you have duplicate mac addresses, you're screwed. */ )
    2505         {
    2506             if (pTrunkIf->pIfPort->pfnIsHostMac(pTrunkIf->pIfPort, &pEthHdr->DstMac))
    2507                 fDst |= INTNETTRUNKDIR_HOST;
    2508             else
    2509                 fDst |= INTNETTRUNKDIR_WIRE;
    2510         }
    2511 
    2512         if (fDst)
    2513             intnetR0TrunkIfSend(pTrunkIf, pNetwork, pIfSender, fDst, pSG, fTrunkLocked);
    2514     }
    2515 
    2516     /* log it */
    2517     if (    !fExactIntNetRecipient
    2518         &&  !fDst
    2519         &&  (   (pEthHdr->DstMac.au8[0] == 0x08 && pEthHdr->DstMac.au8[1] == 0x00 && pEthHdr->DstMac.au8[2] == 0x27)
    2520              || (pEthHdr->SrcMac.au8[0] == 0x08 && pEthHdr->SrcMac.au8[1] == 0x00 && pEthHdr->SrcMac.au8[2] == 0x27)))
    2521         Log2(("Dst=%.6Rhxs ??\n", &pEthHdr->DstMac));
    2522 
    2523     return fExactIntNetRecipient;
    2524 }
    2525 
    2526 
    2527 /**
    2528  * Sends a frame.
    2529  *
    2530  * This function will distribute the frame to the interfaces it is addressed to.
    2531  * It will also update the MAC address of the sender.
    2532  *
    2533  * The caller must own the network mutex.
    2534  *
    2535  * @returns true if it's addressed to someone on the network, otherwise false.
    2536  * @param   pNetwork        The network the frame is being sent to.
    2537  * @param   pIfSender       The interface sending the frame. This is NULL if it's the trunk.
    2538  * @param   fSrc            The source flags. This 0 if it's not from the trunk.
    2539  * @param   pSG             Pointer to the gather list.
    2540  * @param   fTrunkLocked    Whether the caller owns the out-bound trunk lock.
    2541  */
    2542 static bool intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked)
    2543 {
    2544     bool fRc = false;
    2545 
     3115 * @param   pDstTab         The destination table to use.
     3116 */
     3117static INTNETSWDECISION intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc,
     3118                                            PINTNETSG pSG, PINTNETDSTTAB pDstTab)
     3119{
    25463120    /*
    25473121     * Assert reality.
     
    25553129    Assert(pSG->cSegsUsed <= pSG->cSegsAlloc);
    25563130    if (pSG->cbTotal < sizeof(RTNETETHERHDR))
    2557         return fRc;
     3131        return INTNETSWDECISION_INVALID;
    25583132
    25593133    /*
     
    25643138        EthHdr = *(PCRTNETETHERHDR)pSG->aSegs[0].pv;
    25653139    else if (!intnetR0SgReadPart(pSG, 0, sizeof(EthHdr), &EthHdr))
    2566         return false;
     3140        return INTNETSWDECISION_INVALID;
    25673141    if (    (EthHdr.DstMac.au8[0] == 0x08 && EthHdr.DstMac.au8[1] == 0x00 && EthHdr.DstMac.au8[2] == 0x27)
    25683142        ||  (EthHdr.SrcMac.au8[0] == 0x08 && EthHdr.SrcMac.au8[1] == 0x00 && EthHdr.SrcMac.au8[2] == 0x27)
     
    25753149
    25763150    /*
    2577      * Inspect the header updating the mac address of the sender in the process.
    2578      */
    2579     if (    pIfSender
    2580         &&  memcmp(&EthHdr.SrcMac, &pIfSender->Mac, sizeof(pIfSender->Mac)))
    2581     {
    2582         /** @todo stats */
    2583         Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->Mac, &EthHdr.SrcMac));
    2584         pIfSender->Mac = EthHdr.SrcMac;
    2585         pIfSender->fMacSet = true;
    2586     }
    2587 
    2588     /*
    2589      * Distribute the frame.
    2590      */
    2591     if (   EthHdr.DstMac.au16[0] == 0xffff              /* broadcast address. */
    2592         && EthHdr.DstMac.au16[1] == 0xffff
    2593         && EthHdr.DstMac.au16[2] == 0xffff)
    2594         fRc = intnetR0NetworkSendBroadcast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr);
    2595     else if (RT_UNLIKELY(EthHdr.DstMac.au8[0] & 1))     /* multicast address */
    2596         fRc = intnetR0NetworkSendMulticast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr);
    2597     else if (   !(pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
    2598              || !(fSrc & INTNETTRUNKDIR_WIRE))
    2599         fRc = intnetR0NetworkSendUnicast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr);
     3151     * Learn the MAC address of the sender.  No re-learning as the interface
     3152     * user will normally tell us the right MAC address.
     3153     */
     3154    if (RT_UNLIKELY(    pIfSender
     3155                    &&  !pIfSender->fMacSet
     3156                    &&  memcmp(&EthHdr.SrcMac, &pIfSender->MacAddr, sizeof(pIfSender->MacAddr))
     3157                    &&  !intnetR0IsMacAddrMulticast(&EthHdr.SrcMac)
     3158                    ))
     3159    {
     3160        Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->MacAddr, &EthHdr.SrcMac));
     3161        RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     3162        RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3163
     3164        PINTNETMACTABENTRY pIfEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIfSender);
     3165        if (pIfEntry)
     3166            pIfEntry->MacAddr = EthHdr.SrcMac;
     3167        pIfSender->MacAddr    = EthHdr.SrcMac;
     3168
     3169        RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3170    }
     3171
     3172    /*
     3173     * Deal with MAC address sharing as that may required editing of the
     3174     * packets before we dispatch them anywhere.
     3175     */
     3176    INTNETSWDECISION enmSwDecision;
     3177    if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
     3178    {
     3179        if (intnetR0IsMacAddrMulticast(&EthHdr.DstMac))
     3180            enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, fSrc, pIfSender, pSG, &EthHdr, pDstTab);
     3181        else if (fSrc & INTNETTRUNKDIR_WIRE)
     3182            enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchUnicast(pNetwork, pSG, &EthHdr, pDstTab);
     3183        else
     3184            enmSwDecision = intnetR0NetworkSwitchUnicast(pNetwork, fSrc, pIfSender, &EthHdr.DstMac, pDstTab);
     3185    }
     3186    else if (intnetR0IsMacAddrMulticast(&EthHdr.DstMac))
     3187        enmSwDecision = intnetR0NetworkSwitchBroadcast(pNetwork, fSrc, pIfSender, pDstTab);
    26003188    else
    2601         fRc = intnetR0NetworkSendUnicastWithSharedMac(pNetwork, pSG, fTrunkLocked, &EthHdr);
    2602     return fRc;
     3189        enmSwDecision = intnetR0NetworkSwitchUnicast(pNetwork, fSrc, pIfSender, &EthHdr.DstMac, pDstTab);
     3190
     3191    /*
     3192     * Deliver to the destinations if we can.
     3193     */
     3194    if (enmSwDecision != INTNETSWDECISION_BAD_CONTEXT)
     3195    {
     3196        if (intnetR0NetworkIsContextOk(pNetwork, pDstTab))
     3197            intnetR0NetworkDeliver(pNetwork, pDstTab, pSG, pIfSender);
     3198        else
     3199        {
     3200            intnetR0NetworkReleaseDstTab(pNetwork, pDstTab);
     3201            enmSwDecision = INTNETSWDECISION_BAD_CONTEXT;
     3202        }
     3203    }
     3204
     3205    return enmSwDecision;
    26033206}
    26043207
     
    26073210 * Sends one or more frames.
    26083211 *
    2609  * The function will first the frame which is passed as the optional
    2610  * arguments pvFrame and cbFrame. These are optional since it also
    2611  * possible to chain together one or more frames in the send buffer
    2612  * which the function will process after considering it's arguments.
     3212 * The function will first the frame which is passed as the optional arguments
     3213 * pvFrame and cbFrame. These are optional since it also possible to chain
     3214 * together one or more frames in the send buffer which the function will
     3215 * process after considering it's arguments.
     3216 *
     3217 * The caller is responsible for making sure that there are no concurrent calls
     3218 * to this method (with the same handle).
    26133219 *
    26143220 * @returns VBox status code.
     
    26303236
    26313237    /*
    2632      * Lock the network. If there is a trunk retain it and grab its
    2633      * out-bound lock (this requires leaving the network lock first).
    2634      * Grabbing the out-bound lock here simplifies things quite a bit
    2635      * later on, so while this is excessive and a bit expensive it's
    2636      * not worth caring about right now.
    2637      */
     3238     * Make sure we've got a network.
     3239     */
     3240    int rc  = VINF_SUCCESS;
     3241    intnetR0BusyIncIf(pIf);
    26383242    PINTNETNETWORK pNetwork = pIf->pNetwork;
    2639     int rc = RTSemFastMutexRequest(pNetwork->FastMutex2);
    2640     if (RT_FAILURE(rc))
    2641     {
    2642         intnetR0IfRelease(pIf, pSession);
    2643         return rc;
    2644     }
    2645     PINTNETTRUNKIF pTrunkIf = intnetR0TrunkIfRetain(pNetwork->pTrunkIF);
    2646     if (pTrunkIf)
    2647     {
    2648         RTSemFastMutexRelease(pIf->pNetwork->FastMutex2);
    2649 
    2650         if (!intnetR0TrunkIfOutLock(pTrunkIf))
     3243    if (RT_LIKELY(pNetwork))
     3244    {
     3245        /*
     3246         * Grab the destination table.
     3247         */
     3248        PINTNETDSTTAB pDstTab = (PINTNETDSTTAB)ASMAtomicXchgPtr((void * volatile *)&pIf->pDstTab, NULL);
     3249        if (RT_LIKELY(pDstTab))
    26513250        {
    2652             intnetR0TrunkIfRelease(pTrunkIf);
    2653             intnetR0IfRelease(pIf, pSession);
    2654             return VERR_SEM_DESTROYED;
     3251            /*
     3252             * Process the send buffer.
     3253             */
     3254            INTNETSWDECISION    enmSwDecision = INTNETSWDECISION_BROADCAST;
     3255            INTNETSG            Sg; /** @todo this will have to be changed if we're going to use async sending
     3256                                     * with buffer sharing for some OS or service. Darwin copies everything so
     3257                                     * I won't bother allocating and managing SGs rigth now. Sorry. */
     3258            PINTNETHDR          pHdr;
     3259            while ((pHdr = INTNETRingGetNextFrameToRead(&pIf->pIntBuf->Send)) != NULL)
     3260            {
     3261                uint16_t const      u16Type = pHdr->u16Type;
     3262                if (u16Type == INTNETHDR_TYPE_FRAME)
     3263                {
     3264                    /* Send regular frame. */
     3265                    void *pvCurFrame = INTNETHdrGetFramePtr(pHdr, pIf->pIntBuf);
     3266                    INTNETSgInitTemp(&Sg, pvCurFrame, pHdr->cbFrame);
     3267                    if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
     3268                        intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, pHdr->cbFrame, false /*fGso*/, (uint16_t *)&Sg.fFlags);
     3269                    enmSwDecision = intnetR0NetworkSend(pNetwork, pIf,  0 /*fSrc*/, &Sg, pDstTab);
     3270                }
     3271                else if (u16Type == INTNETHDR_TYPE_GSO)
     3272                {
     3273                    /* Send GSO frame if sane. */
     3274                    PPDMNETWORKGSO  pGso       = INTNETHdrGetGsoContext(pHdr, pIf->pIntBuf);
     3275                    uint32_t        cbFrame    = pHdr->cbFrame - sizeof(*pGso);
     3276                    if (RT_LIKELY(PDMNetGsoIsValid(pGso, pHdr->cbFrame, cbFrame)))
     3277                    {
     3278                        void       *pvCurFrame = pGso + 1;
     3279                        INTNETSgInitTempGso(&Sg, pvCurFrame, cbFrame, pGso);
     3280                        if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
     3281                            intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, cbFrame, true /*fGso*/, (uint16_t *)&Sg.fFlags);
     3282                        enmSwDecision = intnetR0NetworkSend(pNetwork, pIf, 0 /*fSrc*/, &Sg, pDstTab);
     3283                    }
     3284                    else
     3285                    {
     3286                        STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */
     3287                        enmSwDecision = INTNETSWDECISION_DROP;
     3288                    }
     3289                }
     3290                /* Unless it's a padding frame, we're getting babble from the producer. */
     3291                else
     3292                {
     3293                    if (u16Type != INTNETHDR_TYPE_PADDING)
     3294                        STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */
     3295                    enmSwDecision = INTNETSWDECISION_DROP;
     3296                }
     3297                if (enmSwDecision == INTNETSWDECISION_BAD_CONTEXT)
     3298                {
     3299                    rc = VERR_TRY_AGAIN;
     3300                    break;
     3301                }
     3302
     3303                /* Skip to the next frame. */
     3304                INTNETRingSkipFrame(&pIf->pIntBuf->Send);
     3305            }
     3306
     3307            /*
     3308             * Put back the destination table.
     3309             */
     3310            Assert(!pIf->pDstTab);
     3311            ASMAtomicWritePtr((void * volatile *)&pIf->pDstTab, pDstTab);
    26553312        }
    2656 
    2657         rc = RTSemFastMutexRequest(pNetwork->FastMutex2);
    2658         if (RT_FAILURE(rc))
    2659         {
    2660             intnetR0TrunkIfOutUnlock(pTrunkIf);
    2661             intnetR0TrunkIfRelease(pTrunkIf);
    2662             intnetR0IfRelease(pIf, pSession);
    2663             return rc;
    2664         }
    2665     }
    2666 
    2667     INTNETSG Sg; /** @todo this will have to be changed if we're going to use async sending
    2668                   * with buffer sharing for some OS or service. Darwin copies everything so
    2669                   * I won't bother allocating and managing SGs rigth now. Sorry. */
    2670 
    2671     /*
    2672      * Process the send buffer.
    2673      */
    2674     PINTNETHDR pHdr;
    2675     while ((pHdr = INTNETRingGetNextFrameToRead(&pIf->pIntBuf->Send)) != NULL)
    2676     {
    2677         uint16_t const u16Type = pHdr->u16Type;
    2678         if (u16Type == INTNETHDR_TYPE_FRAME)
    2679         {
    2680             /* Send regular frame. */
    2681             void *pvCurFrame = INTNETHdrGetFramePtr(pHdr, pIf->pIntBuf);
    2682             INTNETSgInitTemp(&Sg, pvCurFrame, pHdr->cbFrame);
    2683             if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
    2684                 intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, pHdr->cbFrame, false /*fGso*/, (uint16_t *)&Sg.fFlags);
    2685             intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf);
    2686         }
    2687         else if (u16Type == INTNETHDR_TYPE_GSO)
    2688         {
    2689             /* Send GSO frame if sane*/
    2690             PPDMNETWORKGSO  pGso       = INTNETHdrGetGsoContext(pHdr, pIf->pIntBuf);
    2691             uint32_t        cbFrame    = pHdr->cbFrame - sizeof(*pGso);
    2692             if (RT_LIKELY(PDMNetGsoIsValid(pGso, pHdr->cbFrame, cbFrame)))
    2693             {
    2694                 void       *pvCurFrame = pGso + 1;
    2695                 INTNETSgInitTempGso(&Sg, pvCurFrame, cbFrame, pGso);
    2696                 if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
    2697                     intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, cbFrame, true /*fGso*/, (uint16_t *)&Sg.fFlags);
    2698                 intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf);
    2699             }
    2700             else
    2701                 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */
    2702         }
    2703         /* Unless it's a padding frame, we're getting babble from the producer. */
    2704         else if (u16Type != INTNETHDR_TYPE_PADDING)
    2705             STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */
    2706 
    2707         /* Skip to the next frame. */
    2708         INTNETRingSkipFrame(&pIf->pIntBuf->Send);
    2709     }
    2710 
    2711     /*
    2712      * Release the semaphore(s) and release references.
    2713      */
    2714     rc = RTSemFastMutexRelease(pNetwork->FastMutex2);
    2715     if (pTrunkIf)
    2716     {
    2717         intnetR0TrunkIfOutUnlock(pTrunkIf);
    2718         intnetR0TrunkIfRelease(pTrunkIf);
    2719     }
    2720 
     3313        else
     3314            rc = VERR_INTERNAL_ERROR_4;
     3315    }
     3316    else
     3317        rc = VERR_INTERNAL_ERROR_3;
     3318
     3319    /*
     3320     * Release the interface.
     3321     */
     3322    intnetR0BusyDecIf(pIf);
    27213323    intnetR0IfRelease(pIf, pSession);
    27223324    return rc;
     
    27683370     * allocating the buffer.
    27693371     */
    2770     int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex2);
     3372    int rc = RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
    27713373    if (RT_SUCCESS(rc))
    27723374    {
    27733375        *ppRing3Buf = pIf->pIntBufR3;
    2774         rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex2);
     3376
     3377        rc = RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
    27753378    }
    27763379
     
    28243427     * ASSUMES that the handle isn't closed while we're here.
    28253428     */
    2826     int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex2);
     3429    int rc = RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
    28273430    if (RT_SUCCESS(rc))
    28283431    {
    28293432        *ppRing0Buf = pIf->pIntBuf;
    28303433
    2831         rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex2);
     3434        rc = RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
    28323435    }
    28333436    intnetR0IfRelease(pIf, pSession);
     
    29023505
    29033506    /*
    2904      * Grab the network semaphore and make the change.
    2905      */
    2906     int rc;
     3507     * Get the network, take the address spinlock, and make the change.
     3508     * Paranoia^2: Mark ourselves busy to prevent anything from being destroyed.
     3509     */
     3510    int rc = VINF_SUCCESS;
     3511    intnetR0BusyIncIf(pIf);
    29073512    PINTNETNETWORK pNetwork = pIf->pNetwork;
    29083513    if (pNetwork)
    29093514    {
    2910         rc = RTSemFastMutexRequest(pNetwork->FastMutex2);
    2911         if (RT_SUCCESS(rc))
     3515        RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     3516        RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3517
     3518        if (pIf->fPromiscuous != fPromiscuous)
    29123519        {
    2913             if (pIf->fPromiscuous != fPromiscuous)
    2914             {
    2915                 Log(("INTNETR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d\n",
    2916                      hIf, !fPromiscuous, !!fPromiscuous));
    2917                 ASMAtomicUoWriteBool(&pIf->fPromiscuous, fPromiscuous);
    2918             }
    2919 
    2920             rc = RTSemFastMutexRelease(pNetwork->FastMutex2);
     3520            Log(("INTNETR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d\n",
     3521                 hIf, !fPromiscuous, !!fPromiscuous));
     3522            ASMAtomicUoWriteBool(&pIf->fPromiscuous, fPromiscuous);
     3523
     3524            PINTNETMACTABENTRY pEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIf); Assert(pEntry);
     3525            if (RT_LIKELY(pEntry))
     3526                pEntry->fPromiscuous = fPromiscuous;
     3527            pIf->fPromiscuous        = fPromiscuous;
    29213528        }
     3529
     3530        RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
    29223531    }
    29233532    else
    29243533        rc = VERR_WRONG_ORDER;
    29253534
     3535    intnetR0BusyDecIf(pIf);
    29263536    intnetR0IfRelease(pIf, pSession);
    29273537    return rc;
     
    29713581
    29723582    /*
    2973      * Grab the network semaphore and make the change.
    2974      */
    2975     int rc;
     3583     * Get the network, take the address spinlock, and make the change.
     3584     * Paranoia^2: Mark ourselves busy to prevent anything from being destroyed.
     3585     */
     3586    int rc = VINF_SUCCESS;
     3587    intnetR0BusyIncIf(pIf);
    29763588    PINTNETNETWORK pNetwork = pIf->pNetwork;
    29773589    if (pNetwork)
    29783590    {
    2979         rc = RTSemFastMutexRequest(pNetwork->FastMutex2);
    2980         if (RT_SUCCESS(rc))
     3591        RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     3592        RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3593
     3594        if (memcmp(&pIf->MacAddr, pMac, sizeof(pIf->MacAddr)))
    29813595        {
    2982             if (memcmp(&pIf->Mac, pMac, sizeof(pIf->Mac)))
    2983             {
    2984                 Log(("INTNETR0IfSetMacAddress: hIf=%RX32: Changed from %.6Rhxs -> %.6Rhxs\n",
    2985                      hIf, &pIf->Mac, pMac));
    2986                 pIf->Mac = *pMac;
    2987                 pIf->fMacSet = true;
    2988             }
    2989 
    2990             rc = RTSemFastMutexRelease(pNetwork->FastMutex2);
     3596            Log(("INTNETR0IfSetMacAddress: hIf=%RX32: Changed from %.6Rhxs -> %.6Rhxs\n",
     3597                 hIf, &pIf->MacAddr, pMac));
     3598
     3599            PINTNETMACTABENTRY pEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIf); Assert(pEntry);
     3600            if (RT_LIKELY(pEntry))
     3601                pEntry->MacAddr = *pMac;
     3602            pIf->MacAddr        = *pMac;
     3603            pIf->fMacSet        = true;
    29913604        }
     3605
     3606        RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
    29923607    }
    29933608    else
    29943609        rc = VERR_WRONG_ORDER;
    29953610
     3611    intnetR0BusyDecIf(pIf);
    29963612    intnetR0IfRelease(pIf, pSession);
    29973613    return rc;
     
    30163632
    30173633/**
    3018  * Worker for intnetR0IfSetActive.
     3634 * Worker for intnetR0IfSetActive and intnetR0IfDestruct.
    30193635 *
    30203636 * This function will update the active interface count on the network and
    3021  * activate or deactivate the trunk connection if necessary. Note that in
     3637 * activate or deactivate the trunk connection if necessary.  Note that in
    30223638 * order to do this it is necessary to abandond the network semaphore.
    30233639 *
     
    30343650
    30353651    /*
    3036      * If we've got a trunk, lock it now in case we need to call out, and
    3037      * then lock the network.
    3038      */
    3039     PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
    3040     if (pTrunkIf && !intnetR0TrunkIfOutLock(pTrunkIf))
    3041         return VERR_SEM_DESTROYED;
    3042 
    3043     int rc = RTSemFastMutexRequest(pNetwork->FastMutex2); AssertRC(rc);
    3044     if (RT_SUCCESS(rc))
    3045     {
    3046         bool fNetworkLocked = true;
    3047 
    3048         /*
    3049          * Make the change if necessary.
    3050          */
    3051         if (pIf->fActive != fActive)
     3652     * The address spinlock of the network protects the variables, while
     3653     * the out-bound trunk semaphore protects the pfnSetActive call.
     3654     * Try grab both of them in case we have to make a change.
     3655     */
     3656    int             rcTrunkLock = VERR_SEM_DESTROYED;
     3657    PINTNETTRUNKIF  pTrunk      = pNetwork->MacTab.pTrunk;
     3658    if (pTrunk && intnetR0TrunkIfOutLock(pTrunk))
     3659        rcTrunkLock = VINF_SUCCESS;
     3660
     3661    bool            fTellTrunk  = false;
     3662    RTSPINLOCKTMP   Tmp         = RTSPINLOCKTMP_INITIALIZER;
     3663    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3664
     3665    /*
     3666     * Do the update.
     3667     */
     3668    if (pIf->fActive != fActive)
     3669    {
     3670        PINTNETMACTABENTRY pEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIf); Assert(pEntry);
     3671        if (RT_LIKELY(pEntry))
    30523672        {
    3053             pIf->fActive = fActive;
    3054 
    3055             uint32_t const cActiveIFs = pNetwork->cActiveIFs;
    3056             Assert((int32_t)cActiveIFs + (fActive ? 1 : -1) >= 0);
    3057             pNetwork->cActiveIFs += fActive ? 1 : -1;
    3058 
    3059             if (    pTrunkIf
    3060                 &&  (   !pNetwork->cActiveIFs
    3061                      || !cActiveIFs))
     3673            pEntry->fActive = fActive;
     3674            pIf->fActive    = fActive;
     3675
     3676            if (fActive)
    30623677            {
    3063                 /*
    3064                  * We'll have to change the trunk status, so, leave
    3065                  * the network semaphore so we don't create any deadlocks.
    3066                  */
    3067                 int rc2 = RTSemFastMutexRelease(pNetwork->FastMutex2); AssertRC(rc2);
    3068                 fNetworkLocked = false;
    3069 
    3070                 if (pTrunkIf->pIfPort)
    3071                     pTrunkIf->pIfPort->pfnSetActive(pTrunkIf->pIfPort, fActive);
     3678                pNetwork->cActiveIFs++;
     3679                fTellTrunk = pNetwork->cActiveIFs == 1;
     3680            }
     3681            else
     3682            {
     3683                pNetwork->cActiveIFs--;
     3684                fTellTrunk = pNetwork->cActiveIFs == 0;
    30723685            }
    30733686        }
    3074 
    3075         if (fNetworkLocked)
    3076             RTSemFastMutexRelease(pNetwork->FastMutex2);
    3077     }
    3078     if (pTrunkIf)
    3079         intnetR0TrunkIfOutUnlock(pTrunkIf);
    3080     return rc;
    3081 }
    3082 
    3083 
    3084 /**
    3085  * Activates or deactivates a interface.
    3086  *
    3087  * This is used to enable and disable the trunk connection on demans as well as
    3088  * know when not to expect an interface to want to receive packets.
    3089  *
    3090  * @returns VBox status code.
    3091  * @param   pIf         The interface.
    3092  * @param   fActive     What to do.
    3093  */
    3094 static int intnetR0IfSetActive(PINTNETIF pIf, bool fActive)
    3095 {
    3096     /* quick sanity check */
    3097     AssertPtrReturn(pIf, VERR_INVALID_POINTER);
    3098 
    3099     /*
    3100      * Hand it to the network since it might involve the trunk
    3101      * and things are tricky there wrt to locking order.
    3102      */
    3103     PINTNETNETWORK pNetwork = pIf->pNetwork;
    3104     if (!pNetwork)
    3105         return VERR_WRONG_ORDER;
    3106     return intnetR0NetworkSetIfActive(pNetwork, pIf, fActive);
     3687    }
     3688
     3689    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3690
     3691    /*
     3692     * Tell the trunk if necessary.
     3693     */
     3694    if (RT_SUCCESS(rcTrunkLock))
     3695    {
     3696        if (fTellTrunk && pTrunk->pIfPort)
     3697            pTrunk->pIfPort->pfnSetActive(pTrunk->pIfPort, fActive);
     3698
     3699        intnetR0TrunkIfOutUnlock(pTrunk);
     3700    }
     3701
     3702    return VINF_SUCCESS;
    31073703}
    31083704
     
    31333729
    31343730    /*
    3135      * Hand it to the network since it might involve the trunk
    3136      * and things are tricky there wrt to locking order.
    3137      */
     3731     * Hand it to the network since it might involve the trunk and things are
     3732     * tricky there wrt to locking order.
     3733     *
     3734     * Note! We mark the interface busy so the network cannot be removed while
     3735     *       we're working on it - paranoia strikes again.
     3736     */
     3737    intnetR0BusyIncIf(pIf);
     3738
    31383739    int rc;
    31393740    PINTNETNETWORK pNetwork = pIf->pNetwork;
     
    31433744        rc = VERR_WRONG_ORDER;
    31443745
     3746    intnetR0BusyDecIf(pIf);
    31453747    intnetR0IfRelease(pIf, pSession);
    31463748    return rc;
     
    31893791        return VERR_INVALID_HANDLE;
    31903792    }
    3191     const INTNETIFHANDLE    hIfSelf = pIf->hIf;
    3192     const RTSEMEVENT        Event = pIf->Event;
    3193     if (    hIfSelf != hIf              /* paranoia */
    3194         &&  Event != NIL_RTSEMEVENT)
     3793    const INTNETIFHANDLE    hIfSelf    = pIf->hIf;
     3794    const RTSEMEVENT        hRecvEvent = pIf->hRecvEvent;
     3795    if (    hIfSelf    != hIf           /* paranoia */
     3796        &&  hRecvEvent != NIL_RTSEMEVENT)
    31953797    {
    31963798        Log(("INTNETR0IfWait: returns VERR_SEM_DESTROYED\n"));
     
    32123814     */
    32133815    ASMAtomicIncU32(&pIf->cSleepers);
    3214     int rc = RTSemEventWaitNoResume(Event, cMillies);
    3215     if (pIf->Event == Event)
     3816    int rc = RTSemEventWaitNoResume(hRecvEvent, cMillies);
     3817    if (pIf->hRecvEvent == hRecvEvent)
    32163818    {
    32173819        ASMAtomicDecU32(&pIf->cSleepers);
     
    32703872    ASMAtomicWriteU32(&pIf->hIf, INTNET_HANDLE_INVALID);
    32713873
    3272 
    32733874    /*
    32743875     * Release the references to the interface object (handle + free lookup).
     
    32763877     * will wake up too (he'll see hIf == invalid and return correctly).
    32773878     */
    3278     RTSemEventSignal(pIf->Event);
     3879    uint32_t i = pIf->cSleepers;
     3880    while (i-- > 0)
     3881    {
     3882        RTSemEventSignal(pIf->hRecvEvent);
     3883        RTThreadYield();
     3884    }
     3885    RTSemEventSignal(pIf->hRecvEvent);
    32793886
    32803887    void *pvObj = pIf->pvObj;
     
    33213928     * adding or removing interface while we're in here.  For paranoid reasons
    33223929     * we also mark the interface as destroyed here so any waiting threads can
    3323      * take the appropriate actions (theoretical case).
     3930     * take evasive action (theoretical case).
    33243931     */
    33253932    RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
     
    33383945
    33393946    /*
    3340      * If we've got a network deactivate and unlink ourselves from it.
    3341      * Because of cleanup order we might be an orphan now.
     3947     * If we've got a network deactivate and detach ourselves from it.  Because
     3948     * of cleanup order we might have been orphaned by the network destructor.
    33423949     */
    33433950    PINTNETNETWORK pNetwork = pIf->pNetwork;
    33443951    if (pNetwork)
    33453952    {
    3346         intnetR0IfSetActive(pIf, false);
    3347 
    3348         /* unlink */
    3349         if (pNetwork->pIfs == pIf)
    3350             pNetwork->pIfs = pIf->pNext;
    3351         else
    3352         {
    3353             PINTNETIF pPrev = pNetwork->pIfs;
    3354             while (pPrev)
     3953        /* set inactive. */
     3954        intnetR0NetworkSetIfActive(pNetwork, pIf, false /*fActive*/);
     3955
     3956        /* remove ourselves from the switch table. */
     3957        RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     3958        RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3959
     3960        uint32_t iIf = pNetwork->MacTab.cEntries;
     3961        while (iIf-- > 0)
     3962            if (pNetwork->MacTab.paEntries[iIf].pIf == pIf)
    33553963            {
    3356                 if (pPrev->pNext == pIf)
    3357                 {
    3358                     pPrev->pNext = pIf->pNext;
    3359                     break;
    3360                 }
    3361                 pPrev = pPrev->pNext;
     3964                if (iIf + 1 < pNetwork->MacTab.cEntries)
     3965                    memmove(&pNetwork->MacTab.paEntries[iIf],
     3966                            &pNetwork->MacTab.paEntries[iIf + 1],
     3967                            (pNetwork->MacTab.cEntries - iIf - 1) * sizeof(pNetwork->MacTab.paEntries[0]));
     3968                pNetwork->MacTab.cEntries--;
     3969                break;
    33623970            }
    3363             Assert(pPrev);
    3364         }
    3365         pIf->pNext = NULL;
     3971
     3972        RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3973
     3974        /* Wait for the interface to quiesce while we still can. */
     3975        intnetR0BusyWait(pNetwork, &pIf->cBusy);
    33663976
    33673977        /* Release our reference to the network. */
     3978        RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3979        pIf->pNetwork = NULL;
     3980        RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     3981
    33683982        SUPR0ObjRelease(pNetwork->pvObj, pIf->pSession);
    3369         pIf->pNetwork = NULL;
    33703983    }
    33713984
     
    33783991     * that the interface is no longer valid.
    33793992     */
    3380     if (pIf->Event != NIL_RTSEMEVENT)
    3381     {
    3382         RTSEMEVENT Event = pIf->Event;
    3383         unsigned cMaxWait = 0x1000;
     3993    if (pIf->hRecvEvent != NIL_RTSEMEVENT)
     3994    {
     3995        RTSEMEVENT  hRecvEvent = pIf->hRecvEvent;
     3996        unsigned    cMaxWait  = 0x1000;
    33843997        while (pIf->cSleepers && cMaxWait-- > 0)
    33853998        {
    3386             RTSemEventSignal(Event);
     3999            RTSemEventSignal(hRecvEvent);
    33874000            RTThreadYield();
    33884001        }
     
    33944007            while (pIf->cSleepers && cMaxWait-- > 0)
    33954008            {
    3396                 RTSemEventSignal(Event);
     4009                RTSemEventSignal(hRecvEvent);
    33974010                RTThreadSleep(10);
    33984011            }
    33994012        }
    34004013
    3401         RTSemEventDestroy(Event);
    3402         pIf->Event = NIL_RTSEMEVENT;
     4014        RTSemEventDestroy(hRecvEvent);
     4015        pIf->hRecvEvent = NIL_RTSEMEVENT;
    34034016    }
    34044017
     
    34244037
    34254038    /*
    3426      * The interface.
    3427      */
     4039     * Free remaining resources
     4040     */
     4041    RTSpinlockDestroy(pIf->hRecvInSpinlock);
     4042    pIf->hRecvInSpinlock = NIL_RTSPINLOCK;
     4043
     4044    RTMemFree(pIf->pDstTab);
     4045    pIf->pDstTab = NULL;
     4046
     4047    for (unsigned i = 0; i < RT_ELEMENTS(pIf->aAddrCache); i++)
     4048        if (pIf->aAddrCache[i].pbEntries)
     4049        {
     4050            RTMemFree(pIf->aAddrCache[i].pbEntries);
     4051            pIf->aAddrCache[i].pbEntries = NULL;
     4052        }
     4053
    34284054    pIf->pvObj = NULL;
    34294055    RTMemFree(pIf);
     
    34394065 *
    34404066 * @returns VBox status code.
    3441  * @param   pNetwork    The network.
     4067 * @param   pNetwork    The network, referenced.  The reference is consumed on
     4068 *                      success.
    34424069 * @param   pSession    The session handle.
    34434070 * @param   cbSend      The size of the send buffer.
     
    34584085
    34594086    /*
    3460      * Allocate and initialize the interface structure.
     4087     * Make sure that all destination tables as well as the  have space of
     4088     */
     4089    int rc = intnetR0NetworkEnsureTabSpace(pNetwork);
     4090    if (RT_FAILURE(rc))
     4091        return rc;
     4092
     4093    /*
     4094     * Allocate the interface and initalize it.
    34614095     */
    34624096    PINTNETIF pIf = (PINTNETIF)RTMemAllocZ(sizeof(*pIf));
    34634097    if (!pIf)
    34644098        return VERR_NO_MEMORY;
    3465     //pIf->pNext = NULL;
    3466     memset(&pIf->Mac, 0xff, sizeof(pIf->Mac)); /* broadcast */
    3467     //pIf->fMacSet = false;
    3468     //pIf->fPromiscuous = false;
    3469     //pIf->fActive = false;
    3470     //pIf->fDestroying = false;
    3471     //pIf->pIntBuf = 0;
    3472     //pIf->pIntBufR3 = NIL_RTR3PTR;
    3473     //pIf->pIntBufDefault = 0;
     4099
     4100    memset(&pIf->MacAddr, 0xff, sizeof(pIf->MacAddr)); /* broadcast */
     4101    //pIf->fMacSet          = false;
     4102    //pIf->fPromiscuous     = false;
     4103    //pIf->fActive          = false;
     4104    //pIf->fDestroying      = false;
     4105    //pIf->cYields          = 0;
     4106    //pIf->pIntBuf          = 0;
     4107    //pIf->pIntBufR3        = NIL_RTR3PTR;
     4108    //pIf->pIntBufDefault   = 0;
    34744109    //pIf->pIntBufDefaultR3 = NIL_RTR3PTR;
    3475     //pIf->cYields = 0;
    3476     pIf->Event = NIL_RTSEMEVENT;
    3477     //pIf->cSleepers = 0;
    3478     pIf->hIf = INTNET_HANDLE_INVALID;
    3479     pIf->pNetwork = pNetwork;
    3480     pIf->pSession = pSession;
    3481     //pIf->pvObj = NULL;
    3482     //pIf->aAddrCache[kIntNetAddrType_Invalid] = {0};
    3483     //pIf->aAddrCache[kIntNetAddrType_IPv4].pbEntries = NULL;
    3484     //pIf->aAddrCache[kIntNetAddrType_IPv4].cEntries = 0;
     4110    pIf->hRecvEvent         = NIL_RTSEMEVENT;
     4111    //pIf->cSleepers        = 0;
     4112    pIf->hIf                = INTNET_HANDLE_INVALID;
     4113    pIf->pNetwork           = pNetwork;
     4114    pIf->pSession           = pSession;
     4115    //pIf->pvObj            = NULL;
     4116    //pIf->aAddrCache[kIntNetAddrType_Invalid]            = {0};
     4117    //pIf->aAddrCache[kIntNetAddrType_IPv4].pbEntries     = NULL;
     4118    //pIf->aAddrCache[kIntNetAddrType_IPv4].cEntries      = 0;
    34854119    //pIf->aAddrCache[kIntNetAddrType_IPv4].cEntriesAlloc = 0;
    3486     pIf->aAddrCache[kIntNetAddrType_IPv4].cbAddress = intnetR0AddrSize(kIntNetAddrType_IPv4);
    3487     pIf->aAddrCache[kIntNetAddrType_IPv4].cbEntry   = intnetR0AddrSize(kIntNetAddrType_IPv4);
    3488     //pIf->aAddrCache[kIntNetAddrType_IPv6].pbEntries = NULL;
    3489     //pIf->aAddrCache[kIntNetAddrType_IPv6].cEntries = 0;
     4120    pIf->aAddrCache[kIntNetAddrType_IPv4].cbAddress       = intnetR0AddrSize(kIntNetAddrType_IPv4);
     4121    pIf->aAddrCache[kIntNetAddrType_IPv4].cbEntry         = intnetR0AddrSize(kIntNetAddrType_IPv4);
     4122    //pIf->aAddrCache[kIntNetAddrType_IPv6].pbEntries     = NULL;
     4123    //pIf->aAddrCache[kIntNetAddrType_IPv6].cEntries      = 0;
    34904124    //pIf->aAddrCache[kIntNetAddrType_IPv6].cEntriesAlloc = 0;
    3491     pIf->aAddrCache[kIntNetAddrType_IPv6].cbAddress = intnetR0AddrSize(kIntNetAddrType_IPv6);
    3492     pIf->aAddrCache[kIntNetAddrType_IPv6].cbEntry   = intnetR0AddrSize(kIntNetAddrType_IPv6);
    3493     //pIf->aAddrCache[kIntNetAddrType_IPX].pbEntries = NULL;
    3494     //pIf->aAddrCache[kIntNetAddrType_IPX].cEntries = 0;
    3495     //pIf->aAddrCache[kIntNetAddrType_IPX].cEntriesAlloc = 0;
    3496     pIf->aAddrCache[kIntNetAddrType_IPX].cbAddress = intnetR0AddrSize(kIntNetAddrType_IPX);
    3497     pIf->aAddrCache[kIntNetAddrType_IPX].cbEntry   = RT_ALIGN_32(intnetR0AddrSize(kIntNetAddrType_IPv4), 16);
    3498     int rc = RTSemEventCreate((PRTSEMEVENT)&pIf->Event);
     4125    pIf->aAddrCache[kIntNetAddrType_IPv6].cbAddress       = intnetR0AddrSize(kIntNetAddrType_IPv6);
     4126    pIf->aAddrCache[kIntNetAddrType_IPv6].cbEntry         = intnetR0AddrSize(kIntNetAddrType_IPv6);
     4127    //pIf->aAddrCache[kIntNetAddrType_IPX].pbEntries      = NULL;
     4128    //pIf->aAddrCache[kIntNetAddrType_IPX].cEntries       = 0;
     4129    //pIf->aAddrCache[kIntNetAddrType_IPX].cEntriesAlloc  = 0;
     4130    pIf->aAddrCache[kIntNetAddrType_IPX].cbAddress        = intnetR0AddrSize(kIntNetAddrType_IPX);
     4131    pIf->aAddrCache[kIntNetAddrType_IPX].cbEntry          = RT_ALIGN_32(intnetR0AddrSize(kIntNetAddrType_IPX), 16);
     4132    pIf->hRecvInSpinlock    = NIL_RTSPINLOCK;
     4133    pIf->cBusy              = 0;
     4134    //pIf->pDstTab          = NULL;
     4135
     4136    rc = intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, (PINTNETDSTTAB *)&pIf->pDstTab);
     4137    if (RT_SUCCESS(rc))
     4138        rc = RTSemEventCreate((PRTSEMEVENT)&pIf->hRecvEvent);
     4139    if (RT_SUCCESS(rc))
     4140        rc = RTSpinlockCreate(&pIf->hRecvInSpinlock);
    34994141    if (RT_SUCCESS(rc))
    35004142    {
     
    35164158
    35174159            /*
    3518              * Link the interface to the network.
     4160             * Register the interface with the session and create a handle for it.
    35194161             */
    3520             rc = RTSemFastMutexRequest(pNetwork->FastMutex2);
    3521             if (RT_SUCCESS(rc))
     4162            pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE,
     4163                                          intnetR0IfDestruct, pIf, pNetwork->pIntNet);
     4164            if (pIf->pvObj)
    35224165            {
    3523                 pIf->pNext = pNetwork->pIfs;
    3524                 pNetwork->pIfs = pIf;
    3525                 RTSemFastMutexRelease(pNetwork->FastMutex2);
    3526 
    3527                 /*
    3528                  * Register the interface with the session, adding another
    3529                  * reference to the network to ease the cleanup duties of the caller.
    3530                  */
    3531                 rc = SUPR0ObjAddRef(pNetwork->pvObj, pSession);
     4166                rc = RTHandleTableAllocWithCtx(pNetwork->pIntNet->hHtIfs, pIf, pSession, (uint32_t *)&pIf->hIf);
    35324167                if (RT_SUCCESS(rc))
    35334168                {
    3534                     pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, intnetR0IfDestruct, pIf, pNetwork->pIntNet);
    3535                     if (pIf->pvObj)
    3536                     {
    3537                         rc = RTHandleTableAllocWithCtx(pNetwork->pIntNet->hHtIfs, pIf, pSession, (uint32_t *)&pIf->hIf);
    3538                         if (RT_SUCCESS(rc))
    3539                         {
    3540                             *phIf = pIf->hIf;
    3541                             Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%RX32 cbSend=%u cbRecv=%u cbBuf=%u\n",
    3542                                  *phIf, pIf->pIntBufDefault->cbSend, pIf->pIntBufDefault->cbRecv, pIf->pIntBufDefault->cbBuf));
    3543                             return VINF_SUCCESS;
    3544                         }
    3545 
    3546                         SUPR0ObjRelease(pIf->pvObj, pSession);
    3547                         LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
    3548                         return rc;
    3549                     }
    3550 
    3551                     SUPR0ObjRelease(pNetwork->pvObj, pSession);
     4169                    /*
     4170                     * Finally add the interface to the network, consuming the
     4171                     * network reference of the caller.
     4172                     */
     4173                    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     4174                    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     4175
     4176                    uint32_t iIf = pNetwork->MacTab.cEntries;
     4177                    Assert(iIf + 1 <= pNetwork->MacTab.cEntriesAllocated);
     4178
     4179                    pNetwork->MacTab.paEntries[iIf].MacAddr         = pIf->MacAddr;
     4180                    pNetwork->MacTab.paEntries[iIf].fActive         = false;
     4181                    pNetwork->MacTab.paEntries[iIf].fPromiscuous    = false;
     4182                    pNetwork->MacTab.paEntries[iIf].pIf             = pIf;
     4183
     4184                    pNetwork->MacTab.cEntries = iIf + 1;
     4185                    pIf->pNetwork = pNetwork;
     4186
     4187                    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     4188
     4189                    *phIf = pIf->hIf;
     4190                    Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%RX32 cbSend=%u cbRecv=%u cbBuf=%u\n",
     4191                         *phIf, pIf->pIntBufDefault->cbSend, pIf->pIntBufDefault->cbRecv, pIf->pIntBufDefault->cbBuf));
     4192                    return VINF_SUCCESS;
    35524193                }
    35534194
    3554                 RTSemFastMutexDestroy(pNetwork->FastMutex2);
    3555                 pNetwork->FastMutex2 = NIL_RTSEMFASTMUTEX;
     4195                SUPR0ObjRelease(pIf->pvObj, pSession);
     4196                LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
     4197                return rc;
    35564198            }
    35574199
     4200            /* clean up */
    35584201            SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
    35594202            pIf->pIntBufDefault = NULL;
    35604203            pIf->pIntBuf = NULL;
    35614204        }
    3562 
    3563         RTSemEventDestroy(pIf->Event);
    3564         pIf->Event = NIL_RTSEMEVENT;
    3565     }
     4205    }
     4206
     4207    RTSpinlockDestroy(pIf->hRecvInSpinlock);
     4208    pIf->hRecvInSpinlock = NIL_RTSPINLOCK;
     4209    RTSemEventDestroy(pIf->hRecvEvent);
     4210    pIf->hRecvEvent = NIL_RTSEMEVENT;
     4211    RTMemFree(pIf->pDstTab);
    35664212    RTMemFree(pIf);
    35674213    LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
     
    36074253    /* assert some sanity */
    36084254    AssertPtrReturn(pNetwork, INTNETSWDECISION_TRUNK);
    3609     AssertReturn(pNetwork->FastMutex2 != NIL_RTSEMFASTMUTEX, INTNETSWDECISION_TRUNK);
     4255    AssertReturn(pNetwork->hEvtBusyIf != NIL_RTSEMEVENT, INTNETSWDECISION_TRUNK);
    36104256    AssertPtr(pvSrc);
    36114257    AssertPtr(cbSrc >= 6);
     
    36224268{
    36234269    PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
    3624     PINTNETNETWORK pNetwork = pThis->pNetwork;
    36254270
    36264271    /* assert some sanity */
    3627     AssertPtrReturn(pNetwork, false);
    3628     AssertReturn(pNetwork->FastMutex2 != NIL_RTSEMFASTMUTEX, false);
    36294272    AssertPtr(pSG);
    36304273    Assert(fSrc);
    36314274
    36324275    /*
    3633      * Lock the network and send the frame to it.
    3634      */
    3635     int rc = RTSemFastMutexRequest(pNetwork->FastMutex2);
    3636     AssertRCReturn(rc, false);
    3637 
    3638     bool fRc;
    3639     if (RT_LIKELY(pNetwork->cActiveIFs > 0))
    3640         fRc = intnetR0NetworkSend(pNetwork, NULL, fSrc, pSG, false /* fTrunkLocked */);
    3641     else
    3642         fRc = false; /* don't drop it */
    3643 
    3644     rc = RTSemFastMutexRelease(pNetwork->FastMutex2);
    3645     AssertRC(rc);
    3646 
     4276     * Mark the trunk as busy, make sure we've got a network and that there are
     4277     * some active interfaces around.
     4278     */
     4279    bool fRc = false /* don't drop it */;
     4280    intnetR0BusyIncTrunk(pThis);
     4281    PINTNETNETWORK pNetwork = pThis->pNetwork;
     4282    if (RT_LIKELY(   pNetwork
     4283                  && pNetwork->cActiveIFs > 0 ))
     4284    {
     4285        /*
     4286         * Grab or allocate a destination table.
     4287         */
     4288        bool const      fIntCtx = RTThreadPreemptIsEnabled(NIL_RTTHREAD) || RTThreadIsInInterrupt(NIL_RTTHREAD);
     4289        unsigned        iDstTab = 0;
     4290        PINTNETDSTTAB   pDstTab = NULL;
     4291        RTSPINLOCKTMP   Tmp     = RTSPINLOCKTMP_INITIALIZER;
     4292        RTSpinlockAcquireNoInts(pThis->hDstTabSpinlock, &Tmp);
     4293        if (fIntCtx)
     4294        {
     4295            /* Interrupt or restricted context. */
     4296            iDstTab  = RTMpCpuIdToSetIndex(RTMpCpuId());
     4297            iDstTab %= pThis->cIntDstTabs;
     4298            pDstTab  = pThis->apIntDstTabs[iDstTab];
     4299            if (RT_LIKELY(pDstTab))
     4300                pThis->apIntDstTabs[iDstTab] = NULL;
     4301            else
     4302            {
     4303                iDstTab = pThis->cIntDstTabs;
     4304                while (iDstTab-- > 0)
     4305                {
     4306                    pDstTab = pThis->apIntDstTabs[iDstTab];
     4307                    if (pDstTab)
     4308                    {
     4309                        pThis->apIntDstTabs[iDstTab] = NULL;
     4310                        break;
     4311                    }
     4312                }
     4313            }
     4314            RTSpinlockReleaseNoInts(pThis->hDstTabSpinlock, &Tmp);
     4315            Assert(!pDstTab || iDstTab < pThis->cIntDstTabs);
     4316        }
     4317        else
     4318        {
     4319            /* Task context, fallback is to allocate a table. */
     4320            AssertCompile(RT_ELEMENTS(pThis->apTaskDstTabs) == 2); /* for loop rollout */
     4321            pDstTab = pThis->apIntDstTabs[iDstTab = 0];
     4322            if (!pDstTab)
     4323                pDstTab = pThis->apIntDstTabs[iDstTab = 1];
     4324            if (pDstTab)
     4325            {
     4326                pThis->apIntDstTabs[iDstTab] = NULL;
     4327                RTSpinlockReleaseNoInts(pThis->hDstTabSpinlock, &Tmp);
     4328                Assert(iDstTab < RT_ELEMENTS(pThis->apTaskDstTabs));
     4329            }
     4330            else
     4331            {
     4332                RTSpinlockReleaseNoInts(pThis->hDstTabSpinlock, &Tmp);
     4333                intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, &pDstTab);
     4334                iDstTab = 65535;
     4335            }
     4336        }
     4337        if (RT_LIKELY(pDstTab))
     4338        {
     4339            /*
     4340             * Finally, get down to business of sending the frame.
     4341             */
     4342            INTNETSWDECISION enmSwDecision = intnetR0NetworkSend(pNetwork, NULL, fSrc, pSG, pDstTab);
     4343            Assert(enmSwDecision != INTNETSWDECISION_BAD_CONTEXT);
     4344            if (enmSwDecision == INTNETSWDECISION_INTNET)
     4345                fRc = true; /* drop it */
     4346
     4347            /*
     4348             * Free the destination table.
     4349             */
     4350            if (iDstTab == 65535)
     4351                RTMemFree(pDstTab);
     4352            else
     4353            {
     4354                RTSpinlockAcquireNoInts(pThis->hDstTabSpinlock, &Tmp);
     4355                if (fIntCtx && !pThis->apIntDstTabs[iDstTab])
     4356                    pThis->apIntDstTabs[iDstTab]  = pDstTab;
     4357                else if (!fIntCtx && !pThis->apTaskDstTabs[iDstTab])
     4358                    pThis->apTaskDstTabs[iDstTab] = pDstTab;
     4359                else
     4360                {
     4361                    /* this shouldn't happen! */
     4362                    PINTNETDSTTAB *papDstTabs = fIntCtx ? &pThis->apIntDstTabs[0] :            &pThis->apTaskDstTabs[0];
     4363                    iDstTab                   = fIntCtx ? pThis->cIntDstTabs      : RT_ELEMENTS(pThis->apTaskDstTabs);
     4364                    while (iDstTab-- > 0)
     4365                        if (!papDstTabs[iDstTab])
     4366                        {
     4367                            papDstTabs[iDstTab] = pDstTab;
     4368                            break;
     4369                        }
     4370                }
     4371                RTSpinlockReleaseNoInts(pThis->hDstTabSpinlock, &Tmp);
     4372                Assert(iDstTab < RT_MAX(RT_ELEMENTS(pThis->apTaskDstTabs), pThis->cIntDstTabs));
     4373            }
     4374        }
     4375    }
     4376
     4377    intnetR0BusyDecTrunk(pThis);
    36474378    return fRc;
    36484379}
     
    36574388    /* assert some sanity */
    36584389    AssertPtrReturnVoid(pNetwork);
    3659     AssertReturnVoid(pNetwork->FastMutex2 != NIL_RTSEMFASTMUTEX);
     4390    AssertReturnVoid(pNetwork->hEvtBusyIf != NIL_RTSEMEVENT);
    36604391    AssertPtr(pSG);
    36614392    Assert(pSG->cUsers > 0 && pSG->cUsers < 256);
     
    36744405    /* assert some sanity */
    36754406    AssertPtrReturnVoid(pNetwork);
    3676     AssertReturnVoid(pNetwork->FastMutex2 != NIL_RTSEMFASTMUTEX);
     4407    AssertReturnVoid(pNetwork->hEvtBusyIf != NIL_RTSEMEVENT);
    36774408    AssertPtr(pSG);
    36784409    Assert(pSG->cUsers > 0);
     
    37334464{
    37344465    AssertPtrReturn(pThis, false);
    3735     int rc = RTSemFastMutexRequest(pThis->FastMutex);
     4466    int rc = RTSemFastMutexRequest(pThis->FastMutex3);
    37364467    if (RT_SUCCESS(rc))
    37374468    {
    37384469        if (RT_LIKELY(pThis->pIfPort))
    37394470            return true;
    3740         RTSemFastMutexRelease(pThis->FastMutex);
     4471        RTSemFastMutexRelease(pThis->FastMutex3);
    37414472    }
    37424473    else
     
    37554486    if (pThis)
    37564487    {
    3757         int rc = RTSemFastMutexRelease(pThis->FastMutex);
     4488        int rc = RTSemFastMutexRelease(pThis->FastMutex3);
    37584489        AssertRC(rc);
    37594490    }
     
    37624493
    37634494/**
    3764  * Activates the trunk interface.
     4495 * Deactivates the trunk interface.
    37654496 *
    37664497 * @param   pThis       The trunk.
    3767  * @param   fActive     What to do with it.
    37684498 *
    37694499 * @remarks Caller may only own the create/destroy lock.
    37704500 */
    3771 static void intnetR0TrunkIfActivate(PINTNETTRUNKIF pThis, bool fActive)
     4501static void intnetR0TrunkIfDeactivate(PINTNETTRUNKIF pThis)
    37724502{
    37734503    if (intnetR0TrunkIfOutLock(pThis))
    37744504    {
    3775         pThis->pIfPort->pfnSetActive(pThis->pIfPort, fActive);
     4505        pThis->pIfPort->pfnSetActive(pThis->pIfPort, false /*fActive*/);
    37764506        intnetR0TrunkIfOutUnlock(pThis);
    37774507    }
     
    38434573     * Free up the resources.
    38444574     */
    3845     RTSEMFASTMUTEX hFastMutex = pThis->FastMutex;
    3846     pThis->FastMutex = NIL_RTSEMMUTEX;
    3847     pThis->pNetwork = NULL;
     4575    RTSEMFASTMUTEX hFastMutex = pThis->FastMutex3;
     4576    pThis->FastMutex3 = NIL_RTSEMMUTEX;
     4577    pThis->pNetwork   = NULL;
    38484578    RTSemFastMutexRelease(hFastMutex);
    38494579    RTSemFastMutexDestroy(hFastMutex);
     4580    RTSpinlockDestroy(pThis->hDstTabSpinlock);
     4581    for (unsigned i = 0; i < RT_ELEMENTS(pThis->apTaskDstTabs); i++)
     4582    {
     4583        Assert(pThis->apTaskDstTabs[i]);
     4584        RTMemFree(pThis->apTaskDstTabs[i]);
     4585        pThis->apTaskDstTabs[i] = NULL;
     4586    }
     4587    for (unsigned i = 0; i < pThis->cIntDstTabs; i++)
     4588    {
     4589        Assert(pThis->apIntDstTabs[i]);
     4590        RTMemFree(pThis->apIntDstTabs[i]);
     4591        pThis->apIntDstTabs[i] = NULL;
     4592    }
    38504593    RTMemFree(pThis);
    38514594}
     
    38954638
    38964639    /*
    3897      * Allocate the trunk interface.
    3898      */
    3899     PINTNETTRUNKIF pTrunkIF = (PINTNETTRUNKIF)RTMemAllocZ(sizeof(*pTrunkIF));
    3900     if (!pTrunkIF)
     4640     * Allocate the trunk interface and associated destination tables.
     4641     *
     4642     * We take a very optimistic view on the parallelism of the host
     4643     * network stack and NIC driver.  So, we allocate one table for each
     4644     * possible CPU to deal with interrupt time requests and one for task
     4645     * time calls.
     4646     */
     4647    RTCPUID         cCpus    = RTMpGetCount(); Assert(cCpus > 0);
     4648    PINTNETTRUNKIF  pTrunk = (PINTNETTRUNKIF)RTMemAllocZ(RT_OFFSETOF(INTNETTRUNKIF, apIntDstTabs[cCpus]));
     4649    if (!pTrunk)
    39014650        return VERR_NO_MEMORY;
    3902     pTrunkIF->SwitchPort.u32Version                 = INTNETTRUNKSWPORT_VERSION;
    3903     pTrunkIF->SwitchPort.pfnPreRecv                 = intnetR0TrunkIfPortPreRecv;
    3904     pTrunkIF->SwitchPort.pfnRecv                    = intnetR0TrunkIfPortRecv;
    3905     pTrunkIF->SwitchPort.pfnSGRetain                = intnetR0TrunkIfPortSGRetain;
    3906     pTrunkIF->SwitchPort.pfnSGRelease               = intnetR0TrunkIfPortSGRelease;
    3907     pTrunkIF->SwitchPort.pfnSetSGPhys               = intnetR0TrunkIfPortSetSGPhys;
    3908     pTrunkIF->SwitchPort.pfnReportGsoCapabilities   = intnetR0TrunkIfPortReportGsoCapabilities;
    3909     pTrunkIF->SwitchPort.u32VersionEnd              = INTNETTRUNKSWPORT_VERSION;
    3910     //pTrunkIF->pIfPort = NULL;
    3911     pTrunkIF->pNetwork = pNetwork;
    3912     pTrunkIF->CachedMac.au8[0] = 0xfe;
    3913     pTrunkIF->CachedMac.au8[1] = 0xff;
    3914     pTrunkIF->CachedMac.au8[2] = 0xff;
    3915     pTrunkIF->CachedMac.au8[3] = 0xff;
    3916     pTrunkIF->CachedMac.au8[4] = 0xff;
    3917     pTrunkIF->CachedMac.au8[5] = 0xff;
    3918     //pTrunkIF->fPhysSG = false;
    3919     //pTrunkIF->fWirePromiscuous = false;
    3920     //pTrunkIF->fGroksGso = false;  /** @todo query GSO support after connecting. */
    3921     int rc = RTSemFastMutexCreate(&pTrunkIF->FastMutex);
     4651
     4652    Assert(pNetwork->MacTab.cEntriesAllocated > 0);
     4653    int rc = VINF_SUCCESS;
     4654    pTrunk->cIntDstTabs = cCpus;
     4655    for (unsigned i = 0; i < cCpus && RT_SUCCESS(rc); i++)
     4656        rc = intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, &pTrunk->apIntDstTabs[i]);
     4657    for (unsigned i = 0; i < RT_ELEMENTS(pTrunk->apTaskDstTabs) && RT_SUCCESS(rc); i++)
     4658        rc = intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, &pTrunk->apTaskDstTabs[i]);
     4659
    39224660    if (RT_SUCCESS(rc))
    39234661    {
    3924 #ifdef IN_RING0 /* (testcase is ring-3) */
     4662        pTrunk->SwitchPort.u32Version                 = INTNETTRUNKSWPORT_VERSION;
     4663        pTrunk->SwitchPort.pfnPreRecv                 = intnetR0TrunkIfPortPreRecv;
     4664        pTrunk->SwitchPort.pfnRecv                    = intnetR0TrunkIfPortRecv;
     4665        pTrunk->SwitchPort.pfnSGRetain                = intnetR0TrunkIfPortSGRetain;
     4666        pTrunk->SwitchPort.pfnSGRelease               = intnetR0TrunkIfPortSGRelease;
     4667        pTrunk->SwitchPort.pfnSetSGPhys               = intnetR0TrunkIfPortSetSGPhys;
     4668        pTrunk->SwitchPort.pfnReportGsoCapabilities   = intnetR0TrunkIfPortReportGsoCapabilities;
     4669        pTrunk->SwitchPort.u32VersionEnd              = INTNETTRUNKSWPORT_VERSION;
     4670        pTrunk->FastMutex3                = NIL_RTSEMFASTMUTEX;
     4671        //pTrunk->pIfPort                 = NULL;
     4672        pTrunk->pNetwork                  = pNetwork;
     4673        pTrunk->MacAddr.au8[0]            = 0xff;
     4674        pTrunk->MacAddr.au8[1]            = 0xff;
     4675        pTrunk->MacAddr.au8[2]            = 0xff;
     4676        pTrunk->MacAddr.au8[3]            = 0xff;
     4677        pTrunk->MacAddr.au8[4]            = 0xff;
     4678        pTrunk->MacAddr.au8[5]            = 0xff;
     4679        //pTrunk->fWireNoPreempt          = false;
     4680        //pTrunk->fHostNoPreempt          = false;
     4681        //pTrunk->fPhysSG                 = false;
     4682        //pTrunk->cBusy                   = 0;
     4683        //pTrunk->fWireGsoCapabilites     = 0;
     4684        //pTrunk->fHostGsoCapabilites     = 0;
     4685        //pTrunk->abGsoHdrs               = {0};
     4686        pTrunk->hDstTabSpinlock           = NIL_RTSPINLOCK;
     4687        //pTrunk->apTaskDstTabs           = above;
     4688        //pTrunk->cIntDstTabs             = above;
     4689        //pTrunk->apIntDstTabs            = above;
     4690
    39254691        /*
    3926          * Query the factory we want, then use it create and connect the trunk.
     4692         * Create the locks (we've NIL'ed the members above to simplify cleanup).
    39274693         */
    3928         PINTNETTRUNKFACTORY pTrunkFactory = NULL;
    3929         rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory);
     4694        rc = RTSemFastMutexCreate(&pTrunk->FastMutex3);
     4695        if (RT_SUCCESS(rc))
     4696            rc = RTSpinlockCreate(&pTrunk->hDstTabSpinlock);
    39304697        if (RT_SUCCESS(rc))
    39314698        {
    3932             rc = pTrunkFactory->pfnCreateAndConnect(pTrunkFactory, pNetwork->szTrunk, &pTrunkIF->SwitchPort,
    3933                                                     pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE
    3934                                                     ? INTNETTRUNKFACTORY_FLAG_NO_PROMISC : 0,
    3935                                                     &pTrunkIF->pIfPort);
    3936             pTrunkFactory->pfnRelease(pTrunkFactory);
     4699#ifdef IN_RING0 /* (testcase is ring-3) */
     4700            /*
     4701             * Query the factory we want, then use it create and connect the trunk.
     4702             */
     4703            PINTNETTRUNKFACTORY pTrunkFactory = NULL;
     4704            rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory);
    39374705            if (RT_SUCCESS(rc))
    39384706            {
    3939                 Assert(pTrunkIF->pIfPort);
    3940                 pNetwork->pTrunkIF = pTrunkIF;
    3941                 Log(("intnetR0NetworkCreateTrunkIf: VINF_SUCCESS - pszName=%s szTrunk=%s%s Network=%s\n",
    3942                      pszName, pNetwork->szTrunk, pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE ? " shared-mac" : "", pNetwork->szName));
    3943                 return VINF_SUCCESS;
     4707                rc = pTrunkFactory->pfnCreateAndConnect(pTrunkFactory, pNetwork->szTrunk, &pTrunk->SwitchPort,
     4708                                                        pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE
     4709                                                        ? INTNETTRUNKFACTORY_FLAG_NO_PROMISC : 0,
     4710                                                        &pTrunk->pIfPort);
     4711                pTrunkFactory->pfnRelease(pTrunkFactory);
     4712                if (RT_SUCCESS(rc))
     4713                {
     4714                    Assert(pTrunk->pIfPort);
     4715                    pNetwork->MacTab.pTrunk = pTrunk;
     4716
     4717                    /*
     4718                     * Query the host info.
     4719                     *
     4720                     * Note! We don't need to lock the MacTab here since the
     4721                     *       network is being created.
     4722                     */
     4723                    /** @todo this should be reported by VBoxNet* instead of queried by us! */
     4724                    intnetR0TrunkIfOutLock(pTrunk);
     4725
     4726                    pTrunk->pIfPort->pfnGetMacAddress(pTrunk->pIfPort, &pTrunk->MacAddr);
     4727                    pNetwork->MacTab.HostMac          = pTrunk->MacAddr;
     4728
     4729                    pNetwork->MacTab.fHostPromiscuous = pTrunk->pIfPort->pfnIsPromiscuous(pTrunk->pIfPort);
     4730                    pNetwork->MacTab.fHostActive      = true;
     4731
     4732                    pNetwork->MacTab.fWirePromiscuous = false; /** @todo !!(fFlags & INTNET_OPEN_FLAGS_PROMISC_TRUNK_WIRE); */
     4733                    pNetwork->MacTab.fWireActive      = true;
     4734
     4735                    intnetR0TrunkIfOutUnlock(pTrunk);
     4736
     4737                    Log(("intnetR0NetworkCreateTrunkIf: VINF_SUCCESS - pszName=%s szTrunk=%s%s Network=%s\n",
     4738                         pszName, pNetwork->szTrunk, pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE ? " shared-mac" : "", pNetwork->szName));
     4739                    return VINF_SUCCESS;
     4740                }
    39444741            }
     4742#else  /* IN_RING3 */
     4743            rc = VERR_NOT_SUPPORTED;
     4744#endif /* IN_RING3 */
    39454745        }
    3946 #endif /* IN_RING0 */
    3947         RTSemFastMutexDestroy(pTrunkIF->FastMutex);
    3948     }
    3949     RTMemFree(pTrunkIF);
     4746
     4747        /* bail out and clean up. */
     4748        RTSpinlockDestroy(pTrunk->hDstTabSpinlock);
     4749        RTSemFastMutexDestroy(pTrunk->FastMutex3);
     4750    }
     4751
     4752    for (unsigned i = 0; i < RT_ELEMENTS(pTrunk->apTaskDstTabs); i++)
     4753        RTMemFree(pTrunk->apTaskDstTabs[i]);
     4754    for (unsigned i = 0; i < pTrunk->cIntDstTabs; i++)
     4755        RTMemFree(pTrunk->apIntDstTabs[i]);
     4756    RTMemFree(pTrunk);
     4757
    39504758    LogFlow(("intnetR0NetworkCreateTrunkIf: %Rrc - pszName=%s szTrunk=%s Network=%s\n",
    39514759             rc, pszName, pNetwork->szTrunk, pNetwork->szName));
     
    39664774{
    39674775    PINTNETNETWORK  pNetwork = (PINTNETNETWORK)pvUser1;
    3968     PINTNET         pIntNet = (PINTNET)pvUser2;
     4776    PINTNET         pIntNet  = (PINTNET)pvUser2;
    39694777    Log(("intnetR0NetworkDestruct: pvObj=%p pNetwork=%p pIntNet=%p %s\n", pvObj, pNetwork, pIntNet, pNetwork->szName));
    39704778    Assert(pNetwork->pIntNet == pIntNet);
    39714779
    3972     /* take the create/destroy sem. */
     4780    /* Take the big create/open/destroy sem. */
    39734781    RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
    39744782
     
    39764784     * Deactivate the trunk connection first (if any).
    39774785     */
    3978     if (pNetwork->pTrunkIF)
    3979         intnetR0TrunkIfActivate(pNetwork->pTrunkIF, false /* fActive */);
     4786    if (pNetwork->MacTab.pTrunk)
     4787        intnetR0TrunkIfDeactivate(pNetwork->MacTab.pTrunk);
     4788
     4789    /*
     4790     * Deactivate and orphan any remaining interfaces and wait for them to idle.
     4791     *
     4792     * Note! Normally there are no more interfaces at this point, however, when
     4793     *       supdrvCloseSession / supdrvCleanupSession release the objects the
     4794     *       order is undefined.  So, it's quite possible that the network will
     4795     *       be dereference and destroyed before the interfaces.
     4796     */
     4797    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     4798    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     4799
     4800    uint32_t iIf = pNetwork->MacTab.cEntries;
     4801    while (iIf-- > 0)
     4802    {
     4803        pNetwork->MacTab.paEntries[iIf].fActive      = false;
     4804        pNetwork->MacTab.paEntries[iIf].pIf->fActive = false;
     4805    }
     4806
     4807    pNetwork->MacTab.fHostActive = false;
     4808    pNetwork->MacTab.fWireActive = false;
     4809
     4810    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     4811
     4812    /* Wait for all the interfaces to quiesce.  (Interfaces cannot be
     4813       removed / added since we're holding the big lock.) */
     4814    if (pNetwork->MacTab.pTrunk)
     4815        intnetR0BusyWait(pNetwork, &pNetwork->MacTab.pTrunk->cBusy);
     4816
     4817    iIf = pNetwork->MacTab.cEntries;
     4818    while (iIf-- > 0)
     4819        intnetR0BusyWait(pNetwork, &pNetwork->MacTab.paEntries[iIf].pIf->cBusy);
     4820
     4821    /* Orphan the interfaces (not trunk). */
     4822    RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     4823    while ((iIf = pNetwork->MacTab.cEntries) > 0)
     4824    {
     4825        PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf - 1].pIf;
     4826        RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     4827
     4828        intnetR0BusyWait(pNetwork, &pIf->cBusy);
     4829
     4830        RTSpinlockAcquireNoInts(pNetwork->hAddrSpinlock, &Tmp);
     4831        if (   iIf == pNetwork->MacTab.cEntries /* paranoia */
     4832            && pIf->cBusy)
     4833        {
     4834            pIf->pNetwork = NULL;
     4835            pNetwork->MacTab.cEntries--;
     4836        }
     4837    }
     4838
     4839    /*
     4840     * Grab and zap the trunk pointer while we still own the spinlock, destroy
     4841     * the trunk after we've left it.  Note that this might take a while...
     4842     */
     4843    PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk;
     4844    pNetwork->MacTab.pTrunk = NULL;
     4845
     4846    RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
     4847
     4848    if (pTrunk)
     4849        intnetR0TrunkIfDestroy(pTrunk, pNetwork);
    39804850
    39814851    /*
     
    39994869
    40004870    /*
    4001      * Because of the undefined order of the per session object dereferencing
    4002      * when closing a session, we have to handle the case where the network is
    4003      * destroyed before the interfaces.
    4004      * We deal with this simply by orphaning the interfaces.
    4005      */
    4006     RTSemFastMutexRequest(pNetwork->FastMutex2);
    4007 
    4008     PINTNETIF pCur = pNetwork->pIfs;
    4009     while (pCur)
    4010     {
    4011         PINTNETIF pNext = pCur->pNext;
    4012         pCur->pNext    = NULL;
    4013         pCur->pNetwork = NULL;
    4014         pCur = pNext;
    4015     }
    4016 
    4017     /* Grab and zap the trunk pointer before leaving the mutex. */
    4018     PINTNETTRUNKIF pTrunkIF = pNetwork->pTrunkIF;
    4019     pNetwork->pTrunkIF = NULL;
    4020 
    4021     RTSemFastMutexRelease(pNetwork->FastMutex2);
    4022 
    4023     /*
    4024      * If there is a trunk, delete it.
    4025      * Note that this may tak a while if we're unlucky...
    4026      */
    4027     if (pTrunkIF)
    4028         intnetR0TrunkIfDestroy(pTrunkIF, pNetwork);
    4029 
    4030     /*
    40314871     * Free resources.
    40324872     */
    4033     RTSemFastMutexDestroy(pNetwork->FastMutex2);
    4034     pNetwork->FastMutex2 = NIL_RTSEMFASTMUTEX;
     4873    RTSemEventDestroy(pNetwork->hEvtBusyIf);
     4874    pNetwork->hEvtBusyIf = NIL_RTSEMEVENT;
     4875    RTSpinlockDestroy(pNetwork->hAddrSpinlock);
     4876    pNetwork->hAddrSpinlock = NIL_RTSPINLOCK;
     4877    RTMemFree(pNetwork->MacTab.paEntries);
     4878    pNetwork->MacTab.paEntries = NULL;
    40354879    RTMemFree(pNetwork);
    40364880
    4037     /* release the create/destroy sem. (can be done before trunk destruction.) */
     4881    /* Release the create/destroy sem. */
    40384882    RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
    40394883}
     
    41745018    if (fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
    41755019        cb += INTNETNETWORK_TMP_SIZE + 64;
    4176     PINTNETNETWORK pNew = (PINTNETNETWORK)RTMemAllocZ(cb);
    4177     if (!pNew)
     5020    PINTNETNETWORK pNetwork = (PINTNETNETWORK)RTMemAllocZ(cb);
     5021    if (!pNetwork)
    41785022        return VERR_NO_MEMORY;
    4179     int rc = RTSemFastMutexCreate(&pNew->FastMutex2);
     5023    //pNetwork->pNext                   = NULL;
     5024    //pNetwork->pIfs                    = NULL;
     5025    pNetwork->hAddrSpinlock             = NIL_RTSPINLOCK;
     5026    pNetwork->MacTab.cEntries           = 0;
     5027    pNetwork->MacTab.cEntriesAllocated  = INTNET_GROW_DSTTAB_SIZE;
     5028    pNetwork->MacTab.paEntries          = NULL;
     5029    pNetwork->MacTab.fHostPromiscuous   = false;
     5030    pNetwork->MacTab.fHostActive        = false;
     5031    pNetwork->MacTab.fWirePromiscuous   = false;
     5032    pNetwork->MacTab.fWireActive        = false;
     5033    pNetwork->MacTab.pTrunk             = NULL;
     5034    pNetwork->hEvtBusyIf                = NIL_RTSEMEVENT;
     5035    pNetwork->pIntNet                   = pIntNet;
     5036    //pNetwork->pvObj                   = NULL;
     5037    if (fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
     5038        pNetwork->pbTmp                 = RT_ALIGN_PT(pNetwork + 1, 64, uint8_t *);
     5039    //else
     5040    //    pNetwork->pbTmp               = NULL;
     5041    pNetwork->fFlags                    = fFlags;
     5042    //pNetwork->cActiveIFs              = 0;
     5043    size_t cchName                      = strlen(pszNetwork);
     5044    pNetwork->cchName                   = (uint8_t)cchName;
     5045    Assert(cchName && cchName < sizeof(pNetwork->szName));  /* caller's responsibility. */
     5046    memcpy(pNetwork->szName, pszNetwork, cchName);          /* '\0' at courtesy of alloc. */
     5047    pNetwork->enmTrunkType              = enmTrunkType;
     5048    Assert(strlen(pszTrunk) < sizeof(pNetwork->szTrunk));   /* caller's responsibility. */
     5049    strcpy(pNetwork->szTrunk, pszTrunk);
     5050
     5051    /*
     5052     * Create the semaphore, spinlock and allocate the interface table.
     5053     */
     5054    int rc = RTSemEventCreate(&pNetwork->hEvtBusyIf);
    41805055    if (RT_SUCCESS(rc))
    4181     {
    4182         //pNew->pIfs        = NULL;
    4183         pNew->pIntNet       = pIntNet;
    4184         //pNew->cActiveIFs  = 0;
    4185         pNew->fFlags        = fFlags;
    4186         size_t cchName      = strlen(pszNetwork);
    4187         pNew->cchName       = (uint8_t)cchName;
    4188         Assert(cchName && cchName < sizeof(pNew->szName));  /* caller's responsibility. */
    4189         memcpy(pNew->szName, pszNetwork, cchName);          /* '\0' by alloc. */
    4190         pNew->enmTrunkType  = enmTrunkType;
    4191         Assert(strlen(pszTrunk) < sizeof(pNew->szTrunk));   /* caller's responsibility. */
    4192         strcpy(pNew->szTrunk, pszTrunk);
    4193         if (fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
    4194             pNew->pbTmp     = RT_ALIGN_PT(pNew + 1, 64, uint8_t *);
    4195         //else
    4196         //    pNew->pbTmp   = NULL;
    4197 
     5056        rc = RTSpinlockCreate(&pNetwork->hAddrSpinlock);
     5057    if (RT_SUCCESS(rc))
     5058    {
     5059        pNetwork->MacTab.paEntries = (PINTNETMACTABENTRY)RTMemAlloc(sizeof(INTNETMACTABENTRY) * pNetwork->MacTab.cEntriesAllocated);
     5060        if (!pNetwork->MacTab.paEntries)
     5061            rc = VERR_NO_MEMORY;
     5062    }
     5063    if (RT_SUCCESS(rc))
     5064    {
    41985065        /*
    41995066         * Register the object in the current session and link it into the network list.
    42005067         */
    4201         pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNew, pIntNet);
    4202         if (pNew->pvObj)
     5068        pNetwork->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNetwork, pIntNet);
     5069        if (pNetwork->pvObj)
    42035070        {
    4204             pNew->pNext = pIntNet->pNetworks;
    4205             pIntNet->pNetworks = pNew;
     5071            pNetwork->pNext = pIntNet->pNetworks;
     5072            pIntNet->pNetworks = pNetwork;
    42065073
    42075074            /*
     
    42115078             * does no such checks.
    42125079             */
    4213             rc = SUPR0ObjVerifyAccess(pNew->pvObj, pSession, pNew->szName);
     5080            rc = SUPR0ObjVerifyAccess(pNetwork->pvObj, pSession, pNetwork->szName);
    42145081            if (RT_SUCCESS(rc))
    42155082            {
     
    42175084                 * Connect the trunk.
    42185085                 */
    4219                 rc = intnetR0NetworkCreateTrunkIf(pNew, pSession);
     5086                rc = intnetR0NetworkCreateTrunkIf(pNetwork, pSession);
    42205087                if (RT_SUCCESS(rc))
    42215088                {
    4222                     *ppNetwork = pNew;
    4223                     LogFlow(("intnetR0CreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNew));
     5089                    *ppNetwork = pNetwork;
     5090                    LogFlow(("intnetR0CreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNetwork));
    42245091                    return VINF_SUCCESS;
    42255092                }
    42265093            }
    42275094
    4228             SUPR0ObjRelease(pNew->pvObj, pSession);
     5095            SUPR0ObjRelease(pNetwork->pvObj, pSession);
    42295096            LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
    42305097            return rc;
    42315098        }
     5099
     5100        /* cleanup */
    42325101        rc = VERR_NO_MEMORY;
    4233 
    4234         RTSemFastMutexDestroy(pNew->FastMutex2);
    4235         pNew->FastMutex2 = NIL_RTSEMFASTMUTEX;
    4236     }
    4237     RTMemFree(pNew);
     5102    }
     5103
     5104    RTSemEventDestroy(pNetwork->hEvtBusyIf);
     5105    pNetwork->hEvtBusyIf = NIL_RTSEMEVENT;
     5106    RTSpinlockDestroy(pNetwork->hAddrSpinlock);
     5107    pNetwork->hAddrSpinlock = NIL_RTSPINLOCK;
     5108    RTMemFree(pNetwork->MacTab.paEntries);
     5109    pNetwork->MacTab.paEntries = NULL;
     5110    RTMemFree(pNetwork);
     5111
    42385112    LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
    42395113    return rc;
     
    43245198        if (RT_SUCCESS(rc))
    43255199            rc = VINF_ALREADY_INITIALIZED;
    4326         SUPR0ObjRelease(pNetwork->pvObj, pSession);
     5200        else
     5201            SUPR0ObjRelease(pNetwork->pvObj, pSession);
    43275202    }
    43285203    else if (rc == VERR_NOT_FOUND)
     
    43325207        {
    43335208            rc = intnetR0NetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, phIf);
    4334             SUPR0ObjRelease(pNetwork->pvObj, pSession);
     5209            if (RT_FAILURE(rc))
     5210                SUPR0ObjRelease(pNetwork->pvObj, pSession);
    43355211        }
    43365212    }
  • trunk/src/VBox/Devices/Network/testcase/tstIntNetR0.cpp

    r28314 r28623  
    4141#include <VBox/sup.h>
    4242#include <VBox/err.h>
     43#include <iprt/asm.h>
     44#include <iprt/getopt.h>
     45#include <iprt/initterm.h>
     46#include <iprt/mem.h>
     47#include <iprt/mp.h>
    4348#include <iprt/stream.h>
    44 #include <iprt/alloc.h>
    45 #include <iprt/initterm.h>
    4649#include <iprt/thread.h>
    4750#include <iprt/time.h>
    48 #include <iprt/asm.h>
    49 #include <iprt/getopt.h>
     51#include <iprt/test.h>
    5052
    5153
     
    98100*   Global Variables                                                           *
    99101*******************************************************************************/
    100 /** The error count. */
    101 unsigned g_cErrors = 0;
    102 
     102/** The test handle.*/
     103static RTTEST           g_hTest      = NIL_RTTEST;
     104/** The size (in bytes) of the large transfer tests. */
     105static uint32_t         g_cbTransfer = _1M * 384;
    103106/** Fake session handle. */
    104 const PSUPDRVSESSION g_pSession = (PSUPDRVSESSION)0xdeadface;
    105 
    106 /** Testframe 0 */
    107 struct TESTFRAME
    108 {
    109     uint16_t    au16[7];
    110 } g_TestFrame0 = { { /* dst:*/ 0xffff, 0xffff, 0xffff, /*src:*/0x8086, 0, 0, 0x0800 } },
    111   g_TestFrame1 = { { /* dst:*/ 0, 0, 0,                /*src:*/0x8086, 0, 1, 0x0800 } };
     107const PSUPDRVSESSION    g_pSession   = (PSUPDRVSESSION)0xdeadface;
    112108
    113109
    114110INTNETR3DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2)
    115111{
    116     if (pSession != g_pSession)
    117     {
    118         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    119         g_cErrors++;
    120         return NULL;
    121     }
    122     POBJREF pRef = (POBJREF)RTMemAlloc(sizeof(OBJREF));
     112    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, NULL);
     113    POBJREF pRef = (POBJREF)RTTestGuardedAllocTail(g_hTest, sizeof(OBJREF));
    123114    if (!pRef)
    124115        return NULL;
     
    132123INTNETR3DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking)
    133124{
    134     if (pSession != g_pSession)
    135     {
    136         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    137         g_cErrors++;
    138         return VERR_INVALID_PARAMETER;
    139     }
     125    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
    140126    POBJREF pRef = (POBJREF)pvObj;
    141127    ASMAtomicIncU32(&pRef->cRefs);
     
    150136INTNETR3DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession)
    151137{
    152     if (pSession != g_pSession)
    153     {
    154         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    155         g_cErrors++;
    156         return VERR_INVALID_PARAMETER;
    157     }
     138    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
    158139    POBJREF pRef = (POBJREF)pvObj;
    159140    if (!ASMAtomicDecU32(&pRef->cRefs))
    160141    {
    161142        pRef->pfnDestructor(pRef, pRef->pvUser1, pRef->pvUser2);
    162         RTMemFree(pRef);
     143        RTTestGuardedFree(g_hTest, pRef);
    163144        return VINF_OBJECT_DESTROYED;
    164145    }
     
    168149INTNETR3DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName)
    169150{
    170     if (pSession != g_pSession)
    171     {
    172         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    173         g_cErrors++;
    174         return VERR_INVALID_PARAMETER;
    175     }
     151    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
    176152    return VINF_SUCCESS;
    177153}
     
    179155INTNETR3DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3)
    180156{
    181     if (pSession != g_pSession)
    182     {
    183         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    184         g_cErrors++;
    185         return VERR_INVALID_PARAMETER;
    186     }
    187     void *pv = RTMemAlloc(cb);
     157    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
     158    void *pv = RTTestGuardedAllocTail(g_hTest, cb);
    188159    if (!pv)
    189160        return VERR_NO_MEMORY;
     
    196167INTNETR3DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
    197168{
    198     if (pSession != g_pSession)
    199     {
    200         RTPrintf("tstIntNetR0: Invalid session pointer %p, %s!\n", pSession, __FUNCTION__);
    201         g_cErrors++;
    202         return VERR_INVALID_PARAMETER;
    203     }
    204     RTMemFree((void *)uPtr);
     169    RTTEST_CHECK_RET(g_hTest, pSession == g_pSession, VERR_INVALID_PARAMETER);
     170    RTTestGuardedFree(g_hTest, (void *)uPtr);
    205171    return VINF_SUCCESS;
    206172}
    207173
     174/* Fake non-existing ring-0 APIs. */
     175#define RTThreadIsInInterrupt(hThread)      false
     176#define RTThreadPreemptIsEnabled(hThread)   true
     177#define RTMpCpuId()                         0
     178
     179/* No CLI/POPF, please. */
     180#define RTSpinlockAcquireNoInts             RTSpinlockAcquire
     181#define RTSpinlockReleaseNoInts             RTSpinlockRelease
    208182
    209183
     
    230204typedef struct MYARGS
    231205{
    232     PINTNET pIntNet;
    233     PINTNETBUF pBuf;
    234     INTNETIFHANDLE hIf;
    235     RTMAC Mac;
    236     uint64_t u64Start;
    237     uint64_t u64End;
     206    PINTNET         pIntNet;
     207    PINTNETBUF      pBuf;
     208    INTNETIFHANDLE  hIf;
     209    RTMAC           Mac;
     210    uint64_t        u64Start;
     211    uint64_t        u64End;
    238212} MYARGS, *PMYARGS;
    239213
    240214
    241 #define TEST_TRANSFER_SIZE (_1M*384)
     215/**
     216 * Frame header used when testing.
     217 */
     218#pragma pack(1)
     219typedef struct MYFRAMEHDR
     220{
     221    RTMAC       SrcMac;
     222    RTMAC       DstMac;
     223    uint32_t    iFrame;
     224    uint32_t    auEos[3];
     225} MYFRAMEHDR;
     226#pragma pack()
    242227
    243228/**
     
    248233{
    249234    PMYARGS pArgs = (PMYARGS)pvArg;
    250 
    251     /*
    252      * Send 64 MB of data.
    253      */
    254     uint8_t abBuf[4096] = {0};
    255     PRTMAC  pMacSrc = (PRTMAC)&abBuf[0];
    256     PRTMAC  pMacDst = pMacSrc + 1;
    257     *pMacSrc = pArgs->Mac;
    258     *pMacDst = pArgs->Mac;
    259     pMacDst->au16[2] = pArgs->Mac.au16[2] ? 0 : 1;
    260     unsigned *puFrame = (unsigned *)(pMacDst + 1);
    261     unsigned iFrame = 0;
    262     uint32_t cbSent = 0;
    263     uint32_t cSend  = 0;
     235    int rc;
     236
     237    /*
     238     * Send g_cbTransfer of data.
     239     */
     240    uint8_t         abBuf[4096] = {0};
     241    MYFRAMEHDR     *pHdr    = (MYFRAMEHDR *)&abBuf[0];
     242    uint32_t        iFrame  = 0;
     243    uint32_t        cbSent  = 0;
     244    uint32_t        cSend   = 0;
     245
     246    pHdr->SrcMac            = pArgs->Mac;
     247    pHdr->DstMac            = pArgs->Mac;
     248    pHdr->DstMac.au16[2]    = (pArgs->Mac.au16[2] + 1) % 2;
     249
    264250    pArgs->u64Start = RTTimeNanoTS();
    265     for (; cbSent < TEST_TRANSFER_SIZE; iFrame++)
    266     {
    267         const unsigned cb = iFrame % 1519 + 12 + sizeof(unsigned);
    268         *puFrame = iFrame;
     251    for (; cbSent < g_cbTransfer; iFrame++)
     252    {
     253        const unsigned cb = iFrame % 1519 + sizeof(RTMAC) * 2 + sizeof(unsigned);
     254         pHdr->iFrame = iFrame;
    269255
    270256        INTNETSG Sg;
    271257        INTNETSgInitTemp(&Sg, abBuf, cb);
    272         int rc = intnetR0RingWriteFrame(&pArgs->pBuf->Send, &Sg, NULL);
     258        RTTEST_CHECK_RC_OK(g_hTest, rc = intnetR0RingWriteFrame(&pArgs->pBuf->Send, &Sg, NULL));
    273259        if (RT_SUCCESS(rc))
    274             rc = INTNETR0IfSend(pArgs->pIntNet, pArgs->hIf, g_pSession);
    275         if (RT_FAILURE(rc))
    276         {
    277             g_cErrors++;
    278             RTPrintf("tstIntNetR0: Failed sending %d bytes, rc=%Rrc (%d)\n", cb, rc, INTNETRingGetWritable(&pArgs->pBuf->Send));
    279         }
     260            RTTEST_CHECK_RC_OK(g_hTest, rc = INTNETR0IfSend(pArgs->pIntNet, pArgs->hIf, g_pSession));
    280261        cbSent += cb;
    281262    }
     
    284265     * Termination frames.
    285266     */
    286     puFrame[0] = 0xffffdead;
    287     puFrame[1] = 0xffffdead;
    288     puFrame[2] = 0xffffdead;
    289     puFrame[3] = 0xffffdead;
     267    pHdr->iFrame  = 0xffffdead;
     268    pHdr->auEos[0] = 0xffffdead;
     269    pHdr->auEos[1] = 0xffffdead;
     270    pHdr->auEos[2] = 0xffffdead;
    290271    for (unsigned c = 0; c < 20; c++)
    291272    {
    292         int rc = tstIntNetSendBuf(pArgs->pIntNet, &pArgs->pBuf->Send, pArgs->hIf, g_pSession,
    293                                   abBuf, sizeof(RTMAC) * 2 + sizeof(unsigned) * 4);
    294         if (RT_FAILURE(rc))
    295         {
    296             g_cErrors++;
    297             RTPrintf("tstIntNetR0: send failed, rc=%Rrc\n", rc);
    298         }
     273        RTTEST_CHECK_RC_OK(g_hTest, rc = tstIntNetSendBuf(pArgs->pIntNet, &pArgs->pBuf->Send, pArgs->hIf, g_pSession,
     274                                                          abBuf, sizeof(RTMAC) * 2 + sizeof(unsigned) * 4));
    299275        RTThreadSleep(1);
    300276    }
    301277
    302     RTPrintf("tstIntNetR0: sender   thread %.6Rhxs terminating.\n"
    303              "tstIntNetR0:   iFrame=%u  cb=%'u\n",
    304              &pArgs->Mac, iFrame, cbSent);
     278    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     279                 "sender   thread %.6Rhxs terminating.\n"
     280                 "iFrame=%u  cb=%'u\n",
     281                 &pArgs->Mac, iFrame, cbSent);
    305282    return 0;
    306283}
     
    322299    for (;;)
    323300    {
     301        /*
     302         * Read data.
     303         */
     304        while (INTNETRingHasMoreToRead(&pArgs->pBuf->Recv))
     305        {
     306            uint8_t     abBuf[16384];
     307            MYFRAMEHDR *pHdr = (MYFRAMEHDR *)&abBuf[0];
     308            uint32_t    cb   = INTNETRingReadAndSkipFrame(&pArgs->pBuf->Recv, abBuf);
     309
     310            /* check for termination frame. */
     311            if (    pHdr->iFrame   == 0xffffdead
     312                &&  pHdr->auEos[0] == 0xffffdead
     313                &&  pHdr->auEos[1] == 0xffffdead
     314                &&  pHdr->auEos[2] == 0xffffdead)
     315            {
     316                pArgs->u64End = RTTimeNanoTS();
     317                RTThreadSleep(10);
     318                RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     319                             "receiver thread %.6Rhxs terminating.\n"
     320                             "  iFrame=%u  cb=%'u  c=%'u  %'uKB/s  %'ufps  cLost=%'u \n",
     321                             &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames,
     322                             (unsigned)(cbReceived * 1000000000.0 / 1024 / (pArgs->u64End - pArgs->u64Start)),
     323                             (unsigned)((iFrame - cLostFrames) * 1000000000.0 / (pArgs->u64End - pArgs->u64Start)),
     324                             cLostFrames);
     325                return VINF_SUCCESS;
     326            }
     327
     328            /* validate frame header */
     329            if (    pHdr->DstMac.au16[0] != pArgs->Mac.au16[0]
     330                ||  pHdr->DstMac.au16[1] != pArgs->Mac.au16[1]
     331                ||  pHdr->DstMac.au16[2] != pArgs->Mac.au16[2]
     332                ||  pHdr->SrcMac.au16[0] != pArgs->Mac.au16[0]
     333                ||  pHdr->SrcMac.au16[1] != pArgs->Mac.au16[1]
     334                ||  pHdr->SrcMac.au16[2] != (pArgs->Mac.au16[2] + 1) % 2)
     335            {
     336                RTTestFailed(g_hTest, "receiver thread %.6Rhxs received frame header: %.16Rhxs\n", &pArgs->Mac, abBuf);
     337            }
     338
     339            /* frame stuff and stats. */
     340            int32_t off = pHdr->iFrame - (iFrame + 1);
     341            if (off)
     342            {
     343                if (off > 0)
     344                {
     345#ifndef IGNORE_LOST_FRAMES
     346                    RTTestFailed(g_hTest, "receiver thread %.6Rhxs: iFrame=%#x *puFrame=%#x off=%d\n",
     347                                 &pArgs->Mac, iFrame, pHdr->iFrame, off);
     348#endif
     349                    cLostFrames += off;
     350                }
     351                else
     352                {
     353                    cLostFrames++;
     354                    RTTestFailed(g_hTest, "receiver thread %.6Rhxs: iFrame=%#x *puFrame=%#x off=%d\n",
     355                                 &pArgs->Mac, iFrame, pHdr->iFrame, off);
     356                }
     357            }
     358            iFrame = pHdr->iFrame;
     359            cbReceived += cb;
     360        }
     361
    324362        /*
    325363         * Wait for data.
     
    332370                break;
    333371            case VERR_SEM_DESTROYED:
    334                 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs terminating. iFrame=%u cb=%'u c=%'u cLost=%'u\n",
    335                          &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
     372                RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     373                             "receiver thread %.6Rhxs terminating. iFrame=%u cb=%'u c=%'u cLost=%'u\n",
     374                             &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
    336375                return VINF_SUCCESS;
    337376
    338377            default:
    339                 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs got odd return value %Rrc! iFrame=%u cb=%'u c=%'u cLost=%'u\n",
    340                          &pArgs->Mac, rc, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
    341                 g_cErrors++;
     378                RTTestFailed(g_hTest, "receiver thread %.6Rhxs got odd return value %Rrc! iFrame=%u cb=%'u c=%'u cLost=%'u\n",
     379                             &pArgs->Mac, rc, iFrame, cbReceived, iFrame - cLostFrames, cLostFrames);
    342380                return rc;
    343381        }
    344382
     383    }
     384}
     385
     386
     387/**
     388 * Test state.
     389 */
     390typedef struct TSTSTATE
     391{
     392    PINTNET         pIntNet;
     393
     394    PINTNETBUF      pBuf0;
     395    INTNETIFHANDLE  hIf0;
     396
     397    PINTNETBUF      pBuf1;
     398    INTNETIFHANDLE  hIf1;
     399} TSTSTATE;
     400typedef TSTSTATE *PTSTSTATE;
     401
     402
     403/**
     404 * Open two internal network interfaces.
     405 *
     406 * @returns IPRT status of the first failure.
     407 * @param   pThis               The test instance.
     408 */
     409static int tstOpenInterfaces(PTSTSTATE pThis, const char *pszNetwork, uint32_t cbSend, uint32_t cbRecv)
     410{
     411    pThis->hIf0 = INTNET_HANDLE_INVALID;
     412    RTTESTI_CHECK_RC_OK_RET(INTNETR0Open(pThis->pIntNet, g_pSession, pszNetwork, kIntNetTrunkType_None, "",
     413                                         0/*fFlags*/, cbSend, cbRecv, &pThis->hIf0), rcCheck);
     414    RTTESTI_CHECK_RET(pThis->hIf0 != INTNET_HANDLE_INVALID, VERR_INTERNAL_ERROR);
     415    RTTESTI_CHECK_RC_RET(INTNETR0IfGetRing0Buffer(pThis->pIntNet, pThis->hIf0, g_pSession, &pThis->pBuf0), VINF_SUCCESS, rcCheck);
     416    RTTESTI_CHECK_RET(pThis->pBuf0, VERR_INTERNAL_ERROR);
     417
     418
     419    pThis->hIf1 = INTNET_HANDLE_INVALID;
     420    RTTESTI_CHECK_RC_OK_RET(INTNETR0Open(pThis->pIntNet, g_pSession, pszNetwork, kIntNetTrunkType_None, "",
     421                                         0/*fFlags*/, cbSend, cbRecv, &pThis->hIf1), rcCheck);
     422    RTTESTI_CHECK_RET(pThis->hIf1 != INTNET_HANDLE_INVALID, VERR_INTERNAL_ERROR);
     423    RTTESTI_CHECK_RC_RET(INTNETR0IfGetRing0Buffer(pThis->pIntNet, pThis->hIf1, g_pSession, &pThis->pBuf1), VINF_SUCCESS, rcCheck);
     424    RTTESTI_CHECK_RET(pThis->pBuf1, VERR_INTERNAL_ERROR);
     425
     426    return VINF_SUCCESS;
     427}
     428
     429/**
     430 * Close the interfaces.
     431 *
     432 * @param   pThis               The test instance.
     433 */
     434static void tstCloseInterfaces(PTSTSTATE pThis)
     435{
     436    int rc;
     437    RTTESTI_CHECK_RC_OK(rc = INTNETR0IfClose(pThis->pIntNet, pThis->hIf0, g_pSession));
     438    if (RT_SUCCESS(rc))
     439    {
     440        pThis->hIf0  = INTNET_HANDLE_INVALID;
     441        pThis->pBuf0 = NULL;
     442    }
     443
     444    RTTESTI_CHECK_RC_OK(rc = INTNETR0IfClose(pThis->pIntNet, pThis->hIf1, g_pSession));
     445    if (RT_SUCCESS(rc))
     446    {
     447        pThis->hIf1  = INTNET_HANDLE_INVALID;
     448        pThis->pBuf1 = NULL;
     449    }
     450
     451    /* The network should be dead now. */
     452    RTTESTI_CHECK(pThis->pIntNet->pNetworks == NULL);
     453}
     454
     455/**
     456 * Do the bi-directional transfer test.
     457 */
     458static void tstBidirectionalTransfer(PTSTSTATE pThis)
     459{
     460    MYARGS Args0;
     461    RT_ZERO(Args0);
     462    Args0.hIf         = pThis->hIf0;
     463    Args0.pBuf        = pThis->pBuf0;
     464    Args0.pIntNet     = pThis->pIntNet;
     465    Args0.Mac.au16[0] = 0x8086;
     466    Args0.Mac.au16[1] = 0;
     467    Args0.Mac.au16[2] = 0;
     468
     469    MYARGS Args1;
     470    RT_ZERO(Args1);
     471    Args1.hIf         = pThis->hIf1;
     472    Args1.pBuf        = pThis->pBuf1;
     473    Args1.pIntNet     = pThis->pIntNet;
     474    Args1.Mac.au16[0] = 0x8086;
     475    Args1.Mac.au16[1] = 0;
     476    Args1.Mac.au16[2] = 1;
     477
     478    RTTHREAD ThreadRecv0 = NIL_RTTHREAD;
     479    RTTHREAD ThreadRecv1 = NIL_RTTHREAD;
     480    RTTHREAD ThreadSend0 = NIL_RTTHREAD;
     481    RTTHREAD ThreadSend1 = NIL_RTTHREAD;
     482    RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadRecv0, ReceiveThread, &Args0, 0, RTTHREADTYPE_IO,        RTTHREADFLAGS_WAITABLE, "RECV0"));
     483    RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadRecv1, ReceiveThread, &Args1, 0, RTTHREADTYPE_IO,        RTTHREADFLAGS_WAITABLE, "RECV1"));
     484    RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadSend0, SendThread,    &Args0, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND0"));
     485    RTTESTI_CHECK_RC_OK_RETV(RTThreadCreate(&ThreadSend1, SendThread,    &Args1, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND1"));
     486
     487    int rc2 = VINF_SUCCESS;
     488    int rc;
     489    RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadSend0, 5*60*1000, &rc2));
     490    if (RT_SUCCESS(rc))
     491    {
     492        RTTESTI_CHECK_RC_OK(rc2);
     493        ThreadSend0 = NIL_RTTHREAD;
     494        RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadSend1, 5*60*1000, RT_SUCCESS(rc2) ? &rc2 : NULL));
     495        if (RT_SUCCESS(rc))
     496        {
     497            ThreadSend1 = NIL_RTTHREAD;
     498            RTTESTI_CHECK_RC_OK(rc2);
     499        }
     500    }
     501    if (RTTestErrorCount(g_hTest) == 0)
     502    {
    345503        /*
    346          * Read data.
     504         * Wait a bit for the receivers to finish up.
    347505         */
    348         while (INTNETRingHasMoreToRead(&pArgs->pBuf->Recv))
     506        unsigned cYields = 100000;
     507        while (     (  INTNETRingHasMoreToRead(&pThis->pBuf0->Recv)
     508                    || INTNETRingHasMoreToRead(&pThis->pBuf1->Recv))
     509               &&   cYields-- > 0)
     510            RTThreadYield();
     511
     512        uint64_t u64Elapsed = RT_MAX(Args0.u64End, Args1.u64End) - RT_MIN(Args0.u64Start, Args1.u64Start);
     513        uint64_t u64Speed = (uint64_t)((2 * g_cbTransfer / 1024) / (u64Elapsed / 1000000000.0));
     514        RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     515                     "transfered %u bytes in %'RU64 ns (%'RU64 KB/s)\n",
     516                     2 * g_cbTransfer, u64Elapsed, u64Speed);
     517
     518        /*
     519         * Wait for the threads to finish up...
     520         */
     521        RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadRecv0, 5000, &rc2));
     522        if (RT_SUCCESS(rc))
    349523        {
    350             uint8_t abBuf[16384];
    351             uint32_t cb = INTNETRingReadAndSkipFrame(&pArgs->pBuf->Recv, abBuf);
    352             unsigned *puFrame = (unsigned *)&abBuf[sizeof(RTMAC) * 2];
    353 
    354             /* check for termination frame. */
    355             if (    cb == sizeof(RTMAC) * 2 + sizeof(unsigned) * 4
    356                 &&  puFrame[0] == 0xffffdead
    357                 &&  puFrame[1] == 0xffffdead
    358                 &&  puFrame[2] == 0xffffdead
    359                 &&  puFrame[3] == 0xffffdead)
    360             {
    361                 pArgs->u64End = RTTimeNanoTS();
    362                 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs terminating.\n"
    363                          "tstIntNetR0:   iFrame=%u  cb=%'u  c=%'u  %'uKB/s  %'ufps  cLost=%'u \n",
    364                          &pArgs->Mac, iFrame, cbReceived, iFrame - cLostFrames,
    365                          (unsigned)(cbReceived * 1000000000.0 / 1024 / (pArgs->u64End - pArgs->u64Start)),
    366                          (unsigned)((iFrame - cLostFrames) * 1000000000.0 / (pArgs->u64End - pArgs->u64Start)),
    367                          cLostFrames);
    368                 return VINF_SUCCESS;
    369             }
    370 
    371             /* validate frame header */
    372             PRTMAC pMacSrc = (PRTMAC)&abBuf[0];
    373             PRTMAC pMacDst = pMacSrc + 1;
    374             if (    pMacDst->au16[0] != 0x8086
    375                 ||  pMacDst->au16[1] != 0
    376                 ||  pMacDst->au16[2] != pArgs->Mac.au16[2]
    377                 ||  pMacSrc->au16[0] != 0x8086
    378                 ||  pMacSrc->au16[1] != 0
    379                 ||  pMacSrc->au16[2] == pArgs->Mac.au16[2])
    380             {
    381                 RTPrintf("tstIntNetR0: receiver thread %.6Rhxs received frame header: %.16Rhxs\n",
    382                          &pArgs->Mac, abBuf);
    383                 g_cErrors++;
    384             }
    385 
    386             /* frame stuff and stats. */
    387             int off = iFrame + 1 - *puFrame;
    388             if (off)
    389             {
    390                 if (off > 0)
    391                 {
    392                     RTPrintf("tstIntNetR0: receiver thread %.6Rhxs: iFrame=%d *puFrame=%d off=%d\n",
    393                              &pArgs->Mac, iFrame, *puFrame, off);
    394                     g_cErrors++;
    395                     cLostFrames++;
    396                 }
    397                 else
    398                 {
    399                     cLostFrames += -off;
    400 #ifndef IGNORE_LOST_FRAMES
    401                     if (off < 50)
    402                     {
    403                         RTPrintf("tstIntNetR0: receiver thread %.6Rhxs: iFrame=%d *puFrame=%d off=%d\n",
    404                                  &pArgs->Mac, iFrame, *puFrame, off);
    405                         g_cErrors++;
    406                     }
    407 #endif
    408                 }
    409             }
    410             iFrame = *puFrame;
    411             cbReceived += cb;
     524            RTTESTI_CHECK_RC_OK(rc2);
     525            ThreadRecv0 = NIL_RTTHREAD;
    412526        }
    413     }
    414 }
     527
     528        RTTESTI_CHECK_RC_OK(rc = RTThreadWait(ThreadRecv1, 5000, &rc2));
     529        if (RT_SUCCESS(rc))
     530        {
     531            RTTESTI_CHECK_RC_OK(rc2);
     532            ThreadRecv1 = NIL_RTTHREAD;
     533        }
     534    }
     535
     536    /*
     537     * Give them a chance to complete...
     538     */
     539    RTThreadWait(ThreadRecv0, 5000, NULL);
     540    RTThreadWait(ThreadRecv1, 5000, NULL);
     541    RTThreadWait(ThreadSend0, 5000, NULL);
     542    RTThreadWait(ThreadSend1, 5000, NULL);
     543
     544
     545    /*
     546     * Display statistics.
     547     */
     548    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     549                 "Buf0: Yields-OK=%llu Yields-NOK=%llu Lost=%llu Bad=%llu\n",
     550                 pThis->pBuf0->cStatYieldsOk.c,
     551                 pThis->pBuf0->cStatYieldsNok.c,
     552                 pThis->pBuf0->cStatLost.c,
     553                 pThis->pBuf0->cStatBadFrames.c);
     554    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     555                 "Buf0.Recv: Frames=%llu Bytes=%llu Overflows=%llu\n",
     556                 pThis->pBuf0->Recv.cStatFrames,
     557                 pThis->pBuf0->Recv.cbStatWritten.c,
     558                 pThis->pBuf0->Recv.cOverflows.c);
     559    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     560                 "Buf0.Send: Frames=%llu Bytes=%llu Overflows=%llu\n",
     561                 pThis->pBuf0->Send.cStatFrames,
     562                 pThis->pBuf0->Send.cbStatWritten.c,
     563                 pThis->pBuf0->Send.cOverflows.c);
     564
     565    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     566                 "Buf1: Yields-OK=%llu Yields-NOK=%llu Lost=%llu Bad=%llu\n",
     567                 pThis->pBuf1->cStatYieldsOk.c,
     568                 pThis->pBuf1->cStatYieldsNok.c,
     569                 pThis->pBuf1->cStatLost.c,
     570                 pThis->pBuf1->cStatBadFrames.c);
     571    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     572                 "Buf1.Recv: Frames=%llu Bytes=%llu Overflows=%llu\n",
     573                 pThis->pBuf1->Recv.cStatFrames,
     574                 pThis->pBuf1->Recv.cbStatWritten.c,
     575                 pThis->pBuf1->Recv.cOverflows.c);
     576    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     577                 "Buf1.Send: Frames=%llu Bytes=%llu Overflows=%llu\n",
     578                 pThis->pBuf1->Send.cStatFrames,
     579                 pThis->pBuf1->Send.cbStatWritten.c,
     580                 pThis->pBuf1->Send.cOverflows.c);
     581
     582}
     583
     584/**
     585 * Performs a simple broadcast test.
     586 *
     587 * @param   pThis               The test instance.
     588 * @param   fHeadGuard          Whether to use a head or tail guard.
     589 */
     590static void doBroadcastTest(PTSTSTATE pThis, bool fHeadGuard)
     591{
     592    static uint16_t const s_au16Frame[7] = { /* dst:*/ 0xffff, 0xffff, 0xffff, /*src:*/0x8086, 0, 0, 0x0800 };
     593
     594    RTTESTI_CHECK_RC_RETV(tstIntNetSendBuf(pThis->pIntNet, &pThis->pBuf0->Send, pThis->hIf0,
     595                                           g_pSession, &s_au16Frame, sizeof(s_au16Frame)),
     596                          VINF_SUCCESS);
     597
     598    /* No echo, please */
     599    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 1), VERR_TIMEOUT);
     600
     601    /* The other interface should see it though.  But Wait should only return once, thank you. */
     602    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 1), VINF_SUCCESS);
     603    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 0), VERR_TIMEOUT);
     604
     605    /* Receive the data. */
     606    const unsigned cbExpect = RT_ALIGN(sizeof(s_au16Frame) + sizeof(INTNETHDR), sizeof(INTNETHDR));
     607    RTTESTI_CHECK_MSG(INTNETRingGetReadable(&pThis->pBuf1->Recv) == cbExpect,
     608                      ("%#x vs. %#x\n", INTNETRingGetReadable(&pThis->pBuf1->Recv), cbExpect));
     609
     610    void *pvBuf;
     611    RTTESTI_CHECK_RC_OK_RETV(RTTestGuardedAlloc(g_hTest, sizeof(s_au16Frame), 1, fHeadGuard, &pvBuf));
     612    uint32_t cb;
     613    RTTESTI_CHECK_MSG_RETV((cb = INTNETRingReadAndSkipFrame(&pThis->pBuf1->Recv, pvBuf)) == sizeof(s_au16Frame),
     614                           ("%#x vs. %#x\n", cb, sizeof(s_au16Frame)));
     615
     616    if (memcmp(pvBuf, &s_au16Frame, sizeof(s_au16Frame)))
     617        RTTestIFailed("Got invalid data!\n"
     618                      "received: %.*Rhxs\n"
     619                      "expected: %.*Rhxs\n",
     620                      cb, pvBuf, sizeof(s_au16Frame), &s_au16Frame);
     621}
     622
     623/**
     624 * Performs a simple unicast test.
     625 *
     626 * @param   pThis               The test instance.
     627 * @param   fHeadGuard          Whether to use a head or tail guard.
     628 */
     629static void doUnicastTest(PTSTSTATE pThis, bool fHeadGuard)
     630{
     631    static uint16_t const s_au16Frame[7] = { /* dst:*/ 0x8086, 0, 0,      /*src:*/0x8086, 0, 1, 0x0800 };
     632
     633    RTTESTI_CHECK_RC_RETV(tstIntNetSendBuf(pThis->pIntNet, &pThis->pBuf1->Send, pThis->hIf1,
     634                                           g_pSession, s_au16Frame, sizeof(s_au16Frame)),
     635                          VINF_SUCCESS);
     636
     637    /* No echo, please */
     638    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 1), VERR_TIMEOUT);
     639
     640    /* The other interface should see it though.  But Wait should only return once, thank you. */
     641    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 1), VINF_SUCCESS);
     642    RTTESTI_CHECK_RC_RETV(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 0), VERR_TIMEOUT);
     643
     644    /* Receive the data. */
     645    const unsigned cbExpect = RT_ALIGN(sizeof(s_au16Frame) + sizeof(INTNETHDR), sizeof(INTNETHDR));
     646    RTTESTI_CHECK_MSG(INTNETRingGetReadable(&pThis->pBuf0->Recv) == cbExpect,
     647                      ("%#x vs. %#x\n", INTNETRingGetReadable(&pThis->pBuf0->Recv), cbExpect));
     648
     649    void *pvBuf;
     650    RTTESTI_CHECK_RC_OK_RETV(RTTestGuardedAlloc(g_hTest, sizeof(s_au16Frame), 1, fHeadGuard, &pvBuf));
     651    uint32_t cb;
     652    RTTESTI_CHECK_MSG_RETV((cb = INTNETRingReadAndSkipFrame(&pThis->pBuf0->Recv, pvBuf)) == sizeof(s_au16Frame),
     653                           ("%#x vs. %#x\n", cb, sizeof(s_au16Frame)));
     654
     655    if (memcmp(pvBuf, &s_au16Frame, sizeof(s_au16Frame)))
     656        RTTestIFailed("Got invalid data!\n"
     657                      "received: %.*Rhxs\n"
     658                      "expected: %.*Rhxs\n",
     659                      cb, pvBuf, sizeof(s_au16Frame), s_au16Frame);
     660}
     661
     662static void doTest(PTSTSTATE pThis, uint32_t cbRecv, uint32_t cbSend)
     663{
     664
     665    /*
     666     * Create an INTNET instance.
     667     */
     668    RTTestISub("INTNETR0Create");
     669    RTTESTI_CHECK_RC_RETV(INTNETR0Create(&pThis->pIntNet), VINF_SUCCESS);
     670
     671    /*
     672     * Create two interfaces and activate them.
     673     */
     674    RTTestISub("Network creation");
     675    int rc = tstOpenInterfaces(pThis, "test", cbSend, cbRecv);
     676    if (RT_FAILURE(rc))
     677        return;
     678    RTTESTI_CHECK_RC(INTNETR0IfSetActive(pThis->pIntNet, pThis->hIf0, g_pSession, true), VINF_SUCCESS);
     679    RTTESTI_CHECK_RC(INTNETR0IfSetActive(pThis->pIntNet, pThis->hIf1, g_pSession, true), VINF_SUCCESS);
     680
     681    /*
     682     * Test basic waiting.
     683     */
     684    RTTestISub("INTNETR0IfWait");
     685    RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 1), VERR_TIMEOUT);
     686    RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf0, g_pSession, 0), VERR_TIMEOUT);
     687    RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 1), VERR_TIMEOUT);
     688    RTTESTI_CHECK_RC(INTNETR0IfWait(pThis->pIntNet, pThis->hIf1, g_pSession, 0), VERR_TIMEOUT);
     689
     690    /*
     691     * Broadcast send and receive.
     692     * (This establishes the MAC address of the 1st interface.)
     693     */
     694    RTTestISub("Broadcast");
     695    doBroadcastTest(pThis, false /*fHeadGuard*/);
     696    doBroadcastTest(pThis, true /*fHeadGuard*/);
     697
     698    /*
     699     * Unicast send and receive.
     700     * (This establishes the MAC address of the 2nd interface.)
     701     */
     702    RTTestISub("Unicast");
     703    doUnicastTest(pThis, false /*fHeadGuard*/);
     704    doUnicastTest(pThis, true /*fHeadGuard*/);
     705
     706    /*
     707     * Do the big bi-directional transfer test if the basics worked out.
     708     */
     709    if (!RTTestIErrorCount())
     710    {
     711        RTTestISubF("bi-directional benchmark, cbSend=%u, cbRecv=%u, cbTransfer=%u",
     712                    pThis->pBuf0->cbSend, pThis->pBuf0->cbRecv, g_cbTransfer);
     713        tstBidirectionalTransfer(pThis);
     714    }
     715
     716    /*
     717     * Destroy the service.
     718     */
     719    tstCloseInterfaces(pThis);
     720    INTNETR0Destroy(pThis->pIntNet);
     721}
     722
    415723
    416724int main(int argc, char **argv)
    417725{
    418     /*
    419      * Init the runtime and parse arguments.
    420      */
    421     RTR3Init();
    422 
     726    int rc = RTTestInitAndCreate("tstIntNetR0", &g_hTest);
     727    if (rc)
     728        return rc;
     729
     730    /*
     731     * Parse the arguments.
     732     */
    423733    static RTGETOPTDEF const s_aOptions[] =
    424734    {
    425         { "--recv-buffer",  'r', RTGETOPT_REQ_UINT32 },
    426         { "--send-buffer",  's', RTGETOPT_REQ_UINT32 },
     735        { "--recv-buffer",   'r', RTGETOPT_REQ_UINT32 },
     736        { "--send-buffer",   's', RTGETOPT_REQ_UINT32 },
     737        { "--transfer-size", 'l', RTGETOPT_REQ_UINT32 },
    427738    };
    428739
    429     uint32_t cbRecv = 32 * _1K;
    430     uint32_t cbSend = 1536*2;
     740    uint32_t cbSend = 1536*2 + 4;
     741    uint32_t cbRecv = 0x8000;
    431742
    432743    int ch;
     
    437748        switch (ch)
    438749        {
     750            case 'l':
     751                g_cbTransfer = Value.u32;
     752                break;
     753
    439754            case 'r':
    440755                cbRecv = Value.u32;
     
    450765
    451766    /*
    452      * Create an INTNET instance.
    453      */
    454     RTPrintf("tstIntNetR0: TESTING cbSend=%d cbRecv=%d ...\n", cbSend, cbRecv);
    455     PINTNET pIntNet;
    456     int rc = INTNETR0Create(&pIntNet);
    457     if (RT_FAILURE(rc))
    458     {
    459         RTPrintf("tstIntNetR0: INTNETR0Create failed, rc=%Rrc\n");
    460         return 1;
    461     }
    462 
    463     /*
    464      * Create two interfaces.
    465      */
    466     INTNETIFHANDLE hIf0 = INTNET_HANDLE_INVALID;
    467     rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, "", 0, 1536*2 + 4, 0x8000, &hIf0);
    468     if (RT_SUCCESS(rc))
    469     {
    470         if (hIf0 != INTNET_HANDLE_INVALID)
    471         {
    472             INTNETIFHANDLE hIf1 = INTNET_HANDLE_INVALID;
    473             rc = INTNETR0Open(pIntNet, g_pSession, "test", kIntNetTrunkType_None, NULL, 0, 1536*2 + 4, 0x8000, &hIf1);
    474             if (RT_SUCCESS(rc))
    475             {
    476                 if (hIf1 != INTNET_HANDLE_INVALID)
    477                 {
    478                     PINTNETBUF pBuf0;
    479                     rc = INTNETR0IfGetRing0Buffer(pIntNet, hIf0, g_pSession, &pBuf0);
    480                     if (RT_FAILURE(rc) || !pBuf0)
    481                     {
    482                         RTPrintf("tstIntNetR0: INTNETIfGetRing0Buffer failed! pBuf0=%p rc=%Rrc\n", pBuf0, rc);
    483                         g_cErrors++;
    484                     }
    485                     PINTNETBUF pBuf1;
    486                     rc = INTNETR0IfGetRing0Buffer(pIntNet, hIf1, g_pSession, &pBuf1);
    487                     if (RT_FAILURE(rc))
    488                     {
    489                         RTPrintf("tstIntNetR0: INTNETIfGetRing0Buffer failed! pBuf1=%p rc=%Rrc\n", pBuf1, rc);
    490                         g_cErrors++;
    491                     }
    492 
    493                     rc = INTNETR0IfSetActive(pIntNet, hIf0, g_pSession, true);
    494                     if (RT_FAILURE(rc))
    495                     {
    496                         RTPrintf("tstIntNetR0: INTNETR0IfSetActive failed! rc=%Rrc\n", rc);
    497                         g_cErrors++;
    498                     }
    499                     rc = INTNETR0IfSetActive(pIntNet, hIf1, g_pSession, true);
    500                     if (RT_FAILURE(rc))
    501                     {
    502                         RTPrintf("tstIntNetR0: INTNETR0IfSetActive failed! rc=%Rrc\n", rc);
    503                         g_cErrors++;
    504                     }
    505 
    506 
    507                     /*
    508                      * Test basic waiting.
    509                      */
    510                     rc = INTNETR0IfWait(pIntNet, hIf0, g_pSession, 1);
    511                     if (rc != VERR_TIMEOUT)
    512                     {
    513                         RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf0)\n", rc);
    514                         g_cErrors++;
    515                     }
    516                     rc = INTNETR0IfWait(pIntNet, hIf1, g_pSession, 0);
    517                     if (rc != VERR_TIMEOUT)
    518                     {
    519                         RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf1)\n", rc);
    520                         g_cErrors++;
    521                     }
    522 
    523                     /*
    524                      * Send and receive.
    525                      */
    526                     rc = tstIntNetSendBuf(pIntNet, &pBuf0->Send, hIf0, g_pSession, &g_TestFrame0, sizeof(g_TestFrame0));
    527                     if (RT_SUCCESS(rc))
    528                     {
    529                         rc = INTNETR0IfWait(pIntNet, hIf0, g_pSession, 1);
    530                         if (rc != VERR_TIMEOUT)
    531                         {
    532                             RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VERR_TIMEOUT (hIf0, 2nd)\n", rc);
    533                             g_cErrors++;
    534                         }
    535                         rc = INTNETR0IfWait(pIntNet, hIf1, g_pSession, 0);
    536                         if (rc == VINF_SUCCESS)
    537                         {
    538                             /* receive it */
    539                             uint8_t abBuf[sizeof(g_TestFrame0)];
    540                             const unsigned cbExpect = RT_ALIGN(sizeof(g_TestFrame0) + sizeof(INTNETHDR), sizeof(INTNETHDR));
    541                             if (INTNETRingGetReadable(&pBuf1->Recv) != cbExpect)
    542                             {
    543                                 RTPrintf("tstIntNetR0: %d readable bytes, expected %d!\n", INTNETRingGetReadable(&pBuf1->Recv), cbExpect);
    544                                 g_cErrors++;
    545                             }
    546                             uint32_t cb = INTNETRingReadAndSkipFrame(&pBuf1->Recv, abBuf);
    547                             if (cb != sizeof(g_TestFrame0))
    548                             {
    549                                 RTPrintf("tstIntNetR0: read %d frame bytes, expected %d!\n", cb, sizeof(g_TestFrame0));
    550                                 g_cErrors++;
    551                             }
    552                             else if (memcmp(abBuf, &g_TestFrame0, sizeof(g_TestFrame0)))
    553                             {
    554                                 RTPrintf("tstIntNetR0: Got invalid data!\n"
    555                                          "received: %.*Rhxs\n"
    556                                          "expected: %.*Rhxs\n",
    557                                          cb, abBuf, sizeof(g_TestFrame0), &g_TestFrame0);
    558                                 g_cErrors++;
    559                             }
    560 
    561                             /*
    562                              * Send a packet from If1 just to set its MAC address.
    563                              */
    564                             rc = tstIntNetSendBuf(pIntNet, &pBuf1->Send, hIf1, g_pSession, &g_TestFrame1, sizeof(g_TestFrame1));
    565                             if (RT_FAILURE(rc))
    566                             {
    567                                 RTPrintf("tstIntNetR0: INTNETIfSend returned %Rrc! (hIf1)\n", rc);
    568                                 g_cErrors++;
    569                             }
    570 
    571 
    572                             /*
    573                              * Start threaded testcase.
    574                              * Give it 5 mins to finish.
    575                              */
    576                             if (!g_cErrors)
    577                             {
    578                                 MYARGS Args0;
    579                                 RT_ZERO(Args0);
    580                                 Args0.hIf = hIf0;
    581                                 Args0.pBuf = pBuf0;
    582                                 Args0.pIntNet = pIntNet;
    583                                 Args0.Mac.au16[0] = 0x8086;
    584                                 Args0.Mac.au16[1] = 0;
    585                                 Args0.Mac.au16[2] = 0;
    586 
    587                                 MYARGS Args1;
    588                                 RT_ZERO(Args1);
    589                                 Args1.hIf = hIf1;
    590                                 Args1.pBuf = pBuf1;
    591                                 Args1.pIntNet = pIntNet;
    592                                 Args1.Mac.au16[0] = 0x8086;
    593                                 Args1.Mac.au16[1] = 0;
    594                                 Args1.Mac.au16[2] = 1;
    595 
    596                                 RTTHREAD ThreadRecv0 = NIL_RTTHREAD;
    597                                 RTTHREAD ThreadRecv1 = NIL_RTTHREAD;
    598                                 RTTHREAD ThreadSend0 = NIL_RTTHREAD;
    599                                 RTTHREAD ThreadSend1 = NIL_RTTHREAD;
    600                                 rc = RTThreadCreate(&ThreadRecv0, ReceiveThread, &Args0, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV0");
    601                                 if (RT_SUCCESS(rc))
    602                                     rc = RTThreadCreate(&ThreadRecv1, ReceiveThread, &Args1, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "RECV1");
    603                                 if (RT_SUCCESS(rc))
    604                                     rc = RTThreadCreate(&ThreadSend0, SendThread, &Args0, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND0");
    605                                 if (RT_SUCCESS(rc))
    606                                     rc = RTThreadCreate(&ThreadSend1, SendThread, &Args1, 0, RTTHREADTYPE_EMULATION, RTTHREADFLAGS_WAITABLE, "SEND1");
    607                                 if (RT_SUCCESS(rc))
    608                                 {
    609                                     int rc2 = VINF_SUCCESS;
    610                                     rc = RTThreadWait(ThreadSend0, 5*60*1000, &rc2);
    611                                     AssertRC(rc);
    612                                     if (RT_SUCCESS(rc))
    613                                     {
    614                                         ThreadSend0 = NIL_RTTHREAD;
    615                                         rc = RTThreadWait(ThreadSend1, 5*60*1000, RT_SUCCESS(rc2) ? &rc2 : NULL);
    616                                         AssertRC(rc);
    617                                         if (RT_SUCCESS(rc))
    618                                             ThreadSend1 = NIL_RTTHREAD;
    619                                     }
    620                                     if (    RT_SUCCESS(rc)
    621                                         &&  RT_SUCCESS(rc2))
    622                                     {
    623                                         /*
    624                                          * Wait a bit for the receivers to finish up.
    625                                          */
    626                                         unsigned cYields = 100000;
    627                                         while (     (  INTNETRingHasMoreToRead(&pBuf0->Recv)
    628                                                     || INTNETRingHasMoreToRead(&pBuf1->Recv))
    629                                                &&   cYields-- > 0)
    630                                             RTThreadYield();
    631 
    632                                         uint64_t u64Elapsed = RT_MAX(Args0.u64End, Args1.u64End) - RT_MIN(Args0.u64Start, Args1.u64Start);
    633                                         uint64_t u64Speed = (uint64_t)((2 * TEST_TRANSFER_SIZE / 1024) / (u64Elapsed / 1000000000.0));
    634                                         RTPrintf("tstIntNetR0: transfered %d bytes in %'RU64 ns (%'RU64 KB/s)\n",
    635                                                  2 * TEST_TRANSFER_SIZE, u64Elapsed, u64Speed);
    636 
    637                                         /*
    638                                          * Closing time...
    639                                          */
    640                                         rc = RTThreadWait(ThreadRecv0, 5000, &rc2);
    641                                         if (RT_SUCCESS(rc))
    642                                             ThreadRecv0 = NIL_RTTHREAD;
    643                                         if (RT_FAILURE(rc) || RT_FAILURE(rc2))
    644                                         {
    645                                             RTPrintf("tstIntNetR0: Failed waiting on receiver thread 0, rc=%Rrc, rc2=%Rrc\n", rc, rc2);
    646                                             g_cErrors++;
    647                                         }
    648 
    649                                         rc = RTThreadWait(ThreadRecv1, 5000, &rc2);
    650                                         if (RT_SUCCESS(rc))
    651                                             ThreadRecv1 = NIL_RTTHREAD;
    652                                         if (RT_FAILURE(rc) || RT_FAILURE(rc2))
    653                                         {
    654                                             RTPrintf("tstIntNetR0: Failed waiting on receiver thread 1, rc=%Rrc, rc2=%Rrc\n", rc, rc2);
    655                                             g_cErrors++;
    656                                         }
    657 
    658                                         rc = INTNETR0IfClose(pIntNet, hIf0, g_pSession);
    659                                         if (RT_SUCCESS(rc))
    660                                         {
    661                                             hIf0 = INTNET_HANDLE_INVALID;
    662                                             pBuf0 = NULL;
    663                                         }
    664                                         else
    665                                         {
    666                                             RTPrintf("tstIntNetR0: INTNETIfClose failed, rc=%Rrc! (hIf0)\n", rc);
    667                                             g_cErrors++;
    668                                         }
    669 
    670                                         rc = INTNETR0IfClose(pIntNet, hIf1, g_pSession);
    671                                         if (RT_SUCCESS(rc))
    672                                         {
    673                                             hIf1 = INTNET_HANDLE_INVALID;
    674                                             pBuf1 = NULL;
    675                                         }
    676                                         else
    677                                         {
    678                                             RTPrintf("tstIntNetR0: INTNETIfClose failed, rc=%Rrc! (hIf1)\n", rc);
    679                                             g_cErrors++;
    680                                         }
    681 
    682 
    683                                         /* check if the network still exist... */
    684                                         if (pIntNet->pNetworks)
    685                                         {
    686                                             RTPrintf("tstIntNetR0: The network wasn't deleted! (g_cErrors=%d)\n", g_cErrors);
    687                                             g_cErrors++;
    688                                         }
    689                                     }
    690                                     else
    691                                     {
    692                                         RTPrintf("tstIntNetR0: Waiting on senders failed, rc=%Rrc, rc2=%Rrc\n", rc, rc2);
    693                                         g_cErrors++;
    694                                     }
    695 
    696                                     /*
    697                                      * Give them a chance to complete...
    698                                      */
    699                                     RTThreadWait(ThreadRecv0, 5000, NULL);
    700                                     RTThreadWait(ThreadRecv1, 5000, NULL);
    701                                     RTThreadWait(ThreadSend0, 5000, NULL);
    702                                     RTThreadWait(ThreadSend1, 5000, NULL);
    703 
    704                                 }
    705                                 else
    706                                 {
    707                                     RTPrintf("tstIntNetR0: Failed to create threads, rc=%Rrc\n", rc);
    708                                     g_cErrors++;
    709                                 }
    710                             }
    711                         }
    712                         else
    713                         {
    714                             RTPrintf("tstIntNetR0: INTNETIfWait returned %Rrc expected VINF_SUCCESS (hIf1)\n", rc);
    715                             g_cErrors++;
    716                         }
    717                     }
    718                     else
    719                     {
    720                         RTPrintf("tstIntNetR0: INTNETIfSend returned %Rrc! (hIf0)\n", rc);
    721                         g_cErrors++;
    722                     }
    723                 }
    724                 else
    725                 {
    726                     RTPrintf("tstIntNetR0: INTNETOpen returned invalid handle on success! (hIf1)\n");
    727                     g_cErrors++;
    728                 }
    729 
    730                 if (hIf1 != INTNET_HANDLE_INVALID)
    731                     rc = INTNETR0IfClose(pIntNet, hIf1, g_pSession);
    732             }
    733             else
    734             {
    735                 RTPrintf("tstIntNetR0: INTNETOpen failed for the 2nd interface! rc=%Rrc\n", rc);
    736                 g_cErrors++;
    737             }
    738 
    739             if (hIf0 != INTNET_HANDLE_INVALID)
    740                 rc = INTNETR0IfClose(pIntNet, hIf0, g_pSession);
    741         }
    742         else
    743         {
    744             RTPrintf("tstIntNetR0: INTNETOpen returned invalid handle on success! (hIf0)\n");
    745             g_cErrors++;
    746         }
    747     }
    748     else
    749     {
    750         RTPrintf("tstIntNetR0: INTNETOpen failed for the 1st interface! rc=%Rrc\n", rc);
    751         g_cErrors++;
    752     }
    753 
    754     /*
    755      * Destroy the service.
    756      */
    757     INTNETR0Destroy(pIntNet);
    758 
    759     /*
    760      * Summary.
    761      */
    762     if (!g_cErrors)
    763         RTPrintf("tstIntNetR0: SUCCESS\n");
    764     else
    765         RTPrintf("tstIntNetR0: FAILURE - %d errors\n", g_cErrors);
    766 
    767     return !!g_cErrors;
    768 }
    769 
     767     * Do the testing and report summary.
     768     */
     769    TSTSTATE This;
     770    RT_ZERO(This);
     771    doTest(&This, cbRecv, cbSend);
     772
     773    return RTTestSummaryAndDestroy(g_hTest);
     774}
     775
  • trunk/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c

    r28088 r28623  
    427427    Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
    428428    Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
    429 /** @todo Assert(pThis->fActive); - disabled because we may call this without
    430  *        holding the out-bound lock and race the clearing. */
     429    /* No fActive check here. */
    431430
    432431    /*
     
    450449    Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
    451450    Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
    452     Assert(pThis->fActive);
     451    /* No fActive check here. */
    453452
    454453    /*
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette