VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/Ip6Dxe/Ip6Nd.c

Last change on this file was 105670, checked in by vboxsync, 8 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 97.0 KB
Line 
1/** @file
2 Implementation of Neighbor Discovery support routines.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) Microsoft Corporation
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "Ip6Impl.h"
11
12EFI_MAC_ADDRESS mZeroMacAddress;
13
14/**
15 Update the ReachableTime in IP6 service binding instance data, in milliseconds.
16
17 @param[in, out] IpSb Points to the IP6_SERVICE.
18
19 @retval EFI_SUCCESS ReachableTime Updated
20 @retval others Failed to update ReachableTime
21**/
22EFI_STATUS
23Ip6UpdateReachableTime (
24 IN OUT IP6_SERVICE *IpSb
25 )
26{
27 UINT32 Random;
28 EFI_STATUS Status;
29
30 Status = PseudoRandomU32 (&Random);
31 if (EFI_ERROR (Status)) {
32 DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status));
33 return Status;
34 }
35
36 Random = (Random / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE;
37 Random = Random + IP6_MIN_RANDOM_FACTOR_SCALED;
38 IpSb->ReachableTime = (IpSb->BaseReachableTime * Random) / IP6_RANDOM_FACTOR_SCALE;
39
40 return EFI_SUCCESS;
41}
42
43/**
44 Build a array of EFI_IP6_NEIGHBOR_CACHE to be returned to the caller. The number
45 of EFI_IP6_NEIGHBOR_CACHE is also returned.
46
47 @param[in] IpInstance The pointer to IP6_PROTOCOL instance.
48 @param[out] NeighborCount The number of returned neighbor cache entries.
49 @param[out] NeighborCache The pointer to the array of EFI_IP6_NEIGHBOR_CACHE.
50
51 @retval EFI_SUCCESS The EFI_IP6_NEIGHBOR_CACHE successfully built.
52 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the route table.
53
54**/
55EFI_STATUS
56Ip6BuildEfiNeighborCache (
57 IN IP6_PROTOCOL *IpInstance,
58 OUT UINT32 *NeighborCount,
59 OUT EFI_IP6_NEIGHBOR_CACHE **NeighborCache
60 )
61{
62 IP6_NEIGHBOR_ENTRY *Neighbor;
63 LIST_ENTRY *Entry;
64 IP6_SERVICE *IpSb;
65 UINT32 Count;
66 EFI_IP6_NEIGHBOR_CACHE *EfiNeighborCache;
67 EFI_IP6_NEIGHBOR_CACHE *NeighborCacheTmp;
68
69 NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
70 ASSERT (NeighborCount != NULL && NeighborCache != NULL);
71
72 IpSb = IpInstance->Service;
73 Count = 0;
74
75 NET_LIST_FOR_EACH (Entry, &IpSb->NeighborTable) {
76 Count++;
77 }
78
79 if (Count == 0) {
80 return EFI_SUCCESS;
81 }
82
83 NeighborCacheTmp = AllocatePool (Count * sizeof (EFI_IP6_NEIGHBOR_CACHE));
84 if (NeighborCacheTmp == NULL) {
85 return EFI_OUT_OF_RESOURCES;
86 }
87
88 *NeighborCount = Count;
89 Count = 0;
90
91 NET_LIST_FOR_EACH (Entry, &IpSb->NeighborTable) {
92 Neighbor = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
93
94 EfiNeighborCache = NeighborCacheTmp + Count;
95
96 EfiNeighborCache->State = Neighbor->State;
97 IP6_COPY_ADDRESS (&EfiNeighborCache->Neighbor, &Neighbor->Neighbor);
98 IP6_COPY_LINK_ADDRESS (&EfiNeighborCache->LinkAddress, &Neighbor->LinkAddress);
99
100 Count++;
101 }
102
103 ASSERT (*NeighborCount == Count);
104 *NeighborCache = NeighborCacheTmp;
105
106 return EFI_SUCCESS;
107}
108
109/**
110 Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
111 of prefix entries is also returned.
112
113 @param[in] IpInstance The pointer to IP6_PROTOCOL instance.
114 @param[out] PrefixCount The number of returned prefix entries.
115 @param[out] PrefixTable The pointer to the array of PrefixTable.
116
117 @retval EFI_SUCCESS The prefix table successfully built.
118 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the prefix table.
119
120**/
121EFI_STATUS
122Ip6BuildPrefixTable (
123 IN IP6_PROTOCOL *IpInstance,
124 OUT UINT32 *PrefixCount,
125 OUT EFI_IP6_ADDRESS_INFO **PrefixTable
126 )
127{
128 LIST_ENTRY *Entry;
129 IP6_SERVICE *IpSb;
130 UINT32 Count;
131 IP6_PREFIX_LIST_ENTRY *PrefixList;
132 EFI_IP6_ADDRESS_INFO *EfiPrefix;
133 EFI_IP6_ADDRESS_INFO *PrefixTableTmp;
134
135 NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
136 ASSERT (PrefixCount != NULL && PrefixTable != NULL);
137
138 IpSb = IpInstance->Service;
139 Count = 0;
140
141 NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
142 Count++;
143 }
144
145 if (Count == 0) {
146 return EFI_SUCCESS;
147 }
148
149 PrefixTableTmp = AllocatePool (Count * sizeof (EFI_IP6_ADDRESS_INFO));
150 if (PrefixTableTmp == NULL) {
151 return EFI_OUT_OF_RESOURCES;
152 }
153
154 *PrefixCount = Count;
155 Count = 0;
156
157 NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
158 PrefixList = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
159 EfiPrefix = PrefixTableTmp + Count;
160 IP6_COPY_ADDRESS (&EfiPrefix->Address, &PrefixList->Prefix);
161 EfiPrefix->PrefixLength = PrefixList->PrefixLength;
162
163 Count++;
164 }
165
166 ASSERT (*PrefixCount == Count);
167 *PrefixTable = PrefixTableTmp;
168
169 return EFI_SUCCESS;
170}
171
172/**
173 Allocate and initialize a IP6 prefix list entry.
174
175 @param[in] IpSb The pointer to IP6_SERVICE instance.
176 @param[in] OnLinkOrAuto If TRUE, the entry is created for the on link prefix list.
177 Otherwise, it is created for the autoconfiguration prefix list.
178 @param[in] ValidLifetime The length of time in seconds that the prefix
179 is valid for the purpose of on-link determination.
180 @param[in] PreferredLifetime The length of time in seconds that addresses
181 generated from the prefix via stateless address
182 autoconfiguration remain preferred.
183 @param[in] PrefixLength The prefix length of the Prefix.
184 @param[in] Prefix The prefix address.
185
186 @return NULL if it failed to allocate memory for the prefix node. Otherwise, point
187 to the created or existing prefix list entry.
188
189**/
190IP6_PREFIX_LIST_ENTRY *
191Ip6CreatePrefixListEntry (
192 IN IP6_SERVICE *IpSb,
193 IN BOOLEAN OnLinkOrAuto,
194 IN UINT32 ValidLifetime,
195 IN UINT32 PreferredLifetime,
196 IN UINT8 PrefixLength,
197 IN EFI_IPv6_ADDRESS *Prefix
198 )
199{
200 IP6_PREFIX_LIST_ENTRY *PrefixEntry;
201 IP6_ROUTE_ENTRY *RtEntry;
202 LIST_ENTRY *ListHead;
203 LIST_ENTRY *Entry;
204 IP6_PREFIX_LIST_ENTRY *TmpPrefixEntry;
205
206 if ((Prefix == NULL) || (PreferredLifetime > ValidLifetime) || (PrefixLength > IP6_PREFIX_MAX)) {
207 return NULL;
208 }
209
210 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
211
212 PrefixEntry = Ip6FindPrefixListEntry (
213 IpSb,
214 OnLinkOrAuto,
215 PrefixLength,
216 Prefix
217 );
218 if (PrefixEntry != NULL) {
219 PrefixEntry->RefCnt++;
220 return PrefixEntry;
221 }
222
223 PrefixEntry = AllocatePool (sizeof (IP6_PREFIX_LIST_ENTRY));
224 if (PrefixEntry == NULL) {
225 return NULL;
226 }
227
228 PrefixEntry->RefCnt = 1;
229 PrefixEntry->ValidLifetime = ValidLifetime;
230 PrefixEntry->PreferredLifetime = PreferredLifetime;
231 PrefixEntry->PrefixLength = PrefixLength;
232 IP6_COPY_ADDRESS (&PrefixEntry->Prefix, Prefix);
233
234 ListHead = OnLinkOrAuto ? &IpSb->OnlinkPrefix : &IpSb->AutonomousPrefix;
235
236 //
237 // Create a direct route entry for on-link prefix and insert to route area.
238 //
239 if (OnLinkOrAuto) {
240 RtEntry = Ip6CreateRouteEntry (Prefix, PrefixLength, NULL);
241 if (RtEntry == NULL) {
242 FreePool (PrefixEntry);
243 return NULL;
244 }
245
246 RtEntry->Flag = IP6_DIRECT_ROUTE;
247 InsertHeadList (&IpSb->RouteTable->RouteArea[PrefixLength], &RtEntry->Link);
248 IpSb->RouteTable->TotalNum++;
249 }
250
251 //
252 // Insert the prefix entry in the order that a prefix with longer prefix length
253 // is put ahead in the list.
254 //
255 NET_LIST_FOR_EACH (Entry, ListHead) {
256 TmpPrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
257
258 if (TmpPrefixEntry->PrefixLength < PrefixEntry->PrefixLength) {
259 break;
260 }
261 }
262
263 NetListInsertBefore (Entry, &PrefixEntry->Link);
264
265 return PrefixEntry;
266}
267
268/**
269 Destroy a IP6 prefix list entry.
270
271 @param[in] IpSb The pointer to IP6_SERVICE instance.
272 @param[in] PrefixEntry The to be destroyed prefix list entry.
273 @param[in] OnLinkOrAuto If TRUE, the entry is removed from on link prefix list.
274 Otherwise remove from autoconfiguration prefix list.
275 @param[in] ImmediateDelete If TRUE, remove the entry directly.
276 Otherwise, check the reference count to see whether
277 it should be removed.
278
279**/
280VOID
281Ip6DestroyPrefixListEntry (
282 IN IP6_SERVICE *IpSb,
283 IN IP6_PREFIX_LIST_ENTRY *PrefixEntry,
284 IN BOOLEAN OnLinkOrAuto,
285 IN BOOLEAN ImmediateDelete
286 )
287{
288 LIST_ENTRY *Entry;
289 IP6_INTERFACE *IpIf;
290 EFI_STATUS Status;
291
292 if ((!ImmediateDelete) && (PrefixEntry->RefCnt > 0) && ((--PrefixEntry->RefCnt) > 0)) {
293 return;
294 }
295
296 if (OnLinkOrAuto) {
297 //
298 // Remove the direct route for onlink prefix from route table.
299 //
300 do {
301 Status = Ip6DelRoute (
302 IpSb->RouteTable,
303 &PrefixEntry->Prefix,
304 PrefixEntry->PrefixLength,
305 NULL
306 );
307 } while (Status != EFI_NOT_FOUND);
308 } else {
309 //
310 // Remove the corresponding addresses generated from this autonomous prefix.
311 //
312 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
313 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
314
315 Ip6RemoveAddr (IpSb, &IpIf->AddressList, &IpIf->AddressCount, &PrefixEntry->Prefix, PrefixEntry->PrefixLength);
316 }
317 }
318
319 RemoveEntryList (&PrefixEntry->Link);
320 FreePool (PrefixEntry);
321}
322
323/**
324 Search the list array to find an IP6 prefix list entry.
325
326 @param[in] IpSb The pointer to IP6_SERVICE instance.
327 @param[in] OnLinkOrAuto If TRUE, the search the link prefix list,
328 Otherwise search the autoconfiguration prefix list.
329 @param[in] PrefixLength The prefix length of the Prefix
330 @param[in] Prefix The prefix address.
331
332 @return NULL if cannot find the IP6 prefix list entry. Otherwise, return the
333 pointer to the IP6 prefix list entry.
334
335**/
336IP6_PREFIX_LIST_ENTRY *
337Ip6FindPrefixListEntry (
338 IN IP6_SERVICE *IpSb,
339 IN BOOLEAN OnLinkOrAuto,
340 IN UINT8 PrefixLength,
341 IN EFI_IPv6_ADDRESS *Prefix
342 )
343{
344 IP6_PREFIX_LIST_ENTRY *PrefixList;
345 LIST_ENTRY *Entry;
346 LIST_ENTRY *ListHead;
347
348 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
349 ASSERT (Prefix != NULL);
350
351 if (OnLinkOrAuto) {
352 ListHead = &IpSb->OnlinkPrefix;
353 } else {
354 ListHead = &IpSb->AutonomousPrefix;
355 }
356
357 NET_LIST_FOR_EACH (Entry, ListHead) {
358 PrefixList = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
359 if (PrefixLength != 255) {
360 //
361 // Perform exactly prefix match.
362 //
363 if ((PrefixList->PrefixLength == PrefixLength) &&
364 NetIp6IsNetEqual (&PrefixList->Prefix, Prefix, PrefixLength))
365 {
366 return PrefixList;
367 }
368 } else {
369 //
370 // Perform the longest prefix match. The list is already sorted with
371 // the longest length prefix put at the head of the list.
372 //
373 if (NetIp6IsNetEqual (&PrefixList->Prefix, Prefix, PrefixList->PrefixLength)) {
374 return PrefixList;
375 }
376 }
377 }
378
379 return NULL;
380}
381
382/**
383 Release the resource in the prefix list table, and destroy the list entry and
384 corresponding addresses or route entries.
385
386 @param[in] IpSb The pointer to the IP6_SERVICE instance.
387 @param[in] ListHead The list entry head of the prefix list table.
388
389**/
390VOID
391Ip6CleanPrefixListTable (
392 IN IP6_SERVICE *IpSb,
393 IN LIST_ENTRY *ListHead
394 )
395{
396 IP6_PREFIX_LIST_ENTRY *PrefixList;
397 BOOLEAN OnLink;
398
399 OnLink = (BOOLEAN)(ListHead == &IpSb->OnlinkPrefix);
400
401 while (!IsListEmpty (ListHead)) {
402 PrefixList = NET_LIST_HEAD (ListHead, IP6_PREFIX_LIST_ENTRY, Link);
403 Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
404 }
405}
406
407/**
408 Callback function when address resolution is finished. It will cancel
409 all the queued frames if the address resolution failed, or transmit them
410 if the request succeeded.
411
412 @param[in] Context The context of the callback, a pointer to IP6_NEIGHBOR_ENTRY.
413
414**/
415VOID
416Ip6OnArpResolved (
417 IN VOID *Context
418 )
419{
420 LIST_ENTRY *Entry;
421 LIST_ENTRY *Next;
422 IP6_NEIGHBOR_ENTRY *ArpQue;
423 IP6_SERVICE *IpSb;
424 IP6_LINK_TX_TOKEN *Token;
425 EFI_STATUS Status;
426 BOOLEAN Sent;
427
428 ArpQue = (IP6_NEIGHBOR_ENTRY *)Context;
429 if ((ArpQue == NULL) || (ArpQue->Interface == NULL)) {
430 return;
431 }
432
433 IpSb = ArpQue->Interface->Service;
434 if ((IpSb == NULL) || (IpSb->Signature != IP6_SERVICE_SIGNATURE)) {
435 return;
436 }
437
438 //
439 // ARP resolve failed for some reason. Release all the frame
440 // and ARP queue itself. Ip6FreeArpQue will call the frame's
441 // owner back.
442 //
443 if (NET_MAC_EQUAL (&ArpQue->LinkAddress, &mZeroMacAddress, IpSb->SnpMode.HwAddressSize)) {
444 Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, TRUE, EFI_NO_MAPPING, NULL, NULL);
445 return;
446 }
447
448 //
449 // ARP resolve succeeded, Transmit all the frame.
450 //
451 Sent = FALSE;
452 NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
453 RemoveEntryList (Entry);
454
455 Token = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
456 IP6_COPY_LINK_ADDRESS (&Token->DstMac, &ArpQue->LinkAddress);
457
458 //
459 // Insert the tx token before transmitting it via MNP as the FrameSentDpc
460 // may be called before Mnp->Transmit returns which will remove this tx
461 // token from the SentFrames list. Remove it from the list if the returned
462 // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
463 // FrameSentDpc won't be queued.
464 //
465 InsertTailList (&ArpQue->Interface->SentFrames, &Token->Link);
466
467 Status = IpSb->Mnp->Transmit (IpSb->Mnp, &Token->MnpToken);
468 if (EFI_ERROR (Status)) {
469 RemoveEntryList (&Token->Link);
470 Token->CallBack (Token->Packet, Status, 0, Token->Context);
471
472 Ip6FreeLinkTxToken (Token);
473 continue;
474 } else {
475 Sent = TRUE;
476 }
477 }
478
479 //
480 // Free the ArpQue only but not the whole neighbor entry.
481 //
482 Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, FALSE, EFI_SUCCESS, NULL, NULL);
483
484 if (Sent && (ArpQue->State == EfiNeighborStale)) {
485 ArpQue->State = EfiNeighborDelay;
486 ArpQue->Ticks = (UINT32)IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME);
487 }
488}
489
490/**
491 Allocate and initialize an IP6 neighbor cache entry.
492
493 @param[in] IpSb The pointer to the IP6_SERVICE instance.
494 @param[in] CallBack The callback function to be called when
495 address resolution is finished.
496 @param[in] Ip6Address Points to the IPv6 address of the neighbor.
497 @param[in] LinkAddress Points to the MAC address of the neighbor.
498 Ignored if NULL.
499
500 @return NULL if failed to allocate memory for the neighbor cache entry.
501 Otherwise, point to the created neighbor cache entry.
502
503**/
504IP6_NEIGHBOR_ENTRY *
505Ip6CreateNeighborEntry (
506 IN IP6_SERVICE *IpSb,
507 IN IP6_ARP_CALLBACK CallBack,
508 IN EFI_IPv6_ADDRESS *Ip6Address,
509 IN EFI_MAC_ADDRESS *LinkAddress OPTIONAL
510 )
511{
512 IP6_NEIGHBOR_ENTRY *Entry;
513 IP6_DEFAULT_ROUTER *DefaultRouter;
514
515 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
516 ASSERT (Ip6Address != NULL);
517
518 Entry = AllocateZeroPool (sizeof (IP6_NEIGHBOR_ENTRY));
519 if (Entry == NULL) {
520 return NULL;
521 }
522
523 Entry->RefCnt = 1;
524 Entry->IsRouter = FALSE;
525 Entry->ArpFree = FALSE;
526 Entry->Dynamic = FALSE;
527 Entry->State = EfiNeighborInComplete;
528 Entry->Transmit = IP6_MAX_MULTICAST_SOLICIT + 1;
529 Entry->CallBack = CallBack;
530 Entry->Interface = NULL;
531
532 InitializeListHead (&Entry->Frames);
533
534 IP6_COPY_ADDRESS (&Entry->Neighbor, Ip6Address);
535
536 if (LinkAddress != NULL) {
537 IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, LinkAddress);
538 } else {
539 IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, &mZeroMacAddress);
540 }
541
542 InsertHeadList (&IpSb->NeighborTable, &Entry->Link);
543
544 //
545 // If corresponding default router entry exists, establish the relationship.
546 //
547 DefaultRouter = Ip6FindDefaultRouter (IpSb, Ip6Address);
548 if (DefaultRouter != NULL) {
549 DefaultRouter->NeighborCache = Entry;
550 }
551
552 return Entry;
553}
554
555/**
556 Search a IP6 neighbor cache entry.
557
558 @param[in] IpSb The pointer to the IP6_SERVICE instance.
559 @param[in] Ip6Address Points to the IPv6 address of the neighbor.
560
561 @return NULL if it failed to find the matching neighbor cache entry.
562 Otherwise, point to the found neighbor cache entry.
563
564**/
565IP6_NEIGHBOR_ENTRY *
566Ip6FindNeighborEntry (
567 IN IP6_SERVICE *IpSb,
568 IN EFI_IPv6_ADDRESS *Ip6Address
569 )
570{
571 LIST_ENTRY *Entry;
572 LIST_ENTRY *Next;
573 IP6_NEIGHBOR_ENTRY *Neighbor;
574
575 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
576 ASSERT (Ip6Address != NULL);
577
578 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
579 Neighbor = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
580 if (EFI_IP6_EQUAL (Ip6Address, &Neighbor->Neighbor)) {
581 RemoveEntryList (Entry);
582 InsertHeadList (&IpSb->NeighborTable, Entry);
583
584 return Neighbor;
585 }
586 }
587
588 return NULL;
589}
590
591/**
592 Free a IP6 neighbor cache entry and remove all the frames on the address
593 resolution queue that pass the FrameToCancel. That is, either FrameToCancel
594 is NULL, or it returns true for the frame.
595
596 @param[in] IpSb The pointer to the IP6_SERVICE instance.
597 @param[in] NeighborCache The to be free neighbor cache entry.
598 @param[in] SendIcmpError If TRUE, send out ICMP error.
599 @param[in] FullFree If TRUE, remove the neighbor cache entry.
600 Otherwise remove the pending frames.
601 @param[in] IoStatus The status returned to the cancelled frames'
602 callback function.
603 @param[in] FrameToCancel Function to select which frame to cancel.
604 This is an optional parameter that may be NULL.
605 @param[in] Context Opaque parameter to the FrameToCancel.
606 Ignored if FrameToCancel is NULL.
607
608 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
609 @retval EFI_SUCCESS The operation finished successfully.
610
611**/
612EFI_STATUS
613Ip6FreeNeighborEntry (
614 IN IP6_SERVICE *IpSb,
615 IN IP6_NEIGHBOR_ENTRY *NeighborCache,
616 IN BOOLEAN SendIcmpError,
617 IN BOOLEAN FullFree,
618 IN EFI_STATUS IoStatus,
619 IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
620 IN VOID *Context OPTIONAL
621 )
622{
623 IP6_LINK_TX_TOKEN *TxToken;
624 LIST_ENTRY *Entry;
625 LIST_ENTRY *Next;
626 IP6_DEFAULT_ROUTER *DefaultRouter;
627
628 //
629 // If FrameToCancel fails, the token will not be released.
630 // To avoid the memory leak, stop this usage model.
631 //
632 if (FullFree && (FrameToCancel != NULL)) {
633 return EFI_INVALID_PARAMETER;
634 }
635
636 NET_LIST_FOR_EACH_SAFE (Entry, Next, &NeighborCache->Frames) {
637 TxToken = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
638
639 if (SendIcmpError && !IP6_IS_MULTICAST (&TxToken->Packet->Ip.Ip6->DestinationAddress)) {
640 Ip6SendIcmpError (
641 IpSb,
642 TxToken->Packet,
643 NULL,
644 &TxToken->Packet->Ip.Ip6->SourceAddress,
645 ICMP_V6_DEST_UNREACHABLE,
646 ICMP_V6_ADDR_UNREACHABLE,
647 NULL
648 );
649 }
650
651 if ((FrameToCancel == NULL) || FrameToCancel (TxToken, Context)) {
652 RemoveEntryList (Entry);
653 TxToken->CallBack (TxToken->Packet, IoStatus, 0, TxToken->Context);
654 Ip6FreeLinkTxToken (TxToken);
655 }
656 }
657
658 if (NeighborCache->ArpFree && IsListEmpty (&NeighborCache->Frames)) {
659 RemoveEntryList (&NeighborCache->ArpList);
660 NeighborCache->ArpFree = FALSE;
661 }
662
663 if (FullFree) {
664 if (NeighborCache->IsRouter) {
665 DefaultRouter = Ip6FindDefaultRouter (IpSb, &NeighborCache->Neighbor);
666 if (DefaultRouter != NULL) {
667 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
668 }
669 }
670
671 RemoveEntryList (&NeighborCache->Link);
672 FreePool (NeighborCache);
673 }
674
675 return EFI_SUCCESS;
676}
677
678/**
679 Allocate and initialize an IP6 default router entry.
680
681 @param[in] IpSb The pointer to the IP6_SERVICE instance.
682 @param[in] Ip6Address The IPv6 address of the default router.
683 @param[in] RouterLifetime The lifetime associated with the default
684 router, in units of seconds.
685
686 @return NULL if it failed to allocate memory for the default router node.
687 Otherwise, point to the created default router node.
688
689**/
690IP6_DEFAULT_ROUTER *
691Ip6CreateDefaultRouter (
692 IN IP6_SERVICE *IpSb,
693 IN EFI_IPv6_ADDRESS *Ip6Address,
694 IN UINT16 RouterLifetime
695 )
696{
697 IP6_DEFAULT_ROUTER *Entry;
698 IP6_ROUTE_ENTRY *RtEntry;
699
700 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
701 ASSERT (Ip6Address != NULL);
702
703 Entry = AllocatePool (sizeof (IP6_DEFAULT_ROUTER));
704 if (Entry == NULL) {
705 return NULL;
706 }
707
708 Entry->RefCnt = 1;
709 Entry->Lifetime = RouterLifetime;
710 Entry->NeighborCache = Ip6FindNeighborEntry (IpSb, Ip6Address);
711 IP6_COPY_ADDRESS (&Entry->Router, Ip6Address);
712
713 //
714 // Add a default route into route table with both Destination and PrefixLength set to zero.
715 //
716 RtEntry = Ip6CreateRouteEntry (NULL, 0, Ip6Address);
717 if (RtEntry == NULL) {
718 FreePool (Entry);
719 return NULL;
720 }
721
722 InsertHeadList (&IpSb->RouteTable->RouteArea[0], &RtEntry->Link);
723 IpSb->RouteTable->TotalNum++;
724
725 InsertTailList (&IpSb->DefaultRouterList, &Entry->Link);
726
727 return Entry;
728}
729
730/**
731 Destroy an IP6 default router entry.
732
733 @param[in] IpSb The pointer to the IP6_SERVICE instance.
734 @param[in] DefaultRouter The to be destroyed IP6_DEFAULT_ROUTER.
735
736**/
737VOID
738Ip6DestroyDefaultRouter (
739 IN IP6_SERVICE *IpSb,
740 IN IP6_DEFAULT_ROUTER *DefaultRouter
741 )
742{
743 EFI_STATUS Status;
744
745 RemoveEntryList (&DefaultRouter->Link);
746
747 //
748 // Update the Destination Cache - all entries using the time-out router as next-hop
749 // should perform next-hop determination again.
750 //
751 do {
752 Status = Ip6DelRoute (IpSb->RouteTable, NULL, 0, &DefaultRouter->Router);
753 } while (Status != EFI_NOT_FOUND);
754
755 FreePool (DefaultRouter);
756}
757
758/**
759 Clean an IP6 default router list.
760
761 @param[in] IpSb The pointer to the IP6_SERVICE instance.
762
763**/
764VOID
765Ip6CleanDefaultRouterList (
766 IN IP6_SERVICE *IpSb
767 )
768{
769 IP6_DEFAULT_ROUTER *DefaultRouter;
770
771 while (!IsListEmpty (&IpSb->DefaultRouterList)) {
772 DefaultRouter = NET_LIST_HEAD (&IpSb->DefaultRouterList, IP6_DEFAULT_ROUTER, Link);
773 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
774 }
775}
776
777/**
778 Search a default router node from an IP6 default router list.
779
780 @param[in] IpSb The pointer to the IP6_SERVICE instance.
781 @param[in] Ip6Address The IPv6 address of the to be searched default router node.
782
783 @return NULL if it failed to find the matching default router node.
784 Otherwise, point to the found default router node.
785
786**/
787IP6_DEFAULT_ROUTER *
788Ip6FindDefaultRouter (
789 IN IP6_SERVICE *IpSb,
790 IN EFI_IPv6_ADDRESS *Ip6Address
791 )
792{
793 LIST_ENTRY *Entry;
794 IP6_DEFAULT_ROUTER *DefaultRouter;
795
796 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
797 ASSERT (Ip6Address != NULL);
798
799 NET_LIST_FOR_EACH (Entry, &IpSb->DefaultRouterList) {
800 DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
801 if (EFI_IP6_EQUAL (Ip6Address, &DefaultRouter->Router)) {
802 return DefaultRouter;
803 }
804 }
805
806 return NULL;
807}
808
809/**
810 The function to be called after DAD (Duplicate Address Detection) is performed.
811
812 @param[in] IsDadPassed If TRUE, the DAD operation succeed. Otherwise, the DAD operation failed.
813 @param[in] IpIf Points to the IP6_INTERFACE.
814 @param[in] DadEntry The DAD entry which already performed DAD.
815
816**/
817VOID
818Ip6OnDADFinished (
819 IN BOOLEAN IsDadPassed,
820 IN IP6_INTERFACE *IpIf,
821 IN IP6_DAD_ENTRY *DadEntry
822 )
823{
824 IP6_SERVICE *IpSb;
825 IP6_ADDRESS_INFO *AddrInfo;
826 EFI_DHCP6_PROTOCOL *Dhcp6;
827 UINT16 OptBuf[4];
828 EFI_DHCP6_PACKET_OPTION *Oro;
829 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
830 EFI_IPv6_ADDRESS AllNodes;
831
832 IpSb = IpIf->Service;
833 AddrInfo = DadEntry->AddressInfo;
834
835 if (IsDadPassed) {
836 //
837 // DAD succeed.
838 //
839 if (NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
840 ASSERT (!IpSb->LinkLocalOk);
841
842 IP6_COPY_ADDRESS (&IpSb->LinkLocalAddr, &AddrInfo->Address);
843 IpSb->LinkLocalOk = TRUE;
844 IpIf->Configured = TRUE;
845
846 //
847 // Check whether DHCP6 need to be started.
848 //
849 Dhcp6 = IpSb->Ip6ConfigInstance.Dhcp6;
850
851 if (IpSb->Dhcp6NeedStart) {
852 Dhcp6->Start (Dhcp6);
853 IpSb->Dhcp6NeedStart = FALSE;
854 }
855
856 if (IpSb->Dhcp6NeedInfoRequest) {
857 //
858 // Set the exta options to send. Here we only want the option request option
859 // with DNS SERVERS.
860 //
861 Oro = (EFI_DHCP6_PACKET_OPTION *)OptBuf;
862 Oro->OpCode = HTONS (DHCP6_OPT_ORO);
863 Oro->OpLen = HTONS (2);
864 *((UINT16 *)&Oro->Data[0]) = HTONS (DHCP6_OPT_DNS_SERVERS);
865
866 InfoReqReXmit.Irt = 4;
867 InfoReqReXmit.Mrc = 64;
868 InfoReqReXmit.Mrt = 60;
869 InfoReqReXmit.Mrd = 0;
870
871 Dhcp6->InfoRequest (
872 Dhcp6,
873 TRUE,
874 Oro,
875 0,
876 NULL,
877 &InfoReqReXmit,
878 IpSb->Ip6ConfigInstance.Dhcp6Event,
879 Ip6ConfigOnDhcp6Reply,
880 &IpSb->Ip6ConfigInstance
881 );
882 }
883
884 //
885 // Add an on-link prefix for link-local address.
886 //
887 Ip6CreatePrefixListEntry (
888 IpSb,
889 TRUE,
890 (UINT32)IP6_INFINIT_LIFETIME,
891 (UINT32)IP6_INFINIT_LIFETIME,
892 IP6_LINK_LOCAL_PREFIX_LENGTH,
893 &IpSb->LinkLocalAddr
894 );
895 } else {
896 //
897 // Global scope unicast address.
898 //
899 Ip6AddAddr (IpIf, AddrInfo);
900
901 //
902 // Add an on-link prefix for this address.
903 //
904 Ip6CreatePrefixListEntry (
905 IpSb,
906 TRUE,
907 AddrInfo->ValidLifetime,
908 AddrInfo->PreferredLifetime,
909 AddrInfo->PrefixLength,
910 &AddrInfo->Address
911 );
912
913 IpIf->Configured = TRUE;
914 }
915 } else {
916 //
917 // Leave the group we joined before.
918 //
919 Ip6LeaveGroup (IpSb, &DadEntry->Destination);
920 }
921
922 if (DadEntry->Callback != NULL) {
923 DadEntry->Callback (IsDadPassed, &AddrInfo->Address, DadEntry->Context);
924 }
925
926 if (!IsDadPassed && NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
927 FreePool (AddrInfo);
928 RemoveEntryList (&DadEntry->Link);
929 FreePool (DadEntry);
930 //
931 // Leave link-scope all-nodes multicast address (FF02::1)
932 //
933 Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &AllNodes);
934 Ip6LeaveGroup (IpSb, &AllNodes);
935 //
936 // Disable IP operation since link-local address is a duplicate address.
937 //
938 IpSb->LinkLocalDadFail = TRUE;
939 IpSb->Mnp->Configure (IpSb->Mnp, NULL);
940 gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
941 gBS->SetTimer (IpSb->FasterTimer, TimerCancel, 0);
942 return;
943 }
944
945 if (!IsDadPassed || NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
946 //
947 // Free the AddressInfo we hold if DAD fails or it is a link-local address.
948 //
949 FreePool (AddrInfo);
950 }
951
952 RemoveEntryList (&DadEntry->Link);
953 FreePool (DadEntry);
954}
955
956/**
957 Create a DAD (Duplicate Address Detection) entry and queue it to be performed.
958
959 @param[in] IpIf Points to the IP6_INTERFACE.
960 @param[in] AddressInfo The address information which needs DAD performed.
961 @param[in] Callback The callback routine that will be called after DAD
962 is performed. This is an optional parameter that
963 may be NULL.
964 @param[in] Context The opaque parameter for a DAD callback routine.
965 This is an optional parameter that may be NULL.
966
967 @retval EFI_SUCCESS The DAD entry was created and queued.
968 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory to complete the
969 operation.
970
971
972**/
973EFI_STATUS
974Ip6InitDADProcess (
975 IN IP6_INTERFACE *IpIf,
976 IN IP6_ADDRESS_INFO *AddressInfo,
977 IN IP6_DAD_CALLBACK Callback OPTIONAL,
978 IN VOID *Context OPTIONAL
979 )
980{
981 IP6_DAD_ENTRY *Entry;
982 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS *DadXmits;
983 IP6_SERVICE *IpSb;
984 EFI_STATUS Status;
985 UINT32 MaxDelayTick;
986 UINT32 Random;
987
988 NET_CHECK_SIGNATURE (IpIf, IP6_INTERFACE_SIGNATURE);
989 ASSERT (AddressInfo != NULL);
990
991 Status = PseudoRandomU32 (&Random);
992 if (EFI_ERROR (Status)) {
993 DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status));
994 return Status;
995 }
996
997 //
998 // Do nothing if we have already started DAD on the address.
999 //
1000 if (Ip6FindDADEntry (IpIf->Service, &AddressInfo->Address, NULL) != NULL) {
1001 return EFI_SUCCESS;
1002 }
1003
1004 Status = EFI_SUCCESS;
1005 IpSb = IpIf->Service;
1006 DadXmits = &IpSb->Ip6ConfigInstance.DadXmits;
1007
1008 //
1009 // Allocate the resources and insert info
1010 //
1011 Entry = AllocatePool (sizeof (IP6_DAD_ENTRY));
1012 if (Entry == NULL) {
1013 return EFI_OUT_OF_RESOURCES;
1014 }
1015
1016 //
1017 // Map the incoming unicast address to solicited-node multicast address
1018 //
1019 Ip6CreateSNMulticastAddr (&AddressInfo->Address, &Entry->Destination);
1020
1021 //
1022 // Join in the solicited-node multicast address.
1023 //
1024 Status = Ip6JoinGroup (IpSb, IpIf, &Entry->Destination);
1025 if (EFI_ERROR (Status)) {
1026 FreePool (Entry);
1027 return Status;
1028 }
1029
1030 Entry->Signature = IP6_DAD_ENTRY_SIGNATURE;
1031 Entry->MaxTransmit = DadXmits->DupAddrDetectTransmits;
1032 Entry->Transmit = 0;
1033 Entry->Receive = 0;
1034 MaxDelayTick = IP6_MAX_RTR_SOLICITATION_DELAY / IP6_TIMER_INTERVAL_IN_MS;
1035 Entry->RetransTick = (MaxDelayTick * ((Random % 5) + 1)) / 5;
1036 Entry->AddressInfo = AddressInfo;
1037 Entry->Callback = Callback;
1038 Entry->Context = Context;
1039 InsertTailList (&IpIf->DupAddrDetectList, &Entry->Link);
1040
1041 if (Entry->MaxTransmit == 0) {
1042 //
1043 // DAD is disabled on this interface, immediately mark this DAD successful.
1044 //
1045 Ip6OnDADFinished (TRUE, IpIf, Entry);
1046 }
1047
1048 return EFI_SUCCESS;
1049}
1050
1051/**
1052 Search IP6_DAD_ENTRY from the Duplicate Address Detection List.
1053
1054 @param[in] IpSb The pointer to the IP6_SERVICE instance.
1055 @param[in] Target The address information which needs DAD performed .
1056 @param[out] Interface If not NULL, output the IP6 interface that configures
1057 the tentative address.
1058
1059 @return NULL if failed to find the matching DAD entry.
1060 Otherwise, point to the found DAD entry.
1061
1062**/
1063IP6_DAD_ENTRY *
1064Ip6FindDADEntry (
1065 IN IP6_SERVICE *IpSb,
1066 IN EFI_IPv6_ADDRESS *Target,
1067 OUT IP6_INTERFACE **Interface OPTIONAL
1068 )
1069{
1070 LIST_ENTRY *Entry;
1071 LIST_ENTRY *Entry2;
1072 IP6_INTERFACE *IpIf;
1073 IP6_DAD_ENTRY *DupAddrDetect;
1074 IP6_ADDRESS_INFO *AddrInfo;
1075
1076 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
1077 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
1078
1079 NET_LIST_FOR_EACH (Entry2, &IpIf->DupAddrDetectList) {
1080 DupAddrDetect = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);
1081 AddrInfo = DupAddrDetect->AddressInfo;
1082 if (EFI_IP6_EQUAL (&AddrInfo->Address, Target)) {
1083 if (Interface != NULL) {
1084 *Interface = IpIf;
1085 }
1086
1087 return DupAddrDetect;
1088 }
1089 }
1090 }
1091
1092 return NULL;
1093}
1094
1095/**
1096 Generate router solicit message and send it out to Destination Address or
1097 All Router Link Local scope multicast address.
1098
1099 @param[in] IpSb The IP service to send the packet.
1100 @param[in] Interface If not NULL, points to the IP6 interface to send
1101 the packet.
1102 @param[in] SourceAddress If not NULL, the source address of the message.
1103 @param[in] DestinationAddress If not NULL, the destination address of the message.
1104 @param[in] SourceLinkAddress If not NULL, the MAC address of the source.
1105 A source link-layer address option will be appended
1106 to the message.
1107
1108 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1109 operation.
1110 @retval EFI_SUCCESS The router solicit message was successfully sent.
1111
1112**/
1113EFI_STATUS
1114Ip6SendRouterSolicit (
1115 IN IP6_SERVICE *IpSb,
1116 IN IP6_INTERFACE *Interface OPTIONAL,
1117 IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL,
1118 IN EFI_IPv6_ADDRESS *DestinationAddress OPTIONAL,
1119 IN EFI_MAC_ADDRESS *SourceLinkAddress OPTIONAL
1120 )
1121{
1122 NET_BUF *Packet;
1123 EFI_IP6_HEADER Head;
1124 IP6_ICMP_INFORMATION_HEAD *IcmpHead;
1125 IP6_ETHER_ADDR_OPTION *LinkLayerOption;
1126 UINT16 PayloadLen;
1127 IP6_INTERFACE *IpIf;
1128
1129 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
1130
1131 IpIf = Interface;
1132 if ((IpIf == NULL) && (IpSb->DefaultInterface != NULL)) {
1133 IpIf = IpSb->DefaultInterface;
1134 }
1135
1136 //
1137 // Generate the packet to be sent
1138 //
1139
1140 PayloadLen = (UINT16)sizeof (IP6_ICMP_INFORMATION_HEAD);
1141 if (SourceLinkAddress != NULL) {
1142 PayloadLen += sizeof (IP6_ETHER_ADDR_OPTION);
1143 }
1144
1145 Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32)PayloadLen);
1146 if (Packet == NULL) {
1147 return EFI_OUT_OF_RESOURCES;
1148 }
1149
1150 //
1151 // Create the basic IPv6 header.
1152 //
1153 Head.FlowLabelL = 0;
1154 Head.FlowLabelH = 0;
1155 Head.PayloadLength = HTONS (PayloadLen);
1156 Head.NextHeader = IP6_ICMP;
1157 Head.HopLimit = IP6_HOP_LIMIT;
1158
1159 if (SourceAddress != NULL) {
1160 IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
1161 } else {
1162 ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
1163 }
1164
1165 if (DestinationAddress != NULL) {
1166 IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
1167 } else {
1168 Ip6SetToAllNodeMulticast (TRUE, IP6_LINK_LOCAL_SCOPE, &Head.DestinationAddress);
1169 }
1170
1171 NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
1172
1173 //
1174 // Fill in the ICMP header, and Source link-layer address if contained.
1175 //
1176
1177 IcmpHead = (IP6_ICMP_INFORMATION_HEAD *)NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
1178 ASSERT (IcmpHead != NULL);
1179 ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
1180 IcmpHead->Head.Type = ICMP_V6_ROUTER_SOLICIT;
1181 IcmpHead->Head.Code = 0;
1182
1183 LinkLayerOption = NULL;
1184 if (SourceLinkAddress != NULL) {
1185 LinkLayerOption = (IP6_ETHER_ADDR_OPTION *)NetbufAllocSpace (
1186 Packet,
1187 sizeof (IP6_ETHER_ADDR_OPTION),
1188 FALSE
1189 );
1190 ASSERT (LinkLayerOption != NULL);
1191 LinkLayerOption->Type = Ip6OptionEtherSource;
1192 LinkLayerOption->Length = (UINT8)sizeof (IP6_ETHER_ADDR_OPTION);
1193 CopyMem (LinkLayerOption->EtherAddr, SourceLinkAddress, 6);
1194 }
1195
1196 //
1197 // Transmit the packet
1198 //
1199 return Ip6Output (IpSb, IpIf, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
1200}
1201
1202/**
1203 Generate a Neighbor Advertisement message and send it out to Destination Address.
1204
1205 @param[in] IpSb The IP service to send the packet.
1206 @param[in] SourceAddress The source address of the message.
1207 @param[in] DestinationAddress The destination address of the message.
1208 @param[in] TargetIp6Address The target address field in the Neighbor Solicitation
1209 message that prompted this advertisement.
1210 @param[in] TargetLinkAddress The MAC address for the target, i.e. the sender
1211 of the advertisement.
1212 @param[in] IsRouter If TRUE, indicates the sender is a router.
1213 @param[in] Override If TRUE, indicates the advertisement should override
1214 an existing cache entry and update the MAC address.
1215 @param[in] Solicited If TRUE, indicates the advertisement was sent
1216 in response to a Neighbor Solicitation from
1217 the Destination address.
1218
1219 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1220 operation.
1221 @retval EFI_SUCCESS The Neighbor Advertise message was successfully sent.
1222
1223**/
1224EFI_STATUS
1225Ip6SendNeighborAdvertise (
1226 IN IP6_SERVICE *IpSb,
1227 IN EFI_IPv6_ADDRESS *SourceAddress,
1228 IN EFI_IPv6_ADDRESS *DestinationAddress,
1229 IN EFI_IPv6_ADDRESS *TargetIp6Address,
1230 IN EFI_MAC_ADDRESS *TargetLinkAddress,
1231 IN BOOLEAN IsRouter,
1232 IN BOOLEAN Override,
1233 IN BOOLEAN Solicited
1234 )
1235{
1236 NET_BUF *Packet;
1237 EFI_IP6_HEADER Head;
1238 IP6_ICMP_INFORMATION_HEAD *IcmpHead;
1239 IP6_ETHER_ADDR_OPTION *LinkLayerOption;
1240 EFI_IPv6_ADDRESS *Target;
1241 UINT16 PayloadLen;
1242
1243 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
1244
1245 //
1246 // The Neighbor Advertisement message must include a Target link-layer address option
1247 // when responding to multicast solicitation and should include such option when
1248 // responding to unicast solicitation. It also must include such option as unsolicited
1249 // advertisement.
1250 //
1251 ASSERT (DestinationAddress != NULL && TargetIp6Address != NULL && TargetLinkAddress != NULL);
1252
1253 PayloadLen = (UINT16)(sizeof (IP6_ICMP_INFORMATION_HEAD) + sizeof (EFI_IPv6_ADDRESS) + sizeof (IP6_ETHER_ADDR_OPTION));
1254
1255 //
1256 // Generate the packet to be sent
1257 //
1258
1259 Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32)PayloadLen);
1260 if (Packet == NULL) {
1261 return EFI_OUT_OF_RESOURCES;
1262 }
1263
1264 //
1265 // Create the basic IPv6 header.
1266 //
1267 Head.FlowLabelL = 0;
1268 Head.FlowLabelH = 0;
1269 Head.PayloadLength = HTONS (PayloadLen);
1270 Head.NextHeader = IP6_ICMP;
1271 Head.HopLimit = IP6_HOP_LIMIT;
1272
1273 IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
1274 IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
1275
1276 NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
1277
1278 //
1279 // Fill in the ICMP header, Target address, and Target link-layer address.
1280 // Set the Router flag, Solicited flag and Override flag.
1281 //
1282
1283 IcmpHead = (IP6_ICMP_INFORMATION_HEAD *)NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
1284 ASSERT (IcmpHead != NULL);
1285 ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
1286 IcmpHead->Head.Type = ICMP_V6_NEIGHBOR_ADVERTISE;
1287 IcmpHead->Head.Code = 0;
1288
1289 if (IsRouter) {
1290 IcmpHead->Fourth |= IP6_IS_ROUTER_FLAG;
1291 }
1292
1293 if (Solicited) {
1294 IcmpHead->Fourth |= IP6_SOLICITED_FLAG;
1295 }
1296
1297 if (Override) {
1298 IcmpHead->Fourth |= IP6_OVERRIDE_FLAG;
1299 }
1300
1301 Target = (EFI_IPv6_ADDRESS *)NetbufAllocSpace (Packet, sizeof (EFI_IPv6_ADDRESS), FALSE);
1302 ASSERT (Target != NULL);
1303 IP6_COPY_ADDRESS (Target, TargetIp6Address);
1304
1305 LinkLayerOption = (IP6_ETHER_ADDR_OPTION *)NetbufAllocSpace (
1306 Packet,
1307 sizeof (IP6_ETHER_ADDR_OPTION),
1308 FALSE
1309 );
1310 ASSERT (LinkLayerOption != NULL);
1311 LinkLayerOption->Type = Ip6OptionEtherTarget;
1312 LinkLayerOption->Length = 1;
1313 CopyMem (LinkLayerOption->EtherAddr, TargetLinkAddress, 6);
1314
1315 //
1316 // Transmit the packet
1317 //
1318 return Ip6Output (IpSb, NULL, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
1319}
1320
1321/**
1322 Generate the Neighbor Solicitation message and send it to the Destination Address.
1323
1324 @param[in] IpSb The IP service to send the packet
1325 @param[in] SourceAddress The source address of the message.
1326 @param[in] DestinationAddress The destination address of the message.
1327 @param[in] TargetIp6Address The IP address of the target of the solicitation.
1328 It must not be a multicast address.
1329 @param[in] SourceLinkAddress The MAC address for the sender. If not NULL,
1330 a source link-layer address option will be appended
1331 to the message.
1332
1333 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1334 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1335 operation.
1336 @retval EFI_SUCCESS The Neighbor Advertise message was successfully sent.
1337
1338**/
1339EFI_STATUS
1340Ip6SendNeighborSolicit (
1341 IN IP6_SERVICE *IpSb,
1342 IN EFI_IPv6_ADDRESS *SourceAddress,
1343 IN EFI_IPv6_ADDRESS *DestinationAddress,
1344 IN EFI_IPv6_ADDRESS *TargetIp6Address,
1345 IN EFI_MAC_ADDRESS *SourceLinkAddress OPTIONAL
1346 )
1347{
1348 NET_BUF *Packet;
1349 EFI_IP6_HEADER Head;
1350 IP6_ICMP_INFORMATION_HEAD *IcmpHead;
1351 IP6_ETHER_ADDR_OPTION *LinkLayerOption;
1352 EFI_IPv6_ADDRESS *Target;
1353 BOOLEAN IsDAD;
1354 UINT16 PayloadLen;
1355 IP6_NEIGHBOR_ENTRY *Neighbor;
1356
1357 //
1358 // Check input parameters
1359 //
1360 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
1361 if ((DestinationAddress == NULL) || (TargetIp6Address == NULL)) {
1362 return EFI_INVALID_PARAMETER;
1363 }
1364
1365 IsDAD = FALSE;
1366
1367 if ((SourceAddress == NULL) || ((SourceAddress != NULL) && NetIp6IsUnspecifiedAddr (SourceAddress))) {
1368 IsDAD = TRUE;
1369 }
1370
1371 //
1372 // The Neighbor Solicitation message should include a source link-layer address option
1373 // if the solicitation is not sent by performing DAD - Duplicate Address Detection.
1374 // Otherwise must not include it.
1375 //
1376 PayloadLen = (UINT16)(sizeof (IP6_ICMP_INFORMATION_HEAD) + sizeof (EFI_IPv6_ADDRESS));
1377
1378 if (!IsDAD) {
1379 if (SourceLinkAddress == NULL) {
1380 return EFI_INVALID_PARAMETER;
1381 }
1382
1383 PayloadLen = (UINT16)(PayloadLen + sizeof (IP6_ETHER_ADDR_OPTION));
1384 }
1385
1386 //
1387 // Generate the packet to be sent
1388 //
1389
1390 Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32)PayloadLen);
1391 if (Packet == NULL) {
1392 return EFI_OUT_OF_RESOURCES;
1393 }
1394
1395 //
1396 // Create the basic IPv6 header
1397 //
1398 Head.FlowLabelL = 0;
1399 Head.FlowLabelH = 0;
1400 Head.PayloadLength = HTONS (PayloadLen);
1401 Head.NextHeader = IP6_ICMP;
1402 Head.HopLimit = IP6_HOP_LIMIT;
1403
1404 if (SourceAddress != NULL) {
1405 IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
1406 } else {
1407 ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
1408 }
1409
1410 IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
1411
1412 NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
1413
1414 //
1415 // Fill in the ICMP header, Target address, and Source link-layer address.
1416 //
1417 IcmpHead = (IP6_ICMP_INFORMATION_HEAD *)NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
1418 ASSERT (IcmpHead != NULL);
1419 ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
1420 IcmpHead->Head.Type = ICMP_V6_NEIGHBOR_SOLICIT;
1421 IcmpHead->Head.Code = 0;
1422
1423 Target = (EFI_IPv6_ADDRESS *)NetbufAllocSpace (Packet, sizeof (EFI_IPv6_ADDRESS), FALSE);
1424 ASSERT (Target != NULL);
1425 IP6_COPY_ADDRESS (Target, TargetIp6Address);
1426
1427 LinkLayerOption = NULL;
1428 if (!IsDAD) {
1429 //
1430 // Fill in the source link-layer address option
1431 //
1432 LinkLayerOption = (IP6_ETHER_ADDR_OPTION *)NetbufAllocSpace (
1433 Packet,
1434 sizeof (IP6_ETHER_ADDR_OPTION),
1435 FALSE
1436 );
1437 ASSERT (LinkLayerOption != NULL);
1438 LinkLayerOption->Type = Ip6OptionEtherSource;
1439 LinkLayerOption->Length = 1;
1440 CopyMem (LinkLayerOption->EtherAddr, SourceLinkAddress, 6);
1441 }
1442
1443 //
1444 // Create a Neighbor Cache entry in the INCOMPLETE state when performing
1445 // address resolution.
1446 //
1447 if (!IsDAD && Ip6IsSNMulticastAddr (DestinationAddress)) {
1448 Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
1449 if (Neighbor == NULL) {
1450 Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, NULL);
1451 ASSERT (Neighbor != NULL);
1452 }
1453 }
1454
1455 //
1456 // Transmit the packet
1457 //
1458 return Ip6Output (IpSb, IpSb->DefaultInterface, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
1459}
1460
1461/**
1462 Process the Neighbor Solicitation message. The message may be sent for Duplicate
1463 Address Detection or Address Resolution.
1464
1465 @param[in] IpSb The IP service that received the packet.
1466 @param[in] Head The IP head of the message.
1467 @param[in] Packet The content of the message with IP head removed.
1468
1469 @retval EFI_SUCCESS The packet processed successfully.
1470 @retval EFI_INVALID_PARAMETER The packet is invalid.
1471 @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
1472 @retval Others Failed to process the packet.
1473
1474**/
1475EFI_STATUS
1476Ip6ProcessNeighborSolicit (
1477 IN IP6_SERVICE *IpSb,
1478 IN EFI_IP6_HEADER *Head,
1479 IN NET_BUF *Packet
1480 )
1481{
1482 IP6_ICMP_INFORMATION_HEAD Icmp;
1483 EFI_IPv6_ADDRESS Target;
1484 IP6_ETHER_ADDR_OPTION LinkLayerOption;
1485 BOOLEAN IsDAD;
1486 BOOLEAN IsUnicast;
1487 BOOLEAN IsMaintained;
1488 IP6_DAD_ENTRY *DupAddrDetect;
1489 IP6_INTERFACE *IpIf;
1490 IP6_NEIGHBOR_ENTRY *Neighbor;
1491 BOOLEAN Solicited;
1492 BOOLEAN UpdateCache;
1493 EFI_IPv6_ADDRESS Dest;
1494 UINT16 OptionLen;
1495 UINT8 *Option;
1496 BOOLEAN Provided;
1497 EFI_STATUS Status;
1498 VOID *MacAddress;
1499
1500 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);
1501 NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
1502
1503 //
1504 // Perform Message Validation:
1505 // The IP Hop Limit field has a value of 255, i.e., the packet
1506 // could not possibly have been forwarded by a router.
1507 // ICMP Code is 0.
1508 // Target Address is not a multicast address.
1509 //
1510 Status = EFI_INVALID_PARAMETER;
1511
1512 if ((Head->HopLimit != IP6_HOP_LIMIT) || (Icmp.Head.Code != 0) || !NetIp6IsValidUnicast (&Target)) {
1513 goto Exit;
1514 }
1515
1516 //
1517 // ICMP length is 24 or more octets.
1518 //
1519 OptionLen = 0;
1520 if (Head->PayloadLength < IP6_ND_LENGTH) {
1521 goto Exit;
1522 } else {
1523 OptionLen = (UINT16)(Head->PayloadLength - IP6_ND_LENGTH);
1524 if (OptionLen != 0) {
1525 Option = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
1526 ASSERT (Option != NULL);
1527
1528 //
1529 // All included options should have a length that is greater than zero.
1530 //
1531 if (!Ip6IsNDOptionValid (Option, OptionLen)) {
1532 goto Exit;
1533 }
1534 }
1535 }
1536
1537 IsDAD = NetIp6IsUnspecifiedAddr (&Head->SourceAddress);
1538 IsUnicast = (BOOLEAN) !Ip6IsSNMulticastAddr (&Head->DestinationAddress);
1539 IsMaintained = Ip6IsOneOfSetAddress (IpSb, &Target, &IpIf, NULL);
1540
1541 Provided = FALSE;
1542 if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
1543 NetbufCopy (
1544 Packet,
1545 IP6_ND_LENGTH,
1546 sizeof (IP6_ETHER_ADDR_OPTION),
1547 (UINT8 *)&LinkLayerOption
1548 );
1549 //
1550 // The solicitation for neighbor discovery should include a source link-layer
1551 // address option. If the option is not recognized, silently ignore it.
1552 //
1553 if (LinkLayerOption.Type == Ip6OptionEtherSource) {
1554 if (IsDAD) {
1555 //
1556 // If the IP source address is the unspecified address, the source
1557 // link-layer address option must not be included in the message.
1558 //
1559 goto Exit;
1560 }
1561
1562 Provided = TRUE;
1563 }
1564 }
1565
1566 //
1567 // If the IP source address is the unspecified address, the IP
1568 // destination address is a solicited-node multicast address.
1569 //
1570 if (IsDAD && IsUnicast) {
1571 goto Exit;
1572 }
1573
1574 //
1575 // If the target address is tentative, and the source address is a unicast address,
1576 // the solicitation's sender is performing address resolution on the target;
1577 // the solicitation should be silently ignored.
1578 //
1579 if (!IsDAD && !IsMaintained) {
1580 goto Exit;
1581 }
1582
1583 //
1584 // If received unicast neighbor solicitation but destination is not this node,
1585 // drop the packet.
1586 //
1587 if (IsUnicast && !IsMaintained) {
1588 goto Exit;
1589 }
1590
1591 //
1592 // In DAD, when target address is a tentative address,
1593 // process the received neighbor solicitation message but not send out response.
1594 //
1595 if (IsDAD && !IsMaintained) {
1596 DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
1597 if (DupAddrDetect != NULL) {
1598 //
1599 // Check the MAC address of the incoming packet.
1600 //
1601 if (IpSb->RecvRequest.MnpToken.Packet.RxData == NULL) {
1602 goto Exit;
1603 }
1604
1605 MacAddress = IpSb->RecvRequest.MnpToken.Packet.RxData->SourceAddress;
1606 if (MacAddress != NULL) {
1607 if (CompareMem (
1608 MacAddress,
1609 &IpSb->SnpMode.CurrentAddress,
1610 IpSb->SnpMode.HwAddressSize
1611 ) != 0)
1612 {
1613 //
1614 // The NS is from another node to performing DAD on the same address.
1615 // Fail DAD for the tentative address.
1616 //
1617 Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
1618 Status = EFI_ICMP_ERROR;
1619 } else {
1620 //
1621 // The below layer loopback the NS we sent. Record it and wait for more.
1622 //
1623 DupAddrDetect->Receive++;
1624 Status = EFI_SUCCESS;
1625 }
1626 }
1627 }
1628
1629 goto Exit;
1630 }
1631
1632 //
1633 // If the solicitation does not contain a link-layer address, DO NOT create or
1634 // update the neighbor cache entries.
1635 //
1636 if (Provided) {
1637 Neighbor = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
1638 UpdateCache = FALSE;
1639
1640 if (Neighbor == NULL) {
1641 Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, &Head->SourceAddress, NULL);
1642 if (Neighbor == NULL) {
1643 Status = EFI_OUT_OF_RESOURCES;
1644 goto Exit;
1645 }
1646
1647 UpdateCache = TRUE;
1648 } else {
1649 if (CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6) != 0) {
1650 UpdateCache = TRUE;
1651 }
1652 }
1653
1654 if (UpdateCache) {
1655 Neighbor->State = EfiNeighborStale;
1656 Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
1657 CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
1658 //
1659 // Send queued packets if exist.
1660 //
1661 Neighbor->CallBack ((VOID *)Neighbor);
1662 }
1663 }
1664
1665 //
1666 // Sends a Neighbor Advertisement as response.
1667 // Set the Router flag to zero since the node is a host.
1668 // If the source address of the solicitation is unspecified, and target address
1669 // is one of the maintained address, reply a unsolicited multicast advertisement.
1670 //
1671 if (IsDAD && IsMaintained) {
1672 Solicited = FALSE;
1673 Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &Dest);
1674 } else {
1675 Solicited = TRUE;
1676 IP6_COPY_ADDRESS (&Dest, &Head->SourceAddress);
1677 }
1678
1679 Status = Ip6SendNeighborAdvertise (
1680 IpSb,
1681 &Target,
1682 &Dest,
1683 &Target,
1684 &IpSb->SnpMode.CurrentAddress,
1685 FALSE,
1686 TRUE,
1687 Solicited
1688 );
1689Exit:
1690 NetbufFree (Packet);
1691 return Status;
1692}
1693
1694/**
1695 Process the Neighbor Advertisement message.
1696
1697 @param[in] IpSb The IP service that received the packet.
1698 @param[in] Head The IP head of the message.
1699 @param[in] Packet The content of the message with IP head removed.
1700
1701 @retval EFI_SUCCESS The packet processed successfully.
1702 @retval EFI_INVALID_PARAMETER The packet is invalid.
1703 @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
1704 @retval Others Failed to process the packet.
1705
1706**/
1707EFI_STATUS
1708Ip6ProcessNeighborAdvertise (
1709 IN IP6_SERVICE *IpSb,
1710 IN EFI_IP6_HEADER *Head,
1711 IN NET_BUF *Packet
1712 )
1713{
1714 IP6_ICMP_INFORMATION_HEAD Icmp;
1715 EFI_IPv6_ADDRESS Target;
1716 IP6_ETHER_ADDR_OPTION LinkLayerOption;
1717 BOOLEAN Provided;
1718 INTN Compare;
1719 IP6_NEIGHBOR_ENTRY *Neighbor;
1720 IP6_DEFAULT_ROUTER *DefaultRouter;
1721 BOOLEAN Solicited;
1722 BOOLEAN IsRouter;
1723 BOOLEAN Override;
1724 IP6_DAD_ENTRY *DupAddrDetect;
1725 IP6_INTERFACE *IpIf;
1726 UINT16 OptionLen;
1727 UINT8 *Option;
1728 EFI_STATUS Status;
1729
1730 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);
1731 NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
1732
1733 //
1734 // Validate the incoming Neighbor Advertisement
1735 //
1736 Status = EFI_INVALID_PARAMETER;
1737 //
1738 // The IP Hop Limit field has a value of 255, i.e., the packet
1739 // could not possibly have been forwarded by a router.
1740 // ICMP Code is 0.
1741 // Target Address is not a multicast address.
1742 //
1743 if ((Head->HopLimit != IP6_HOP_LIMIT) || (Icmp.Head.Code != 0) || !NetIp6IsValidUnicast (&Target)) {
1744 goto Exit;
1745 }
1746
1747 //
1748 // ICMP length is 24 or more octets.
1749 //
1750 Provided = FALSE;
1751 OptionLen = 0;
1752 if (Head->PayloadLength < IP6_ND_LENGTH) {
1753 goto Exit;
1754 } else {
1755 OptionLen = (UINT16)(Head->PayloadLength - IP6_ND_LENGTH);
1756 if (OptionLen != 0) {
1757 Option = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
1758 ASSERT (Option != NULL);
1759
1760 //
1761 // All included options should have a length that is greater than zero.
1762 //
1763 if (!Ip6IsNDOptionValid (Option, OptionLen)) {
1764 goto Exit;
1765 }
1766 }
1767 }
1768
1769 //
1770 // If the IP destination address is a multicast address, Solicited Flag is ZERO.
1771 //
1772 Solicited = FALSE;
1773 if ((Icmp.Fourth & IP6_SOLICITED_FLAG) == IP6_SOLICITED_FLAG) {
1774 Solicited = TRUE;
1775 }
1776
1777 if (IP6_IS_MULTICAST (&Head->DestinationAddress) && Solicited) {
1778 goto Exit;
1779 }
1780
1781 //
1782 // DAD - Check whether the Target is one of our tentative address.
1783 //
1784 DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
1785 if (DupAddrDetect != NULL) {
1786 //
1787 // DAD fails, some other node is using this address.
1788 //
1789 NetbufFree (Packet);
1790 Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
1791 return EFI_ICMP_ERROR;
1792 }
1793
1794 //
1795 // Search the Neighbor Cache for the target's entry. If no entry exists,
1796 // the advertisement should be silently discarded.
1797 //
1798 Neighbor = Ip6FindNeighborEntry (IpSb, &Target);
1799 if (Neighbor == NULL) {
1800 goto Exit;
1801 }
1802
1803 //
1804 // Get IsRouter Flag and Override Flag
1805 //
1806 IsRouter = FALSE;
1807 Override = FALSE;
1808 if ((Icmp.Fourth & IP6_IS_ROUTER_FLAG) == IP6_IS_ROUTER_FLAG) {
1809 IsRouter = TRUE;
1810 }
1811
1812 if ((Icmp.Fourth & IP6_OVERRIDE_FLAG) == IP6_OVERRIDE_FLAG) {
1813 Override = TRUE;
1814 }
1815
1816 //
1817 // Check whether link layer option is included.
1818 //
1819 if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
1820 NetbufCopy (
1821 Packet,
1822 IP6_ND_LENGTH,
1823 sizeof (IP6_ETHER_ADDR_OPTION),
1824 (UINT8 *)&LinkLayerOption
1825 );
1826
1827 if (LinkLayerOption.Type == Ip6OptionEtherTarget) {
1828 Provided = TRUE;
1829 }
1830 }
1831
1832 Compare = 0;
1833 if (Provided) {
1834 Compare = CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
1835 }
1836
1837 if (!Neighbor->IsRouter && IsRouter) {
1838 DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
1839 if (DefaultRouter != NULL) {
1840 DefaultRouter->NeighborCache = Neighbor;
1841 }
1842 }
1843
1844 if (Neighbor->State == EfiNeighborInComplete) {
1845 //
1846 // If the target's Neighbor Cache entry is in INCOMPLETE state and no
1847 // Target Link-Layer address option is included while link layer has
1848 // address, the message should be silently discarded.
1849 //
1850 if (!Provided) {
1851 goto Exit;
1852 }
1853
1854 //
1855 // Update the Neighbor Cache
1856 //
1857 CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
1858 if (Solicited) {
1859 Neighbor->State = EfiNeighborReachable;
1860 Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
1861 } else {
1862 Neighbor->State = EfiNeighborStale;
1863 Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
1864 //
1865 // Send any packets queued for the neighbor awaiting address resolution.
1866 //
1867 Neighbor->CallBack ((VOID *)Neighbor);
1868 }
1869
1870 Neighbor->IsRouter = IsRouter;
1871 } else {
1872 if (!Override && (Compare != 0)) {
1873 //
1874 // When the Override Flag is clear and supplied link-layer address differs from
1875 // that in the cache, if the state of the entry is not REACHABLE, ignore the
1876 // message. Otherwise set it to STALE but do not update the entry in any
1877 // other way.
1878 //
1879 if (Neighbor->State == EfiNeighborReachable) {
1880 Neighbor->State = EfiNeighborStale;
1881 Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
1882 }
1883 } else {
1884 if (Compare != 0) {
1885 CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
1886 }
1887
1888 //
1889 // Update the entry's state
1890 //
1891 if (Solicited) {
1892 Neighbor->State = EfiNeighborReachable;
1893 Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
1894 } else {
1895 if (Compare != 0) {
1896 Neighbor->State = EfiNeighborStale;
1897 Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
1898 }
1899 }
1900
1901 //
1902 // When IsRouter is changed from TRUE to FALSE, remove the router from the
1903 // Default Router List and remove the Destination Cache entries for all destinations
1904 // using the neighbor as a router.
1905 //
1906 if (Neighbor->IsRouter && !IsRouter) {
1907 DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
1908 if (DefaultRouter != NULL) {
1909 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
1910 }
1911 }
1912
1913 Neighbor->IsRouter = IsRouter;
1914 }
1915 }
1916
1917 if (Neighbor->State == EfiNeighborReachable) {
1918 Neighbor->CallBack ((VOID *)Neighbor);
1919 }
1920
1921 Status = EFI_SUCCESS;
1922
1923Exit:
1924 NetbufFree (Packet);
1925 return Status;
1926}
1927
1928/**
1929 Process the Router Advertisement message according to RFC4861.
1930
1931 @param[in] IpSb The IP service that received the packet.
1932 @param[in] Head The IP head of the message.
1933 @param[in] Packet The content of the message with the IP head removed.
1934
1935 @retval EFI_SUCCESS The packet processed successfully.
1936 @retval EFI_INVALID_PARAMETER The packet is invalid.
1937 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1938 operation.
1939 @retval Others Failed to process the packet.
1940
1941**/
1942EFI_STATUS
1943Ip6ProcessRouterAdvertise (
1944 IN IP6_SERVICE *IpSb,
1945 IN EFI_IP6_HEADER *Head,
1946 IN NET_BUF *Packet
1947 )
1948{
1949 IP6_ICMP_INFORMATION_HEAD Icmp;
1950 UINT32 ReachableTime;
1951 UINT32 RetransTimer;
1952 UINT16 RouterLifetime;
1953 UINT32 Offset;
1954 UINT8 Type;
1955 UINT8 Length;
1956 IP6_ETHER_ADDR_OPTION LinkLayerOption;
1957 UINT32 Fourth;
1958 UINT8 CurHopLimit;
1959 BOOLEAN Mflag;
1960 BOOLEAN Oflag;
1961 IP6_DEFAULT_ROUTER *DefaultRouter;
1962 IP6_NEIGHBOR_ENTRY *NeighborCache;
1963 EFI_MAC_ADDRESS LinkLayerAddress;
1964 IP6_MTU_OPTION MTUOption;
1965 IP6_PREFIX_INFO_OPTION PrefixOption;
1966 IP6_PREFIX_LIST_ENTRY *PrefixList;
1967 BOOLEAN OnLink;
1968 BOOLEAN Autonomous;
1969 EFI_IPv6_ADDRESS StatelessAddress;
1970 EFI_STATUS Status;
1971 UINT16 OptionLen;
1972 UINT8 *Option;
1973 INTN Result;
1974
1975 Status = EFI_INVALID_PARAMETER;
1976
1977 if (IpSb->Ip6ConfigInstance.Policy != Ip6ConfigPolicyAutomatic) {
1978 //
1979 // Skip the process below as it's not required under the current policy.
1980 //
1981 goto Exit;
1982 }
1983
1984 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);
1985
1986 //
1987 // Validate the incoming Router Advertisement
1988 //
1989
1990 //
1991 // The IP source address must be a link-local address
1992 //
1993 if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
1994 goto Exit;
1995 }
1996
1997 //
1998 // The IP Hop Limit field has a value of 255, i.e. the packet
1999 // could not possibly have been forwarded by a router.
2000 // ICMP Code is 0.
2001 // ICMP length (derived from the IP length) is 16 or more octets.
2002 //
2003 if ((Head->HopLimit != IP6_HOP_LIMIT) || (Icmp.Head.Code != 0) ||
2004 (Head->PayloadLength < IP6_RA_LENGTH))
2005 {
2006 goto Exit;
2007 }
2008
2009 //
2010 // All included options have a length that is greater than zero.
2011 //
2012 OptionLen = (UINT16)(Head->PayloadLength - IP6_RA_LENGTH);
2013 if (OptionLen != 0) {
2014 Option = NetbufGetByte (Packet, IP6_RA_LENGTH, NULL);
2015 ASSERT (Option != NULL);
2016
2017 if (!Ip6IsNDOptionValid (Option, OptionLen)) {
2018 goto Exit;
2019 }
2020 }
2021
2022 //
2023 // Process Fourth field.
2024 // In Router Advertisement, Fourth is composed of CurHopLimit (8bit), M flag, O flag,
2025 // and Router Lifetime (16 bit).
2026 //
2027
2028 Fourth = NTOHL (Icmp.Fourth);
2029 CopyMem (&RouterLifetime, &Fourth, sizeof (UINT16));
2030
2031 //
2032 // If the source address already in the default router list, update it.
2033 // Otherwise create a new entry.
2034 // A Lifetime of zero indicates that the router is not a default router.
2035 //
2036 DefaultRouter = Ip6FindDefaultRouter (IpSb, &Head->SourceAddress);
2037 if (DefaultRouter == NULL) {
2038 if (RouterLifetime != 0) {
2039 DefaultRouter = Ip6CreateDefaultRouter (IpSb, &Head->SourceAddress, RouterLifetime);
2040 if (DefaultRouter == NULL) {
2041 Status = EFI_OUT_OF_RESOURCES;
2042 goto Exit;
2043 }
2044 }
2045 } else {
2046 if (RouterLifetime != 0) {
2047 DefaultRouter->Lifetime = RouterLifetime;
2048 //
2049 // Check the corresponding neighbor cache entry here.
2050 //
2051 if (DefaultRouter->NeighborCache == NULL) {
2052 DefaultRouter->NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
2053 }
2054 } else {
2055 //
2056 // If the address is in the host's default router list and the router lifetime is zero,
2057 // immediately time-out the entry.
2058 //
2059 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
2060 }
2061 }
2062
2063 CurHopLimit = *((UINT8 *)&Fourth + 3);
2064 if (CurHopLimit != 0) {
2065 IpSb->CurHopLimit = CurHopLimit;
2066 }
2067
2068 Mflag = FALSE;
2069 Oflag = FALSE;
2070 if ((*((UINT8 *)&Fourth + 2) & IP6_M_ADDR_CONFIG_FLAG) == IP6_M_ADDR_CONFIG_FLAG) {
2071 Mflag = TRUE;
2072 } else {
2073 if ((*((UINT8 *)&Fourth + 2) & IP6_O_CONFIG_FLAG) == IP6_O_CONFIG_FLAG) {
2074 Oflag = TRUE;
2075 }
2076 }
2077
2078 if (Mflag || Oflag) {
2079 //
2080 // Use Ip6Config to get available addresses or other configuration from DHCP.
2081 //
2082 Ip6ConfigStartStatefulAutoConfig (&IpSb->Ip6ConfigInstance, Oflag);
2083 }
2084
2085 //
2086 // Process Reachable Time and Retrans Timer fields.
2087 //
2088 NetbufCopy (Packet, sizeof (Icmp), sizeof (UINT32), (UINT8 *)&ReachableTime);
2089 NetbufCopy (Packet, sizeof (Icmp) + sizeof (UINT32), sizeof (UINT32), (UINT8 *)&RetransTimer);
2090 ReachableTime = NTOHL (ReachableTime);
2091 RetransTimer = NTOHL (RetransTimer);
2092
2093 if ((ReachableTime != 0) && (ReachableTime != IpSb->BaseReachableTime)) {
2094 //
2095 // If new value is not unspecified and differs from the previous one, record it
2096 // in BaseReachableTime and recompute a ReachableTime.
2097 //
2098 IpSb->BaseReachableTime = ReachableTime;
2099 Status = Ip6UpdateReachableTime (IpSb);
2100 if (EFI_ERROR (Status)) {
2101 goto Exit;
2102 }
2103 }
2104
2105 if (RetransTimer != 0) {
2106 IpSb->RetransTimer = RetransTimer;
2107 }
2108
2109 //
2110 // IsRouter flag must be set to TRUE if corresponding neighbor cache entry exists.
2111 //
2112 NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
2113 if (NeighborCache != NULL) {
2114 NeighborCache->IsRouter = TRUE;
2115 }
2116
2117 //
2118 // If an valid router advertisement is received, stops router solicitation.
2119 //
2120 IpSb->RouterAdvertiseReceived = TRUE;
2121
2122 //
2123 // The only defined options that may appear are the Source
2124 // Link-Layer Address, Prefix information and MTU options.
2125 // All included options have a length that is greater than zero and
2126 // fit within the input packet.
2127 //
2128 Offset = 16;
2129 while (Offset < (UINT32)Head->PayloadLength) {
2130 NetbufCopy (Packet, Offset, sizeof (UINT8), &Type);
2131 switch (Type) {
2132 case Ip6OptionEtherSource:
2133 //
2134 // Update the neighbor cache
2135 //
2136 NetbufCopy (Packet, Offset, sizeof (IP6_ETHER_ADDR_OPTION), (UINT8 *)&LinkLayerOption);
2137
2138 //
2139 // Option size validity ensured by Ip6IsNDOptionValid().
2140 //
2141 ASSERT (LinkLayerOption.Length != 0);
2142 ASSERT (Offset + (UINT32)LinkLayerOption.Length * 8 <= (UINT32)Head->PayloadLength);
2143
2144 ZeroMem (&LinkLayerAddress, sizeof (EFI_MAC_ADDRESS));
2145 CopyMem (&LinkLayerAddress, LinkLayerOption.EtherAddr, 6);
2146
2147 if (NeighborCache == NULL) {
2148 NeighborCache = Ip6CreateNeighborEntry (
2149 IpSb,
2150 Ip6OnArpResolved,
2151 &Head->SourceAddress,
2152 &LinkLayerAddress
2153 );
2154 if (NeighborCache == NULL) {
2155 Status = EFI_OUT_OF_RESOURCES;
2156 goto Exit;
2157 }
2158
2159 NeighborCache->IsRouter = TRUE;
2160 NeighborCache->State = EfiNeighborStale;
2161 NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
2162 } else {
2163 Result = CompareMem (&LinkLayerAddress, &NeighborCache->LinkAddress, 6);
2164
2165 //
2166 // If the link-local address is the same as that already in the cache,
2167 // the cache entry's state remains unchanged. Otherwise update the
2168 // reachability state to STALE.
2169 //
2170 if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
2171 CopyMem (&NeighborCache->LinkAddress, &LinkLayerAddress, 6);
2172
2173 NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
2174
2175 if (NeighborCache->State == EfiNeighborInComplete) {
2176 //
2177 // Send queued packets if exist.
2178 //
2179 NeighborCache->State = EfiNeighborStale;
2180 NeighborCache->CallBack ((VOID *)NeighborCache);
2181 } else {
2182 NeighborCache->State = EfiNeighborStale;
2183 }
2184 }
2185 }
2186
2187 Offset += (UINT32)LinkLayerOption.Length * 8;
2188 break;
2189 case Ip6OptionPrefixInfo:
2190 NetbufCopy (Packet, Offset, sizeof (IP6_PREFIX_INFO_OPTION), (UINT8 *)&PrefixOption);
2191
2192 //
2193 // Option size validity ensured by Ip6IsNDOptionValid().
2194 //
2195 ASSERT (PrefixOption.Length == 4);
2196 ASSERT (Offset + (UINT32)PrefixOption.Length * 8 <= (UINT32)Head->PayloadLength);
2197
2198 PrefixOption.ValidLifetime = NTOHL (PrefixOption.ValidLifetime);
2199 PrefixOption.PreferredLifetime = NTOHL (PrefixOption.PreferredLifetime);
2200
2201 //
2202 // Get L and A flag, recorded in the lower 2 bits of Reserved1
2203 //
2204 OnLink = FALSE;
2205 if ((PrefixOption.Reserved1 & IP6_ON_LINK_FLAG) == IP6_ON_LINK_FLAG) {
2206 OnLink = TRUE;
2207 }
2208
2209 Autonomous = FALSE;
2210 if ((PrefixOption.Reserved1 & IP6_AUTO_CONFIG_FLAG) == IP6_AUTO_CONFIG_FLAG) {
2211 Autonomous = TRUE;
2212 }
2213
2214 //
2215 // If the prefix is the link-local prefix, silently ignore the prefix option.
2216 //
2217 if ((PrefixOption.PrefixLength == IP6_LINK_LOCAL_PREFIX_LENGTH) &&
2218 NetIp6IsLinkLocalAddr (&PrefixOption.Prefix)
2219 )
2220 {
2221 Offset += sizeof (IP6_PREFIX_INFO_OPTION);
2222 break;
2223 }
2224
2225 //
2226 // Do following if on-link flag is set according to RFC4861.
2227 //
2228 if (OnLink) {
2229 PrefixList = Ip6FindPrefixListEntry (
2230 IpSb,
2231 TRUE,
2232 PrefixOption.PrefixLength,
2233 &PrefixOption.Prefix
2234 );
2235 //
2236 // Create a new entry for the prefix, if the ValidLifetime is zero,
2237 // silently ignore the prefix option.
2238 //
2239 if ((PrefixList == NULL) && (PrefixOption.ValidLifetime != 0)) {
2240 PrefixList = Ip6CreatePrefixListEntry (
2241 IpSb,
2242 TRUE,
2243 PrefixOption.ValidLifetime,
2244 PrefixOption.PreferredLifetime,
2245 PrefixOption.PrefixLength,
2246 &PrefixOption.Prefix
2247 );
2248 if (PrefixList == NULL) {
2249 Status = EFI_OUT_OF_RESOURCES;
2250 goto Exit;
2251 }
2252 } else if (PrefixList != NULL) {
2253 if (PrefixOption.ValidLifetime != 0) {
2254 PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
2255 } else {
2256 //
2257 // If the prefix exists and incoming ValidLifetime is zero, immediately
2258 // remove the prefix.
2259 Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
2260 }
2261 }
2262 }
2263
2264 //
2265 // Do following if Autonomous flag is set according to RFC4862.
2266 //
2267 if (Autonomous && (PrefixOption.PreferredLifetime <= PrefixOption.ValidLifetime)) {
2268 PrefixList = Ip6FindPrefixListEntry (
2269 IpSb,
2270 FALSE,
2271 PrefixOption.PrefixLength,
2272 &PrefixOption.Prefix
2273 );
2274 //
2275 // Create a new entry for the prefix, and form an address by prefix + interface id
2276 // If the sum of the prefix length and interface identifier length
2277 // does not equal 128 bits, the Prefix Information option MUST be ignored.
2278 //
2279 if ((PrefixList == NULL) &&
2280 (PrefixOption.ValidLifetime != 0) &&
2281 (PrefixOption.PrefixLength + IpSb->InterfaceIdLen * 8 == 128)
2282 )
2283 {
2284 //
2285 // Form the address in network order.
2286 //
2287 CopyMem (&StatelessAddress, &PrefixOption.Prefix, sizeof (UINT64));
2288 CopyMem (&StatelessAddress.Addr[8], IpSb->InterfaceId, sizeof (UINT64));
2289
2290 //
2291 // If the address is not yet in the assigned address list, adds it into.
2292 //
2293 if (!Ip6IsOneOfSetAddress (IpSb, &StatelessAddress, NULL, NULL)) {
2294 //
2295 // And also not in the DAD process, check its uniqueness firstly.
2296 //
2297 if (Ip6FindDADEntry (IpSb, &StatelessAddress, NULL) == NULL) {
2298 Status = Ip6SetAddress (
2299 IpSb->DefaultInterface,
2300 &StatelessAddress,
2301 FALSE,
2302 PrefixOption.PrefixLength,
2303 PrefixOption.ValidLifetime,
2304 PrefixOption.PreferredLifetime,
2305 NULL,
2306 NULL
2307 );
2308 if (EFI_ERROR (Status)) {
2309 goto Exit;
2310 }
2311 }
2312 }
2313
2314 //
2315 // Adds the prefix option to stateless prefix option list.
2316 //
2317 PrefixList = Ip6CreatePrefixListEntry (
2318 IpSb,
2319 FALSE,
2320 PrefixOption.ValidLifetime,
2321 PrefixOption.PreferredLifetime,
2322 PrefixOption.PrefixLength,
2323 &PrefixOption.Prefix
2324 );
2325 if (PrefixList == NULL) {
2326 Status = EFI_OUT_OF_RESOURCES;
2327 goto Exit;
2328 }
2329 } else if (PrefixList != NULL) {
2330 //
2331 // Reset the preferred lifetime of the address if the advertised prefix exists.
2332 // Perform specific action to valid lifetime together.
2333 //
2334 PrefixList->PreferredLifetime = PrefixOption.PreferredLifetime;
2335 if ((PrefixOption.ValidLifetime > 7200) ||
2336 (PrefixOption.ValidLifetime > PrefixList->ValidLifetime))
2337 {
2338 //
2339 // If the received Valid Lifetime is greater than 2 hours or
2340 // greater than RemainingLifetime, set the valid lifetime of the
2341 // corresponding address to the advertised Valid Lifetime.
2342 //
2343 PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
2344 } else if (PrefixList->ValidLifetime <= 7200) {
2345 //
2346 // If RemainingLifetime is less than or equals to 2 hours, ignore the
2347 // Prefix Information option with regards to the valid lifetime.
2348 // TODO: If this option has been authenticated, set the valid lifetime.
2349 //
2350 } else {
2351 //
2352 // Otherwise, reset the valid lifetime of the corresponding
2353 // address to 2 hours.
2354 //
2355 PrefixList->ValidLifetime = 7200;
2356 }
2357 }
2358 }
2359
2360 Offset += sizeof (IP6_PREFIX_INFO_OPTION);
2361 break;
2362 case Ip6OptionMtu:
2363 NetbufCopy (Packet, Offset, sizeof (IP6_MTU_OPTION), (UINT8 *)&MTUOption);
2364
2365 //
2366 // Option size validity ensured by Ip6IsNDOptionValid().
2367 //
2368 ASSERT (MTUOption.Length == 1);
2369 ASSERT (Offset + (UINT32)MTUOption.Length * 8 <= (UINT32)Head->PayloadLength);
2370
2371 //
2372 // Use IPv6 minimum link MTU 1280 bytes as the maximum packet size in order
2373 // to omit implementation of Path MTU Discovery. Thus ignore the MTU option
2374 // in Router Advertisement.
2375 //
2376
2377 Offset += sizeof (IP6_MTU_OPTION);
2378 break;
2379 default:
2380 //
2381 // Silently ignore unrecognized options
2382 //
2383 NetbufCopy (Packet, Offset + sizeof (UINT8), sizeof (UINT8), &Length);
2384
2385 ASSERT (Length != 0);
2386
2387 Offset += (UINT32)Length * 8;
2388 break;
2389 }
2390 }
2391
2392 Status = EFI_SUCCESS;
2393
2394Exit:
2395 NetbufFree (Packet);
2396 return Status;
2397}
2398
2399/**
2400 Process the ICMPv6 redirect message. Find the instance, then update
2401 its route cache.
2402
2403 @param[in] IpSb The IP6 service binding instance that received
2404 the packet.
2405 @param[in] Head The IP head of the received ICMPv6 packet.
2406 @param[in] Packet The content of the ICMPv6 redirect packet with
2407 the IP head removed.
2408
2409 @retval EFI_INVALID_PARAMETER The parameter is invalid.
2410 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
2411 operation.
2412 @retval EFI_SUCCESS Successfully updated the route caches.
2413
2414**/
2415EFI_STATUS
2416Ip6ProcessRedirect (
2417 IN IP6_SERVICE *IpSb,
2418 IN EFI_IP6_HEADER *Head,
2419 IN NET_BUF *Packet
2420 )
2421{
2422 IP6_ICMP_INFORMATION_HEAD *Icmp;
2423 EFI_IPv6_ADDRESS *Target;
2424 EFI_IPv6_ADDRESS *IcmpDest;
2425 UINT8 *Option;
2426 UINT16 OptionLen;
2427 IP6_ROUTE_ENTRY *RouteEntry;
2428 IP6_ROUTE_CACHE_ENTRY *RouteCache;
2429 IP6_NEIGHBOR_ENTRY *NeighborCache;
2430 INT32 Length;
2431 UINT8 OptLen;
2432 IP6_ETHER_ADDR_OPTION *LinkLayerOption;
2433 EFI_MAC_ADDRESS Mac;
2434 UINT32 Index;
2435 BOOLEAN IsRouter;
2436 EFI_STATUS Status;
2437 INTN Result;
2438
2439 Status = EFI_INVALID_PARAMETER;
2440
2441 Icmp = (IP6_ICMP_INFORMATION_HEAD *)NetbufGetByte (Packet, 0, NULL);
2442 if (Icmp == NULL) {
2443 goto Exit;
2444 }
2445
2446 //
2447 // Validate the incoming Redirect message
2448 //
2449
2450 //
2451 // The IP Hop Limit field has a value of 255, i.e. the packet
2452 // could not possibly have been forwarded by a router.
2453 // ICMP Code is 0.
2454 // ICMP length (derived from the IP length) is 40 or more octets.
2455 //
2456 if ((Head->HopLimit != IP6_HOP_LIMIT) || (Icmp->Head.Code != 0) ||
2457 (Head->PayloadLength < IP6_REDITECT_LENGTH))
2458 {
2459 goto Exit;
2460 }
2461
2462 //
2463 // The IP source address must be a link-local address
2464 //
2465 if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
2466 goto Exit;
2467 }
2468
2469 //
2470 // The dest of this ICMP redirect message is not us.
2471 //
2472 if (!Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) {
2473 goto Exit;
2474 }
2475
2476 //
2477 // All included options have a length that is greater than zero.
2478 //
2479 OptionLen = (UINT16)(Head->PayloadLength - IP6_REDITECT_LENGTH);
2480 if (OptionLen != 0) {
2481 Option = NetbufGetByte (Packet, IP6_REDITECT_LENGTH, NULL);
2482 ASSERT (Option != NULL);
2483
2484 if (!Ip6IsNDOptionValid (Option, OptionLen)) {
2485 goto Exit;
2486 }
2487 }
2488
2489 Target = (EFI_IPv6_ADDRESS *)(Icmp + 1);
2490 IcmpDest = Target + 1;
2491
2492 //
2493 // The ICMP Destination Address field in the redirect message does not contain
2494 // a multicast address.
2495 //
2496 if (IP6_IS_MULTICAST (IcmpDest)) {
2497 goto Exit;
2498 }
2499
2500 //
2501 // The ICMP Target Address is either a link-local address (when redirected to
2502 // a router) or the same as the ICMP Destination Address (when redirected to
2503 // the on-link destination).
2504 //
2505 IsRouter = (BOOLEAN) !EFI_IP6_EQUAL (Target, IcmpDest);
2506 if (!NetIp6IsLinkLocalAddr (Target) && IsRouter) {
2507 goto Exit;
2508 }
2509
2510 //
2511 // Check the options. The only interested option here is the target-link layer
2512 // address option.
2513 //
2514 Length = Packet->TotalSize - 40;
2515 Option = (UINT8 *)(IcmpDest + 1);
2516 LinkLayerOption = NULL;
2517 while (Length > 0) {
2518 switch (*Option) {
2519 case Ip6OptionEtherTarget:
2520
2521 LinkLayerOption = (IP6_ETHER_ADDR_OPTION *)Option;
2522 OptLen = LinkLayerOption->Length;
2523 if (OptLen != 1) {
2524 //
2525 // For ethernet, the length must be 1.
2526 //
2527 goto Exit;
2528 }
2529
2530 break;
2531
2532 default:
2533
2534 OptLen = *(Option + 1);
2535 if (OptLen == 0) {
2536 //
2537 // A length of 0 is invalid.
2538 //
2539 goto Exit;
2540 }
2541
2542 break;
2543 }
2544
2545 Length -= 8 * OptLen;
2546 Option += 8 * OptLen;
2547 }
2548
2549 if (Length != 0) {
2550 goto Exit;
2551 }
2552
2553 //
2554 // The IP source address of the Redirect is the same as the current
2555 // first-hop router for the specified ICMP Destination Address.
2556 //
2557 RouteCache = Ip6FindRouteCache (IpSb->RouteTable, IcmpDest, &Head->DestinationAddress);
2558 if (RouteCache != NULL) {
2559 if (!EFI_IP6_EQUAL (&RouteCache->NextHop, &Head->SourceAddress)) {
2560 //
2561 // The source of this Redirect message must match the NextHop of the
2562 // corresponding route cache entry.
2563 //
2564 goto Exit;
2565 }
2566
2567 //
2568 // Update the NextHop.
2569 //
2570 IP6_COPY_ADDRESS (&RouteCache->NextHop, Target);
2571
2572 if (!IsRouter) {
2573 RouteEntry = (IP6_ROUTE_ENTRY *)RouteCache->Tag;
2574 RouteEntry->Flag = RouteEntry->Flag | IP6_DIRECT_ROUTE;
2575 }
2576 } else {
2577 //
2578 // Get the Route Entry.
2579 //
2580 RouteEntry = Ip6FindRouteEntry (IpSb->RouteTable, IcmpDest, NULL);
2581 if (RouteEntry == NULL) {
2582 RouteEntry = Ip6CreateRouteEntry (IcmpDest, 0, NULL);
2583 if (RouteEntry == NULL) {
2584 Status = EFI_OUT_OF_RESOURCES;
2585 goto Exit;
2586 }
2587 }
2588
2589 if (!IsRouter) {
2590 RouteEntry->Flag = IP6_DIRECT_ROUTE;
2591 }
2592
2593 //
2594 // Create a route cache for this.
2595 //
2596 RouteCache = Ip6CreateRouteCacheEntry (
2597 IcmpDest,
2598 &Head->DestinationAddress,
2599 Target,
2600 (UINTN)RouteEntry
2601 );
2602 if (RouteCache == NULL) {
2603 Status = EFI_OUT_OF_RESOURCES;
2604 goto Exit;
2605 }
2606
2607 //
2608 // Insert the newly created route cache entry.
2609 //
2610 Index = IP6_ROUTE_CACHE_HASH (IcmpDest, &Head->DestinationAddress);
2611 InsertHeadList (&IpSb->RouteTable->Cache.CacheBucket[Index], &RouteCache->Link);
2612 }
2613
2614 //
2615 // Try to locate the neighbor cache for the Target.
2616 //
2617 NeighborCache = Ip6FindNeighborEntry (IpSb, Target);
2618
2619 if (LinkLayerOption != NULL) {
2620 if (NeighborCache == NULL) {
2621 //
2622 // Create a neighbor cache for the Target.
2623 //
2624 ZeroMem (&Mac, sizeof (EFI_MAC_ADDRESS));
2625 CopyMem (&Mac, LinkLayerOption->EtherAddr, 6);
2626 NeighborCache = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, Target, &Mac);
2627 if (NeighborCache == NULL) {
2628 //
2629 // Just report a success here. The neighbor cache can be created in
2630 // some other place.
2631 //
2632 Status = EFI_SUCCESS;
2633 goto Exit;
2634 }
2635
2636 NeighborCache->State = EfiNeighborStale;
2637 NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
2638 } else {
2639 Result = CompareMem (LinkLayerOption->EtherAddr, &NeighborCache->LinkAddress, 6);
2640
2641 //
2642 // If the link-local address is the same as that already in the cache,
2643 // the cache entry's state remains unchanged. Otherwise update the
2644 // reachability state to STALE.
2645 //
2646 if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
2647 CopyMem (&NeighborCache->LinkAddress, LinkLayerOption->EtherAddr, 6);
2648
2649 NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
2650
2651 if (NeighborCache->State == EfiNeighborInComplete) {
2652 //
2653 // Send queued packets if exist.
2654 //
2655 NeighborCache->State = EfiNeighborStale;
2656 NeighborCache->CallBack ((VOID *)NeighborCache);
2657 } else {
2658 NeighborCache->State = EfiNeighborStale;
2659 }
2660 }
2661 }
2662 }
2663
2664 if ((NeighborCache != NULL) && IsRouter) {
2665 //
2666 // The Target is a router, set IsRouter to TRUE.
2667 //
2668 NeighborCache->IsRouter = TRUE;
2669 }
2670
2671 Status = EFI_SUCCESS;
2672
2673Exit:
2674 NetbufFree (Packet);
2675 return Status;
2676}
2677
2678/**
2679 Add Neighbor cache entries. It is a work function for EfiIp6Neighbors().
2680
2681 @param[in] IpSb The IP6 service binding instance.
2682 @param[in] TargetIp6Address Pointer to Target IPv6 address.
2683 @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
2684 @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
2685 cache. It will be deleted after Timeout. A value of zero means that
2686 the entry is permanent. A non-zero value means that the entry is
2687 dynamic.
2688 @param[in] Override If TRUE, the cached link-layer address of the matching entry will
2689 be overridden and updated; if FALSE, and if a
2690 corresponding cache entry already existed, EFI_ACCESS_DENIED
2691 will be returned.
2692
2693 @retval EFI_SUCCESS The neighbor cache entry has been added.
2694 @retval EFI_OUT_OF_RESOURCES Could not add the entry to the neighbor cache
2695 due to insufficient resources.
2696 @retval EFI_NOT_FOUND TargetLinkAddress is NULL.
2697 @retval EFI_ACCESS_DENIED The to-be-added entry is already defined in the neighbor cache,
2698 and that entry is tagged as un-overridden (when DeleteFlag
2699 is FALSE).
2700
2701**/
2702EFI_STATUS
2703Ip6AddNeighbor (
2704 IN IP6_SERVICE *IpSb,
2705 IN EFI_IPv6_ADDRESS *TargetIp6Address,
2706 IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
2707 IN UINT32 Timeout,
2708 IN BOOLEAN Override
2709 )
2710{
2711 IP6_NEIGHBOR_ENTRY *Neighbor;
2712
2713 Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
2714 if (Neighbor != NULL) {
2715 if (!Override) {
2716 return EFI_ACCESS_DENIED;
2717 } else {
2718 if (TargetLinkAddress != NULL) {
2719 IP6_COPY_LINK_ADDRESS (&Neighbor->LinkAddress, TargetLinkAddress);
2720 }
2721 }
2722 } else {
2723 if (TargetLinkAddress == NULL) {
2724 return EFI_NOT_FOUND;
2725 }
2726
2727 Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, TargetLinkAddress);
2728 if (Neighbor == NULL) {
2729 return EFI_OUT_OF_RESOURCES;
2730 }
2731 }
2732
2733 Neighbor->State = EfiNeighborReachable;
2734
2735 if (Timeout != 0) {
2736 Neighbor->Ticks = IP6_GET_TICKS (Timeout / TICKS_PER_MS);
2737 Neighbor->Dynamic = TRUE;
2738 } else {
2739 Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
2740 }
2741
2742 return EFI_SUCCESS;
2743}
2744
2745/**
2746 Delete or update Neighbor cache entries. It is a work function for EfiIp6Neighbors().
2747
2748 @param[in] IpSb The IP6 service binding instance.
2749 @param[in] TargetIp6Address Pointer to Target IPv6 address.
2750 @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
2751 @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
2752 cache. It will be deleted after Timeout. A value of zero means that
2753 the entry is permanent. A non-zero value means that the entry is
2754 dynamic.
2755 @param[in] Override If TRUE, the cached link-layer address of the matching entry will
2756 be overridden and updated; if FALSE, and if a
2757 corresponding cache entry already existed, EFI_ACCESS_DENIED
2758 will be returned.
2759
2760 @retval EFI_SUCCESS The neighbor cache entry has been updated or deleted.
2761 @retval EFI_NOT_FOUND This entry is not in the neighbor cache.
2762
2763**/
2764EFI_STATUS
2765Ip6DelNeighbor (
2766 IN IP6_SERVICE *IpSb,
2767 IN EFI_IPv6_ADDRESS *TargetIp6Address,
2768 IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
2769 IN UINT32 Timeout,
2770 IN BOOLEAN Override
2771 )
2772{
2773 IP6_NEIGHBOR_ENTRY *Neighbor;
2774
2775 Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
2776 if (Neighbor == NULL) {
2777 return EFI_NOT_FOUND;
2778 }
2779
2780 RemoveEntryList (&Neighbor->Link);
2781 FreePool (Neighbor);
2782
2783 return EFI_SUCCESS;
2784}
2785
2786/**
2787 The heartbeat timer of ND module in IP6_TIMER_INTERVAL_IN_MS milliseconds.
2788 This time routine handles DAD module and neighbor state transition.
2789 It is also responsible for sending out router solicitations.
2790
2791 @param[in] Event The IP6 service instance's heartbeat timer.
2792 @param[in] Context The IP6 service instance.
2793
2794**/
2795VOID
2796EFIAPI
2797Ip6NdFasterTimerTicking (
2798 IN EFI_EVENT Event,
2799 IN VOID *Context
2800 )
2801{
2802 LIST_ENTRY *Entry;
2803 LIST_ENTRY *Next;
2804 LIST_ENTRY *Entry2;
2805 IP6_INTERFACE *IpIf;
2806 IP6_DELAY_JOIN_LIST *DelayNode;
2807 EFI_IPv6_ADDRESS Source;
2808 IP6_DAD_ENTRY *DupAddrDetect;
2809 EFI_STATUS Status;
2810 IP6_NEIGHBOR_ENTRY *NeighborCache;
2811 EFI_IPv6_ADDRESS Destination;
2812 IP6_SERVICE *IpSb;
2813 BOOLEAN Flag;
2814
2815 IpSb = (IP6_SERVICE *)Context;
2816 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
2817
2818 ZeroMem (&Source, sizeof (EFI_IPv6_ADDRESS));
2819
2820 //
2821 // A host SHOULD transmit up to MAX_RTR_SOLICITATIONS (3) Router
2822 // Solicitation messages, each separated by at least
2823 // RTR_SOLICITATION_INTERVAL (4) seconds.
2824 //
2825 if ((IpSb->Ip6ConfigInstance.Policy == Ip6ConfigPolicyAutomatic) &&
2826 !IpSb->RouterAdvertiseReceived &&
2827 (IpSb->SolicitTimer > 0)
2828 )
2829 {
2830 if ((IpSb->Ticks == 0) || (--IpSb->Ticks == 0)) {
2831 Status = Ip6SendRouterSolicit (IpSb, NULL, NULL, NULL, NULL);
2832 if (!EFI_ERROR (Status)) {
2833 IpSb->SolicitTimer--;
2834 IpSb->Ticks = (UINT32)IP6_GET_TICKS (IP6_RTR_SOLICITATION_INTERVAL);
2835 }
2836 }
2837 }
2838
2839 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
2840 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
2841
2842 //
2843 // Process the delay list to join the solicited-node multicast address.
2844 //
2845 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {
2846 DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);
2847 if ((DelayNode->DelayTime == 0) || (--DelayNode->DelayTime == 0)) {
2848 //
2849 // The timer expires, init the duplicate address detection.
2850 //
2851 Ip6InitDADProcess (
2852 DelayNode->Interface,
2853 DelayNode->AddressInfo,
2854 DelayNode->DadCallback,
2855 DelayNode->Context
2856 );
2857
2858 //
2859 // Remove the delay node
2860 //
2861 RemoveEntryList (&DelayNode->Link);
2862 FreePool (DelayNode);
2863 }
2864 }
2865
2866 //
2867 // Process the duplicate address detection list.
2868 //
2869 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {
2870 DupAddrDetect = NET_LIST_USER_STRUCT (Entry2, IP6_DAD_ENTRY, Link);
2871
2872 if ((DupAddrDetect->RetransTick == 0) || (--DupAddrDetect->RetransTick == 0)) {
2873 //
2874 // The timer expires, check the remaining transmit counts.
2875 //
2876 if (DupAddrDetect->Transmit < DupAddrDetect->MaxTransmit) {
2877 //
2878 // Send the Neighbor Solicitation message with
2879 // Source - unspecified address, destination - solicited-node multicast address
2880 // Target - the address to be validated
2881 //
2882 Status = Ip6SendNeighborSolicit (
2883 IpSb,
2884 NULL,
2885 &DupAddrDetect->Destination,
2886 &DupAddrDetect->AddressInfo->Address,
2887 NULL
2888 );
2889 if (EFI_ERROR (Status)) {
2890 return;
2891 }
2892
2893 DupAddrDetect->Transmit++;
2894 DupAddrDetect->RetransTick = IP6_GET_TICKS (IpSb->RetransTimer);
2895 } else {
2896 //
2897 // All required solicitation has been sent out, and the RetransTime after the last
2898 // Neighbor Solicit is elapsed, finish the DAD process.
2899 //
2900 Flag = FALSE;
2901 if ((DupAddrDetect->Receive == 0) ||
2902 (DupAddrDetect->Transmit <= DupAddrDetect->Receive))
2903 {
2904 Flag = TRUE;
2905 }
2906
2907 Ip6OnDADFinished (Flag, IpIf, DupAddrDetect);
2908 }
2909 }
2910 }
2911 }
2912
2913 //
2914 // Polling the state of Neighbor cache
2915 //
2916 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
2917 NeighborCache = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
2918
2919 switch (NeighborCache->State) {
2920 case EfiNeighborInComplete:
2921 if (NeighborCache->Ticks > 0) {
2922 --NeighborCache->Ticks;
2923 }
2924
2925 //
2926 // Retransmit Neighbor Solicitation messages approximately every
2927 // RetransTimer milliseconds while awaiting a response.
2928 //
2929 if (NeighborCache->Ticks == 0) {
2930 if (NeighborCache->Transmit > 1) {
2931 //
2932 // Send out multicast neighbor solicitation for address resolution.
2933 // After last neighbor solicitation message has been sent out, wait
2934 // for RetransTimer and then remove entry if no response is received.
2935 //
2936 Ip6CreateSNMulticastAddr (&NeighborCache->Neighbor, &Destination);
2937 Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
2938 if (EFI_ERROR (Status)) {
2939 return;
2940 }
2941
2942 Status = Ip6SendNeighborSolicit (
2943 IpSb,
2944 &Source,
2945 &Destination,
2946 &NeighborCache->Neighbor,
2947 &IpSb->SnpMode.CurrentAddress
2948 );
2949 if (EFI_ERROR (Status)) {
2950 return;
2951 }
2952 }
2953
2954 //
2955 // Update the retransmit times.
2956 //
2957 if (NeighborCache->Transmit > 0) {
2958 --NeighborCache->Transmit;
2959 NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
2960 }
2961 }
2962
2963 if (NeighborCache->Transmit == 0) {
2964 //
2965 // Timeout, send ICMP destination unreachable packet and then remove entry
2966 //
2967 Status = Ip6FreeNeighborEntry (
2968 IpSb,
2969 NeighborCache,
2970 TRUE,
2971 TRUE,
2972 EFI_ICMP_ERROR,
2973 NULL,
2974 NULL
2975 );
2976 if (EFI_ERROR (Status)) {
2977 return;
2978 }
2979 }
2980
2981 break;
2982
2983 case EfiNeighborReachable:
2984 //
2985 // This entry is inserted by EfiIp6Neighbors() as static entry
2986 // and will not timeout.
2987 //
2988 if (!NeighborCache->Dynamic && (NeighborCache->Ticks == IP6_INFINIT_LIFETIME)) {
2989 break;
2990 }
2991
2992 if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
2993 if (NeighborCache->Dynamic) {
2994 //
2995 // This entry is inserted by EfiIp6Neighbors() as dynamic entry
2996 // and will be deleted after timeout.
2997 //
2998 Status = Ip6FreeNeighborEntry (
2999 IpSb,
3000 NeighborCache,
3001 FALSE,
3002 TRUE,
3003 EFI_TIMEOUT,
3004 NULL,
3005 NULL
3006 );
3007 if (EFI_ERROR (Status)) {
3008 return;
3009 }
3010 } else {
3011 NeighborCache->State = EfiNeighborStale;
3012 NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
3013 }
3014 }
3015
3016 break;
3017
3018 case EfiNeighborDelay:
3019 if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
3020 NeighborCache->State = EfiNeighborProbe;
3021 NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
3022 NeighborCache->Transmit = IP6_MAX_UNICAST_SOLICIT + 1;
3023 //
3024 // Send out unicast neighbor solicitation for Neighbor Unreachability Detection
3025 //
3026 Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
3027 if (EFI_ERROR (Status)) {
3028 return;
3029 }
3030
3031 Status = Ip6SendNeighborSolicit (
3032 IpSb,
3033 &Source,
3034 &NeighborCache->Neighbor,
3035 &NeighborCache->Neighbor,
3036 &IpSb->SnpMode.CurrentAddress
3037 );
3038 if (EFI_ERROR (Status)) {
3039 return;
3040 }
3041
3042 NeighborCache->Transmit--;
3043 }
3044
3045 break;
3046
3047 case EfiNeighborProbe:
3048 if (NeighborCache->Ticks > 0) {
3049 --NeighborCache->Ticks;
3050 }
3051
3052 //
3053 // Retransmit Neighbor Solicitation messages approximately every
3054 // RetransTimer milliseconds while awaiting a response.
3055 //
3056 if (NeighborCache->Ticks == 0) {
3057 if (NeighborCache->Transmit > 1) {
3058 //
3059 // Send out unicast neighbor solicitation for Neighbor Unreachability
3060 // Detection. After last neighbor solicitation message has been sent out,
3061 // wait for RetransTimer and then remove entry if no response is received.
3062 //
3063 Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
3064 if (EFI_ERROR (Status)) {
3065 return;
3066 }
3067
3068 Status = Ip6SendNeighborSolicit (
3069 IpSb,
3070 &Source,
3071 &NeighborCache->Neighbor,
3072 &NeighborCache->Neighbor,
3073 &IpSb->SnpMode.CurrentAddress
3074 );
3075 if (EFI_ERROR (Status)) {
3076 return;
3077 }
3078 }
3079
3080 //
3081 // Update the retransmit times.
3082 //
3083 if (NeighborCache->Transmit > 0) {
3084 --NeighborCache->Transmit;
3085 NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
3086 }
3087 }
3088
3089 if (NeighborCache->Transmit == 0) {
3090 //
3091 // Delete the neighbor entry.
3092 //
3093 Status = Ip6FreeNeighborEntry (
3094 IpSb,
3095 NeighborCache,
3096 FALSE,
3097 TRUE,
3098 EFI_TIMEOUT,
3099 NULL,
3100 NULL
3101 );
3102 if (EFI_ERROR (Status)) {
3103 return;
3104 }
3105 }
3106
3107 break;
3108
3109 default:
3110 break;
3111 }
3112 }
3113}
3114
3115/**
3116 The heartbeat timer of ND module in 1 second. This time routine handles following
3117 things: 1) maintain default router list; 2) maintain prefix options;
3118 3) maintain route caches.
3119
3120 @param[in] IpSb The IP6 service binding instance.
3121
3122**/
3123VOID
3124Ip6NdTimerTicking (
3125 IN IP6_SERVICE *IpSb
3126 )
3127{
3128 LIST_ENTRY *Entry;
3129 LIST_ENTRY *Next;
3130 IP6_DEFAULT_ROUTER *DefaultRouter;
3131 IP6_PREFIX_LIST_ENTRY *PrefixOption;
3132 UINT8 Index;
3133 IP6_ROUTE_CACHE_ENTRY *RouteCache;
3134
3135 //
3136 // Decrease the lifetime of default router, if expires remove it from default router list.
3137 //
3138 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->DefaultRouterList) {
3139 DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
3140 if (DefaultRouter->Lifetime != IP6_INF_ROUTER_LIFETIME) {
3141 if ((DefaultRouter->Lifetime == 0) || (--DefaultRouter->Lifetime == 0)) {
3142 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
3143 }
3144 }
3145 }
3146
3147 //
3148 // Decrease Valid lifetime and Preferred lifetime of Prefix options and corresponding addresses.
3149 //
3150 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->AutonomousPrefix) {
3151 PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
3152 if (PrefixOption->ValidLifetime != (UINT32)IP6_INFINIT_LIFETIME) {
3153 if ((PrefixOption->ValidLifetime > 0) && (--PrefixOption->ValidLifetime > 0)) {
3154 if ((PrefixOption->PreferredLifetime != (UINT32)IP6_INFINIT_LIFETIME) &&
3155 (PrefixOption->PreferredLifetime > 0)
3156 )
3157 {
3158 --PrefixOption->PreferredLifetime;
3159 }
3160 } else {
3161 Ip6DestroyPrefixListEntry (IpSb, PrefixOption, FALSE, TRUE);
3162 }
3163 }
3164 }
3165
3166 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->OnlinkPrefix) {
3167 PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
3168 if (PrefixOption->ValidLifetime != (UINT32)IP6_INFINIT_LIFETIME) {
3169 if ((PrefixOption->ValidLifetime == 0) || (--PrefixOption->ValidLifetime == 0)) {
3170 Ip6DestroyPrefixListEntry (IpSb, PrefixOption, TRUE, TRUE);
3171 }
3172 }
3173 }
3174
3175 //
3176 // Each bucket of route cache can contain at most IP6_ROUTE_CACHE_MAX entries.
3177 // Remove the entries at the tail of the bucket. These entries
3178 // are likely to be used least.
3179 // Reclaim frequency is set to 1 second.
3180 //
3181 for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
3182 while (IpSb->RouteTable->Cache.CacheNum[Index] > IP6_ROUTE_CACHE_MAX) {
3183 Entry = NetListRemoveTail (&IpSb->RouteTable->Cache.CacheBucket[Index]);
3184 if (Entry == NULL) {
3185 break;
3186 }
3187
3188 RouteCache = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
3189 Ip6FreeRouteCacheEntry (RouteCache);
3190 ASSERT (IpSb->RouteTable->Cache.CacheNum[Index] > 0);
3191 IpSb->RouteTable->Cache.CacheNum[Index]--;
3192 }
3193 }
3194}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette