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