VirtualBox

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


Ignore:
Timestamp:
Apr 24, 2013 6:47:18 PM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
85262
Message:

IntNet: Integration of wireless IPv6 support patch + unicast ND solicitation fix + 32-bit compile fix + formatting (#3060)

File:
1 edited

Legend:

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

    r45356 r45716  
    839839
    840840/**
     841 * Checks if the IPv6 address is a good interface address.
     842 * @returns true/false.
     843 * @param   addr        The address, network endian.
     844 */
     845DECLINLINE(bool) intnetR0IPv6AddrIsGood(RTNETADDRIPV6 addr)
     846{
     847    return  !(   (   addr.QWords.qw0 == 0 && addr.QWords.qw1 == 0)                      /* :: */
     848              || (   addr.Words.w0 & RT_H2BE_U16(0xff00) == RT_H2BE_U16(0xff00)) /* multicast */
     849              || (   addr.Words.w0 == 0 && addr.Words.w1 == 0
     850                  && addr.Words.w2 == 0 && addr.Words.w3 == 0
     851                  && addr.Words.w4 == 0 && addr.Words.w5 == 0
     852                  && addr.Words.w6 == 0 && addr.Words.w7 == RT_H2BE_U16(0x0001)));     /* ::1 */
     853}
     854
     855
     856/**
    841857 * Checks if the IPv4 address is a broadcast address.
    842858 * @returns true/false.
     
    10711087    {
    10721088        case kIntNetAddrType_IPv4:
    1073             Log(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",
    1074                  pIf->hIf, &pIf->MacAddr, iEntry, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
     1089            Log(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 deleted #%d  %RTnaipv4 %s\n",
     1090                 pIf->hIf, &pIf->MacAddr, iEntry, pAddr->IPv4, pszMsg));
     1091            break;
     1092        case kIntNetAddrType_IPv6:
     1093            Log(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv6 deleted #%d %RTnaipv6 %s\n",
     1094                pIf->hIf, &pIf->MacAddr, iEntry, pAddr->IPv6, pszMsg));
    10751095            break;
    10761096        default:
     
    12481268    {
    12491269        case kIntNetAddrType_IPv4:
    1250             Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",
    1251                  pIf->hIf, &pIf->MacAddr, pCache->cEntries, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
     1270            Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %RTnaipv4 %s\n",
     1271                 pIf->hIf, &pIf->MacAddr, pCache->cEntries, pAddr->IPv4, pszMsg));
     1272            break;
     1273        case kIntNetAddrType_IPv6:
     1274            Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv6 added #%d %RTnaipv6 %s\n",
     1275                 pIf->hIf, &pIf->MacAddr, pCache->cEntries, pAddr->IPv6, pszMsg));
    12521276            break;
    12531277        default:
     
    23342358        }
    23352359
    2336         case RTNET_ETHERTYPE_IPV6:
    2337         {
    2338             /** @todo IPv6: Check for ICMPv6. It looks like type 133 (Router solicitation) might
    2339              * need to be edited. Check out how NDP works...  */
    2340             break;
    2341         }
    2342 
    23432360        case RTNET_ETHERTYPE_ARP:
    23442361            intnetR0TrunkIfSnoopArp(pNetwork, pSG);
     
    23472364}
    23482365#endif /* INTNET_WITH_DHCP_SNOOPING */
     2366
     2367/**
     2368 * Deals with an IPv6 packet.
     2369 *
     2370 * This will fish out the source IP address and add it to the cache.
     2371 * Then it will look for DHCPRELEASE requests (?) and anything else
     2372 * that we might find useful later.
     2373 *
     2374 * @param   pIf             The interface that's sending the frame.
     2375 * @param   pIpHdr          Pointer to the IPv4 header in the frame.
     2376 * @param   cbPacket        The size of the packet, or more correctly the
     2377 *                          size of the frame without the ethernet header.
     2378 * @param   fGso            Set if this is a GSO frame, clear if regular.
     2379 */
     2380static void intnetR0IfSnoopIPv6SourceAddr(PINTNETIF pIf, PCRTNETIPV6 pIpHdr, uint32_t cbPacket, bool fGso)
     2381{
     2382    /*
     2383     * Check the header size first to prevent access invalid data.
     2384     */
     2385    if (cbPacket < RTNETIPV6_MIN_LEN)
     2386        return;
     2387
     2388    /*
     2389     * If the source address is good (not multicast) and
     2390     * not already in the address cache of the sender, add it.
     2391     */
     2392    RTNETADDRU Addr;
     2393    Addr.IPv6 = pIpHdr->ip6_src;
     2394
     2395    if (    intnetR0IPv6AddrIsGood(Addr.IPv6) && (pIpHdr->ip6_hlim == 0xff)
     2396        &&  intnetR0IfAddrCacheLookupLikely(&pIf->aAddrCache[kIntNetAddrType_IPv6], &Addr, sizeof(Addr.IPv6)) < 0)
     2397    {
     2398        intnetR0IfAddrCacheAddIt(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv6], &Addr, "if/ipv6");
     2399    }
     2400}
    23492401
    23502402
     
    24982550            intnetR0IfSnoopIPv4SourceAddr(pIf, (PCRTNETIPV4)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso);
    24992551            break;
    2500 #if 0 /** @todo IntNet: implement IPv6 for wireless MAC sharing. */
     2552
    25012553        case RTNET_ETHERTYPE_IPV6:
    2502             /** @todo IPv6: Check for ICMPv6. It looks like type 133 (Router solicitation) might
    2503              * need to be edited. Check out how NDP works...  */
    2504             intnetR0IfSnoopIPv6SourceAddr(pIf, (PCINTNETIPV6)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso, pfSgFlags);
     2554            intnetR0IfSnoopIPv6SourceAddr(pIf, (PCRTNETIPV6)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso);
    25052555            break;
    2506 #endif
     2556
    25072557#if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */
    25082558        case RTNET_ETHERTYPE_IPX_1:
     
    26862736}
    26872737
     2738
     2739/**
     2740 * Calculates the checksum of a full ipv6 frame.
     2741 *
     2742 * @returns 16-bit hecksum value.
     2743 * @param   pIpHdr          The IPv6 header (network endian (big)).
     2744 * @param   bProtocol       The protocol number.  This can be the same as the
     2745 *                          ip6_nxt field, but doesn't need to be.
     2746 * @param   cbPkt           The packet size (host endian of course).  This can
     2747 *                          be the same as the ip6_plen field, but as with @a
     2748 *                          bProtocol it won't be when extension headers are
     2749 *                          present.  For UDP this will be uh_ulen converted to
     2750 *                          host endian.
     2751 */
     2752static uint16_t computeIPv6FullChecksum(PCRTNETIPV6 pIpHdr)
     2753{
     2754    uint16_t const *data;
     2755    int len         = RT_BE2H_U16(pIpHdr->ip6_plen);
     2756    uint32_t sum    = RTNetIPv6PseudoChecksum(pIpHdr);
     2757
     2758    /* add the payload */
     2759    data = (uint16_t *) (pIpHdr + 1);
     2760    while(len > 1)
     2761    {
     2762        sum += *(data);
     2763        data++;
     2764        len -= 2;
     2765    }
     2766
     2767    if(len > 0)
     2768        sum += *((uint8_t *) data);
     2769
     2770    while(sum >> 16)
     2771        sum = (sum & 0xffff) + (sum >> 16);
     2772
     2773    return (uint16_t) ~sum;
     2774}
    26882775
    26892776/**
     
    27662853            }
    27672854        }
    2768         //else if (pSG->fFlags & INTNETSG_FLAGS_ICMPV6_NDP)
    2769         //{ /// @todo move the editing into a different function
    2770         //}
     2855        else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
     2856        {
     2857            /*
     2858             * IPV6 ICMP Neighbor Discovery : replace
     2859             * 1) the advertised source mac address in outgoing neighbor sollicitations
     2860             *    with the HW MAC address of the trunk interface,
     2861             * 2) the advertised target mac address in outgoing neighbor advertisements
     2862             *    with the HW mac address of the trunk interface.
     2863             *
     2864             * Note that this only applies to traffic going out on the trunk. Incoming
     2865             * NS/NA will never advertise any VM mac address, so we do not need to touch
     2866             * them. Other VMs on this bridge as well as the host will see and use the VM's
     2867             * actual mac addresses.
     2868             *
     2869             */
     2870
     2871            PRTNETIPV6 pIPv6            = (PRTNETIPV6)(pEthHdr + 1);
     2872            PRTNETNDP pNd               = (PRTNETNDP)(pIPv6 + 1);
     2873            PRTNETNDP_SLLA_OPT pLLAOpt  = (PRTNETNDP_SLLA_OPT)(pNd + 1);
     2874
     2875            /* make sure we have enough bytes to work with */
     2876            if(pSG->cbTotal >= (RTNETIPV6_MIN_LEN + RTNETIPV6_ICMPV6_ND_WITH_LLA_OPT_MIN_LEN) &&
     2877               /* ensure the packet came from our LAN (not gone through any router) */
     2878               pIPv6->ip6_hlim == 0xff &&
     2879               /* protocol has to be icmpv6 */
     2880                pIPv6->ip6_nxt == RTNETIPV6_PROT_ICMPV6 &&
     2881               /* we either have a sollicitation with source link layer addr. opt, or */
     2882                ((pNd->icmp6_type == RTNETIPV6_ICMP_NS_TYPE &&
     2883                            pNd->icmp6_code == RTNETIPV6_ICMPV6_CODE_0 &&
     2884                            pLLAOpt->type == RTNETIPV6_ICMP_ND_SLLA_OPT) ||
     2885                 /* an advertisement with target link layer addr. option */
     2886                ((pNd->icmp6_type == RTNETIPV6_ICMP_NA_TYPE &&
     2887                            pNd->icmp6_code == RTNETIPV6_ICMPV6_CODE_0 &&
     2888                            pLLAOpt->type == RTNETIPV6_ICMP_ND_TLLA_OPT)) ) &&
     2889                pLLAOpt->len == RTNETIPV6_ICMP_ND_LLA_LEN)
     2890            {
     2891                /* swap the advertised VM MAC address with the trunk's */
     2892                pLLAOpt->slla   = pThis->MacAddr;
     2893
     2894                /* recompute the checksum since we changed the packet */
     2895                pNd->icmp6_cksum = 0;
     2896                pNd->icmp6_cksum = computeIPv6FullChecksum(pIPv6);
     2897            }
     2898           
     2899        }
    27712900    }
    27722901
     
    27912920
    27922921
     2922/**
     2923 * Work around the issue with WiFi routers that replace IPv6 multicast
     2924 * Ethernet addresses with unicast ones. We check IPv6 destination address
     2925 * to determine if the packet originally had a multicast address, and if so
     2926 * we restore the original address and treat the modified packet as being a
     2927 * broadcast.
     2928 *
     2929 * @param   pNetwork        The network the frame is being sent to.
     2930 * @param   pSG             Pointer to the gather list for the frame.
     2931 * @param   pEthHdr         Pointer to the ethernet header.
     2932 */
     2933static bool intnetR0NetworkDetectAndFixNdBroadcast(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
     2934{
     2935    if (RT_BE2H_U16(pEthHdr->EtherType) != RTNET_ETHERTYPE_IPV6)
     2936        return false;
     2937    /*
     2938     * Check the minimum size and get a linear copy of the thing to work on,
     2939     * using the temporary buffer if necessary.
     2940     */
     2941    if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) +
     2942                                            sizeof(RTNETNDP)))
     2943        return false;
     2944    uint8_t bTmp[sizeof(RTNETIPV6) + sizeof(RTNETNDP)];
     2945    PRTNETIPV6 pIPv6 = (PRTNETIPV6)((uint8_t *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
     2946    if (    pSG->cSegsUsed != 1
     2947        &&  pSG->aSegs[0].cb < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) +
     2948                                                        sizeof(RTNETNDP))
     2949    {
     2950        Log6(("fw: Copying IPv6 pkt %u\n", sizeof(RTNETIPV6)));
     2951        if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), sizeof(RTNETIPV6)
     2952                                               + sizeof(RTNETNDP), bTmp))
     2953            return false;
     2954        pIPv6 = (PRTNETIPV6)bTmp;
     2955    }
     2956
     2957    PCRTNETNDP pNd  = (PCRTNETNDP) (pIPv6 + 1);
     2958
     2959    /* Check IPv6 destination address if it is a multicast address. */
     2960    static uint8_t auSolicitedNodeMulticastPrefix[] =
     2961        {
     2962            0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     2963            0x00, 0x00, 0x00, 0x01, 0xff
     2964        };
     2965    if (memcmp(pIPv6->ip6_dst.au8, auSolicitedNodeMulticastPrefix,
     2966               sizeof(auSolicitedNodeMulticastPrefix)) == 0)
     2967    {
     2968        /*
     2969         * The original must have been composed of 0x3333 followed by the last
     2970         * four bytes of the solicited-node multicast address.
     2971         */
     2972        if (pSG->aSegs[0].cb < sizeof(RTNETETHERHDR))
     2973        {
     2974            RTMAC DstMac;
     2975            DstMac.au16[0] = 0x3333;
     2976            DstMac.au16[1] = pIPv6->ip6_dst.au16[6];
     2977            DstMac.au16[2] = pIPv6->ip6_dst.au16[7];
     2978            return intnetR0SgWritePart(pSG, RT_OFFSETOF(RTNETETHERHDR, DstMac), sizeof(RTMAC), &DstMac);
     2979        }
     2980        pEthHdr = (PRTNETETHERHDR)pSG->aSegs[0].pv;
     2981        pEthHdr->DstMac.au16[0] = 0x3333;
     2982        pEthHdr->DstMac.au16[1] = pIPv6->ip6_dst.au16[6];
     2983        pEthHdr->DstMac.au16[2] = pIPv6->ip6_dst.au16[7];
     2984        return true;
     2985    }
     2986
     2987    return false;
     2988}
     2989
     2990
     2991/**
     2992 * Snoops a multicast ICMPv6 ND DAD from the wire via the trunk connection.
     2993 *
     2994 * @param   pNetwork        The network the frame is being sent to.
     2995 * @param   pSG             Pointer to the gather list for the frame.
     2996 * @param   pEthHdr         Pointer to the ethernet header.
     2997 */
     2998static void intnetR0NetworkSnoopNAFromWire(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
     2999{
     3000    /*
     3001     * Check the minimum size and get a linear copy of the thing to work on,
     3002     * using the temporary buffer if necessary.
     3003     */
     3004    if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) +
     3005                                            sizeof(RTNETNDP)))
     3006        return;
     3007    PRTNETIPV6 pIPv6 = (PRTNETIPV6)((uint8_t *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
     3008    if (    pSG->cSegsUsed != 1
     3009        &&  pSG->aSegs[0].cb < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) +
     3010                                                        sizeof(RTNETNDP))
     3011    {
     3012        Log6(("fw: Copying IPv6 pkt %u\n", sizeof(RTNETIPV6)));
     3013        if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), sizeof(RTNETIPV6)
     3014                                               + sizeof(RTNETNDP), pNetwork->pbTmp))
     3015            return;
     3016        pSG->fFlags |= INTNETSG_FLAGS_PKT_CP_IN_TMP;
     3017        pIPv6 = (PRTNETIPV6)pNetwork->pbTmp;
     3018    }
     3019
     3020    PCRTNETNDP pNd  = (PCRTNETNDP) (pIPv6 + 1);
     3021
     3022    /*
     3023     * a multicast NS with :: as source address means a DAD packet.
     3024     * if it comes from the wire and we have the DAD'd address in our cache,
     3025     * flush the entry as the address is being acquired by someone else on
     3026     * the network.
     3027     */
     3028    if (    pIPv6->ip6_hlim == 0xff
     3029        &&  pIPv6->ip6_nxt  == RTNETIPV6_PROT_ICMPV6
     3030        &&  pNd->icmp6_type == RTNETIPV6_ICMP_NS_TYPE
     3031        &&  pNd->icmp6_code == RTNETIPV6_ICMPV6_CODE_0
     3032        &&  pIPv6->ip6_src.QWords.qw0 == 0
     3033        &&  pIPv6->ip6_src.QWords.qw1 == 0)
     3034    {
     3035       
     3036        intnetR0NetworkAddrCacheDelete(pNetwork, (PCRTNETADDRU) &pNd->target_address,
     3037                                        kIntNetAddrType_IPv6, sizeof(RTNETADDRIPV6), "tif/ip6");
     3038    }
     3039}
    27933040/**
    27943041 * Edits an ARP packet arriving from the wire via the trunk connection.
     
    30983345
    30993346    /*
     3347     * Check for ICMPv6 Neighbor Advertisements coming from the trunk.
     3348     * If we see an advertisement for an IP in our cache, we can safely remove
     3349     * it as the IP has probably moved.
     3350     */
     3351    if (    (fSrc & INTNETTRUNKDIR_WIRE)
     3352        &&  RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_IPV6
     3353        &&  pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID)
     3354        intnetR0NetworkSnoopNAFromWire(pNetwork, pSG, pEthHdr);
     3355
     3356
     3357    /*
    31003358     * Check for ARP packets from the wire since we'll have to make
    31013359     * modification to them if we're sharing the MAC address with the host.
     
    31753433            break;
    31763434
    3177 #if 0 /** @todo IntNet: implement IPv6 for wireless MAC sharing. */
    3178         case RTNET_ETHERTYPE_IPV6
     3435        case RTNET_ETHERTYPE_IPV6:
    31793436            if (RT_UNLIKELY(!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPV6, ip6_dst), sizeof(Addr.IPv6), &Addr)))
    31803437            {
     
    31853442            cbAddr = sizeof(Addr.IPv6);
    31863443            break;
    3187 #endif
    31883444#if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */
    31893445        case RTNET_ETHERTYPE_IPX_1:
     
    34013657            enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, fSrc, pIfSender, pSG, &EthHdr, pDstTab);
    34023658        else if (fSrc & INTNETTRUNKDIR_WIRE)
    3403             enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchUnicast(pNetwork, pSG, &EthHdr, pDstTab);
     3659        {
     3660            if (intnetR0NetworkDetectAndFixNdBroadcast(pNetwork, pSG, &EthHdr))
     3661                enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, fSrc, pIfSender, pSG, &EthHdr, pDstTab);
     3662            else
     3663                enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchUnicast(pNetwork, pSG, &EthHdr, pDstTab);
     3664        }
    34043665        else
    34053666            enmSwDecision = intnetR0NetworkSwitchUnicast(pNetwork, fSrc, pIfSender, &EthHdr.DstMac, pDstTab);
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