]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Ip6Dxe/Ip6Nd.c
NetworkPkg/Ip6Dxe: Improve Neightbor Discovery message validation.
[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 return PrefixList;
355 }
356 } else {
357 //
358 // Perform the longest prefix match. The list is already sorted with
359 // the longest length prefix put at the head of the list.
360 //
361 if (NetIp6IsNetEqual (&PrefixList->Prefix, Prefix, PrefixList->PrefixLength)) {
362 return PrefixList;
363 }
364 }
365 }
366
367 return NULL;
368 }
369
370 /**
371 Release the resource in the prefix list table, and destroy the list entry and
372 corresponding addresses or route entries.
373
374 @param[in] IpSb The pointer to the IP6_SERVICE instance.
375 @param[in] ListHead The list entry head of the prefix list table.
376
377 **/
378 VOID
379 Ip6CleanPrefixListTable (
380 IN IP6_SERVICE *IpSb,
381 IN LIST_ENTRY *ListHead
382 )
383 {
384 IP6_PREFIX_LIST_ENTRY *PrefixList;
385 BOOLEAN OnLink;
386
387 OnLink = (BOOLEAN) (ListHead == &IpSb->OnlinkPrefix);
388
389 while (!IsListEmpty (ListHead)) {
390 PrefixList = NET_LIST_HEAD (ListHead, IP6_PREFIX_LIST_ENTRY, Link);
391 Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
392 }
393 }
394
395 /**
396 Callback function when address resolution is finished. It will cancel
397 all the queued frames if the address resolution failed, or transmit them
398 if the request succeeded.
399
400 @param[in] Context The context of the callback, a pointer to IP6_NEIGHBOR_ENTRY.
401
402 **/
403 VOID
404 Ip6OnArpResolved (
405 IN VOID *Context
406 )
407 {
408 LIST_ENTRY *Entry;
409 LIST_ENTRY *Next;
410 IP6_NEIGHBOR_ENTRY *ArpQue;
411 IP6_SERVICE *IpSb;
412 IP6_LINK_TX_TOKEN *Token;
413 EFI_STATUS Status;
414 BOOLEAN Sent;
415
416 ArpQue = (IP6_NEIGHBOR_ENTRY *) Context;
417 if ((ArpQue == NULL) || (ArpQue->Interface == NULL)) {
418 return ;
419 }
420
421 IpSb = ArpQue->Interface->Service;
422 if ((IpSb == NULL) || (IpSb->Signature != IP6_SERVICE_SIGNATURE)) {
423 return ;
424 }
425
426 //
427 // ARP resolve failed for some reason. Release all the frame
428 // and ARP queue itself. Ip6FreeArpQue will call the frame's
429 // owner back.
430 //
431 if (NET_MAC_EQUAL (&ArpQue->LinkAddress, &mZeroMacAddress, IpSb->SnpMode.HwAddressSize)) {
432 Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, TRUE, EFI_NO_MAPPING, NULL, NULL);
433 return ;
434 }
435
436 //
437 // ARP resolve succeeded, Transmit all the frame.
438 //
439 Sent = FALSE;
440 NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
441 RemoveEntryList (Entry);
442
443 Token = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
444 IP6_COPY_LINK_ADDRESS (&Token->DstMac, &ArpQue->LinkAddress);
445
446 //
447 // Insert the tx token before transmitting it via MNP as the FrameSentDpc
448 // may be called before Mnp->Transmit returns which will remove this tx
449 // token from the SentFrames list. Remove it from the list if the returned
450 // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
451 // FrameSentDpc won't be queued.
452 //
453 InsertTailList (&ArpQue->Interface->SentFrames, &Token->Link);
454
455 Status = IpSb->Mnp->Transmit (IpSb->Mnp, &Token->MnpToken);
456 if (EFI_ERROR (Status)) {
457 RemoveEntryList (&Token->Link);
458 Token->CallBack (Token->Packet, Status, 0, Token->Context);
459
460 Ip6FreeLinkTxToken (Token);
461 continue;
462 } else {
463 Sent = TRUE;
464 }
465 }
466
467 //
468 // Free the ArpQue only but not the whole neighbor entry.
469 //
470 Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, FALSE, EFI_SUCCESS, NULL, NULL);
471
472 if (Sent && (ArpQue->State == EfiNeighborStale)) {
473 ArpQue->State = EfiNeighborDelay;
474 ArpQue->Ticks = (UINT32) IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME);
475 }
476 }
477
478 /**
479 Allocate and initialize an IP6 neighbor cache entry.
480
481 @param[in] IpSb The pointer to the IP6_SERVICE instance.
482 @param[in] CallBack The callback function to be called when
483 address resolution is finished.
484 @param[in] Ip6Address Points to the IPv6 address of the neighbor.
485 @param[in] LinkAddress Points to the MAC address of the neighbor.
486 Ignored if NULL.
487
488 @return NULL if failed to allocate memory for the neighbor cache entry.
489 Otherwise, point to the created neighbor cache entry.
490
491 **/
492 IP6_NEIGHBOR_ENTRY *
493 Ip6CreateNeighborEntry (
494 IN IP6_SERVICE *IpSb,
495 IN IP6_ARP_CALLBACK CallBack,
496 IN EFI_IPv6_ADDRESS *Ip6Address,
497 IN EFI_MAC_ADDRESS *LinkAddress OPTIONAL
498 )
499 {
500 IP6_NEIGHBOR_ENTRY *Entry;
501 IP6_DEFAULT_ROUTER *DefaultRouter;
502
503 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
504 ASSERT (Ip6Address!= NULL);
505
506 Entry = AllocateZeroPool (sizeof (IP6_NEIGHBOR_ENTRY));
507 if (Entry == NULL) {
508 return NULL;
509 }
510
511 Entry->RefCnt = 1;
512 Entry->IsRouter = FALSE;
513 Entry->ArpFree = FALSE;
514 Entry->Dynamic = FALSE;
515 Entry->State = EfiNeighborInComplete;
516 Entry->Transmit = IP6_MAX_MULTICAST_SOLICIT + 1;
517 Entry->CallBack = CallBack;
518 Entry->Interface = NULL;
519
520 InitializeListHead (&Entry->Frames);
521
522 IP6_COPY_ADDRESS (&Entry->Neighbor, Ip6Address);
523
524 if (LinkAddress != NULL) {
525 IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, LinkAddress);
526 } else {
527 IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, &mZeroMacAddress);
528 }
529
530 InsertHeadList (&IpSb->NeighborTable, &Entry->Link);
531
532 //
533 // If corresponding default router entry exists, establish the relationship.
534 //
535 DefaultRouter = Ip6FindDefaultRouter (IpSb, Ip6Address);
536 if (DefaultRouter != NULL) {
537 DefaultRouter->NeighborCache = Entry;
538 }
539
540 return Entry;
541 }
542
543 /**
544 Search a IP6 neighbor cache entry.
545
546 @param[in] IpSb The pointer to the IP6_SERVICE instance.
547 @param[in] Ip6Address Points to the IPv6 address of the neighbor.
548
549 @return NULL if it failed to find the matching neighbor cache entry.
550 Otherwise, point to the found neighbor cache entry.
551
552 **/
553 IP6_NEIGHBOR_ENTRY *
554 Ip6FindNeighborEntry (
555 IN IP6_SERVICE *IpSb,
556 IN EFI_IPv6_ADDRESS *Ip6Address
557 )
558 {
559 LIST_ENTRY *Entry;
560 LIST_ENTRY *Next;
561 IP6_NEIGHBOR_ENTRY *Neighbor;
562
563 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
564 ASSERT (Ip6Address != NULL);
565
566 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
567 Neighbor = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
568 if (EFI_IP6_EQUAL (Ip6Address, &Neighbor->Neighbor)) {
569 RemoveEntryList (Entry);
570 InsertHeadList (&IpSb->NeighborTable, Entry);
571
572 return Neighbor;
573 }
574 }
575
576 return NULL;
577 }
578
579 /**
580 Free a IP6 neighbor cache entry and remove all the frames on the address
581 resolution queue that pass the FrameToCancel. That is, either FrameToCancel
582 is NULL, or it returns true for the frame.
583
584 @param[in] IpSb The pointer to the IP6_SERVICE instance.
585 @param[in] NeighborCache The to be free neighbor cache entry.
586 @param[in] SendIcmpError If TRUE, send out ICMP error.
587 @param[in] FullFree If TRUE, remove the neighbor cache entry.
588 Otherwise remove the pending frames.
589 @param[in] IoStatus The status returned to the cancelled frames'
590 callback function.
591 @param[in] FrameToCancel Function to select which frame to cancel.
592 This is an optional parameter that may be NULL.
593 @param[in] Context Opaque parameter to the FrameToCancel.
594 Ignored if FrameToCancel is NULL.
595
596 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
597 @retval EFI_SUCCESS The operation finished successfully.
598
599 **/
600 EFI_STATUS
601 Ip6FreeNeighborEntry (
602 IN IP6_SERVICE *IpSb,
603 IN IP6_NEIGHBOR_ENTRY *NeighborCache,
604 IN BOOLEAN SendIcmpError,
605 IN BOOLEAN FullFree,
606 IN EFI_STATUS IoStatus,
607 IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
608 IN VOID *Context OPTIONAL
609 )
610 {
611 IP6_LINK_TX_TOKEN *TxToken;
612 LIST_ENTRY *Entry;
613 LIST_ENTRY *Next;
614 IP6_DEFAULT_ROUTER *DefaultRouter;
615
616 //
617 // If FrameToCancel fails, the token will not be released.
618 // To avoid the memory leak, stop this usage model.
619 //
620 if (FullFree && FrameToCancel != NULL) {
621 return EFI_INVALID_PARAMETER;
622 }
623
624 NET_LIST_FOR_EACH_SAFE (Entry, Next, &NeighborCache->Frames) {
625 TxToken = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
626
627 if (SendIcmpError && !IP6_IS_MULTICAST (&TxToken->Packet->Ip.Ip6->DestinationAddress)) {
628 Ip6SendIcmpError (
629 IpSb,
630 TxToken->Packet,
631 NULL,
632 &TxToken->Packet->Ip.Ip6->SourceAddress,
633 ICMP_V6_DEST_UNREACHABLE,
634 ICMP_V6_ADDR_UNREACHABLE,
635 NULL
636 );
637 }
638
639 if ((FrameToCancel == NULL) || FrameToCancel (TxToken, Context)) {
640 RemoveEntryList (Entry);
641 TxToken->CallBack (TxToken->Packet, IoStatus, 0, TxToken->Context);
642 Ip6FreeLinkTxToken (TxToken);
643 }
644 }
645
646 if (NeighborCache->ArpFree && IsListEmpty (&NeighborCache->Frames)) {
647 RemoveEntryList (&NeighborCache->ArpList);
648 NeighborCache->ArpFree = FALSE;
649 }
650
651 if (FullFree) {
652 if (NeighborCache->IsRouter) {
653 DefaultRouter = Ip6FindDefaultRouter (IpSb, &NeighborCache->Neighbor);
654 if (DefaultRouter != NULL) {
655 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
656 }
657 }
658
659 RemoveEntryList (&NeighborCache->Link);
660 FreePool (NeighborCache);
661 }
662
663 return EFI_SUCCESS;
664 }
665
666 /**
667 Allocate and initialize an IP6 default router entry.
668
669 @param[in] IpSb The pointer to the IP6_SERVICE instance.
670 @param[in] Ip6Address The IPv6 address of the default router.
671 @param[in] RouterLifetime The lifetime associated with the default
672 router, in units of seconds.
673
674 @return NULL if it failed to allocate memory for the default router node.
675 Otherwise, point to the created default router node.
676
677 **/
678 IP6_DEFAULT_ROUTER *
679 Ip6CreateDefaultRouter (
680 IN IP6_SERVICE *IpSb,
681 IN EFI_IPv6_ADDRESS *Ip6Address,
682 IN UINT16 RouterLifetime
683 )
684 {
685 IP6_DEFAULT_ROUTER *Entry;
686 IP6_ROUTE_ENTRY *RtEntry;
687
688 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
689 ASSERT (Ip6Address != NULL);
690
691 Entry = AllocatePool (sizeof (IP6_DEFAULT_ROUTER));
692 if (Entry == NULL) {
693 return NULL;
694 }
695
696 Entry->RefCnt = 1;
697 Entry->Lifetime = RouterLifetime;
698 Entry->NeighborCache = Ip6FindNeighborEntry (IpSb, Ip6Address);
699 IP6_COPY_ADDRESS (&Entry->Router, Ip6Address);
700
701 //
702 // Add a default route into route table with both Destination and PrefixLength set to zero.
703 //
704 RtEntry = Ip6CreateRouteEntry (NULL, 0, Ip6Address);
705 if (RtEntry == NULL) {
706 FreePool (Entry);
707 return NULL;
708 }
709
710 InsertHeadList (&IpSb->RouteTable->RouteArea[0], &RtEntry->Link);
711 IpSb->RouteTable->TotalNum++;
712
713 InsertTailList (&IpSb->DefaultRouterList, &Entry->Link);
714
715 return Entry;
716 }
717
718 /**
719 Destroy an IP6 default router entry.
720
721 @param[in] IpSb The pointer to the IP6_SERVICE instance.
722 @param[in] DefaultRouter The to be destroyed IP6_DEFAULT_ROUTER.
723
724 **/
725 VOID
726 Ip6DestroyDefaultRouter (
727 IN IP6_SERVICE *IpSb,
728 IN IP6_DEFAULT_ROUTER *DefaultRouter
729 )
730 {
731 EFI_STATUS Status;
732
733 RemoveEntryList (&DefaultRouter->Link);
734
735 //
736 // Update the Destination Cache - all entries using the time-out router as next-hop
737 // should perform next-hop determination again.
738 //
739 do {
740 Status = Ip6DelRoute (IpSb->RouteTable, NULL, 0, &DefaultRouter->Router);
741 } while (Status != EFI_NOT_FOUND);
742
743 FreePool (DefaultRouter);
744 }
745
746 /**
747 Clean an IP6 default router list.
748
749 @param[in] IpSb The pointer to the IP6_SERVICE instance.
750
751 **/
752 VOID
753 Ip6CleanDefaultRouterList (
754 IN IP6_SERVICE *IpSb
755 )
756 {
757 IP6_DEFAULT_ROUTER *DefaultRouter;
758
759 while (!IsListEmpty (&IpSb->DefaultRouterList)) {
760 DefaultRouter = NET_LIST_HEAD (&IpSb->DefaultRouterList, IP6_DEFAULT_ROUTER, Link);
761 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
762 }
763 }
764
765 /**
766 Search a default router node from an IP6 default router list.
767
768 @param[in] IpSb The pointer to the IP6_SERVICE instance.
769 @param[in] Ip6Address The IPv6 address of the to be searched default router node.
770
771 @return NULL if it failed to find the matching default router node.
772 Otherwise, point to the found default router node.
773
774 **/
775 IP6_DEFAULT_ROUTER *
776 Ip6FindDefaultRouter (
777 IN IP6_SERVICE *IpSb,
778 IN EFI_IPv6_ADDRESS *Ip6Address
779 )
780 {
781 LIST_ENTRY *Entry;
782 IP6_DEFAULT_ROUTER *DefaultRouter;
783
784 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
785 ASSERT (Ip6Address != NULL);
786
787 NET_LIST_FOR_EACH (Entry, &IpSb->DefaultRouterList) {
788 DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
789 if (EFI_IP6_EQUAL (Ip6Address, &DefaultRouter->Router)) {
790 return DefaultRouter;
791 }
792 }
793
794 return NULL;
795 }
796
797 /**
798 The function to be called after DAD (Duplicate Address Detection) is performed.
799
800 @param[in] IsDadPassed If TRUE, the DAD operation succeed. Otherwise, the DAD operation failed.
801 @param[in] IpIf Points to the IP6_INTERFACE.
802 @param[in] DadEntry The DAD entry which already performed DAD.
803
804 **/
805 VOID
806 Ip6OnDADFinished (
807 IN BOOLEAN IsDadPassed,
808 IN IP6_INTERFACE *IpIf,
809 IN IP6_DAD_ENTRY *DadEntry
810 )
811 {
812 IP6_SERVICE *IpSb;
813 IP6_ADDRESS_INFO *AddrInfo;
814 EFI_DHCP6_PROTOCOL *Dhcp6;
815 UINT16 OptBuf[4];
816 EFI_DHCP6_PACKET_OPTION *Oro;
817 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
818 EFI_IPv6_ADDRESS AllNodes;
819
820 IpSb = IpIf->Service;
821 AddrInfo = DadEntry->AddressInfo;
822
823 if (IsDadPassed) {
824 //
825 // DAD succeed.
826 //
827 if (NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
828 ASSERT (!IpSb->LinkLocalOk);
829
830 IP6_COPY_ADDRESS (&IpSb->LinkLocalAddr, &AddrInfo->Address);
831 IpSb->LinkLocalOk = TRUE;
832 IpIf->Configured = TRUE;
833
834 //
835 // Check whether DHCP6 need to be started.
836 //
837 Dhcp6 = IpSb->Ip6ConfigInstance.Dhcp6;
838
839 if (IpSb->Dhcp6NeedStart) {
840 Dhcp6->Start (Dhcp6);
841 IpSb->Dhcp6NeedStart = FALSE;
842 }
843
844 if (IpSb->Dhcp6NeedInfoRequest) {
845 //
846 // Set the exta options to send. Here we only want the option request option
847 // with DNS SERVERS.
848 //
849 Oro = (EFI_DHCP6_PACKET_OPTION *) OptBuf;
850 Oro->OpCode = HTONS (DHCP6_OPT_ORO);
851 Oro->OpLen = HTONS (2);
852 *((UINT16 *) &Oro->Data[0]) = HTONS (DHCP6_OPT_DNS_SERVERS);
853
854 InfoReqReXmit.Irt = 4;
855 InfoReqReXmit.Mrc = 64;
856 InfoReqReXmit.Mrt = 60;
857 InfoReqReXmit.Mrd = 0;
858
859 Dhcp6->InfoRequest (
860 Dhcp6,
861 TRUE,
862 Oro,
863 0,
864 NULL,
865 &InfoReqReXmit,
866 IpSb->Ip6ConfigInstance.Dhcp6Event,
867 Ip6ConfigOnDhcp6Reply,
868 &IpSb->Ip6ConfigInstance
869 );
870 }
871
872 //
873 // Add an on-link prefix for link-local address.
874 //
875 Ip6CreatePrefixListEntry (
876 IpSb,
877 TRUE,
878 (UINT32) IP6_INFINIT_LIFETIME,
879 (UINT32) IP6_INFINIT_LIFETIME,
880 IP6_LINK_LOCAL_PREFIX_LENGTH,
881 &IpSb->LinkLocalAddr
882 );
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 return DupAddrDetect;
1069 }
1070 }
1071 }
1072
1073 return NULL;
1074 }
1075
1076 /**
1077 Generate router solicit message and send it out to Destination Address or
1078 All Router Link Local scope multicast address.
1079
1080 @param[in] IpSb The IP service to send the packet.
1081 @param[in] Interface If not NULL, points to the IP6 interface to send
1082 the packet.
1083 @param[in] SourceAddress If not NULL, the source address of the message.
1084 @param[in] DestinationAddress If not NULL, the destination address of the message.
1085 @param[in] SourceLinkAddress If not NULL, the MAC address of the source.
1086 A source link-layer address option will be appended
1087 to the message.
1088
1089 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1090 operation.
1091 @retval EFI_SUCCESS The router solicit message was successfully sent.
1092
1093 **/
1094 EFI_STATUS
1095 Ip6SendRouterSolicit (
1096 IN IP6_SERVICE *IpSb,
1097 IN IP6_INTERFACE *Interface OPTIONAL,
1098 IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL,
1099 IN EFI_IPv6_ADDRESS *DestinationAddress OPTIONAL,
1100 IN EFI_MAC_ADDRESS *SourceLinkAddress OPTIONAL
1101 )
1102 {
1103 NET_BUF *Packet;
1104 EFI_IP6_HEADER Head;
1105 IP6_ICMP_INFORMATION_HEAD *IcmpHead;
1106 IP6_ETHER_ADDR_OPTION *LinkLayerOption;
1107 UINT16 PayloadLen;
1108 IP6_INTERFACE *IpIf;
1109
1110 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
1111
1112 IpIf = Interface;
1113 if (IpIf == NULL && IpSb->DefaultInterface != NULL) {
1114 IpIf = IpSb->DefaultInterface;
1115 }
1116
1117 //
1118 // Generate the packet to be sent
1119 //
1120
1121 PayloadLen = (UINT16) sizeof (IP6_ICMP_INFORMATION_HEAD);
1122 if (SourceLinkAddress != NULL) {
1123 PayloadLen += sizeof (IP6_ETHER_ADDR_OPTION);
1124 }
1125
1126 Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32) PayloadLen);
1127 if (Packet == NULL) {
1128 return EFI_OUT_OF_RESOURCES;
1129 }
1130
1131 //
1132 // Create the basic IPv6 header.
1133 //
1134 Head.FlowLabelL = 0;
1135 Head.FlowLabelH = 0;
1136 Head.PayloadLength = HTONS (PayloadLen);
1137 Head.NextHeader = IP6_ICMP;
1138 Head.HopLimit = IP6_HOP_LIMIT;
1139
1140 if (SourceAddress != NULL) {
1141 IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
1142 } else {
1143 ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
1144 }
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 //
1413 // Fill in the source link-layer address option
1414 //
1415 LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) NetbufAllocSpace (
1416 Packet,
1417 sizeof (IP6_ETHER_ADDR_OPTION),
1418 FALSE
1419 );
1420 ASSERT (LinkLayerOption != NULL);
1421 LinkLayerOption->Type = Ip6OptionEtherSource;
1422 LinkLayerOption->Length = 1;
1423 CopyMem (LinkLayerOption->EtherAddr, SourceLinkAddress, 6);
1424 }
1425
1426 //
1427 // Create a Neighbor Cache entry in the INCOMPLETE state when performing
1428 // address resolution.
1429 //
1430 if (!IsDAD && Ip6IsSNMulticastAddr (DestinationAddress)) {
1431 Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
1432 if (Neighbor == NULL) {
1433 Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, NULL);
1434 ASSERT (Neighbor != NULL);
1435 }
1436 }
1437
1438 //
1439 // Transmit the packet
1440 //
1441 return Ip6Output (IpSb, IpSb->DefaultInterface, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
1442 }
1443
1444 /**
1445 Process the Neighbor Solicitation message. The message may be sent for Duplicate
1446 Address Detection or Address Resolution.
1447
1448 @param[in] IpSb The IP service that received the packet.
1449 @param[in] Head The IP head of the message.
1450 @param[in] Packet The content of the message with IP head removed.
1451
1452 @retval EFI_SUCCESS The packet processed successfully.
1453 @retval EFI_INVALID_PARAMETER The packet is invalid.
1454 @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
1455 @retval Others Failed to process the packet.
1456
1457 **/
1458 EFI_STATUS
1459 Ip6ProcessNeighborSolicit (
1460 IN IP6_SERVICE *IpSb,
1461 IN EFI_IP6_HEADER *Head,
1462 IN NET_BUF *Packet
1463 )
1464 {
1465 IP6_ICMP_INFORMATION_HEAD Icmp;
1466 EFI_IPv6_ADDRESS Target;
1467 IP6_ETHER_ADDR_OPTION LinkLayerOption;
1468 BOOLEAN IsDAD;
1469 BOOLEAN IsUnicast;
1470 BOOLEAN IsMaintained;
1471 IP6_DAD_ENTRY *DupAddrDetect;
1472 IP6_INTERFACE *IpIf;
1473 IP6_NEIGHBOR_ENTRY *Neighbor;
1474 BOOLEAN Solicited;
1475 BOOLEAN UpdateCache;
1476 EFI_IPv6_ADDRESS Dest;
1477 UINT16 OptionLen;
1478 UINT8 *Option;
1479 BOOLEAN Provided;
1480 EFI_STATUS Status;
1481 VOID *MacAddress;
1482
1483 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
1484 NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
1485
1486 //
1487 // Perform Message Validation:
1488 // The IP Hop Limit field has a value of 255, i.e., the packet
1489 // could not possibly have been forwarded by a router.
1490 // ICMP Code is 0.
1491 // Target Address is not a multicast address.
1492 //
1493 Status = EFI_INVALID_PARAMETER;
1494
1495 if (Head->HopLimit != IP6_HOP_LIMIT || Icmp.Head.Code != 0 || !NetIp6IsValidUnicast (&Target)) {
1496 goto Exit;
1497 }
1498
1499 //
1500 // ICMP length is 24 or more octets.
1501 //
1502 OptionLen = 0;
1503 if (Head->PayloadLength < IP6_ND_LENGTH) {
1504 goto Exit;
1505 } else {
1506 OptionLen = (UINT16) (Head->PayloadLength - IP6_ND_LENGTH);
1507 if (OptionLen != 0) {
1508 Option = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
1509 ASSERT (Option != NULL);
1510
1511 //
1512 // All included options should have a length that is greater than zero.
1513 //
1514 if (!Ip6IsNDOptionValid (Option, OptionLen)) {
1515 goto Exit;
1516 }
1517 }
1518 }
1519
1520 IsDAD = NetIp6IsUnspecifiedAddr (&Head->SourceAddress);
1521 IsUnicast = (BOOLEAN) !Ip6IsSNMulticastAddr (&Head->DestinationAddress);
1522 IsMaintained = Ip6IsOneOfSetAddress (IpSb, &Target, &IpIf, NULL);
1523
1524 Provided = FALSE;
1525 if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
1526 NetbufCopy (
1527 Packet,
1528 IP6_ND_LENGTH,
1529 sizeof (IP6_ETHER_ADDR_OPTION),
1530 (UINT8 *) &LinkLayerOption
1531 );
1532 //
1533 // The solicitation for neighbor discovery should include a source link-layer
1534 // address option. If the option is not recognized, silently ignore it.
1535 //
1536 if (LinkLayerOption.Type == Ip6OptionEtherSource) {
1537 if (IsDAD) {
1538 //
1539 // If the IP source address is the unspecified address, the source
1540 // link-layer address option must not be included in the message.
1541 //
1542 goto Exit;
1543 }
1544
1545 Provided = TRUE;
1546 }
1547 }
1548
1549 //
1550 // If the IP source address is the unspecified address, the IP
1551 // destination address is a solicited-node multicast address.
1552 //
1553 if (IsDAD && IsUnicast) {
1554 goto Exit;
1555 }
1556
1557 //
1558 // If the target address is tentative, and the source address is a unicast address,
1559 // the solicitation's sender is performing address resolution on the target;
1560 // the solicitation should be silently ignored.
1561 //
1562 if (!IsDAD && !IsMaintained) {
1563 goto Exit;
1564 }
1565
1566 //
1567 // If received unicast neighbor solicitation but destination is not this node,
1568 // drop the packet.
1569 //
1570 if (IsUnicast && !IsMaintained) {
1571 goto Exit;
1572 }
1573
1574 //
1575 // In DAD, when target address is a tentative address,
1576 // process the received neighbor solicitation message but not send out response.
1577 //
1578 if (IsDAD && !IsMaintained) {
1579 DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
1580 if (DupAddrDetect != NULL) {
1581 //
1582 // Check the MAC address of the incoming packet.
1583 //
1584 if (IpSb->RecvRequest.MnpToken.Packet.RxData == NULL) {
1585 goto Exit;
1586 }
1587
1588 MacAddress = IpSb->RecvRequest.MnpToken.Packet.RxData->SourceAddress;
1589 if (MacAddress != NULL) {
1590 if (CompareMem (
1591 MacAddress,
1592 &IpSb->SnpMode.CurrentAddress,
1593 IpSb->SnpMode.HwAddressSize
1594 ) != 0) {
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 goto Exit;
1611 }
1612
1613 //
1614 // If the solicitation does not contain a link-layer address, DO NOT create or
1615 // update the neighbor cache entries.
1616 //
1617 if (Provided) {
1618 Neighbor = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
1619 UpdateCache = FALSE;
1620
1621 if (Neighbor == NULL) {
1622 Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, &Head->SourceAddress, NULL);
1623 if (Neighbor == NULL) {
1624 Status = EFI_OUT_OF_RESOURCES;
1625 goto Exit;
1626 }
1627 UpdateCache = TRUE;
1628 } else {
1629 if (CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6) != 0) {
1630 UpdateCache = TRUE;
1631 }
1632 }
1633
1634 if (UpdateCache) {
1635 Neighbor->State = EfiNeighborStale;
1636 Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
1637 CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
1638 //
1639 // Send queued packets if exist.
1640 //
1641 Neighbor->CallBack ((VOID *) Neighbor);
1642 }
1643 }
1644
1645 //
1646 // Sends a Neighbor Advertisement as response.
1647 // Set the Router flag to zero since the node is a host.
1648 // If the source address of the solicitation is unspecified, and target address
1649 // is one of the maintained address, reply a unsolicited multicast advertisement.
1650 //
1651 if (IsDAD && IsMaintained) {
1652 Solicited = FALSE;
1653 Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &Dest);
1654 } else {
1655 Solicited = TRUE;
1656 IP6_COPY_ADDRESS (&Dest, &Head->SourceAddress);
1657 }
1658
1659 Status = Ip6SendNeighborAdvertise (
1660 IpSb,
1661 &Target,
1662 &Dest,
1663 &Target,
1664 &IpSb->SnpMode.CurrentAddress,
1665 FALSE,
1666 TRUE,
1667 Solicited
1668 );
1669 Exit:
1670 NetbufFree (Packet);
1671 return Status;
1672 }
1673
1674 /**
1675 Process the Neighbor Advertisement message.
1676
1677 @param[in] IpSb The IP service that received the packet.
1678 @param[in] Head The IP head of the message.
1679 @param[in] Packet The content of the message with IP head removed.
1680
1681 @retval EFI_SUCCESS The packet processed successfully.
1682 @retval EFI_INVALID_PARAMETER The packet is invalid.
1683 @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
1684 @retval Others Failed to process the packet.
1685
1686 **/
1687 EFI_STATUS
1688 Ip6ProcessNeighborAdvertise (
1689 IN IP6_SERVICE *IpSb,
1690 IN EFI_IP6_HEADER *Head,
1691 IN NET_BUF *Packet
1692 )
1693 {
1694 IP6_ICMP_INFORMATION_HEAD Icmp;
1695 EFI_IPv6_ADDRESS Target;
1696 IP6_ETHER_ADDR_OPTION LinkLayerOption;
1697 BOOLEAN Provided;
1698 INTN Compare;
1699 IP6_NEIGHBOR_ENTRY *Neighbor;
1700 IP6_DEFAULT_ROUTER *DefaultRouter;
1701 BOOLEAN Solicited;
1702 BOOLEAN IsRouter;
1703 BOOLEAN Override;
1704 IP6_DAD_ENTRY *DupAddrDetect;
1705 IP6_INTERFACE *IpIf;
1706 UINT16 OptionLen;
1707 UINT8 *Option;
1708 EFI_STATUS Status;
1709
1710 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
1711 NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
1712
1713 //
1714 // Validate the incoming Neighbor Advertisement
1715 //
1716 Status = EFI_INVALID_PARAMETER;
1717 //
1718 // The IP Hop Limit field has a value of 255, i.e., the packet
1719 // could not possibly have been forwarded by a router.
1720 // ICMP Code is 0.
1721 // Target Address is not a multicast address.
1722 //
1723 if (Head->HopLimit != IP6_HOP_LIMIT || Icmp.Head.Code != 0 || !NetIp6IsValidUnicast (&Target)) {
1724 goto Exit;
1725 }
1726
1727 //
1728 // ICMP length is 24 or more octets.
1729 //
1730 Provided = FALSE;
1731 OptionLen = 0;
1732 if (Head->PayloadLength < IP6_ND_LENGTH) {
1733 goto Exit;
1734 } else {
1735 OptionLen = (UINT16) (Head->PayloadLength - IP6_ND_LENGTH);
1736 if (OptionLen != 0) {
1737 Option = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
1738 ASSERT (Option != NULL);
1739
1740 //
1741 // All included options should have a length that is greater than zero.
1742 //
1743 if (!Ip6IsNDOptionValid (Option, OptionLen)) {
1744 goto Exit;
1745 }
1746 }
1747 }
1748
1749 //
1750 // If the IP destination address is a multicast address, Solicited Flag is ZERO.
1751 //
1752 Solicited = FALSE;
1753 if ((Icmp.Fourth & IP6_SOLICITED_FLAG) == IP6_SOLICITED_FLAG) {
1754 Solicited = TRUE;
1755 }
1756 if (IP6_IS_MULTICAST (&Head->DestinationAddress) && Solicited) {
1757 goto Exit;
1758 }
1759
1760 //
1761 // DAD - Check whether the Target is one of our tentative address.
1762 //
1763 DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
1764 if (DupAddrDetect != NULL) {
1765 //
1766 // DAD fails, some other node is using this address.
1767 //
1768 NetbufFree (Packet);
1769 Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
1770 return EFI_ICMP_ERROR;
1771 }
1772
1773 //
1774 // Search the Neighbor Cache for the target's entry. If no entry exists,
1775 // the advertisement should be silently discarded.
1776 //
1777 Neighbor = Ip6FindNeighborEntry (IpSb, &Target);
1778 if (Neighbor == NULL) {
1779 goto Exit;
1780 }
1781
1782 //
1783 // Get IsRouter Flag and Override Flag
1784 //
1785 IsRouter = FALSE;
1786 Override = FALSE;
1787 if ((Icmp.Fourth & IP6_IS_ROUTER_FLAG) == IP6_IS_ROUTER_FLAG) {
1788 IsRouter = TRUE;
1789 }
1790 if ((Icmp.Fourth & IP6_OVERRIDE_FLAG) == IP6_OVERRIDE_FLAG) {
1791 Override = TRUE;
1792 }
1793
1794 //
1795 // Check whether link layer option is included.
1796 //
1797 if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
1798 NetbufCopy (
1799 Packet,
1800 IP6_ND_LENGTH,
1801 sizeof (IP6_ETHER_ADDR_OPTION),
1802 (UINT8 *) &LinkLayerOption
1803 );
1804
1805 if (LinkLayerOption.Type == Ip6OptionEtherTarget) {
1806 Provided = TRUE;
1807 }
1808 }
1809
1810 Compare = 0;
1811 if (Provided) {
1812 Compare = CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
1813 }
1814
1815 if (!Neighbor->IsRouter && IsRouter) {
1816 DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
1817 if (DefaultRouter != NULL) {
1818 DefaultRouter->NeighborCache = Neighbor;
1819 }
1820 }
1821
1822 if (Neighbor->State == EfiNeighborInComplete) {
1823 //
1824 // If the target's Neighbor Cache entry is in INCOMPLETE state and no
1825 // Target Link-Layer address option is included while link layer has
1826 // address, the message should be silently discarded.
1827 //
1828 if (!Provided) {
1829 goto Exit;
1830 }
1831 //
1832 // Update the Neighbor Cache
1833 //
1834 CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
1835 if (Solicited) {
1836 Neighbor->State = EfiNeighborReachable;
1837 Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
1838 } else {
1839 Neighbor->State = EfiNeighborStale;
1840 Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
1841 //
1842 // Send any packets queued for the neighbor awaiting address resolution.
1843 //
1844 Neighbor->CallBack ((VOID *) Neighbor);
1845 }
1846
1847 Neighbor->IsRouter = IsRouter;
1848
1849 } else {
1850 if (!Override && Compare != 0) {
1851 //
1852 // When the Override Flag is clear and supplied link-layer address differs from
1853 // that in the cache, if the state of the entry is not REACHABLE, ignore the
1854 // message. Otherwise set it to STALE but do not update the entry in any
1855 // other way.
1856 //
1857 if (Neighbor->State == EfiNeighborReachable) {
1858 Neighbor->State = EfiNeighborStale;
1859 Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
1860 }
1861 } else {
1862 if (Compare != 0) {
1863 CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
1864 }
1865 //
1866 // Update the entry's state
1867 //
1868 if (Solicited) {
1869 Neighbor->State = EfiNeighborReachable;
1870 Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
1871 } else {
1872 if (Compare != 0) {
1873 Neighbor->State = EfiNeighborStale;
1874 Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
1875 }
1876 }
1877
1878 //
1879 // When IsRouter is changed from TRUE to FALSE, remove the router from the
1880 // Default Router List and remove the Destination Cache entries for all destinations
1881 // using the neighbor as a router.
1882 //
1883 if (Neighbor->IsRouter && !IsRouter) {
1884 DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
1885 if (DefaultRouter != NULL) {
1886 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
1887 }
1888 }
1889
1890 Neighbor->IsRouter = IsRouter;
1891 }
1892 }
1893
1894 if (Neighbor->State == EfiNeighborReachable) {
1895 Neighbor->CallBack ((VOID *) Neighbor);
1896 }
1897
1898 Status = EFI_SUCCESS;
1899
1900 Exit:
1901 NetbufFree (Packet);
1902 return Status;
1903 }
1904
1905 /**
1906 Process the Router Advertisement message according to RFC4861.
1907
1908 @param[in] IpSb The IP service that received the packet.
1909 @param[in] Head The IP head of the message.
1910 @param[in] Packet The content of the message with the IP head removed.
1911
1912 @retval EFI_SUCCESS The packet processed successfully.
1913 @retval EFI_INVALID_PARAMETER The packet is invalid.
1914 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1915 operation.
1916 @retval Others Failed to process the packet.
1917
1918 **/
1919 EFI_STATUS
1920 Ip6ProcessRouterAdvertise (
1921 IN IP6_SERVICE *IpSb,
1922 IN EFI_IP6_HEADER *Head,
1923 IN NET_BUF *Packet
1924 )
1925 {
1926 IP6_ICMP_INFORMATION_HEAD Icmp;
1927 UINT32 ReachableTime;
1928 UINT32 RetransTimer;
1929 UINT16 RouterLifetime;
1930 UINT32 Offset;
1931 UINT8 Type;
1932 UINT8 Length;
1933 IP6_ETHER_ADDR_OPTION LinkLayerOption;
1934 UINT32 Fourth;
1935 UINT8 CurHopLimit;
1936 BOOLEAN Mflag;
1937 BOOLEAN Oflag;
1938 IP6_DEFAULT_ROUTER *DefaultRouter;
1939 IP6_NEIGHBOR_ENTRY *NeighborCache;
1940 EFI_MAC_ADDRESS LinkLayerAddress;
1941 IP6_MTU_OPTION MTUOption;
1942 IP6_PREFIX_INFO_OPTION PrefixOption;
1943 IP6_PREFIX_LIST_ENTRY *PrefixList;
1944 BOOLEAN OnLink;
1945 BOOLEAN Autonomous;
1946 EFI_IPv6_ADDRESS StatelessAddress;
1947 EFI_STATUS Status;
1948 UINT16 OptionLen;
1949 UINT8 *Option;
1950 INTN Result;
1951
1952 Status = EFI_INVALID_PARAMETER;
1953
1954 if (IpSb->Ip6ConfigInstance.Policy != Ip6ConfigPolicyAutomatic) {
1955 //
1956 // Skip the process below as it's not required under the current policy.
1957 //
1958 goto Exit;
1959 }
1960
1961 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
1962
1963 //
1964 // Validate the incoming Router Advertisement
1965 //
1966
1967 //
1968 // The IP source address must be a link-local address
1969 //
1970 if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
1971 goto Exit;
1972 }
1973 //
1974 // The IP Hop Limit field has a value of 255, i.e. the packet
1975 // could not possibly have been forwarded by a router.
1976 // ICMP Code is 0.
1977 // ICMP length (derived from the IP length) is 16 or more octets.
1978 //
1979 if (Head->HopLimit != IP6_HOP_LIMIT || Icmp.Head.Code != 0 ||
1980 Head->PayloadLength < IP6_RA_LENGTH) {
1981 goto Exit;
1982 }
1983
1984 //
1985 // All included options have a length that is greater than zero.
1986 //
1987 OptionLen = (UINT16) (Head->PayloadLength - IP6_RA_LENGTH);
1988 if (OptionLen != 0) {
1989 Option = NetbufGetByte (Packet, IP6_RA_LENGTH, NULL);
1990 ASSERT (Option != NULL);
1991
1992 if (!Ip6IsNDOptionValid (Option, OptionLen)) {
1993 goto Exit;
1994 }
1995 }
1996
1997 //
1998 // Process Fourth field.
1999 // In Router Advertisement, Fourth is composed of CurHopLimit (8bit), M flag, O flag,
2000 // and Router Lifetime (16 bit).
2001 //
2002
2003 Fourth = NTOHL (Icmp.Fourth);
2004 CopyMem (&RouterLifetime, &Fourth, sizeof (UINT16));
2005
2006 //
2007 // If the source address already in the default router list, update it.
2008 // Otherwise create a new entry.
2009 // A Lifetime of zero indicates that the router is not a default router.
2010 //
2011 DefaultRouter = Ip6FindDefaultRouter (IpSb, &Head->SourceAddress);
2012 if (DefaultRouter == NULL) {
2013 if (RouterLifetime != 0) {
2014 DefaultRouter = Ip6CreateDefaultRouter (IpSb, &Head->SourceAddress, RouterLifetime);
2015 if (DefaultRouter == NULL) {
2016 Status = EFI_OUT_OF_RESOURCES;
2017 goto Exit;
2018 }
2019 }
2020 } else {
2021 if (RouterLifetime != 0) {
2022 DefaultRouter->Lifetime = RouterLifetime;
2023 //
2024 // Check the corresponding neighbor cache entry here.
2025 //
2026 if (DefaultRouter->NeighborCache == NULL) {
2027 DefaultRouter->NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
2028 }
2029 } else {
2030 //
2031 // If the address is in the host's default router list and the router lifetime is zero,
2032 // immediately time-out the entry.
2033 //
2034 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
2035 }
2036 }
2037
2038 CurHopLimit = *((UINT8 *) &Fourth + 3);
2039 if (CurHopLimit != 0) {
2040 IpSb->CurHopLimit = CurHopLimit;
2041 }
2042
2043 Mflag = FALSE;
2044 Oflag = FALSE;
2045 if ((*((UINT8 *) &Fourth + 2) & IP6_M_ADDR_CONFIG_FLAG) == IP6_M_ADDR_CONFIG_FLAG) {
2046 Mflag = TRUE;
2047 } else {
2048 if ((*((UINT8 *) &Fourth + 2) & IP6_O_CONFIG_FLAG) == IP6_O_CONFIG_FLAG) {
2049 Oflag = TRUE;
2050 }
2051 }
2052
2053 if (Mflag || Oflag) {
2054 //
2055 // Use Ip6Config to get available addresses or other configuration from DHCP.
2056 //
2057 Ip6ConfigStartStatefulAutoConfig (&IpSb->Ip6ConfigInstance, Oflag);
2058 }
2059
2060 //
2061 // Process Reachable Time and Retrans Timer fields.
2062 //
2063 NetbufCopy (Packet, sizeof (Icmp), sizeof (UINT32), (UINT8 *) &ReachableTime);
2064 NetbufCopy (Packet, sizeof (Icmp) + sizeof (UINT32), sizeof (UINT32), (UINT8 *) &RetransTimer);
2065 ReachableTime = NTOHL (ReachableTime);
2066 RetransTimer = NTOHL (RetransTimer);
2067
2068 if (ReachableTime != 0 && ReachableTime != IpSb->BaseReachableTime) {
2069 //
2070 // If new value is not unspecified and differs from the previous one, record it
2071 // in BaseReachableTime and recompute a ReachableTime.
2072 //
2073 IpSb->BaseReachableTime = ReachableTime;
2074 Ip6UpdateReachableTime (IpSb);
2075 }
2076
2077 if (RetransTimer != 0) {
2078 IpSb->RetransTimer = RetransTimer;
2079 }
2080
2081 //
2082 // IsRouter flag must be set to TRUE if corresponding neighbor cache entry exists.
2083 //
2084 NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
2085 if (NeighborCache != NULL) {
2086 NeighborCache->IsRouter = TRUE;
2087 }
2088
2089 //
2090 // If an valid router advertisement is received, stops router solicitation.
2091 //
2092 IpSb->RouterAdvertiseReceived = TRUE;
2093
2094 //
2095 // The only defined options that may appear are the Source
2096 // Link-Layer Address, Prefix information and MTU options.
2097 // All included options have a length that is greater than zero and
2098 // fit within the input packet.
2099 //
2100 Offset = 16;
2101 while (Offset < (UINT32) Head->PayloadLength) {
2102 NetbufCopy (Packet, Offset, sizeof (UINT8), &Type);
2103 switch (Type) {
2104 case Ip6OptionEtherSource:
2105 //
2106 // Update the neighbor cache
2107 //
2108 NetbufCopy (Packet, Offset, sizeof (IP6_ETHER_ADDR_OPTION), (UINT8 *) &LinkLayerOption);
2109
2110 //
2111 // Option size validity ensured by Ip6IsNDOptionValid().
2112 //
2113 ASSERT (LinkLayerOption.Length != 0);
2114 ASSERT (Offset + (UINT32) LinkLayerOption.Length * 8 >= (UINT32) Head->PayloadLength);
2115
2116 ZeroMem (&LinkLayerAddress, sizeof (EFI_MAC_ADDRESS));
2117 CopyMem (&LinkLayerAddress, LinkLayerOption.EtherAddr, 6);
2118
2119 if (NeighborCache == NULL) {
2120 NeighborCache = Ip6CreateNeighborEntry (
2121 IpSb,
2122 Ip6OnArpResolved,
2123 &Head->SourceAddress,
2124 &LinkLayerAddress
2125 );
2126 if (NeighborCache == NULL) {
2127 Status = EFI_OUT_OF_RESOURCES;
2128 goto Exit;
2129 }
2130 NeighborCache->IsRouter = TRUE;
2131 NeighborCache->State = EfiNeighborStale;
2132 NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
2133 } else {
2134 Result = CompareMem (&LinkLayerAddress, &NeighborCache->LinkAddress, 6);
2135
2136 //
2137 // If the link-local address is the same as that already in the cache,
2138 // the cache entry's state remains unchanged. Otherwise update the
2139 // reachability state to STALE.
2140 //
2141 if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
2142 CopyMem (&NeighborCache->LinkAddress, &LinkLayerAddress, 6);
2143
2144 NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
2145
2146 if (NeighborCache->State == EfiNeighborInComplete) {
2147 //
2148 // Send queued packets if exist.
2149 //
2150 NeighborCache->State = EfiNeighborStale;
2151 NeighborCache->CallBack ((VOID *) NeighborCache);
2152 } else {
2153 NeighborCache->State = EfiNeighborStale;
2154 }
2155 }
2156 }
2157
2158 Offset += (UINT32) LinkLayerOption.Length * 8;
2159 break;
2160 case Ip6OptionPrefixInfo:
2161 NetbufCopy (Packet, Offset, sizeof (IP6_PREFIX_INFO_OPTION), (UINT8 *) &PrefixOption);
2162
2163 //
2164 // Option size validity ensured by Ip6IsNDOptionValid().
2165 //
2166 ASSERT (PrefixOption.Length == 4);
2167 ASSERT (Offset + (UINT32) PrefixOption.Length * 8 >= (UINT32) Head->PayloadLength);
2168
2169 PrefixOption.ValidLifetime = NTOHL (PrefixOption.ValidLifetime);
2170 PrefixOption.PreferredLifetime = NTOHL (PrefixOption.PreferredLifetime);
2171
2172 //
2173 // Get L and A flag, recorded in the lower 2 bits of Reserved1
2174 //
2175 OnLink = FALSE;
2176 if ((PrefixOption.Reserved1 & IP6_ON_LINK_FLAG) == IP6_ON_LINK_FLAG) {
2177 OnLink = TRUE;
2178 }
2179 Autonomous = FALSE;
2180 if ((PrefixOption.Reserved1 & IP6_AUTO_CONFIG_FLAG) == IP6_AUTO_CONFIG_FLAG) {
2181 Autonomous = TRUE;
2182 }
2183
2184 //
2185 // If the prefix is the link-local prefix, silently ignore the prefix option.
2186 //
2187 if (PrefixOption.PrefixLength == IP6_LINK_LOCAL_PREFIX_LENGTH &&
2188 NetIp6IsLinkLocalAddr (&PrefixOption.Prefix)
2189 ) {
2190 Offset += sizeof (IP6_PREFIX_INFO_OPTION);
2191 break;
2192 }
2193 //
2194 // Do following if on-link flag is set according to RFC4861.
2195 //
2196 if (OnLink) {
2197 PrefixList = Ip6FindPrefixListEntry (
2198 IpSb,
2199 TRUE,
2200 PrefixOption.PrefixLength,
2201 &PrefixOption.Prefix
2202 );
2203 //
2204 // Create a new entry for the prefix, if the ValidLifetime is zero,
2205 // silently ignore the prefix option.
2206 //
2207 if (PrefixList == NULL && PrefixOption.ValidLifetime != 0) {
2208 PrefixList = Ip6CreatePrefixListEntry (
2209 IpSb,
2210 TRUE,
2211 PrefixOption.ValidLifetime,
2212 PrefixOption.PreferredLifetime,
2213 PrefixOption.PrefixLength,
2214 &PrefixOption.Prefix
2215 );
2216 if (PrefixList == NULL) {
2217 Status = EFI_OUT_OF_RESOURCES;
2218 goto Exit;
2219 }
2220 } else if (PrefixList != NULL) {
2221 if (PrefixOption.ValidLifetime != 0) {
2222 PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
2223 } else {
2224 //
2225 // If the prefix exists and incoming ValidLifetime is zero, immediately
2226 // remove the prefix.
2227 Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
2228 }
2229 }
2230 }
2231
2232 //
2233 // Do following if Autonomous flag is set according to RFC4862.
2234 //
2235 if (Autonomous && PrefixOption.PreferredLifetime <= PrefixOption.ValidLifetime) {
2236 PrefixList = Ip6FindPrefixListEntry (
2237 IpSb,
2238 FALSE,
2239 PrefixOption.PrefixLength,
2240 &PrefixOption.Prefix
2241 );
2242 //
2243 // Create a new entry for the prefix, and form an address by prefix + interface id
2244 // If the sum of the prefix length and interface identifier length
2245 // does not equal 128 bits, the Prefix Information option MUST be ignored.
2246 //
2247 if (PrefixList == NULL &&
2248 PrefixOption.ValidLifetime != 0 &&
2249 PrefixOption.PrefixLength + IpSb->InterfaceIdLen * 8 == 128
2250 ) {
2251 //
2252 // Form the address in network order.
2253 //
2254 CopyMem (&StatelessAddress, &PrefixOption.Prefix, sizeof (UINT64));
2255 CopyMem (&StatelessAddress.Addr[8], IpSb->InterfaceId, sizeof (UINT64));
2256
2257 //
2258 // If the address is not yet in the assigned address list, adds it into.
2259 //
2260 if (!Ip6IsOneOfSetAddress (IpSb, &StatelessAddress, NULL, NULL)) {
2261 //
2262 // And also not in the DAD process, check its uniqueness firstly.
2263 //
2264 if (Ip6FindDADEntry (IpSb, &StatelessAddress, NULL) == NULL) {
2265 Status = Ip6SetAddress (
2266 IpSb->DefaultInterface,
2267 &StatelessAddress,
2268 FALSE,
2269 PrefixOption.PrefixLength,
2270 PrefixOption.ValidLifetime,
2271 PrefixOption.PreferredLifetime,
2272 NULL,
2273 NULL
2274 );
2275 if (EFI_ERROR (Status)) {
2276 goto Exit;
2277 }
2278 }
2279 }
2280
2281 //
2282 // Adds the prefix option to stateless prefix option list.
2283 //
2284 PrefixList = Ip6CreatePrefixListEntry (
2285 IpSb,
2286 FALSE,
2287 PrefixOption.ValidLifetime,
2288 PrefixOption.PreferredLifetime,
2289 PrefixOption.PrefixLength,
2290 &PrefixOption.Prefix
2291 );
2292 if (PrefixList == NULL) {
2293 Status = EFI_OUT_OF_RESOURCES;
2294 goto Exit;
2295 }
2296 } else if (PrefixList != NULL) {
2297
2298 //
2299 // Reset the preferred lifetime of the address if the advertised prefix exists.
2300 // Perform specific action to valid lifetime together.
2301 //
2302 PrefixList->PreferredLifetime = PrefixOption.PreferredLifetime;
2303 if ((PrefixOption.ValidLifetime > 7200) ||
2304 (PrefixOption.ValidLifetime > PrefixList->ValidLifetime)) {
2305 //
2306 // If the received Valid Lifetime is greater than 2 hours or
2307 // greater than RemainingLifetime, set the valid lifetime of the
2308 // corresponding address to the advertised Valid Lifetime.
2309 //
2310 PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
2311
2312 } else if (PrefixList->ValidLifetime <= 7200) {
2313 //
2314 // If RemainingLifetime is less than or equals to 2 hours, ignore the
2315 // Prefix Information option with regards to the valid lifetime.
2316 // TODO: If this option has been authenticated, set the valid lifetime.
2317 //
2318 } else {
2319 //
2320 // Otherwise, reset the valid lifetime of the corresponding
2321 // address to 2 hours.
2322 //
2323 PrefixList->ValidLifetime = 7200;
2324 }
2325 }
2326 }
2327
2328 Offset += sizeof (IP6_PREFIX_INFO_OPTION);
2329 break;
2330 case Ip6OptionMtu:
2331 NetbufCopy (Packet, Offset, sizeof (IP6_MTU_OPTION), (UINT8 *) &MTUOption);
2332
2333 //
2334 // Option size validity ensured by Ip6IsNDOptionValid().
2335 //
2336 ASSERT (MTUOption.Length == 1);
2337 ASSERT (Offset + (UINT32) MTUOption.Length * 8 >= (UINT32) Head->PayloadLength);
2338
2339 //
2340 // Use IPv6 minimum link MTU 1280 bytes as the maximum packet size in order
2341 // to omit implementation of Path MTU Discovery. Thus ignore the MTU option
2342 // in Router Advertisement.
2343 //
2344
2345 Offset += sizeof (IP6_MTU_OPTION);
2346 break;
2347 default:
2348 //
2349 // Silently ignore unrecognized options
2350 //
2351 NetbufCopy (Packet, Offset + sizeof (UINT8), sizeof (UINT8), &Length);
2352
2353 ASSERT (Length != 0);
2354
2355 Offset += (UINT32) Length * 8;
2356 break;
2357 }
2358 }
2359
2360 Status = EFI_SUCCESS;
2361
2362 Exit:
2363 NetbufFree (Packet);
2364 return Status;
2365 }
2366
2367 /**
2368 Process the ICMPv6 redirect message. Find the instance, then update
2369 its route cache.
2370
2371 @param[in] IpSb The IP6 service binding instance that received
2372 the packet.
2373 @param[in] Head The IP head of the received ICMPv6 packet.
2374 @param[in] Packet The content of the ICMPv6 redirect packet with
2375 the IP head removed.
2376
2377 @retval EFI_INVALID_PARAMETER The parameter is invalid.
2378 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
2379 operation.
2380 @retval EFI_SUCCESS Successfully updated the route caches.
2381
2382 **/
2383 EFI_STATUS
2384 Ip6ProcessRedirect (
2385 IN IP6_SERVICE *IpSb,
2386 IN EFI_IP6_HEADER *Head,
2387 IN NET_BUF *Packet
2388 )
2389 {
2390 IP6_ICMP_INFORMATION_HEAD *Icmp;
2391 EFI_IPv6_ADDRESS *Target;
2392 EFI_IPv6_ADDRESS *IcmpDest;
2393 UINT8 *Option;
2394 UINT16 OptionLen;
2395 IP6_ROUTE_ENTRY *RouteEntry;
2396 IP6_ROUTE_CACHE_ENTRY *RouteCache;
2397 IP6_NEIGHBOR_ENTRY *NeighborCache;
2398 INT32 Length;
2399 UINT8 OptLen;
2400 IP6_ETHER_ADDR_OPTION *LinkLayerOption;
2401 EFI_MAC_ADDRESS Mac;
2402 UINT32 Index;
2403 BOOLEAN IsRouter;
2404 EFI_STATUS Status;
2405 INTN Result;
2406
2407 Status = EFI_INVALID_PARAMETER;
2408
2409 Icmp = (IP6_ICMP_INFORMATION_HEAD *) NetbufGetByte (Packet, 0, NULL);
2410 if (Icmp == NULL) {
2411 goto Exit;
2412 }
2413
2414 //
2415 // Validate the incoming Redirect message
2416 //
2417
2418 //
2419 // The IP Hop Limit field has a value of 255, i.e. the packet
2420 // could not possibly have been forwarded by a router.
2421 // ICMP Code is 0.
2422 // ICMP length (derived from the IP length) is 40 or more octets.
2423 //
2424 if (Head->HopLimit != IP6_HOP_LIMIT || Icmp->Head.Code != 0 ||
2425 Head->PayloadLength < IP6_REDITECT_LENGTH) {
2426 goto Exit;
2427 }
2428
2429 //
2430 // The IP source address must be a link-local address
2431 //
2432 if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
2433 goto Exit;
2434 }
2435
2436 //
2437 // The dest of this ICMP redirect message is not us.
2438 //
2439 if (!Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) {
2440 goto Exit;
2441 }
2442
2443 //
2444 // All included options have a length that is greater than zero.
2445 //
2446 OptionLen = (UINT16) (Head->PayloadLength - IP6_REDITECT_LENGTH);
2447 if (OptionLen != 0) {
2448 Option = NetbufGetByte (Packet, IP6_REDITECT_LENGTH, NULL);
2449 ASSERT (Option != NULL);
2450
2451 if (!Ip6IsNDOptionValid (Option, OptionLen)) {
2452 goto Exit;
2453 }
2454 }
2455
2456 Target = (EFI_IPv6_ADDRESS *) (Icmp + 1);
2457 IcmpDest = Target + 1;
2458
2459 //
2460 // The ICMP Destination Address field in the redirect message does not contain
2461 // a multicast address.
2462 //
2463 if (IP6_IS_MULTICAST (IcmpDest)) {
2464 goto Exit;
2465 }
2466
2467 //
2468 // The ICMP Target Address is either a link-local address (when redirected to
2469 // a router) or the same as the ICMP Destination Address (when redirected to
2470 // the on-link destination).
2471 //
2472 IsRouter = (BOOLEAN) !EFI_IP6_EQUAL (Target, IcmpDest);
2473 if (!NetIp6IsLinkLocalAddr (Target) && IsRouter) {
2474 goto Exit;
2475 }
2476
2477 //
2478 // Check the options. The only interested option here is the target-link layer
2479 // address option.
2480 //
2481 Length = Packet->TotalSize - 40;
2482 Option = (UINT8 *) (IcmpDest + 1);
2483 LinkLayerOption = NULL;
2484 while (Length > 0) {
2485 switch (*Option) {
2486 case Ip6OptionEtherTarget:
2487
2488 LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) Option;
2489 OptLen = LinkLayerOption->Length;
2490 if (OptLen != 1) {
2491 //
2492 // For ethernet, the length must be 1.
2493 //
2494 goto Exit;
2495 }
2496 break;
2497
2498 default:
2499
2500 OptLen = *(Option + 1);
2501 if (OptLen == 0) {
2502 //
2503 // A length of 0 is invalid.
2504 //
2505 goto Exit;
2506 }
2507 break;
2508 }
2509
2510 Length -= 8 * OptLen;
2511 Option += 8 * OptLen;
2512 }
2513
2514 if (Length != 0) {
2515 goto Exit;
2516 }
2517
2518 //
2519 // The IP source address of the Redirect is the same as the current
2520 // first-hop router for the specified ICMP Destination Address.
2521 //
2522 RouteCache = Ip6FindRouteCache (IpSb->RouteTable, IcmpDest, &Head->DestinationAddress);
2523 if (RouteCache != NULL) {
2524 if (!EFI_IP6_EQUAL (&RouteCache->NextHop, &Head->SourceAddress)) {
2525 //
2526 // The source of this Redirect message must match the NextHop of the
2527 // corresponding route cache entry.
2528 //
2529 goto Exit;
2530 }
2531
2532 //
2533 // Update the NextHop.
2534 //
2535 IP6_COPY_ADDRESS (&RouteCache->NextHop, Target);
2536
2537 if (!IsRouter) {
2538 RouteEntry = (IP6_ROUTE_ENTRY *) RouteCache->Tag;
2539 RouteEntry->Flag = RouteEntry->Flag | IP6_DIRECT_ROUTE;
2540 }
2541
2542 } else {
2543 //
2544 // Get the Route Entry.
2545 //
2546 RouteEntry = Ip6FindRouteEntry (IpSb->RouteTable, IcmpDest, NULL);
2547 if (RouteEntry == NULL) {
2548 RouteEntry = Ip6CreateRouteEntry (IcmpDest, 0, NULL);
2549 if (RouteEntry == NULL) {
2550 Status = EFI_OUT_OF_RESOURCES;
2551 goto Exit;
2552 }
2553 }
2554
2555 if (!IsRouter) {
2556 RouteEntry->Flag = IP6_DIRECT_ROUTE;
2557 }
2558
2559 //
2560 // Create a route cache for this.
2561 //
2562 RouteCache = Ip6CreateRouteCacheEntry (
2563 IcmpDest,
2564 &Head->DestinationAddress,
2565 Target,
2566 (UINTN) RouteEntry
2567 );
2568 if (RouteCache == NULL) {
2569 Status = EFI_OUT_OF_RESOURCES;
2570 goto Exit;
2571 }
2572
2573 //
2574 // Insert the newly created route cache entry.
2575 //
2576 Index = IP6_ROUTE_CACHE_HASH (IcmpDest, &Head->DestinationAddress);
2577 InsertHeadList (&IpSb->RouteTable->Cache.CacheBucket[Index], &RouteCache->Link);
2578 }
2579
2580 //
2581 // Try to locate the neighbor cache for the Target.
2582 //
2583 NeighborCache = Ip6FindNeighborEntry (IpSb, Target);
2584
2585 if (LinkLayerOption != NULL) {
2586 if (NeighborCache == NULL) {
2587 //
2588 // Create a neighbor cache for the Target.
2589 //
2590 ZeroMem (&Mac, sizeof (EFI_MAC_ADDRESS));
2591 CopyMem (&Mac, LinkLayerOption->EtherAddr, 6);
2592 NeighborCache = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, Target, &Mac);
2593 if (NeighborCache == NULL) {
2594 //
2595 // Just report a success here. The neighbor cache can be created in
2596 // some other place.
2597 //
2598 Status = EFI_SUCCESS;
2599 goto Exit;
2600 }
2601
2602 NeighborCache->State = EfiNeighborStale;
2603 NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
2604 } else {
2605 Result = CompareMem (LinkLayerOption->EtherAddr, &NeighborCache->LinkAddress, 6);
2606
2607 //
2608 // If the link-local address is the same as that already in the cache,
2609 // the cache entry's state remains unchanged. Otherwise update the
2610 // reachability state to STALE.
2611 //
2612 if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
2613 CopyMem (&NeighborCache->LinkAddress, LinkLayerOption->EtherAddr, 6);
2614
2615 NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
2616
2617 if (NeighborCache->State == EfiNeighborInComplete) {
2618 //
2619 // Send queued packets if exist.
2620 //
2621 NeighborCache->State = EfiNeighborStale;
2622 NeighborCache->CallBack ((VOID *) NeighborCache);
2623 } else {
2624 NeighborCache->State = EfiNeighborStale;
2625 }
2626 }
2627 }
2628 }
2629
2630 if (NeighborCache != NULL && IsRouter) {
2631 //
2632 // The Target is a router, set IsRouter to TRUE.
2633 //
2634 NeighborCache->IsRouter = TRUE;
2635 }
2636
2637 Status = EFI_SUCCESS;
2638
2639 Exit:
2640 NetbufFree (Packet);
2641 return Status;
2642 }
2643
2644 /**
2645 Add Neighbor cache entries. It is a work function for EfiIp6Neighbors().
2646
2647 @param[in] IpSb The IP6 service binding instance.
2648 @param[in] TargetIp6Address Pointer to Target IPv6 address.
2649 @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
2650 @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
2651 cache. It will be deleted after Timeout. A value of zero means that
2652 the entry is permanent. A non-zero value means that the entry is
2653 dynamic.
2654 @param[in] Override If TRUE, the cached link-layer address of the matching entry will
2655 be overridden and updated; if FALSE, and if a
2656 corresponding cache entry already existed, EFI_ACCESS_DENIED
2657 will be returned.
2658
2659 @retval EFI_SUCCESS The neighbor cache entry has been added.
2660 @retval EFI_OUT_OF_RESOURCES Could not add the entry to the neighbor cache
2661 due to insufficient resources.
2662 @retval EFI_NOT_FOUND TargetLinkAddress is NULL.
2663 @retval EFI_ACCESS_DENIED The to-be-added entry is already defined in the neighbor cache,
2664 and that entry is tagged as un-overridden (when DeleteFlag
2665 is FALSE).
2666
2667 **/
2668 EFI_STATUS
2669 Ip6AddNeighbor (
2670 IN IP6_SERVICE *IpSb,
2671 IN EFI_IPv6_ADDRESS *TargetIp6Address,
2672 IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
2673 IN UINT32 Timeout,
2674 IN BOOLEAN Override
2675 )
2676 {
2677 IP6_NEIGHBOR_ENTRY *Neighbor;
2678
2679 Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
2680 if (Neighbor != NULL) {
2681 if (!Override) {
2682 return EFI_ACCESS_DENIED;
2683 } else {
2684 if (TargetLinkAddress != NULL) {
2685 IP6_COPY_LINK_ADDRESS (&Neighbor->LinkAddress, TargetLinkAddress);
2686 }
2687 }
2688 } else {
2689 if (TargetLinkAddress == NULL) {
2690 return EFI_NOT_FOUND;
2691 }
2692
2693 Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, TargetLinkAddress);
2694 if (Neighbor == NULL) {
2695 return EFI_OUT_OF_RESOURCES;
2696 }
2697 }
2698
2699 Neighbor->State = EfiNeighborReachable;
2700
2701 if (Timeout != 0) {
2702 Neighbor->Ticks = IP6_GET_TICKS (Timeout / TICKS_PER_MS);
2703 Neighbor->Dynamic = TRUE;
2704 } else {
2705 Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
2706 }
2707
2708 return EFI_SUCCESS;
2709 }
2710
2711 /**
2712 Delete or update Neighbor cache entries. It is a work function for EfiIp6Neighbors().
2713
2714 @param[in] IpSb The IP6 service binding instance.
2715 @param[in] TargetIp6Address Pointer to Target IPv6 address.
2716 @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
2717 @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
2718 cache. It will be deleted after Timeout. A value of zero means that
2719 the entry is permanent. A non-zero value means that the entry is
2720 dynamic.
2721 @param[in] Override If TRUE, the cached link-layer address of the matching entry will
2722 be overridden and updated; if FALSE, and if a
2723 corresponding cache entry already existed, EFI_ACCESS_DENIED
2724 will be returned.
2725
2726 @retval EFI_SUCCESS The neighbor cache entry has been updated or deleted.
2727 @retval EFI_NOT_FOUND This entry is not in the neighbor cache.
2728
2729 **/
2730 EFI_STATUS
2731 Ip6DelNeighbor (
2732 IN IP6_SERVICE *IpSb,
2733 IN EFI_IPv6_ADDRESS *TargetIp6Address,
2734 IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
2735 IN UINT32 Timeout,
2736 IN BOOLEAN Override
2737 )
2738 {
2739 IP6_NEIGHBOR_ENTRY *Neighbor;
2740
2741 Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
2742 if (Neighbor == NULL) {
2743 return EFI_NOT_FOUND;
2744 }
2745
2746 RemoveEntryList (&Neighbor->Link);
2747 FreePool (Neighbor);
2748
2749 return EFI_SUCCESS;
2750 }
2751
2752 /**
2753 The heartbeat timer of ND module in IP6_TIMER_INTERVAL_IN_MS milliseconds.
2754 This time routine handles DAD module and neighbor state transition.
2755 It is also responsible for sending out router solicitations.
2756
2757 @param[in] Event The IP6 service instance's heartbeat timer.
2758 @param[in] Context The IP6 service instance.
2759
2760 **/
2761 VOID
2762 EFIAPI
2763 Ip6NdFasterTimerTicking (
2764 IN EFI_EVENT Event,
2765 IN VOID *Context
2766 )
2767 {
2768 LIST_ENTRY *Entry;
2769 LIST_ENTRY *Next;
2770 LIST_ENTRY *Entry2;
2771 IP6_INTERFACE *IpIf;
2772 IP6_DELAY_JOIN_LIST *DelayNode;
2773 EFI_IPv6_ADDRESS Source;
2774 IP6_DAD_ENTRY *DupAddrDetect;
2775 EFI_STATUS Status;
2776 IP6_NEIGHBOR_ENTRY *NeighborCache;
2777 EFI_IPv6_ADDRESS Destination;
2778 IP6_SERVICE *IpSb;
2779 BOOLEAN Flag;
2780
2781 IpSb = (IP6_SERVICE *) Context;
2782 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
2783
2784 ZeroMem (&Source, sizeof (EFI_IPv6_ADDRESS));
2785
2786 //
2787 // A host SHOULD transmit up to MAX_RTR_SOLICITATIONS (3) Router
2788 // Solicitation messages, each separated by at least
2789 // RTR_SOLICITATION_INTERVAL (4) seconds.
2790 //
2791 if ((IpSb->Ip6ConfigInstance.Policy == Ip6ConfigPolicyAutomatic) &&
2792 !IpSb->RouterAdvertiseReceived &&
2793 IpSb->SolicitTimer > 0
2794 ) {
2795 if ((IpSb->Ticks == 0) || (--IpSb->Ticks == 0)) {
2796 Status = Ip6SendRouterSolicit (IpSb, NULL, NULL, NULL, NULL);
2797 if (!EFI_ERROR (Status)) {
2798 IpSb->SolicitTimer--;
2799 IpSb->Ticks = (UINT32) IP6_GET_TICKS (IP6_RTR_SOLICITATION_INTERVAL);
2800 }
2801 }
2802 }
2803
2804 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
2805 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
2806
2807 //
2808 // Process the delay list to join the solicited-node multicast address.
2809 //
2810 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {
2811 DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);
2812 if ((DelayNode->DelayTime == 0) || (--DelayNode->DelayTime == 0)) {
2813 //
2814 // The timer expires, init the duplicate address detection.
2815 //
2816 Ip6InitDADProcess (
2817 DelayNode->Interface,
2818 DelayNode->AddressInfo,
2819 DelayNode->DadCallback,
2820 DelayNode->Context
2821 );
2822
2823 //
2824 // Remove the delay node
2825 //
2826 RemoveEntryList (&DelayNode->Link);
2827 FreePool (DelayNode);
2828 }
2829 }
2830
2831 //
2832 // Process the duplicate address detection list.
2833 //
2834 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {
2835 DupAddrDetect = NET_LIST_USER_STRUCT (Entry2, IP6_DAD_ENTRY, Link);
2836
2837 if ((DupAddrDetect->RetransTick == 0) || (--DupAddrDetect->RetransTick == 0)) {
2838 //
2839 // The timer expires, check the remaining transmit counts.
2840 //
2841 if (DupAddrDetect->Transmit < DupAddrDetect->MaxTransmit) {
2842 //
2843 // Send the Neighbor Solicitation message with
2844 // Source - unspecified address, destination - solicited-node multicast address
2845 // Target - the address to be validated
2846 //
2847 Status = Ip6SendNeighborSolicit (
2848 IpSb,
2849 NULL,
2850 &DupAddrDetect->Destination,
2851 &DupAddrDetect->AddressInfo->Address,
2852 NULL
2853 );
2854 if (EFI_ERROR (Status)) {
2855 return;
2856 }
2857
2858 DupAddrDetect->Transmit++;
2859 DupAddrDetect->RetransTick = IP6_GET_TICKS (IpSb->RetransTimer);
2860 } else {
2861 //
2862 // All required solicitation has been sent out, and the RetransTime after the last
2863 // Neighbor Solicit is elapsed, finish the DAD process.
2864 //
2865 Flag = FALSE;
2866 if ((DupAddrDetect->Receive == 0) ||
2867 (DupAddrDetect->Transmit <= DupAddrDetect->Receive)) {
2868 Flag = TRUE;
2869 }
2870
2871 Ip6OnDADFinished (Flag, IpIf, DupAddrDetect);
2872 }
2873 }
2874 }
2875 }
2876
2877 //
2878 // Polling the state of Neighbor cache
2879 //
2880 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
2881 NeighborCache = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
2882
2883 switch (NeighborCache->State) {
2884 case EfiNeighborInComplete:
2885 if (NeighborCache->Ticks > 0) {
2886 --NeighborCache->Ticks;
2887 }
2888
2889 //
2890 // Retransmit Neighbor Solicitation messages approximately every
2891 // RetransTimer milliseconds while awaiting a response.
2892 //
2893 if (NeighborCache->Ticks == 0) {
2894 if (NeighborCache->Transmit > 1) {
2895 //
2896 // Send out multicast neighbor solicitation for address resolution.
2897 // After last neighbor solicitation message has been sent out, wait
2898 // for RetransTimer and then remove entry if no response is received.
2899 //
2900 Ip6CreateSNMulticastAddr (&NeighborCache->Neighbor, &Destination);
2901 Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
2902 if (EFI_ERROR (Status)) {
2903 return;
2904 }
2905
2906 Status = Ip6SendNeighborSolicit (
2907 IpSb,
2908 &Source,
2909 &Destination,
2910 &NeighborCache->Neighbor,
2911 &IpSb->SnpMode.CurrentAddress
2912 );
2913 if (EFI_ERROR (Status)) {
2914 return;
2915 }
2916 }
2917
2918 //
2919 // Update the retransmit times.
2920 //
2921 if (NeighborCache->Transmit > 0) {
2922 --NeighborCache->Transmit;
2923 NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
2924 }
2925 }
2926
2927 if (NeighborCache->Transmit == 0) {
2928 //
2929 // Timeout, send ICMP destination unreachable packet and then remove entry
2930 //
2931 Status = Ip6FreeNeighborEntry (
2932 IpSb,
2933 NeighborCache,
2934 TRUE,
2935 TRUE,
2936 EFI_ICMP_ERROR,
2937 NULL,
2938 NULL
2939 );
2940 if (EFI_ERROR (Status)) {
2941 return;
2942 }
2943 }
2944
2945 break;
2946
2947 case EfiNeighborReachable:
2948 //
2949 // This entry is inserted by EfiIp6Neighbors() as static entry
2950 // and will not timeout.
2951 //
2952 if (!NeighborCache->Dynamic && (NeighborCache->Ticks == IP6_INFINIT_LIFETIME)) {
2953 break;
2954 }
2955
2956 if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
2957 if (NeighborCache->Dynamic) {
2958 //
2959 // This entry is inserted by EfiIp6Neighbors() as dynamic entry
2960 // and will be deleted after timeout.
2961 //
2962 Status = Ip6FreeNeighborEntry (
2963 IpSb,
2964 NeighborCache,
2965 FALSE,
2966 TRUE,
2967 EFI_TIMEOUT,
2968 NULL,
2969 NULL
2970 );
2971 if (EFI_ERROR (Status)) {
2972 return;
2973 }
2974 } else {
2975 NeighborCache->State = EfiNeighborStale;
2976 NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
2977 }
2978 }
2979
2980 break;
2981
2982 case EfiNeighborDelay:
2983 if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
2984
2985 NeighborCache->State = EfiNeighborProbe;
2986 NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
2987 NeighborCache->Transmit = IP6_MAX_UNICAST_SOLICIT + 1;
2988 //
2989 // Send out unicast neighbor solicitation for Neighbor Unreachability Detection
2990 //
2991 Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
2992 if (EFI_ERROR (Status)) {
2993 return;
2994 }
2995
2996 Status = Ip6SendNeighborSolicit (
2997 IpSb,
2998 &Source,
2999 &NeighborCache->Neighbor,
3000 &NeighborCache->Neighbor,
3001 &IpSb->SnpMode.CurrentAddress
3002 );
3003 if (EFI_ERROR (Status)) {
3004 return;
3005 }
3006
3007 NeighborCache->Transmit--;
3008 }
3009
3010 break;
3011
3012 case EfiNeighborProbe:
3013 if (NeighborCache->Ticks > 0) {
3014 --NeighborCache->Ticks;
3015 }
3016
3017 //
3018 // Retransmit Neighbor Solicitation messages approximately every
3019 // RetransTimer milliseconds while awaiting a response.
3020 //
3021 if (NeighborCache->Ticks == 0) {
3022 if (NeighborCache->Transmit > 1) {
3023 //
3024 // Send out unicast neighbor solicitation for Neighbor Unreachability
3025 // Detection. After last neighbor solicitation message has been sent out,
3026 // wait for RetransTimer and then remove entry if no response is received.
3027 //
3028 Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
3029 if (EFI_ERROR (Status)) {
3030 return;
3031 }
3032
3033 Status = Ip6SendNeighborSolicit (
3034 IpSb,
3035 &Source,
3036 &NeighborCache->Neighbor,
3037 &NeighborCache->Neighbor,
3038 &IpSb->SnpMode.CurrentAddress
3039 );
3040 if (EFI_ERROR (Status)) {
3041 return;
3042 }
3043 }
3044
3045 //
3046 // Update the retransmit times.
3047 //
3048 if (NeighborCache->Transmit > 0) {
3049 --NeighborCache->Transmit;
3050 NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
3051 }
3052 }
3053
3054 if (NeighborCache->Transmit == 0) {
3055 //
3056 // Delete the neighbor entry.
3057 //
3058 Status = Ip6FreeNeighborEntry (
3059 IpSb,
3060 NeighborCache,
3061 FALSE,
3062 TRUE,
3063 EFI_TIMEOUT,
3064 NULL,
3065 NULL
3066 );
3067 if (EFI_ERROR (Status)) {
3068 return;
3069 }
3070 }
3071
3072 break;
3073
3074 default:
3075 break;
3076 }
3077 }
3078 }
3079
3080 /**
3081 The heartbeat timer of ND module in 1 second. This time routine handles following
3082 things: 1) maintain default router list; 2) maintain prefix options;
3083 3) maintain route caches.
3084
3085 @param[in] IpSb The IP6 service binding instance.
3086
3087 **/
3088 VOID
3089 Ip6NdTimerTicking (
3090 IN IP6_SERVICE *IpSb
3091 )
3092 {
3093 LIST_ENTRY *Entry;
3094 LIST_ENTRY *Next;
3095 IP6_DEFAULT_ROUTER *DefaultRouter;
3096 IP6_PREFIX_LIST_ENTRY *PrefixOption;
3097 UINT8 Index;
3098 IP6_ROUTE_CACHE_ENTRY *RouteCache;
3099
3100 //
3101 // Decrease the lifetime of default router, if expires remove it from default router list.
3102 //
3103 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->DefaultRouterList) {
3104 DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
3105 if (DefaultRouter->Lifetime != IP6_INF_ROUTER_LIFETIME) {
3106 if ((DefaultRouter->Lifetime == 0) || (--DefaultRouter->Lifetime == 0)) {
3107 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
3108 }
3109 }
3110 }
3111
3112 //
3113 // Decrease Valid lifetime and Preferred lifetime of Prefix options and corresponding addresses.
3114 //
3115 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->AutonomousPrefix) {
3116 PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
3117 if (PrefixOption->ValidLifetime != (UINT32) IP6_INFINIT_LIFETIME) {
3118 if ((PrefixOption->ValidLifetime > 0) && (--PrefixOption->ValidLifetime > 0)) {
3119 if ((PrefixOption->PreferredLifetime != (UINT32) IP6_INFINIT_LIFETIME) &&
3120 (PrefixOption->PreferredLifetime > 0)
3121 ) {
3122 --PrefixOption->PreferredLifetime;
3123 }
3124 } else {
3125 Ip6DestroyPrefixListEntry (IpSb, PrefixOption, FALSE, TRUE);
3126 }
3127 }
3128 }
3129
3130 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->OnlinkPrefix) {
3131 PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
3132 if (PrefixOption->ValidLifetime != (UINT32) IP6_INFINIT_LIFETIME) {
3133 if ((PrefixOption->ValidLifetime == 0) || (--PrefixOption->ValidLifetime == 0)) {
3134 Ip6DestroyPrefixListEntry (IpSb, PrefixOption, TRUE, TRUE);
3135 }
3136 }
3137 }
3138
3139 //
3140 // Each bucket of route cache can contain at most IP6_ROUTE_CACHE_MAX entries.
3141 // Remove the entries at the tail of the bucket. These entries
3142 // are likely to be used least.
3143 // Reclaim frequency is set to 1 second.
3144 //
3145 for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
3146 while (IpSb->RouteTable->Cache.CacheNum[Index] > IP6_ROUTE_CACHE_MAX) {
3147 Entry = NetListRemoveTail (&IpSb->RouteTable->Cache.CacheBucket[Index]);
3148 if (Entry == NULL) {
3149 break;
3150 }
3151
3152 RouteCache = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
3153 Ip6FreeRouteCacheEntry (RouteCache);
3154 ASSERT (IpSb->RouteTable->Cache.CacheNum[Index] > 0);
3155 IpSb->RouteTable->Cache.CacheNum[Index]--;
3156 }
3157 }
3158 }
3159