Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenrouter.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS TCP/IP protocol driver 00004 * FILE: network/router.c 00005 * PURPOSE: IP routing subsystem 00006 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 00007 * NOTES: 00008 * This file holds authoritative routing information. 00009 * Information queries on the route table should be handled here. 00010 * This information should always override the route cache info. 00011 * REVISIONS: 00012 * CSH 01/08-2000 Created 00013 */ 00014 00015 #include "precomp.h" 00016 00017 00018 LIST_ENTRY FIBListHead; 00019 KSPIN_LOCK FIBLock; 00020 00021 void RouterDumpRoutes() { 00022 PLIST_ENTRY CurrentEntry; 00023 PLIST_ENTRY NextEntry; 00024 PFIB_ENTRY Current; 00025 PNEIGHBOR_CACHE_ENTRY NCE; 00026 00027 TI_DbgPrint(DEBUG_ROUTER,("Dumping Routes\n")); 00028 00029 CurrentEntry = FIBListHead.Flink; 00030 while (CurrentEntry != &FIBListHead) { 00031 NextEntry = CurrentEntry->Flink; 00032 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); 00033 00034 NCE = Current->Router; 00035 00036 TI_DbgPrint(DEBUG_ROUTER,("Examining FIBE %x\n", Current)); 00037 TI_DbgPrint(DEBUG_ROUTER,("... NetworkAddress %s\n", A2S(&Current->NetworkAddress))); 00038 TI_DbgPrint(DEBUG_ROUTER,("... NCE->Address . %s\n", A2S(&NCE->Address))); 00039 00040 CurrentEntry = NextEntry; 00041 } 00042 00043 TI_DbgPrint(DEBUG_ROUTER,("Dumping Routes ... Done\n")); 00044 } 00045 00046 VOID FreeFIB( 00047 PVOID Object) 00048 /* 00049 * FUNCTION: Frees an forward information base object 00050 * ARGUMENTS: 00051 * Object = Pointer to an forward information base structure 00052 */ 00053 { 00054 ExFreePoolWithTag(Object, FIB_TAG); 00055 } 00056 00057 00058 VOID DestroyFIBE( 00059 PFIB_ENTRY FIBE) 00060 /* 00061 * FUNCTION: Destroys an forward information base entry 00062 * ARGUMENTS: 00063 * FIBE = Pointer to FIB entry 00064 * NOTES: 00065 * The forward information base lock must be held when called 00066 */ 00067 { 00068 TI_DbgPrint(DEBUG_ROUTER, ("Called. FIBE (0x%X).\n", FIBE)); 00069 00070 /* Unlink the FIB entry from the list */ 00071 RemoveEntryList(&FIBE->ListEntry); 00072 00073 /* And free the FIB entry */ 00074 FreeFIB(FIBE); 00075 } 00076 00077 00078 VOID DestroyFIBEs( 00079 VOID) 00080 /* 00081 * FUNCTION: Destroys all forward information base entries 00082 * NOTES: 00083 * The forward information base lock must be held when called 00084 */ 00085 { 00086 PLIST_ENTRY CurrentEntry; 00087 PLIST_ENTRY NextEntry; 00088 PFIB_ENTRY Current; 00089 00090 /* Search the list and remove every FIB entry we find */ 00091 CurrentEntry = FIBListHead.Flink; 00092 while (CurrentEntry != &FIBListHead) { 00093 NextEntry = CurrentEntry->Flink; 00094 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); 00095 /* Destroy the FIB entry */ 00096 DestroyFIBE(Current); 00097 CurrentEntry = NextEntry; 00098 } 00099 } 00100 00101 00102 UINT CountFIBs(PIP_INTERFACE IF) { 00103 UINT FibCount = 0; 00104 PLIST_ENTRY CurrentEntry; 00105 PLIST_ENTRY NextEntry; 00106 PFIB_ENTRY Current; 00107 00108 CurrentEntry = FIBListHead.Flink; 00109 while (CurrentEntry != &FIBListHead) { 00110 NextEntry = CurrentEntry->Flink; 00111 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); 00112 if (Current->Router->Interface == IF) 00113 FibCount++; 00114 CurrentEntry = NextEntry; 00115 } 00116 00117 return FibCount; 00118 } 00119 00120 00121 UINT CopyFIBs( PIP_INTERFACE IF, PFIB_ENTRY Target ) { 00122 UINT FibCount = 0; 00123 PLIST_ENTRY CurrentEntry; 00124 PLIST_ENTRY NextEntry; 00125 PFIB_ENTRY Current; 00126 00127 CurrentEntry = FIBListHead.Flink; 00128 while (CurrentEntry != &FIBListHead) { 00129 NextEntry = CurrentEntry->Flink; 00130 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); 00131 if (Current->Router->Interface == IF) 00132 { 00133 Target[FibCount] = *Current; 00134 FibCount++; 00135 } 00136 CurrentEntry = NextEntry; 00137 } 00138 00139 return FibCount; 00140 } 00141 00142 00143 UINT CommonPrefixLength( 00144 PIP_ADDRESS Address1, 00145 PIP_ADDRESS Address2) 00146 /* 00147 * FUNCTION: Computes the length of the longest prefix common to two addresses 00148 * ARGUMENTS: 00149 * Address1 = Pointer to first address 00150 * Address2 = Pointer to second address 00151 * NOTES: 00152 * The two addresses must be of the same type 00153 * RETURNS: 00154 * Length of longest common prefix 00155 */ 00156 { 00157 PUCHAR Addr1, Addr2; 00158 UINT Size; 00159 UINT i, j; 00160 UINT Bitmask; 00161 00162 TI_DbgPrint(DEBUG_ROUTER, ("Called. Address1 (0x%X) Address2 (0x%X).\n", Address1, Address2)); 00163 00164 /*TI_DbgPrint(DEBUG_ROUTER, ("Target (%s) \n", A2S(Address1)));*/ 00165 /*TI_DbgPrint(DEBUG_ROUTER, ("Adapter (%s).\n", A2S(Address2)));*/ 00166 00167 if (Address1->Type == IP_ADDRESS_V4) 00168 Size = sizeof(IPv4_RAW_ADDRESS); 00169 else 00170 Size = sizeof(IPv6_RAW_ADDRESS); 00171 00172 Addr1 = (PUCHAR)&Address1->Address.IPv4Address; 00173 Addr2 = (PUCHAR)&Address2->Address.IPv4Address; 00174 00175 /* Find first non-matching byte */ 00176 for (i = 0; i < Size && Addr1[i] == Addr2[i]; i++); 00177 if( i == Size ) return 8 * i; 00178 00179 /* Find first non-matching bit */ 00180 Bitmask = 0x80; 00181 for (j = 0; (Addr1[i] & Bitmask) == (Addr2[i] & Bitmask); j++) 00182 Bitmask >>= 1; 00183 00184 TI_DbgPrint(DEBUG_ROUTER, ("Returning %d\n", 8 * i + j)); 00185 00186 return 8 * i + j; 00187 } 00188 00189 00190 PFIB_ENTRY RouterAddRoute( 00191 PIP_ADDRESS NetworkAddress, 00192 PIP_ADDRESS Netmask, 00193 PNEIGHBOR_CACHE_ENTRY Router, 00194 UINT Metric) 00195 /* 00196 * FUNCTION: Adds a route to the Forward Information Base (FIB) 00197 * ARGUMENTS: 00198 * NetworkAddress = Pointer to address of network 00199 * Netmask = Pointer to netmask of network 00200 * Router = Pointer to NCE of router to use 00201 * Metric = Cost of this route 00202 * RETURNS: 00203 * Pointer to FIB entry if the route was added, NULL if not 00204 * NOTES: 00205 * The FIB entry references the NetworkAddress, Netmask and 00206 * the NCE of the router. The caller is responsible for providing 00207 * these references 00208 */ 00209 { 00210 PFIB_ENTRY FIBE; 00211 00212 TI_DbgPrint(DEBUG_ROUTER, ("Called. NetworkAddress (0x%X) Netmask (0x%X) " 00213 "Router (0x%X) Metric (%d).\n", NetworkAddress, Netmask, Router, Metric)); 00214 00215 TI_DbgPrint(DEBUG_ROUTER, ("NetworkAddress (%s) Netmask (%s) Router (%s).\n", 00216 A2S(NetworkAddress), 00217 A2S(Netmask), 00218 A2S(&Router->Address))); 00219 00220 FIBE = ExAllocatePoolWithTag(NonPagedPool, sizeof(FIB_ENTRY), FIB_TAG); 00221 if (!FIBE) { 00222 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); 00223 return NULL; 00224 } 00225 00226 RtlCopyMemory( &FIBE->NetworkAddress, NetworkAddress, 00227 sizeof(FIBE->NetworkAddress) ); 00228 RtlCopyMemory( &FIBE->Netmask, Netmask, 00229 sizeof(FIBE->Netmask) ); 00230 FIBE->Router = Router; 00231 FIBE->Metric = Metric; 00232 00233 /* Add FIB to the forward information base */ 00234 TcpipInterlockedInsertTailList(&FIBListHead, &FIBE->ListEntry, &FIBLock); 00235 00236 return FIBE; 00237 } 00238 00239 00240 PNEIGHBOR_CACHE_ENTRY RouterGetRoute(PIP_ADDRESS Destination) 00241 /* 00242 * FUNCTION: Finds a router to use to get to Destination 00243 * ARGUMENTS: 00244 * Destination = Pointer to destination address (NULL means don't care) 00245 * RETURNS: 00246 * Pointer to NCE for router, NULL if none was found 00247 * NOTES: 00248 * If found the NCE is referenced 00249 */ 00250 { 00251 KIRQL OldIrql; 00252 PLIST_ENTRY CurrentEntry; 00253 PLIST_ENTRY NextEntry; 00254 PFIB_ENTRY Current; 00255 UCHAR State; 00256 UINT Length, BestLength = 0, MaskLength; 00257 PNEIGHBOR_CACHE_ENTRY NCE, BestNCE = NULL; 00258 00259 TI_DbgPrint(DEBUG_ROUTER, ("Called. Destination (0x%X)\n", Destination)); 00260 00261 TI_DbgPrint(DEBUG_ROUTER, ("Destination (%s)\n", A2S(Destination))); 00262 00263 TcpipAcquireSpinLock(&FIBLock, &OldIrql); 00264 00265 CurrentEntry = FIBListHead.Flink; 00266 while (CurrentEntry != &FIBListHead) { 00267 NextEntry = CurrentEntry->Flink; 00268 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); 00269 00270 NCE = Current->Router; 00271 State = NCE->State; 00272 00273 Length = CommonPrefixLength(Destination, &Current->NetworkAddress); 00274 MaskLength = AddrCountPrefixBits(&Current->Netmask); 00275 00276 TI_DbgPrint(DEBUG_ROUTER,("This-Route: %s (Sharing %d bits)\n", 00277 A2S(&NCE->Address), Length)); 00278 00279 if(Length >= MaskLength && (Length > BestLength || !BestNCE) && 00280 (!(State & NUD_STALE) || !BestNCE)) { 00281 /* This seems to be a better router */ 00282 BestNCE = NCE; 00283 BestLength = Length; 00284 TI_DbgPrint(DEBUG_ROUTER,("Route selected\n")); 00285 } 00286 00287 CurrentEntry = NextEntry; 00288 } 00289 00290 TcpipReleaseSpinLock(&FIBLock, OldIrql); 00291 00292 if( BestNCE ) { 00293 TI_DbgPrint(DEBUG_ROUTER,("Routing to %s\n", A2S(&BestNCE->Address))); 00294 } else { 00295 TI_DbgPrint(DEBUG_ROUTER,("Packet won't be routed\n")); 00296 } 00297 00298 return BestNCE; 00299 } 00300 00301 PNEIGHBOR_CACHE_ENTRY RouteGetRouteToDestination(PIP_ADDRESS Destination) 00302 /* 00303 * FUNCTION: Locates an RCN describing a route to a destination address 00304 * ARGUMENTS: 00305 * Destination = Pointer to destination address to find route to 00306 * RCN = Address of pointer to an RCN 00307 * RETURNS: 00308 * Status of operation 00309 * NOTES: 00310 * The RCN is referenced for the caller. The caller is responsible 00311 * for dereferencing it after use 00312 */ 00313 { 00314 PNEIGHBOR_CACHE_ENTRY NCE = NULL; 00315 PIP_INTERFACE Interface; 00316 00317 TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X)\n", Destination)); 00318 00319 TI_DbgPrint(DEBUG_RCACHE, ("Destination (%s)\n", A2S(Destination))); 00320 00321 #if 0 00322 TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n")); 00323 PrintTree(RouteCache); 00324 #endif 00325 00326 /* Check if the destination is on-link */ 00327 Interface = FindOnLinkInterface(Destination); 00328 if (Interface) { 00329 /* The destination address is on-link. Check our neighbor cache */ 00330 NCE = NBFindOrCreateNeighbor(Interface, Destination, FALSE); 00331 } else { 00332 /* Destination is not on any subnets we're on. Find a router to use */ 00333 NCE = RouterGetRoute(Destination); 00334 } 00335 00336 if( NCE ) 00337 TI_DbgPrint(DEBUG_ROUTER,("Interface->MTU: %d\n", NCE->Interface->MTU)); 00338 00339 return NCE; 00340 } 00341 00342 VOID RouterRemoveRoutesForInterface(PIP_INTERFACE Interface) 00343 { 00344 KIRQL OldIrql; 00345 PLIST_ENTRY CurrentEntry; 00346 PLIST_ENTRY NextEntry; 00347 PFIB_ENTRY Current; 00348 00349 TcpipAcquireSpinLock(&FIBLock, &OldIrql); 00350 00351 CurrentEntry = FIBListHead.Flink; 00352 while (CurrentEntry != &FIBListHead) { 00353 NextEntry = CurrentEntry->Flink; 00354 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); 00355 00356 if (Interface == Current->Router->Interface) 00357 DestroyFIBE(Current); 00358 00359 CurrentEntry = NextEntry; 00360 } 00361 00362 TcpipReleaseSpinLock(&FIBLock, OldIrql); 00363 } 00364 00365 NTSTATUS RouterRemoveRoute(PIP_ADDRESS Target, PIP_ADDRESS Router) 00366 /* 00367 * FUNCTION: Removes a route from the Forward Information Base (FIB) 00368 * ARGUMENTS: 00369 * Target: The machine or network targeted by the route 00370 * Router: The router used to pass the packet to the destination 00371 * 00372 * Searches the FIB and removes a route matching the indicated parameters. 00373 */ 00374 { 00375 KIRQL OldIrql; 00376 PLIST_ENTRY CurrentEntry; 00377 PLIST_ENTRY NextEntry; 00378 PFIB_ENTRY Current; 00379 BOOLEAN Found = FALSE; 00380 PNEIGHBOR_CACHE_ENTRY NCE; 00381 00382 TI_DbgPrint(DEBUG_ROUTER, ("Called\n")); 00383 TI_DbgPrint(DEBUG_ROUTER, ("Deleting Route From: %s\n", A2S(Router))); 00384 TI_DbgPrint(DEBUG_ROUTER, (" To: %s\n", A2S(Target))); 00385 00386 TcpipAcquireSpinLock(&FIBLock, &OldIrql); 00387 00388 RouterDumpRoutes(); 00389 00390 CurrentEntry = FIBListHead.Flink; 00391 while (CurrentEntry != &FIBListHead) { 00392 NextEntry = CurrentEntry->Flink; 00393 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); 00394 00395 NCE = Current->Router; 00396 00397 if( AddrIsEqual( &Current->NetworkAddress, Target ) && 00398 AddrIsEqual( &NCE->Address, Router ) ) { 00399 Found = TRUE; 00400 break; 00401 } 00402 00403 Current = NULL; 00404 CurrentEntry = NextEntry; 00405 } 00406 00407 if( Found ) { 00408 TI_DbgPrint(DEBUG_ROUTER, ("Deleting route\n")); 00409 DestroyFIBE( Current ); 00410 } 00411 00412 RouterDumpRoutes(); 00413 00414 TcpipReleaseSpinLock(&FIBLock, OldIrql); 00415 00416 TI_DbgPrint(DEBUG_ROUTER, ("Leaving\n")); 00417 00418 return Found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; 00419 } 00420 00421 00422 PFIB_ENTRY RouterCreateRoute( 00423 PIP_ADDRESS NetworkAddress, 00424 PIP_ADDRESS Netmask, 00425 PIP_ADDRESS RouterAddress, 00426 PIP_INTERFACE Interface, 00427 UINT Metric) 00428 /* 00429 * FUNCTION: Creates a route with IPv4 addresses as parameters 00430 * ARGUMENTS: 00431 * NetworkAddress = Address of network 00432 * Netmask = Netmask of network 00433 * RouterAddress = Address of router to use 00434 * NTE = Pointer to NTE to use 00435 * Metric = Cost of this route 00436 * RETURNS: 00437 * Pointer to FIB entry if the route was created, NULL if not. 00438 * The FIB entry references the NTE. The caller is responsible 00439 * for providing this reference 00440 */ 00441 { 00442 KIRQL OldIrql; 00443 PLIST_ENTRY CurrentEntry; 00444 PLIST_ENTRY NextEntry; 00445 PFIB_ENTRY Current; 00446 PNEIGHBOR_CACHE_ENTRY NCE; 00447 00448 TcpipAcquireSpinLock(&FIBLock, &OldIrql); 00449 00450 CurrentEntry = FIBListHead.Flink; 00451 while (CurrentEntry != &FIBListHead) { 00452 NextEntry = CurrentEntry->Flink; 00453 Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); 00454 00455 NCE = Current->Router; 00456 00457 if(AddrIsEqual(NetworkAddress, &Current->NetworkAddress) && 00458 AddrIsEqual(Netmask, &Current->Netmask) && 00459 NCE->Interface == Interface) 00460 { 00461 TI_DbgPrint(DEBUG_ROUTER,("Attempting to add duplicate route to %s\n", A2S(NetworkAddress))); 00462 TcpipReleaseSpinLock(&FIBLock, OldIrql); 00463 return NULL; 00464 } 00465 00466 CurrentEntry = NextEntry; 00467 } 00468 00469 TcpipReleaseSpinLock(&FIBLock, OldIrql); 00470 00471 /* The NCE references RouterAddress. The NCE is referenced for us */ 00472 NCE = NBFindOrCreateNeighbor(Interface, RouterAddress, TRUE); 00473 00474 if (!NCE) { 00475 /* Not enough free resources */ 00476 return NULL; 00477 } 00478 00479 return RouterAddRoute(NetworkAddress, Netmask, NCE, Metric); 00480 } 00481 00482 00483 NTSTATUS RouterStartup( 00484 VOID) 00485 /* 00486 * FUNCTION: Initializes the routing subsystem 00487 * RETURNS: 00488 * Status of operation 00489 */ 00490 { 00491 TI_DbgPrint(DEBUG_ROUTER, ("Called.\n")); 00492 00493 /* Initialize the Forward Information Base */ 00494 InitializeListHead(&FIBListHead); 00495 TcpipInitializeSpinLock(&FIBLock); 00496 00497 return STATUS_SUCCESS; 00498 } 00499 00500 00501 NTSTATUS RouterShutdown( 00502 VOID) 00503 /* 00504 * FUNCTION: Shuts down the routing subsystem 00505 * RETURNS: 00506 * Status of operation 00507 */ 00508 { 00509 KIRQL OldIrql; 00510 00511 TI_DbgPrint(DEBUG_ROUTER, ("Called.\n")); 00512 00513 /* Clear Forward Information Base */ 00514 TcpipAcquireSpinLock(&FIBLock, &OldIrql); 00515 DestroyFIBEs(); 00516 TcpipReleaseSpinLock(&FIBLock, OldIrql); 00517 00518 return STATUS_SUCCESS; 00519 } 00520 00521 /* EOF */ Generated on Sun May 27 2012 04:26:34 for ReactOS by
1.7.6.1
|