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.

347 lines
9.2 KiB

  1. /*++
  2. Copyright(c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. brdgtbl.c
  5. Abstract:
  6. Ethernet MAC level bridge.
  7. MAC Table section
  8. Author:
  9. Mark Aiken
  10. (original bridge by Jameel Hyder)
  11. Environment:
  12. Kernel mode driver
  13. Revision History:
  14. Feb 2000 - Original version
  15. --*/
  16. #define NDIS_MINIPORT_DRIVER
  17. #define NDIS50_MINIPORT 1
  18. #define NDIS_WDM 1
  19. #pragma warning( push, 3 )
  20. #include <ndis.h>
  21. #include <ntddk.h>
  22. #pragma warning( pop )
  23. #include <netevent.h>
  24. #include "bridge.h"
  25. #include "brdgtbl.h"
  26. // ===========================================================================
  27. //
  28. // PRIVATE DECLARATIONS
  29. //
  30. // ===========================================================================
  31. // Default age at which entries are removed from table
  32. #define DEFAULT_MAX_TBL_AGE (300 * 1000) // 5 minutes in milliseconds
  33. //
  34. // Default cap on forwarding table size
  35. //
  36. #define DEFAULT_MAX_TBL_MEMORY (500 * 1024) // 500K in bytes
  37. //
  38. // Registry values that hold our config values
  39. //
  40. const PWCHAR gMaxTableMemoryParameterName = L"MaxTableMemory";
  41. // Structure of a table entry
  42. typedef struct _MAC_FWDTABLE_ENTRY
  43. {
  44. HASH_TABLE_ENTRY hte;
  45. PADAPT pAdapt;
  46. } MAC_FWDTABLE_ENTRY, *PMAC_FWDTABLE_ENTRY;
  47. // ===========================================================================
  48. //
  49. // GLOBALS
  50. //
  51. // ===========================================================================
  52. // The MAC forwarding table
  53. PHASH_TABLE gMACForwardingTable;
  54. // Number of hash buckets (needs to be N^2 for the hash function to work)
  55. #define NUM_HASH_BUCKETS 256
  56. // ===========================================================================
  57. //
  58. // PRIVATE FUNCTIONS
  59. //
  60. // ===========================================================================
  61. // These would all be inlines except that we have to pass pointers to them
  62. //
  63. // Our hash function for Ethernet addresses. Uses the lower bits of byte #4.
  64. //
  65. // This hash function requires NUM_HASH_BUCKETS buckets; don't change this
  66. // without updating the number of hash buckets available.
  67. //
  68. ULONG
  69. BrdgTblHashAddress(
  70. IN PUCHAR pAddr
  71. )
  72. {
  73. return *((pAddr)+ETH_LENGTH_OF_ADDRESS-2) & (NUM_HASH_BUCKETS-1);
  74. }
  75. //
  76. // Returns TRUE if the pAdapt field in two entries match
  77. //
  78. BOOLEAN
  79. BrdgTblEntriesMatch(
  80. IN PHASH_TABLE_ENTRY pEntry,
  81. IN PVOID pAdapt
  82. )
  83. {
  84. return (BOOLEAN)(((PMAC_FWDTABLE_ENTRY)pEntry)->pAdapt == (PADAPT)pAdapt);
  85. }
  86. //
  87. // Copies the MAC address from a table entry to a data buffer.
  88. //
  89. VOID
  90. BrdgTblCopyEntries(
  91. PHASH_TABLE_ENTRY pEntry,
  92. PUCHAR pDest
  93. )
  94. {
  95. PMAC_FWDTABLE_ENTRY pMACEntry = (PMAC_FWDTABLE_ENTRY)pEntry;
  96. // The MAC address is the key. Copy it to the target buffer.
  97. ETH_COPY_NETWORK_ADDRESS( pDest, pMACEntry->hte.key );
  98. }
  99. // ===========================================================================
  100. //
  101. // PUBLIC FUNCTIONS
  102. //
  103. // ===========================================================================
  104. NTSTATUS
  105. BrdgTblDriverInit()
  106. /*++
  107. Routine Description:
  108. Load-time initialization function
  109. Arguments:
  110. None
  111. Return Value:
  112. Status of initialization. A return code != STATUS_SUCCESS aborts driver load.
  113. --*/
  114. {
  115. NTSTATUS NtStatus;
  116. ULONG MaxMemory, MaxEntries;
  117. NtStatus = BrdgReadRegDWord( &gRegistryPath, gMaxTableMemoryParameterName, &MaxMemory );
  118. if( NtStatus != STATUS_SUCCESS )
  119. {
  120. DBGPRINT(GENERAL, ("Failed to read MaxTableMemory value: %08x\n", NtStatus));
  121. MaxMemory = DEFAULT_MAX_TBL_MEMORY;
  122. DBGPRINT(GENERAL, ( "Using DEFAULT maximum memory of %i\n", MaxMemory ));
  123. }
  124. MaxEntries = MaxMemory / sizeof(MAC_FWDTABLE_ENTRY);
  125. DBGPRINT(GENERAL, ( "Forwarding table cap set at %i entries (%iK of memory)\n", MaxEntries, MaxMemory / 1024 ));
  126. gMACForwardingTable = BrdgHashCreateTable( BrdgTblHashAddress, NUM_HASH_BUCKETS, sizeof(MAC_FWDTABLE_ENTRY),
  127. MaxEntries, DEFAULT_MAX_TBL_AGE, DEFAULT_MAX_TBL_AGE,
  128. ETH_LENGTH_OF_ADDRESS );
  129. if( gMACForwardingTable == NULL )
  130. {
  131. DBGPRINT(FWD, ("FAILED TO ALLOCATE MAC TABLE!\n"));
  132. return STATUS_INSUFFICIENT_RESOURCES;
  133. }
  134. else
  135. {
  136. return STATUS_SUCCESS;
  137. }
  138. }
  139. //
  140. // Creates a new table entry associating the given MAC address with the given
  141. // adapter, or refreshes an existing entry.
  142. //
  143. VOID
  144. BrdgTblNoteAddress(
  145. IN PUCHAR pAddr,
  146. IN PADAPT pAdapt
  147. )
  148. /*++
  149. Routine Description:
  150. Creates a new table entry associating the given MAC address with the given
  151. adapter, or refreshes an existing entry.
  152. Arguments:
  153. pAddr The MAC address to look up
  154. pAdapt The adapter to associate it with
  155. Return Value:
  156. None
  157. --*/
  158. {
  159. PMAC_FWDTABLE_ENTRY pEntry;
  160. BOOLEAN bIsNewEntry;
  161. LOCK_STATE LockState;
  162. // Refuse to record non-unicast addresses
  163. if( ETH_IS_MULTICAST(pAddr) )
  164. {
  165. THROTTLED_DBGPRINT(FWD, ("## BRIDGE ## Not recording multicast address in BrdgTblNoteAddress\n"));
  166. return;
  167. }
  168. pEntry = (PMAC_FWDTABLE_ENTRY)BrdgHashRefreshOrInsert( gMACForwardingTable, pAddr, &bIsNewEntry, &LockState);
  169. if( pEntry != NULL )
  170. {
  171. // Regardless of whether or not this is a new table entry or an existing one,
  172. // just cram in the adapter pointer with an interlocked instruction.
  173. InterlockedExchangePointer( &pEntry->pAdapt, pAdapt );
  174. // Since the function came back != NULL, we must release the table lock.
  175. NdisReleaseReadWriteLock( &gMACForwardingTable->tableLock, &LockState );
  176. }
  177. }
  178. PADAPT
  179. BrdgTblFindTargetAdapter(
  180. IN PUCHAR pAddr
  181. )
  182. /*++
  183. Routine Description:
  184. Locates the adapter corresponding to a particular MAC address.
  185. If an adapter is found, this function returns a PADAPT pointer after
  186. having INCREMENTED THE REFCOUNT for that adapter. This is to ensure that
  187. the adapter is not unbound until the caller is done using it. The caller
  188. should be sure to decrement the PADAPT's refcount when it is done using
  189. the pointer.
  190. Arguments:
  191. pAddr The MAC address to look up
  192. Return Value:
  193. A pointer to the ADAPT structure describing the adapter associated with
  194. the given MAC address, with its refcount INCREMENTED, or NULL if an
  195. entry associating the given MAC address to an adapter was not found.
  196. --*/
  197. {
  198. PMAC_FWDTABLE_ENTRY pEntry;
  199. LOCK_STATE LockState;
  200. PADAPT pAdapt = NULL;
  201. pEntry = (PMAC_FWDTABLE_ENTRY)BrdgHashFindEntry( gMACForwardingTable, pAddr, &LockState );
  202. if( pEntry != NULL )
  203. {
  204. // Read this once since it can be changed even while we hold the RW lock
  205. pAdapt = pEntry->pAdapt;
  206. SAFEASSERT( pAdapt != NULL );
  207. //
  208. // Increment this adapter's refcount while inside the RW lock for the table.
  209. // This lets us close a race condition window for unbinding the adapter;
  210. // the caller will hang on to the returned PADAPT after we return, leading
  211. // to problems if the adapter is unbound before our caller is done using
  212. // the PADAPT structure.
  213. //
  214. BrdgAcquireAdapterInLock( pAdapt );
  215. // Release the table lock
  216. NdisReleaseReadWriteLock( &gMACForwardingTable->tableLock, &LockState );
  217. }
  218. return pAdapt;
  219. }
  220. //
  221. // This function cleans all the adapters from the tables (this is in the case of a GPO changing
  222. // our bridging settings)
  223. //
  224. VOID
  225. BrdgTblScrubAllAdapters()
  226. {
  227. PADAPT pAdapt = NULL;
  228. LOCK_STATE LockStateMACTable;
  229. LOCK_STATE LockStateAdapterList;
  230. //
  231. // We don't want the table to be modified while we're doing this, and we also don't want an adapter
  232. // to go away while we're enumerating the list of adapters.
  233. //
  234. NdisAcquireReadWriteLock(&gMACForwardingTable->tableLock, FALSE /*Read Only*/, &LockStateMACTable);
  235. NdisAcquireReadWriteLock(&gAdapterListLock, FALSE /*Read Only*/, &LockStateAdapterList);
  236. for( pAdapt = gAdapterList; pAdapt != NULL; pAdapt = pAdapt->Next )
  237. {
  238. // Scrub adapter from the table.
  239. BrdgTblScrubAdapter(pAdapt);
  240. }
  241. NdisReleaseReadWriteLock(&gAdapterListLock, &LockStateAdapterList);
  242. NdisReleaseReadWriteLock(&gMACForwardingTable->tableLock, &LockStateMACTable);
  243. }
  244. VOID
  245. BrdgTblCleanup()
  246. /*++
  247. Routine Description:
  248. Unload-time orderly shutdown
  249. This function is guaranteed to be called exactly once
  250. Arguments:
  251. None
  252. Return Value:
  253. None
  254. --*/
  255. {
  256. SAFEASSERT( gMACForwardingTable != NULL );
  257. BrdgHashFreeHashTable( gMACForwardingTable );
  258. gMACForwardingTable = NULL;
  259. }