Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4435 lines
146 KiB

  1. /*++
  2. Copyright(c) 2000 Microsoft Corporation
  3. Module Name:
  4. brdgcomp.c
  5. Abstract:
  6. Ethernet MAC level bridge.
  7. Compatibility-Mode section
  8. Author:
  9. Mark Aiken
  10. Environment:
  11. Kernel mode driver
  12. Revision History:
  13. September 2000 - Original version
  14. Notes
  15. Currently, this code only works with traditional Ethernet framing (dest, src, ethertype).
  16. Much of the code would need to be changed to support IEEE 802.3-style framing
  17. (dest, src, size, LLC DSAP, LLC SSAP, LLC type).
  18. --*/
  19. #define NDIS_MINIPORT_DRIVER
  20. #define NDIS50_MINIPORT 1
  21. #define NDIS_WDM 1
  22. #pragma warning( push, 3 )
  23. #include <ndis.h>
  24. // TCPIP.SYS structure definitions
  25. #include <ipinfo.h>
  26. #include <tdiinfo.h>
  27. #include <ntddtcp.h>
  28. #include <ntddip.h>
  29. #pragma warning( pop )
  30. #include "bridge.h"
  31. #include "brdgcomp.h"
  32. #include "brdgfwd.h"
  33. #include "brdgbuf.h"
  34. // ===========================================================================
  35. //
  36. // TYPES
  37. //
  38. // ===========================================================================
  39. // An IPv4 address
  40. typedef UINT32 IPADDRESS;
  41. typedef PUINT32 PIPADDRESS;
  42. // Types of ARP packets
  43. typedef enum
  44. {
  45. ArpRequest,
  46. ArpReply
  47. } ARP_TYPE;
  48. // ===========================================================================
  49. //
  50. // CONSTANTS
  51. //
  52. // ===========================================================================
  53. // Size of the payload of an IPv4 ARP packet
  54. #define SIZE_OF_ARP_DATA 28 // bytes
  55. // Total size of an IPv4 ARP packet, including framing
  56. #define SIZE_OF_ARP_PACKET (SIZE_OF_ARP_DATA + ETHERNET_HEADER_SIZE)
  57. // Size of a basic IPv4 header, not including options
  58. #define SIZE_OF_BASIC_IP_HEADER 20 // bytes
  59. // Minimum amount of frame data we need to parse the IP header
  60. #define MINIMUM_SIZE_FOR_IP (ETHERNET_HEADER_SIZE + SIZE_OF_BASIC_IP_HEADER)
  61. // Size of a basic UDP header
  62. #define SIZE_OF_UDP_HEADER 8 // bytes
  63. // Minimum size of the payload of a BOOTP packet
  64. #define SIZE_OF_BASIC_BOOTP_PACKET 236 // bytes
  65. // The IP Ethertype
  66. const USHORT IP_ETHERTYPE = 0x0800;
  67. // The ARP Ethertype
  68. const USHORT ARP_ETHERTYPE = 0x0806;
  69. // The UDP IP protocol type
  70. const UCHAR UDP_PROTOCOL = 0x11;
  71. // Number of hash buckets in the IP and pending-ARP tables. This must
  72. // be a power of 2 for our hash function to work propery.
  73. #define NUM_HASH_BUCKETS 256
  74. // Number of hash buckets for the pending-DHCP table. This
  75. // must be a power of 2 for our hash function to work properly.
  76. #define NUM_DHCP_HASH_BUCKETS 32
  77. // The "shift factor" for our IP next-hop cache. The number of entries
  78. // in the cache is 2 ^ (this number)
  79. #define HOP_CACHE_SHIFT_FACTOR 8 // 256 cache entries
  80. // Default size cap for the IP forwarding table
  81. #define DEFAULT_MAX_IP_TABLE_SIZE (500 * 1024) // 500K in bytes
  82. // Name of the registry parameter that optionally specifies the max table size
  83. const PWCHAR gMaxIPTableSizeParameterName = L"MaxIPTableSize";
  84. // Default size cap for the pending-ARP table
  85. #define DEFAULT_MAX_ARP_TABLE_SIZE (100 * 1024) // 100K in bytes
  86. // Name of the registry parameter that optionally specifies the max table size
  87. const PWCHAR gMaxARPTableSizeParameterName = L"MaxARPTableSize";
  88. // Default size cap for the pending-DHCP table
  89. #define DEFAULT_MAX_DHCP_TABLE_SIZE (50 * 1024) // 50K in bytes
  90. // Name of the registry parameter that optionally specifies the max table size
  91. const PWCHAR gMaxDHCPTableSizeParameterName = L"MaxDHCPTableSize";
  92. //
  93. // Timeout length for IP forwarding table entries
  94. //
  95. // This should be somewhat longer than the time it takes hosts to age out
  96. // their ARP table entries, since we learn the location of IP hosts
  97. // by ARP traffic. Current Windows implementations age out their
  98. // ARP table entries after 2 minutes if there has been no traffic from
  99. // the station corresponding to the entry.
  100. //
  101. // We keep our forwarding table entries alive indefinitely as long as we
  102. // continue to see IP traffic from the hosts we have information about.
  103. // Windows implementations will age out their ARP entries under those
  104. // conditions after 20mins or so.
  105. //
  106. #define MAX_IP_ENTRY_AGE (5 * 60 * 1000) // 5 minutes in ms
  107. //
  108. // Timeout length for pending-ARP table entries
  109. //
  110. // This should be somewhat longer than the maximum time hosts will wait to
  111. // hear the results of an ARP discovery before timing out. Windows boxes
  112. // have a giveup time of 1s.
  113. //
  114. // Note that it is not destructive to deliver ARP reply packets to a station
  115. // after it has given up or even after its initial discovery was
  116. // satisfied.
  117. //
  118. #define MAX_ARP_ENTRY_AGE (10 * 1000) // 10 seconds
  119. //
  120. // Timeout length for pending-DHCP table entries
  121. //
  122. // RFC 2131 mentions that clients may wait as long as 60 seconds for an
  123. // ACK. Have the timeout be somewhat longer than even that.
  124. //
  125. #define MAX_DHCP_ENTRY_AGE (90 * 1000) // 1 1/2 minutes
  126. // ===========================================================================
  127. //
  128. // DECLARATIONS
  129. //
  130. // ===========================================================================
  131. // Structure to express the information carried in ARP packets
  132. typedef struct _ARPINFO
  133. {
  134. ARP_TYPE type;
  135. IPADDRESS ipSource, ipTarget;
  136. UCHAR macSource[ETH_LENGTH_OF_ADDRESS];
  137. UCHAR macTarget[ETH_LENGTH_OF_ADDRESS];
  138. } ARPINFO, *PARPINFO;
  139. // Structure to express the information carried in an IP header
  140. typedef struct _IP_HEADER_INFO
  141. {
  142. UCHAR protocol;
  143. IPADDRESS ipSource, ipTarget;
  144. USHORT headerSize;
  145. } IP_HEADER_INFO, *PIP_HEADER_INFO;
  146. // Structure of our IP forwarding hash table entries
  147. typedef struct _IP_TABLE_ENTRY
  148. {
  149. HASH_TABLE_ENTRY hte; // Required for hash table use
  150. // Protects the following fields
  151. NDIS_SPIN_LOCK lock;
  152. PADAPT pAdapt;
  153. UCHAR macAddr[ETH_LENGTH_OF_ADDRESS];
  154. } IP_TABLE_ENTRY, *PIP_TABLE_ENTRY;
  155. //
  156. // Structure of the pending-ARP table keys. We want this to get
  157. // packet into 8 bytes.
  158. //
  159. typedef struct _ARP_TABLE_KEY
  160. {
  161. IPADDRESS ipTarget;
  162. IPADDRESS ipReqestor;
  163. } ARP_TABLE_KEY, *PARP_TABLE_KEY;
  164. // Structure of our pending-ARP hash table entries
  165. typedef struct _ARP_TABLE_ENTRY
  166. {
  167. HASH_TABLE_ENTRY hte; // Required for hash table use
  168. // Protects the following fields
  169. NDIS_SPIN_LOCK lock;
  170. // Information on the station that was trying to discover this host
  171. // The discovering station's IP address is part of the entry key.
  172. PADAPT pOriginalAdapt;
  173. UCHAR originalMAC[ETH_LENGTH_OF_ADDRESS];
  174. } ARP_TABLE_ENTRY, *PARP_TABLE_ENTRY;
  175. // Structure of our DHCP-relay table entries
  176. typedef struct _DHCP_TABLE_ENTRY
  177. {
  178. HASH_TABLE_ENTRY hte; // Required for hash table use
  179. // Protects the following fields
  180. NDIS_SPIN_LOCK lock;
  181. UCHAR requestorMAC[ETH_LENGTH_OF_ADDRESS];
  182. PADAPT pRequestorAdapt;
  183. } DHCP_TABLE_ENTRY, *PDHCP_TABLE_ENTRY;
  184. // Structure for deferring an ARP packet transmission
  185. typedef struct _DEFERRED_ARP
  186. {
  187. ARPINFO ai;
  188. PADAPT pTargetAdapt;
  189. } DEFERRED_ARP, *PDEFERRED_ARP;
  190. // Per-adapter rewriting function
  191. typedef VOID (*PPER_ADAPT_EDIT_FUNC)(PUCHAR, PADAPT, PVOID);
  192. // ===========================================================================
  193. //
  194. // GLOBALS
  195. //
  196. // ===========================================================================
  197. //
  198. // Whether or not there are *any* compatibility-mode adapters in our list
  199. // at the moment. Is updated in the protocol module with a write lock
  200. // held on the global adapter list
  201. //
  202. BOOLEAN gCompatAdaptersExist = FALSE;
  203. //
  204. // Our list of the bridge machine's IP addresses (passed down through an
  205. // OID). The list is allocated on the heap and is protected by
  206. // gLocalIPAddressLock.
  207. //
  208. PIPADDRESS gLocalIPAddressList = NULL;
  209. ULONG gLocalIPAddressListLength = 0L;
  210. NDIS_RW_LOCK gLocalIPAddressListLock;
  211. //
  212. // The IP address-based forwarding table
  213. //
  214. PHASH_TABLE gIPForwardingTable;
  215. //
  216. // Our table to hold pending ARP requests so we can proxy back replies
  217. //
  218. PHASH_TABLE gPendingARPTable;
  219. //
  220. // Our table to hold pending DHCP requests so we can translate DHCP packets
  221. // appropriately (the MAC address of the requesting station is carried
  222. // in a DHCP request and has to be edited when we relay it)
  223. //
  224. PHASH_TABLE gPendingDHCPTable;
  225. //
  226. // A cache of IP next-hop information to avoid hammering the IP drivers's
  227. // route table
  228. //
  229. CACHE gNextHopCache;
  230. // Special IP address indicating a negative cache entry (we tried previously
  231. // and got no answer)
  232. const IPADDRESS NO_ADDRESS = 0xFFFFFFFF;
  233. // Whether we have an overall MAC address for the bridge miniport yet
  234. BOOLEAN gCompHaveMACAddress = FALSE;
  235. // Our overall MAC address (cached here instead of calling the miniport
  236. // section all the time to increase perf)
  237. UCHAR gCompMACAddress[ETH_LENGTH_OF_ADDRESS];
  238. // Pointers and handles for interacting with TCP
  239. HANDLE gTCPFileHandle = NULL;
  240. PFILE_OBJECT gTCPFileObject = NULL;
  241. PDEVICE_OBJECT gTCPDeviceObject = NULL;
  242. // Pointers and handles for interacting with IP
  243. HANDLE gIPFileHandle = NULL;
  244. PFILE_OBJECT gIPFileObject = NULL;
  245. PDEVICE_OBJECT gIPDeviceObject = NULL;
  246. // Lock to protect the references above
  247. NDIS_SPIN_LOCK gTCPIPLock;
  248. // IRP posted to TCPIP for notifications of when the route table changes.
  249. // Manipulated with InterlockedExchange.
  250. PIRP gIPRouteChangeIRP = NULL;
  251. // Refcount to allow us to block and wait when people are using the TCP
  252. // driver
  253. WAIT_REFCOUNT gTCPIPRefcount;
  254. // ===========================================================================
  255. //
  256. // PRIVATE PROTOTYPES
  257. //
  258. // ===========================================================================
  259. BOOLEAN
  260. BrdgCompDecodeARPPacket(
  261. IN PUCHAR pPacketData,
  262. IN UINT dataLen,
  263. OUT PARPINFO pARPInfo
  264. );
  265. VOID
  266. BrdgCompTransmitARPPacket(
  267. IN PADAPT pAdapt,
  268. IN PARPINFO pARPInfo
  269. );
  270. BOOLEAN
  271. BrdgCompDecodeIPHeader(
  272. IN PUCHAR pHeader,
  273. OUT PIP_HEADER_INFO piphi
  274. );
  275. BOOLEAN
  276. BrdgCompProcessOutboundARPPacket(
  277. IN PNDIS_PACKET pPacket,
  278. IN PUCHAR pPacketData,
  279. IN UINT packetLen,
  280. IN PADAPT pTargetAdapt
  281. );
  282. BOOLEAN
  283. BrdgCompProcessOutboundNonARPPacket(
  284. IN PNDIS_PACKET pPacket,
  285. IN PUCHAR pPacketData,
  286. IN UINT packetLen,
  287. IN PADAPT pTargetAdapt
  288. );
  289. BOOLEAN
  290. BrdgCompProcessInboundARPPacket(
  291. IN PNDIS_PACKET pPacket,
  292. IN PADAPT pAdapt,
  293. IN BOOLEAN bCanRetain,
  294. IN PUCHAR pPacketData,
  295. IN UINT packetLen
  296. );
  297. BOOLEAN
  298. BrdgCompProcessInboundNonARPPacket(
  299. IN PNDIS_PACKET pPacket,
  300. IN PADAPT pAdapt,
  301. IN BOOLEAN bCanRetain,
  302. IN PUCHAR pPacketData,
  303. IN UINT packetLen
  304. );
  305. VOID
  306. BrdgCompTransmitDeferredARP(
  307. IN PVOID pData
  308. );
  309. BOOLEAN
  310. BrdgCompProcessInboundBootPPacket(
  311. IN PNDIS_PACKET pPacket,
  312. IN PADAPT pAdapt,
  313. IN BOOLEAN bCanRetain,
  314. IN PUCHAR pPacketData,
  315. IN UINT packetLen,
  316. IN PIP_HEADER_INFO piphi,
  317. IN PUCHAR pBootPData
  318. );
  319. BOOLEAN
  320. BrdgCompProcessOutboundBootPPacket(
  321. IN PNDIS_PACKET pPacket,
  322. IN PUCHAR pPacketData,
  323. IN UINT packetLen,
  324. IN PADAPT pTargetAdapt,
  325. IN PUCHAR pBootPData,
  326. IN PIP_HEADER_INFO piphi
  327. );
  328. BOOLEAN
  329. BrdgCompIsUnicastIPAddress(
  330. IN IPADDRESS ip
  331. );
  332. VOID
  333. BrdgCompAttachToTCPIP(
  334. IN PVOID ignored
  335. );
  336. VOID
  337. BrdgCompDetachFromTCPIP(
  338. IN PVOID ignored
  339. );
  340. BOOLEAN
  341. BrdgCompIsLocalIPAddress(
  342. IN IPADDRESS ipAddr
  343. );
  344. // ===========================================================================
  345. //
  346. // INLINES / MACROS
  347. //
  348. // ===========================================================================
  349. //
  350. // This retrieves the Ethertype of an Ethernet frame from a pointer
  351. // to its header.
  352. //
  353. __forceinline
  354. USHORT
  355. BrdgCompGetEtherType(
  356. IN PUCHAR pEtherHeader
  357. )
  358. {
  359. USHORT retVal;
  360. // The two bytes immediately following the source and destination addresses
  361. // encode the Ethertype, most significant byte first.
  362. retVal = 0L;
  363. retVal |= (pEtherHeader[2 * ETH_LENGTH_OF_ADDRESS]) << 8;
  364. retVal |= pEtherHeader[2 * ETH_LENGTH_OF_ADDRESS + 1];
  365. return retVal;
  366. }
  367. //
  368. // Transmits a packet on an adapter after rewriting the source MAC address
  369. // to be the adapter's own MAC address.
  370. //
  371. // The caller relinquishes ownership of the packet with this call.
  372. //
  373. __forceinline
  374. VOID
  375. BrdgCompSendPacket(
  376. IN PNDIS_PACKET pPacket,
  377. IN PUCHAR pPacketData,
  378. IN PADAPT pAdapt
  379. )
  380. {
  381. // Rewrite the source MAC address to be our address
  382. ETH_COPY_NETWORK_ADDRESS(pPacketData + ETH_LENGTH_OF_ADDRESS, pAdapt->MACAddr);
  383. BrdgFwdSendPacketForCompat(pPacket, pAdapt);
  384. }
  385. //
  386. // Transmits a packet, dealing with an optional editing function if one is
  387. // present
  388. //
  389. __forceinline
  390. VOID
  391. BrdgCompEditAndSendPacket(
  392. IN PNDIS_PACKET pPacket,
  393. IN PUCHAR pPacketData,
  394. IN PADAPT pAdapt,
  395. IN PPER_ADAPT_EDIT_FUNC pFunc,
  396. IN PVOID pData
  397. )
  398. {
  399. if( pFunc != NULL )
  400. {
  401. (*pFunc)(pPacketData, pAdapt, pData);
  402. }
  403. BrdgCompSendPacket( pPacket, pPacketData, pAdapt );
  404. }
  405. //
  406. // Transmits a packet, dealing with the possibility that we are not allowed to
  407. // retain the packet and setting the destination MAC address to a specified
  408. // value
  409. //
  410. // Returns whether the input packet was retained
  411. //
  412. __inline
  413. BOOLEAN
  414. BrdgCompEditAndSendPacketOrPacketCopy(
  415. IN PNDIS_PACKET pPacket,
  416. IN PUCHAR pPacketData,
  417. IN BOOLEAN bCanRetain,
  418. IN PUCHAR pDestMAC,
  419. IN PADAPT pAdapt,
  420. IN PPER_ADAPT_EDIT_FUNC pFunc,
  421. IN PVOID pData
  422. )
  423. {
  424. UINT dataLen;
  425. SAFEASSERT( (pPacket != NULL) && (pPacketData != NULL) );
  426. if( !bCanRetain )
  427. {
  428. // We aren't allowed to use the original packet. Make a copy.
  429. pPacket = BrdgFwdMakeCompatCopyPacket(pPacket, &pPacketData, &dataLen, FALSE);
  430. }
  431. if( (pPacket != NULL) && (pPacketData != NULL) )
  432. {
  433. // Poke the destination MAC address
  434. ETH_COPY_NETWORK_ADDRESS(pPacketData, pDestMAC);
  435. BrdgCompEditAndSendPacket(pPacket, pPacketData, pAdapt, pFunc, pData);
  436. }
  437. // If we were allowed to retain the packet, we did.
  438. return bCanRetain;
  439. }
  440. //
  441. // Indicates a packet to the local machine. If the target MAC address was previously
  442. // the adapter's hardware MAC address, it is rewritten to the bridge adapter's
  443. // overall MAC address.
  444. //
  445. // The caller relinquishes ownership of the packet with this call.
  446. //
  447. __inline
  448. VOID
  449. BrdgCompIndicatePacket(
  450. IN PNDIS_PACKET pPacket,
  451. IN PUCHAR pPacketData,
  452. IN PADAPT pAdapt // Receiving adapter
  453. )
  454. {
  455. // No packet indications can occur until we have a MAC address
  456. if( gCompHaveMACAddress )
  457. {
  458. UINT Result;
  459. // See if this frame was targeted at this adapter's MAC address.
  460. ETH_COMPARE_NETWORK_ADDRESSES_EQ(pPacketData, pAdapt->MACAddr, &Result);
  461. if( Result == 0 )
  462. {
  463. ETH_COPY_NETWORK_ADDRESS( pPacketData, gCompMACAddress );
  464. }
  465. else
  466. {
  467. // We expect to only be indicating frames unicast to this machine
  468. // or sent to bcast / multicast hardware addresses.
  469. SAFEASSERT( ETH_IS_BROADCAST(pPacketData) || ETH_IS_MULTICAST(pPacketData) );
  470. }
  471. BrdgFwdIndicatePacketForCompat( pPacket );
  472. }
  473. }
  474. //
  475. // Indicates a packet to the local machine, making a copy of the packet if
  476. // necessary.
  477. //
  478. __inline
  479. BOOLEAN
  480. BrdgCompIndicatePacketOrPacketCopy(
  481. IN PNDIS_PACKET pPacket,
  482. IN PUCHAR pPacketData,
  483. IN BOOLEAN bCanRetain,
  484. IN PADAPT pAdapt,
  485. IN PPER_ADAPT_EDIT_FUNC pEditFunc,
  486. IN PVOID pData
  487. )
  488. {
  489. if( bCanRetain )
  490. {
  491. if( pEditFunc != NULL )
  492. {
  493. (*pEditFunc)(pPacketData, LOCAL_MINIPORT, pData);
  494. }
  495. BrdgCompIndicatePacket( pPacket, pPacketData, pAdapt );
  496. }
  497. else
  498. {
  499. UINT packetLen;
  500. // Make our own copy of the packet for indication
  501. pPacket = BrdgFwdMakeCompatCopyPacket( pPacket, &pPacketData, &packetLen, FALSE );
  502. if( pPacket != NULL )
  503. {
  504. if( pEditFunc != NULL )
  505. {
  506. (*pEditFunc)(pPacketData, LOCAL_MINIPORT, pData);
  507. }
  508. BrdgCompIndicatePacket( pPacket, pPacketData, pAdapt );
  509. }
  510. else
  511. {
  512. DBGPRINT(COMPAT, ("Failed to acquire a packet for indication in BrdgCompIndicatePacketOrPacketCopy\n"));
  513. }
  514. }
  515. // If we were allowed to retain the packet, we did.
  516. return bCanRetain;
  517. }
  518. //
  519. // The IP and UDP checksums treat the data they are checksumming as a
  520. // sequence of 16-bit words. The checksum is carried as the bitwise
  521. // inverse of the actual checksum (~C). The formula for calculating
  522. // the new checksum as transmitted, ~C', given that a 16-bit word of
  523. // the checksummed data has changed from w to w' is
  524. //
  525. // ~C' = ~C + w + ~w' (addition in ones-complement)
  526. //
  527. // This function returns the updated checksum given the original checksum
  528. // and the original and new values of a word in the checksummed data.
  529. //
  530. __forceinline
  531. USHORT
  532. BrdgCompRecalcChecksum(
  533. IN USHORT oldChecksum,
  534. IN USHORT oldWord,
  535. IN USHORT newWord
  536. )
  537. {
  538. ULONG sum;
  539. sum = oldChecksum + oldWord + ((~(newWord)) & 0xFFFF);
  540. return (USHORT)((sum & 0xFFFF) + (sum >> 16));
  541. }
  542. //
  543. // Rewrites a BootP packet so the client MAC address in the packet payload
  544. // is the given new MAC address
  545. //
  546. __inline
  547. BrdgCompRewriteBootPClientAddress(
  548. IN PUCHAR pPacketData,
  549. IN PIP_HEADER_INFO piphi,
  550. IN PUCHAR newMAC
  551. )
  552. {
  553. USHORT checkSum;
  554. PUCHAR pBootPData, pCheckSum, pDestMAC, pSrcMAC;
  555. UINT i;
  556. // The BOOTP packet lives right after the UDP header
  557. pBootPData = pPacketData + ETHERNET_HEADER_SIZE + piphi->headerSize + SIZE_OF_UDP_HEADER;
  558. // The checksum lives at offset 7 in the UDP packet.
  559. pCheckSum = pPacketData + ETHERNET_HEADER_SIZE + piphi->headerSize + 6;
  560. checkSum = 0;
  561. checkSum = pCheckSum[0] << 8;
  562. checkSum |= pCheckSum[1];
  563. // Replace the client's hardware address, updating the checksum as we go.
  564. // The client's hardware address lives at offset 29 in the BOOTP packet
  565. pSrcMAC = newMAC;
  566. pDestMAC = &pBootPData[28];
  567. for( i = 0 ; i < ETH_LENGTH_OF_ADDRESS / 2; i++ )
  568. {
  569. checkSum = BrdgCompRecalcChecksum( checkSum,
  570. (USHORT)(pDestMAC[0] << 8 | pDestMAC[1]),
  571. (USHORT)(pSrcMAC[0] << 8 | pSrcMAC[1]) );
  572. pDestMAC[0] = pSrcMAC[0];
  573. pDestMAC[1] = pSrcMAC[1];
  574. pDestMAC += 2;
  575. pSrcMAC += 2;
  576. }
  577. // Write the new checksum back out
  578. pCheckSum[0] = (UCHAR)(checkSum >> 8);
  579. pCheckSum[1] = (UCHAR)(checkSum & 0xFF);
  580. }
  581. //
  582. // Rewrites an oubound ARP packet so the source MAC address carried in the payload
  583. // matches the MAC address of the outbound adapter
  584. //
  585. VOID
  586. BrdgCompRewriteOutboundARPPacket(
  587. IN PUCHAR pPacketData,
  588. IN PADAPT pAdapt,
  589. IN PVOID ignored
  590. )
  591. {
  592. //
  593. // Rewrite the source MAC address so it is the MAC address of the adapter the
  594. // request is going out on.
  595. //
  596. pPacketData[22] = pAdapt->MACAddr[0];
  597. pPacketData[23] = pAdapt->MACAddr[1];
  598. pPacketData[24] = pAdapt->MACAddr[2];
  599. pPacketData[25] = pAdapt->MACAddr[3];
  600. pPacketData[26] = pAdapt->MACAddr[4];
  601. pPacketData[27] = pAdapt->MACAddr[5];
  602. // Leave the rewriting of the MAC address in the actual Ethernet header to
  603. // BrdgCompSendPacket(), which always overwrites the source MAC address
  604. // with the adapter's MAC address.
  605. }
  606. //
  607. // Provides a PDEVICE_OBJECT and a PFILE_OBJECT that can be used to talk to
  608. // TCPIP.SYS. Returns TRUE if a channel is open and the pointers can be used,
  609. // FALSE otherwise.
  610. //
  611. __inline
  612. BOOLEAN
  613. BrdgCompAcquireTCPIP(
  614. OUT PDEVICE_OBJECT OPTIONAL *pTCPpdo,
  615. OUT PFILE_OBJECT OPTIONAL *pTCPpfo,
  616. OUT PDEVICE_OBJECT OPTIONAL *pIPpdo,
  617. OUT PFILE_OBJECT OPTIONAL *pIPpfo
  618. )
  619. {
  620. BOOLEAN rc = FALSE;
  621. if( BrdgIncrementWaitRef(&gTCPIPRefcount) )
  622. {
  623. NdisAcquireSpinLock( &gTCPIPLock );
  624. SAFEASSERT( gTCPDeviceObject != NULL );
  625. SAFEASSERT( gTCPFileHandle != NULL );
  626. SAFEASSERT( gTCPFileObject != NULL );
  627. SAFEASSERT( gIPFileHandle != NULL );
  628. SAFEASSERT( gIPDeviceObject != NULL );
  629. SAFEASSERT( gIPFileObject != NULL );
  630. if( pTCPpdo != NULL )
  631. {
  632. *pTCPpdo = gTCPDeviceObject;
  633. }
  634. if( pTCPpfo != NULL )
  635. {
  636. *pTCPpfo = gTCPFileObject;
  637. }
  638. if( pIPpdo != NULL )
  639. {
  640. *pIPpdo = gIPDeviceObject;
  641. }
  642. if( pIPpfo != NULL )
  643. {
  644. *pIPpfo = gIPFileObject;
  645. }
  646. rc = TRUE;
  647. NdisReleaseSpinLock( &gTCPIPLock );
  648. }
  649. return rc;
  650. }
  651. //
  652. // Releases the refcount on our connection to the TCPIP driver after a
  653. // previous call to BrdgCompAcquireTCPIP().
  654. //
  655. __inline
  656. VOID
  657. BrdgCompReleaseTCPIP()
  658. {
  659. BrdgDecrementWaitRef( &gTCPIPRefcount );
  660. }
  661. // ====================================================================
  662. //
  663. // These small helper functions would be inline except we need to pass
  664. // pointers to them
  665. //
  666. // ====================================================================
  667. //
  668. // Rewrites a BootP packet for a particular adapter
  669. //
  670. VOID
  671. BrdgCompRewriteBootPPacketForAdapt(
  672. IN PUCHAR pPacketData,
  673. IN PADAPT pAdapt,
  674. IN PVOID pData
  675. )
  676. {
  677. PIP_HEADER_INFO piphi = (PIP_HEADER_INFO)pData;
  678. //
  679. // pAdapt can be LOCAL_MINIPORT if we're being used to edit a packet
  680. // for indication to the local machine. No rewriting is necessary
  681. // in that case.
  682. //
  683. if( pAdapt != LOCAL_MINIPORT )
  684. {
  685. SAFEASSERT( pAdapt != NULL );
  686. BrdgCompRewriteBootPClientAddress( pPacketData, piphi, pAdapt->MACAddr );
  687. }
  688. }
  689. //
  690. // Hashes an IP address. Used for the IP forwarding table as well as
  691. // the pending-ARP table, which uses an extended key made up of
  692. // the target IP address and the requesting station's IP address
  693. //
  694. ULONG
  695. BrdgCompHashIPAddress(
  696. IN PUCHAR pKey
  697. )
  698. {
  699. // Our hash function consists of taking the lower portion of the IP
  700. // address. The number of hash buckets has to be a power of 2 for
  701. // this to work propery.
  702. return (*(PULONG)pKey) & (NUM_HASH_BUCKETS - 1);
  703. }
  704. //
  705. // Hashes a DHCP transaction id
  706. //
  707. ULONG
  708. BrdgCompHashXID(
  709. IN PUCHAR pXid
  710. )
  711. {
  712. // Our hash function consists of taking the lower portion of the
  713. // XID. The number of hash buckets has to be a power of 2 for
  714. // this to work propery.
  715. return (*(PULONG)pXid) & (NUM_DHCP_HASH_BUCKETS - 1);
  716. }
  717. //
  718. // Returns true if the given IP table entry refers to a certain
  719. // adapter
  720. BOOLEAN
  721. BrdgCompIPEntriesMatchAdapter(
  722. IN PHASH_TABLE_ENTRY phte,
  723. IN PVOID pData
  724. )
  725. {
  726. PADAPT pAdapt = (PADAPT)pData;
  727. PIP_TABLE_ENTRY pipte = (PIP_TABLE_ENTRY)phte;
  728. // Don't take the spin lock since we're doing a single read,
  729. // which we ASSUME to be atomic.
  730. return (BOOLEAN)(pipte->pAdapt == pAdapt);
  731. }
  732. //
  733. // Returns true if the given ARP table entry refers to a certain
  734. // adapter
  735. //
  736. BOOLEAN
  737. BrdgCompARPEntriesMatchAdapter(
  738. IN PHASH_TABLE_ENTRY phte,
  739. IN PVOID pData
  740. )
  741. {
  742. PADAPT pAdapt = (PADAPT)pData;
  743. PARP_TABLE_ENTRY pate = (PARP_TABLE_ENTRY)phte;
  744. // Don't take the spin lock since we're doing a single read,
  745. // which we ASSUME to be atomic.
  746. return (BOOLEAN)(pate->pOriginalAdapt == pAdapt);
  747. }
  748. //
  749. // Returns true if the given DHCP table entry refers to a certain
  750. // adapter
  751. //
  752. BOOLEAN
  753. BrdgCompDHCPEntriesMatchAdapter(
  754. IN PHASH_TABLE_ENTRY phte,
  755. IN PVOID pData
  756. )
  757. {
  758. PADAPT pAdapt = (PADAPT)pData;
  759. PDHCP_TABLE_ENTRY pdhcpte = (PDHCP_TABLE_ENTRY)phte;
  760. // Don't take the spin lock since we're doing a single read,
  761. // which we ASSUME to be atomic.
  762. return (BOOLEAN)(pdhcpte->pRequestorAdapt == pAdapt);
  763. }
  764. //
  765. // Completion function for route lookup IRPs. Returns
  766. // STATUS_MORE_PROCESSING_REQUIRED to prevent the IO manager
  767. // from mucking with the IRP (which we free ourselves).
  768. //
  769. NTSTATUS
  770. BrdgCompCompleteRouteLookupIRP(
  771. IN PDEVICE_OBJECT DeviceObject,
  772. IN PIRP pirp,
  773. IN PVOID ignored
  774. )
  775. {
  776. IoFreeIrp( pirp );
  777. return STATUS_MORE_PROCESSING_REQUIRED;
  778. }
  779. // ===========================================================================
  780. //
  781. // PUBLIC FUNCTIONS
  782. //
  783. // ===========================================================================
  784. NTSTATUS
  785. BrdgCompDriverInit()
  786. /*++
  787. Routine Description:
  788. Driver-initialization function for the compatibility module
  789. Arguments:
  790. None
  791. Return Value:
  792. Status. Anything other than STATUS_SUCCESS aborts the driver load.
  793. --*/
  794. {
  795. ULONG MaxSize, MaxEntries;
  796. // Initialize the next-hop cache
  797. if( BrdgInitializeCache(&gNextHopCache, HOP_CACHE_SHIFT_FACTOR) != NDIS_STATUS_SUCCESS )
  798. {
  799. DBGPRINT(COMPAT, ("FAILED TO ALLOCATE NEXT-HOPE CACHE!\n"));
  800. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_INIT_MALLOC_FAILED, 0L, 0L, NULL, 0L, NULL );
  801. return STATUS_INSUFFICIENT_RESOURCES;
  802. }
  803. // See if the registry specifies a max table size for the IP table
  804. if( BrdgReadRegDWord(&gRegistryPath, gMaxIPTableSizeParameterName, &MaxSize) != STATUS_SUCCESS )
  805. {
  806. MaxSize = DEFAULT_MAX_IP_TABLE_SIZE;
  807. }
  808. MaxEntries = MaxSize / sizeof(IP_TABLE_ENTRY);
  809. DBGPRINT(COMPAT, ("Capping IP forwarding table at %i entries (%i bytes of memory)\n", MaxEntries, MaxSize));
  810. gIPForwardingTable = BrdgHashCreateTable( BrdgCompHashIPAddress, NUM_HASH_BUCKETS, sizeof(IP_TABLE_ENTRY),
  811. MaxEntries, MAX_IP_ENTRY_AGE, MAX_IP_ENTRY_AGE, sizeof(IPADDRESS) );
  812. if( gIPForwardingTable == NULL )
  813. {
  814. DBGPRINT(COMPAT, ("FAILED TO ALLOCATE IP TABLE!\n"));
  815. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_INIT_MALLOC_FAILED, 0L, 0L, NULL, 0L, NULL );
  816. return STATUS_INSUFFICIENT_RESOURCES;
  817. }
  818. //
  819. // Our Pending-ARP table uses ARP_TABLE_KEY structures as a key, but we still use the BrdgCompHashIPAddress
  820. // routine to hash the keys. This will result in the hash being based on the first part of the key alone (the
  821. // target IP address), which is what we want, since all the entries for a single target must end up in the
  822. // same bucket for our multi-match retrieval to work.
  823. //
  824. // See if the registry specifies a max table size for the ARP table
  825. if( BrdgReadRegDWord(&gRegistryPath, gMaxARPTableSizeParameterName, &MaxSize) != STATUS_SUCCESS )
  826. {
  827. MaxSize = DEFAULT_MAX_ARP_TABLE_SIZE;
  828. }
  829. MaxEntries = MaxSize / sizeof(ARP_TABLE_ENTRY);
  830. DBGPRINT(COMPAT, ("Capping Pending-ARP table at %i entries (%i bytes of memory)\n", MaxEntries, MaxSize));
  831. gPendingARPTable = BrdgHashCreateTable( BrdgCompHashIPAddress, NUM_HASH_BUCKETS, sizeof(ARP_TABLE_ENTRY),
  832. MaxEntries, MAX_ARP_ENTRY_AGE, MAX_ARP_ENTRY_AGE, sizeof(ARP_TABLE_KEY) );
  833. if( gPendingARPTable == NULL )
  834. {
  835. BrdgHashFreeHashTable( gIPForwardingTable );
  836. DBGPRINT(COMPAT, ("FAILED TO ALLOCATE ARP TABLE!\n"));
  837. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_INIT_MALLOC_FAILED, 0L, 0L, NULL, 0L, NULL );
  838. return STATUS_INSUFFICIENT_RESOURCES;
  839. }
  840. // See if the registry specifies a max table size for the DHCP table
  841. if( BrdgReadRegDWord(&gRegistryPath, gMaxDHCPTableSizeParameterName, &MaxSize) != STATUS_SUCCESS )
  842. {
  843. MaxSize = DEFAULT_MAX_DHCP_TABLE_SIZE;
  844. }
  845. MaxEntries = MaxSize / sizeof(DHCP_TABLE_ENTRY);
  846. DBGPRINT(COMPAT, ("Capping Pending-DHCP table at %i entries (%i bytes of memory)\n", MaxEntries, MaxSize));
  847. gPendingDHCPTable = BrdgHashCreateTable( BrdgCompHashXID, NUM_DHCP_HASH_BUCKETS, sizeof(DHCP_TABLE_ENTRY),
  848. MaxEntries, MAX_DHCP_ENTRY_AGE, MAX_DHCP_ENTRY_AGE, sizeof(ULONG) );
  849. if( gPendingDHCPTable == NULL )
  850. {
  851. BrdgHashFreeHashTable( gIPForwardingTable );
  852. BrdgHashFreeHashTable( gPendingARPTable );
  853. DBGPRINT(COMPAT, ("FAILED TO ALLOCATE DHCP TABLE!\n"));
  854. NdisWriteEventLogEntry( gDriverObject, EVENT_BRIDGE_INIT_MALLOC_FAILED, 0L, 0L, NULL, 0L, NULL );
  855. return STATUS_INSUFFICIENT_RESOURCES;
  856. }
  857. // Initialize synchronization objects
  858. NdisInitializeReadWriteLock( &gLocalIPAddressListLock );
  859. NdisAllocateSpinLock( &gTCPIPLock );
  860. BrdgInitializeWaitRef( &gTCPIPRefcount, FALSE );
  861. // We start out with no connection to TCPIP so the waitref needs to be in the shutdown state
  862. BrdgShutdownWaitRefOnce( &gTCPIPRefcount );
  863. return STATUS_SUCCESS;
  864. }
  865. VOID
  866. BrdgCompCleanup()
  867. /*++
  868. Routine Description:
  869. One-time cleanup for the compatibility module
  870. Arguments:
  871. None
  872. Return Value:
  873. None
  874. --*/
  875. {
  876. LOCK_STATE LockState;
  877. // Detach from TCPIP
  878. BrdgCompDetachFromTCPIP(NULL);
  879. // Dump the next-hop cache
  880. BrdgFreeCache( &gNextHopCache );
  881. // Dump the forwarding hash table
  882. BrdgHashFreeHashTable( gIPForwardingTable );
  883. gIPForwardingTable = NULL;
  884. // Dump the pending-ARP hash table
  885. BrdgHashFreeHashTable( gPendingARPTable );
  886. gPendingARPTable = NULL;
  887. // Dump the pending-DHCP table
  888. BrdgHashFreeHashTable( gPendingDHCPTable );
  889. gPendingDHCPTable = NULL;
  890. // Clean up the list of network addresses.
  891. NdisAcquireReadWriteLock( &gLocalIPAddressListLock, TRUE /*Read-Write*/, &LockState );
  892. if( gLocalIPAddressListLength > 0L )
  893. {
  894. NdisFreeMemory( gLocalIPAddressList, gLocalIPAddressListLength, 0 );
  895. gLocalIPAddressList = NULL;
  896. gLocalIPAddressListLength = 0L;
  897. }
  898. NdisReleaseReadWriteLock( &gLocalIPAddressListLock, &LockState );
  899. }
  900. VOID
  901. BrdgCompScrubAdapter(
  902. IN PADAPT pAdapt
  903. )
  904. /*++
  905. Routine Description:
  906. Removes all table entries that refer to a given adapter; called when that
  907. adapter is being removed (future references to this adapter are illegal)
  908. Arguments:
  909. None
  910. Return Value:
  911. None
  912. --*/
  913. {
  914. DBGPRINT(COMPAT, ("Scrubbing Adapter %p from the compatibility tables...\n", pAdapt));
  915. // Remove all entries referencing this adapter from the IP table
  916. BrdgHashRemoveMatching( gIPForwardingTable, BrdgCompIPEntriesMatchAdapter, pAdapt );
  917. // Remove all entries referencing this adapter from the pending-ARP table
  918. BrdgHashRemoveMatching( gPendingARPTable, BrdgCompARPEntriesMatchAdapter, pAdapt );
  919. // Remove all entries referencing this adapter from the DHCP table
  920. BrdgHashRemoveMatching( gPendingDHCPTable, BrdgCompDHCPEntriesMatchAdapter, pAdapt );
  921. }
  922. VOID BrdgCompScrubAllAdapters()
  923. /*++
  924. Routine Description:
  925. This function cleans all the adapters from the IP tables (this is in the case of a GPO changing
  926. our bridging settings)
  927. Arguments:
  928. None
  929. Return Value:
  930. None
  931. --*/
  932. {
  933. PADAPT pAdapt = NULL;
  934. LOCK_STATE LockStateAdapterList;
  935. //
  936. // We don't want an adapter to go away while we're running through the list of adapters.
  937. //
  938. NdisAcquireReadWriteLock(&gAdapterListLock, FALSE /* Read Only */, &LockStateAdapterList);
  939. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  940. {
  941. // Scrub the adapter from the Compatibility tables.
  942. BrdgCompScrubAdapter(pAdapt);
  943. }
  944. NdisReleaseReadWriteLock(&gAdapterListLock, &LockStateAdapterList);
  945. }
  946. VOID
  947. BrdgCompNotifyMACAddress(
  948. IN PUCHAR pBridgeMACAddr
  949. )
  950. /*++
  951. Routine Description:
  952. Called by the miniport module to notify us of the MAC address of the miniport
  953. Arguments:
  954. pBridgeMACAddr Our MAC address
  955. Return Value:
  956. None
  957. --*/
  958. {
  959. ETH_COPY_NETWORK_ADDRESS( &gCompMACAddress, pBridgeMACAddr );
  960. gCompHaveMACAddress = TRUE;
  961. }
  962. BOOLEAN
  963. BrdgCompRequiresCompatWork(
  964. IN PADAPT pAdapt,
  965. IN PUCHAR pPacketData,
  966. IN UINT dataSize
  967. )
  968. /*++
  969. Routine Description:
  970. Called during the processing of inbound packets to determine whether a
  971. packet will require compatibility-mode work.
  972. The compatibility code requires that its packets be flat, whereas packets
  973. indicated from underlying miniports can be arbitrarily fragmented. The
  974. forwarding engine uses the result of this call to determine whether an
  975. inbound packet must be copied to a flat data buffer in a copy packet that
  976. we own or whether it can be handled along fast-track paths that don't
  977. care about packet fragmentation.
  978. Arguments:
  979. pAdapt Adapter on which the packet was received
  980. pPacketDataq A pointer to the beginning of the packet data
  981. dataSize The amount of data pointed to
  982. Return Value:
  983. TRUE: The forwarding engine should call BrdgCompProcessInboundPacket at
  984. a later time to process this packet
  985. FALSE: BrdgCompProcessInboundPacket should never be called for this packet
  986. --*/
  987. {
  988. UINT result;
  989. USHORT etherType;
  990. // Weird runty packets are of no use to anyone
  991. if( dataSize < ETHERNET_HEADER_SIZE )
  992. {
  993. return FALSE;
  994. }
  995. //
  996. // No compatibility-mode work is required if there are no compatibility-mode
  997. // adapters.
  998. //
  999. if( !gCompatAdaptersExist )
  1000. {
  1001. return FALSE;
  1002. }
  1003. // All frames that arrive on a compatibility adapter are processed
  1004. if( pAdapt->bCompatibilityMode )
  1005. {
  1006. return TRUE;
  1007. }
  1008. // Broadcast or multicast frames always require compatibility processing
  1009. if( ETH_IS_BROADCAST(pPacketData) || ETH_IS_MULTICAST(pPacketData) )
  1010. {
  1011. return TRUE;
  1012. }
  1013. //
  1014. // The packet was unicast. If it wasn't sent to the adapter's MAC address,
  1015. // it does not require compatibility-mode processing.
  1016. //
  1017. ETH_COMPARE_NETWORK_ADDRESSES_EQ( pPacketData, pAdapt->MACAddr, &result );
  1018. if( result != 0 )
  1019. {
  1020. return FALSE;
  1021. }
  1022. //
  1023. // The packet is only of interest if it is ARP or IP (on a non-compat
  1024. // adapter)
  1025. //
  1026. etherType = BrdgCompGetEtherType( pPacketData );
  1027. return (BOOLEAN)( (etherType == ARP_ETHERTYPE) || (etherType == IP_ETHERTYPE) );
  1028. }
  1029. BOOLEAN
  1030. BrdgCompProcessInboundPacket(
  1031. IN PNDIS_PACKET pPacket,
  1032. IN PADAPT pAdapt,
  1033. IN BOOLEAN bCanRetain
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. Called to hand an inbound packet to the compatibility module for processing.
  1038. If the packet arrived on a non-compatibility adapter, the compatibility
  1039. code should NEVER indicate the packet, as that will be done by the
  1040. regular forwarding engine code. On the other hand, if the packet
  1041. arrived on a compatibility-mode adapter, the compatibility code MUST
  1042. indicate the packet if appropriate. Why the disparity? A packet
  1043. arriving on a compatibility adapter will likely require editing before
  1044. indication, whereas a packet arriving on a non-compatibility adapter
  1045. will not.
  1046. The compatibility module may retain the packet if bCanRetain is TRUE
  1047. (in which case we must return TRUE). If bCanRetain is FALSE, the
  1048. compatibility code may NOT retain the packet. If it needs to forward
  1049. the packet data or indicate the packet, it must make a copy
  1050. packet and use that instead of the original.
  1051. Arguments:
  1052. pPacket The received packet
  1053. pAdapt The adapter the packet was received on
  1054. bCanRetain Whether we can hang on to the packet
  1055. Return Value:
  1056. TRUE: The packet was retained (should never be returned if bCanRetain == FALSE)
  1057. The caller should not use this packet or attempt to free it.
  1058. FALSE: The packet was not retained. The caller still has ownership of the
  1059. packet and should arrange for it to be freed when appropriate.
  1060. --*/
  1061. {
  1062. PNDIS_BUFFER pBuffer;
  1063. PUCHAR pBufferData;
  1064. UINT bufferLen = 0;
  1065. UINT totLen;
  1066. USHORT etherType;
  1067. BOOLEAN bRetained;
  1068. NdisGetFirstBufferFromPacketSafe( pPacket, &pBuffer, &pBufferData, &bufferLen,
  1069. &totLen, NormalPagePriority );
  1070. if( pBufferData == NULL )
  1071. {
  1072. // The packet was empty or the system is under severe memory pressure
  1073. // We didn't retain the packet.
  1074. return FALSE;
  1075. }
  1076. if( totLen < ETHERNET_HEADER_SIZE )
  1077. {
  1078. return FALSE;
  1079. }
  1080. // The packet should be flat
  1081. SAFEASSERT( totLen == bufferLen );
  1082. etherType = BrdgCompGetEtherType( pBufferData );
  1083. if( etherType == ARP_ETHERTYPE )
  1084. {
  1085. bRetained = BrdgCompProcessInboundARPPacket( pPacket, pAdapt, bCanRetain, pBufferData, bufferLen );
  1086. }
  1087. else
  1088. {
  1089. bRetained = BrdgCompProcessInboundNonARPPacket( pPacket, pAdapt, bCanRetain, pBufferData, bufferLen );
  1090. }
  1091. if( !bCanRetain )
  1092. {
  1093. SAFEASSERT( !bRetained );
  1094. }
  1095. return bRetained;
  1096. }
  1097. VOID
  1098. BrdgCompProcessOutboundPacket(
  1099. IN PNDIS_PACKET pPacket,
  1100. IN PADAPT pTargetAdapt
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. Called to hand an outbound packet to the compatibility module for processing.
  1105. Because the packet passed to us is from an overlying protocol driver, we
  1106. are not allowed to do anything with it. The packet may be arbitrarily
  1107. fragmented, and its data buffers must be treated as read-only.
  1108. This function is only called if a packet is bound for an adapter in
  1109. compatibility mode (so we can do any necessary packet editing) or for a packet
  1110. for which we have no known outbound adapter (i.e., it is a packet we are
  1111. flooding).
  1112. In the case that pTargetAdapt == NULL (a flood), the compatibility code is
  1113. responsible for sending the packet out all *compatibility mode* adapters.
  1114. Sending the packet out regular-mode adapters is the job of the regular
  1115. code in the forwarding engine.
  1116. Arguments:
  1117. pPacket The outbound packet
  1118. pTargetAdapt The target adapter, as determined by a previous lookup in
  1119. the MAC forwarding table. This can be NULL to indicate
  1120. a flood.
  1121. Return Value:
  1122. None
  1123. --*/
  1124. {
  1125. PNDIS_PACKET pCopyPacket;
  1126. PUCHAR pCopyPacketData;
  1127. UINT copyPacketSize;
  1128. // There's no point in calling us for a packet that is bound for a MAC
  1129. // address which is known to be reachable on a non-compat adapter
  1130. SAFEASSERT( (pTargetAdapt == NULL) || (pTargetAdapt->bCompatibilityMode) );
  1131. // There is no work to do if there are no compatibility adapters
  1132. if( !gCompatAdaptersExist )
  1133. {
  1134. return;
  1135. }
  1136. // Prepare the flattened copy packet so our functions can edit
  1137. // the packet as appropriate. The packet will be counted as a local-source
  1138. // transmission when / if it is used.
  1139. pCopyPacket = BrdgFwdMakeCompatCopyPacket( pPacket, &pCopyPacketData, &copyPacketSize, TRUE );
  1140. if( pCopyPacket != NULL )
  1141. {
  1142. BOOLEAN bRetained = FALSE;
  1143. if( copyPacketSize >= ETHERNET_HEADER_SIZE )
  1144. {
  1145. USHORT etherType;
  1146. etherType = BrdgCompGetEtherType(pCopyPacketData);
  1147. if( etherType == ARP_ETHERTYPE )
  1148. {
  1149. bRetained = BrdgCompProcessOutboundARPPacket(pCopyPacket, pCopyPacketData, copyPacketSize, pTargetAdapt);
  1150. }
  1151. else
  1152. {
  1153. bRetained = BrdgCompProcessOutboundNonARPPacket(pCopyPacket, pCopyPacketData, copyPacketSize, pTargetAdapt);
  1154. }
  1155. }
  1156. // else the packet was really small!
  1157. if( ! bRetained )
  1158. {
  1159. // The functions above decided not to hang on to the packet after all.
  1160. // Release it.
  1161. BrdgFwdReleaseCompatPacket( pCopyPacket );
  1162. }
  1163. }
  1164. // Else we didn't get a packet
  1165. }
  1166. VOID
  1167. BrdgCompNotifyNetworkAddresses(
  1168. IN PNETWORK_ADDRESS_LIST pAddressList,
  1169. IN ULONG infoLength
  1170. )
  1171. /*++
  1172. Routine Description:
  1173. Called by the miniport code when we get an OID indicating our network-layer
  1174. addresses to us. We copy out the list of our IP addresses. The buffer
  1175. passed to us can also be formatted in such a way as to indicate that we
  1176. should dump our list of network addresses.
  1177. Arguments:
  1178. pAddressList The data buffer passed down in the OID
  1179. infoLength The size of the buffer
  1180. Return Value:
  1181. None
  1182. --*/
  1183. {
  1184. PIPADDRESS pOldList;
  1185. UINT oldListLength;
  1186. LOCK_STATE LockState;
  1187. if( infoLength < sizeof(NETWORK_ADDRESS_LIST) - sizeof(NETWORK_ADDRESS) )
  1188. {
  1189. // The structure is too small to hold anything interesting.
  1190. return;
  1191. }
  1192. if( pAddressList->AddressCount > 0 )
  1193. {
  1194. USHORT i, numAddresses, copiedAddresses = 0;
  1195. NETWORK_ADDRESS UNALIGNED *pNetAddress;
  1196. NDIS_STATUS Status;
  1197. PIPADDRESS pNewList;
  1198. //
  1199. // Make sure the structure can hold the number of addresses it claims to.
  1200. // NETWORK_ADDRESS_LIST is defined with one NETWORK_ADDRESS at its tail,
  1201. // so knock one off pAddressList->AddressCount when calculating the
  1202. // size of the total structure.
  1203. //
  1204. if( infoLength < sizeof(NETWORK_ADDRESS_LIST) +
  1205. ( sizeof(NETWORK_ADDRESS) * (pAddressList->AddressCount - 1) ) )
  1206. {
  1207. // The structure is too small to contain the number of addresses
  1208. // it claims to.
  1209. SAFEASSERT( FALSE );
  1210. return;
  1211. }
  1212. // Make a first pass to count the number of IP addresses in the list
  1213. pNetAddress = pAddressList->Address;
  1214. for( i = 0, numAddresses = 0; i < pAddressList->AddressCount; i++ )
  1215. {
  1216. if( pNetAddress->AddressType == NDIS_PROTOCOL_ID_TCP_IP )
  1217. {
  1218. numAddresses++;
  1219. }
  1220. pNetAddress = (NETWORK_ADDRESS UNALIGNED*)(((PUCHAR)pNetAddress) + pNetAddress->AddressLength);
  1221. }
  1222. if( numAddresses == 0 )
  1223. {
  1224. // There are no IP addresses in this list. Nothing to do.
  1225. return;
  1226. }
  1227. // Allocate enough room to hold the addresses
  1228. Status = NdisAllocateMemoryWithTag( &pNewList, sizeof(IPADDRESS) * numAddresses, 'gdrB' );
  1229. if( Status != NDIS_STATUS_SUCCESS )
  1230. {
  1231. DBGPRINT(COMPAT, ("NdisAllocateMemoryWithTag failed while recording IP address list\n"));
  1232. // Clobber the old list with a NULL, since we know that the old list is outdated,
  1233. // but we failed to record the new info
  1234. pNewList = NULL;
  1235. }
  1236. else
  1237. {
  1238. SAFEASSERT( pNewList != NULL );
  1239. // Copy the IP addresses to our list
  1240. pNetAddress = pAddressList->Address;
  1241. for( i = 0; i < pAddressList->AddressCount; i++ )
  1242. {
  1243. if( pNetAddress->AddressType == NDIS_PROTOCOL_ID_TCP_IP )
  1244. {
  1245. NETWORK_ADDRESS_IP UNALIGNED *pIPAddr;
  1246. PUCHAR pIPNetAddr;
  1247. SAFEASSERT( copiedAddresses < numAddresses );
  1248. pIPAddr = (NETWORK_ADDRESS_IP UNALIGNED*)&pNetAddress->Address[0];
  1249. pIPNetAddr = (PUCHAR)&pIPAddr->in_addr;
  1250. // IP passes down the IP address in the opposite byte order that we use
  1251. pNewList[copiedAddresses] = 0L;
  1252. pNewList[copiedAddresses] |= pIPNetAddr[3];
  1253. pNewList[copiedAddresses] |= pIPNetAddr[2] << 8;
  1254. pNewList[copiedAddresses] |= pIPNetAddr[1] << 16;
  1255. pNewList[copiedAddresses] |= pIPNetAddr[0] << 24;
  1256. DBGPRINT(COMPAT, ("Noted local IP address %i.%i.%i.%i\n",
  1257. pIPNetAddr[0], pIPNetAddr[1], pIPNetAddr[2], pIPNetAddr[3] ));
  1258. copiedAddresses++;
  1259. }
  1260. pNetAddress = (NETWORK_ADDRESS UNALIGNED*)(((PUCHAR)pNetAddress) + pNetAddress->AddressLength);
  1261. }
  1262. SAFEASSERT( copiedAddresses == numAddresses );
  1263. }
  1264. // Swap in the new list (even if it's NULL)
  1265. NdisAcquireReadWriteLock( &gLocalIPAddressListLock, TRUE /*Read-write*/, &LockState );
  1266. pOldList = gLocalIPAddressList;
  1267. oldListLength = gLocalIPAddressListLength;
  1268. gLocalIPAddressList = pNewList;
  1269. if( pNewList != NULL )
  1270. {
  1271. gLocalIPAddressListLength = sizeof(IPADDRESS) * numAddresses;
  1272. }
  1273. else
  1274. {
  1275. gLocalIPAddressListLength = 0L;
  1276. }
  1277. NdisReleaseReadWriteLock( &gLocalIPAddressListLock, &LockState );
  1278. // Ditch the old list if there was one
  1279. if( pOldList != NULL )
  1280. {
  1281. SAFEASSERT( oldListLength > 0L );
  1282. NdisFreeMemory( pOldList, oldListLength, 0 );
  1283. }
  1284. // Only attach to TCPIP if we actually learned some IP addresses
  1285. if( numAddresses > 0 )
  1286. {
  1287. // We are at DISPATCH_LEVEL in this function. Defer the call to BrdgCompAttachToTCPIP
  1288. // so we open a channel of communication to the TCPIP driver.
  1289. BrdgDeferFunction( BrdgCompAttachToTCPIP, NULL );
  1290. }
  1291. }
  1292. else
  1293. {
  1294. // This is a request to clear out our list of network-layer
  1295. // addresses.
  1296. if( pAddressList->AddressType == NDIS_PROTOCOL_ID_TCP_IP )
  1297. {
  1298. DBGPRINT(COMPAT, ("Flushing list of IP addresses\n"));
  1299. // Dump our list of network addresses
  1300. NdisAcquireReadWriteLock( &gLocalIPAddressListLock, TRUE /*Read-write*/, &LockState );
  1301. pOldList = gLocalIPAddressList;
  1302. oldListLength = gLocalIPAddressListLength;
  1303. gLocalIPAddressList = NULL;
  1304. gLocalIPAddressListLength = 0L;
  1305. NdisReleaseReadWriteLock( &gLocalIPAddressListLock, &LockState );
  1306. if( oldListLength > 0L )
  1307. {
  1308. SAFEASSERT( pOldList != NULL );
  1309. NdisFreeMemory( pOldList, oldListLength, 0 );
  1310. }
  1311. // Detach from the TCPIP driver at lower IRQL
  1312. BrdgDeferFunction( BrdgCompDetachFromTCPIP, NULL );
  1313. }
  1314. }
  1315. }
  1316. // ===========================================================================
  1317. //
  1318. // PRIVATE UTILITY FUNCTIONS
  1319. //
  1320. // ===========================================================================
  1321. NTSTATUS
  1322. BrdgCompRouteChangeCompletion(
  1323. PDEVICE_OBJECT DeviceObject,
  1324. PIRP pirp,
  1325. PVOID Context
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. Called when the IRP we post to TCPIP.SYS completes, indicating a change
  1330. in the IP routing table
  1331. Arguments:
  1332. DeviceObject Unused
  1333. pirp The completed IRP
  1334. Context Unused
  1335. Return Value:
  1336. STATUS_SUCCESS, indicating we are done with this IRP
  1337. STATUS_MORE_PROCESSING_REQUIRED when we reuse this IRP by reposting it
  1338. --*/
  1339. {
  1340. PIO_STACK_LOCATION IrpSp;
  1341. PDEVICE_OBJECT pdo;
  1342. PFILE_OBJECT pfo;
  1343. DBGPRINT(COMPAT, ("IP route table changed; flushing route cache.\n"));
  1344. // Flush the route cache
  1345. BrdgClearCache( &gNextHopCache );
  1346. //
  1347. // If gIPRouteChangeIRP != pirp, it indicates that we are either detached
  1348. // from TCPIP (gIPRouteChangeIRP == NULL) or we have detached and
  1349. // reattached (gIPRouteChangeIRP != NULL && gIPRouteChangeIRP != pirp).
  1350. // In either case, we should stop reusing this IRP to post route-change
  1351. // notification requests.
  1352. //
  1353. if( (gIPRouteChangeIRP == pirp) && (BrdgCompAcquireTCPIP(NULL, NULL, &pdo, &pfo)) )
  1354. {
  1355. NTSTATUS status;
  1356. //
  1357. // Reinitialize the IRP structure and submit it again
  1358. // for further notification.
  1359. //
  1360. pirp->Cancel = FALSE;
  1361. pirp->IoStatus.Status = 0;
  1362. pirp->IoStatus.Information = 0;
  1363. pirp->AssociatedIrp.SystemBuffer = NULL;
  1364. IoSetCompletionRoutine( pirp, BrdgCompRouteChangeCompletion,
  1365. NULL, TRUE, FALSE, FALSE );
  1366. IrpSp = IoGetNextIrpStackLocation(pirp);
  1367. IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  1368. IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_IP_RTCHANGE_NOTIFY_REQUEST;
  1369. IrpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
  1370. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  1371. status = IoCallDriver(pdo, pirp);
  1372. BrdgCompReleaseTCPIP();
  1373. if (!NT_SUCCESS(status))
  1374. {
  1375. // We failed to call TCPIP. Release the IRP.
  1376. DBGPRINT(COMPAT, ("Failed to call TCPIP for route notification: %08x\n", status));
  1377. return STATUS_SUCCESS;
  1378. }
  1379. else
  1380. {
  1381. // We keep the IRP since we reposted it to TCPIP
  1382. return STATUS_MORE_PROCESSING_REQUIRED;
  1383. }
  1384. }
  1385. else
  1386. {
  1387. // We must be detaching or detached from TCPIP. Don't repost the IRP.
  1388. DBGPRINT(COMPAT, ("Stopping our route change notifications...\n"));
  1389. return STATUS_SUCCESS;
  1390. }
  1391. }
  1392. VOID
  1393. BrdgCompAttachToTCPIP(
  1394. IN PVOID ignored
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. Establishes a connection to TCPIP for sending future route-lookup requests.
  1399. Opens a connection to the TCPIP driver and posts an IRP for route change
  1400. notifications.
  1401. Arguments:
  1402. ignored ignored
  1403. Return Value:
  1404. None
  1405. --*/
  1406. {
  1407. NTSTATUS status;
  1408. HANDLE TCPFileHandle, IPFileHandle;
  1409. PFILE_OBJECT pTCPFileObject, pIPFileObject;
  1410. PDEVICE_OBJECT pTCPDeviceObject, pIPDeviceObject;
  1411. BOOLEAN bAbort = FALSE;
  1412. // Check if there is already a connection open to TCP
  1413. if( BrdgCompAcquireTCPIP(NULL, NULL, NULL, NULL) )
  1414. {
  1415. BrdgCompReleaseTCPIP();
  1416. return;
  1417. }
  1418. // There doesn't appear to currently be a connection to the TCPIP driver.
  1419. // Open one.
  1420. status = BrdgOpenDevice( DD_TCP_DEVICE_NAME, &pTCPDeviceObject, &TCPFileHandle, &pTCPFileObject );
  1421. if( ! NT_SUCCESS(status) )
  1422. {
  1423. DBGPRINT(ALWAYS_PRINT, ("Couldn't open TCP device: %08x\n", status));
  1424. return;
  1425. }
  1426. status = BrdgOpenDevice( DD_IP_DEVICE_NAME, &pIPDeviceObject, &IPFileHandle, &pIPFileObject );
  1427. if( ! NT_SUCCESS(status) )
  1428. {
  1429. DBGPRINT(ALWAYS_PRINT, ("Couldn't open IP device: %08x\n", status));
  1430. BrdgCloseDevice(TCPFileHandle, pTCPFileObject, pTCPDeviceObject);
  1431. return;
  1432. }
  1433. NdisAcquireSpinLock( &gTCPIPLock );
  1434. if( gTCPDeviceObject == NULL )
  1435. {
  1436. SAFEASSERT( gTCPFileHandle == NULL );
  1437. SAFEASSERT( gTCPFileObject == NULL );
  1438. SAFEASSERT( gIPDeviceObject == NULL );
  1439. SAFEASSERT( gIPFileHandle == NULL );
  1440. SAFEASSERT( gIPFileObject == NULL );
  1441. // Swap in the info we just obtained.
  1442. gTCPDeviceObject = pTCPDeviceObject;
  1443. gTCPFileHandle = TCPFileHandle;
  1444. gTCPFileObject = pTCPFileObject;
  1445. gIPDeviceObject = pIPDeviceObject;
  1446. gIPFileHandle = IPFileHandle;
  1447. gIPFileObject = pIPFileObject;
  1448. // Let people acquire the TCPIP driver
  1449. BrdgResetWaitRef( &gTCPIPRefcount );
  1450. }
  1451. else
  1452. {
  1453. // Someone else opened TCPIP.SYS between our initial call to BrdgCompAcquireTCPIP
  1454. // and now. This should be rather rare.
  1455. SAFEASSERT( gTCPFileHandle != NULL );
  1456. SAFEASSERT( gTCPFileObject != NULL );
  1457. SAFEASSERT( gIPDeviceObject != NULL );
  1458. SAFEASSERT( gIPFileHandle != NULL );
  1459. SAFEASSERT( gIPFileObject != NULL );
  1460. bAbort = TRUE;
  1461. }
  1462. NdisReleaseSpinLock( &gTCPIPLock );
  1463. if( bAbort )
  1464. {
  1465. // Need to back out of the attempt to open TCPIP.SYS
  1466. BrdgCloseDevice( TCPFileHandle, pTCPFileObject, pTCPDeviceObject );
  1467. BrdgCloseDevice( IPFileHandle, pIPFileObject, pIPDeviceObject );
  1468. }
  1469. else
  1470. {
  1471. if( BrdgCompAcquireTCPIP(NULL, NULL, &pIPDeviceObject, &pIPFileObject) )
  1472. {
  1473. NTSTATUS status;
  1474. PIRP pirp;
  1475. // Set up the route-change notification IRP
  1476. pirp = IoBuildDeviceIoControlRequest( IOCTL_IP_RTCHANGE_NOTIFY_REQUEST, pIPDeviceObject,
  1477. NULL, 0, NULL, 0, FALSE, NULL, NULL );
  1478. if( pirp == NULL )
  1479. {
  1480. DBGPRINT(COMPAT, ("Failed to allocate an IRP for route-change notification!\n"));
  1481. }
  1482. else
  1483. {
  1484. if( InterlockedExchangePointer(&gIPRouteChangeIRP, pirp) != NULL )
  1485. {
  1486. //
  1487. // Oops; someone else created an IRP to post to TCPIP at the same time as us.
  1488. // Abort our attempt.
  1489. //
  1490. IoCompleteRequest( pirp, IO_NO_INCREMENT );
  1491. }
  1492. else
  1493. {
  1494. IoSetCompletionRoutine( pirp, BrdgCompRouteChangeCompletion, NULL, TRUE, FALSE, FALSE );
  1495. status = IoCallDriver( pIPDeviceObject, pirp );
  1496. if( ! NT_SUCCESS(status) )
  1497. {
  1498. DBGPRINT(COMPAT, ("Failed to post IRP to TCPIP for route-change notification: %08x\n", status));
  1499. }
  1500. else
  1501. {
  1502. DBGPRINT(COMPAT, ("Posted route-change notification request to TCPIP\n"));
  1503. }
  1504. }
  1505. }
  1506. BrdgCompReleaseTCPIP();
  1507. }
  1508. // else someone shut down the connection to TCPIP very quickly after we set it up
  1509. }
  1510. }
  1511. VOID
  1512. BrdgCompDetachFromTCPIP(
  1513. IN PVOID ignored
  1514. )
  1515. /*++
  1516. Routine Description:
  1517. Severs the current connection, if any, to TCPIP.SYS.
  1518. Arguments:
  1519. ignored ignored
  1520. Return Value:
  1521. None
  1522. --*/
  1523. {
  1524. HANDLE TCPFileHandle, IPFileHandle;
  1525. PFILE_OBJECT pTCPFileObject, pIPFileObject;
  1526. PDEVICE_OBJECT pTCPDeviceObject, pIPDeviceObject;
  1527. PIRP pRouteIRP;
  1528. // Wait for everyone to be done using the driver
  1529. // Ignore return value because we are multi-shutdown-safe.
  1530. BrdgShutdownWaitRef( &gTCPIPRefcount );
  1531. // Cancel the IRP we use for route change notifications.
  1532. pRouteIRP = InterlockedExchangePointer( &gIPRouteChangeIRP, NULL );
  1533. // pRouteIRP can be NULL if someone is shutting down the connection
  1534. // at the same time as us, or if the connection was already shut down
  1535. if( pRouteIRP != NULL )
  1536. {
  1537. IoCancelIrp( pRouteIRP );
  1538. }
  1539. // Flush the route cache
  1540. BrdgClearCache( &gNextHopCache );
  1541. // Copy out the pointers and NULL them
  1542. NdisAcquireSpinLock( &gTCPIPLock );
  1543. TCPFileHandle = gTCPFileHandle;
  1544. gTCPFileHandle = NULL;
  1545. pTCPFileObject = gTCPFileObject;
  1546. gTCPFileObject = NULL;
  1547. pTCPDeviceObject = gTCPDeviceObject;
  1548. gTCPDeviceObject = NULL;
  1549. IPFileHandle = gIPFileHandle;
  1550. gIPFileHandle = NULL;
  1551. pIPFileObject = gIPFileObject;
  1552. gIPFileObject = NULL;
  1553. pIPDeviceObject = gIPDeviceObject;
  1554. gIPDeviceObject = NULL;
  1555. NdisReleaseSpinLock( &gTCPIPLock );
  1556. // The global pointers can be NULL if someone else is shutting down the
  1557. // connection concurrently with us, or if the connection was already
  1558. // shut down.
  1559. if( pTCPFileObject != NULL )
  1560. {
  1561. SAFEASSERT( TCPFileHandle != NULL );
  1562. SAFEASSERT( pTCPDeviceObject != NULL );
  1563. SAFEASSERT( IPFileHandle != NULL );
  1564. SAFEASSERT( pIPFileObject != NULL );
  1565. SAFEASSERT( pIPDeviceObject != NULL );
  1566. BrdgCloseDevice( TCPFileHandle, pTCPFileObject, pTCPDeviceObject );
  1567. BrdgCloseDevice( IPFileHandle, pIPFileObject, pIPDeviceObject );
  1568. }
  1569. else
  1570. {
  1571. SAFEASSERT( TCPFileHandle == NULL );
  1572. SAFEASSERT( pTCPDeviceObject == NULL );
  1573. SAFEASSERT( IPFileHandle == NULL );
  1574. SAFEASSERT( pIPFileObject == NULL );
  1575. SAFEASSERT( pIPDeviceObject == NULL );
  1576. }
  1577. }
  1578. BOOLEAN
  1579. BrdgCompIsUnicastIPAddress(
  1580. IN IPADDRESS ip
  1581. )
  1582. /*++
  1583. Routine Description:
  1584. Determines whether a given IP address is a unicast address (i.e., one that
  1585. can reasonably designate a single station)
  1586. Arguments:
  1587. ip The IP address
  1588. Return Value:
  1589. TRUE: The address appears to be a unicast address
  1590. FALSE: The opposite is true
  1591. --*/
  1592. {
  1593. UCHAR highByte;
  1594. // The broadcast address is not cool
  1595. if( ip == 0xFFFFFFFF )
  1596. {
  1597. return FALSE;
  1598. }
  1599. // The zero address is no good
  1600. if( ip == 0L )
  1601. {
  1602. return FALSE;
  1603. }
  1604. // Any class D (multicast) or class E (currently undefined) is similarly uncool
  1605. highByte = (UCHAR)(ip >> 24);
  1606. if( (highByte & 0xF0) == 0xE0 || (highByte & 0xF0) == 0xF0 )
  1607. {
  1608. return FALSE;
  1609. }
  1610. // Check each address class to see if this is a net-directed (or all-subnets)
  1611. // broadcast
  1612. if( (highByte & 0x80) && ((ip & 0x00FFFFFF) == 0x00FFFFFFFF) )
  1613. {
  1614. // Class A net-directed or all-subnets broadcast.
  1615. return FALSE;
  1616. }
  1617. else if( ((highByte & 0xC0) == 0x80) && ((ip & 0x0000FFFF) == 0x0000FFFF) )
  1618. {
  1619. // Class B net-directed or all-subnets broadcast.
  1620. return FALSE;
  1621. }
  1622. else if( ((highByte & 0xE0) == 0xC) && ((UCHAR)ip == 0xFF) )
  1623. {
  1624. // Class C net-directed or all-subnets broadcast.
  1625. return FALSE;
  1626. }
  1627. //
  1628. // This address appears to be OK, although note that since we have no way of
  1629. // knowing the subnet prefix in use on the local links, we cannot detect
  1630. // subnet-directed broadcasts.
  1631. //
  1632. return TRUE;
  1633. }
  1634. BOOLEAN
  1635. BrdgCompGetNextHopForTarget(
  1636. IN IPADDRESS ipTarget,
  1637. OUT PIPADDRESS pipNextHop
  1638. )
  1639. /*++
  1640. Routine Description:
  1641. Calls into the TCPIP.SYS driver to determine the next-hop address for a
  1642. given target IP.
  1643. Arguments:
  1644. ipTarget The target address
  1645. pipNextHop Receives the next-hop address
  1646. Return Value:
  1647. TRUE if the next-hop lookup succeeded and *pipNextHop is valid, FALSE
  1648. otherwise.
  1649. --*/
  1650. {
  1651. BOOLEAN rc = FALSE;
  1652. // First look for the information in our next-hop cache
  1653. *pipNextHop = BrdgProbeCache( &gNextHopCache, (UINT32)ipTarget );
  1654. if( *pipNextHop != 0L )
  1655. {
  1656. if( *pipNextHop != NO_ADDRESS )
  1657. {
  1658. // The cache contained a valid next hop
  1659. rc = TRUE;
  1660. }
  1661. else
  1662. {
  1663. // We asked TCPIP before about this target address and it
  1664. // told us it doesn't know.
  1665. rc = FALSE;
  1666. }
  1667. }
  1668. else
  1669. {
  1670. PDEVICE_OBJECT pdo;
  1671. PFILE_OBJECT pfo;
  1672. if( BrdgCompAcquireTCPIP(&pdo, &pfo, NULL, NULL) )
  1673. {
  1674. PIRP pirp;
  1675. pirp = IoAllocateIrp( pdo->StackSize, FALSE );
  1676. if( pirp != NULL )
  1677. {
  1678. TCP_REQUEST_QUERY_INFORMATION_EX trqiBuffer;
  1679. IPRouteLookupData *pRtLookupData;
  1680. TDIObjectID *lpObject;
  1681. IPRouteEntry routeEntry;
  1682. PIO_STACK_LOCATION irpSp;
  1683. NTSTATUS status;
  1684. RtlZeroMemory (&trqiBuffer, sizeof (trqiBuffer));
  1685. pRtLookupData = (IPRouteLookupData *)trqiBuffer.Context;
  1686. pRtLookupData->SrcAdd = 0;
  1687. // IP uses the opposite byte ordering from us.
  1688. ((PUCHAR)&pRtLookupData->DestAdd)[0] = ((PUCHAR)&ipTarget)[3];
  1689. ((PUCHAR)&pRtLookupData->DestAdd)[1] = ((PUCHAR)&ipTarget)[2];
  1690. ((PUCHAR)&pRtLookupData->DestAdd)[2] = ((PUCHAR)&ipTarget)[1];
  1691. ((PUCHAR)&pRtLookupData->DestAdd)[3] = ((PUCHAR)&ipTarget)[0];
  1692. lpObject = &trqiBuffer.ID;
  1693. lpObject->toi_id = IP_MIB_SINGLE_RT_ENTRY_ID;
  1694. lpObject->toi_class = INFO_CLASS_PROTOCOL;
  1695. lpObject->toi_type = INFO_TYPE_PROVIDER;
  1696. lpObject->toi_entity.tei_entity = CL_NL_ENTITY;
  1697. lpObject->toi_entity.tei_instance = 0;
  1698. irpSp = IoGetNextIrpStackLocation(pirp);
  1699. SAFEASSERT( irpSp != NULL );
  1700. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  1701. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_TCP_QUERY_INFORMATION_EX;
  1702. irpSp->DeviceObject = pdo;
  1703. irpSp->FileObject = pfo;
  1704. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = &trqiBuffer;
  1705. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(trqiBuffer);
  1706. irpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(routeEntry);
  1707. pirp->UserBuffer = &routeEntry;
  1708. pirp->RequestorMode = KernelMode;
  1709. IoSetCompletionRoutine( pirp, BrdgCompCompleteRouteLookupIRP, NULL, TRUE, TRUE, TRUE );
  1710. status = IoCallDriver( pdo, pirp );
  1711. // STATUS_PENDING will bugcheck the machine since we passed buffers that
  1712. // are on the stack.
  1713. SAFEASSERT( status != STATUS_PENDING );
  1714. if( status == STATUS_SUCCESS )
  1715. {
  1716. //
  1717. // TCPIP signals failure by setting the interface designator
  1718. // on the reply to 0xFFFFFFFF
  1719. //
  1720. if( routeEntry.ire_index != 0xFFFFFFFF )
  1721. {
  1722. // IP uses the opposite byte ordering from us.
  1723. ((PUCHAR)pipNextHop)[3] = ((PUCHAR)&routeEntry.ire_nexthop)[0];
  1724. ((PUCHAR)pipNextHop)[2] = ((PUCHAR)&routeEntry.ire_nexthop)[1];
  1725. ((PUCHAR)pipNextHop)[1] = ((PUCHAR)&routeEntry.ire_nexthop)[2];
  1726. ((PUCHAR)pipNextHop)[0] = ((PUCHAR)&routeEntry.ire_nexthop)[3];
  1727. if( ! BrdgCompIsLocalIPAddress(*pipNextHop) )
  1728. {
  1729. // Poke the new data into the cache
  1730. BrdgUpdateCache( &gNextHopCache, ipTarget, *pipNextHop );
  1731. rc = TRUE;
  1732. }
  1733. else
  1734. {
  1735. THROTTLED_DBGPRINT(COMPAT, ("TCPIP gave a bridge IP address as next hop for %i.%i.%i.%i\n",
  1736. ((PUCHAR)&ipTarget)[3], ((PUCHAR)&ipTarget)[2], ((PUCHAR)&ipTarget)[1],
  1737. ((PUCHAR)&ipTarget)[0] ));
  1738. BrdgUpdateCache( &gNextHopCache, ipTarget, NO_ADDRESS );
  1739. }
  1740. }
  1741. else
  1742. {
  1743. // Poke a negative entry into the cache so we don't keep trying to look this up.
  1744. THROTTLED_DBGPRINT(COMPAT, ("TCPIP found no route entry for %i.%i.%i.%i\n", ((PUCHAR)&ipTarget)[3], ((PUCHAR)&ipTarget)[2],
  1745. ((PUCHAR)&ipTarget)[1], ((PUCHAR)&ipTarget)[0] ));
  1746. BrdgUpdateCache( &gNextHopCache, ipTarget, NO_ADDRESS );
  1747. }
  1748. }
  1749. else
  1750. {
  1751. DBGPRINT(COMPAT, ("TPCIP failed route lookup IRP: %08x\n", status));
  1752. }
  1753. }
  1754. else
  1755. {
  1756. DBGPRINT(COMPAT, ("Failed to allocate an IRP in BrdgCompGetNextHopForTarget!\n"));
  1757. }
  1758. // We are done talking to TCPIP
  1759. BrdgCompReleaseTCPIP();
  1760. }
  1761. // else no open channel to TCPIP
  1762. }
  1763. return rc;
  1764. }
  1765. BOOLEAN
  1766. BrdgCompIsLocalIPAddress(
  1767. IN IPADDRESS ipAddr
  1768. )
  1769. /*++
  1770. Routine Description:
  1771. Determines whether a given IP address is one of our local addresses.
  1772. Arguments:
  1773. ipAddr The address
  1774. Return Value:
  1775. TRUE if the given address is on our list of local addresses, FALSE
  1776. otherwise
  1777. --*/
  1778. {
  1779. LOCK_STATE LockState;
  1780. ULONG i;
  1781. PIPADDRESS pAddr = (PIPADDRESS)gLocalIPAddressList;
  1782. BOOLEAN bFound = FALSE;
  1783. NdisAcquireReadWriteLock( &gLocalIPAddressListLock, FALSE/*Read only*/, &LockState );
  1784. // There should be an integral number of IP addresses in the list!
  1785. SAFEASSERT( (gLocalIPAddressListLength % sizeof(IPADDRESS)) == 0 );
  1786. SAFEASSERT( (gLocalIPAddressListLength == 0) || (gLocalIPAddressList != NULL) );
  1787. for( i = 0L; i < gLocalIPAddressListLength / sizeof(IPADDRESS); i++ )
  1788. {
  1789. if( pAddr[i] == ipAddr )
  1790. {
  1791. bFound = TRUE;
  1792. break;
  1793. }
  1794. }
  1795. NdisReleaseReadWriteLock( &gLocalIPAddressListLock, &LockState );
  1796. return bFound;
  1797. }
  1798. BOOLEAN
  1799. BrdgCompSendToMultipleAdapters(
  1800. IN PNDIS_PACKET pPacket,
  1801. IN PADAPT pOriginalAdapt,
  1802. IN PUCHAR pPacketData,
  1803. IN BOOLEAN bCanRetain,
  1804. IN BOOLEAN bAllAdapters,
  1805. IN PPER_ADAPT_EDIT_FUNC pEditFunc,
  1806. IN PVOID pData
  1807. )
  1808. /*++
  1809. Routine Description:
  1810. Sends a packet (or a copy thereof) to multiple adapters. Usually used to send around
  1811. a broadcast packet.
  1812. Arguments:
  1813. pPacket The packet to send (or to send a copy of)
  1814. pOriginalAdapt The adapter the packet was originally received on (so
  1815. we can skip it). This can be NULL
  1816. pPacketData A pointer to the packet's data buffer
  1817. bCanRetain Whether we can retain the packet
  1818. bAllAdapters TRUE: Send to all adapters FALSE: send only to
  1819. adapters in compatibility mode
  1820. pEditFunc Optional function that gets called before sending to
  1821. each adapter (to edit the packet)
  1822. pData Cookie to pass to pEditFunc as context
  1823. Return Value:
  1824. TRUE if pPacket was retained, FALSE otherwise
  1825. --*/
  1826. {
  1827. UINT numTargets = 0L, i;
  1828. PADAPT pAdapt;
  1829. PADAPT SendList[MAX_ADAPTERS];
  1830. LOCK_STATE LockState;
  1831. BOOLEAN bSentOriginal = FALSE; // Whether we have sent the packet we were given yet
  1832. //
  1833. // First we need a list of the adapters we intend to send this packet to
  1834. //
  1835. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE /*Read only*/, &LockState );
  1836. // Note each adapter to send to
  1837. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  1838. {
  1839. // Don't need to acquire the global adapter characteristics lock to read the
  1840. // media state because we don't care about the global consistency of the
  1841. // adapters' characteristics here
  1842. if( (pAdapt != pOriginalAdapt) &&
  1843. (pAdapt->MediaState == NdisMediaStateConnected) && // Don't send to disconnected adapters
  1844. (pAdapt->State == Forwarding) && // Adapter must be in relaying state
  1845. (! pAdapt->bResetting) ) // Adapter must not be resetting
  1846. {
  1847. // If we're not trying to send to every single adapter, make sure
  1848. // this one is in compatibility mode
  1849. if( bAllAdapters || (pAdapt->bCompatibilityMode) )
  1850. {
  1851. if( numTargets < MAX_ADAPTERS )
  1852. {
  1853. // We will use this adapter outside the list lock; bump its refcount
  1854. BrdgAcquireAdapterInLock(pAdapt);
  1855. SendList[numTargets] = pAdapt;
  1856. numTargets++;
  1857. }
  1858. else
  1859. {
  1860. // Too many copies to send!
  1861. SAFEASSERT( FALSE );
  1862. }
  1863. }
  1864. }
  1865. }
  1866. // Can let go of the adapter list now; we have copied out all the target adapters
  1867. // and incremented the refcount for the adapters we will be using.
  1868. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  1869. for( i = 0; i < numTargets; i++ )
  1870. {
  1871. PNDIS_PACKET pPacketToSend;
  1872. PUCHAR pPacketToSendData;
  1873. if( bCanRetain && (! bSentOriginal) && (i == (numTargets - 1)) )
  1874. {
  1875. //
  1876. // Use the packet we were given.
  1877. // We must do this only with the last adapter since we need to be
  1878. // able to copy from it for every adapter before the last one.
  1879. //
  1880. pPacketToSend = pPacket;
  1881. pPacketToSendData = pPacketData;
  1882. bSentOriginal = TRUE;
  1883. }
  1884. else
  1885. {
  1886. UINT pPacketToSendSize;
  1887. // Duplicate the original packet yet another time so we have an editable
  1888. // copy for this target adapter
  1889. pPacketToSend = BrdgFwdMakeCompatCopyPacket(pPacket, &pPacketToSendData, &pPacketToSendSize, FALSE);
  1890. }
  1891. if( pPacketToSend != NULL )
  1892. {
  1893. BrdgCompEditAndSendPacket( pPacketToSend, pPacketToSendData, SendList[i], pEditFunc, pData );
  1894. }
  1895. // Done with this adapter
  1896. BrdgReleaseAdapter( SendList[i] );
  1897. }
  1898. return bSentOriginal;
  1899. }
  1900. VOID
  1901. BrdgCompRefreshOrInsertIPEntry(
  1902. IN IPADDRESS IPAddr,
  1903. IN PADAPT pAdapt,
  1904. IN PUCHAR pMACAddr
  1905. )
  1906. /*++
  1907. Routine Description:
  1908. Inserts a new entry into the IP forwarding table or refreshes an existing entry
  1909. Arguments:
  1910. IPAddr The address to insert
  1911. pAdapt The adapter to associate with the IP address
  1912. pMACAddr The MAC address to associate with the IP address
  1913. Return Value:
  1914. None
  1915. --*/
  1916. {
  1917. PIP_TABLE_ENTRY pEntry;
  1918. BOOLEAN bIsNewEntry;
  1919. LOCK_STATE LockState;
  1920. if( BrdgCompIsUnicastIPAddress(IPAddr) )
  1921. {
  1922. pEntry = (PIP_TABLE_ENTRY)BrdgHashRefreshOrInsert( gIPForwardingTable, (PUCHAR)&IPAddr,
  1923. &bIsNewEntry, &LockState );
  1924. if( pEntry != NULL )
  1925. {
  1926. if( bIsNewEntry )
  1927. {
  1928. // This is a brand new table entry. Initialize it.
  1929. NdisAllocateSpinLock( &pEntry->lock );
  1930. pEntry->pAdapt = pAdapt;
  1931. ETH_COPY_NETWORK_ADDRESS( pEntry->macAddr, pMACAddr );
  1932. DBGPRINT(COMPAT, ("Learned the location of %i.%i.%i.%i\n", ((PUCHAR)&IPAddr)[3], ((PUCHAR)&IPAddr)[2],
  1933. ((PUCHAR)&IPAddr)[1], ((PUCHAR)&IPAddr)[0]));
  1934. }
  1935. else
  1936. {
  1937. // This is an existing entry and we may only have a read lock
  1938. // held on the hash table. Use the entry's spin lock to protect
  1939. // us while we monkey with the contents
  1940. NdisAcquireSpinLock( &pEntry->lock );
  1941. pEntry->pAdapt = pAdapt;
  1942. ETH_COPY_NETWORK_ADDRESS( pEntry->macAddr, pMACAddr );
  1943. NdisReleaseSpinLock( &pEntry->lock );
  1944. }
  1945. // Since we got a non-NULL result we must release the table lock
  1946. NdisReleaseReadWriteLock( &gIPForwardingTable->tableLock, &LockState );
  1947. }
  1948. }
  1949. else
  1950. {
  1951. //
  1952. // We shouldn't be getting called with non-unicast source IP addresses
  1953. //
  1954. THROTTLED_DBGPRINT(COMPAT, ("WARNING: Not noting non-unicast source IP address %i.%i.%i.%i from adapter %p!\n",
  1955. ((PUCHAR)&IPAddr)[3], ((PUCHAR)&IPAddr)[2], ((PUCHAR)&IPAddr)[1], ((PUCHAR)&IPAddr)[0],
  1956. pAdapt ));
  1957. }
  1958. }
  1959. PUCHAR
  1960. BrdgCompIsBootPPacket(
  1961. IN PUCHAR pPacketData,
  1962. IN UINT packetLen,
  1963. IN PIP_HEADER_INFO piphi
  1964. )
  1965. /*++
  1966. Routine Description:
  1967. Determines whether a given packet is a BOOTP packet
  1968. Arguments:
  1969. pPacketData Pointer to the packet's data buffer
  1970. packetLen Amount of data at pPacketDaa
  1971. piphi Info about the IP header of this packet
  1972. Return Value:
  1973. A pointer to the BOOTP payload within the packet, or NULL if the packet was not
  1974. a BOOTP Packet.
  1975. --*/
  1976. {
  1977. // After the IP header, there must be enough room for a UDP header and
  1978. // a basic BOOTP packet
  1979. if( packetLen < ETHERNET_HEADER_SIZE + (UINT)piphi->headerSize + SIZE_OF_UDP_HEADER +
  1980. SIZE_OF_BASIC_BOOTP_PACKET)
  1981. {
  1982. return NULL;
  1983. }
  1984. // Protocol must be UDP
  1985. if( piphi->protocol != UDP_PROTOCOL )
  1986. {
  1987. return NULL;
  1988. }
  1989. // Jump to the beginning of the UDP packet by skipping the IP header
  1990. pPacketData += ETHERNET_HEADER_SIZE + piphi->headerSize;
  1991. // The first two bytes are the source port and should be the
  1992. // BOOTP Client port (0x0044) or the BOOTP Server port (0x0043)
  1993. if( (pPacketData[0] != 00) ||
  1994. ((pPacketData[1] != 0x44) && (pPacketData[1] != 0x43)) )
  1995. {
  1996. return NULL;
  1997. }
  1998. // The next two bytes are the destination port and should be the BOOTP
  1999. // server port (0x0043) or the BOOTP client port (0x44)
  2000. if( (pPacketData[2] != 00) ||
  2001. ((pPacketData[3] != 0x43) && (pPacketData[3] != 0x44)) )
  2002. {
  2003. return NULL;
  2004. }
  2005. // Skip ahead to the beginning of the BOOTP packet
  2006. pPacketData += SIZE_OF_UDP_HEADER;
  2007. // The first byte is the op code and should be 0x01 for a request
  2008. // or 0x02 for a reply
  2009. if( pPacketData[0] > 0x02 )
  2010. {
  2011. return NULL;
  2012. }
  2013. // The next byte is the hardware type and should be 0x01 for Ethernet
  2014. if( pPacketData[1] != 0x01 )
  2015. {
  2016. return NULL;
  2017. }
  2018. // The next byte is the address length and should be 0x06 for Ethernet
  2019. if( pPacketData[2] != 0x06 )
  2020. {
  2021. return NULL;
  2022. }
  2023. // Everything checks out; this looks like a BOOTP request packet.
  2024. return pPacketData;
  2025. }
  2026. BOOLEAN
  2027. BrdgCompDecodeIPHeader(
  2028. IN PUCHAR pHeader,
  2029. OUT PIP_HEADER_INFO piphi
  2030. )
  2031. /*++
  2032. Routine Description:
  2033. Decodes basic information from the IP header (no options)
  2034. Arguments:
  2035. pHeader Pointer to an IP header
  2036. piphi Receives the info
  2037. Return Value:
  2038. TRUE: header was valid
  2039. FALSE: packet is not an IP packet
  2040. --*/
  2041. {
  2042. // First nibble of the header encodes the packet version, which must be 4.
  2043. if( (*pHeader >> 4) != 0x04 )
  2044. {
  2045. return FALSE;
  2046. }
  2047. // Next nibble of the header encodes the length of the header in 32-bit words.
  2048. // This length must be at least 20 bytes or something is amiss.
  2049. piphi->headerSize = (*pHeader & 0x0F) * 4;
  2050. if( piphi->headerSize < 20 )
  2051. {
  2052. return FALSE;
  2053. }
  2054. // Retrieve the protocol byte (offset 10)
  2055. piphi->protocol = pHeader[9];
  2056. // The source IP address begins at the 12th byte (most significant byte first)
  2057. piphi->ipSource = 0L;
  2058. piphi->ipSource |= pHeader[12] << 24;
  2059. piphi->ipSource |= pHeader[13] << 16;
  2060. piphi->ipSource |= pHeader[14] << 8;
  2061. piphi->ipSource |= pHeader[15];
  2062. // The destination IP address is next
  2063. piphi->ipTarget = 0L;
  2064. piphi->ipTarget |= pHeader[16] << 24;
  2065. piphi->ipTarget |= pHeader[17] << 16;
  2066. piphi->ipTarget |= pHeader[18] << 8;
  2067. piphi->ipTarget |= pHeader[19];
  2068. return TRUE;
  2069. }
  2070. BOOLEAN
  2071. BrdgCompDecodeARPPacket(
  2072. IN PUCHAR pPacketData,
  2073. IN UINT dataLen,
  2074. OUT PARPINFO pARPInfo
  2075. )
  2076. /*++
  2077. Routine Description:
  2078. Decodes an ARP packet
  2079. Arguments:
  2080. pPacketData Pointer to a packet's data buffer
  2081. dataLen Amount of data at pPacketData
  2082. pARPInfo Receives the info
  2083. Return Value:
  2084. TRUE: packet was valid
  2085. FALSE: packet is not an ARP packet
  2086. --*/
  2087. {
  2088. SAFEASSERT( pPacketData != NULL );
  2089. SAFEASSERT( pARPInfo != NULL );
  2090. // We can't process this if it's too small
  2091. if( dataLen < SIZE_OF_ARP_PACKET )
  2092. {
  2093. return FALSE;
  2094. }
  2095. // Check the ethertype for consistency (0x0806 is ARP)
  2096. if( (pPacketData[12] != 0x08) || (pPacketData[13] != 0x06) )
  2097. {
  2098. return FALSE;
  2099. }
  2100. // Check the hardware type for consistency (0x0001 is classic Ethernet;
  2101. // 802 has a seperate value)
  2102. if( (pPacketData[14] != 0x00) || (pPacketData[15] != 0x01) )
  2103. {
  2104. return FALSE;
  2105. }
  2106. // Check the protocol type for consistency (0x0800 is IPv4)
  2107. if( (pPacketData[16] != 0x08) || (pPacketData[17] != 0x00) )
  2108. {
  2109. return FALSE;
  2110. }
  2111. // Check the length of the hardware address for consistency (must be 6 bytes)
  2112. if( pPacketData[18] != 0x06 )
  2113. {
  2114. return FALSE;
  2115. }
  2116. // Check the length of the protocol address for consistency (must be 4 bytes)
  2117. if( pPacketData[19] != 0x04 )
  2118. {
  2119. return FALSE;
  2120. }
  2121. // Next two bytes are the operation (0x0001 == request, 0x0002 == reply)
  2122. if( pPacketData[20] != 0x00 )
  2123. {
  2124. return FALSE;
  2125. }
  2126. if( pPacketData[21] == 0x01 )
  2127. {
  2128. pARPInfo->type = ArpRequest;
  2129. }
  2130. else if( pPacketData[21] == 0x02 )
  2131. {
  2132. pARPInfo->type = ArpReply;
  2133. }
  2134. else
  2135. {
  2136. return FALSE;
  2137. }
  2138. // Next 6 bytes are the sender's MAC address
  2139. pARPInfo->macSource[0] = pPacketData[22];
  2140. pARPInfo->macSource[1] = pPacketData[23];
  2141. pARPInfo->macSource[2] = pPacketData[24];
  2142. pARPInfo->macSource[3] = pPacketData[25];
  2143. pARPInfo->macSource[4] = pPacketData[26];
  2144. pARPInfo->macSource[5] = pPacketData[27];
  2145. // Next 4 bytes are the sender's protocol address (most significant byte first)
  2146. pARPInfo->ipSource = 0;
  2147. pARPInfo->ipSource |= pPacketData[28] << 24;
  2148. pARPInfo->ipSource |= pPacketData[29] << 16;
  2149. pARPInfo->ipSource |= pPacketData[30] << 8;
  2150. pARPInfo->ipSource |= pPacketData[31];
  2151. //
  2152. // Next 6 bytes are the target's MAC address. For a request, these bytes are
  2153. // meaningless.
  2154. //
  2155. pARPInfo->macTarget[0] = pPacketData[32];
  2156. pARPInfo->macTarget[1] = pPacketData[33];
  2157. pARPInfo->macTarget[2] = pPacketData[34];
  2158. pARPInfo->macTarget[3] = pPacketData[35];
  2159. pARPInfo->macTarget[4] = pPacketData[36];
  2160. pARPInfo->macTarget[5] = pPacketData[37];
  2161. // Next 4 bytes are the sender's protocol address (most significant byte first)
  2162. pARPInfo->ipTarget = 0;
  2163. pARPInfo->ipTarget |= pPacketData[38] << 24;
  2164. pARPInfo->ipTarget |= pPacketData[39] << 16;
  2165. pARPInfo->ipTarget |= pPacketData[40] << 8;
  2166. pARPInfo->ipTarget |= pPacketData[41];
  2167. return TRUE;
  2168. }
  2169. VOID
  2170. BrdgCompTransmitDeferredARP(
  2171. IN PVOID pData
  2172. )
  2173. /*++
  2174. Routine Description:
  2175. Transmits an ARP packet whose transmission was deferred
  2176. Arguments:
  2177. pData Info on the deferred ARP packet to
  2178. be transmitted
  2179. Return Value:
  2180. None
  2181. --*/
  2182. {
  2183. PDEFERRED_ARP pda = (PDEFERRED_ARP)pData;
  2184. BrdgCompTransmitARPPacket( pda->pTargetAdapt, &pda->ai );
  2185. // We incremented this adapter's refcount when setting up the
  2186. // function deferral
  2187. BrdgReleaseAdapter( pda->pTargetAdapt );
  2188. // Free the memory for this request
  2189. NdisFreeMemory( pda, sizeof(DEFERRED_ARP), 0 );
  2190. }
  2191. VOID
  2192. BrdgCompTransmitARPPacket(
  2193. IN PADAPT pAdapt,
  2194. IN PARPINFO pARPInfo
  2195. )
  2196. /*++
  2197. Routine Description:
  2198. Transmits an ARP packet
  2199. Arguments:
  2200. pAdapt Adapter to transmit on
  2201. pARPInfo The info to transmit as an ARP packet
  2202. Return Value:
  2203. None
  2204. --*/
  2205. {
  2206. NDIS_STATUS Status;
  2207. UCHAR ARPPacket[SIZE_OF_ARP_PACKET];
  2208. SAFEASSERT( pAdapt != NULL );
  2209. SAFEASSERT( pARPInfo != NULL );
  2210. SAFEASSERT( (pARPInfo->type == ArpRequest) || (pARPInfo->type == ArpReply) );
  2211. //
  2212. // Fill in the destination MAC address. If the operation is a discovery,
  2213. // the target MAC address is the broadcast address. If it is a reply, the
  2214. // target MAC address is the target machine's MAC address.
  2215. //
  2216. if( pARPInfo->type == ArpRequest )
  2217. {
  2218. ARPPacket[0] = ARPPacket[1] = ARPPacket[2] = ARPPacket[3] =
  2219. ARPPacket[4] = ARPPacket[5] = 0xFF;
  2220. }
  2221. else
  2222. {
  2223. ARPPacket[0] = pARPInfo->macTarget[0];
  2224. ARPPacket[1] = pARPInfo->macTarget[1];
  2225. ARPPacket[2] = pARPInfo->macTarget[2];
  2226. ARPPacket[3] = pARPInfo->macTarget[3];
  2227. ARPPacket[4] = pARPInfo->macTarget[4];
  2228. ARPPacket[5] = pARPInfo->macTarget[5];
  2229. }
  2230. // Fill in the source MAC address
  2231. ARPPacket[6] = pARPInfo->macSource[0];
  2232. ARPPacket[7] = pARPInfo->macSource[1];
  2233. ARPPacket[8] = pARPInfo->macSource[2];
  2234. ARPPacket[9] = pARPInfo->macSource[3];
  2235. ARPPacket[10] = pARPInfo->macSource[4];
  2236. ARPPacket[11] = pARPInfo->macSource[5];
  2237. // Next 2 bytes are the EtherType (0x0806 == ARP)
  2238. ARPPacket[12] = 0x08;
  2239. ARPPacket[13] = 0x06;
  2240. // Next 2 bytes are 0x0001 for classic Ethernet
  2241. // (802 has a seperate value)
  2242. ARPPacket[14] = 0x00;
  2243. ARPPacket[15] = 0x01;
  2244. // Next 2 bytes indicate that this is ARP for IPv4 traffic
  2245. ARPPacket[16] = 0x08;
  2246. ARPPacket[17] = 0x00;
  2247. // Next byte indicates the length of the hardware address (6 bytes)
  2248. ARPPacket[18] = 0x6;
  2249. // Next byte indicates the length of the protocol address (4 bytes)
  2250. ARPPacket[19] = 0x4;
  2251. // Next byte is the operation (1 == request, 2 == reply)
  2252. if( pARPInfo->type == ArpRequest )
  2253. {
  2254. ARPPacket[20] = 0x00;
  2255. ARPPacket[21] = 0x01;
  2256. }
  2257. else
  2258. {
  2259. ARPPacket[20] = 0x00;
  2260. ARPPacket[21] = 0x02;
  2261. }
  2262. // Next 6 bytes are the sender's MAC address (LSB first)
  2263. ARPPacket[22] = pARPInfo->macSource[0];
  2264. ARPPacket[23] = pARPInfo->macSource[1];
  2265. ARPPacket[24] = pARPInfo->macSource[2];
  2266. ARPPacket[25] = pARPInfo->macSource[3];
  2267. ARPPacket[26] = pARPInfo->macSource[4];
  2268. ARPPacket[27] = pARPInfo->macSource[5];
  2269. // Next 4 bytes are the sender's protocol address (most significant byte first)
  2270. ARPPacket[28] = (UCHAR)((pARPInfo->ipSource >> 24) & 0xFF);
  2271. ARPPacket[29] = (UCHAR)((pARPInfo->ipSource >> 16) & 0xFF);
  2272. ARPPacket[30] = (UCHAR)((pARPInfo->ipSource >> 8) & 0xFF);
  2273. ARPPacket[31] = (UCHAR)(pARPInfo->ipSource & 0xFF);
  2274. //
  2275. // Next 6 bytes are the target's MAC address. For a request, these bytes are
  2276. // ignored and set to zero.
  2277. //
  2278. if( pARPInfo->type == ArpRequest )
  2279. {
  2280. ARPPacket[32] = ARPPacket[33] = ARPPacket[34] = ARPPacket[35] =
  2281. ARPPacket[36] = ARPPacket[37] = 0x00;
  2282. }
  2283. else
  2284. {
  2285. // MAC address is transmitted LSB first.
  2286. ARPPacket[32] = pARPInfo->macTarget[0];
  2287. ARPPacket[33] = pARPInfo->macTarget[1];
  2288. ARPPacket[34] = pARPInfo->macTarget[2];
  2289. ARPPacket[35] = pARPInfo->macTarget[3];
  2290. ARPPacket[36] = pARPInfo->macTarget[4];
  2291. ARPPacket[37] = pARPInfo->macTarget[5];
  2292. }
  2293. // Next 4 bytes are the target's protocol address (most significant byte first)
  2294. ARPPacket[38] = (UCHAR)((pARPInfo->ipTarget >> 24) & 0xFF);
  2295. ARPPacket[39] = (UCHAR)((pARPInfo->ipTarget >> 16) & 0xFF);
  2296. ARPPacket[40] = (UCHAR)((pARPInfo->ipTarget >> 8) & 0xFF);
  2297. ARPPacket[41] = (UCHAR)(pARPInfo->ipTarget & 0xFF);
  2298. // Send the finished packet
  2299. Status = BrdgFwdSendBuffer( pAdapt, ARPPacket, sizeof(ARPPacket) );
  2300. if( Status != NDIS_STATUS_SUCCESS )
  2301. {
  2302. THROTTLED_DBGPRINT(COMPAT, ("ARP packet send failed: %08x\n", Status));
  2303. }
  2304. }
  2305. //
  2306. // pTargetAdapt comes back with incremented refcount if
  2307. // *pbIsRequest == FALSE and *pTargetAdapt != NULL
  2308. //
  2309. BOOLEAN
  2310. BrdgCompPreprocessBootPPacket(
  2311. IN PUCHAR pPacketData,
  2312. IN PIP_HEADER_INFO piphi,
  2313. IN PUCHAR pBootPData, // Actual BOOTP packet
  2314. IN PADAPT pAdapt, // Receiving adapt (or NULL for outbound from local machine)
  2315. OUT PBOOLEAN pbIsRequest,
  2316. OUT PADAPT *ppTargetAdapt, // Only if bIsRequest == FALSE
  2317. OUT PUCHAR targetMAC // Only if bIsRequest == FALSE
  2318. )
  2319. /*++
  2320. Routine Description:
  2321. Does preliminary processing of a BOOTP packet common to the inbound and outbound case
  2322. Arguments:
  2323. pPacketData Pointer to a packet's data buffer
  2324. piphi Info on the packet's IP header
  2325. pBootPData Pointer to the BOOTP payload within the packet
  2326. pAdapt Receiving adapter (or NULL if this packet is outbound from
  2327. the local machine)
  2328. pbIsRequest Receives a flag indicating if this is a BOOTP request
  2329. ppTargetAdapt Receives the target adapter this packet should be relayed to
  2330. (only valid if bIsRequest == FALSE and return == TRUE)
  2331. targetMAC The MAC address this packet should be relayed to (valid under
  2332. same conditions as ppTargetAdapt)
  2333. Return Value:
  2334. TRUE : packet was processed successfully
  2335. FALSE : an error occured or something is wrong with the packet
  2336. --*/
  2337. {
  2338. PDHCP_TABLE_ENTRY pEntry;
  2339. ULONG xid;
  2340. LOCK_STATE LockState;
  2341. SAFEASSERT( pbIsRequest != NULL );
  2342. SAFEASSERT( ppTargetAdapt != NULL );
  2343. SAFEASSERT( targetMAC != NULL );
  2344. // Decode the xid (bytes 5 through 8)
  2345. xid = 0L;
  2346. xid |= pBootPData[4] << 24;
  2347. xid |= pBootPData[5] << 16;
  2348. xid |= pBootPData[6] << 8;
  2349. xid |= pBootPData[7];
  2350. // Byte 0 is the operation; 1 for a request, 2 for a reply
  2351. if( pBootPData[0] == 0x01 )
  2352. {
  2353. BOOLEAN bIsNewEntry;
  2354. // This is a request. We need to note the correspondence betweeen
  2355. // this client's XID and its adapter and MAC address
  2356. pEntry = (PDHCP_TABLE_ENTRY)BrdgHashRefreshOrInsert( gPendingDHCPTable, (PUCHAR)&xid, &bIsNewEntry,
  2357. &LockState );
  2358. if( pEntry != NULL )
  2359. {
  2360. if( bIsNewEntry )
  2361. {
  2362. // Initialize the entry.
  2363. // The client's hardware address is at offset 29
  2364. NdisAllocateSpinLock( &pEntry->lock );
  2365. ETH_COPY_NETWORK_ADDRESS( pEntry->requestorMAC, &pBootPData[28] );
  2366. pEntry->pRequestorAdapt = pAdapt; // Can be NULL for local machine
  2367. DBGPRINT(COMPAT, ("Saw new DHCP XID: %x\n", xid));
  2368. }
  2369. else
  2370. {
  2371. //
  2372. // An entry already existed for this XID. This is fine if the existing information
  2373. // matches what we're trying to record, but it's also possible that two stations
  2374. // decided independently to use the same XID, or that the same station changed
  2375. // apparent MAC address and/or adapter due to topology changes. Our scheme breaks
  2376. // down under these circumstances.
  2377. //
  2378. // Either way, use the most recent information possible; clobber the existing
  2379. // information with the latest.
  2380. //
  2381. NdisAcquireSpinLock( &pEntry->lock );
  2382. #if DBG
  2383. {
  2384. UINT Result;
  2385. ETH_COMPARE_NETWORK_ADDRESSES_EQ( pEntry->requestorMAC, &pBootPData[28], &Result );
  2386. // Warn if the data changed, as this probably signals a problem
  2387. if( Result != 0 )
  2388. {
  2389. DBGPRINT(COMPAT, ("[COMPAT] WARNING: Station with MAC address %02x:%02x:%02x:%02x:%02x:%02x is using DHCP XID %x at the same time as station %02x:%02x:%02x:%02x:%02x:%02x!\n",
  2390. pBootPData[28], pBootPData[29], pBootPData[30], pBootPData[31], pBootPData[32], pBootPData[33],
  2391. xid, pEntry->requestorMAC[0], pEntry->requestorMAC[1], pEntry->requestorMAC[2],
  2392. pEntry->requestorMAC[3], pEntry->requestorMAC[4], pEntry->requestorMAC[5] ));
  2393. }
  2394. else if( pEntry->pRequestorAdapt != pAdapt )
  2395. {
  2396. DBGPRINT(COMPAT, ("[COMPAT] WARNING: Station with MAC address %02x:%02x:%02x:%02x:%02x:%02x appeared to change from adapter %p to adapter %p during DHCP request!\n",
  2397. pBootPData[28], pBootPData[29], pBootPData[30],
  2398. pBootPData[31], pBootPData[32], pBootPData[33],
  2399. pEntry->pRequestorAdapt, pAdapt ));
  2400. }
  2401. }
  2402. #endif
  2403. ETH_COPY_NETWORK_ADDRESS( pEntry->requestorMAC, &pBootPData[28] );
  2404. pEntry->pRequestorAdapt = pAdapt; // Can be NULL for local machine
  2405. NdisReleaseSpinLock( &pEntry->lock );
  2406. }
  2407. NdisReleaseReadWriteLock( &gPendingDHCPTable->tableLock, &LockState );
  2408. }
  2409. else
  2410. {
  2411. // This packet could not be processed
  2412. DBGPRINT(COMPAT, ("Couldn't create table entry for BOOTP packet!\n"));
  2413. return FALSE;
  2414. }
  2415. *pbIsRequest = TRUE;
  2416. // ppTargetAdapt and targetMAC are not defined for this case
  2417. return TRUE;
  2418. }
  2419. else if ( pBootPData[0] == 0x02 )
  2420. {
  2421. // Look up the xid for this transaction to recover the MAC address of the client
  2422. pEntry = (PDHCP_TABLE_ENTRY)BrdgHashFindEntry( gPendingDHCPTable, (PUCHAR)&xid, &LockState );
  2423. if( pEntry != NULL )
  2424. {
  2425. NdisAcquireSpinLock( &pEntry->lock );
  2426. ETH_COPY_NETWORK_ADDRESS( targetMAC, pEntry->requestorMAC );
  2427. *ppTargetAdapt = pEntry->pRequestorAdapt;
  2428. NdisReleaseSpinLock( &pEntry->lock );
  2429. //
  2430. // We will use this adapter outside the table lock. NULL is a permissible
  2431. // value that indicates that the local machine is the requestor for
  2432. // this xid.
  2433. //
  2434. if( *ppTargetAdapt != NULL )
  2435. {
  2436. BrdgAcquireAdapterInLock( *ppTargetAdapt );
  2437. }
  2438. NdisReleaseReadWriteLock( &gPendingDHCPTable->tableLock, &LockState );
  2439. }
  2440. if( pEntry != NULL )
  2441. {
  2442. *pbIsRequest = FALSE;
  2443. return TRUE;
  2444. }
  2445. else
  2446. {
  2447. DBGPRINT(COMPAT, ("Couldn't find a table entry for XID %x!\n", xid));
  2448. return FALSE;
  2449. }
  2450. }
  2451. else
  2452. {
  2453. // Someone passed us a crummy packet
  2454. return FALSE;
  2455. }
  2456. }
  2457. // ===========================================================================
  2458. //
  2459. // INBOUND PACKET PROCESSING
  2460. //
  2461. // ===========================================================================
  2462. VOID
  2463. BrdgCompSendProxyARPRequests(
  2464. IN PARPINFO pai,
  2465. IN PADAPT pOriginalAdapt,
  2466. IN BOOLEAN bSendToNonCompat
  2467. )
  2468. /*++
  2469. Routine Description:
  2470. Floods ARP requests out appropriate adapters in response to an ARP request
  2471. for which we did not have information about the target.
  2472. Arguments:
  2473. pai Info on the inbound request
  2474. pOriginalAdapt Adapter the request was indicated on
  2475. bSendToNonCompat Whether we need to send the request to all adapters
  2476. or just compatibility adapters
  2477. Return Value:
  2478. None
  2479. --*/
  2480. {
  2481. UINT numTargets = 0L, i;
  2482. PADAPT pAdapt;
  2483. PADAPT SendList[MAX_ADAPTERS];
  2484. LOCK_STATE LockState;
  2485. SAFEASSERT( pai->type == ArpRequest );
  2486. //
  2487. // First we need a list of the adapters we intend to send this packet to
  2488. //
  2489. NdisAcquireReadWriteLock( &gAdapterListLock, FALSE /*Read only*/, &LockState );
  2490. // Note each adapter to send to
  2491. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  2492. {
  2493. // Don't need to acquire the global adapter characteristics lock to read the
  2494. // media state because we don't care about the global consistency of the
  2495. // adapters' characteristics here
  2496. if( (pAdapt != pOriginalAdapt ) && // Don't send on the original adapter
  2497. (pAdapt->MediaState == NdisMediaStateConnected) && // Don't send to disconnected adapters
  2498. (pAdapt->State == Forwarding) && // Adapter must be in relaying state
  2499. (! pAdapt->bResetting) ) // Adapter must not be resetting
  2500. {
  2501. // If we're not trying to send to every single adapter, make sure
  2502. // this one is in compatibility mode
  2503. if( bSendToNonCompat || (pAdapt->bCompatibilityMode) )
  2504. {
  2505. if( numTargets < MAX_ADAPTERS )
  2506. {
  2507. // We will use this adapter outside the list lock; bump its refcount
  2508. BrdgAcquireAdapterInLock(pAdapt);
  2509. SendList[numTargets] = pAdapt;
  2510. numTargets++;
  2511. }
  2512. else
  2513. {
  2514. // Too many copies to send!
  2515. SAFEASSERT( FALSE );
  2516. }
  2517. }
  2518. }
  2519. }
  2520. // Can let go of the adapter list now; we have copied out all the target adapters
  2521. // and incremented the refcount for the adapters we will be using.
  2522. NdisReleaseReadWriteLock( &gAdapterListLock, &LockState );
  2523. for( i = 0; i < numTargets; i++ )
  2524. {
  2525. // For each adapter, the source MAC address is the adapter's MAC address
  2526. ETH_COPY_NETWORK_ADDRESS( pai->macSource, SendList[i]->MACAddr );
  2527. // Send the ARP request
  2528. BrdgCompTransmitARPPacket( SendList[i], pai );
  2529. // Done with this adapter
  2530. BrdgReleaseAdapter( SendList[i] );
  2531. }
  2532. }
  2533. VOID
  2534. BrdgCompAnswerPendingARP(
  2535. IN PHASH_TABLE_ENTRY pEntry,
  2536. IN PVOID pData
  2537. )
  2538. /*++
  2539. Routine Description:
  2540. Sends a reply to a station that is waiting for an ARP reply. Called when we find
  2541. an entry to this effect in our pending-ARP table.
  2542. We do not send an ARP reply to the discovering station if it turns out that the
  2543. station it is looking for is on the same segment as it.
  2544. Arguments:
  2545. pEntry The entry in the pending-ARP table telling us about
  2546. the station waiting for information
  2547. pData The adapter we received an ARP reply on that
  2548. triggered this operation
  2549. Return Value:
  2550. None
  2551. --*/
  2552. {
  2553. PARP_TABLE_ENTRY pate = (PARP_TABLE_ENTRY)pEntry;
  2554. PADAPT pReceivedAdapt = (PADAPT)pData;
  2555. PARP_TABLE_KEY pKey;
  2556. pKey = (PARP_TABLE_KEY)pate->hte.key;
  2557. if( pKey->ipReqestor != 0L )
  2558. {
  2559. PADAPT pOriginalAdapt;
  2560. UCHAR originalMAC[ETH_LENGTH_OF_ADDRESS];
  2561. // Copy the information out of the table entry
  2562. NdisAcquireSpinLock( &pate->lock );
  2563. pOriginalAdapt = pate->pOriginalAdapt;
  2564. ETH_COPY_NETWORK_ADDRESS( originalMAC, pate->originalMAC );
  2565. NdisReleaseSpinLock( &pate->lock );
  2566. //
  2567. // The station we just discovered must be on a different segment
  2568. // from the discovering station for us to send back a reply.
  2569. //
  2570. if( pOriginalAdapt != pReceivedAdapt )
  2571. {
  2572. PDEFERRED_ARP pda;
  2573. NDIS_STATUS Status;
  2574. // The adapters are different. We should send a reply.
  2575. // We need to defer the actual transmission of the reply so we
  2576. // don't perform it with a lock held on the pending ARP
  2577. // table.
  2578. Status = NdisAllocateMemoryWithTag( &pda, sizeof(DEFERRED_ARP), 'gdrB' );
  2579. if( Status == NDIS_STATUS_SUCCESS )
  2580. {
  2581. pda->pTargetAdapt = pOriginalAdapt;
  2582. // We will use the adapter pointer outside the table lock
  2583. BrdgAcquireAdapterInLock( pda->pTargetAdapt );
  2584. pda->ai.ipTarget = pKey->ipReqestor;
  2585. ETH_COPY_NETWORK_ADDRESS( pda->ai.macTarget, originalMAC );
  2586. // Pretend to be the IP address the requestor is looking for
  2587. pda->ai.ipSource = pKey->ipTarget;
  2588. ETH_COPY_NETWORK_ADDRESS( pda->ai.macSource, pda->pTargetAdapt->MACAddr );
  2589. pda->ai.type = ArpReply;
  2590. // Queue up the call to BrdgCompTransmitDeferredARP
  2591. BrdgDeferFunction( BrdgCompTransmitDeferredARP, pda );
  2592. }
  2593. else
  2594. {
  2595. // We failed the allocation. Not much we can do.
  2596. DBGPRINT(COMPAT, ("Memory allocation failed in BrdgCompAnswerPendingARP!\n"));
  2597. }
  2598. }
  2599. // else the discovering station and the station we discovered are on the same
  2600. // adapter; don't reply.
  2601. }
  2602. else
  2603. {
  2604. // This entry exists only to indicate that the local machine is also trying to discover
  2605. // this IP address. Ignore it.
  2606. }
  2607. }
  2608. BOOLEAN
  2609. BrdgCompIndicateInboundARPReply(
  2610. IN PNDIS_PACKET pPacket,
  2611. IN PADAPT pAdapt,
  2612. IN BOOLEAN bCanRetain,
  2613. IN PUCHAR pPacketData,
  2614. IN UINT packetLen
  2615. )
  2616. /*++
  2617. Routine Description:
  2618. Indicates an ARP reply to the local machine
  2619. Arguments:
  2620. pPacket The ARP reply packet
  2621. pAdapt The receiving adapter
  2622. bCanRetain If we can retain the packet
  2623. pPacketData The packet's data buffer
  2624. packetLen Size of data in buffer
  2625. Return Value:
  2626. Whether we retained the packet
  2627. --*/
  2628. {
  2629. PUCHAR pTargetMAC;
  2630. UINT Result;
  2631. if( ! bCanRetain )
  2632. {
  2633. // We're not allowed to use the packet we're given to indicate.
  2634. // Allocate a new one to hold the data.
  2635. pPacket = BrdgFwdMakeCompatCopyPacket( pPacket, &pPacketData, &packetLen, FALSE );
  2636. if( pPacket == NULL )
  2637. {
  2638. // We failed to get a packet.
  2639. return FALSE;
  2640. }
  2641. }
  2642. // Rewrite the target MAC address in the ARP reply. This portion
  2643. // of the packet is at offset 32.
  2644. pTargetMAC = pPacketData + 32;
  2645. // Check to see if the target MAC address is the adapter's MAC address,
  2646. // as it should be
  2647. ETH_COMPARE_NETWORK_ADDRESSES_EQ( pTargetMAC, pAdapt->MACAddr, &Result );
  2648. if( Result == 0 )
  2649. {
  2650. // Rewrite the target MAC address to the bridge's MAC address
  2651. ETH_COPY_NETWORK_ADDRESS( pTargetMAC, gCompMACAddress );
  2652. }
  2653. else
  2654. {
  2655. DBGPRINT(COMPAT, ("WARNING: Mismatch between frame MAC target and ARP payload target in ARP reply!\n"));
  2656. }
  2657. BrdgCompIndicatePacket( pPacket, pPacketData, pAdapt );
  2658. return bCanRetain;
  2659. }
  2660. PADAPT
  2661. BrdgCompFindTargetAdapterForIPAddress(
  2662. IN PNDIS_PACKET pPacket)
  2663. /*++
  2664. Routine Description:
  2665. Finds the correct target adapter based on the IP address
  2666. Arguments:
  2667. pPacket The IP packet containing the address information.
  2668. Return Value:
  2669. The TargetAdapter if we found one in the table, or NULL if we did not.
  2670. --*/
  2671. {
  2672. PIP_TABLE_ENTRY pipte = NULL;
  2673. LOCK_STATE LockState;
  2674. PADAPT TargetAdapt = NULL;
  2675. IP_HEADER_INFO iphi;
  2676. PNDIS_BUFFER pBuffer;
  2677. PUCHAR pPacketData;
  2678. UINT packetLen = 0;
  2679. UINT totLen;
  2680. USHORT etherType;
  2681. NdisGetFirstBufferFromPacketSafe( pPacket, &pBuffer, &pPacketData, &packetLen,
  2682. &totLen, NormalPagePriority );
  2683. if( pPacketData == NULL )
  2684. {
  2685. // The packet was empty or the system is under severe memory pressure
  2686. // We didn't retain the packet.
  2687. return NULL;
  2688. }
  2689. if( totLen < ETHERNET_HEADER_SIZE )
  2690. {
  2691. return NULL;
  2692. }
  2693. // The packet should be flat
  2694. SAFEASSERT( totLen == packetLen );
  2695. etherType = BrdgCompGetEtherType( pPacketData );
  2696. if( etherType == IP_ETHERTYPE )
  2697. {
  2698. SAFEASSERT( (pPacket != NULL) && (pPacketData != NULL) );
  2699. if( packetLen >= MINIMUM_SIZE_FOR_IP )
  2700. {
  2701. if( BrdgCompDecodeIPHeader(pPacketData + ETHERNET_HEADER_SIZE, &iphi) )
  2702. {
  2703. pipte = (PIP_TABLE_ENTRY)BrdgHashFindEntry( gIPForwardingTable, (PUCHAR)&iphi.ipTarget,
  2704. &LockState );
  2705. if (pipte != NULL)
  2706. {
  2707. TargetAdapt = pipte->pAdapt;
  2708. // Release the table lock.
  2709. NdisReleaseReadWriteLock( &gIPForwardingTable->tableLock, &LockState );
  2710. }
  2711. }
  2712. }
  2713. }
  2714. return TargetAdapt;
  2715. }
  2716. BOOLEAN
  2717. BrdgCompProcessInboundARPRequest(
  2718. IN PARPINFO pai,
  2719. IN PNDIS_PACKET pPacket,
  2720. IN PADAPT pAdapt,
  2721. IN BOOLEAN bCanRetain,
  2722. IN PUCHAR pPacketData,
  2723. IN UINT packetLen
  2724. )
  2725. /*++
  2726. Routine Description:
  2727. Processes an inbound ARP request
  2728. Arguments:
  2729. pai The decoded info
  2730. pPacket The ARP request packet
  2731. pAdapt The receiving adapter
  2732. bCanRetain If we can retain the packet
  2733. pPacketData The packet's data buffer
  2734. packetLen Size of data in buffer
  2735. Return Value:
  2736. Whether we retained the packet
  2737. --*/
  2738. {
  2739. PIP_TABLE_ENTRY pipte;
  2740. LOCK_STATE LockState;
  2741. BOOLEAN bSendReply = FALSE;
  2742. SAFEASSERT( pai->type == ArpRequest );
  2743. // See if we already have the target IP address in our table
  2744. pipte = (PIP_TABLE_ENTRY)BrdgHashFindEntry( gIPForwardingTable, (PUCHAR)&pai->ipTarget,
  2745. &LockState );
  2746. if( pipte != NULL )
  2747. {
  2748. //
  2749. // Compare the adapter the target is reachable on to the adapter that
  2750. // we got the request on while we still have the table lock.
  2751. //
  2752. // We should only send an ARP reply if the requesting station is on
  2753. // a different adapter than the station he is trying to discover.
  2754. //
  2755. bSendReply = (BOOLEAN)(pipte->pAdapt != pAdapt);
  2756. // Release the table lock.
  2757. NdisReleaseReadWriteLock( &gIPForwardingTable->tableLock, &LockState );
  2758. }
  2759. if( bSendReply )
  2760. {
  2761. IPADDRESS ipTransmitter = pai->ipSource;
  2762. DBGPRINT(COMPAT, ("ANSWERING ARP request for %i.%i.%i.%i\n",
  2763. ((PUCHAR)&pai->ipTarget)[3], ((PUCHAR)&pai->ipTarget)[2],
  2764. ((PUCHAR)&pai->ipTarget)[1], ((PUCHAR)&pai->ipTarget)[0] ));
  2765. // We found the target station. Use our ARPINFO structure to build a
  2766. // reply right back to the sending station.
  2767. pai->type = ArpReply;
  2768. // Pretend to be the IP station the transmitting station is asking for
  2769. pai->ipSource = pai->ipTarget;
  2770. // Send to the requesting station
  2771. ETH_COPY_NETWORK_ADDRESS( pai->macTarget, pai->macSource );
  2772. pai->ipTarget = ipTransmitter;
  2773. // Fill in the adapter's own MAC address as the source
  2774. ETH_COPY_NETWORK_ADDRESS( pai->macSource, pAdapt->MACAddr );
  2775. // Transmit the answer right now!
  2776. BrdgCompTransmitARPPacket( pAdapt, pai );
  2777. }
  2778. else
  2779. {
  2780. // We didn't find the address the transmitting station is asking for.
  2781. // We'll need to proxy the request onto other adapters to discover
  2782. // the target station.
  2783. // We need to proxy onto regular adapters too if the original adapter
  2784. // was compatibility-mode.
  2785. BOOLEAN bSendToNonCompat = pAdapt->bCompatibilityMode;
  2786. PARP_TABLE_ENTRY pEntry;
  2787. LOCK_STATE LockState;
  2788. BOOLEAN bIsNewEntry;
  2789. ARP_TABLE_KEY atk;
  2790. // Record the fact that we've proxied out this request
  2791. atk.ipReqestor = pai->ipSource;
  2792. atk.ipTarget = pai->ipTarget;
  2793. pEntry = (PARP_TABLE_ENTRY)BrdgHashRefreshOrInsert( gPendingARPTable, (PUCHAR)&atk,
  2794. &bIsNewEntry, &LockState );
  2795. if( pEntry != NULL )
  2796. {
  2797. if( bIsNewEntry )
  2798. {
  2799. // This is a new table entry, as expected. Initialize it.
  2800. NdisAllocateSpinLock( &pEntry->lock );
  2801. pEntry->pOriginalAdapt = pAdapt;
  2802. ETH_COPY_NETWORK_ADDRESS( pEntry->originalMAC, pai->macSource );
  2803. }
  2804. else
  2805. {
  2806. // There was already a pending-ARP entry for this source and target
  2807. // IP address. Refresh the information in the entry on the slim
  2808. // chance that the requesting machine has changed apparent MAC
  2809. // address or adapter due to topology changes or the like.
  2810. NdisAcquireSpinLock( &pEntry->lock );
  2811. pEntry->pOriginalAdapt = pAdapt;
  2812. ETH_COPY_NETWORK_ADDRESS( pEntry->originalMAC, pai->macSource );
  2813. NdisReleaseSpinLock( &pEntry->lock );
  2814. }
  2815. // We are responsible for releasing the table lock since
  2816. // BrdgHashRefreshOrInsert() came back non-NULL
  2817. NdisReleaseReadWriteLock( &gPendingARPTable->tableLock, &LockState );
  2818. }
  2819. // This function twiddles the ARPINFO structure you pass it,
  2820. // but that's OK by us.
  2821. BrdgCompSendProxyARPRequests( pai, pAdapt, bSendToNonCompat );
  2822. }
  2823. // Always indicate ARP requests to the local machine so it can note the
  2824. // information about the sender and reply if it wants.
  2825. return BrdgCompIndicatePacketOrPacketCopy( pPacket, pPacketData, bCanRetain, pAdapt, NULL, NULL );
  2826. }
  2827. // Returns whether the packet was retained
  2828. BOOLEAN
  2829. BrdgCompProcessInboundARPPacket(
  2830. IN PNDIS_PACKET pPacket,
  2831. IN PADAPT pAdapt,
  2832. IN BOOLEAN bCanRetain,
  2833. IN PUCHAR pPacketData,
  2834. IN UINT packetLen
  2835. )
  2836. /*++
  2837. Routine Description:
  2838. Processes an inbound ARP packet
  2839. Arguments:
  2840. pPacket The ARP request packet
  2841. pAdapt The receiving adapter
  2842. bCanRetain If we can retain the packet
  2843. pPacketData The packet's data buffer
  2844. packetLen Size of data in buffer
  2845. Return Value:
  2846. Whether we retained the packet
  2847. --*/
  2848. {
  2849. ARPINFO ai;
  2850. if( BrdgCompDecodeARPPacket(pPacketData, packetLen, &ai) )
  2851. {
  2852. BOOLEAN bRetained;
  2853. // Regardless of what kind of packet this is, we always note
  2854. // the correspondence between the sender's IP address and
  2855. // MAC address.
  2856. BrdgCompRefreshOrInsertIPEntry( ai.ipSource, pAdapt, ai.macSource );
  2857. // Always see if the information we just learned would let us
  2858. // proxy back a reply to a station doing a discovery.
  2859. BrdgHashPrefixMultiMatch( gPendingARPTable, (PUCHAR)&ai.ipSource, sizeof(IPADDRESS),
  2860. BrdgCompAnswerPendingARP, pAdapt );
  2861. if( ai.type == ArpReply )
  2862. {
  2863. BOOLEAN bIndicateReply;
  2864. ARP_TABLE_KEY atk;
  2865. LOCK_STATE LockState;
  2866. //
  2867. // The packet is an ARP reply.
  2868. //
  2869. // See if there's a table entry indicating that the local machine is trying to
  2870. // resolve this target address
  2871. atk.ipTarget = ai.ipSource;
  2872. atk.ipReqestor = 0L;
  2873. if( BrdgHashFindEntry(gPendingARPTable, (PUCHAR)&atk, &LockState) != NULL )
  2874. {
  2875. bIndicateReply = TRUE;
  2876. NdisReleaseReadWriteLock( &gPendingARPTable->tableLock, &LockState );
  2877. }
  2878. else
  2879. {
  2880. bIndicateReply = FALSE;
  2881. }
  2882. // We can't indicate the reply if we don't have the bridge's overall
  2883. // MAC address available
  2884. if( bIndicateReply && gCompHaveMACAddress )
  2885. {
  2886. bRetained = BrdgCompIndicateInboundARPReply( pPacket, pAdapt, bCanRetain, pPacketData, packetLen );
  2887. }
  2888. else
  2889. {
  2890. bRetained = FALSE;
  2891. }
  2892. }
  2893. else
  2894. {
  2895. //
  2896. // The packet is an ARP request.
  2897. //
  2898. // This function trashes ai, but that's OK.
  2899. bRetained = BrdgCompProcessInboundARPRequest( &ai, pPacket, pAdapt, bCanRetain, pPacketData, packetLen );
  2900. }
  2901. // Sanity
  2902. if( ! bCanRetain )
  2903. {
  2904. SAFEASSERT( !bRetained );
  2905. }
  2906. return bRetained;
  2907. }
  2908. else
  2909. {
  2910. // The inbound ARP packet is somehow invalid. Process it as a regular packet
  2911. // (which should indicate it to the local machine) in case it's carrying something
  2912. // we don't understand.
  2913. return BrdgCompProcessInboundNonARPPacket( pPacket, pAdapt, bCanRetain, pPacketData, packetLen );
  2914. }
  2915. }
  2916. BOOLEAN
  2917. BrdgCompProcessInboundIPPacket(
  2918. IN PNDIS_PACKET pPacket,
  2919. IN PIP_HEADER_INFO piphi,
  2920. IN PADAPT pAdapt,
  2921. IN BOOLEAN bCanRetain,
  2922. IN PUCHAR pPacketData,
  2923. IN UINT packetLen,
  2924. IN PPER_ADAPT_EDIT_FUNC pEditFunc,
  2925. IN PVOID pData
  2926. )
  2927. /*++
  2928. Routine Description:
  2929. Processes an inbound IP packet
  2930. Arguments:
  2931. pPacket The IP packet
  2932. piphi Decoded IP header information
  2933. pAdapt The receiving adapter
  2934. bCanRetain If we can retain the packet
  2935. pPacketData The packet's data buffer
  2936. packetLen Size of data in buffer
  2937. pEditFunc Optional function that must be called
  2938. for each adapter before transmission
  2939. pData Context cookie for pEditFunc
  2940. Return Value:
  2941. Whether we retained the packet
  2942. --*/
  2943. {
  2944. BOOLEAN bRetained;
  2945. PIP_TABLE_ENTRY pipte;
  2946. LOCK_STATE LockState;
  2947. //
  2948. // We refresh our forwarding table with each IP packet we see. Find the entry
  2949. // for this IP address
  2950. //
  2951. if( BrdgCompIsUnicastIPAddress(piphi->ipSource) )
  2952. {
  2953. pipte = (PIP_TABLE_ENTRY)BrdgHashFindEntry( gIPForwardingTable, (PUCHAR)&piphi->ipSource, &LockState );
  2954. if( pipte != NULL )
  2955. {
  2956. BOOLEAN bInfoMatches = FALSE;
  2957. //
  2958. // Make sure the information in this entry is correct. If it's not, we do NOT clobber the old
  2959. // information, nor do we refresh the old entry; we want it to time out in due course.
  2960. //
  2961. // We only create IP forwarding table entries in response to ARP packets, as that is the only
  2962. // officially sanctioned way of learning the correspondence between an IP address and a MAC address.
  2963. //
  2964. NdisAcquireSpinLock( &pipte->lock );
  2965. if( pipte->pAdapt == pAdapt )
  2966. {
  2967. UINT Result;
  2968. ETH_COMPARE_NETWORK_ADDRESSES_EQ( pipte->macAddr, &pPacketData[ETH_LENGTH_OF_ADDRESS], &Result );
  2969. if( Result == 0 )
  2970. {
  2971. bInfoMatches = TRUE;
  2972. }
  2973. }
  2974. NdisReleaseSpinLock( &pipte->lock );
  2975. if( bInfoMatches )
  2976. {
  2977. // Refresh the entry
  2978. BrdgHashRefreshEntry( (PHASH_TABLE_ENTRY)pipte );
  2979. }
  2980. else
  2981. {
  2982. // The info is mismatched; let the entry fester
  2983. THROTTLED_DBGPRINT(COMPAT, ("WARNING: Saw a packet from %i.%i.%i.%i that did not match its forwarding table entry! Table is %02x:%02x:%02x:%02x:%02x:%02x, packet is %02x:%02x:%02x:%02x:%02x:%02x\n",
  2984. ((PUCHAR)&piphi->ipSource)[3], ((PUCHAR)&piphi->ipSource)[2], ((PUCHAR)&piphi->ipSource)[1],
  2985. ((PUCHAR)&piphi->ipSource)[0], pipte->macAddr[0], pipte->macAddr[1], pipte->macAddr[2],
  2986. pipte->macAddr[3], pipte->macAddr[4], pipte->macAddr[5], pPacketData[ETH_LENGTH_OF_ADDRESS],
  2987. pPacketData[ETH_LENGTH_OF_ADDRESS + 1], pPacketData[ETH_LENGTH_OF_ADDRESS + 2], pPacketData[ETH_LENGTH_OF_ADDRESS + 3],
  2988. pPacketData[ETH_LENGTH_OF_ADDRESS + 4], pPacketData[ETH_LENGTH_OF_ADDRESS + 5] ));
  2989. }
  2990. NdisReleaseReadWriteLock( &gIPForwardingTable->tableLock, &LockState );
  2991. }
  2992. else
  2993. {
  2994. // CONSIDER: Make a forwarding table entry here? Are there cases where this would be undesirable?
  2995. //
  2996. //THROTTLED_DBGPRINT(COMPAT, ("WARNING: Saw IP packet before ARP from %i.%i.%i.%i\n",
  2997. // ((PUCHAR)&piphi->ipSource)[3], ((PUCHAR)&piphi->ipSource)[2], ((PUCHAR)&piphi->ipSource)[1],
  2998. // ((PUCHAR)&piphi->ipSource)[0] ));
  2999. }
  3000. }
  3001. else
  3002. {
  3003. //
  3004. // The source IP address on this packet is to be ignored.
  3005. // Just about the only thing we expect is the zero address
  3006. //
  3007. if( piphi->ipSource != 0L )
  3008. {
  3009. THROTTLED_DBGPRINT(COMPAT, ("Saw a packet with a non-unicast source IP address %i.%i.%i.%i on adapter %p!\n",
  3010. ((PUCHAR)&piphi->ipSource)[3], ((PUCHAR)&piphi->ipSource)[2], ((PUCHAR)&piphi->ipSource)[1],
  3011. ((PUCHAR)&piphi->ipSource)[0], pAdapt));
  3012. }
  3013. }
  3014. //
  3015. // Now that we have refreshed the IP forwarding table entry for the sending station,
  3016. // figure out where to send the packet based on its destination.
  3017. //
  3018. // The target MAC address is the first thing in the Ethernet frame
  3019. if( ETH_IS_BROADCAST(pPacketData) || ETH_IS_MULTICAST(pPacketData) )
  3020. {
  3021. //
  3022. // Packet is broadcast / multicast at the Ethernet level.
  3023. //
  3024. // We need to send it on all other compatibility-mode adapters
  3025. // (and regular adapters too if this came in on a compatibility
  3026. // adapter)
  3027. //
  3028. bRetained = BrdgCompSendToMultipleAdapters( pPacket, pAdapt, pPacketData,
  3029. bCanRetain && (!pAdapt->bCompatibilityMode), // TRUE == can retain
  3030. // If this is a compat adapter, send to all adapters
  3031. pAdapt->bCompatibilityMode,
  3032. pEditFunc, pData );
  3033. if( (!bCanRetain) || (pAdapt->bCompatibilityMode) )
  3034. {
  3035. SAFEASSERT( !bRetained );
  3036. }
  3037. if( pAdapt->bCompatibilityMode )
  3038. {
  3039. // It's our job to indicate this packet.
  3040. bRetained = BrdgCompIndicatePacketOrPacketCopy(pPacket, pPacketData, bCanRetain, pAdapt, pEditFunc, pData );
  3041. }
  3042. // else the regular-mode processing will indicate this frame
  3043. }
  3044. else
  3045. {
  3046. //
  3047. // Packet is unicast at the Ethernet level. Verify that it's targeted at a unicast IP address.
  3048. //
  3049. BOOLEAN bIsUnicast = BrdgCompIsUnicastIPAddress(piphi->ipTarget);
  3050. if( !bIsUnicast )
  3051. {
  3052. //
  3053. // Strange; this packet is unicast to us at the Ethernet level but is for a
  3054. // broadcast, multicast or zero target IP address.
  3055. //
  3056. // We will have no entries for this in our forwarding table, and we assume the
  3057. // IP stack will have no next-hop information for this address, so we just indicate
  3058. // it right away and let the IP driver figure out what this thing is.
  3059. //
  3060. THROTTLED_DBGPRINT(COMPAT, ("Packet with non-unicast target IP address %i.%i.%i.%i received in unicast Ethernet frame on adapter %p",
  3061. ((PUCHAR)&piphi->ipTarget)[3], ((PUCHAR)&piphi->ipTarget)[2], ((PUCHAR)&piphi->ipTarget)[1],
  3062. ((PUCHAR)&piphi->ipTarget)[0], pAdapt ));
  3063. // Process the packet below as if it were unicast to us.
  3064. }
  3065. if( (!bIsUnicast) || BrdgCompIsLocalIPAddress(piphi->ipTarget) )
  3066. {
  3067. //
  3068. // It's only appropriate for us to indicate the packet if the adapter
  3069. // on which the packet was received is a compatibility-mode adapter.
  3070. // Otherwise, the packet is indicated along regular codepaths without
  3071. // the need to edit it in any way.
  3072. //
  3073. if( pAdapt->bCompatibilityMode )
  3074. {
  3075. bRetained = BrdgCompIndicatePacketOrPacketCopy(pPacket, pPacketData, bCanRetain, pAdapt, pEditFunc, pData );
  3076. }
  3077. else
  3078. {
  3079. bRetained = FALSE;
  3080. }
  3081. }
  3082. else
  3083. {
  3084. //
  3085. // This packet is not for us. Look it up in our forwarding table to see if
  3086. // we know where the target machine is.
  3087. //
  3088. pipte = (PIP_TABLE_ENTRY)BrdgHashFindEntry( gIPForwardingTable, (PUCHAR)&piphi->ipTarget, &LockState );
  3089. if( pipte != NULL )
  3090. {
  3091. PADAPT pTargetAdapt;
  3092. UCHAR targetMAC[ETH_LENGTH_OF_ADDRESS];
  3093. // Copy out the information we need within the spin lock
  3094. NdisAcquireSpinLock( &pipte->lock );
  3095. pTargetAdapt = pipte->pAdapt;
  3096. ETH_COPY_NETWORK_ADDRESS( targetMAC, pipte->macAddr );
  3097. NdisReleaseSpinLock( &pipte->lock );
  3098. // We will use the adapter outside the table lock
  3099. BrdgAcquireAdapterInLock( pTargetAdapt );
  3100. // Done with the table entry
  3101. NdisReleaseReadWriteLock( &gIPForwardingTable->tableLock, &LockState );
  3102. // It is strange to receive traffic that needs to be retransmitted on the same adapter.
  3103. if( pTargetAdapt == pAdapt )
  3104. {
  3105. THROTTLED_DBGPRINT(COMPAT, ("WARNING: retransmitting traffic for %i.%i.%i.%i on Adapter %p\n",
  3106. ((PUCHAR)&piphi->ipTarget)[3], ((PUCHAR)&piphi->ipTarget)[2],
  3107. ((PUCHAR)&piphi->ipTarget)[1], ((PUCHAR)&piphi->ipTarget)[0], pAdapt));
  3108. }
  3109. bRetained = BrdgCompEditAndSendPacketOrPacketCopy(pPacket, pPacketData, bCanRetain, targetMAC,
  3110. pTargetAdapt, pEditFunc, pData );
  3111. BrdgReleaseAdapter( pTargetAdapt );
  3112. }
  3113. else
  3114. {
  3115. IPADDRESS ipNextHop;
  3116. //
  3117. // This packet was unicast to us at the Ethernet level but is for an IP address
  3118. // that isn't in our forwarding table. Assuming the transmitting station had a
  3119. // good reason for sending us this packet, and that our forward tables are working
  3120. // correctly and aren't corrupt, two possibilities remain:
  3121. //
  3122. // a) The packet needs to be routed off the subnet by the local machine (this is
  3123. // why the target IP address doesn't appear in our tables; one does not ARP for
  3124. // an off-subnet machine before transmitting to it; one sends packets to one's
  3125. // default gateway)
  3126. //
  3127. // b) The packet needs to be routed off the subnet by some other machine. Unfortunately
  3128. // we don't know which one, since all packets that come to us have the same target
  3129. // MAC address and the target IP address is no use; what we really want is the
  3130. // first-hop IP address.
  3131. //
  3132. // To sort this out, we call TCPIP to do a route lookup for the packet's target IP
  3133. // address. If the resulting next-hop IP address appears in our forwarding table
  3134. // (i.e., it is reachable on the bridged network), we send the packet on to that
  3135. // destination. If TCPIP gives us no first-hop, or the first-hop isn't in our table
  3136. // (as would occur if the next hop is reachable through some non-bridged adapter)
  3137. // we indicate the packet so TCPIP can deal with it. In such a case, the packet is
  3138. // either not routable (and IP will drop it) or was meant to be routed by the local
  3139. // machine (in which case IP will route it to its next hop).
  3140. //
  3141. if( BrdgCompGetNextHopForTarget(piphi->ipTarget, &ipNextHop) )
  3142. {
  3143. // We got a next-hop address. See if that address is in our forwarding table.
  3144. pipte = (PIP_TABLE_ENTRY)BrdgHashFindEntry( gIPForwardingTable, (PUCHAR)&ipNextHop, &LockState );
  3145. if( pipte != NULL )
  3146. {
  3147. PADAPT pNextHopAdapt;
  3148. UCHAR nextHopMAC[ETH_LENGTH_OF_ADDRESS];
  3149. // Must copy out the information inside the entry's spin lock
  3150. NdisAcquireSpinLock( &pipte->lock );
  3151. pNextHopAdapt = pipte->pAdapt;
  3152. ETH_COPY_NETWORK_ADDRESS( nextHopMAC, pipte->macAddr );
  3153. NdisReleaseSpinLock( &pipte->lock );
  3154. // We will use the adapter outside the table lock
  3155. BrdgAcquireAdapterInLock( pNextHopAdapt );
  3156. // We're done with the forwarding table
  3157. NdisReleaseReadWriteLock( &gIPForwardingTable->tableLock, &LockState );
  3158. // Something strange is afoot if the next hop is reachable through the same adapter
  3159. if( pNextHopAdapt == pAdapt )
  3160. {
  3161. THROTTLED_DBGPRINT(COMPAT, ("WARNING: retransmitting traffic for %i.%i.%i.%i on Adapter %p to next-hop %i.%i.%i.%i\n",
  3162. ((PUCHAR)&piphi->ipTarget)[3], ((PUCHAR)&piphi->ipTarget)[2],
  3163. ((PUCHAR)&piphi->ipTarget)[1], ((PUCHAR)&piphi->ipTarget)[0], pAdapt,
  3164. ((PUCHAR)&ipNextHop)[3], ((PUCHAR)&ipNextHop)[2],
  3165. ((PUCHAR)&ipNextHop)[1], ((PUCHAR)&ipNextHop)[0]));
  3166. }
  3167. // Send the packet out the appropriate adapter
  3168. bRetained = BrdgCompEditAndSendPacketOrPacketCopy( pPacket, pPacketData, bCanRetain, nextHopMAC,
  3169. pNextHopAdapt, pEditFunc, pData );
  3170. BrdgReleaseAdapter( pNextHopAdapt );
  3171. }
  3172. else
  3173. {
  3174. //
  3175. // The next hop isn't in our forwarding table. This means that the next hop machine
  3176. // isn't reachable on the bridged network, unless we're in a screwy state with
  3177. // respect to the transmitting machine (i.e., it never ARPed for the router it
  3178. // wanted because it had a static ARP entry or some other such weirdness).
  3179. // At any rate, conclude at this point that the local machine should handle the packet.
  3180. //
  3181. bRetained = BrdgCompIndicatePacketOrPacketCopy( pPacket, pPacketData, bCanRetain, pAdapt, pEditFunc, pData );
  3182. }
  3183. }
  3184. else
  3185. {
  3186. //
  3187. // No usable next-hop information. Conclude that the packet should be handled by
  3188. // the local machine. Indicate.
  3189. //
  3190. bRetained = BrdgCompIndicatePacketOrPacketCopy( pPacket, pPacketData, bCanRetain, pAdapt, pEditFunc, pData );
  3191. }
  3192. }
  3193. }
  3194. }
  3195. if( !bCanRetain )
  3196. {
  3197. SAFEASSERT( !bRetained );
  3198. }
  3199. return bRetained;
  3200. }
  3201. // Returns whether the packet was retained
  3202. BOOLEAN
  3203. BrdgCompProcessInboundNonARPPacket(
  3204. IN PNDIS_PACKET pPacket,
  3205. IN PADAPT pAdapt,
  3206. IN BOOLEAN bCanRetain,
  3207. IN PUCHAR pPacketData,
  3208. IN UINT packetLen
  3209. )
  3210. /*++
  3211. Routine Description:
  3212. Processes an inbound non-ARP packet
  3213. Arguments:
  3214. pPacket The packet
  3215. pAdapt The receiving adapter
  3216. bCanRetain If we can retain the packet
  3217. pPacketData The packet's data buffer
  3218. packetLen Size of data in buffer
  3219. Return Value:
  3220. Whether we retained the packet
  3221. --*/
  3222. {
  3223. BOOLEAN bRetained = FALSE;
  3224. IP_HEADER_INFO iphi;
  3225. SAFEASSERT( (pPacket != NULL) && (pPacketData != NULL) );
  3226. if( packetLen >= MINIMUM_SIZE_FOR_IP )
  3227. {
  3228. if( BrdgCompDecodeIPHeader(pPacketData + ETHERNET_HEADER_SIZE, &iphi) )
  3229. {
  3230. PUCHAR pBootPData;
  3231. pBootPData = BrdgCompIsBootPPacket( pPacketData, packetLen, &iphi );
  3232. if ( pBootPData != NULL )
  3233. {
  3234. // This is a BOOTP packet; do BOOTP-specific processing
  3235. bRetained = BrdgCompProcessInboundBootPPacket( pPacket, pAdapt, bCanRetain, pPacketData, packetLen, &iphi, pBootPData );
  3236. }
  3237. else
  3238. {
  3239. // Do generic IP processing
  3240. bRetained = BrdgCompProcessInboundIPPacket(pPacket, &iphi, pAdapt, bCanRetain, pPacketData, packetLen, NULL, NULL);
  3241. }
  3242. }
  3243. }
  3244. if( !bCanRetain )
  3245. {
  3246. SAFEASSERT( !bRetained );
  3247. }
  3248. return bRetained;
  3249. }
  3250. BOOLEAN
  3251. BrdgCompProcessInboundBootPPacket(
  3252. IN PNDIS_PACKET pPacket,
  3253. IN PADAPT pAdapt,
  3254. IN BOOLEAN bCanRetain,
  3255. IN PUCHAR pPacketData,
  3256. IN UINT packetLen,
  3257. IN PIP_HEADER_INFO piphi,
  3258. IN PUCHAR pBootPData
  3259. )
  3260. /*++
  3261. Routine Description:
  3262. Processes an inbound BOOTP packet
  3263. Arguments:
  3264. pPacket The packet
  3265. pAdapt The receiving adapter
  3266. bCanRetain If we can retain the packet
  3267. pPacketData The packet's data buffer
  3268. packetLen Size of data in buffer
  3269. piphi Decoded IP header info
  3270. pBootPData Pointer to BOOTP payload within the packet
  3271. Return Value:
  3272. Whether we retained the packet
  3273. --*/
  3274. {
  3275. UCHAR targetMAC[ETH_LENGTH_OF_ADDRESS];
  3276. BOOLEAN bIsRequest;
  3277. PADAPT pTargetAdapt = NULL;
  3278. if( BrdgCompPreprocessBootPPacket(pPacketData, piphi, pBootPData, pAdapt, &bIsRequest, &pTargetAdapt, targetMAC) )
  3279. {
  3280. if( bIsRequest )
  3281. {
  3282. //
  3283. // This is a request packet. It can be processed as a regular inbound IP packet,
  3284. // subject to appropriate rewriting at each step.
  3285. //
  3286. SAFEASSERT( pTargetAdapt == NULL );
  3287. return BrdgCompProcessInboundIPPacket( pPacket, piphi, pAdapt, bCanRetain, pPacketData, packetLen,
  3288. BrdgCompRewriteBootPPacketForAdapt, piphi );
  3289. }
  3290. else
  3291. {
  3292. BOOLEAN bUsingCopyPacket, bRetained;
  3293. //
  3294. // This is a reply packet. We can rewrite it once for all purposes.
  3295. //
  3296. // Make a copy if necessary so we can edit.
  3297. if( ! bCanRetain )
  3298. {
  3299. pPacket = BrdgFwdMakeCompatCopyPacket( pPacket, &pPacketData, &packetLen, FALSE );
  3300. if( (pPacket == NULL) || (pPacketData == NULL) )
  3301. {
  3302. // Free the target adapter before bailing out
  3303. if( pTargetAdapt != NULL )
  3304. {
  3305. BrdgReleaseAdapter( pTargetAdapt );
  3306. }
  3307. return FALSE;
  3308. }
  3309. bUsingCopyPacket = TRUE;
  3310. }
  3311. else
  3312. {
  3313. bUsingCopyPacket = FALSE;
  3314. }
  3315. // Rewrite the packet to the retrieved MAC address.
  3316. BrdgCompRewriteBootPClientAddress( pPacketData, piphi, targetMAC );
  3317. if( pTargetAdapt != NULL )
  3318. {
  3319. // If the reply was sent by broadcast, respect this, even if we think
  3320. // we know the unicast MAC address of the target.
  3321. if( ETH_IS_BROADCAST(pPacketData) || ETH_IS_MULTICAST(pPacketData) )
  3322. {
  3323. // Broadcast around the reply
  3324. bRetained = BrdgCompSendToMultipleAdapters( pPacket, pAdapt, pPacketData, TRUE, pAdapt->bCompatibilityMode,
  3325. NULL, NULL );
  3326. }
  3327. else
  3328. {
  3329. // Unicast back the reply
  3330. ETH_COPY_NETWORK_ADDRESS( pPacketData, targetMAC );
  3331. BrdgCompSendPacket( pPacket, pPacketData, pTargetAdapt );
  3332. bRetained = TRUE;
  3333. }
  3334. // The target adapter came back with an incremented refcount
  3335. BrdgReleaseAdapter( pTargetAdapt );
  3336. }
  3337. else
  3338. {
  3339. // This reply is for the local machine!
  3340. UINT Result;
  3341. // The recorded MAC address should be the MAC address of the bridge.
  3342. SAFEASSERT( gCompHaveMACAddress );
  3343. ETH_COMPARE_NETWORK_ADDRESSES_EQ( targetMAC, gCompMACAddress, &Result );
  3344. SAFEASSERT( Result == 0 );
  3345. // Indicate the edited reply
  3346. BrdgCompIndicatePacket( pPacket, pPacketData, pAdapt );
  3347. bRetained = TRUE;
  3348. }
  3349. if( bUsingCopyPacket )
  3350. {
  3351. if( !bRetained )
  3352. {
  3353. // Our copy packet was not retained.
  3354. BrdgFwdReleaseCompatPacket( pPacket );
  3355. }
  3356. // If we were using a copy packet, we definitely did not retain the packet passed in
  3357. bRetained = FALSE;
  3358. }
  3359. return bRetained;
  3360. }
  3361. }
  3362. else
  3363. {
  3364. // Something went wrong in the preprocessing.
  3365. return FALSE;
  3366. }
  3367. }
  3368. // ===========================================================================
  3369. //
  3370. // OUTBOUND PACKET PROCESSING
  3371. //
  3372. // ===========================================================================
  3373. BOOLEAN
  3374. BrdgCompProcessOutboundNonARPPacket(
  3375. IN PNDIS_PACKET pPacket,
  3376. IN PUCHAR pPacketData,
  3377. IN UINT packetLen,
  3378. IN PADAPT pTargetAdapt
  3379. )
  3380. /*++
  3381. Routine Description:
  3382. Processes an outbound non-ARP packet. This function may retain the
  3383. given packet if it wishes.
  3384. Arguments:
  3385. pPacket The packet
  3386. pPacketData The packet's data buffer
  3387. packetLen Length of the data buffer
  3388. pTargetAdapt The target adapter, as determined
  3389. by a previous MAC-table lookup
  3390. Return Value:
  3391. Whether we retained the packet
  3392. --*/
  3393. {
  3394. IP_HEADER_INFO iphi;
  3395. BOOLEAN bRetained = FALSE, bIsMulticast;
  3396. if( packetLen >= MINIMUM_SIZE_FOR_IP &&
  3397. BrdgCompDecodeIPHeader(pPacketData + ETHERNET_HEADER_SIZE, &iphi) )
  3398. {
  3399. PUCHAR pBootPData;
  3400. pBootPData = BrdgCompIsBootPPacket(pPacketData, packetLen, &iphi);
  3401. if( pBootPData != NULL )
  3402. {
  3403. // Do special BOOTP processing
  3404. return BrdgCompProcessOutboundBootPPacket( pPacket, pPacketData, packetLen, pTargetAdapt, pBootPData, &iphi );
  3405. }
  3406. }
  3407. bIsMulticast = (BOOLEAN)(ETH_IS_BROADCAST(pPacketData) || ETH_IS_MULTICAST(pPacketData));
  3408. // We edit and transmit the packet even if it doesn't appear to be IP.
  3409. if( (pTargetAdapt == NULL) || bIsMulticast )
  3410. {
  3411. // Don't expect a target adapter when the outbound frame is broadcast
  3412. if( bIsMulticast )
  3413. {
  3414. SAFEASSERT( pTargetAdapt == NULL );
  3415. }
  3416. // We need to send this packet to all compat adapters.
  3417. bRetained = BrdgCompSendToMultipleAdapters( pPacket, NULL, pPacketData, TRUE, /*Can retain*/
  3418. FALSE /* Compat-mode adapters only*/,
  3419. NULL /*No editing function*/, NULL );
  3420. }
  3421. else
  3422. {
  3423. BrdgCompSendPacket( pPacket, pPacketData, pTargetAdapt );
  3424. // The packet has been handed off to the forwarding engine
  3425. bRetained = TRUE;
  3426. }
  3427. return bRetained;
  3428. }
  3429. BOOLEAN
  3430. BrdgCompProcessOutboundARPPacket(
  3431. IN PNDIS_PACKET pPacket,
  3432. IN PUCHAR pPacketData,
  3433. IN UINT packetLen,
  3434. IN PADAPT pTargetAdapt
  3435. )
  3436. /*++
  3437. Routine Description:
  3438. Processes an outbound ARP packet. This function may retain the
  3439. given packet if it wishes.
  3440. Arguments:
  3441. pPacket The packet
  3442. pPacketData The packet's data buffer
  3443. packetLen Length of the data buffer
  3444. pTargetAdapt The target adapter, as determined
  3445. by a previous MAC-table lookup
  3446. Return Value:
  3447. Whether we retained the packet
  3448. --*/
  3449. {
  3450. BOOLEAN bRetained = FALSE, bIsMulticast;
  3451. ARPINFO ai;
  3452. if( packetLen < SIZE_OF_ARP_PACKET )
  3453. {
  3454. // Packet is too small to be ARP; process as non-ARP
  3455. return BrdgCompProcessOutboundNonARPPacket( pPacket, pPacketData, packetLen, pTargetAdapt );
  3456. }
  3457. if( BrdgCompDecodeARPPacket(pPacketData, packetLen, &ai) )
  3458. {
  3459. if( ai.type == ArpRequest )
  3460. {
  3461. ARP_TABLE_KEY atk;
  3462. PARP_TABLE_ENTRY pEntry;
  3463. LOCK_STATE LockState;
  3464. BOOLEAN bIsNewEntry;
  3465. // Note that the local machine is trying to resolve this target IP address by
  3466. // inserting or refreshing an entry with 0.0.0.0 as the requestor
  3467. atk.ipReqestor = 0L; // Special value for local machine
  3468. atk.ipTarget = ai.ipTarget;
  3469. pEntry = (PARP_TABLE_ENTRY)BrdgHashRefreshOrInsert( gPendingARPTable, (PUCHAR)&atk, &bIsNewEntry,
  3470. &LockState );
  3471. if( pEntry != NULL )
  3472. {
  3473. if( bIsNewEntry)
  3474. {
  3475. // Even though this entry isn't really ever used, initialize it so
  3476. // functions walking across table entries don't get confused or crash.
  3477. NdisAllocateSpinLock( &pEntry->lock );
  3478. pEntry->pOriginalAdapt = NULL;
  3479. pEntry->originalMAC[0] = pEntry->originalMAC[1] = pEntry->originalMAC[2] =
  3480. pEntry->originalMAC[3] = pEntry->originalMAC[4] =pEntry->originalMAC[5] = 0;
  3481. }
  3482. NdisReleaseReadWriteLock( &gPendingARPTable->tableLock, &LockState );
  3483. }
  3484. }
  3485. // Check if this frame looks like it should be relayed to all compat adapters
  3486. bIsMulticast = (BOOLEAN)(ETH_IS_BROADCAST(pPacketData) || ETH_IS_MULTICAST(pPacketData));
  3487. if( (pTargetAdapt == NULL) || bIsMulticast )
  3488. {
  3489. // Don't expect a target adapter when the outbound frame is broadcast
  3490. if( bIsMulticast )
  3491. {
  3492. SAFEASSERT( pTargetAdapt == NULL );
  3493. }
  3494. // We need to send this packet to all compat adapters.
  3495. bRetained = BrdgCompSendToMultipleAdapters( pPacket, NULL, pPacketData, TRUE,/*Can retain*/
  3496. FALSE /* Compat-mode adapters only*/,
  3497. BrdgCompRewriteOutboundARPPacket, NULL );
  3498. }
  3499. else
  3500. {
  3501. // Edit the packet for the outbound adapter
  3502. BrdgCompRewriteOutboundARPPacket( pPacketData, pTargetAdapt, NULL );
  3503. // Send the packet on its way
  3504. BrdgCompSendPacket( pPacket, pPacketData, pTargetAdapt );
  3505. // The packet has been handed off to the forwarding engine
  3506. bRetained = TRUE;
  3507. }
  3508. }
  3509. else
  3510. {
  3511. // The packet didn't look like an ARP packet. Process it otherwise.
  3512. return BrdgCompProcessOutboundNonARPPacket( pPacket, pPacketData, packetLen, pTargetAdapt );
  3513. }
  3514. return bRetained;
  3515. }
  3516. BOOLEAN
  3517. BrdgCompProcessOutboundBootPPacket(
  3518. IN PNDIS_PACKET pPacket,
  3519. IN PUCHAR pPacketData,
  3520. IN UINT packetLen,
  3521. IN PADAPT pTargetAdapt,
  3522. IN PUCHAR pBootPData,
  3523. IN PIP_HEADER_INFO piphi
  3524. )
  3525. /*++
  3526. Routine Description:
  3527. Processes an outbound BOOTP packet. This function may retain the
  3528. given packet if it wishes.
  3529. Arguments:
  3530. pPacket The packet
  3531. pPacketData The packet's data buffer
  3532. packetLen Length of the data buffer
  3533. pTargetAdapt The target adapter, as determined
  3534. by a previous MAC-table lookup
  3535. pBootPData Pointer to the BOOTP payload within the packet
  3536. piphi Decoded info from the packet's IP header
  3537. Return Value:
  3538. Whether we retained the packet
  3539. --*/
  3540. {
  3541. BOOLEAN bIsRequest, bRetained;
  3542. PADAPT pRequestorAdapt = NULL;
  3543. UCHAR macRequestor[ETH_LENGTH_OF_ADDRESS];
  3544. if( BrdgCompPreprocessBootPPacket( pPacketData, piphi, pBootPData, NULL, &bIsRequest, &pRequestorAdapt, macRequestor ) )
  3545. {
  3546. if( bIsRequest )
  3547. {
  3548. //
  3549. // This is a BOOTP request. Transmit as appropriate but rewrite for each adapter.
  3550. //
  3551. SAFEASSERT( pRequestorAdapt == NULL );
  3552. if( (pTargetAdapt == NULL) || ETH_IS_BROADCAST(pPacketData) || ETH_IS_MULTICAST(pPacketData) )
  3553. {
  3554. bRetained = BrdgCompSendToMultipleAdapters( pPacket, NULL, pPacketData, TRUE, FALSE, BrdgCompRewriteBootPPacketForAdapt,
  3555. piphi );
  3556. }
  3557. else
  3558. {
  3559. // Rewrite the packet before transmission
  3560. BrdgCompRewriteBootPPacketForAdapt( pPacketData, pTargetAdapt, piphi );
  3561. // Unicast out the packet
  3562. BrdgCompSendPacket( pPacket, pPacketData, pTargetAdapt );
  3563. bRetained = TRUE;
  3564. }
  3565. }
  3566. else
  3567. {
  3568. //
  3569. // This is a BOOTP reply. No editing is necessary; just send it.
  3570. //
  3571. if( (pTargetAdapt == NULL) || ETH_IS_BROADCAST(pPacketData) || ETH_IS_MULTICAST(pPacketData) )
  3572. {
  3573. bRetained = BrdgCompSendToMultipleAdapters( pPacket, NULL, pPacketData, TRUE, FALSE, NULL, NULL );
  3574. }
  3575. else
  3576. {
  3577. UINT Result;
  3578. // Verify for sanity that the target we're sending it to matches the information
  3579. // in the table.
  3580. ETH_COMPARE_NETWORK_ADDRESSES_EQ( macRequestor, pPacketData, &Result );
  3581. SAFEASSERT( Result == 0 );
  3582. SAFEASSERT( pTargetAdapt == pRequestorAdapt );
  3583. // This packet is unicast, probably part of an established conversation with a
  3584. // DHCP server.
  3585. BrdgCompSendPacket( pPacket, pPacketData, pTargetAdapt );
  3586. bRetained = TRUE;
  3587. }
  3588. // This comes back with its refcount incremented
  3589. if( pRequestorAdapt != NULL )
  3590. {
  3591. BrdgReleaseAdapter( pRequestorAdapt );
  3592. }
  3593. }
  3594. }
  3595. else
  3596. {
  3597. // Preprocessing failed
  3598. bRetained = FALSE;
  3599. }
  3600. return bRetained;
  3601. }