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