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 * This file holds authoritative routing information.
9 * Information queries on the route table should be handled here.
10 * This information should always override the route cache info.
12 * CSH 01/08-2000 Created
18 LIST_ENTRY FIBListHead
;
21 void RouterDumpRoutes() {
22 PLIST_ENTRY CurrentEntry
;
23 PLIST_ENTRY NextEntry
;
25 PNEIGHBOR_CACHE_ENTRY NCE
;
27 TI_DbgPrint(DEBUG_ROUTER
,("Dumping Routes\n"));
29 CurrentEntry
= FIBListHead
.Flink
;
30 while (CurrentEntry
!= &FIBListHead
) {
31 NextEntry
= CurrentEntry
->Flink
;
32 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
34 NCE
= Current
->Router
;
36 TI_DbgPrint(DEBUG_ROUTER
,("Examining FIBE %x\n", Current
));
37 TI_DbgPrint(DEBUG_ROUTER
,("... NetworkAddress %s\n", A2S(&Current
->NetworkAddress
)));
38 TI_DbgPrint(DEBUG_ROUTER
,("... NCE->Address . %s\n", A2S(&NCE
->Address
)));
40 CurrentEntry
= NextEntry
;
43 TI_DbgPrint(DEBUG_ROUTER
,("Dumping Routes ... Done\n"));
49 * FUNCTION: Frees an forward information base object
51 * Object = Pointer to an forward information base structure
61 * FUNCTION: Destroys an forward information base entry
63 * FIBE = Pointer to FIB entry
65 * The forward information base lock must be held when called
68 TI_DbgPrint(DEBUG_ROUTER
, ("Called. FIBE (0x%X).\n", FIBE
));
70 /* Unlink the FIB entry from the list */
71 RemoveEntryList(&FIBE
->ListEntry
);
73 /* And free the FIB entry */
81 * FUNCTION: Destroys all forward information base entries
83 * The forward information base lock must be held when called
86 PLIST_ENTRY CurrentEntry
;
87 PLIST_ENTRY NextEntry
;
90 /* Search the list and remove every FIB entry we find */
91 CurrentEntry
= FIBListHead
.Flink
;
92 while (CurrentEntry
!= &FIBListHead
) {
93 NextEntry
= CurrentEntry
->Flink
;
94 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
95 /* Destroy the FIB entry */
97 CurrentEntry
= NextEntry
;
102 UINT
CountFIBs(PIP_INTERFACE IF
) {
104 PLIST_ENTRY CurrentEntry
;
105 PLIST_ENTRY NextEntry
;
108 CurrentEntry
= FIBListHead
.Flink
;
109 while (CurrentEntry
!= &FIBListHead
) {
110 NextEntry
= CurrentEntry
->Flink
;
111 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
112 if (Current
->Router
->Interface
== IF
)
114 CurrentEntry
= NextEntry
;
121 UINT
CopyFIBs( PIP_INTERFACE IF
, PFIB_ENTRY Target
) {
123 PLIST_ENTRY CurrentEntry
;
124 PLIST_ENTRY NextEntry
;
127 CurrentEntry
= FIBListHead
.Flink
;
128 while (CurrentEntry
!= &FIBListHead
) {
129 NextEntry
= CurrentEntry
->Flink
;
130 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
131 if (Current
->Router
->Interface
== IF
)
133 Target
[FibCount
] = *Current
;
136 CurrentEntry
= NextEntry
;
143 UINT
CommonPrefixLength(
144 PIP_ADDRESS Address1
,
145 PIP_ADDRESS Address2
)
147 * FUNCTION: Computes the length of the longest prefix common to two addresses
149 * Address1 = Pointer to first address
150 * Address2 = Pointer to second address
152 * The two addresses must be of the same type
154 * Length of longest common prefix
162 TI_DbgPrint(DEBUG_ROUTER
, ("Called. Address1 (0x%X) Address2 (0x%X).\n", Address1
, Address2
));
164 /*TI_DbgPrint(DEBUG_ROUTER, ("Target (%s) \n", A2S(Address1)));*/
165 /*TI_DbgPrint(DEBUG_ROUTER, ("Adapter (%s).\n", A2S(Address2)));*/
167 if (Address1
->Type
== IP_ADDRESS_V4
)
168 Size
= sizeof(IPv4_RAW_ADDRESS
);
170 Size
= sizeof(IPv6_RAW_ADDRESS
);
172 Addr1
= (PUCHAR
)&Address1
->Address
.IPv4Address
;
173 Addr2
= (PUCHAR
)&Address2
->Address
.IPv4Address
;
175 /* Find first non-matching byte */
176 for (i
= 0; i
< Size
&& Addr1
[i
] == Addr2
[i
]; i
++);
177 if( i
== Size
) return 8 * i
;
179 /* Find first non-matching bit */
181 for (j
= 0; (Addr1
[i
] & Bitmask
) == (Addr2
[i
] & Bitmask
); j
++)
184 TI_DbgPrint(DEBUG_ROUTER
, ("Returning %d\n", 8 * i
+ j
));
190 PFIB_ENTRY
RouterAddRoute(
191 PIP_ADDRESS NetworkAddress
,
193 PNEIGHBOR_CACHE_ENTRY Router
,
196 * FUNCTION: Adds a route to the Forward Information Base (FIB)
198 * NetworkAddress = Pointer to address of network
199 * Netmask = Pointer to netmask of network
200 * Router = Pointer to NCE of router to use
201 * Metric = Cost of this route
203 * Pointer to FIB entry if the route was added, NULL if not
205 * The FIB entry references the NetworkAddress, Netmask and
206 * the NCE of the router. The caller is responsible for providing
212 TI_DbgPrint(DEBUG_ROUTER
, ("Called. NetworkAddress (0x%X) Netmask (0x%X) "
213 "Router (0x%X) Metric (%d).\n", NetworkAddress
, Netmask
, Router
, Metric
));
215 TI_DbgPrint(DEBUG_ROUTER
, ("NetworkAddress (%s) Netmask (%s) Router (%s).\n",
218 A2S(&Router
->Address
)));
220 FIBE
= exAllocatePool(NonPagedPool
, sizeof(FIB_ENTRY
));
222 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
226 INIT_TAG(Router
, 'TUOR');
228 RtlCopyMemory( &FIBE
->NetworkAddress
, NetworkAddress
,
229 sizeof(FIBE
->NetworkAddress
) );
230 RtlCopyMemory( &FIBE
->Netmask
, Netmask
,
231 sizeof(FIBE
->Netmask
) );
232 FIBE
->Router
= Router
;
233 FIBE
->Metric
= Metric
;
235 /* Add FIB to the forward information base */
236 TcpipInterlockedInsertTailList(&FIBListHead
, &FIBE
->ListEntry
, &FIBLock
);
242 PNEIGHBOR_CACHE_ENTRY
RouterGetRoute(PIP_ADDRESS Destination
)
244 * FUNCTION: Finds a router to use to get to Destination
246 * Destination = Pointer to destination address (NULL means don't care)
248 * Pointer to NCE for router, NULL if none was found
250 * If found the NCE is referenced
254 PLIST_ENTRY CurrentEntry
;
255 PLIST_ENTRY NextEntry
;
257 UCHAR State
, BestState
= 0;
258 UINT Length
, BestLength
= 0, MaskLength
;
259 PNEIGHBOR_CACHE_ENTRY NCE
, BestNCE
= NULL
;
261 TI_DbgPrint(DEBUG_ROUTER
, ("Called. Destination (0x%X)\n", Destination
));
263 TI_DbgPrint(DEBUG_ROUTER
, ("Destination (%s)\n", A2S(Destination
)));
265 TcpipAcquireSpinLock(&FIBLock
, &OldIrql
);
267 CurrentEntry
= FIBListHead
.Flink
;
268 while (CurrentEntry
!= &FIBListHead
) {
269 NextEntry
= CurrentEntry
->Flink
;
270 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
272 NCE
= Current
->Router
;
275 Length
= CommonPrefixLength(Destination
, &Current
->NetworkAddress
);
276 MaskLength
= AddrCountPrefixBits(&Current
->Netmask
);
278 TI_DbgPrint(DEBUG_ROUTER
,("This-Route: %s (Sharing %d bits)\n",
279 A2S(&NCE
->Address
), Length
));
281 if(Length
>= MaskLength
&& (Length
> BestLength
|| !BestNCE
) &&
282 (!(State
& NUD_STALE
) || !BestNCE
)) {
283 /* This seems to be a better router */
287 TI_DbgPrint(DEBUG_ROUTER
,("Route selected\n"));
290 CurrentEntry
= NextEntry
;
293 TcpipReleaseSpinLock(&FIBLock
, OldIrql
);
296 TI_DbgPrint(DEBUG_ROUTER
,("Routing to %s\n", A2S(&BestNCE
->Address
)));
298 TI_DbgPrint(DEBUG_ROUTER
,("Packet won't be routed\n"));
304 PNEIGHBOR_CACHE_ENTRY
RouteGetRouteToDestination(PIP_ADDRESS Destination
)
306 * FUNCTION: Locates an RCN describing a route to a destination address
308 * Destination = Pointer to destination address to find route to
309 * RCN = Address of pointer to an RCN
311 * Status of operation
313 * The RCN is referenced for the caller. The caller is responsible
314 * for dereferencing it after use
317 PNEIGHBOR_CACHE_ENTRY NCE
= NULL
;
318 PIP_INTERFACE Interface
;
320 TI_DbgPrint(DEBUG_RCACHE
, ("Called. Destination (0x%X)\n", Destination
));
322 TI_DbgPrint(DEBUG_RCACHE
, ("Destination (%s)\n", A2S(Destination
)));
325 TI_DbgPrint(MIN_TRACE
, ("Displaying tree (before).\n"));
326 PrintTree(RouteCache
);
329 /* Check if the destination is on-link */
330 Interface
= FindOnLinkInterface(Destination
);
332 /* The destination address is on-link. Check our neighbor cache */
333 NCE
= NBFindOrCreateNeighbor(Interface
, Destination
);
335 /* Destination is not on any subnets we're on. Find a router to use */
336 NCE
= RouterGetRoute(Destination
);
340 TI_DbgPrint(DEBUG_ROUTER
,("Interface->MTU: %d\n", NCE
->Interface
->MTU
));
345 NTSTATUS
RouterRemoveRoute(PIP_ADDRESS Target
, PIP_ADDRESS Router
)
347 * FUNCTION: Removes a route from the Forward Information Base (FIB)
349 * Target: The machine or network targeted by the route
350 * Router: The router used to pass the packet to the destination
352 * Searches the FIB and removes a route matching the indicated parameters.
356 PLIST_ENTRY CurrentEntry
;
357 PLIST_ENTRY NextEntry
;
359 BOOLEAN Found
= FALSE
;
360 PNEIGHBOR_CACHE_ENTRY NCE
;
362 TI_DbgPrint(DEBUG_ROUTER
, ("Called\n"));
363 TI_DbgPrint(DEBUG_ROUTER
, ("Deleting Route From: %s\n", A2S(Router
)));
364 TI_DbgPrint(DEBUG_ROUTER
, (" To: %s\n", A2S(Target
)));
366 TcpipAcquireSpinLock(&FIBLock
, &OldIrql
);
370 CurrentEntry
= FIBListHead
.Flink
;
371 while (CurrentEntry
!= &FIBListHead
) {
372 NextEntry
= CurrentEntry
->Flink
;
373 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
375 NCE
= Current
->Router
;
377 if( AddrIsEqual( &Current
->NetworkAddress
, Target
) &&
378 AddrIsEqual( &NCE
->Address
, Router
) ) {
384 CurrentEntry
= NextEntry
;
388 TI_DbgPrint(DEBUG_ROUTER
, ("Deleting route\n"));
389 DestroyFIBE( Current
);
394 TcpipReleaseSpinLock(&FIBLock
, OldIrql
);
396 TI_DbgPrint(DEBUG_ROUTER
, ("Leaving\n"));
398 return Found
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
402 PFIB_ENTRY
RouterCreateRoute(
403 PIP_ADDRESS NetworkAddress
,
405 PIP_ADDRESS RouterAddress
,
406 PIP_INTERFACE Interface
,
409 * FUNCTION: Creates a route with IPv4 addresses as parameters
411 * NetworkAddress = Address of network
412 * Netmask = Netmask of network
413 * RouterAddress = Address of router to use
414 * NTE = Pointer to NTE to use
415 * Metric = Cost of this route
417 * Pointer to FIB entry if the route was created, NULL if not.
418 * The FIB entry references the NTE. The caller is responsible
419 * for providing this reference
423 PLIST_ENTRY CurrentEntry
;
424 PLIST_ENTRY NextEntry
;
426 PNEIGHBOR_CACHE_ENTRY NCE
;
428 TcpipAcquireSpinLock(&FIBLock
, &OldIrql
);
430 CurrentEntry
= FIBListHead
.Flink
;
431 while (CurrentEntry
!= &FIBListHead
) {
432 NextEntry
= CurrentEntry
->Flink
;
433 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
435 NCE
= Current
->Router
;
437 if( AddrIsEqual(NetworkAddress
, &Current
->NetworkAddress
) &&
438 AddrIsEqual(Netmask
, &Current
->Netmask
) ) {
439 TI_DbgPrint(DEBUG_ROUTER
,("Attempting to add duplicate route to %s\n", A2S(NetworkAddress
)));
440 TcpipReleaseSpinLock(&FIBLock
, OldIrql
);
444 CurrentEntry
= NextEntry
;
447 TcpipReleaseSpinLock(&FIBLock
, OldIrql
);
449 /* The NCE references RouterAddress. The NCE is referenced for us */
450 NCE
= NBFindOrCreateNeighbor(Interface
, RouterAddress
);
453 /* Not enough free resources */
457 return RouterAddRoute(NetworkAddress
, Netmask
, NCE
, Metric
);
461 NTSTATUS
RouterStartup(
464 * FUNCTION: Initializes the routing subsystem
466 * Status of operation
469 TI_DbgPrint(DEBUG_ROUTER
, ("Called.\n"));
471 /* Initialize the Forward Information Base */
472 InitializeListHead(&FIBListHead
);
473 TcpipInitializeSpinLock(&FIBLock
);
475 return STATUS_SUCCESS
;
479 NTSTATUS
RouterShutdown(
482 * FUNCTION: Shuts down the routing subsystem
484 * Status of operation
489 TI_DbgPrint(DEBUG_ROUTER
, ("Called.\n"));
491 /* Clear Forward Information Base */
492 TcpipAcquireSpinLock(&FIBLock
, &OldIrql
);
494 TcpipReleaseSpinLock(&FIBLock
, OldIrql
);
496 return STATUS_SUCCESS
;