--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Ip4Route.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+\r
+/**\r
+ Allocate a route entry then initialize it with the Dest/Netmaks\r
+ and Gateway.\r
+\r
+ @param Dest The destination network\r
+ @param Netmask The destination network mask\r
+ @param GateWay The nexthop address\r
+\r
+ @return NULL if failed to allocate memeory, otherwise the newly created\r
+ @return route entry.\r
+\r
+**/\r
+STATIC\r
+IP4_ROUTE_ENTRY *\r
+Ip4CreateRouteEntry (\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Netmask,\r
+ IN IP4_ADDR GateWay\r
+ )\r
+{\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+\r
+ RtEntry = NetAllocatePool (sizeof (IP4_ROUTE_ENTRY));\r
+\r
+ if (RtEntry == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInit (&RtEntry->Link);\r
+\r
+ RtEntry->RefCnt = 1;\r
+ RtEntry->Dest = Dest;\r
+ RtEntry->Netmask = Netmask;\r
+ RtEntry->NextHop = GateWay;\r
+ RtEntry->Flag = 0;\r
+\r
+ return RtEntry;\r
+}\r
+\r
+\r
+/**\r
+ Free the route table entry. It is reference counted.\r
+\r
+ @param RtEntry The route entry to free.\r
+\r
+ @return NONE\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4FreeRouteEntry (\r
+ IN IP4_ROUTE_ENTRY *RtEntry\r
+ )\r
+{\r
+ ASSERT (RtEntry->RefCnt > 0);\r
+\r
+ if (--RtEntry->RefCnt == 0) {\r
+ NetFreePool (RtEntry);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Allocate and initialize a IP4 route cache entry.\r
+\r
+ @param Dst The destination address\r
+ @param Src The source address\r
+ @param GateWay The next hop address\r
+ @param Tag The tag from the caller. This marks all the cache\r
+ entries spawned from one route table entry.\r
+\r
+ @return NULL if failed to allocate memory for the cache, other point\r
+ @return to the created route cache entry.\r
+\r
+**/\r
+STATIC\r
+IP4_ROUTE_CACHE_ENTRY *\r
+Ip4CreateRouteCacheEntry (\r
+ IN IP4_ADDR Dst,\r
+ IN IP4_ADDR Src,\r
+ IN IP4_ADDR GateWay,\r
+ IN UINTN Tag\r
+ )\r
+{\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+\r
+ RtCacheEntry = NetAllocatePool (sizeof (IP4_ROUTE_CACHE_ENTRY));\r
+\r
+ if (RtCacheEntry == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInit (&RtCacheEntry->Link);\r
+\r
+ RtCacheEntry->RefCnt = 1;\r
+ RtCacheEntry->Dest = Dst;\r
+ RtCacheEntry->Src = Src;\r
+ RtCacheEntry->NextHop = GateWay;\r
+ RtCacheEntry->Tag = Tag;\r
+\r
+ return RtCacheEntry;\r
+}\r
+\r
+\r
+/**\r
+ Free the route cache entry. It is reference counted.\r
+\r
+ @param RtCacheEntry The route cache entry to free.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4FreeRouteCacheEntry (\r
+ IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry\r
+ )\r
+{\r
+ ASSERT (RtCacheEntry->RefCnt > 0);\r
+\r
+ if (--RtCacheEntry->RefCnt == 0) {\r
+ NetFreePool (RtCacheEntry);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Initialize an empty route cache table.\r
+\r
+ @param RtCache The rotue cache table to initialize.\r
+\r
+ @return NONE\r
+\r
+**/\r
+VOID\r
+Ip4InitRouteCache (\r
+ IN IP4_ROUTE_CACHE *RtCache\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {\r
+ NetListInit (&(RtCache->CacheBucket[Index]));\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Clean up a route cache, that is free all the route cache\r
+ entries enqueued in the cache.\r
+\r
+ @param RtCache The route cache table to clean up\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4CleanRouteCache (\r
+ IN IP4_ROUTE_CACHE *RtCache\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtCache->CacheBucket[Index])) {\r
+ RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
+\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteCacheEntry (RtCacheEntry);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
+/**\r
+ Create an empty route table, includes its internal route cache\r
+\r
+ None\r
+\r
+ @return NULL if failed to allocate memory for the route table, otherwise\r
+ @return the point to newly created route table.\r
+\r
+**/\r
+IP4_ROUTE_TABLE *\r
+Ip4CreateRouteTable (\r
+ VOID\r
+ )\r
+{\r
+ IP4_ROUTE_TABLE *RtTable;\r
+ UINT32 Index;\r
+\r
+ RtTable = NetAllocatePool (sizeof (IP4_ROUTE_TABLE));\r
+\r
+ if (RtTable == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ RtTable->RefCnt = 1;\r
+ RtTable->TotalNum = 0;\r
+\r
+ for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
+ NetListInit (&(RtTable->RouteArea[Index]));\r
+ }\r
+\r
+ RtTable->Next = NULL;\r
+\r
+ Ip4InitRouteCache (&RtTable->Cache);\r
+ return RtTable;\r
+}\r
+\r
+\r
+/**\r
+ Free the route table and its associated route cache. Route\r
+ table is reference counted.\r
+\r
+ @param RtTable The route table to free.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4FreeRouteTable (\r
+ IN IP4_ROUTE_TABLE *RtTable\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+ UINT32 Index;\r
+\r
+ ASSERT (RtTable->RefCnt > 0);\r
+\r
+ if (--RtTable->RefCnt > 0) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Free all the route table entry and its route cache.\r
+ //\r
+ for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtTable->RouteArea[Index])) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteEntry (RtEntry);\r
+ }\r
+ }\r
+\r
+ Ip4CleanRouteCache (&RtTable->Cache);\r
+\r
+ NetFreePool (RtTable);\r
+}\r
+\r
+\r
+\r
+/**\r
+ Remove all the cache entries bearing the Tag. When a route cache\r
+ entry is created, it is tagged with the address of route entry\r
+ from which it is spawned. When a route entry is deleted, the cache\r
+ entries spawned from it are also deleted.\r
+\r
+ @param RtCache Route cache to remove the entries from\r
+ @param Tag The Tag of the entries to remove\r
+\r
+ @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+Ip4PurgeRouteCache (\r
+ IN IP4_ROUTE_CACHE *RtCache,\r
+ IN UINTN Tag\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtCache->CacheBucket[Index]) {\r
+\r
+ RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
+\r
+ if (RtCacheEntry->Tag == Tag) {\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteCacheEntry (RtCacheEntry);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Add a route entry to the route table. All the IP4_ADDRs are in\r
+ host byte order.\r
+\r
+ @param RtTable Route table to add route to\r
+ @param Dest The destination of the network\r
+ @param Netmask The netmask of the destination\r
+ @param Gateway The next hop address\r
+\r
+ @retval EFI_ACCESS_DENIED The same route already exists\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the entry\r
+ @retval EFI_SUCCESS The route is added successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4AddRoute (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Netmask,\r
+ IN IP4_ADDR Gateway\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+\r
+ //\r
+ // All the route entries with the same netmask length are\r
+ // linke to the same route area\r
+ //\r
+ Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);\r
+\r
+ //\r
+ // First check whether the route exists\r
+ //\r
+ NET_LIST_FOR_EACH (Entry, Head) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Create a route entry and insert it to the route area.\r
+ //\r
+ RtEntry = Ip4CreateRouteEntry (Dest, Netmask, Gateway);\r
+\r
+ if (RtEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (Gateway == IP4_ALLZERO_ADDRESS) {\r
+ RtEntry->Flag = IP4_DIRECT_ROUTE;\r
+ }\r
+\r
+ NetListInsertHead (Head, &RtEntry->Link);\r
+ RtTable->TotalNum++;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Remove a route entry and all the route caches spawn from it.\r
+\r
+ @param RtTable The route table to remove the route from\r
+ @param Dest The destination network\r
+ @param Netmask The netmask of the Dest\r
+ @param Gateway The next hop address\r
+\r
+ @retval EFI_SUCCESS The route entry is successfully removed\r
+ @retval EFI_NOT_FOUND There is no route entry in the table with that\r
+ properity.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4DelRoute (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Netmask,\r
+ IN IP4_ADDR Gateway\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+\r
+ Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {\r
+ Ip4PurgeRouteCache (&RtTable->Cache, (UINTN) RtEntry);\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteEntry (RtEntry);\r
+\r
+ RtTable->TotalNum--;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Find a route cache with the dst and src. This is used by ICMP\r
+ redirect messasge process. All kinds of redirect is treated as\r
+ host redirect according to RFC1122. So, only route cache entries\r
+ are modified according to the ICMP redirect message.\r
+\r
+ @param RtTable The route table to search the cache for\r
+ @param Dest The destination address\r
+ @param Src The source address\r
+\r
+ @return NULL if no route entry to the (Dest, Src). Otherwise the point\r
+ @return to the correct route cache entry.\r
+\r
+**/\r
+IP4_ROUTE_CACHE_ENTRY *\r
+Ip4FindRouteCache (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Src\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+ UINT32 Index;\r
+\r
+ Index = IP4_ROUTE_CACHE_HASH (Dest, Src);\r
+\r
+ NET_LIST_FOR_EACH (Entry, &RtTable->Cache.CacheBucket[Index]) {\r
+ RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
+\r
+ if ((RtCacheEntry->Dest == Dest) && (RtCacheEntry->Src == Src)) {\r
+ NET_GET_REF (RtCacheEntry);\r
+ return RtCacheEntry;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Search the route table for a most specific match to the Dst. It searches\r
+ from the longest route area (mask length == 32) to the shortest route area (\r
+ default routes). In each route area, it will first search the instance's\r
+ route table, then the default route table. This is required by the following\r
+ requirements:\r
+ 1. IP search the route table for a most specific match\r
+ 2. The local route entries have precedence over the default route entry.\r
+\r
+ @param RtTable The route table to search from\r
+ @param Dst The destionation address to search\r
+\r
+ @return NULL if no route matches the Dst, otherwise the point to the\r
+ @return most specific route to the Dst.\r
+\r
+**/\r
+STATIC\r
+IP4_ROUTE_ENTRY *\r
+Ip4FindRouteEntry (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dst\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+ IP4_ROUTE_TABLE *Table;\r
+ INTN Index;\r
+\r
+ RtEntry = NULL;\r
+\r
+ for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {\r
+ for (Table = RtTable; Table != NULL; Table = Table->Next) {\r
+ NET_LIST_FOR_EACH (Entry, &Table->RouteArea[Index]) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ if (IP4_NET_EQUAL (RtEntry->Dest, Dst, RtEntry->Netmask)) {\r
+ NET_GET_REF (RtEntry);\r
+ return RtEntry;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Search the route table to route the packet. Return/creat a route\r
+ cache if there is a route to the destination.\r
+\r
+ @param RtTable The route table to search from\r
+ @param Dest The destination address to search for\r
+ @param Src The source address to search for\r
+\r
+ @return NULL if failed to route packet, otherwise a route cache\r
+ @return entry that can be used to route packet.\r
+\r
+**/\r
+IP4_ROUTE_CACHE_ENTRY *\r
+Ip4Route (\r
+ IN IP4_ROUTE_TABLE *RtTable,\r
+ IN IP4_ADDR Dest,\r
+ IN IP4_ADDR Src\r
+ )\r
+{\r
+ NET_LIST_ENTRY *Head;\r
+ NET_LIST_ENTRY *Entry;\r
+ NET_LIST_ENTRY *Next;\r
+ IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
+ IP4_ROUTE_CACHE_ENTRY *Cache;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+ IP4_ADDR NextHop;\r
+ UINT32 Count;\r
+\r
+ ASSERT (RtTable != NULL);\r
+\r
+ Head = &RtTable->Cache.CacheBucket[IP4_ROUTE_CACHE_HASH (Dest, Src)];\r
+ RtCacheEntry = Ip4FindRouteCache (RtTable, Dest, Src);\r
+\r
+ //\r
+ // If found, promote the cache entry to the head of the hash bucket. LRU\r
+ //\r
+ if (RtCacheEntry != NULL) {\r
+ NetListRemoveEntry (&RtCacheEntry->Link);\r
+ NetListInsertHead (Head, &RtCacheEntry->Link);\r
+ return RtCacheEntry;\r
+ }\r
+\r
+ //\r
+ // Search the route table for the most specific route\r
+ //\r
+ RtEntry = Ip4FindRouteEntry (RtTable, Dest);\r
+\r
+ if (RtEntry == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Found a route to the Dest, if it is a direct route, the packet\r
+ // will be send directly to the destination, such as for connected\r
+ // network. Otherwise, it is an indirect route, the packet will be\r
+ // send the next hop router.\r
+ //\r
+ if (RtEntry->Flag & IP4_DIRECT_ROUTE) {\r
+ NextHop = Dest;\r
+ } else {\r
+ NextHop = RtEntry->NextHop;\r
+ }\r
+\r
+ Ip4FreeRouteEntry (RtEntry);\r
+\r
+ //\r
+ // Create a route cache entry, and tag it as spawned from this route entry\r
+ //\r
+ RtCacheEntry = Ip4CreateRouteCacheEntry (Dest, Src, NextHop, (UINTN) RtEntry);\r
+\r
+ if (RtCacheEntry == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ NetListInsertHead (Head, &RtCacheEntry->Link);\r
+ NET_GET_REF (RtCacheEntry);\r
+\r
+ //\r
+ // Each bucket of route cache can contain at most 64 entries.\r
+ // Remove the entries at the tail of the bucket. These entries\r
+ // are likely to be used least.\r
+ //\r
+ Count = 0;\r
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
+ if (++Count < IP4_ROUTE_CACHE_MAX) {\r
+ continue;\r
+ }\r
+\r
+ Cache = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
+\r
+ NetListRemoveEntry (Entry);\r
+ Ip4FreeRouteCacheEntry (Cache);\r
+ }\r
+\r
+ return RtCacheEntry;\r
+}\r
+\r
+\r
+/**\r
+ Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of\r
+ GetModeData. The EFI_IP4_ROUTE_TABLE is clumsy to use in the\r
+ internal operation of the IP4 driver.\r
+\r
+ @param IpInstance The IP4 child that requests the route table.\r
+\r
+ @retval EFI_SUCCESS The route table is successfully build\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the rotue table.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4BuildEfiRouteTable (\r
+ IN IP4_PROTOCOL *IpInstance\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ NET_LIST_ENTRY *Entry;\r
+ IP4_ROUTE_TABLE *RtTable;\r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+ EFI_IP4_ROUTE_TABLE *Table;\r
+ UINT32 Count;\r
+ INT32 Index;\r
+\r
+ IpSb = IpInstance->Service;\r
+ RtTable = IpInstance->RouteTable;\r
+\r
+ if (IpInstance->EfiRouteTable != NULL) {\r
+ NetFreePool (IpInstance->EfiRouteTable);\r
+\r
+ IpInstance->EfiRouteTable = NULL;\r
+ IpInstance->EfiRouteCount = 0;\r
+ }\r
+\r
+ Count = RtTable->TotalNum;\r
+\r
+ if (RtTable->Next != NULL) {\r
+ Count += RtTable->Next->TotalNum;\r
+ }\r
+\r
+ if (Count == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Table = NetAllocatePool (sizeof (EFI_IP4_ROUTE_TABLE) * Count);\r
+\r
+ if (Table == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Copy the route entry to EFI route table. Keep the order of\r
+ // route entry copied from most specific to default route. That\r
+ // is, interlevel the route entry from the instance's route area\r
+ // and those from the default route table's route area.\r
+ //\r
+ Count = 0;\r
+\r
+ for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {\r
+ for (RtTable = IpInstance->RouteTable; RtTable != NULL; RtTable = RtTable->Next) {\r
+ NET_LIST_FOR_EACH (Entry, &(RtTable->RouteArea[Index])) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ EFI_IP4 (Table[Count].SubnetAddress) = HTONL (RtEntry->Dest & RtEntry->Netmask);\r
+ EFI_IP4 (Table[Count].SubnetMask) = HTONL (RtEntry->Netmask);\r
+ EFI_IP4 (Table[Count].GatewayAddress) = HTONL (RtEntry->NextHop);\r
+\r
+ Count++;\r
+ }\r
+ }\r
+ }\r
+\r
+ IpInstance->EfiRouteTable = Table;\r
+ IpInstance->EfiRouteCount = Count;\r
+ return EFI_SUCCESS;\r
+}\r