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
;
25 * FUNCTION: Frees an forward information base object
27 * Object = Pointer to an forward information base structure
30 PoolFreeBuffer(Object
);
37 * FUNCTION: Destroys an forward information base entry
39 * FIBE = Pointer to FIB entry
41 * The forward information base lock must be held when called
44 TI_DbgPrint(DEBUG_ROUTER
, ("Called. FIBE (0x%X).\n", FIBE
));
46 /* Unlink the FIB entry from the list */
47 RemoveEntryList(&FIBE
->ListEntry
);
49 /* And free the FIB entry */
57 * FUNCTION: Destroys all forward information base entries
59 * The forward information base lock must be held when called
62 PLIST_ENTRY CurrentEntry
;
63 PLIST_ENTRY NextEntry
;
66 /* Search the list and remove every FIB entry we find */
67 CurrentEntry
= FIBListHead
.Flink
;
68 while (CurrentEntry
!= &FIBListHead
) {
69 NextEntry
= CurrentEntry
->Flink
;
70 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
71 /* Destroy the FIB entry */
73 CurrentEntry
= NextEntry
;
80 PLIST_ENTRY CurrentEntry
;
81 PLIST_ENTRY NextEntry
;
83 /* Search the list and remove every FIB entry we find */
84 CurrentEntry
= FIBListHead
.Flink
;
85 while (CurrentEntry
!= &FIBListHead
) {
86 NextEntry
= CurrentEntry
->Flink
;
87 CurrentEntry
= NextEntry
;
95 UINT
CopyFIBs( PFIB_ENTRY Target
) {
97 PLIST_ENTRY CurrentEntry
;
98 PLIST_ENTRY NextEntry
;
101 /* Search the list and remove every FIB entry we find */
102 CurrentEntry
= FIBListHead
.Flink
;
103 while (CurrentEntry
!= &FIBListHead
) {
104 NextEntry
= CurrentEntry
->Flink
;
105 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
106 Target
[FibCount
] = *Current
;
107 CurrentEntry
= NextEntry
;
115 UINT
CommonPrefixLength(
116 PIP_ADDRESS Address1
,
117 PIP_ADDRESS Address2
)
119 * FUNCTION: Computes the length of the longest prefix common to two addresses
121 * Address1 = Pointer to first address
122 * Address2 = Pointer to second address
124 * The two addresses must be of the same type
126 * Length of longest common prefix
134 TI_DbgPrint(DEBUG_ROUTER
, ("Called. Address1 (0x%X) Address2 (0x%X).\n", Address1
, Address2
));
136 /*TI_DbgPrint(DEBUG_ROUTER, ("Target (%s) \n", A2S(Address1)));*/
137 /*TI_DbgPrint(DEBUG_ROUTER, ("Adapter (%s).\n", A2S(Address2)));*/
139 if (Address1
->Type
== IP_ADDRESS_V4
)
140 Size
= sizeof(IPv4_RAW_ADDRESS
);
142 Size
= sizeof(IPv6_RAW_ADDRESS
);
144 Addr1
= (PUCHAR
)&Address1
->Address
.IPv4Address
;
145 Addr2
= (PUCHAR
)&Address2
->Address
.IPv4Address
;
147 /* Find first non-matching byte */
148 for (i
= 0; i
< Size
&& Addr1
[i
] == Addr2
[i
]; i
++);
149 if( i
== Size
) return 8 * i
;
151 /* Find first non-matching bit */
153 for (j
= 0; (Addr1
[i
] & Bitmask
) == (Addr2
[i
] & Bitmask
); j
++)
156 TI_DbgPrint(DEBUG_ROUTER
, ("Returning %d\n", 8 * i
+ j
));
162 PFIB_ENTRY
RouterAddRoute(
163 PIP_ADDRESS NetworkAddress
,
165 PNEIGHBOR_CACHE_ENTRY Router
,
168 * FUNCTION: Adds a route to the Forward Information Base (FIB)
170 * NetworkAddress = Pointer to address of network
171 * Netmask = Pointer to netmask of network
172 * Router = Pointer to NCE of router to use
173 * Metric = Cost of this route
175 * Pointer to FIB entry if the route was added, NULL if not
177 * The FIB entry references the NetworkAddress, Netmask and
178 * the NCE of the router. The caller is responsible for providing
184 TI_DbgPrint(DEBUG_ROUTER
, ("Called. NetworkAddress (0x%X) Netmask (0x%X) "
185 "Router (0x%X) Metric (%d).\n", NetworkAddress
, Netmask
, Router
, Metric
));
187 TI_DbgPrint(DEBUG_ROUTER
, ("NetworkAddress (%s) Netmask (%s) Router (%s).\n",
190 A2S(&Router
->Address
)));
192 FIBE
= PoolAllocateBuffer(sizeof(FIB_ENTRY
));
194 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
198 INIT_TAG(Router
, TAG('R','O','U','T'));
200 RtlCopyMemory( &FIBE
->NetworkAddress
, NetworkAddress
,
201 sizeof(FIBE
->NetworkAddress
) );
202 RtlCopyMemory( &FIBE
->Netmask
, Netmask
,
203 sizeof(FIBE
->Netmask
) );
204 FIBE
->Router
= Router
;
205 FIBE
->Metric
= Metric
;
207 /* Add FIB to the forward information base */
208 TcpipInterlockedInsertTailList(&FIBListHead
, &FIBE
->ListEntry
, &FIBLock
);
214 PNEIGHBOR_CACHE_ENTRY
RouterGetRoute(PIP_ADDRESS Destination
)
216 * FUNCTION: Finds a router to use to get to Destination
218 * Destination = Pointer to destination address (NULL means don't care)
220 * Pointer to NCE for router, NULL if none was found
222 * If found the NCE is referenced
226 PLIST_ENTRY CurrentEntry
;
227 PLIST_ENTRY NextEntry
;
229 UCHAR State
, BestState
= 0;
230 UINT Length
, BestLength
= 0;
231 PNEIGHBOR_CACHE_ENTRY NCE
, BestNCE
= NULL
;
233 TI_DbgPrint(DEBUG_ROUTER
, ("Called. Destination (0x%X)\n", Destination
));
235 TI_DbgPrint(DEBUG_ROUTER
, ("Destination (%s)\n", A2S(Destination
)));
237 TcpipAcquireSpinLock(&FIBLock
, &OldIrql
);
239 CurrentEntry
= FIBListHead
.Flink
;
240 while (CurrentEntry
!= &FIBListHead
) {
241 NextEntry
= CurrentEntry
->Flink
;
242 Current
= CONTAINING_RECORD(CurrentEntry
, FIB_ENTRY
, ListEntry
);
244 NCE
= Current
->Router
;
248 Length
= CommonPrefixLength(Destination
, &NCE
->Address
);
253 if ((State
> BestState
) ||
254 ((State
== BestState
) &&
255 (Length
> BestLength
))) {
256 /* This seems to be a better router */
262 /* First suitable router found, save it */
268 CurrentEntry
= NextEntry
;
271 TcpipReleaseSpinLock(&FIBLock
, OldIrql
);
277 VOID
RouterRemoveRoute(
280 * FUNCTION: Removes a route from the Forward Information Base (FIB)
282 * FIBE = Pointer to FIB entry describing route
287 TI_DbgPrint(DEBUG_ROUTER
, ("Called. FIBE (0x%X).\n", FIBE
));
289 TI_DbgPrint(DEBUG_ROUTER
, ("FIBE (%s).\n", A2S(&FIBE
->NetworkAddress
)));
291 TcpipAcquireSpinLock(&FIBLock
, &OldIrql
);
293 TcpipReleaseSpinLock(&FIBLock
, OldIrql
);
297 PFIB_ENTRY
RouterCreateRoute(
298 IP_ADDRESS NetworkAddress
,
300 IP_ADDRESS RouterAddress
,
301 PIP_INTERFACE Interface
,
304 * FUNCTION: Creates a route with IPv4 addresses as parameters
306 * NetworkAddress = Address of network
307 * Netmask = Netmask of network
308 * RouterAddress = Address of router to use
309 * NTE = Pointer to NTE to use
310 * Metric = Cost of this route
312 * Pointer to FIB entry if the route was created, NULL if not.
313 * The FIB entry references the NTE. The caller is responsible
314 * for providing this reference
317 PNEIGHBOR_CACHE_ENTRY NCE
;
320 /* The NCE references RouterAddress. The NCE is referenced for us */
321 NCE
= NBAddNeighbor(Interface
,
324 Interface
->AddressLength
,
327 /* Not enough free resources */
331 FIBE
= RouterAddRoute(&NetworkAddress
, &Netmask
, NCE
, 1);
333 /* Not enough free resources */
334 NBRemoveNeighbor(NCE
);
341 NTSTATUS
RouterStartup(
344 * FUNCTION: Initializes the routing subsystem
346 * Status of operation
349 TI_DbgPrint(DEBUG_ROUTER
, ("Called.\n"));
351 /* Initialize the Forward Information Base */
352 InitializeListHead(&FIBListHead
);
353 TcpipInitializeSpinLock(&FIBLock
);
356 /* TEST: Create a test route */
357 /* Network is 10.0.0.0 */
358 /* Netmask is 255.0.0.0 */
359 /* Router is 10.0.0.1 */
360 RouterCreateRouteIPv4(0x0000000A, 0x000000FF, 0x0100000A, NTE
?, 1);
362 return STATUS_SUCCESS
;
366 NTSTATUS
RouterShutdown(
369 * FUNCTION: Shuts down the routing subsystem
371 * Status of operation
376 TI_DbgPrint(DEBUG_ROUTER
, ("Called.\n"));
378 /* Clear Forward Information Base */
379 TcpipAcquireSpinLock(&FIBLock
, &OldIrql
);
381 TcpipReleaseSpinLock(&FIBLock
, OldIrql
);
383 return STATUS_SUCCESS
;