ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

router.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.