2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: network/router.c
5 * PURPOSE: IP routing subsystem
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
16 LIST_ENTRY FIBListHead;
23 * FUNCTION: Frees an forward information base object
25 * Object = Pointer to an forward information base structure
35 * FUNCTION: Destroys an forward information base entry
37 * FIBE = Pointer to FIB entry
39 * The forward information base lock must be held when called
42 TI_DbgPrint(DEBUG_ROUTER, ("Called. FIBE (0x%X).\n", FIBE));
44 /* Unlink the FIB entry from the list */
45 RemoveEntryList(&FIBE->ListEntry);
47 /* Dereference the referenced objects */
48 DereferenceObject(FIBE->NetworkAddress);
49 DereferenceObject(FIBE->Netmask);
50 DereferenceObject(FIBE->Router);
51 DereferenceObject(FIBE->NTE);
56 if (FIBE->RefCount != 0) {
57 TI_DbgPrint(MIN_TRACE, ("FIB entry at (0x%X) has (%d) references (Should be 0).\n", FIBE, FIBE->RefCount));
61 /* And free the FIB entry */
69 * FUNCTION: Destroys all forward information base entries
71 * The forward information base lock must be held when called
74 PLIST_ENTRY CurrentEntry;
75 PLIST_ENTRY NextEntry;
78 /* Search the list and remove every FIB entry we find */
79 CurrentEntry = FIBListHead.Flink;
80 while (CurrentEntry != &FIBListHead) {
81 NextEntry = CurrentEntry->Flink;
82 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
83 /* Destroy the FIB entry */
85 CurrentEntry = NextEntry;
90 UINT CommonPrefixLength(
94 * FUNCTION: Computes the length of the longest prefix common to two addresses
96 * Address1 = Pointer to first address
97 * Address2 = Pointer to second address
99 * The two addresses must be of the same type
101 * Length of longest common prefix
109 TI_DbgPrint(DEBUG_ROUTER, ("Called. Address1 (0x%X) Address2 (0x%X).\n", Address1, Address2));
111 TI_DbgPrint(DEBUG_ROUTER, ("Address1 (%s) Address2 (%s).\n",
112 A2S(Address1), A2S(Address2)));
114 if (Address1->Type == IP_ADDRESS_V4)
115 Size = sizeof(IPv4_RAW_ADDRESS);
117 Size = sizeof(IPv6_RAW_ADDRESS);
119 Addr1 = (PUCHAR)&Address1->Address;
120 Addr2 = (PUCHAR)&Address2->Address;
122 /* Find first non-matching byte */
125 return 8 * i; /* The two addresses are equal */
127 if (Addr1[i] != Addr2[i])
131 /* Find first non-matching bit */
134 if ((Addr1[i] & Bitmask) != (Addr2[i] & Bitmask))
148 * FUNCTION: Determines wether an address has an given prefix
150 * Address = Pointer to address to use
151 * Prefix = Pointer to prefix to check for
152 * Length = Length of prefix
154 * TRUE if the address has the prefix, FALSE if not
156 * The two addresses must be of the same type
159 PUCHAR pAddress = (PUCHAR)&Address->Address;
160 PUCHAR pPrefix = (PUCHAR)&Prefix->Address;
162 TI_DbgPrint(DEBUG_ROUTER, ("Called. Address (0x%X) Prefix (0x%X) Length (%d).\n", Address, Prefix, Length));
164 TI_DbgPrint(DEBUG_ROUTER, ("Address (%s) Prefix (%s).\n",
165 A2S(Address), A2S(Prefix)));
167 /* Check that initial integral bytes match */
169 if (*pAddress++ != *pPrefix++)
174 /* Check any remaining bits */
175 if ((Length > 0) && ((*pAddress >> (8 - Length)) != (*pPrefix >> (8 - Length))))
182 PNET_TABLE_ENTRY RouterFindBestNTE(
183 PIP_INTERFACE Interface,
184 PIP_ADDRESS Destination)
186 * FUNCTION: Checks all on-link prefixes to find out if an address is on-link
188 * Interface = Pointer to interface to use
189 * Destination = Pointer to destination address
191 * If found the NTE if referenced
193 * Pointer to NTE if found, NULL if not
197 PLIST_ENTRY CurrentEntry;
198 PNET_TABLE_ENTRY Current;
199 UINT Length, BestLength = 0;
200 PNET_TABLE_ENTRY BestNTE = NULL;
202 TI_DbgPrint(DEBUG_ROUTER, ("Called. Interface (0x%X) Destination (0x%X).\n", Interface, Destination));
204 TI_DbgPrint(DEBUG_ROUTER, ("Destination (%s).\n", A2S(Destination)));
206 KeAcquireSpinLock(&Interface->Lock, &OldIrql);
208 CurrentEntry = Interface->NTEListHead.Flink;
209 while (CurrentEntry != &Interface->NTEListHead) {
210 Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
212 Length = CommonPrefixLength(Destination, Current->Address);
214 if (Length > BestLength) {
215 /* This seems to be a better NTE */
216 DereferenceObject(BestNTE);
217 ReferenceObject(Current);
222 /* First suitable NTE found, save it */
223 ReferenceObject(Current);
227 CurrentEntry = CurrentEntry->Flink;
230 KeReleaseSpinLock(&Interface->Lock, OldIrql);
236 PIP_INTERFACE RouterFindOnLinkInterface(
238 PNET_TABLE_ENTRY NTE)
240 * FUNCTION: Checks all on-link prefixes to find out if an address is on-link
242 * Address = Pointer to address to check
243 * NTE = Pointer to NTE to check (NULL = check all interfaces)
245 * Pointer to interface if address is on-link, NULL if not
248 PLIST_ENTRY CurrentEntry;
249 PPREFIX_LIST_ENTRY Current;
251 TI_DbgPrint(DEBUG_ROUTER, ("Called. Address (0x%X) NTE (0x%X).\n", Address, NTE));
253 TI_DbgPrint(DEBUG_ROUTER, ("Address (%s) NTE (%s).\n",
254 A2S(Address), A2S(NTE->Address)));
256 CurrentEntry = PrefixListHead.Flink;
257 while (CurrentEntry != &PrefixListHead) {
258 Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry);
260 if (HasPrefix(Address, Current->Prefix, Current->PrefixLength) &&
261 ((!NTE) || (NTE->Interface == Current->Interface)))
262 return Current->Interface;
264 CurrentEntry = CurrentEntry->Flink;
271 PFIB_ENTRY RouterAddRoute(
272 PIP_ADDRESS NetworkAddress,
274 PNET_TABLE_ENTRY NTE,
275 PNEIGHBOR_CACHE_ENTRY Router,
278 * FUNCTION: Adds a route to the Forward Information Base (FIB)
280 * NetworkAddress = Pointer to address of network
281 * Netmask = Pointer to netmask of network
282 * NTE = Pointer to NTE to use
283 * Router = Pointer to NCE of router to use
284 * Metric = Cost of this route
286 * Pointer to FIB entry if the route was added, NULL if not
288 * The FIB entry references the NetworkAddress, Netmask, NTE and
289 * the NCE of the router. The caller is responsible for providing
295 TI_DbgPrint(DEBUG_ROUTER, ("Called. NetworkAddress (0x%X) Netmask (0x%X) NTE (0x%X) "
296 "Router (0x%X) Metric (%d).\n", NetworkAddress, Netmask, NTE, Router, Metric));
298 TI_DbgPrint(DEBUG_ROUTER, ("NetworkAddress (%s) Netmask (%s) NTE (%s) Router (%s).\n",
299 A2S(NetworkAddress), A2S(Netmask), A2S(NTE->Address), A2S(Router->Address)));
301 FIBE = ExAllocatePool(NonPagedPool, sizeof(FIB_ENTRY));
303 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
307 INIT_TAG(NTE, TAG('N','T','E',' '));
308 INIT_TAG(Router, TAG('R','O','U','T'));
310 FIBE->Free = FreeFIB;
311 FIBE->NetworkAddress = NetworkAddress;
312 FIBE->Netmask = Netmask;
314 FIBE->Router = Router;
315 FIBE->Metric = Metric;
317 /* Add FIB to the forward information base */
318 ExInterlockedInsertTailList(&FIBListHead, &FIBE->ListEntry, &FIBLock);
324 PNEIGHBOR_CACHE_ENTRY RouterGetRoute(
325 PIP_ADDRESS Destination,
326 PNET_TABLE_ENTRY NTE)
328 * FUNCTION: Finds a router to use to get to Destination
330 * Destination = Pointer to destination address (NULL means don't care)
331 * NTE = Pointer to NTE describing net to send on
332 * (NULL means don't care)
334 * Pointer to NCE for router, NULL if none was found
336 * If found the NCE is referenced
340 PLIST_ENTRY CurrentEntry;
341 PLIST_ENTRY NextEntry;
343 UCHAR State, BestState = 0;
344 UINT Length, BestLength = 0;
345 PNEIGHBOR_CACHE_ENTRY NCE, BestNCE = NULL;
347 TI_DbgPrint(DEBUG_ROUTER, ("Called. Destination (0x%X) NTE (0x%X).\n", Destination, NTE));
349 TI_DbgPrint(DEBUG_ROUTER, ("Destination (%s) NTE (%s).\n",
350 A2S(Destination), A2S(NTE->Address)));
352 KeAcquireSpinLock(&FIBLock, &OldIrql);
354 CurrentEntry = FIBListHead.Flink;
355 while (CurrentEntry != &FIBListHead) {
356 NextEntry = CurrentEntry->Flink;
357 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
359 NCE = Current->Router;
362 if ((!NTE) || (NTE->Interface == NCE->Interface)) {
364 Length = CommonPrefixLength(Destination, NCE->Address);
369 if ((State > BestState) ||
370 ((State == BestState) &&
371 (Length > BestLength))) {
372 /* This seems to be a better router */
373 DereferenceObject(BestNCE);
374 ReferenceObject(NCE);
380 /* First suitable router found, save it */
381 ReferenceObject(NCE);
387 CurrentEntry = NextEntry;
390 KeReleaseSpinLock(&FIBLock, OldIrql);
396 VOID RouterRemoveRoute(
399 * FUNCTION: Removes a route from the Forward Information Base (FIB)
401 * FIBE = Pointer to FIB entry describing route
406 TI_DbgPrint(DEBUG_ROUTER, ("Called. FIBE (0x%X).\n", FIBE));
408 TI_DbgPrint(DEBUG_ROUTER, ("FIBE (%s).\n", A2S(FIBE->NetworkAddress)));
410 KeAcquireSpinLock(&FIBLock, &OldIrql);
412 KeReleaseSpinLock(&FIBLock, OldIrql);
416 PFIB_ENTRY RouterCreateRouteIPv4(
417 IPv4_RAW_ADDRESS NetworkAddress,
418 IPv4_RAW_ADDRESS Netmask,
419 IPv4_RAW_ADDRESS RouterAddress,
420 PNET_TABLE_ENTRY NTE,
423 * FUNCTION: Creates a route with IPv4 addresses as parameters
425 * NetworkAddress = Address of network
426 * Netmask = Netmask of network
427 * RouterAddress = Address of router to use
428 * NTE = Pointer to NTE to use
429 * Metric = Cost of this route
431 * Pointer to FIB entry if the route was created, NULL if not.
432 * The FIB entry references the NTE. The caller is responsible
433 * for providing this reference
436 PIP_ADDRESS pNetworkAddress;
437 PIP_ADDRESS pNetmask;
438 PIP_ADDRESS pRouterAddress;
439 PNEIGHBOR_CACHE_ENTRY NCE;
442 pNetworkAddress = AddrBuildIPv4(NetworkAddress);
443 if (!pNetworkAddress) {
444 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
448 pNetmask = AddrBuildIPv4(Netmask);
450 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
451 DereferenceObject(pNetworkAddress);
455 pRouterAddress = AddrBuildIPv4(RouterAddress);
456 if (!pRouterAddress) {
457 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
458 DereferenceObject(pNetworkAddress);
459 DereferenceObject(pNetmask);
463 /* The NCE references RouterAddress. The NCE is referenced for us */
464 NCE = NBAddNeighbor(NTE->Interface,
467 NTE->Interface->AddressLength,
470 /* Not enough free resources */
471 DereferenceObject(pNetworkAddress);
472 DereferenceObject(pNetmask);
473 DereferenceObject(pRouterAddress);
477 ReferenceObject(pNetworkAddress);
478 ReferenceObject(pNetmask);
479 FIBE = RouterAddRoute(pNetworkAddress, pNetmask, NTE, NCE, 1);
481 /* Not enough free resources */
482 NBRemoveNeighbor(NCE);
483 DereferenceObject(pNetworkAddress);
484 DereferenceObject(pNetmask);
485 DereferenceObject(pRouterAddress);
487 (pNetworkAddress->Free)(pNetworkAddress);
488 (pNetmask->Free)(pNetmask);
489 (pRouterAddress->Free)(pRouterAddress);
496 NTSTATUS RouterStartup(
499 * FUNCTION: Initializes the routing subsystem
501 * Status of operation
504 TI_DbgPrint(DEBUG_ROUTER, ("Called.\n"));
506 /* Initialize the Forward Information Base */
507 InitializeListHead(&FIBListHead);
508 KeInitializeSpinLock(&FIBLock);
511 /* TEST: Create a test route */
512 /* Network is 10.0.0.0 */
513 /* Netmask is 255.0.0.0 */
514 /* Router is 10.0.0.1 */
515 RouterCreateRouteIPv4(0x0000000A, 0x000000FF, 0x0100000A, NTE?, 1);
517 return STATUS_SUCCESS;
521 NTSTATUS RouterShutdown(
524 * FUNCTION: Shuts down the routing subsystem
526 * Status of operation
531 TI_DbgPrint(DEBUG_ROUTER, ("Called.\n"));
533 /* Clear Forward Information Base */
534 KeAcquireSpinLock(&FIBLock, &OldIrql);
536 KeReleaseSpinLock(&FIBLock, OldIrql);
538 return STATUS_SUCCESS;