VirtualBox

Changeset 10923 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Jul 29, 2008 12:22:11 AM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
33769
Message:

intnet: MAC sharing under construction...

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp

    r10846 r10923  
    4343*   Structures and Typedefs                                                    *
    4444*******************************************************************************/
     45typedef enum INTNETADDRTYPE
     46{
     47    /** The invalid 0 entry. */
     48    kIntNetAddrType_Invalid = 0,
     49    /** IP version 4. */
     50    kIntNetAddrType_IPv4,
     51    /** IP version 6. */
     52    kIntNetAddrType_IPv6,
     53    /** IPX. */
     54    kIntNetAddrType_IPX,
     55    /** The end of the valid values. */
     56    kIntNetAddrType_End,
     57    /** The usual 32-bit hack. */
     58    kIntNetAddrType_32BitHack = 0x7fffffff
     59} INTNETADDRTYPE;
     60/** Pointer to a network layer address type. */
     61typedef INTNETADDRTYPE *PINTNETADDRTYPE;
     62
     63/**
     64 * IPv4 address.
     65 */
     66typedef RTUINT32U INTNETADDRIPV4;
     67/** Pointer to a IPv4 address. */
     68typedef INTNETADDRIPV4 *PINTNETADDRIPV4;
     69/** Pointer to a const IPv4 address. */
     70typedef INTNETADDRIPV4 const *PCINTNETADDRIPV4;
     71
     72/**
     73 * IPv6 address.
     74 */
     75typedef RTUINT128U INTNETADDRIPV6;
     76/** Pointer to a IPv4 address. */
     77typedef INTNETADDRIPV6 *PINTNETADDRIPV6;
     78/** Pointer to a const IPv4 address. */
     79typedef INTNETADDRIPV6 const *PCINTNETADDRIPV6;
     80
     81/**
     82 * IPX address.
     83 */
     84typedef struct INTNETADDRIPX
     85{
     86    /** The network ID. */
     87    uint32_t Network;
     88    /** The node ID. (Defaults to the MAC address apparently.) */
     89    PDMMAC Node;
     90} INTNETADDRIPX;
     91/** Pointer to an IPX address. */
     92typedef INTNETADDRIPX *PINTNETADDRIPX;
     93/** Pointer to a const IPX address. */
     94typedef INTNETADDRIPX const *PCINTNETADDRIPX;
     95
     96/**
     97 * Address union.
     98 */
     99typedef union INTNETADDRU
     100{
     101    /** 64-bit view. */
     102    uint64_t au64[2];
     103    /** 32-bit view. */
     104    uint32_t au32[4];
     105    /** 16-bit view. */
     106    uint16_t au16[8];
     107    /** 8-bit view. */
     108    uint8_t  au8[16];
     109    /** IPv4 view. */
     110    INTNETADDRIPV4 IPv4;
     111    /** IPv6 view. */
     112    INTNETADDRIPV6 IPv6;
     113    /** IPX view. */
     114    INTNETADDRIPX Ipx;
     115} INTNETADDRU;
     116/** Pointer to an address union. */
     117typedef INTNETADDRU *PINTNETADDRU;
     118/** Pointer to a const address union. */
     119typedef INTNETADDRU const *PCINTNETADDRU;
     120
     121/**
     122 * Address and type.
     123 */
     124typedef struct INTNETADDR
     125{
     126    /** The address type. */
     127    INTNETADDRTYPE enmType;
     128    /** The address. */
     129    INTNETADDRU Addr;
     130} INTNETADDR;
     131/** Pointer to an address. */
     132typedef INTNETADDR *PINTNETADDR;
     133/** Pointer to a const address. */
     134typedef INTNETADDR const *PCINTNETADDR;
     135
     136
     137/**
     138 * Address cache for a specific network layer.
     139 */
     140typedef struct INTNETADDRCACHE
     141{
     142    /** Pointer to the table of addresses. */
     143    uint8_t *pbEntries;
     144    /** The number of valid address entries. */
     145    uint8_t cEntries;
     146    /** The number of allocated address entries. */
     147    uint8_t cEntriesAlloc;
     148    /** The address size. */
     149    uint8_t cbAddress;
     150    /** The size of an entry. */
     151    uint8_t cbEntry;
     152} INTNETADDRCACHE;
     153/** Pointer to an address cache. */
     154typedef INTNETADDRCACHE *PINTNETADDRCACHE;
     155/** Pointer to a const address cache. */
     156typedef INTNETADDRCACHE const *PCINTNETADDRCACHE;
     157
     158
    45159/**
    46160 * A network interface.
     
    92206    /** The SUPR0 object id. */
    93207    void                   *pvObj;
     208    /** The network layer address cache. (Indexed by type, 0 entry isn't used.) */
     209    INTNETADDRCACHE         aAddrCache[kIntNetAddrType_End];
    94210} INTNETIF;
    95211/** Pointer to an internal network interface. */
     
    177293
    178294
     295/**
     296 * Ethernet header.
     297 */
     298#pragma pack(1)
     299typedef struct INTNETETHERHDR
     300{
     301    PDMMAC      MacDst;
     302    PDMMAC      MacSrc;
     303    uint16_t    EtherType;
     304} INTNETETHERHDR;
     305#pragma pack()
     306/** Pointer to an ethernet header. */
     307typedef INTNETETHERHDR *PINTNETETHERHDR;
     308/** Pointer to a const ethernet header. */
     309typedef INTNETETHERHDR const *PCINTNETETHERHDR;
     310
     311/** @name EtherType
     312 * @{ */
     313#define INTNET_ETHERTYPE_IPV4   UINT16_C(0x0800)
     314#define INTNET_ETHERTYPE_ARP    UINT16_C(0x0806)
     315#define INTNET_ETHERTYPE_IPV6   UINT16_C(0x86dd)
     316/** @} */
     317
     318
     319#pragma pack(1)
     320typedef struct INTNETIPV4
     321{
     322#ifdef RT_BIG_ENDIAN
     323    unsigned int    ip_v : 4;
     324    unsigned int    ip_hl : 4;
     325    unsigned int    ip_tos : 8;
     326    unsigned int    ip_len : 16;
     327#else
     328    unsigned int    ip_hl : 4;
     329    unsigned int    ip_v : 4;
     330    unsigned int    ip_tos : 8;
     331    unsigned int    ip_len : 16;
     332#endif
     333    uint16_t        ip_id;
     334    uint16_t        ip_off;
     335    uint8_t         ip_ttl;
     336    uint8_t         ip_p;
     337    uint16_t        ip_sum;
     338    uint32_t        ip_src;
     339    uint32_t        ip_dst;
     340    /* more */
     341    uint32_t        ip_options[1];
     342} INTNETIPV4;
     343typedef INTNETIPV4 *PINTNETIPV4;
     344typedef INTNETIPV4 const *PCINTNETIPV4;
     345
     346
     347typedef struct INTNETUDPV4
     348{
     349    uint16_t    uh_sport;
     350    uint16_t    uh_dport;
     351    uint16_t    uh_ulen;
     352    uint16_t    uh_sum;
     353} INTNETUDPV4;
     354typedef INTNETUDPV4 *PINTNETUDPV4;
     355typedef INTNETUDPV4 const *PCINTNETUDPV4;
     356
     357
     358typedef struct INTNETDHCP
     359{
     360    uint8_t     Op;
     361    uint8_t     HType;
     362    uint8_t     HLen;
     363    uint8_t     Hops;
     364    uint32_t    XID;
     365    uint16_t    Secs;
     366    uint16_t    Flags;
     367    uint32_t    CIAddr;
     368    uint32_t    YIAddr;
     369    uint32_t    SIAddr;
     370    uint32_t    GIAddr;
     371    uint8_t     CHAddr[16];
     372    uint8_t     SName[64];
     373    uint8_t     File[128];
     374    uint8_t     abMagic[4];
     375    uint8_t     DhcpOpt;
     376    uint8_t     DhcpLen; /* 1 */
     377    uint8_t     DhcpReq;
     378    uint8_t     abOptions[57];
     379} INTNETDHCP;
     380typedef INTNETDHCP *PINTNETDHCP;
     381typedef INTNETDHCP const *PCINTNETDHCP;
     382
     383#pragma pack(0)
     384
     385/** IPv4: UDP */
     386#define INTNETIPV4_PROT_UDP         7
     387
     388
     389/** ARP hardware type - ethernet. */
     390#define INTNET_ARP_ETHER            UINT16_C(1)
     391
     392/** @name ARP operations
     393 * @{ */
     394#define INTNET_ARPOP_REQUEST        UINT16_C(1) /**< Request hardward address given a protocol address (ARP). */
     395#define INTNET_ARPOP_REPLY          UINT16_C(2)
     396#define INTNET_ARPOP_REVREQUEST     UINT16_C(3) /**< Request protocol address given a hardware address (RARP). */
     397#define INTNET_ARPOP_REVREPLY       UINT16_C(4)
     398#define INTNET_ARPOP_INVREQUEST     UINT16_C(8) /**< Inverse ARP.  */
     399#define INTNET_ARPOP_INVREPLY       UINT16_C(9)
     400#define INTNET_ARPOP_IS_REQUEST(Op) ((Op) & 1)
     401#define INTNET_ARPOP_IS_REPLY(Op)   (!INTNET_ARPOP_IS_REQUEST(Op))
     402/** @} */
     403
     404#pragma pack(1)
     405/**
     406 * Ethernet ARP header.
     407 */
     408typedef struct INTNETARPHDR
     409{
     410    /** The hardware type. */
     411    uint16_t    ar_htype;
     412    /** The protocol type (ethertype). */
     413    uint16_t    ar_ptype;
     414    /** The hardware address length. */
     415    uint8_t     ar_hlen;
     416    /** The protocol address length. */
     417    uint8_t     ar_plen;
     418    /** The operation. */
     419    uint16_t    ar_oper;
     420} INTNETARPHDR;
     421#pragma pack(0)
     422/** Pointer to an ethernet ARP header. */
     423typedef INTNETARPHDR *PINTNETARPHDR;
     424/** Pointer to a const ethernet ARP header. */
     425typedef INTNETARPHDR const *PCINTNETARPHDR;
     426
     427
     428#pragma pack(1)
     429/**
     430 * Ethernet IPv4 + 6-byte MAC ARP request packet.
     431 */
     432typedef struct INTNETARPIPV4
     433{
     434    INTNETARPHDR    Hdr;
     435    /** The sender hardware address. */
     436    PDMMAC          ar_sha;
     437    /** The sender protocol address. */
     438    INTNETADDRIPV4  ar_spa;
     439    /** The target hardware address. */
     440    PDMMAC          ar_tha;
     441    /** The arget protocol address. */
     442    INTNETADDRIPV4  ar_tpa;
     443} INTNETARPIPV4;
     444#pragma pack(0)
     445/** Pointer to an ethernet IPv4+MAC ARP request packet. */
     446typedef INTNETARPIPV4 *PINTNETARPIPV4;
     447/** Pointer to a const ethernet IPv4+MAC ARP request packet. */
     448typedef INTNETARPIPV4 const *PCINTNETARPIPV4;
     449
     450
     451#pragma pack(1)
     452/**
     453 * Ethernet IPv6 + 6-byte MAC ARP request packet.
     454 */
     455typedef struct INTNETARPIPV6
     456{
     457    INTNETARPHDR    Hdr;
     458    /** The sender hardware address. */
     459    PDMMAC          ar_sha;
     460    /** The sender protocol address. */
     461    INTNETADDRIPV6  ar_spa;
     462    /** The target hardware address. */
     463    PDMMAC          ar_tha;
     464    /** The arget protocol address. */
     465    INTNETADDRIPV6  ar_tpa;
     466} INTNETARPIPV6;
     467#pragma pack(0)
     468/** Pointer to an ethernet IPv6+MAC ARP request packet. */
     469typedef INTNETARPIPV6 *PINTNETARPIPV6;
     470/** Pointer to a const ethernet IPv6+MAC ARP request packet. */
     471typedef INTNETARPIPV6 const *PCINTNETARPIPV6;
     472
     473
    179474/*******************************************************************************
    180475*   Internal Functions                                                         *
     
    237532        return intnetR0IfRetain(pIf, (PSUPDRVSESSION)pvCtx);
    238533    return VINF_SUCCESS;
     534}
     535
     536
     537/**
     538 * Gets the address size of a network layer type.
     539 *
     540 * @returns size in bytes.
     541 * @param   enmType             The type.
     542 */
     543DECLINLINE(uint8_t) intnetR0AddrSize(INTNETADDRTYPE enmType)
     544{
     545    switch (enmType)
     546    {
     547        case kIntNetAddrType_IPv4:  return 4;
     548        case kIntNetAddrType_IPv6:  return 16;
     549        case kIntNetAddrType_IPX:   return 4 + 6;
     550        default:                    AssertFailedReturn(0);
     551    }
     552}
     553
     554
     555/**
     556 * Compares two address to see if they are equal, assuming naturally align structures.
     557 *
     558 * @returns true if equal, false if not.
     559 * @param   pAddr1          The first address.
     560 * @param   pAddr2          The second address.
     561 * @param   cbAddr          The address size.
     562 */
     563DECLINLINE(bool) intnetR0AddrUIsEqualEx(PCINTNETADDRU pAddr1, PCINTNETADDRU pAddr2, uint8_t const cbAddr)
     564{
     565    switch (cbAddr)
     566    {
     567        case 4:  /* IPv4 */
     568            return pAddr1->au32[0] == pAddr2->au32[0];
     569        case 16: /* IPv6 */
     570            return pAddr1->au64[0] == pAddr2->au64[0]
     571                && pAddr1->au64[1] == pAddr2->au64[1];
     572        case 10: /* IPX */
     573            return pAddr1->au64[0] == pAddr2->au64[0]
     574                && pAddr1->au16[4] == pAddr2->au16[4];
     575        default:
     576            AssertFailedReturn(false);
     577    }
     578}
     579
     580
     581/**
     582 * Worker for intnetR0IfAddrCacheLookup that performs the lookup
     583 * in the remaining cache entries after the caller has check the
     584 * most likely ones.
     585 *
     586 * @returns -1 if not found, the index of the cache entry if found.
     587 * @param   pCache      The cache.
     588 * @param   pAddr       The address.
     589 * @param   cbAddr      The address size (optimization).
     590 */
     591static int intnetR0IfAddrCacheLookupSlow(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
     592{
     593    unsigned i = pCache->cEntries - 2;
     594    uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
     595    while (i >= 1)
     596    {
     597        if (intnetR0AddrUIsEqualEx((PCINTNETADDRU)pbEntry, pAddr, cbAddr))
     598            return i;
     599        pbEntry -= pCache->cbEntry;
     600        i--;
     601    }
     602
     603    return -1;
     604}
     605
     606/**
     607 * Lookup an address in a cache without any expectations.
     608 *
     609 * @returns -1 if not found, the index of the cache entry if found.
     610 * @param   pCache          The cache.
     611 * @param   pAddr           The address.
     612 * @param   cbAddr          The address size (optimization).
     613 */
     614DECLINLINE(int) intnetR0IfAddrCacheLookup(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
     615{
     616    Assert(pCache->cbAddress == cbAddr);
     617
     618    /*
     619     * The optimized case is when there is one cache entry and
     620     * it doesn't match.
     621     */
     622    unsigned i = pCache->cEntries;
     623    if (    i > 0
     624        &&  intnetR0AddrUIsEqualEx((PCINTNETADDRU)pCache->pbEntries, pAddr, cbAddr))
     625        return 0;
     626    if (i <= 1)
     627        return -1;
     628
     629    /*
     630     * Check the last entry.
     631     */
     632    i--;
     633    if (intnetR0AddrUIsEqualEx((PCINTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr))
     634        return i;
     635    if (i <= 1)
     636        return -1;
     637
     638    return intnetR0IfAddrCacheLookupSlow(pCache, pAddr, cbAddr);
     639}
     640
     641/** Same as intnetR0IfAddrCacheLookup except we expect the address to be present already. */
     642DECLINLINE(int) intnetR0IfAddrCacheLookupLikely(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
     643{
     644    /** @todo implement this. */
     645    return intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
     646}
     647
     648
     649/**
     650 * Worker for intnetR0IfAddrCacheLookupUnlikely that performs
     651 * the lookup in the remaining cache entries after the caller
     652 * has check the most likely ones.
     653 *
     654 * The routine is expecting not to find the address.
     655 *
     656 * @returns -1 if not found, the index of the cache entry if found.
     657 * @param   pCache      The cache.
     658 * @param   pAddr       The address.
     659 * @param   cbAddr      The address size (optimization).
     660 */
     661static int intnetR0IfAddrCacheInCacheUnlikelySlow(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
     662{
     663    /*
     664     * Perform a full table lookup.
     665     */
     666    unsigned i = pCache->cEntries - 2;
     667    uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
     668    while (i >= 1)
     669    {
     670        if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCINTNETADDRU)pbEntry, pAddr, cbAddr)))
     671            return i;
     672        pbEntry -= pCache->cbEntry;
     673        i--;
     674    }
     675
     676    return -1;
     677}
     678
     679
     680/**
     681 * Lookup an address in a cache expecting not to find it.
     682 *
     683 * @returns -1 if not found, the index of the cache entry if found.
     684 * @param   pCache          The cache.
     685 * @param   pAddr           The address.
     686 * @param   cbAddr          The address size (optimization).
     687 */
     688DECLINLINE(int) intnetR0IfAddrCacheLookupUnlikely(PCINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
     689{
     690    Assert(pCache->cbAddress == cbAddr);
     691
     692    /*
     693     * The optimized case is when there is one cache entry and
     694     * it doesn't match.
     695     */
     696    unsigned i = pCache->cEntries;
     697    if (RT_UNLIKELY(   i > 0
     698                    && intnetR0AddrUIsEqualEx((PCINTNETADDRU)pCache->pbEntries, pAddr, cbAddr)))
     699        return 0;
     700    if (RT_LIKELY(i <= 1))
     701        return -1;
     702
     703    /*
     704     * Then check the last entry and return if there are just two cache entries.
     705     */
     706    i--;
     707    if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCINTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr)))
     708        return i;
     709    if (i <= 1)
     710        return -1;
     711
     712    return intnetR0IfAddrCacheInCacheUnlikelySlow(pCache, pAddr, cbAddr);
     713}
     714
     715
     716/**
     717 * Deletes a specific cache entry.
     718 *
     719 * Worker for intnetR0NetworkAddrCacheDelete and intnetR0NetworkAddrCacheDeleteMinusIf.
     720 *
     721 * @param   pIf             The interface (for logging).
     722 * @param   pCache          The cache.
     723 * @param   iEntry          The entry to delete.
     724 */
     725static void intnetR0IfAddrCacheDeleteIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, int iEntry)
     726{
     727    Log(("intnetR0IfAddrCacheDeleteIt: hIf=%RX32 type=%d #%d %.*Rhxs\n", pIf->hIf,
     728         (int)(intptr_t)(pCache - &pIf->aAddrCache[0]), iEntry, pCache->cbAddress, pCache->pbEntries + iEntry * pCache->cbEntry));
     729    Assert(iEntry < pCache->cEntries);
     730    pCache->cEntries--;
     731    if (iEntry < pCache->cEntries)
     732        memmove(pCache->pbEntries +      iEntry  * pCache->cbEntry,
     733                pCache->pbEntries + (iEntry + 1) * pCache->cbEntry,
     734                (pCache->cEntries - iEntry)      * pCache->cbEntry);
     735}
     736
     737
     738/**
     739 * Deletes an address from the cache, assuming it isn't actually in the cache.
     740 *
     741 * @param   pIf             The interface (for logging).
     742 * @param   pCache          The cache.
     743 * @param   pAddr           The address.
     744 * @param   cbAddr          The address size (optimization).
     745 */
     746DECLINLINE(void) intnetR0IfAddrCacheDelete(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
     747{
     748    int i = intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
     749    if (RT_UNLIKELY(i >= 0))
     750        intnetR0IfAddrCacheDeleteIt(pIf, pCache, i);
     751}
     752
     753
     754/**
     755 * Deletes the address from all the interface caches.
     756 *
     757 * This is used to remove stale entries that has been reassigned to
     758 * other machines on the network.
     759 *
     760 * @param   pNetwork        The network.
     761 * @param   pAddr           The address.
     762 * @param   enmType         The address type.
     763 * @param   cbAddr          The address size (optimization).
     764 */
     765DECLINLINE(void) intnetR0NetworkAddrCacheDelete(PINTNETNETWORK pNetwork, PCINTNETADDRU pAddr,
     766                                                INTNETADDRTYPE const enmType, uint8_t const cbAddr)
     767{
     768    for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
     769    {
     770        int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
     771        if (RT_UNLIKELY(i >= 0))
     772            intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i);
     773    }
     774}
     775
     776
     777/**
     778 * Deletes the address from all the interface caches except the specified one.
     779 *
     780 * This is used to remove stale entries that has been reassigned to
     781 * other machines on the network.
     782 *
     783 * @param   pNetwork        The network.
     784 * @param   pAddr           The address.
     785 * @param   enmType         The address type.
     786 * @param   cbAddr          The address size (optimization).
     787 */
     788DECLINLINE(void) intnetR0NetworkAddrCacheDeleteMinusIf(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, PCINTNETADDRU pAddr,
     789                                                       INTNETADDRTYPE const enmType, uint8_t const cbAddr)
     790{
     791    for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
     792        if (pIf != pIfSender)
     793        {
     794            int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
     795            if (RT_UNLIKELY(i >= 0))
     796                intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i);
     797        }
     798}
     799
     800
     801/**
     802 * Adds an address to the cache, the caller is responsible for making sure it'
     803 * s not already in the cache.
     804 *
     805 * @param   pIf         The interface (for logging).
     806 * @param   pCache      The address cache.
     807 * @param   pAddr       The address.
     808 */
     809static void intnetR0IfAddrCacheAddIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCINTNETADDRU pAddr)
     810{
     811    if (!pCache->cEntriesAlloc)
     812    {
     813        /* Allocate the first array */
     814        pCache->pbEntries = (uint8_t *)RTMemAllocZ(pCache->cbEntry * 16);
     815        if (!pCache->pbEntries)
     816            return;
     817    }
     818    else
     819    {
     820        bool fReplace = true;
     821        if (pCache->cEntriesAlloc < 64)
     822        {
     823            uint8_t cEntriesAlloc = pCache->cEntriesAlloc + 16;
     824            void *pvNew = RTMemRealloc(pCache->pbEntries, pCache->cbEntry * cEntriesAlloc);
     825            if (pvNew)
     826            {
     827                pCache->pbEntries = (uint8_t *)pvNew;
     828                pCache->cEntriesAlloc = cEntriesAlloc;
     829                fReplace = false;
     830            }
     831        }
     832        if (fReplace)
     833        {
     834            /* simple FIFO, might consider usage/ageing here? */
     835            Log(("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n",
     836                 (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cbAddress, pCache->pbEntries));
     837            memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1));
     838            pCache->cEntries--;
     839        }
     840    }
     841
     842    /*
     843     * Add the new entry to the end of the array.
     844     */
     845    uint8_t *pbEntry = pCache->pbEntries + pCache->cEntries * pCache->cbEntry;
     846    memcpy(pbEntry, pAddr, pCache->cbAddress);
     847    memset(pbEntry + pCache->cbAddress, '\0', pCache->cbEntry - pCache->cbAddress);
     848    Log(("intnetR0IfAddrCacheAddIt: type=%d added #%d %.*Rhxs\n",
     849         (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cEntries, pCache->cbAddress, pAddr));
     850    pCache->cEntries++;
     851    Assert(pCache->cEntries <= pCache->cEntriesAlloc);
     852}
     853
     854
     855/**
     856 * A intnetR0IfAddrCacheAdd worker that performs the rest of the lookup.
     857 *
     858 * @param   pIf         The interface (for logging).
     859 * @param   pCache      The address cache.
     860 * @param   pAddr       The address.
     861 * @param   cbAddr      The size of the address (optimization).
     862 */
     863static void intnetR0IfAddrCacheAddSlow(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
     864{
     865    /*
     866     * Check all but the first and last entries, the caller
     867     * has already checked those.
     868     */
     869    unsigned cLeft = pCache->cEntries;
     870    uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry;
     871    while (--cLeft > 1)
     872    {
     873        if (RT_LIKELY(intnetR0AddrUIsEqualEx((PCINTNETADDRU)pbEntry, pAddr, cbAddr)))
     874        {
     875            /** @todo usage/ageing? */
     876            return;
     877        }
     878        pbEntry += pCache->cbEntry;
     879        cLeft--;
     880    }
     881
     882    /*
     883     * Not found, add it.
     884     */
     885    intnetR0IfAddrCacheAddIt(pIf, pCache, pAddr);
     886}
     887
     888
     889/**
     890 * Adds an address to the cache if it's not already there.
     891 *
     892 * @param   pIf         The interface (for logging).
     893 * @param   pCache      The address cache.
     894 * @param   pAddr       The address.
     895 * @param   cbAddr      The size of the address (optimization).
     896 */
     897DECLINLINE(void) intnetR0IfAddrCacheAdd(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCINTNETADDRU pAddr, uint8_t const cbAddr)
     898{
     899    Assert(pCache->cbAddress == cbAddr);
     900
     901    /*
     902     * The optimized case is when the address the first cache entry.
     903     */
     904    unsigned i = pCache->cEntries;
     905    if (RT_LIKELY(   i > 0
     906                  && intnetR0AddrUIsEqualEx((PCINTNETADDRU)pCache->pbEntries, pAddr, cbAddr)))
     907    {
     908        /** @todo usage/ageing? */
     909        return;
     910    }
     911    if (i <= 1)
     912        return;
     913
     914    /*
     915     * And the case where it's the last entry.
     916     */
     917    i--;
     918    if (RT_LIKELY(intnetR0AddrUIsEqualEx((PCINTNETADDRU)pCache->pbEntries, pAddr, cbAddr)))
     919    {
     920        /** @todo usage/ageing? */
     921        return;
     922    }
     923    if (i <= 1)
     924        return;
     925
     926    intnetR0IfAddrCacheAddSlow(pIf, pCache, pAddr, cbAddr);
     927}
     928
     929
     930/**
     931 * Deals with an IPv4 packet.
     932 *
     933 * This will fish out the source IP address and add it to the cache.
     934 * Then it will look for DHCPRELEASE requests (?) and anything else
     935 * that we migh find useful later.
     936 *
     937 * @param   pIf             The interface that's sending the frame.
     938 * @param   pHdr            Pointer to the IPv4 header in the frame.
     939 * @param   cbPacket        The size of the packet, or more correctly the
     940 *                          size of the frame without the ethernet header.
     941 */
     942static void intnetR0IfSniffIPv4SourceAddr(PINTNETIF pIf, PCINTNETIPV4 pHdr, uint32_t cbPacket)
     943{
     944    /*
     945     * Check the header size.
     946     */
     947    if (cbPacket < RT_UOFFSETOF(INTNETIPV4, ip_options)) /** @todo check minimum size requirements here. */
     948        return;
     949    uint32_t cbHdr = (uint32_t)pHdr->ip_hl * 4;
     950    if (    cbHdr < RT_UOFFSETOF(INTNETIPV4, ip_options)
     951        ||  cbPacket < cbHdr)
     952        return;
     953
     954    /*
     955     * Ignore 255.255.255.255 (broadcast), 0.0.0.0 (null) and already cached addresses.
     956     */
     957    INTNETADDRU Addr;
     958    Addr.au32[0] = pHdr->ip_src;
     959    if (Addr.au32[0] == UINT32_C(0xffffffff))
     960        return;
     961
     962    int i = -1;
     963    if (    Addr.au32[0] == 0
     964        || (i = intnetR0IfAddrCacheLookupLikely(&pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, sizeof(pHdr->ip_src))) >= 0)
     965    {
     966#if 0 /** @todo quick DHCP check? */
     967        if (pHdr->ip_p != INTNETIPV4_PROT_UDP)
     968            return;
     969#endif
     970        return;
     971    }
     972
     973    /*
     974     * Check the header checksum.
     975     */
     976    /** @todo IP checksumming */
     977
     978    /*
     979     * Add the source address.
     980     */
     981    if (i < 0)
     982        intnetR0IfAddrCacheAddIt(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr);
     983
     984    /*
     985     * Check for DHCP (properly this time).
     986     */
     987    /** @todo DHCPRELEASE request? */
     988}
     989
     990
     991
     992/**
     993 * Sniff up source addresses from an ARP request or reply.
     994 *
     995 * @param   pIf             The interface that's sending the frame.
     996 * @param   pHdr            The ARP header.
     997 * @param   cbPacket        The size of the packet (migth be larger than the ARP
     998 *                          request 'cause of min ethernet frame size).
     999 */
     1000static void intnetR0IfSniffArpSourceAddr(PINTNETIF pIf, PCINTNETARPHDR pHdr, uint32_t cbPacket)
     1001{
     1002    /*
     1003     * Ignore malformed packets and packets which doesn't interrest us.
     1004     */
     1005    if (RT_UNLIKELY(    cbPacket <= sizeof(*pHdr)
     1006                    ||  pHdr->ar_hlen != sizeof(PDMMAC)
     1007                    ||  pHdr->ar_htype != RT_H2BE_U16(INTNET_ARP_ETHER)
     1008                    ||  (   pHdr->ar_oper != RT_H2BE_U16(INTNET_ARPOP_REQUEST)
     1009                         && pHdr->ar_oper != RT_H2BE_U16(INTNET_ARPOP_REPLY)
     1010                         && pHdr->ar_oper != RT_H2BE_U16(INTNET_ARPOP_REVREQUEST)
     1011                         && pHdr->ar_oper != RT_H2BE_U16(INTNET_ARPOP_REVREPLY)
     1012                         /** @todo Read up on inverse ARP. */
     1013                        )
     1014                   )
     1015       )
     1016        return;
     1017
     1018    /*
     1019     * Deal with the protocols.
     1020     */
     1021    INTNETADDRU Addr;
     1022    if (pHdr->ar_ptype == RT_H2BE_U16(INTNET_ETHERTYPE_IPV4))
     1023    {
     1024        /*
     1025         * IPv4.
     1026         */
     1027        PCINTNETARPIPV4 pReq = (PCINTNETARPIPV4)pHdr;
     1028        if (RT_UNLIKELY(    pHdr->ar_plen == sizeof(pReq->ar_spa)
     1029                        ||  cbPacket < sizeof(*pReq)
     1030                        ||  pReq->ar_spa.u == 0 /** @todo add an inline function for checking that an IP address is worth caching. */
     1031                        ||  pReq->ar_spa.u == UINT32_C(0xffffffff)))
     1032            return;
     1033
     1034        if (INTNET_ARPOP_IS_REPLY(RT_BE2H_U16(pHdr->ar_oper)))
     1035        {
     1036            Addr.IPv4 = pReq->ar_tpa;
     1037            intnetR0IfAddrCacheDelete(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, sizeof(pReq->ar_tpa));
     1038        }
     1039        Addr.IPv4 = pReq->ar_spa;
     1040        intnetR0IfAddrCacheAdd(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, sizeof(pReq->ar_spa));
     1041    }
     1042    else if (pHdr->ar_ptype == RT_H2BE_U16(INTNET_ETHERTYPE_IPV6))
     1043    {
     1044        /*
     1045         * IPv6.
     1046         */
     1047        PCINTNETARPIPV6 pReq = (PCINTNETARPIPV6)pHdr;
     1048        if (RT_UNLIKELY(    pHdr->ar_plen == sizeof(pReq->ar_spa)
     1049                        ||  cbPacket < sizeof(*pReq)
     1050                        /** @todo IPv6 ||  pReq->ar_spa.au32[0] == 0 or something
     1051                        ||  pReq->ar_spa.au32[0] == UINT32_C(0xffffffff)*/))
     1052            return;
     1053
     1054        if (INTNET_ARPOP_IS_REPLY(RT_BE2H_U16(pHdr->ar_oper)))
     1055        {
     1056            Addr.IPv6 = pReq->ar_tpa;
     1057            intnetR0IfAddrCacheDelete(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv6], &Addr, sizeof(pReq->ar_tpa));
     1058        }
     1059        Addr.IPv6 = pReq->ar_spa;
     1060        intnetR0IfAddrCacheAdd(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv6], &Addr, sizeof(pReq->ar_spa));
     1061    }
     1062    else
     1063        Log(("intnetR0IfSniffArpSourceAddr: unknown ar_ptype=%#x\n", RT_BE2H_U16(pHdr->ar_ptype)));
     1064}
     1065
     1066
     1067
     1068/**
     1069 * Checks packets send by a normal interface for new network
     1070 * layer addresses.
     1071 *
     1072 * @param   pIf             The interface that's sending the frame.
     1073 * @param   pbFrame         The frame.
     1074 * @param   cbFrame         The size of the frame.
     1075 */
     1076static void intnetR0IfSniffSourceAddr(PINTNETIF pIf, uint8_t const *pbFrame, uint32_t cbFrame)
     1077{
     1078    /*
     1079     * Fish out the ethertype and look for stuff we can handle.
     1080     */
     1081    if (cbFrame <= sizeof(INTNETETHERHDR))
     1082        return;
     1083    cbFrame -= sizeof(INTNETETHERHDR);
     1084
     1085    uint16_t EtherType = ((PCINTNETETHERHDR)pbFrame)->EtherType;
     1086    if (EtherType == RT_H2BE_U16(INTNET_ETHERTYPE_IPV4))
     1087        intnetR0IfSniffIPv4SourceAddr(pIf, (PCINTNETIPV4)((PCINTNETETHERHDR)pbFrame + 1), cbFrame);
     1088#if 0 /** @todo IntNet: implement IPv6 for wireless MAC sharing. */
     1089    else if (EtherType == RT_H2BE_U16(INTNET_ETHERTYPE_IPV6))
     1090        intnetR0IfSniffIPv6SourceAddr(pIf, (PCINTNETIPV6)((PCINTNETETHERHDR)pbFrame + 1), cbFrame);
     1091#endif
     1092#if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */
     1093    else if (   EtherType == RT_H2BE_U16(0x8037) //??
     1094             || EtherType == RT_H2BE_U16(0x8137) //??
     1095             || EtherType == RT_H2BE_U16(0x8138) //??
     1096             )
     1097        intnetR0IfSniffIpxSourceAddr(pIf, (PCINTNETIPX)((PCINTNETETHERHDR)pbFrame + 1), cbFrame);
     1098#endif
     1099    else if (EtherType == RT_H2BE_U16(INTNET_ETHERTYPE_ARP))
     1100        intnetR0IfSniffArpSourceAddr(pIf, (PCINTNETARPHDR)((PCINTNETETHERHDR)pbFrame + 1), cbFrame);
    2391101}
    2401102
     
    4371299
    4381300/**
    439  * Ethernet header.
    440  */
    441 #pragma pack(1)
    442 typedef struct INTNETETHERHDR
    443 {
    444     PDMMAC      MacDst;
    445     PDMMAC      MacSrc;
    446     uint16_t    EtherType;
    447 } INTNETETHERHDR;
    448 #pragma pack()
    449 typedef INTNETETHERHDR *PINTNETETHERHDR;
    450 typedef INTNETETHERHDR const *PCINTNETETHERHDR;
    451 
    452 
    453 /**
    4541301 * Sends a frame to a specific interface.
    4551302 *
     
    4711318    }
    4721319
    473     Log(("intnetR0IfSend: overflow cb=%d hIf=%#x\n", pSG->cbTotal, pIf->hIf));
     1320    Log(("intnetR0IfSend: overflow cb=%d hIf=%RX32\n", pSG->cbTotal, pIf->hIf));
    4741321
    4751322#if 0 /* This is bad stuff now as we're blocking while locking down the network.
     
    9071754    {
    9081755        intnetR0SgInitTemp(&Sg, (void *)pvFrame, cbFrame);
    909         intnetR0NetworkSend(pIf->pNetwork, pIf, 0, &Sg, !!pTrunkIf);
     1756        intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf);
    9101757    }
    9111758
     
    9221769            if (pvCurFrame)
    9231770            {
     1771                if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
     1772                    intnetR0IfSniffSourceAddr(pIf, (uint8_t *)pvCurFrame, pHdr->cbFrame);
    9241773                intnetR0SgInitTemp(&Sg, pvCurFrame, pHdr->cbFrame);
    925                 intnetR0NetworkSend(pIf->pNetwork, pIf, 0, &Sg, !!pTrunkIf);
     1774                intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf);
    9261775            }
    9271776        }
     
    9351784     * Release the semaphore(s) and release references.
    9361785     */
    937     rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
     1786    rc = RTSemFastMutexRelease(pNetwork->FastMutex);
    9381787    if (pTrunkIf)
    9391788    {
     
    15392388    PINTNETIF pIf = (PINTNETIF)pvUser1;
    15402389    PINTNET   pIntNet = (PINTNET)pvUser2;
    1541     Log(("intnetR0IfDestruct: pvObj=%p pIf=%p pIntNet=%p hIf=%#x\n", pvObj, pIf, pIntNet, pIf->hIf));
     2390    Log(("intnetR0IfDestruct: pvObj=%p pIf=%p pIntNet=%p hIf=%RX32\n", pvObj, pIf, pIntNet, pIf->hIf));
    15422391
    15432392    RTSemFastMutexRequest(pIntNet->FastMutex);
     
    15572406    {
    15582407        void *pvObj2 = RTHandleTableFreeWithCtx(pIntNet->hHtIfs, hIf, pIf->pSession);
    1559         AssertMsg(pvObj2 == pIf, ("%p, %p, hIf=%#x pSession=%p\n", pvObj2, pIf, hIf, pIf->pSession));
     2408        AssertMsg(pvObj2 == pIf, ("%p, %p, hIf=%RX32 pSession=%p\n", pvObj2, pIf, hIf, pIf->pSession));
    15602409    }
    15612410
     
    17592608                    {
    17602609                        *phIf = pIf->hIf;
    1761                         Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%p cbSend=%u cbRecv=%u cbBuf=%u\n",
     2610                        Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%RX32 cbSend=%u cbRecv=%u cbBuf=%u\n",
    17622611                             *phIf, pIf->pIntBufDefault->cbSend, pIf->pIntBufDefault->cbRecv, pIf->pIntBufDefault->cbBuf));
    17632612                        return VINF_SUCCESS;
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