Changeset 45716 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Apr 24, 2013 6:47:18 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 85262
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp
r45356 r45716 839 839 840 840 /** 841 * Checks if the IPv6 address is a good interface address. 842 * @returns true/false. 843 * @param addr The address, network endian. 844 */ 845 DECLINLINE(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 /** 841 857 * Checks if the IPv4 address is a broadcast address. 842 858 * @returns true/false. … … 1071 1087 { 1072 1088 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)); 1075 1095 break; 1076 1096 default: … … 1248 1268 { 1249 1269 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)); 1252 1276 break; 1253 1277 default: … … 2334 2358 } 2335 2359 2336 case RTNET_ETHERTYPE_IPV6:2337 {2338 /** @todo IPv6: Check for ICMPv6. It looks like type 133 (Router solicitation) might2339 * need to be edited. Check out how NDP works... */2340 break;2341 }2342 2343 2360 case RTNET_ETHERTYPE_ARP: 2344 2361 intnetR0TrunkIfSnoopArp(pNetwork, pSG); … … 2347 2364 } 2348 2365 #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 */ 2380 static 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 } 2349 2401 2350 2402 … … 2498 2550 intnetR0IfSnoopIPv4SourceAddr(pIf, (PCRTNETIPV4)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso); 2499 2551 break; 2500 #if 0 /** @todo IntNet: implement IPv6 for wireless MAC sharing. */ 2552 2501 2553 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); 2505 2555 break; 2506 #endif 2556 2507 2557 #if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */ 2508 2558 case RTNET_ETHERTYPE_IPX_1: … … 2686 2736 } 2687 2737 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 */ 2752 static 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 } 2688 2775 2689 2776 /** … … 2766 2853 } 2767 2854 } 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 } 2771 2900 } 2772 2901 … … 2791 2920 2792 2921 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 */ 2933 static 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 */ 2998 static 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 } 2793 3040 /** 2794 3041 * Edits an ARP packet arriving from the wire via the trunk connection. … … 3098 3345 3099 3346 /* 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 /* 3100 3358 * Check for ARP packets from the wire since we'll have to make 3101 3359 * modification to them if we're sharing the MAC address with the host. … … 3175 3433 break; 3176 3434 3177 #if 0 /** @todo IntNet: implement IPv6 for wireless MAC sharing. */ 3178 case RTNET_ETHERTYPE_IPV6 3435 case RTNET_ETHERTYPE_IPV6: 3179 3436 if (RT_UNLIKELY(!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPV6, ip6_dst), sizeof(Addr.IPv6), &Addr))) 3180 3437 { … … 3185 3442 cbAddr = sizeof(Addr.IPv6); 3186 3443 break; 3187 #endif3188 3444 #if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */ 3189 3445 case RTNET_ETHERTYPE_IPX_1: … … 3401 3657 enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, fSrc, pIfSender, pSG, &EthHdr, pDstTab); 3402 3658 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 } 3404 3665 else 3405 3666 enmSwDecision = intnetR0NetworkSwitchUnicast(pNetwork, fSrc, pIfSender, &EthHdr.DstMac, pDstTab);
Note:
See TracChangeset
for help on using the changeset viewer.