Ticket #5503: vbox_ipv6_shared_mac_addr.patch
File vbox_ipv6_shared_mac_addr.patch, 18.6 KB (added by , 12 years ago) |
---|
-
include/iprt/net.h
diff -aur VirtualBox-4.2.10-orig/include/iprt/net.h VirtualBox-4.2.10/include/iprt/net.h
old new 323 323 324 324 /** The minimum IPv6 header length (in bytes). 325 325 * Up to and including RTNETIPV6::ip6_dst. */ 326 #define RTNETIPV6_MIN_LEN (40) 326 #define RTNETIPV6_MIN_LEN (40) 327 #define RTNETIPV6_ICMPV6_ND_WITH_LLA_OPT_MIN_LEN (32) 327 328 328 329 RTDECL(uint32_t) RTNetIPv6PseudoChecksum(PCRTNETIPV6 pIpHdr); 329 330 RTDECL(uint32_t) RTNetIPv6PseudoChecksumEx(PCRTNETIPV6 pIpHdr, uint8_t bProtocol, uint16_t cbPkt); 330 331 RTDECL(uint32_t) RTNetIPv6PseudoChecksumBits(PCRTNETADDRIPV6 pSrcAddr, PCRTNETADDRIPV6 pDstAddr, 331 332 uint8_t bProtocol, uint16_t cbPkt); 332 333 333 334 334 /** 335 335 * UDP header. 336 336 */ … … 737 737 738 738 /** @todo add ICMPv6 when needed. */ 739 739 740 #define RTNETIPV6_PROT_ICMPV6 (58) 741 #define RTNETIPV6_ICMPV6_CODE_0 (0) 742 #define RTNETIPV6_ICMP_NS_TYPE (135) 743 #define RTNETIPV6_ICMP_NA_TYPE (136) 744 #define RTNETIPV6_ICMP_ND_SLLA_OPT (1) 745 #define RTNETIPV6_ICMP_ND_TLLA_OPT (2) 746 #define RTNETIPV6_ICMP_ND_LLA_LEN (1) 747 748 /** ICMPv6 ND Source Link Layer Address option */ 749 #pragma pack(1) 750 typedef struct RTNETNDP_SLLA_OPT 751 { 752 uint8_t type; 753 uint8_t len; 754 RTMAC slla; 755 } RTNETNDP_SLLA_OPT; 756 #pragma pack() 757 758 AssertCompileSize(RTNETNDP_SLLA_OPT, 1+1+6); 759 760 typedef RTNETNDP_SLLA_OPT *PRTNETNDP_SLLA_OPT; 761 typedef RTNETNDP_SLLA_OPT const *PCRTNETNDP_SLLA_OPT; 762 763 /** ICMPv6 ND Neighbor Sollicitation */ 764 #pragma pack(1) 765 typedef struct RTNETNDP 766 { 767 /** ICMPv6 type. **/ 768 uint8_t icmp6_type; 769 /** ICMPv6 code. **/ 770 uint8_t icmp6_code; 771 /** ICMPv6 checksum **/ 772 uint16_t icmp6_cksum; 773 /** reserved **/ 774 uint32_t reserved; 775 /** target address **/ 776 RTNETADDRIPV6 target_address; 777 } RTNETNDP; 778 #pragma pack() 779 AssertCompileSize(RTNETNDP, 1+1+2+4+16); 780 /** Pointer to a NDP ND packet. */ 781 typedef RTNETNDP *PRTNETNDP; 782 /** Pointer to a const NDP NS packet. */ 783 typedef RTNETNDP const *PCRTNETNDP; 784 740 785 741 786 /** 742 787 * Ethernet ARP header. … … 805 850 typedef RTNETARPIPV4 const *PCRTNETARPIPV4; 806 851 807 852 808 /** @todo RTNETNDP (IPv6)*/809 810 811 853 /** @} */ 812 854 813 855 RT_C_DECLS_END -
include/iprt/types.h
diff -aur VirtualBox-4.2.10-orig/include/iprt/types.h VirtualBox-4.2.10/include/iprt/types.h
old new 395 395 /** 396 396 * 128-bit unsigned integer union. 397 397 */ 398 #pragma pack(1) 398 399 typedef union RTUINT128U 399 400 { 400 401 /** Natural view. … … 470 471 /** 8-bit view. */ 471 472 uint8_t au8[16]; 472 473 } RTUINT128U; 474 #pragma pack() 473 475 /** Pointer to a 64-bit unsigned integer union. */ 474 476 typedef RTUINT128U *PRTUINT128U; 475 477 /** Pointer to a const 64-bit unsigned integer union. */ -
src/VBox/Devices/Network/SrvIntNetR0.cpp
diff -aur VirtualBox-4.2.10-orig/src/VBox/Devices/Network/SrvIntNetR0.cpp VirtualBox-4.2.10/src/VBox/Devices/Network/SrvIntNetR0.cpp
old new 836 836 return NULL; 837 837 } 838 838 839 /** 840 * Checks if the IPv6 address is a good interface address. 841 * @returns true/false. 842 * @param addr The address, network endian. 843 */ 844 DECLINLINE(bool) intnetR0IPv6AddrIsGood(RTNETADDRIPV6 addr) 845 { 846 //check for :: 847 return !(addr.u == 0 || 848 //check for multicast 849 (addr.Words.w0 & RT_H2BE_U16(0xff00) == RT_H2BE_U16(0xff00)) || 850 //check for ::1 851 (addr.Words.w0 == 0 && addr.Words.w1 == 0 && addr.Words.w2 == 0 && 852 addr.Words.w3 == 0 && addr.Words.w4 ==0 && addr.Words.w5 == 0 && 853 addr.Words.w6 == 0 && addr.Words.w7 == RT_H2BE_U16(0x0001)) ); 854 } 855 839 856 840 857 /** 841 858 * Checks if the IPv4 address is a broadcast address. … … 848 865 return Addr.u == UINT32_MAX; 849 866 } 850 867 851 852 868 /** 853 869 * Checks if the IPv4 address is a good interface address. 854 870 * @returns true/false. … … 1070 1086 switch (enmAddrType) 1071 1087 { 1072 1088 case kIntNetAddrType_IPv4: 1073 Log (("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",1089 LogRel(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 deleted #%d %d.%d.%d.%d %s\n", 1074 1090 pIf->hIf, &pIf->MacAddr, iEntry, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg)); 1075 1091 break; 1092 case kIntNetAddrType_IPv6: 1093 LogRel(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv6 deleted #%d %00x:%00x:%00x:%00x:%00x:%00x:%00x %00x %s\n", 1094 pIf->hIf, &pIf->MacAddr, iEntry, 1095 pAddr->IPv6.Words.w0, 1096 pAddr->IPv6.Words.w1, 1097 pAddr->IPv6.Words.w2, 1098 pAddr->IPv6.Words.w3, 1099 pAddr->IPv6.Words.w4, 1100 pAddr->IPv6.Words.w5, 1101 pAddr->IPv6.Words.w6, 1102 pAddr->IPv6.Words.w7, 1103 pszMsg 1104 )); 1105 break; 1076 1106 default: 1077 Log (("intnetR0IfAddrCacheDeleteIt: hIf=%RX32 MAC=%.6Rhxs type=%d #%d %.*Rhxs %s\n",1107 LogRel(("intnetR0IfAddrCacheDeleteIt: hIf=%RX32 MAC=%.6Rhxs type=%d #%d %.*Rhxs %s\n", 1078 1108 pIf->hIf, &pIf->MacAddr, enmAddrType, iEntry, pCache->cbAddress, pAddr, pszMsg)); 1079 1109 break; 1080 1110 } … … 1229 1259 /* When the table is full, drop the older entry (FIFO). Do proper ageing? */ 1230 1260 if (pCache->cEntries >= pCache->cEntriesAlloc) 1231 1261 { 1232 Log (("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n",1262 LogRel(("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n", 1233 1263 (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cbAddress, pCache->pbEntries)); 1234 1264 memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1)); 1235 1265 pCache->cEntries--; … … 1247 1277 switch (enmAddrType) 1248 1278 { 1249 1279 case kIntNetAddrType_IPv4: 1250 Log (("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",1280 LogRel(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n", 1251 1281 pIf->hIf, &pIf->MacAddr, pCache->cEntries, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg)); 1252 1282 break; 1283 case kIntNetAddrType_IPv6: 1284 LogRel(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv6 added #%d %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x %s\n", 1285 pIf->hIf, &pIf->MacAddr, pCache->cEntries, 1286 RT_BE2H_U16(pAddr->IPv6.Words.w0), 1287 RT_BE2H_U16(pAddr->IPv6.Words.w1), 1288 RT_BE2H_U16(pAddr->IPv6.Words.w2), 1289 RT_BE2H_U16(pAddr->IPv6.Words.w3), 1290 RT_BE2H_U16(pAddr->IPv6.Words.w4), 1291 RT_BE2H_U16(pAddr->IPv6.Words.w5), 1292 RT_BE2H_U16(pAddr->IPv6.Words.w6), 1293 RT_BE2H_U16(pAddr->IPv6.Words.w7), 1294 pszMsg 1295 )); 1296 break; 1253 1297 default: 1254 Log (("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs type=%d added #%d %.*Rhxs %s\n",1298 LogRel(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs type=%d added #%d %.*Rhxs %s\n", 1255 1299 pIf->hIf, &pIf->MacAddr, enmAddrType, pCache->cEntries, pCache->cbAddress, pAddr, pszMsg)); 1256 1300 break; 1257 1301 } … … 2251 2295 2252 2296 #ifdef INTNET_WITH_DHCP_SNOOPING 2253 2297 /** 2254 * Snoop up addresses from ARP and DHCP traffic from frames coming2298 * Snoop up addresses from ND, ARP and DHCP traffic from frames coming 2255 2299 * over the trunk connection. 2256 2300 * 2257 2301 * The caller is responsible for do some basic filtering before calling … … 2333 2377 break; 2334 2378 } 2335 2379 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 2380 case RTNET_ETHERTYPE_ARP: 2344 2381 intnetR0TrunkIfSnoopArp(pNetwork, pSG); 2345 2382 break; … … 2347 2384 } 2348 2385 #endif /* INTNET_WITH_DHCP_SNOOPING */ 2349 2386 2387 /** 2388 * Deals with an IPv6 packet. 2389 * 2390 * This will fish out the source IP address and add it to the cache. 2391 * Then it will look for DHCPRELEASE requests (?) and anything else 2392 * that we might find useful later. 2393 * 2394 * @param pIf The interface that's sending the frame. 2395 * @param pIpHdr Pointer to the IPv4 header in the frame. 2396 * @param cbPacket The size of the packet, or more correctly the 2397 * size of the frame without the ethernet header. 2398 * @param fGso Set if this is a GSO frame, clear if regular. 2399 */ 2400 static void intnetR0IfSnoopIPv6SourceAddr(PINTNETIF pIf, PCRTNETIPV6 pIpHdr, uint32_t cbPacket, bool fGso) 2401 { 2402 /* 2403 * Check the header size first to prevent access invalid data. 2404 */ 2405 if (cbPacket < RTNETIPV6_MIN_LEN) 2406 return; 2407 2408 /* 2409 * If the source address is good (not multicast) and 2410 * not already in the address cache of the sender, add it. 2411 */ 2412 RTNETADDRU Addr; 2413 Addr.IPv6 = pIpHdr->ip6_src; 2414 2415 if ( intnetR0IPv6AddrIsGood(Addr.IPv6) && (pIpHdr->ip6_hlim == 0xff) 2416 && intnetR0IfAddrCacheLookupLikely(&pIf->aAddrCache[kIntNetAddrType_IPv6], &Addr, sizeof(Addr.IPv6)) < 0) 2417 { 2418 intnetR0IfAddrCacheAddIt(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv6], &Addr, "if/ipv6"); 2419 } 2420 } 2421 2350 2422 2351 2423 /** 2352 2424 * Deals with an IPv4 packet. … … 2497 2569 case RTNET_ETHERTYPE_IPV4: 2498 2570 intnetR0IfSnoopIPv4SourceAddr(pIf, (PCRTNETIPV4)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso); 2499 2571 break; 2500 #if 0 /** @todo IntNet: implement IPv6 for wireless MAC sharing. */ 2572 2501 2573 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); 2574 intnetR0IfSnoopIPv6SourceAddr(pIf, (PCRTNETIPV6)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso); 2505 2575 break; 2506 #endif 2576 2507 2577 #if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */ 2508 2578 case RTNET_ETHERTYPE_IPX_1: 2509 2579 case RTNET_ETHERTYPE_IPX_2: … … 2685 2755 return !!(pThis->fHostGsoCapabilites & pThis->fWireGsoCapabilites & fMask); 2686 2756 } 2687 2757 2758 /** 2759 * Calculates the checksum of a full ipv6 frame. 2760 * 2761 * @returns 16-bit hecksum value. 2762 * @param pIpHdr The IPv6 header (network endian (big)). 2763 * @param bProtocol The protocol number. This can be the same as the 2764 * ip6_nxt field, but doesn't need to be. 2765 * @param cbPkt The packet size (host endian of course). This can 2766 * be the same as the ip6_plen field, but as with @a 2767 * bProtocol it won't be when extension headers are 2768 * present. For UDP this will be uh_ulen converted to 2769 * host endian. 2770 */ 2771 static uint16_t computeIPv6FullChecksum(PCRTNETIPV6 pIpHdr) 2772 { 2773 uint16_t const *data; 2774 int len = RT_BE2H_U16(pIpHdr->ip6_plen); 2775 uint32_t sum = RTNetIPv6PseudoChecksum(pIpHdr); 2776 2777 //add the payload 2778 data = (uint16_t *) (pIpHdr + 1); 2779 while(len > 1) 2780 { 2781 sum += *(data); 2782 data++; 2783 len -= 2; 2784 } 2785 2786 if(len > 0) 2787 sum += *((uint8_t *) data); 2788 2789 while(sum >> 16) 2790 sum = (sum & 0xffff) + (sum >> 16); 2791 2792 return (uint16_t) ~sum; 2793 } 2688 2794 2689 2795 /** 2690 2796 * Sends a frame down the trunk. … … 2765 2906 pArp->ar_tha = pThis->MacAddr; 2766 2907 } 2767 2908 } 2768 //else if (pSG->fFlags & INTNETSG_FLAGS_ICMPV6_NDP) 2769 //{ /// @todo move the editing into a different function 2770 //} 2909 else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6)) 2910 { 2911 /* 2912 * IPV6 ICMP Neighbor Discovery : replace 2913 * 1) the advertised source mac address in outgoing neighbor sollicitations 2914 * with the HW MAC address of the trunk interface, 2915 * 2) the advertised target mac address in outgoing neighbor advertisements 2916 * with the HW mac address of the trunk interface. 2917 * 2918 * Note that this only applies to traffic going out on the trunk. Incoming 2919 * NS/NA will never advertise any VM mac address, so we do not need to touch 2920 * them. Other VMs on this bridge as well as the host will see and use the VM's 2921 * actual mac addresses. 2922 * 2923 */ 2924 2925 PRTNETIPV6 pIPv6 = (PRTNETIPV6)(pEthHdr + 1); 2926 PRTNETNDP pNd = (PRTNETNDP)(pIPv6 + 1); 2927 PRTNETNDP_SLLA_OPT pLLAOpt = (PRTNETNDP_SLLA_OPT)(pNd + 1); 2928 2929 //make sure we have enough bytes to work with 2930 if(pSG->cbTotal >= (RTNETIPV6_MIN_LEN + RTNETIPV6_ICMPV6_ND_WITH_LLA_OPT_MIN_LEN) && 2931 //ensure the packet came from our LAN (not gone through any router) 2932 pIPv6->ip6_hlim == 0xff && 2933 //protocol has to be icmpv6 2934 pIPv6->ip6_nxt == RTNETIPV6_PROT_ICMPV6 && 2935 //we either have a sollicitation with source link layer addr. opt, or 2936 ((pNd->icmp6_type == RTNETIPV6_ICMP_NS_TYPE && 2937 pNd->icmp6_code == RTNETIPV6_ICMPV6_CODE_0 && 2938 pLLAOpt->type == RTNETIPV6_ICMP_ND_SLLA_OPT) || 2939 //an advertisement with target link layer addr. option 2940 ((pNd->icmp6_type == RTNETIPV6_ICMP_NA_TYPE && 2941 pNd->icmp6_code == RTNETIPV6_ICMPV6_CODE_0 && 2942 pLLAOpt->type == RTNETIPV6_ICMP_ND_TLLA_OPT)) ) && 2943 pLLAOpt->len == RTNETIPV6_ICMP_ND_LLA_LEN) 2944 { 2945 //swap the advertised VM MAC address with the trunk's 2946 pLLAOpt->slla = pThis->MacAddr; 2947 2948 //recompute the checksum since we changed the packet 2949 pNd->icmp6_cksum = 0; 2950 pNd->icmp6_cksum = computeIPv6FullChecksum(pIPv6); 2951 } 2952 2953 } 2771 2954 } 2772 2955 2773 2956 /* … … 2791 2974 2792 2975 2793 2976 /** 2977 * Snoops a multicast ICMPv6 ND DAD from the wire via the trunk connection. 2978 * 2979 * @param pNetwork The network the frame is being sent to. 2980 * @param pSG Pointer to the gather list for the frame. 2981 * @param pEthHdr Pointer to the ethernet header. 2982 */ 2983 static void intnetR0NetworkSnoopNAFromWire(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr) 2984 { 2985 /* 2986 * Check the minimum size and get a linear copy of the thing to work on, 2987 * using the temporary buffer if necessary. 2988 */ 2989 if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) + 2990 sizeof(RTNETNDP))) 2991 return; 2992 PRTNETIPV6 pIPv6 = (PRTNETIPV6)((uint8_t *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR)); 2993 if ( pSG->cSegsUsed != 1 2994 && pSG->aSegs[0].cb < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) + 2995 sizeof(RTNETNDP)) 2996 { 2997 Log6(("fw: Copying IPv6 pkt %u\n", sizeof(RTNETIPV6))); 2998 if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), sizeof(RTNETIPV6) 2999 + sizeof(RTNETNDP), pNetwork->pbTmp)) 3000 return; 3001 pSG->fFlags |= INTNETSG_FLAGS_PKT_CP_IN_TMP; 3002 pIPv6 = (PRTNETIPV6)pNetwork->pbTmp; 3003 } 3004 3005 PCRTNETNDP pNd = (PCRTNETNDP) (pIPv6 + 1); 3006 3007 //a multicast NS with :: as source address means a DAD packet. 3008 //if it comes from the wire and we have the DAD'd address in our cache, 3009 //flush the entry as the address is being acquired by someone else on 3010 //the network. 3011 if( pIPv6->ip6_hlim == 0xff && 3012 pIPv6->ip6_nxt == RTNETIPV6_PROT_ICMPV6 && 3013 pNd->icmp6_type == RTNETIPV6_ICMP_NS_TYPE && 3014 pNd->icmp6_code == RTNETIPV6_ICMPV6_CODE_0 && 3015 pIPv6->ip6_src.u == 0) 3016 { 3017 3018 intnetR0NetworkAddrCacheDelete(pNetwork, (PCRTNETADDRU) &pNd->target_address, 3019 kIntNetAddrType_IPv6, sizeof(RTNETADDRIPV6), "tif/ip6"); 3020 } 3021 } 3022 /** 2794 3023 * Edits an ARP packet arriving from the wire via the trunk connection. 2795 3024 * 2796 3025 * @param pNetwork The network the frame is being sent to. … … 3097 3326 return INTNETSWDECISION_BAD_CONTEXT; 3098 3327 3099 3328 /* 3329 * Check for ICMPv6 Neighbor Advertisements coming from the trunk. 3330 * If we see an advertisement for an IP in our cache, we can safely remove 3331 * it as the IP has probably moved. 3332 */ 3333 if ( (fSrc & INTNETTRUNKDIR_WIRE) 3334 && RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_IPV6 3335 && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID) 3336 intnetR0NetworkSnoopNAFromWire(pNetwork, pSG, pEthHdr); 3337 3338 3339 /* 3100 3340 * Check for ARP packets from the wire since we'll have to make 3101 3341 * modification to them if we're sharing the MAC address with the host. 3102 3342 */ … … 3174 3414 Log6(("intnetshareduni: IPv4 %d.%d.%d.%d\n", Addr.au8[0], Addr.au8[1], Addr.au8[2], Addr.au8[3])); 3175 3415 break; 3176 3416 3177 #if 0 /** @todo IntNet: implement IPv6 for wireless MAC sharing. */ 3178 case RTNET_ETHERTYPE_IPV6 3417 case RTNET_ETHERTYPE_IPV6: 3179 3418 if (RT_UNLIKELY(!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPV6, ip6_dst), sizeof(Addr.IPv6), &Addr))) 3180 3419 { 3181 3420 Log(("intnetshareduni: failed to read ip6_dst! cbTotal=%#x\n", pSG->cbTotal)); … … 3184 3423 enmAddrType = kIntNetAddrType_IPv6; 3185 3424 cbAddr = sizeof(Addr.IPv6); 3186 3425 break; 3187 #endif3188 3426 #if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */ 3189 3427 case RTNET_ETHERTYPE_IPX_1: 3190 3428 case RTNET_ETHERTYPE_IPX_2: … … 3379 3617 && !intnetR0IsMacAddrMulticast(&EthHdr.SrcMac) 3380 3618 )) 3381 3619 { 3382 Log 2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->MacAddr, &EthHdr.SrcMac));3620 LogRel(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->MacAddr, &EthHdr.SrcMac)); 3383 3621 RTSpinlockAcquire(pNetwork->hAddrSpinlock); 3384 3622 3385 3623 PINTNETMACTABENTRY pIfEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIfSender);