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