TianoCore EDK2 master
Loading...
Searching...
No Matches
Ip6Route.c
Go to the documentation of this file.
1
10#include "Ip6Impl.h"
11
22UINT32
26 )
27{
28 UINT32 Prefix1;
29 UINT32 Prefix2;
30
31 Prefix1 = *((UINT32 *)((UINTN *)(Ip1)));
32 Prefix2 = *((UINT32 *)((UINTN *)(Ip2)));
33
34 return ((UINT32)(Prefix1 ^ Prefix2) % IP6_ROUTE_CACHE_HASH_SIZE);
35}
36
52 IN EFI_IPv6_ADDRESS *Destination OPTIONAL,
53 IN UINT8 PrefixLength,
54 IN EFI_IPv6_ADDRESS *GatewayAddress OPTIONAL
55 )
56{
57 IP6_ROUTE_ENTRY *RtEntry;
58
59 RtEntry = AllocateZeroPool (sizeof (IP6_ROUTE_ENTRY));
60
61 if (RtEntry == NULL) {
62 return NULL;
63 }
64
65 RtEntry->RefCnt = 1;
66 RtEntry->Flag = 0;
67 RtEntry->PrefixLength = PrefixLength;
68
69 if (Destination != NULL) {
70 IP6_COPY_ADDRESS (&RtEntry->Destination, Destination);
71 }
72
73 if (GatewayAddress != NULL) {
74 IP6_COPY_ADDRESS (&RtEntry->NextHop, GatewayAddress);
75 }
76
77 return RtEntry;
78}
79
86VOID
88 IN OUT IP6_ROUTE_ENTRY *RtEntry
89 )
90{
91 ASSERT ((RtEntry != NULL) && (RtEntry->RefCnt > 0));
92
93 if (--RtEntry->RefCnt == 0) {
94 FreePool (RtEntry);
95 }
96}
97
119 IN IP6_ROUTE_TABLE *RtTable,
120 IN EFI_IPv6_ADDRESS *Destination OPTIONAL,
121 IN EFI_IPv6_ADDRESS *NextHop OPTIONAL
122 )
123{
124 LIST_ENTRY *Entry;
125 IP6_ROUTE_ENTRY *RtEntry;
126 INTN Index;
127
128 ASSERT (Destination != NULL || NextHop != NULL);
129
130 RtEntry = NULL;
131
132 for (Index = IP6_PREFIX_MAX; Index >= 0; Index--) {
133 NET_LIST_FOR_EACH (Entry, &RtTable->RouteArea[Index]) {
134 RtEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
135
136 if (Destination != NULL) {
137 if (NetIp6IsNetEqual (Destination, &RtEntry->Destination, RtEntry->PrefixLength)) {
138 NET_GET_REF (RtEntry);
139 return RtEntry;
140 }
141 } else if (NextHop != NULL) {
142 if (NetIp6IsNetEqual (NextHop, &RtEntry->NextHop, RtEntry->PrefixLength)) {
143 NET_GET_REF (RtEntry);
144 return RtEntry;
145 }
146 }
147 }
148 }
149
150 return NULL;
151}
152
168 IN EFI_IPv6_ADDRESS *Dst,
169 IN EFI_IPv6_ADDRESS *Src,
170 IN EFI_IPv6_ADDRESS *GateWay,
171 IN UINTN Tag
172 )
173{
174 IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
175
176 RtCacheEntry = AllocatePool (sizeof (IP6_ROUTE_CACHE_ENTRY));
177
178 if (RtCacheEntry == NULL) {
179 return NULL;
180 }
181
182 RtCacheEntry->RefCnt = 1;
183 RtCacheEntry->Tag = Tag;
184
185 IP6_COPY_ADDRESS (&RtCacheEntry->Destination, Dst);
186 IP6_COPY_ADDRESS (&RtCacheEntry->Source, Src);
187 IP6_COPY_ADDRESS (&RtCacheEntry->NextHop, GateWay);
188
189 return RtCacheEntry;
190}
191
198VOID
200 IN OUT IP6_ROUTE_CACHE_ENTRY *RtCacheEntry
201 )
202{
203 ASSERT (RtCacheEntry->RefCnt > 0);
204
205 if (--RtCacheEntry->RefCnt == 0) {
206 FreePool (RtCacheEntry);
207 }
208}
209
224 IN IP6_ROUTE_TABLE *RtTable,
225 IN EFI_IPv6_ADDRESS *Dest,
227 )
228{
229 LIST_ENTRY *Entry;
230 IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
231 UINT32 Index;
232
233 Index = IP6_ROUTE_CACHE_HASH (Dest, Src);
234
235 NET_LIST_FOR_EACH (Entry, &RtTable->Cache.CacheBucket[Index]) {
236 RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
237
238 if (EFI_IP6_EQUAL (Dest, &RtCacheEntry->Destination) && EFI_IP6_EQUAL (Src, &RtCacheEntry->Source)) {
239 NET_GET_REF (RtCacheEntry);
240 return RtCacheEntry;
241 }
242 }
243
244 return NULL;
245}
246
262 IN IP6_ROUTE_TABLE *RouteTable,
263 OUT UINT32 *EfiRouteCount,
264 OUT EFI_IP6_ROUTE_TABLE **EfiRouteTable OPTIONAL
265 )
266{
267 LIST_ENTRY *Entry;
268 IP6_ROUTE_ENTRY *RtEntry;
269 EFI_IP6_ROUTE_TABLE *EfiTable;
270 UINT32 Count;
271 INT32 Index;
272
273 ASSERT (EfiRouteCount != NULL);
274
275 Count = RouteTable->TotalNum;
276 *EfiRouteCount = Count;
277
278 if ((EfiRouteTable == NULL) || (Count == 0)) {
279 return EFI_SUCCESS;
280 }
281
282 if (*EfiRouteTable == NULL) {
283 *EfiRouteTable = AllocatePool (sizeof (EFI_IP6_ROUTE_TABLE) * Count);
284 if (*EfiRouteTable == NULL) {
285 return EFI_OUT_OF_RESOURCES;
286 }
287 }
288
289 EfiTable = *EfiRouteTable;
290
291 //
292 // Copy the route entry to EFI route table.
293 //
294 Count = 0;
295
296 for (Index = IP6_PREFIX_MAX; Index >= 0; Index--) {
297 NET_LIST_FOR_EACH (Entry, &(RouteTable->RouteArea[Index])) {
298 RtEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
299
301 &EfiTable[Count].Destination,
302 &RtEntry->Destination,
303 RtEntry->PrefixLength
304 );
305
306 IP6_COPY_ADDRESS (&EfiTable[Count].Gateway, &RtEntry->NextHop);
307 EfiTable[Count].PrefixLength = RtEntry->PrefixLength;
308
309 Count++;
310 }
311 }
312
313 ASSERT (Count == RouteTable->TotalNum);
314
315 return EFI_SUCCESS;
316}
317
327 VOID
328 )
329{
330 IP6_ROUTE_TABLE *RtTable;
331 UINT32 Index;
332
333 RtTable = AllocatePool (sizeof (IP6_ROUTE_TABLE));
334 if (RtTable == NULL) {
335 return NULL;
336 }
337
338 RtTable->RefCnt = 1;
339 RtTable->TotalNum = 0;
340
341 for (Index = 0; Index <= IP6_PREFIX_MAX; Index++) {
342 InitializeListHead (&RtTable->RouteArea[Index]);
343 }
344
345 for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
346 InitializeListHead (&RtTable->Cache.CacheBucket[Index]);
347 RtTable->Cache.CacheNum[Index] = 0;
348 }
349
350 return RtTable;
351}
352
360VOID
362 IN OUT IP6_ROUTE_TABLE *RtTable
363 )
364{
365 LIST_ENTRY *Entry;
366 LIST_ENTRY *Next;
367 IP6_ROUTE_ENTRY *RtEntry;
368 IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
369 UINT32 Index;
370
371 ASSERT (RtTable->RefCnt > 0);
372
373 if (--RtTable->RefCnt > 0) {
374 return;
375 }
376
377 //
378 // Free all the route table entry and its route cache.
379 //
380 for (Index = 0; Index <= IP6_PREFIX_MAX; Index++) {
381 NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtTable->RouteArea[Index]) {
382 RtEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
383 RemoveEntryList (Entry);
384 Ip6FreeRouteEntry (RtEntry);
385 }
386 }
387
388 for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
389 NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtTable->Cache.CacheBucket[Index]) {
390 RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
391 RemoveEntryList (Entry);
392 Ip6FreeRouteCacheEntry (RtCacheEntry);
393 }
394 }
395
396 FreePool (RtTable);
397}
398
409VOID
411 IN IP6_ROUTE_CACHE *RtCache,
412 IN UINTN Tag
413 )
414{
415 LIST_ENTRY *Entry;
416 LIST_ENTRY *Next;
417 IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
418 UINT32 Index;
419
420 for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
421 NET_LIST_FOR_EACH_SAFE (Entry, Next, &RtCache->CacheBucket[Index]) {
422 RtCacheEntry = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
423
424 if (RtCacheEntry->Tag == Tag) {
425 RemoveEntryList (Entry);
426 Ip6FreeRouteCacheEntry (RtCacheEntry);
427 }
428 }
429 }
430}
431
447 IN OUT IP6_ROUTE_TABLE *RtTable,
448 IN EFI_IPv6_ADDRESS *Destination,
449 IN UINT8 PrefixLength,
450 IN EFI_IPv6_ADDRESS *GatewayAddress
451 )
452{
453 LIST_ENTRY *ListHead;
454 LIST_ENTRY *Entry;
455 IP6_ROUTE_ENTRY *Route;
456
457 ListHead = &RtTable->RouteArea[PrefixLength];
458
459 //
460 // First check whether the route exists
461 //
462 NET_LIST_FOR_EACH (Entry, ListHead) {
463 Route = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
464
465 if (NetIp6IsNetEqual (Destination, &Route->Destination, PrefixLength) &&
466 EFI_IP6_EQUAL (GatewayAddress, &Route->NextHop))
467 {
468 return EFI_ACCESS_DENIED;
469 }
470 }
471
472 //
473 // Create a route entry and insert it to the route area.
474 //
475 Route = Ip6CreateRouteEntry (Destination, PrefixLength, GatewayAddress);
476
477 if (Route == NULL) {
478 return EFI_OUT_OF_RESOURCES;
479 }
480
481 if (NetIp6IsUnspecifiedAddr (GatewayAddress)) {
482 Route->Flag = IP6_DIRECT_ROUTE;
483 }
484
485 InsertHeadList (ListHead, &Route->Link);
486 RtTable->TotalNum++;
487
488 return EFI_SUCCESS;
489}
490
507 IN OUT IP6_ROUTE_TABLE *RtTable,
508 IN EFI_IPv6_ADDRESS *Destination,
509 IN UINT8 PrefixLength,
510 IN EFI_IPv6_ADDRESS *GatewayAddress
511 )
512{
513 LIST_ENTRY *ListHead;
514 LIST_ENTRY *Entry;
515 LIST_ENTRY *Next;
516 IP6_ROUTE_ENTRY *Route;
517 UINT32 TotalNum;
518
519 ListHead = &RtTable->RouteArea[PrefixLength];
520 TotalNum = RtTable->TotalNum;
521
522 NET_LIST_FOR_EACH_SAFE (Entry, Next, ListHead) {
523 Route = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_ENTRY, Link);
524
525 if ((Destination != NULL) && !NetIp6IsNetEqual (Destination, &Route->Destination, PrefixLength)) {
526 continue;
527 }
528
529 if ((GatewayAddress != NULL) && !EFI_IP6_EQUAL (GatewayAddress, &Route->NextHop)) {
530 continue;
531 }
532
533 Ip6PurgeRouteCache (&RtTable->Cache, (UINTN)Route);
534 RemoveEntryList (Entry);
535 Ip6FreeRouteEntry (Route);
536
537 ASSERT (RtTable->TotalNum > 0);
538 RtTable->TotalNum--;
539 }
540
541 return TotalNum == RtTable->TotalNum ? EFI_NOT_FOUND : EFI_SUCCESS;
542}
543
558 IN IP6_SERVICE *IpSb,
559 IN EFI_IPv6_ADDRESS *Dest,
561 )
562{
563 IP6_ROUTE_TABLE *RtTable;
564 LIST_ENTRY *ListHead;
565 IP6_ROUTE_CACHE_ENTRY *RtCacheEntry;
566 IP6_ROUTE_ENTRY *RtEntry;
567 EFI_IPv6_ADDRESS NextHop;
568 UINT32 Index;
569
570 RtTable = IpSb->RouteTable;
571
572 ASSERT (RtTable != NULL);
573
574 //
575 // Search the destination cache in IP6_ROUTE_TABLE.
576 //
577 Index = IP6_ROUTE_CACHE_HASH (Dest, Src);
578 ListHead = &RtTable->Cache.CacheBucket[Index];
579
580 RtCacheEntry = Ip6FindRouteCache (RtTable, Dest, Src);
581
582 //
583 // If found, promote the cache entry to the head of the hash bucket.
584 //
585 if (RtCacheEntry != NULL) {
586 RemoveEntryList (&RtCacheEntry->Link);
587 InsertHeadList (ListHead, &RtCacheEntry->Link);
588 return RtCacheEntry;
589 }
590
591 //
592 // Search the route table for the most specific route
593 //
594 RtEntry = Ip6FindRouteEntry (RtTable, Dest, NULL);
595 if (RtEntry == NULL) {
596 return NULL;
597 }
598
599 //
600 // Found a route to the Dest, if it is a direct route, the packet
601 // will be send directly to the destination, such as for connected
602 // network. Otherwise, it is an indirect route, the packet will be
603 // send the next hop router.
604 //
605 if ((RtEntry->Flag & IP6_DIRECT_ROUTE) == IP6_DIRECT_ROUTE) {
606 IP6_COPY_ADDRESS (&NextHop, Dest);
607 } else {
608 IP6_COPY_ADDRESS (&NextHop, &RtEntry->NextHop);
609 }
610
611 Ip6FreeRouteEntry (RtEntry);
612
613 //
614 // Create a route cache entry, and tag it as spawned from this route entry
615 //
616 RtCacheEntry = Ip6CreateRouteCacheEntry (Dest, Src, &NextHop, (UINTN)RtEntry);
617
618 if (RtCacheEntry == NULL) {
619 return NULL;
620 }
621
622 InsertHeadList (ListHead, &RtCacheEntry->Link);
623 NET_GET_REF (RtCacheEntry);
624 RtTable->Cache.CacheNum[Index]++;
625
626 return RtCacheEntry;
627}
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 AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID Ip6CopyAddressByPrefix(OUT EFI_IPv6_ADDRESS *Dest, IN EFI_IPv6_ADDRESS *Src, IN UINT8 PrefixLength)
Definition: Ip6Common.c:593
EFI_STATUS Ip6BuildEfiRouteTable(IN IP6_ROUTE_TABLE *RouteTable, OUT UINT32 *EfiRouteCount, OUT EFI_IP6_ROUTE_TABLE **EfiRouteTable OPTIONAL)
Definition: Ip6Route.c:261
VOID Ip6FreeRouteCacheEntry(IN OUT IP6_ROUTE_CACHE_ENTRY *RtCacheEntry)
Definition: Ip6Route.c:199
VOID Ip6CleanRouteTable(IN OUT IP6_ROUTE_TABLE *RtTable)
Definition: Ip6Route.c:361
IP6_ROUTE_ENTRY * Ip6CreateRouteEntry(IN EFI_IPv6_ADDRESS *Destination OPTIONAL, IN UINT8 PrefixLength, IN EFI_IPv6_ADDRESS *GatewayAddress OPTIONAL)
Definition: Ip6Route.c:51
IP6_ROUTE_TABLE * Ip6CreateRouteTable(VOID)
Definition: Ip6Route.c:326
IP6_ROUTE_ENTRY * Ip6FindRouteEntry(IN IP6_ROUTE_TABLE *RtTable, IN EFI_IPv6_ADDRESS *Destination OPTIONAL, IN EFI_IPv6_ADDRESS *NextHop OPTIONAL)
Definition: Ip6Route.c:118
EFI_STATUS Ip6AddRoute(IN OUT IP6_ROUTE_TABLE *RtTable, IN EFI_IPv6_ADDRESS *Destination, IN UINT8 PrefixLength, IN EFI_IPv6_ADDRESS *GatewayAddress)
Definition: Ip6Route.c:446
IP6_ROUTE_CACHE_ENTRY * Ip6FindRouteCache(IN IP6_ROUTE_TABLE *RtTable, IN EFI_IPv6_ADDRESS *Dest, IN EFI_IPv6_ADDRESS *Src)
Definition: Ip6Route.c:223
EFI_STATUS Ip6DelRoute(IN OUT IP6_ROUTE_TABLE *RtTable, IN EFI_IPv6_ADDRESS *Destination, IN UINT8 PrefixLength, IN EFI_IPv6_ADDRESS *GatewayAddress)
Definition: Ip6Route.c:506
VOID Ip6PurgeRouteCache(IN IP6_ROUTE_CACHE *RtCache, IN UINTN Tag)
Definition: Ip6Route.c:410
IP6_ROUTE_CACHE_ENTRY * Ip6CreateRouteCacheEntry(IN EFI_IPv6_ADDRESS *Dst, IN EFI_IPv6_ADDRESS *Src, IN EFI_IPv6_ADDRESS *GateWay, IN UINTN Tag)
Definition: Ip6Route.c:167
UINT32 Ip6RouteCacheHash(IN EFI_IPv6_ADDRESS *Ip1, IN EFI_IPv6_ADDRESS *Ip2)
Definition: Ip6Route.c:23
IP6_ROUTE_CACHE_ENTRY * Ip6Route(IN IP6_SERVICE *IpSb, IN EFI_IPv6_ADDRESS *Dest, IN EFI_IPv6_ADDRESS *Src)
Definition: Ip6Route.c:557
VOID Ip6FreeRouteEntry(IN OUT IP6_ROUTE_ENTRY *RtEntry)
Definition: Ip6Route.c:87
#define NULL
Definition: Base.h:319
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
BOOLEAN EFIAPI NetIp6IsNetEqual(EFI_IPv6_ADDRESS *Ip1, EFI_IPv6_ADDRESS *Ip2, UINT8 PrefixLength)
Definition: DxeNetLib.c:837
BOOLEAN EFIAPI NetIp6IsUnspecifiedAddr(IN EFI_IPv6_ADDRESS *Ip6)
Definition: DxeNetLib.c:766
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
UINT8 PrefixLength
Definition: Ip6.h:243