]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Route.c
ECP_PEI_PCI_CFG_PPI should be passed to ECP_PEI_PCI_CFG_PPI's function.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Route.c
CommitLineData
772db4bb 1/** @file\r
2\r
3Copyright (c) 2005 - 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12\r
13Module Name:\r
14\r
15 Ip4Route.c\r
16\r
17Abstract:\r
18\r
19\r
20**/\r
21\r
22#include "Ip4Impl.h"\r
23\r
24\r
25/**\r
26 Allocate a route entry then initialize it with the Dest/Netmaks\r
27 and Gateway.\r
28\r
29 @param Dest The destination network\r
30 @param Netmask The destination network mask\r
31 @param GateWay The nexthop address\r
32\r
33 @return NULL if failed to allocate memeory, otherwise the newly created\r
34 @return route entry.\r
35\r
36**/\r
772db4bb 37IP4_ROUTE_ENTRY *\r
38Ip4CreateRouteEntry (\r
39 IN IP4_ADDR Dest,\r
40 IN IP4_ADDR Netmask,\r
41 IN IP4_ADDR GateWay\r
42 )\r
43{\r
44 IP4_ROUTE_ENTRY *RtEntry;\r
45\r
e48e37fc 46 RtEntry = AllocatePool (sizeof (IP4_ROUTE_ENTRY));\r
772db4bb 47\r
48 if (RtEntry == NULL) {\r
49 return NULL;\r
50 }\r
51\r
e48e37fc 52 InitializeListHead (&RtEntry->Link);\r
772db4bb 53\r
54 RtEntry->RefCnt = 1;\r
55 RtEntry->Dest = Dest;\r
56 RtEntry->Netmask = Netmask;\r
57 RtEntry->NextHop = GateWay;\r
58 RtEntry->Flag = 0;\r
59\r
60 return RtEntry;\r
61}\r
62\r
63\r
64/**\r
65 Free the route table entry. It is reference counted.\r
66\r
67 @param RtEntry The route entry to free.\r
68\r
69 @return NONE\r
70\r
71**/\r
772db4bb 72VOID\r
73Ip4FreeRouteEntry (\r
74 IN IP4_ROUTE_ENTRY *RtEntry\r
75 )\r
76{\r
77 ASSERT (RtEntry->RefCnt > 0);\r
78\r
79 if (--RtEntry->RefCnt == 0) {\r
e48e37fc 80 gBS->FreePool (RtEntry);\r
772db4bb 81 }\r
82}\r
83\r
84\r
85/**\r
86 Allocate and initialize a IP4 route cache entry.\r
87\r
88 @param Dst The destination address\r
89 @param Src The source address\r
90 @param GateWay The next hop address\r
91 @param Tag The tag from the caller. This marks all the cache\r
92 entries spawned from one route table entry.\r
93\r
94 @return NULL if failed to allocate memory for the cache, other point\r
95 @return to the created route cache entry.\r
96\r
97**/\r
772db4bb 98IP4_ROUTE_CACHE_ENTRY *\r
99Ip4CreateRouteCacheEntry (\r
100 IN IP4_ADDR Dst,\r
101 IN IP4_ADDR Src,\r
102 IN IP4_ADDR GateWay,\r
103 IN UINTN Tag\r
104 )\r
105{\r
106 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
107\r
e48e37fc 108 RtCacheEntry = AllocatePool (sizeof (IP4_ROUTE_CACHE_ENTRY));\r
772db4bb 109\r
110 if (RtCacheEntry == NULL) {\r
111 return NULL;\r
112 }\r
113\r
e48e37fc 114 InitializeListHead (&RtCacheEntry->Link);\r
772db4bb 115\r
116 RtCacheEntry->RefCnt = 1;\r
117 RtCacheEntry->Dest = Dst;\r
118 RtCacheEntry->Src = Src;\r
119 RtCacheEntry->NextHop = GateWay;\r
120 RtCacheEntry->Tag = Tag;\r
121\r
122 return RtCacheEntry;\r
123}\r
124\r
125\r
126/**\r
127 Free the route cache entry. It is reference counted.\r
128\r
129 @param RtCacheEntry The route cache entry to free.\r
130\r
131 @return None\r
132\r
133**/\r
134VOID\r
135Ip4FreeRouteCacheEntry (\r
136 IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry\r
137 )\r
138{\r
139 ASSERT (RtCacheEntry->RefCnt > 0);\r
140\r
141 if (--RtCacheEntry->RefCnt == 0) {\r
e48e37fc 142 gBS->FreePool (RtCacheEntry);\r
772db4bb 143 }\r
144}\r
145\r
146\r
147/**\r
148 Initialize an empty route cache table.\r
149\r
150 @param RtCache The rotue cache table to initialize.\r
151\r
152 @return NONE\r
153\r
154**/\r
155VOID\r
156Ip4InitRouteCache (\r
157 IN IP4_ROUTE_CACHE *RtCache\r
158 )\r
159{\r
160 UINT32 Index;\r
161\r
162 for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {\r
e48e37fc 163 InitializeListHead (&(RtCache->CacheBucket[Index]));\r
772db4bb 164 }\r
165}\r
166\r
167\r
168/**\r
169 Clean up a route cache, that is free all the route cache\r
170 entries enqueued in the cache.\r
171\r
172 @param RtCache The route cache table to clean up\r
173\r
174 @return None\r
175\r
176**/\r
177VOID\r
178Ip4CleanRouteCache (\r
179 IN IP4_ROUTE_CACHE *RtCache\r
180 )\r
181{\r
e48e37fc 182 LIST_ENTRY *Entry;\r
183 LIST_ENTRY *Next;\r
772db4bb 184 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
185 UINT32 Index;\r
186\r
187 for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {\r
188 NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtCache->CacheBucket[Index])) {\r
189 RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
190\r
e48e37fc 191 RemoveEntryList (Entry);\r
772db4bb 192 Ip4FreeRouteCacheEntry (RtCacheEntry);\r
193 }\r
194 }\r
195}\r
196\r
197\r
198\r
199/**\r
200 Create an empty route table, includes its internal route cache\r
201\r
202 None\r
203\r
204 @return NULL if failed to allocate memory for the route table, otherwise\r
205 @return the point to newly created route table.\r
206\r
207**/\r
208IP4_ROUTE_TABLE *\r
209Ip4CreateRouteTable (\r
210 VOID\r
211 )\r
212{\r
213 IP4_ROUTE_TABLE *RtTable;\r
214 UINT32 Index;\r
215\r
e48e37fc 216 RtTable = AllocatePool (sizeof (IP4_ROUTE_TABLE));\r
772db4bb 217\r
218 if (RtTable == NULL) {\r
219 return NULL;\r
220 }\r
221\r
222 RtTable->RefCnt = 1;\r
223 RtTable->TotalNum = 0;\r
224\r
225 for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
e48e37fc 226 InitializeListHead (&(RtTable->RouteArea[Index]));\r
772db4bb 227 }\r
228\r
229 RtTable->Next = NULL;\r
230\r
231 Ip4InitRouteCache (&RtTable->Cache);\r
232 return RtTable;\r
233}\r
234\r
235\r
236/**\r
237 Free the route table and its associated route cache. Route\r
238 table is reference counted.\r
239\r
240 @param RtTable The route table to free.\r
241\r
242 @return None\r
243\r
244**/\r
245VOID\r
246Ip4FreeRouteTable (\r
247 IN IP4_ROUTE_TABLE *RtTable\r
248 )\r
249{\r
e48e37fc 250 LIST_ENTRY *Entry;\r
251 LIST_ENTRY *Next;\r
772db4bb 252 IP4_ROUTE_ENTRY *RtEntry;\r
253 UINT32 Index;\r
254\r
255 ASSERT (RtTable->RefCnt > 0);\r
256\r
257 if (--RtTable->RefCnt > 0) {\r
258 return ;\r
259 }\r
260\r
261 //\r
262 // Free all the route table entry and its route cache.\r
263 //\r
264 for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
265 NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtTable->RouteArea[Index])) {\r
266 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
267\r
e48e37fc 268 RemoveEntryList (Entry);\r
772db4bb 269 Ip4FreeRouteEntry (RtEntry);\r
270 }\r
271 }\r
272\r
273 Ip4CleanRouteCache (&RtTable->Cache);\r
274\r
e48e37fc 275 gBS->FreePool (RtTable);\r
772db4bb 276}\r
277\r
278\r
279\r
280/**\r
281 Remove all the cache entries bearing the Tag. When a route cache\r
282 entry is created, it is tagged with the address of route entry\r
283 from which it is spawned. When a route entry is deleted, the cache\r
284 entries spawned from it are also deleted.\r
285\r
286 @param RtCache Route cache to remove the entries from\r
287 @param Tag The Tag of the entries to remove\r
288\r
289 @return None\r
290\r
291**/\r
772db4bb 292VOID\r
293Ip4PurgeRouteCache (\r
294 IN IP4_ROUTE_CACHE *RtCache,\r
295 IN UINTN Tag\r
296 )\r
297{\r
e48e37fc 298 LIST_ENTRY *Entry;\r
299 LIST_ENTRY *Next;\r
772db4bb 300 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
301 UINT32 Index;\r
302\r
303 for (Index = 0; Index < IP4_ROUTE_CACHE_HASH; Index++) {\r
304 NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtCache->CacheBucket[Index]) {\r
305\r
306 RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
307\r
308 if (RtCacheEntry->Tag == Tag) {\r
e48e37fc 309 RemoveEntryList (Entry);\r
772db4bb 310 Ip4FreeRouteCacheEntry (RtCacheEntry);\r
311 }\r
312 }\r
313 }\r
314}\r
315\r
316\r
317/**\r
318 Add a route entry to the route table. All the IP4_ADDRs are in\r
319 host byte order.\r
320\r
321 @param RtTable Route table to add route to\r
322 @param Dest The destination of the network\r
323 @param Netmask The netmask of the destination\r
324 @param Gateway The next hop address\r
325\r
326 @retval EFI_ACCESS_DENIED The same route already exists\r
327 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the entry\r
328 @retval EFI_SUCCESS The route is added successfully.\r
329\r
330**/\r
331EFI_STATUS\r
332Ip4AddRoute (\r
333 IN IP4_ROUTE_TABLE *RtTable,\r
334 IN IP4_ADDR Dest,\r
335 IN IP4_ADDR Netmask,\r
336 IN IP4_ADDR Gateway\r
337 )\r
338{\r
e48e37fc 339 LIST_ENTRY *Head;\r
340 LIST_ENTRY *Entry;\r
772db4bb 341 IP4_ROUTE_ENTRY *RtEntry;\r
342\r
343 //\r
344 // All the route entries with the same netmask length are\r
345 // linke to the same route area\r
346 //\r
347 Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);\r
348\r
349 //\r
350 // First check whether the route exists\r
351 //\r
352 NET_LIST_FOR_EACH (Entry, Head) {\r
353 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
354\r
355 if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {\r
356 return EFI_ACCESS_DENIED;\r
357 }\r
358 }\r
359\r
360 //\r
361 // Create a route entry and insert it to the route area.\r
362 //\r
363 RtEntry = Ip4CreateRouteEntry (Dest, Netmask, Gateway);\r
364\r
365 if (RtEntry == NULL) {\r
366 return EFI_OUT_OF_RESOURCES;\r
367 }\r
368\r
369 if (Gateway == IP4_ALLZERO_ADDRESS) {\r
370 RtEntry->Flag = IP4_DIRECT_ROUTE;\r
371 }\r
372\r
e48e37fc 373 InsertHeadList (Head, &RtEntry->Link);\r
772db4bb 374 RtTable->TotalNum++;\r
375\r
376 return EFI_SUCCESS;\r
377}\r
378\r
379\r
380/**\r
381 Remove a route entry and all the route caches spawn from it.\r
382\r
383 @param RtTable The route table to remove the route from\r
384 @param Dest The destination network\r
385 @param Netmask The netmask of the Dest\r
386 @param Gateway The next hop address\r
387\r
388 @retval EFI_SUCCESS The route entry is successfully removed\r
389 @retval EFI_NOT_FOUND There is no route entry in the table with that\r
390 properity.\r
391\r
392**/\r
393EFI_STATUS\r
394Ip4DelRoute (\r
395 IN IP4_ROUTE_TABLE *RtTable,\r
396 IN IP4_ADDR Dest,\r
397 IN IP4_ADDR Netmask,\r
398 IN IP4_ADDR Gateway\r
399 )\r
400{\r
e48e37fc 401 LIST_ENTRY *Head;\r
402 LIST_ENTRY *Entry;\r
403 LIST_ENTRY *Next;\r
772db4bb 404 IP4_ROUTE_ENTRY *RtEntry;\r
405\r
406 Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);\r
407\r
408 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
409 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
410\r
411 if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {\r
412 Ip4PurgeRouteCache (&RtTable->Cache, (UINTN) RtEntry);\r
e48e37fc 413 RemoveEntryList (Entry);\r
772db4bb 414 Ip4FreeRouteEntry (RtEntry);\r
415\r
416 RtTable->TotalNum--;\r
417 return EFI_SUCCESS;\r
418 }\r
419 }\r
420\r
421 return EFI_NOT_FOUND;\r
422}\r
423\r
424\r
425/**\r
426 Find a route cache with the dst and src. This is used by ICMP\r
427 redirect messasge process. All kinds of redirect is treated as\r
428 host redirect according to RFC1122. So, only route cache entries\r
429 are modified according to the ICMP redirect message.\r
430\r
431 @param RtTable The route table to search the cache for\r
432 @param Dest The destination address\r
433 @param Src The source address\r
434\r
435 @return NULL if no route entry to the (Dest, Src). Otherwise the point\r
436 @return to the correct route cache entry.\r
437\r
438**/\r
439IP4_ROUTE_CACHE_ENTRY *\r
440Ip4FindRouteCache (\r
441 IN IP4_ROUTE_TABLE *RtTable,\r
442 IN IP4_ADDR Dest,\r
443 IN IP4_ADDR Src\r
444 )\r
445{\r
e48e37fc 446 LIST_ENTRY *Entry;\r
772db4bb 447 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
448 UINT32 Index;\r
449\r
450 Index = IP4_ROUTE_CACHE_HASH (Dest, Src);\r
451\r
452 NET_LIST_FOR_EACH (Entry, &RtTable->Cache.CacheBucket[Index]) {\r
453 RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
454\r
455 if ((RtCacheEntry->Dest == Dest) && (RtCacheEntry->Src == Src)) {\r
456 NET_GET_REF (RtCacheEntry);\r
457 return RtCacheEntry;\r
458 }\r
459 }\r
460\r
461 return NULL;\r
462}\r
463\r
464\r
465/**\r
466 Search the route table for a most specific match to the Dst. It searches\r
467 from the longest route area (mask length == 32) to the shortest route area (\r
468 default routes). In each route area, it will first search the instance's\r
469 route table, then the default route table. This is required by the following\r
470 requirements:\r
471 1. IP search the route table for a most specific match\r
472 2. The local route entries have precedence over the default route entry.\r
473\r
474 @param RtTable The route table to search from\r
475 @param Dst The destionation address to search\r
476\r
477 @return NULL if no route matches the Dst, otherwise the point to the\r
478 @return most specific route to the Dst.\r
479\r
480**/\r
772db4bb 481IP4_ROUTE_ENTRY *\r
482Ip4FindRouteEntry (\r
483 IN IP4_ROUTE_TABLE *RtTable,\r
484 IN IP4_ADDR Dst\r
485 )\r
486{\r
e48e37fc 487 LIST_ENTRY *Entry;\r
772db4bb 488 IP4_ROUTE_ENTRY *RtEntry;\r
489 IP4_ROUTE_TABLE *Table;\r
490 INTN Index;\r
491\r
492 RtEntry = NULL;\r
493\r
494 for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {\r
495 for (Table = RtTable; Table != NULL; Table = Table->Next) {\r
496 NET_LIST_FOR_EACH (Entry, &Table->RouteArea[Index]) {\r
497 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
498\r
499 if (IP4_NET_EQUAL (RtEntry->Dest, Dst, RtEntry->Netmask)) {\r
500 NET_GET_REF (RtEntry);\r
501 return RtEntry;\r
502 }\r
503 }\r
504 }\r
505 }\r
506\r
507\r
508 return NULL;\r
509}\r
510\r
511\r
512/**\r
513 Search the route table to route the packet. Return/creat a route\r
514 cache if there is a route to the destination.\r
515\r
516 @param RtTable The route table to search from\r
517 @param Dest The destination address to search for\r
518 @param Src The source address to search for\r
519\r
520 @return NULL if failed to route packet, otherwise a route cache\r
521 @return entry that can be used to route packet.\r
522\r
523**/\r
524IP4_ROUTE_CACHE_ENTRY *\r
525Ip4Route (\r
526 IN IP4_ROUTE_TABLE *RtTable,\r
527 IN IP4_ADDR Dest,\r
528 IN IP4_ADDR Src\r
529 )\r
530{\r
e48e37fc 531 LIST_ENTRY *Head;\r
532 LIST_ENTRY *Entry;\r
533 LIST_ENTRY *Next;\r
772db4bb 534 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;\r
535 IP4_ROUTE_CACHE_ENTRY *Cache;\r
536 IP4_ROUTE_ENTRY *RtEntry;\r
537 IP4_ADDR NextHop;\r
538 UINT32 Count;\r
539\r
540 ASSERT (RtTable != NULL);\r
541\r
542 Head = &RtTable->Cache.CacheBucket[IP4_ROUTE_CACHE_HASH (Dest, Src)];\r
543 RtCacheEntry = Ip4FindRouteCache (RtTable, Dest, Src);\r
544\r
545 //\r
546 // If found, promote the cache entry to the head of the hash bucket. LRU\r
547 //\r
548 if (RtCacheEntry != NULL) {\r
e48e37fc 549 RemoveEntryList (&RtCacheEntry->Link);\r
550 InsertHeadList (Head, &RtCacheEntry->Link);\r
772db4bb 551 return RtCacheEntry;\r
552 }\r
553\r
554 //\r
555 // Search the route table for the most specific route\r
556 //\r
557 RtEntry = Ip4FindRouteEntry (RtTable, Dest);\r
558\r
559 if (RtEntry == NULL) {\r
560 return NULL;\r
561 }\r
562\r
563 //\r
564 // Found a route to the Dest, if it is a direct route, the packet\r
565 // will be send directly to the destination, such as for connected\r
566 // network. Otherwise, it is an indirect route, the packet will be\r
567 // send the next hop router.\r
568 //\r
5405e9a6 569 if ((RtEntry->Flag & IP4_DIRECT_ROUTE) != 0) {\r
772db4bb 570 NextHop = Dest;\r
571 } else {\r
572 NextHop = RtEntry->NextHop;\r
573 }\r
574\r
575 Ip4FreeRouteEntry (RtEntry);\r
576\r
577 //\r
578 // Create a route cache entry, and tag it as spawned from this route entry\r
579 //\r
580 RtCacheEntry = Ip4CreateRouteCacheEntry (Dest, Src, NextHop, (UINTN) RtEntry);\r
581\r
582 if (RtCacheEntry == NULL) {\r
583 return NULL;\r
584 }\r
585\r
e48e37fc 586 InsertHeadList (Head, &RtCacheEntry->Link);\r
772db4bb 587 NET_GET_REF (RtCacheEntry);\r
588\r
589 //\r
590 // Each bucket of route cache can contain at most 64 entries.\r
591 // Remove the entries at the tail of the bucket. These entries\r
592 // are likely to be used least.\r
593 //\r
594 Count = 0;\r
595 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
596 if (++Count < IP4_ROUTE_CACHE_MAX) {\r
597 continue;\r
598 }\r
599\r
600 Cache = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);\r
601\r
e48e37fc 602 RemoveEntryList (Entry);\r
772db4bb 603 Ip4FreeRouteCacheEntry (Cache);\r
604 }\r
605\r
606 return RtCacheEntry;\r
607}\r
608\r
609\r
610/**\r
611 Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of\r
612 GetModeData. The EFI_IP4_ROUTE_TABLE is clumsy to use in the\r
613 internal operation of the IP4 driver.\r
614\r
615 @param IpInstance The IP4 child that requests the route table.\r
616\r
617 @retval EFI_SUCCESS The route table is successfully build\r
618 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the rotue table.\r
619\r
620**/\r
621EFI_STATUS\r
622Ip4BuildEfiRouteTable (\r
623 IN IP4_PROTOCOL *IpInstance\r
624 )\r
625{\r
e48e37fc 626 LIST_ENTRY *Entry;\r
772db4bb 627 IP4_ROUTE_TABLE *RtTable;\r
628 IP4_ROUTE_ENTRY *RtEntry;\r
629 EFI_IP4_ROUTE_TABLE *Table;\r
630 UINT32 Count;\r
631 INT32 Index;\r
632\r
772db4bb 633 RtTable = IpInstance->RouteTable;\r
634\r
635 if (IpInstance->EfiRouteTable != NULL) {\r
e48e37fc 636 gBS->FreePool (IpInstance->EfiRouteTable);\r
772db4bb 637\r
638 IpInstance->EfiRouteTable = NULL;\r
639 IpInstance->EfiRouteCount = 0;\r
640 }\r
641\r
642 Count = RtTable->TotalNum;\r
643\r
644 if (RtTable->Next != NULL) {\r
645 Count += RtTable->Next->TotalNum;\r
646 }\r
647\r
648 if (Count == 0) {\r
649 return EFI_SUCCESS;\r
650 }\r
651\r
e48e37fc 652 Table = AllocatePool (sizeof (EFI_IP4_ROUTE_TABLE) * Count);\r
772db4bb 653\r
654 if (Table == NULL) {\r
655 return EFI_OUT_OF_RESOURCES;\r
656 }\r
657\r
658 //\r
659 // Copy the route entry to EFI route table. Keep the order of\r
660 // route entry copied from most specific to default route. That\r
661 // is, interlevel the route entry from the instance's route area\r
662 // and those from the default route table's route area.\r
663 //\r
664 Count = 0;\r
665\r
666 for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {\r
667 for (RtTable = IpInstance->RouteTable; RtTable != NULL; RtTable = RtTable->Next) {\r
668 NET_LIST_FOR_EACH (Entry, &(RtTable->RouteArea[Index])) {\r
669 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
670\r
671 EFI_IP4 (Table[Count].SubnetAddress) = HTONL (RtEntry->Dest & RtEntry->Netmask);\r
672 EFI_IP4 (Table[Count].SubnetMask) = HTONL (RtEntry->Netmask);\r
673 EFI_IP4 (Table[Count].GatewayAddress) = HTONL (RtEntry->NextHop);\r
674\r
675 Count++;\r
676 }\r
677 }\r
678 }\r
679\r
680 IpInstance->EfiRouteTable = Table;\r
681 IpInstance->EfiRouteCount = Count;\r
682 return EFI_SUCCESS;\r
683}\r