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