VirtualBox

Changeset 52518 in vbox


Ignore:
Timestamp:
Aug 28, 2014 3:42:09 PM (10 years ago)
Author:
vboxsync
Message:

intnetR0NetworkSharedMacDetectAndFixBroadcast: handle ARP, IPv4 and IPv6.
Ok bird@.

File:
1 edited

Legend:

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

    r52445 r52518  
    29562956
    29572957/**
    2958  * Work around the issue with WiFi routers that replace IPv6 multicast
    2959  * Ethernet addresses with unicast ones. We check IPv6 destination address
    2960  * to determine if the packet originally had a multicast address, and if so
    2961  * we restore the original address and treat the modified packet as being a
    2962  * broadcast.
    2963  *
     2958 * Detect broadcasts packaged as unicast and convert them back to broadcast.
     2959 *
     2960 * WiFi routers try to use ethernet unicast instead of broadcast or
     2961 * multicast when possible.  Look inside the packet and fix up
     2962 * ethernet destination to be proper broadcast or multicast if
     2963 * necessary.
     2964 *
     2965 * @returns true broadcast (pEthHdr & pSG are modified), false if not.
    29642966 * @param   pNetwork        The network the frame is being sent to.
    2965  * @param   pSG             Pointer to the gather list for the frame.
    2966  * @param   pEthHdr         Pointer to the ethernet header.
    2967  */
    2968 static bool intnetR0NetworkDetectAndFixNdBroadcast(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
     2967 * @param   pSG             Pointer to the gather list for the frame.  The
     2968 *                          ethernet destination address is modified when
     2969 *                          returning true.
     2970 * @param   pEthHdr         Pointer to the ethernet header.  The ethernet
     2971 *                          destination address is modified when returning true.
     2972 */
     2973static bool intnetR0NetworkSharedMacDetectAndFixBroadcast(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
    29692974{
    29702975    NOREF(pNetwork);
    29712976
    2972     if (RT_BE2H_U16(pEthHdr->EtherType) != RTNET_ETHERTYPE_IPV6)
    2973         return false;
    2974     /*
    2975      * Check the minimum size and get a linear copy of the thing to work on,
    2976      * using the temporary buffer if necessary.
    2977      */
    2978     if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) +
    2979                                             sizeof(RTNETNDP)))
    2980         return false;
    2981     uint8_t bTmp[sizeof(RTNETIPV6) + sizeof(RTNETNDP)];
    2982     PRTNETIPV6 pIPv6 = (PRTNETIPV6)((uint8_t *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
    2983     if (    pSG->cSegsUsed != 1
    2984         &&  pSG->aSegs[0].cb < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) +
    2985                                                         sizeof(RTNETNDP))
    2986     {
    2987         Log6(("fw: Copying IPv6 pkt %u\n", sizeof(RTNETIPV6)));
    2988         if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), sizeof(RTNETIPV6)
    2989                                                + sizeof(RTNETNDP), bTmp))
     2977    switch (pEthHdr->EtherType)
     2978    {
     2979        case RT_H2N_U16_C(RTNET_ETHERTYPE_ARP):
     2980        {
     2981            uint16_t ar_oper;
     2982            if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETARPHDR, ar_oper),
     2983                                    sizeof(ar_oper), &ar_oper))
     2984                return false;
     2985
     2986            if (ar_oper == RT_H2N_U16_C(RTNET_ARPOP_REQUEST))
     2987            {
     2988                /* change to broadcast */
     2989                pEthHdr->DstMac.au16[0] = 0xffff;
     2990                pEthHdr->DstMac.au16[1] = 0xffff;
     2991                pEthHdr->DstMac.au16[2] = 0xffff;
     2992            }
     2993            else
     2994                return false;
     2995            break;
     2996        }
     2997
     2998        case RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4):
     2999        {
     3000            RTNETADDRIPV4 ip_dst;
     3001            if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPV4, ip_dst),
     3002                                    sizeof(ip_dst), &ip_dst))
     3003                return false;
     3004
     3005            if (ip_dst.u == 0xffffffff) /* 255.255.255.255? */
     3006            {
     3007                /* change to broadcast */
     3008                pEthHdr->DstMac.au16[0] = 0xffff;
     3009                pEthHdr->DstMac.au16[1] = 0xffff;
     3010                pEthHdr->DstMac.au16[2] = 0xffff;
     3011            }
     3012            else if ((ip_dst.au8[0] & 0xf0) == 0xe0) /* IPv4 multicast? */
     3013            {
     3014                /* change to 01:00:5e:xx:xx:xx multicast ... */
     3015                pEthHdr->DstMac.au8[0] = 0x01;
     3016                pEthHdr->DstMac.au8[1] = 0x00;
     3017                pEthHdr->DstMac.au8[2] = 0x5e;
     3018                /* ... with lower 23 bits from the multicast IP address */
     3019                pEthHdr->DstMac.au8[3] = ip_dst.au8[1] & 0x7f;
     3020                pEthHdr->DstMac.au8[4] = ip_dst.au8[2];
     3021                pEthHdr->DstMac.au8[5] = ip_dst.au8[3];
     3022            }
     3023            else
     3024                return false;
     3025            break;
     3026        }
     3027
     3028        case RT_H2N_U16_C(RTNET_ETHERTYPE_IPV6):
     3029        {
     3030            RTNETADDRIPV6 ip6_dst;
     3031            if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPV6, ip6_dst),
     3032                                    sizeof(ip6_dst), &ip6_dst))
     3033                return false;
     3034
     3035            if (ip6_dst.au8[0] == 0xff) /* IPv6 multicast? */
     3036            {
     3037                pEthHdr->DstMac.au16[0] = 0x3333;
     3038                pEthHdr->DstMac.au16[1] = ip6_dst.au16[6];
     3039                pEthHdr->DstMac.au16[2] = ip6_dst.au16[7];
     3040            }
     3041            else
     3042                return false;
     3043            break;
     3044        }
     3045
     3046        default:
    29903047            return false;
    2991         pIPv6 = (PRTNETIPV6)bTmp;
    2992     }
    2993 
    2994     /* Check IPv6 destination address if it is a multicast address. */
    2995     static uint8_t auSolicitedNodeMulticastPrefix[] =
    2996         {
    2997             0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    2998             0x00, 0x00, 0x00, 0x01, 0xff
    2999         };
    3000     if (memcmp(pIPv6->ip6_dst.au8, auSolicitedNodeMulticastPrefix,
    3001                sizeof(auSolicitedNodeMulticastPrefix)) == 0)
    3002     {
    3003         /*
    3004          * The original must have been composed of 0x3333 followed by the last
    3005          * four bytes of the solicited-node multicast address.
    3006          */
    3007         if (pSG->aSegs[0].cb < sizeof(RTNETETHERHDR))
    3008         {
    3009             RTMAC DstMac;
    3010             DstMac.au16[0] = 0x3333;
    3011             DstMac.au16[1] = pIPv6->ip6_dst.au16[6];
    3012             DstMac.au16[2] = pIPv6->ip6_dst.au16[7];
    3013             return intnetR0SgWritePart(pSG, RT_OFFSETOF(RTNETETHERHDR, DstMac), sizeof(RTMAC), &DstMac);
    3014         }
    3015         pEthHdr = (PRTNETETHERHDR)pSG->aSegs[0].pv;
    3016         pEthHdr->DstMac.au16[0] = 0x3333;
    3017         pEthHdr->DstMac.au16[1] = pIPv6->ip6_dst.au16[6];
    3018         pEthHdr->DstMac.au16[2] = pIPv6->ip6_dst.au16[7];
    3019         return true;
    3020     }
    3021 
    3022     return false;
     3048    }
     3049
     3050
     3051    /*
     3052     * Update ethernet destination in the segment.
     3053     */
     3054    intnetR0SgWritePart(pSG, RT_OFFSETOF(RTNETETHERHDR, DstMac), sizeof(pEthHdr->DstMac), &pEthHdr->DstMac);
     3055
     3056    return true;
    30233057}
    30243058
     
    37063740        else if (fSrc & INTNETTRUNKDIR_WIRE)
    37073741        {
    3708             if (intnetR0NetworkDetectAndFixNdBroadcast(pNetwork, pSG, &EthHdr))
     3742            if (intnetR0NetworkSharedMacDetectAndFixBroadcast(pNetwork, pSG, &EthHdr))
    37093743                enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, fSrc, pIfSender, pSG, &EthHdr, pDstTab);
    37103744            else
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