TianoCore EDK2 master
Loading...
Searching...
No Matches
Ip4Route.c
Go to the documentation of this file.
1
8#include "Ip4Impl.h"
9
24 IN IP4_ADDR Dest,
25 IN IP4_ADDR Netmask,
26 IN IP4_ADDR GateWay
27 )
28{
29 IP4_ROUTE_ENTRY *RtEntry;
30
31 RtEntry = AllocatePool (sizeof (IP4_ROUTE_ENTRY));
32
33 if (RtEntry == NULL) {
34 return NULL;
35 }
36
37 InitializeListHead (&RtEntry->Link);
38
39 RtEntry->RefCnt = 1;
40 RtEntry->Dest = Dest;
41 RtEntry->Netmask = Netmask;
42 RtEntry->NextHop = GateWay;
43 RtEntry->Flag = 0;
44
45 return RtEntry;
46}
47
54VOID
56 IN IP4_ROUTE_ENTRY *RtEntry
57 )
58{
59 ASSERT (RtEntry->RefCnt > 0);
60
61 if (--RtEntry->RefCnt == 0) {
62 FreePool (RtEntry);
63 }
64}
65
81 IN IP4_ADDR Dst,
82 IN IP4_ADDR Src,
83 IN IP4_ADDR GateWay,
84 IN UINTN Tag
85 )
86{
87 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
88
89 RtCacheEntry = AllocatePool (sizeof (IP4_ROUTE_CACHE_ENTRY));
90
91 if (RtCacheEntry == NULL) {
92 return NULL;
93 }
94
95 InitializeListHead (&RtCacheEntry->Link);
96
97 RtCacheEntry->RefCnt = 1;
98 RtCacheEntry->Dest = Dst;
99 RtCacheEntry->Src = Src;
100 RtCacheEntry->NextHop = GateWay;
101 RtCacheEntry->Tag = Tag;
102
103 return RtCacheEntry;
104}
105
112VOID
114 IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry
115 )
116{
117 ASSERT (RtCacheEntry->RefCnt > 0);
118
119 if (--RtCacheEntry->RefCnt == 0) {
120 FreePool (RtCacheEntry);
121 }
122}
123
130VOID
132 IN OUT IP4_ROUTE_CACHE *RtCache
133 )
134{
135 UINT32 Index;
136
137 for (Index = 0; Index < IP4_ROUTE_CACHE_HASH_VALUE; Index++) {
138 InitializeListHead (&(RtCache->CacheBucket[Index]));
139 }
140}
141
149VOID
151 IN IP4_ROUTE_CACHE *RtCache
152 )
153{
154 LIST_ENTRY *Entry;
155 LIST_ENTRY *Next;
156 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
157 UINT32 Index;
158
159 for (Index = 0; Index < IP4_ROUTE_CACHE_HASH_VALUE; Index++) {
160 NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtCache->CacheBucket[Index])) {
161 RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
162
163 RemoveEntryList (Entry);
164 Ip4FreeRouteCacheEntry (RtCacheEntry);
165 }
166 }
167}
168
178 VOID
179 )
180{
181 IP4_ROUTE_TABLE *RtTable;
182 UINT32 Index;
183
184 RtTable = AllocatePool (sizeof (IP4_ROUTE_TABLE));
185
186 if (RtTable == NULL) {
187 return NULL;
188 }
189
190 RtTable->RefCnt = 1;
191 RtTable->TotalNum = 0;
192
193 for (Index = 0; Index <= IP4_MASK_MAX; Index++) {
194 InitializeListHead (&(RtTable->RouteArea[Index]));
195 }
196
197 RtTable->Next = NULL;
198
199 Ip4InitRouteCache (&RtTable->Cache);
200 return RtTable;
201}
202
210VOID
212 IN IP4_ROUTE_TABLE *RtTable
213 )
214{
215 LIST_ENTRY *Entry;
216 LIST_ENTRY *Next;
217 IP4_ROUTE_ENTRY *RtEntry;
218 UINT32 Index;
219
220 ASSERT (RtTable->RefCnt > 0);
221
222 if (--RtTable->RefCnt > 0) {
223 return;
224 }
225
226 //
227 // Free all the route table entry and its route cache.
228 //
229 for (Index = 0; Index <= IP4_MASK_MAX; Index++) {
230 NET_LIST_FOR_EACH_SAFE (Entry, Next, &(RtTable->RouteArea[Index])) {
231 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
232
233 RemoveEntryList (Entry);
234 Ip4FreeRouteEntry (RtEntry);
235 }
236 }
237
238 Ip4CleanRouteCache (&RtTable->Cache);
239
240 FreePool (RtTable);
241}
242
253VOID
255 IN OUT IP4_ROUTE_CACHE *RtCache,
256 IN UINTN Tag
257 )
258{
259 LIST_ENTRY *Entry;
260 LIST_ENTRY *Next;
261 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
262 UINT32 Index;
263
264 for (Index = 0; Index < IP4_ROUTE_CACHE_HASH_VALUE; Index++) {
265 NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtCache->CacheBucket[Index]) {
266 RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
267
268 if (RtCacheEntry->Tag == Tag) {
269 RemoveEntryList (Entry);
270 Ip4FreeRouteCacheEntry (RtCacheEntry);
271 }
272 }
273 }
274}
275
292 IN OUT IP4_ROUTE_TABLE *RtTable,
293 IN IP4_ADDR Dest,
294 IN IP4_ADDR Netmask,
295 IN IP4_ADDR Gateway
296 )
297{
298 LIST_ENTRY *Head;
299 LIST_ENTRY *Entry;
300 IP4_ROUTE_ENTRY *RtEntry;
301
302 //
303 // All the route entries with the same netmask length are
304 // linke to the same route area
305 //
306 Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);
307
308 //
309 // First check whether the route exists
310 //
311 NET_LIST_FOR_EACH (Entry, Head) {
312 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
313
314 if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {
315 return EFI_ACCESS_DENIED;
316 }
317 }
318
319 //
320 // Create a route entry and insert it to the route area.
321 //
322 RtEntry = Ip4CreateRouteEntry (Dest, Netmask, Gateway);
323
324 if (RtEntry == NULL) {
325 return EFI_OUT_OF_RESOURCES;
326 }
327
328 if (Gateway == IP4_ALLZERO_ADDRESS) {
329 RtEntry->Flag = IP4_DIRECT_ROUTE;
330 }
331
332 InsertHeadList (Head, &RtEntry->Link);
333 RtTable->TotalNum++;
334
335 return EFI_SUCCESS;
336}
337
353 IN OUT IP4_ROUTE_TABLE *RtTable,
354 IN IP4_ADDR Dest,
355 IN IP4_ADDR Netmask,
356 IN IP4_ADDR Gateway
357 )
358{
359 LIST_ENTRY *Head;
360 LIST_ENTRY *Entry;
361 LIST_ENTRY *Next;
362 IP4_ROUTE_ENTRY *RtEntry;
363
364 Head = &(RtTable->RouteArea[NetGetMaskLength (Netmask)]);
365
366 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
367 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
368
369 if (IP4_NET_EQUAL (RtEntry->Dest, Dest, Netmask) && (RtEntry->NextHop == Gateway)) {
370 Ip4PurgeRouteCache (&RtTable->Cache, (UINTN)RtEntry);
371 RemoveEntryList (Entry);
372 Ip4FreeRouteEntry (RtEntry);
373
374 RtTable->TotalNum--;
375 return EFI_SUCCESS;
376 }
377 }
378
379 return EFI_NOT_FOUND;
380}
381
398 IN IP4_ROUTE_TABLE *RtTable,
399 IN IP4_ADDR Dest,
400 IN IP4_ADDR Src
401 )
402{
403 LIST_ENTRY *Entry;
404 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
405 UINT32 Index;
406
407 Index = IP4_ROUTE_CACHE_HASH (Dest, Src);
408
409 NET_LIST_FOR_EACH (Entry, &RtTable->Cache.CacheBucket[Index]) {
410 RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
411
412 if ((RtCacheEntry->Dest == Dest) && (RtCacheEntry->Src == Src)) {
413 NET_GET_REF (RtCacheEntry);
414 return RtCacheEntry;
415 }
416 }
417
418 return NULL;
419}
420
439 IN IP4_ROUTE_TABLE *RtTable,
440 IN IP4_ADDR Dst
441 )
442{
443 LIST_ENTRY *Entry;
444 IP4_ROUTE_ENTRY *RtEntry;
445 IP4_ROUTE_TABLE *Table;
446 INTN Index;
447
448 RtEntry = NULL;
449
450 for (Index = IP4_MASK_MAX; Index >= 0; Index--) {
451 for (Table = RtTable; Table != NULL; Table = Table->Next) {
452 NET_LIST_FOR_EACH (Entry, &Table->RouteArea[Index]) {
453 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
454
455 if (IP4_NET_EQUAL (RtEntry->Dest, Dst, RtEntry->Netmask)) {
456 NET_GET_REF (RtEntry);
457 return RtEntry;
458 }
459 }
460 }
461 }
462
463 return NULL;
464}
465
485 IN IP4_ROUTE_TABLE *RtTable,
486 IN IP4_ADDR Dest,
487 IN IP4_ADDR Src,
488 IN IP4_ADDR SubnetMask,
489 IN BOOLEAN AlwaysTryDestAddr
490 )
491{
492 LIST_ENTRY *Head;
493 LIST_ENTRY *Entry;
494 LIST_ENTRY *Next;
495 IP4_ROUTE_CACHE_ENTRY *RtCacheEntry;
497 IP4_ROUTE_ENTRY *RtEntry;
498 IP4_ADDR NextHop;
499 UINT32 Count;
500
501 ASSERT (RtTable != NULL);
502
503 Head = &RtTable->Cache.CacheBucket[IP4_ROUTE_CACHE_HASH (Dest, Src)];
504 RtCacheEntry = Ip4FindRouteCache (RtTable, Dest, Src);
505
506 //
507 // If found, promote the cache entry to the head of the hash bucket. LRU
508 //
509 if (RtCacheEntry != NULL) {
510 RemoveEntryList (&RtCacheEntry->Link);
511 InsertHeadList (Head, &RtCacheEntry->Link);
512 return RtCacheEntry;
513 }
514
515 //
516 // Search the route table for the most specific route
517 //
518 RtEntry = Ip4FindRouteEntry (RtTable, Dest);
519
520 if (RtEntry == NULL) {
521 if (SubnetMask != IP4_ALLONE_ADDRESS) {
522 return NULL;
523 } else if (!AlwaysTryDestAddr) {
524 return NULL;
525 }
526 }
527
528 //
529 // Found a route to the Dest, if it is a direct route, the packet
530 // will be sent directly to the destination, such as for connected
531 // network. Otherwise, it is an indirect route, the packet will be
532 // sent to the next hop router.
533 //
534 // When using /32 subnet mask, the packet will always be sent to the direct
535 // destination first, if we can't find a matching route cache.
536 //
537 if ((SubnetMask == IP4_ALLONE_ADDRESS) || ((RtEntry->Flag & IP4_DIRECT_ROUTE) != 0)) {
538 NextHop = Dest;
539 } else {
540 NextHop = RtEntry->NextHop;
541 }
542
543 if (RtEntry != NULL) {
544 Ip4FreeRouteEntry (RtEntry);
545 }
546
547 //
548 // Create a route cache entry, and tag it as spawned from this route entry
549 // For /32 subnet mask, the default route in RtEntry will be used if failed
550 // to send the packet to driect destination address.
551 //
552 RtCacheEntry = Ip4CreateRouteCacheEntry (Dest, Src, NextHop, (UINTN)RtEntry);
553
554 if (RtCacheEntry == NULL) {
555 return NULL;
556 }
557
558 InsertHeadList (Head, &RtCacheEntry->Link);
559 NET_GET_REF (RtCacheEntry);
560
561 //
562 // Each bucket of route cache can contain at most 64 entries.
563 // Remove the entries at the tail of the bucket. These entries
564 // are likely to be used least.
565 //
566 Count = 0;
567 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
568 if (++Count < IP4_ROUTE_CACHE_MAX) {
569 continue;
570 }
571
572 Cache = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_CACHE_ENTRY, Link);
573
574 RemoveEntryList (Entry);
576 }
577
578 return RtCacheEntry;
579}
580
594 IN IP4_PROTOCOL *IpInstance
595 )
596{
597 LIST_ENTRY *Entry;
598 IP4_ROUTE_TABLE *RtTable;
599 IP4_ROUTE_ENTRY *RtEntry;
600 EFI_IP4_ROUTE_TABLE *Table;
601 UINT32 Count;
602 INT32 Index;
603
604 RtTable = IpInstance->RouteTable;
605
606 if (IpInstance->EfiRouteTable != NULL) {
607 FreePool (IpInstance->EfiRouteTable);
608
609 IpInstance->EfiRouteTable = NULL;
610 IpInstance->EfiRouteCount = 0;
611 }
612
613 Count = RtTable->TotalNum;
614
615 if (RtTable->Next != NULL) {
616 Count += RtTable->Next->TotalNum;
617 }
618
619 if (Count == 0) {
620 return EFI_SUCCESS;
621 }
622
623 Table = AllocatePool (sizeof (EFI_IP4_ROUTE_TABLE) * Count);
624
625 if (Table == NULL) {
626 return EFI_OUT_OF_RESOURCES;
627 }
628
629 //
630 // Copy the route entry to EFI route table. Keep the order of
631 // route entry copied from most specific to default route. That
632 // is, interlevel the route entry from the instance's route area
633 // and those from the default route table's route area.
634 //
635 Count = 0;
636
637 for (Index = IP4_MASK_MAX; Index >= 0; Index--) {
638 for (RtTable = IpInstance->RouteTable; RtTable != NULL; RtTable = RtTable->Next) {
639 NET_LIST_FOR_EACH (Entry, &(RtTable->RouteArea[Index])) {
640 RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
641
642 EFI_IP4 (Table[Count].SubnetAddress) = HTONL (RtEntry->Dest & RtEntry->Netmask);
643 EFI_IP4 (Table[Count].SubnetMask) = HTONL (RtEntry->Netmask);
644 EFI_IP4 (Table[Count].GatewayAddress) = HTONL (RtEntry->NextHop);
645
646 Count++;
647 }
648 }
649 }
650
651 IpInstance->EfiRouteTable = Table;
652 IpInstance->EfiRouteCount = Count;
653 return EFI_SUCCESS;
654}
UINT64 UINTN
INT64 INTN
LIST_ENTRY *EFIAPI InsertHeadList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:218
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS Ip4BuildEfiRouteTable(IN IP4_PROTOCOL *IpInstance)
Definition: Ip4Route.c:593
IP4_ROUTE_CACHE_ENTRY * Ip4FindRouteCache(IN IP4_ROUTE_TABLE *RtTable, IN IP4_ADDR Dest, IN IP4_ADDR Src)
Definition: Ip4Route.c:397
EFI_STATUS Ip4DelRoute(IN OUT IP4_ROUTE_TABLE *RtTable, IN IP4_ADDR Dest, IN IP4_ADDR Netmask, IN IP4_ADDR Gateway)
Definition: Ip4Route.c:352
VOID Ip4FreeRouteCacheEntry(IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry)
Definition: Ip4Route.c:113
VOID Ip4CleanRouteCache(IN IP4_ROUTE_CACHE *RtCache)
Definition: Ip4Route.c:150
IP4_ROUTE_TABLE * Ip4CreateRouteTable(VOID)
Definition: Ip4Route.c:177
IP4_ROUTE_ENTRY * Ip4FindRouteEntry(IN IP4_ROUTE_TABLE *RtTable, IN IP4_ADDR Dst)
Definition: Ip4Route.c:438
IP4_ROUTE_CACHE_ENTRY * Ip4Route(IN IP4_ROUTE_TABLE *RtTable, IN IP4_ADDR Dest, IN IP4_ADDR Src, IN IP4_ADDR SubnetMask, IN BOOLEAN AlwaysTryDestAddr)
Definition: Ip4Route.c:484
VOID Ip4InitRouteCache(IN OUT IP4_ROUTE_CACHE *RtCache)
Definition: Ip4Route.c:131
IP4_ROUTE_ENTRY * Ip4CreateRouteEntry(IN IP4_ADDR Dest, IN IP4_ADDR Netmask, IN IP4_ADDR GateWay)
Definition: Ip4Route.c:23
EFI_STATUS Ip4AddRoute(IN OUT IP4_ROUTE_TABLE *RtTable, IN IP4_ADDR Dest, IN IP4_ADDR Netmask, IN IP4_ADDR Gateway)
Definition: Ip4Route.c:291
VOID Ip4FreeRouteEntry(IN IP4_ROUTE_ENTRY *RtEntry)
Definition: Ip4Route.c:55
VOID Ip4PurgeRouteCache(IN OUT IP4_ROUTE_CACHE *RtCache, IN UINTN Tag)
Definition: Ip4Route.c:254
VOID Ip4FreeRouteTable(IN IP4_ROUTE_TABLE *RtTable)
Definition: Ip4Route.c:211
IP4_ROUTE_CACHE_ENTRY * Ip4CreateRouteCacheEntry(IN IP4_ADDR Dst, IN IP4_ADDR Src, IN IP4_ADDR GateWay, IN UINTN Tag)
Definition: Ip4Route.c:80
#define NULL
Definition: Base.h:319
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
INTN EFIAPI NetGetMaskLength(IN IP4_ADDR NetMask)
Definition: DxeNetLib.c:600
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112