Changeset 10923 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Jul 29, 2008 12:22:11 AM (17 years ago)
- svn:sync-xref-src-repo-rev:
- 33769
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp
r10846 r10923 43 43 * Structures and Typedefs * 44 44 *******************************************************************************/ 45 typedef 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. */ 61 typedef INTNETADDRTYPE *PINTNETADDRTYPE; 62 63 /** 64 * IPv4 address. 65 */ 66 typedef RTUINT32U INTNETADDRIPV4; 67 /** Pointer to a IPv4 address. */ 68 typedef INTNETADDRIPV4 *PINTNETADDRIPV4; 69 /** Pointer to a const IPv4 address. */ 70 typedef INTNETADDRIPV4 const *PCINTNETADDRIPV4; 71 72 /** 73 * IPv6 address. 74 */ 75 typedef RTUINT128U INTNETADDRIPV6; 76 /** Pointer to a IPv4 address. */ 77 typedef INTNETADDRIPV6 *PINTNETADDRIPV6; 78 /** Pointer to a const IPv4 address. */ 79 typedef INTNETADDRIPV6 const *PCINTNETADDRIPV6; 80 81 /** 82 * IPX address. 83 */ 84 typedef 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. */ 92 typedef INTNETADDRIPX *PINTNETADDRIPX; 93 /** Pointer to a const IPX address. */ 94 typedef INTNETADDRIPX const *PCINTNETADDRIPX; 95 96 /** 97 * Address union. 98 */ 99 typedef 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. */ 117 typedef INTNETADDRU *PINTNETADDRU; 118 /** Pointer to a const address union. */ 119 typedef INTNETADDRU const *PCINTNETADDRU; 120 121 /** 122 * Address and type. 123 */ 124 typedef struct INTNETADDR 125 { 126 /** The address type. */ 127 INTNETADDRTYPE enmType; 128 /** The address. */ 129 INTNETADDRU Addr; 130 } INTNETADDR; 131 /** Pointer to an address. */ 132 typedef INTNETADDR *PINTNETADDR; 133 /** Pointer to a const address. */ 134 typedef INTNETADDR const *PCINTNETADDR; 135 136 137 /** 138 * Address cache for a specific network layer. 139 */ 140 typedef 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. */ 154 typedef INTNETADDRCACHE *PINTNETADDRCACHE; 155 /** Pointer to a const address cache. */ 156 typedef INTNETADDRCACHE const *PCINTNETADDRCACHE; 157 158 45 159 /** 46 160 * A network interface. … … 92 206 /** The SUPR0 object id. */ 93 207 void *pvObj; 208 /** The network layer address cache. (Indexed by type, 0 entry isn't used.) */ 209 INTNETADDRCACHE aAddrCache[kIntNetAddrType_End]; 94 210 } INTNETIF; 95 211 /** Pointer to an internal network interface. */ … … 177 293 178 294 295 /** 296 * Ethernet header. 297 */ 298 #pragma pack(1) 299 typedef struct INTNETETHERHDR 300 { 301 PDMMAC MacDst; 302 PDMMAC MacSrc; 303 uint16_t EtherType; 304 } INTNETETHERHDR; 305 #pragma pack() 306 /** Pointer to an ethernet header. */ 307 typedef INTNETETHERHDR *PINTNETETHERHDR; 308 /** Pointer to a const ethernet header. */ 309 typedef 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) 320 typedef 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; 343 typedef INTNETIPV4 *PINTNETIPV4; 344 typedef INTNETIPV4 const *PCINTNETIPV4; 345 346 347 typedef 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; 354 typedef INTNETUDPV4 *PINTNETUDPV4; 355 typedef INTNETUDPV4 const *PCINTNETUDPV4; 356 357 358 typedef 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; 380 typedef INTNETDHCP *PINTNETDHCP; 381 typedef 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 */ 408 typedef 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. */ 423 typedef INTNETARPHDR *PINTNETARPHDR; 424 /** Pointer to a const ethernet ARP header. */ 425 typedef INTNETARPHDR const *PCINTNETARPHDR; 426 427 428 #pragma pack(1) 429 /** 430 * Ethernet IPv4 + 6-byte MAC ARP request packet. 431 */ 432 typedef 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. */ 446 typedef INTNETARPIPV4 *PINTNETARPIPV4; 447 /** Pointer to a const ethernet IPv4+MAC ARP request packet. */ 448 typedef INTNETARPIPV4 const *PCINTNETARPIPV4; 449 450 451 #pragma pack(1) 452 /** 453 * Ethernet IPv6 + 6-byte MAC ARP request packet. 454 */ 455 typedef 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. */ 469 typedef INTNETARPIPV6 *PINTNETARPIPV6; 470 /** Pointer to a const ethernet IPv6+MAC ARP request packet. */ 471 typedef INTNETARPIPV6 const *PCINTNETARPIPV6; 472 473 179 474 /******************************************************************************* 180 475 * Internal Functions * … … 237 532 return intnetR0IfRetain(pIf, (PSUPDRVSESSION)pvCtx); 238 533 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 */ 543 DECLINLINE(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 */ 563 DECLINLINE(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 */ 591 static 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 */ 614 DECLINLINE(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. */ 642 DECLINLINE(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 */ 661 static 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 */ 688 DECLINLINE(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 */ 725 static 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 */ 746 DECLINLINE(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 */ 765 DECLINLINE(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 */ 788 DECLINLINE(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 */ 809 static 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 */ 863 static 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 */ 897 DECLINLINE(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 */ 942 static 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 */ 1000 static 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 */ 1076 static 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); 239 1101 } 240 1102 … … 437 1299 438 1300 /** 439 * Ethernet header.440 */441 #pragma pack(1)442 typedef struct INTNETETHERHDR443 {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 /**454 1301 * Sends a frame to a specific interface. 455 1302 * … … 471 1318 } 472 1319 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)); 474 1321 475 1322 #if 0 /* This is bad stuff now as we're blocking while locking down the network. … … 907 1754 { 908 1755 intnetR0SgInitTemp(&Sg, (void *)pvFrame, cbFrame); 909 intnetR0NetworkSend(p If->pNetwork, pIf, 0, &Sg, !!pTrunkIf);1756 intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf); 910 1757 } 911 1758 … … 922 1769 if (pvCurFrame) 923 1770 { 1771 if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE) 1772 intnetR0IfSniffSourceAddr(pIf, (uint8_t *)pvCurFrame, pHdr->cbFrame); 924 1773 intnetR0SgInitTemp(&Sg, pvCurFrame, pHdr->cbFrame); 925 intnetR0NetworkSend(p If->pNetwork, pIf, 0, &Sg, !!pTrunkIf);1774 intnetR0NetworkSend(pNetwork, pIf, 0, &Sg, !!pTrunkIf); 926 1775 } 927 1776 } … … 935 1784 * Release the semaphore(s) and release references. 936 1785 */ 937 rc = RTSemFastMutexRelease(p If->pNetwork->FastMutex);1786 rc = RTSemFastMutexRelease(pNetwork->FastMutex); 938 1787 if (pTrunkIf) 939 1788 { … … 1539 2388 PINTNETIF pIf = (PINTNETIF)pvUser1; 1540 2389 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)); 1542 2391 1543 2392 RTSemFastMutexRequest(pIntNet->FastMutex); … … 1557 2406 { 1558 2407 void *pvObj2 = RTHandleTableFreeWithCtx(pIntNet->hHtIfs, hIf, pIf->pSession); 1559 AssertMsg(pvObj2 == pIf, ("%p, %p, hIf=% #xpSession=%p\n", pvObj2, pIf, hIf, pIf->pSession));2408 AssertMsg(pvObj2 == pIf, ("%p, %p, hIf=%RX32 pSession=%p\n", pvObj2, pIf, hIf, pIf->pSession)); 1560 2409 } 1561 2410 … … 1759 2608 { 1760 2609 *phIf = pIf->hIf; 1761 Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=% pcbSend=%u cbRecv=%u cbBuf=%u\n",2610 Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%RX32 cbSend=%u cbRecv=%u cbBuf=%u\n", 1762 2611 *phIf, pIf->pIntBufDefault->cbSend, pIf->pIntBufDefault->cbRecv, pIf->pIntBufDefault->cbBuf)); 1763 2612 return VINF_SUCCESS;
Note:
See TracChangeset
for help on using the changeset viewer.