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