]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6ConfigImpl.c
1 /** @file
2 The implementation of EFI IPv6 Configuration Protocol.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) Microsoft Corporation.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "Ip6Impl.h"
12
13 LIST_ENTRY mIp6ConfigInstanceList = {&mIp6ConfigInstanceList, &mIp6ConfigInstanceList};
14
15 /**
16 The event process routine when the DHCPv6 service binding protocol is installed
17 in the system.
18
19 @param[in] Event Not used.
20 @param[in] Context Pointer to the IP6 config instance data.
21
22 **/
23 VOID
24 EFIAPI
25 Ip6ConfigOnDhcp6SbInstalled (
26 IN EFI_EVENT Event,
27 IN VOID *Context
28 );
29
30 /**
31 Update the current policy to NewPolicy. During the transition
32 period, the default router list, on-link prefix list, autonomous prefix list
33 and address list in all interfaces will be released.
34
35 @param[in] IpSb The IP6 service binding instance.
36 @param[in] NewPolicy The new policy to be updated to.
37
38 **/
39 VOID
40 Ip6ConfigOnPolicyChanged (
41 IN IP6_SERVICE *IpSb,
42 IN EFI_IP6_CONFIG_POLICY NewPolicy
43 )
44 {
45 LIST_ENTRY *Entry;
46 LIST_ENTRY *Entry2;
47 LIST_ENTRY *Next;
48 IP6_INTERFACE *IpIf;
49 IP6_DAD_ENTRY *DadEntry;
50 IP6_DELAY_JOIN_LIST *DelayNode;
51 IP6_ADDRESS_INFO *AddrInfo;
52 IP6_PROTOCOL *Instance;
53 BOOLEAN Recovery;
54
55 Recovery = FALSE;
56
57 //
58 // Currently there are only two policies: Manual and Automatic. Regardless of
59 // what transition is going on, i.e., Manual -> Automatic and Automatic ->
60 // Manual, we have to free default router list, on-link prefix list, autonomous
61 // prefix list, address list in all the interfaces and destroy any IPv6 child
62 // instance whose local IP is neither 0 nor the link-local address.
63 //
64 Ip6CleanDefaultRouterList (IpSb);
65 Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);
66 Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);
67
68 //
69 // It's tricky... If the LinkLocal address is O.K., add back the link-local
70 // prefix to the on-link prefix table.
71 //
72 if (IpSb->LinkLocalOk) {
73 Ip6CreatePrefixListEntry (
74 IpSb,
75 TRUE,
76 (UINT32) IP6_INFINIT_LIFETIME,
77 (UINT32) IP6_INFINIT_LIFETIME,
78 IP6_LINK_LOCAL_PREFIX_LENGTH,
79 &IpSb->LinkLocalAddr
80 );
81 }
82
83 if (!IsListEmpty (&IpSb->DefaultInterface->AddressList) && IpSb->DefaultInterface->AddressCount > 0) {
84 //
85 // If any IPv6 children (Instance) in configured state and use global unicast address, it will be
86 // destroyed in Ip6RemoveAddr() function later. Then, the upper layer driver's Stop() function will be
87 // called, which may break the upper layer network stacks. So, the driver should take the responsibility
88 // for the recovery by using ConnectController() after Ip6RemoveAddr().
89 // Here, just check whether need to recover the upper layer network stacks later.
90 //
91 NET_LIST_FOR_EACH (Entry, &IpSb->DefaultInterface->AddressList) {
92 AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
93 if (!IsListEmpty (&IpSb->Children)) {
94 NET_LIST_FOR_EACH (Entry2, &IpSb->Children) {
95 Instance = NET_LIST_USER_STRUCT_S (Entry2, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
96 if ((Instance->State == IP6_STATE_CONFIGED) && EFI_IP6_EQUAL (&Instance->ConfigData.StationAddress, &AddrInfo->Address)) {
97 Recovery = TRUE;
98 break;
99 }
100 }
101 }
102 }
103
104 //
105 // All IPv6 children that use global unicast address as its source address
106 // should be destroyed now. The survivers are those use the link-local address
107 // or the unspecified address as the source address.
108 // TODO: Conduct a check here.
109 Ip6RemoveAddr (
110 IpSb,
111 &IpSb->DefaultInterface->AddressList,
112 &IpSb->DefaultInterface->AddressCount,
113 NULL,
114 0
115 );
116
117 if (IpSb->Controller != NULL && Recovery) {
118 //
119 // ConnectController() to recover the upper layer network stacks.
120 //
121 gBS->ConnectController (IpSb->Controller, NULL, NULL, TRUE);
122 }
123 }
124
125
126 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
127 //
128 // remove all pending delay node and DAD entries for the global addresses.
129 //
130 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
131
132 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {
133 DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);
134 if (!NetIp6IsLinkLocalAddr (&DelayNode->AddressInfo->Address)) {
135 RemoveEntryList (&DelayNode->Link);
136 FreePool (DelayNode);
137 }
138 }
139
140 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {
141 DadEntry = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);
142
143 if (!NetIp6IsLinkLocalAddr (&DadEntry->AddressInfo->Address)) {
144 //
145 // Fail this DAD entry if the address is not link-local.
146 //
147 Ip6OnDADFinished (FALSE, IpIf, DadEntry);
148 }
149 }
150 }
151
152 if (NewPolicy == Ip6ConfigPolicyAutomatic) {
153 //
154 // Set parameters to trigger router solicitation sending in timer handler.
155 //
156 IpSb->RouterAdvertiseReceived = FALSE;
157 IpSb->SolicitTimer = IP6_MAX_RTR_SOLICITATIONS;
158 //
159 // delay 1 second
160 //
161 IpSb->Ticks = (UINT32) IP6_GET_TICKS (IP6_ONE_SECOND_IN_MS);
162 }
163 }
164
165 /**
166 The work function to trigger the DHCPv6 process to perform a stateful autoconfiguration.
167
168 @param[in] Instance Pointer to the IP6 config instance data.
169 @param[in] OtherInfoOnly If FALSE, get stateful address and other information
170 via DHCPv6. Otherwise, only get the other information.
171
172 @retval EFI_SUCCESS The operation finished successfully.
173 @retval EFI_UNSUPPORTED The DHCP6 driver is not available.
174
175 **/
176 EFI_STATUS
177 Ip6ConfigStartStatefulAutoConfig (
178 IN IP6_CONFIG_INSTANCE *Instance,
179 IN BOOLEAN OtherInfoOnly
180 )
181 {
182 EFI_STATUS Status;
183 IP6_SERVICE *IpSb;
184 EFI_DHCP6_CONFIG_DATA Dhcp6CfgData;
185 EFI_DHCP6_PROTOCOL *Dhcp6;
186 EFI_DHCP6_PACKET_OPTION *OptList[1];
187 UINT16 OptBuf[4];
188 EFI_DHCP6_PACKET_OPTION *Oro;
189 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
190
191 //
192 // A host must not invoke stateful address configuration if it is already
193 // participating in the statuful protocol as a result of an earlier advertisement.
194 //
195 if (Instance->Dhcp6Handle != NULL) {
196 return EFI_SUCCESS;
197 }
198
199 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
200
201 Instance->OtherInfoOnly = OtherInfoOnly;
202
203 Status = NetLibCreateServiceChild (
204 IpSb->Controller,
205 IpSb->Image,
206 &gEfiDhcp6ServiceBindingProtocolGuid,
207 &Instance->Dhcp6Handle
208 );
209
210 if (Status == EFI_UNSUPPORTED) {
211 //
212 // No DHCPv6 Service Binding protocol, register a notify.
213 //
214 if (Instance->Dhcp6SbNotifyEvent == NULL) {
215 Instance->Dhcp6SbNotifyEvent = EfiCreateProtocolNotifyEvent (
216 &gEfiDhcp6ServiceBindingProtocolGuid,
217 TPL_CALLBACK,
218 Ip6ConfigOnDhcp6SbInstalled,
219 (VOID *) Instance,
220 &Instance->Registration
221 );
222 }
223 }
224
225 if (EFI_ERROR (Status)) {
226 return Status;
227 }
228
229 if (Instance->Dhcp6SbNotifyEvent != NULL) {
230 gBS->CloseEvent (Instance->Dhcp6SbNotifyEvent);
231 }
232
233 Status = gBS->OpenProtocol (
234 Instance->Dhcp6Handle,
235 &gEfiDhcp6ProtocolGuid,
236 (VOID **) &Instance->Dhcp6,
237 IpSb->Image,
238 IpSb->Controller,
239 EFI_OPEN_PROTOCOL_BY_DRIVER
240 );
241 ASSERT_EFI_ERROR (Status);
242
243 Dhcp6 = Instance->Dhcp6;
244 Dhcp6->Configure (Dhcp6, NULL);
245
246 //
247 // Set the exta options to send. Here we only want the option request option
248 // with DNS SERVERS.
249 //
250 Oro = (EFI_DHCP6_PACKET_OPTION *) OptBuf;
251 Oro->OpCode = HTONS (DHCP6_OPT_ORO);
252 Oro->OpLen = HTONS (2);
253 *((UINT16 *) &Oro->Data[0]) = HTONS (DHCP6_OPT_DNS_SERVERS);
254 OptList[0] = Oro;
255
256 Status = EFI_SUCCESS;
257
258 if (!OtherInfoOnly) {
259 //
260 // Get stateful address and other information via DHCPv6.
261 //
262 Dhcp6CfgData.Dhcp6Callback = NULL;
263 Dhcp6CfgData.CallbackContext = NULL;
264 Dhcp6CfgData.OptionCount = 1;
265 Dhcp6CfgData.OptionList = &OptList[0];
266 Dhcp6CfgData.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;
267 Dhcp6CfgData.IaDescriptor.IaId = Instance->IaId;
268 Dhcp6CfgData.IaInfoEvent = Instance->Dhcp6Event;
269 Dhcp6CfgData.ReconfigureAccept = FALSE;
270 Dhcp6CfgData.RapidCommit = FALSE;
271 Dhcp6CfgData.SolicitRetransmission = NULL;
272
273 Status = Dhcp6->Configure (Dhcp6, &Dhcp6CfgData);
274
275 if (!EFI_ERROR (Status)) {
276
277 if (IpSb->LinkLocalOk) {
278 Status = Dhcp6->Start (Dhcp6);
279 } else {
280 IpSb->Dhcp6NeedStart = TRUE;
281 }
282
283 }
284 } else {
285 //
286 // Only get other information via DHCPv6, this doesn't require a config
287 // action.
288 //
289 InfoReqReXmit.Irt = 4;
290 InfoReqReXmit.Mrc = 64;
291 InfoReqReXmit.Mrt = 60;
292 InfoReqReXmit.Mrd = 0;
293
294 if (IpSb->LinkLocalOk) {
295 Status = Dhcp6->InfoRequest (
296 Dhcp6,
297 TRUE,
298 Oro,
299 0,
300 NULL,
301 &InfoReqReXmit,
302 Instance->Dhcp6Event,
303 Ip6ConfigOnDhcp6Reply,
304 Instance
305 );
306 } else {
307 IpSb->Dhcp6NeedInfoRequest = TRUE;
308 }
309
310 }
311
312 return Status;
313 }
314
315 /**
316 Signal the registered event. It is the callback routine for NetMapIterate.
317
318 @param[in] Map Points to the list of registered event.
319 @param[in] Item The registered event.
320 @param[in] Arg Not used.
321
322 **/
323 EFI_STATUS
324 EFIAPI
325 Ip6ConfigSignalEvent (
326 IN NET_MAP *Map,
327 IN NET_MAP_ITEM *Item,
328 IN VOID *Arg
329 )
330 {
331 gBS->SignalEvent ((EFI_EVENT) Item->Key);
332
333 return EFI_SUCCESS;
334 }
335
336 /**
337 Read the configuration data from variable storage according to the VarName and
338 gEfiIp6ConfigProtocolGuid. It checks the integrity of variable data. If the
339 data is corrupted, it clears the variable data to ZERO. Otherwise, it outputs the
340 configuration data to IP6_CONFIG_INSTANCE.
341
342 @param[in] VarName The pointer to the variable name
343 @param[in, out] Instance The pointer to the IP6 config instance data.
344
345 @retval EFI_NOT_FOUND The variable can not be found or already corrupted.
346 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.
347 @retval EFI_SUCCESS The configuration data was retrieved successfully.
348
349 **/
350 EFI_STATUS
351 Ip6ConfigReadConfigData (
352 IN CHAR16 *VarName,
353 IN OUT IP6_CONFIG_INSTANCE *Instance
354 )
355 {
356 EFI_STATUS Status;
357 UINTN VarSize;
358 IP6_CONFIG_VARIABLE *Variable;
359 IP6_CONFIG_DATA_ITEM *DataItem;
360 UINTN Index;
361 IP6_CONFIG_DATA_RECORD DataRecord;
362 CHAR8 *Data;
363
364 //
365 // Try to read the configuration variable.
366 //
367 VarSize = 0;
368 Status = gRT->GetVariable (
369 VarName,
370 &gEfiIp6ConfigProtocolGuid,
371 NULL,
372 &VarSize,
373 NULL
374 );
375
376 if (Status == EFI_BUFFER_TOO_SMALL) {
377 //
378 // Allocate buffer and read the config variable.
379 //
380 Variable = AllocatePool (VarSize);
381 if (Variable == NULL) {
382 return EFI_OUT_OF_RESOURCES;
383 }
384
385 Status = gRT->GetVariable (
386 VarName,
387 &gEfiIp6ConfigProtocolGuid,
388 NULL,
389 &VarSize,
390 Variable
391 );
392 if (EFI_ERROR (Status) || (UINT16) (~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize)) != 0) {
393 //
394 // GetVariable error or the variable is corrupted.
395 //
396 goto Error;
397 }
398
399 //
400 // Get the IAID we use.
401 //
402 Instance->IaId = Variable->IaId;
403
404 for (Index = 0; Index < Variable->DataRecordCount; Index++) {
405
406 CopyMem (&DataRecord, &Variable->DataRecord[Index], sizeof (DataRecord));
407
408 DataItem = &Instance->DataItem[DataRecord.DataType];
409 if (DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED) &&
410 (DataItem->DataSize != DataRecord.DataSize)
411 ) {
412 //
413 // Perhaps a corrupted data record...
414 //
415 continue;
416 }
417
418 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
419 //
420 // This data item has variable length data.
421 // Check that the length is contained within the variable before allocating.
422 //
423 if (DataRecord.DataSize > VarSize - DataRecord.Offset) {
424 goto Error;
425 }
426
427 DataItem->Data.Ptr = AllocatePool (DataRecord.DataSize);
428 if (DataItem->Data.Ptr == NULL) {
429 //
430 // no memory resource
431 //
432 continue;
433 }
434 }
435
436 Data = (CHAR8 *) Variable + DataRecord.Offset;
437 CopyMem (DataItem->Data.Ptr, Data, DataRecord.DataSize);
438
439 DataItem->DataSize = DataRecord.DataSize;
440 DataItem->Status = EFI_SUCCESS;
441 }
442
443 FreePool (Variable);
444 return EFI_SUCCESS;
445 }
446
447 return Status;
448
449 Error:
450 //
451 // Fall back to the default value.
452 //
453 if (Variable != NULL) {
454 FreePool (Variable);
455 }
456
457 //
458 // Remove the problematic variable and return EFI_NOT_FOUND, a new
459 // variable will be set again.
460 //
461 gRT->SetVariable (
462 VarName,
463 &gEfiIp6ConfigProtocolGuid,
464 IP6_CONFIG_VARIABLE_ATTRIBUTE,
465 0,
466 NULL
467 );
468
469 return EFI_NOT_FOUND;
470 }
471
472 /**
473 Write the configuration data from IP6_CONFIG_INSTANCE to variable storage.
474
475 @param[in] VarName The pointer to the variable name.
476 @param[in] Instance The pointer to the IP6 configuration instance data.
477
478 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.
479 @retval EFI_SUCCESS The configuration data is written successfully.
480
481 **/
482 EFI_STATUS
483 Ip6ConfigWriteConfigData (
484 IN CHAR16 *VarName,
485 IN IP6_CONFIG_INSTANCE *Instance
486 )
487 {
488 UINTN Index;
489 UINTN VarSize;
490 IP6_CONFIG_DATA_ITEM *DataItem;
491 IP6_CONFIG_VARIABLE *Variable;
492 IP6_CONFIG_DATA_RECORD *DataRecord;
493 CHAR8 *Heap;
494 EFI_STATUS Status;
495
496 VarSize = sizeof (IP6_CONFIG_VARIABLE) - sizeof (IP6_CONFIG_DATA_RECORD);
497
498 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
499
500 DataItem = &Instance->DataItem[Index];
501 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {
502
503 VarSize += sizeof (IP6_CONFIG_DATA_RECORD) + DataItem->DataSize;
504 }
505 }
506
507 Variable = AllocatePool (VarSize);
508 if (Variable == NULL) {
509 return EFI_OUT_OF_RESOURCES;
510 }
511
512 Variable->IaId = Instance->IaId;
513 Heap = (CHAR8 *) Variable + VarSize;
514 Variable->DataRecordCount = 0;
515
516 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
517
518 DataItem = &Instance->DataItem[Index];
519 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {
520
521 Heap -= DataItem->DataSize;
522 CopyMem (Heap, DataItem->Data.Ptr, DataItem->DataSize);
523
524 DataRecord = &Variable->DataRecord[Variable->DataRecordCount];
525 DataRecord->DataType = (EFI_IP6_CONFIG_DATA_TYPE) Index;
526 DataRecord->DataSize = (UINT32) DataItem->DataSize;
527 DataRecord->Offset = (UINT16) (Heap - (CHAR8 *) Variable);
528
529 Variable->DataRecordCount++;
530 }
531 }
532
533 Variable->Checksum = 0;
534 Variable->Checksum = (UINT16) ~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize);
535
536 Status = gRT->SetVariable (
537 VarName,
538 &gEfiIp6ConfigProtocolGuid,
539 IP6_CONFIG_VARIABLE_ATTRIBUTE,
540 VarSize,
541 Variable
542 );
543
544 FreePool (Variable);
545
546 return Status;
547 }
548
549 /**
550 The work function for EfiIp6ConfigGetData() to get the interface information
551 of the communication device this IP6Config instance manages.
552
553 @param[in] Instance Pointer to the IP6 config instance data.
554 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in
555 bytes, the size of buffer required to store the specified
556 configuration data.
557 @param[in] Data The data buffer in which the configuration data is returned.
558 Ignored if DataSize is ZERO.
559
560 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified
561 configuration data, and the required size is
562 returned in DataSize.
563 @retval EFI_SUCCESS The specified configuration data was obtained.
564
565 **/
566 EFI_STATUS
567 Ip6ConfigGetIfInfo (
568 IN IP6_CONFIG_INSTANCE *Instance,
569 IN OUT UINTN *DataSize,
570 IN VOID *Data OPTIONAL
571 )
572 {
573 IP6_SERVICE *IpSb;
574 UINTN Length;
575 IP6_CONFIG_DATA_ITEM *Item;
576 EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;
577 UINT32 AddressCount;
578 UINT32 RouteCount;
579
580 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
581 Length = sizeof (EFI_IP6_CONFIG_INTERFACE_INFO);
582
583 //
584 // Calculate the required length, add the buffer size for AddressInfo and
585 // RouteTable
586 //
587 Ip6BuildEfiAddressList (IpSb, &AddressCount, NULL);
588 Ip6BuildEfiRouteTable (IpSb->RouteTable, &RouteCount, NULL);
589
590 Length += AddressCount * sizeof (EFI_IP6_ADDRESS_INFO) + RouteCount * sizeof (EFI_IP6_ROUTE_TABLE);
591
592 if (*DataSize < Length) {
593 *DataSize = Length;
594 return EFI_BUFFER_TOO_SMALL;
595 }
596
597 //
598 // Copy the fixed size part of the interface info.
599 //
600 Item = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];
601 IfInfo = (EFI_IP6_CONFIG_INTERFACE_INFO *) Data;
602 CopyMem (IfInfo, Item->Data.Ptr, sizeof (EFI_IP6_CONFIG_INTERFACE_INFO));
603
604 //
605 // AddressInfo
606 //
607 IfInfo->AddressInfo = (EFI_IP6_ADDRESS_INFO *) (IfInfo + 1);
608 Ip6BuildEfiAddressList (IpSb, &IfInfo->AddressInfoCount, &IfInfo->AddressInfo);
609
610 //
611 // RouteTable
612 //
613 IfInfo->RouteTable = (EFI_IP6_ROUTE_TABLE *) (IfInfo->AddressInfo + IfInfo->AddressInfoCount);
614 Ip6BuildEfiRouteTable (IpSb->RouteTable, &IfInfo->RouteCount, &IfInfo->RouteTable);
615
616 if (IfInfo->AddressInfoCount == 0) {
617 IfInfo->AddressInfo = NULL;
618 }
619
620 if (IfInfo->RouteCount == 0) {
621 IfInfo->RouteTable = NULL;
622 }
623
624 return EFI_SUCCESS;
625 }
626
627 /**
628 The work function for EfiIp6ConfigSetData() to set the alternative interface ID
629 for the communication device managed by this IP6Config instance, if the link local
630 IPv6 addresses generated from the interface ID based on the default source the
631 EFI IPv6 Protocol uses is a duplicate address.
632
633 @param[in] Instance Pointer to the IP6 configuration instance data.
634 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
635 @param[in] Data The data buffer to set.
636
637 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type,
638 8 bytes.
639 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
640 network stack was set.
641
642 **/
643 EFI_STATUS
644 Ip6ConfigSetAltIfId (
645 IN IP6_CONFIG_INSTANCE *Instance,
646 IN UINTN DataSize,
647 IN VOID *Data
648 )
649 {
650 EFI_IP6_CONFIG_INTERFACE_ID *OldIfId;
651 EFI_IP6_CONFIG_INTERFACE_ID *NewIfId;
652 IP6_CONFIG_DATA_ITEM *DataItem;
653
654 if (DataSize != sizeof (EFI_IP6_CONFIG_INTERFACE_ID)) {
655 return EFI_BAD_BUFFER_SIZE;
656 }
657
658 DataItem = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];
659 OldIfId = DataItem->Data.AltIfId;
660 NewIfId = (EFI_IP6_CONFIG_INTERFACE_ID *) Data;
661
662 CopyMem (OldIfId, NewIfId, DataSize);
663 DataItem->Status = EFI_SUCCESS;
664
665 return EFI_SUCCESS;
666 }
667
668 /**
669 The work function for EfiIp6ConfigSetData() to set the general configuration
670 policy for the EFI IPv6 network stack that is running on the communication device
671 managed by this IP6Config instance. The policy will affect other configuration settings.
672
673 @param[in] Instance Pointer to the IP6 config instance data.
674 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
675 @param[in] Data The data buffer to set.
676
677 @retval EFI_INVALID_PARAMETER The to be set policy is invalid.
678 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
679 @retval EFI_ABORTED The new policy equals the current policy.
680 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
681 network stack was set.
682
683 **/
684 EFI_STATUS
685 Ip6ConfigSetPolicy (
686 IN IP6_CONFIG_INSTANCE *Instance,
687 IN UINTN DataSize,
688 IN VOID *Data
689 )
690 {
691 EFI_IP6_CONFIG_POLICY NewPolicy;
692 IP6_CONFIG_DATA_ITEM *DataItem;
693 IP6_SERVICE *IpSb;
694
695 if (DataSize != sizeof (EFI_IP6_CONFIG_POLICY)) {
696 return EFI_BAD_BUFFER_SIZE;
697 }
698
699 NewPolicy = *((EFI_IP6_CONFIG_POLICY *) Data);
700
701 if (NewPolicy > Ip6ConfigPolicyAutomatic) {
702 return EFI_INVALID_PARAMETER;
703 }
704
705 if (NewPolicy == Instance->Policy) {
706
707 return EFI_ABORTED;
708 } else {
709 //
710 // Clean the ManualAddress, Gateway and DnsServers, shrink the variable
711 // data size, and fire up all the related events.
712 //
713 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
714 if (DataItem->Data.Ptr != NULL) {
715 FreePool (DataItem->Data.Ptr);
716 }
717 DataItem->Data.Ptr = NULL;
718 DataItem->DataSize = 0;
719 DataItem->Status = EFI_NOT_FOUND;
720 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);
721
722 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];
723 if (DataItem->Data.Ptr != NULL) {
724 FreePool (DataItem->Data.Ptr);
725 }
726 DataItem->Data.Ptr = NULL;
727 DataItem->DataSize = 0;
728 DataItem->Status = EFI_NOT_FOUND;
729 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);
730
731 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
732 DataItem->Data.Ptr = NULL;
733 DataItem->DataSize = 0;
734 DataItem->Status = EFI_NOT_FOUND;
735 NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);
736
737 if (NewPolicy == Ip6ConfigPolicyManual) {
738 //
739 // The policy is changed from automatic to manual. Stop the DHCPv6 process
740 // and destroy the DHCPv6 child.
741 //
742 if (Instance->Dhcp6Handle != NULL) {
743 Ip6ConfigDestroyDhcp6 (Instance);
744 }
745 }
746
747 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
748 Ip6ConfigOnPolicyChanged (IpSb, NewPolicy);
749
750 Instance->Policy = NewPolicy;
751
752 return EFI_SUCCESS;
753 }
754 }
755
756 /**
757 The work function for EfiIp6ConfigSetData() to set the number of consecutive
758 Neighbor Solicitation messages sent while performing Duplicate Address Detection
759 on a tentative address. A value of ZERO indicates that Duplicate Address Detection
760 will not be performed on a tentative address.
761
762 @param[in] Instance The Instance Pointer to the IP6 config instance data.
763 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
764 @param[in] Data The data buffer to set.
765
766 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
767 @retval EFI_ABORTED The new transmit count equals the current configuration.
768 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
769 network stack was set.
770
771 **/
772 EFI_STATUS
773 Ip6ConfigSetDadXmits (
774 IN IP6_CONFIG_INSTANCE *Instance,
775 IN UINTN DataSize,
776 IN VOID *Data
777 )
778 {
779 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS *OldDadXmits;
780
781 if (DataSize != sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS)) {
782 return EFI_BAD_BUFFER_SIZE;
783 }
784
785 OldDadXmits = Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits].Data.DadXmits;
786
787 if ((*(UINT32 *) Data) == OldDadXmits->DupAddrDetectTransmits) {
788
789 return EFI_ABORTED;
790 } else {
791
792 OldDadXmits->DupAddrDetectTransmits = *((UINT32 *) Data);
793 return EFI_SUCCESS;
794 }
795 }
796
797 /**
798 The callback function for Ip6SetAddr. The prototype is defined
799 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed
800 for the manual address set by Ip6ConfigSetManualAddress.
801
802 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passed.
803 @param[in] TargetAddress The tentative IPv6 address to be checked.
804 @param[in] Context Pointer to the IP6 configuration instance data.
805
806 **/
807 VOID
808 Ip6ManualAddrDadCallback (
809 IN BOOLEAN IsDadPassed,
810 IN EFI_IPv6_ADDRESS *TargetAddress,
811 IN VOID *Context
812 )
813 {
814 IP6_CONFIG_INSTANCE *Instance;
815 UINTN Index;
816 IP6_CONFIG_DATA_ITEM *Item;
817 EFI_IP6_CONFIG_MANUAL_ADDRESS *ManualAddr;
818 EFI_IP6_CONFIG_MANUAL_ADDRESS *PassedAddr;
819 UINTN DadPassCount;
820 UINTN DadFailCount;
821 IP6_SERVICE *IpSb;
822
823 Instance = (IP6_CONFIG_INSTANCE *) Context;
824 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
825 Item = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
826 ManualAddr = NULL;
827
828 if (Item->DataSize == 0) {
829 return;
830 }
831
832 for (Index = 0; Index < Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS); Index++) {
833 //
834 // Find the original tag used to place into the NET_MAP.
835 //
836 ManualAddr = Item->Data.ManualAddress + Index;
837 if (EFI_IP6_EQUAL (TargetAddress, &ManualAddr->Address)) {
838 break;
839 }
840 }
841
842 ASSERT (Index != Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
843
844 if (IsDadPassed) {
845 NetMapInsertTail (&Instance->DadPassedMap, ManualAddr, NULL);
846 } else {
847 NetMapInsertTail (&Instance->DadFailedMap, ManualAddr, NULL);
848 }
849
850 DadPassCount = NetMapGetCount (&Instance->DadPassedMap);
851 DadFailCount = NetMapGetCount (&Instance->DadFailedMap);
852
853 if ((DadPassCount + DadFailCount) == (Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS))) {
854 //
855 // All addresses have finished the configuration process.
856 //
857 if (DadFailCount != 0) {
858 //
859 // There is at least one duplicate address.
860 //
861 FreePool (Item->Data.Ptr);
862
863 Item->DataSize = DadPassCount * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
864 if (Item->DataSize == 0) {
865 //
866 // All failed, bad luck.
867 //
868 Item->Data.Ptr = NULL;
869 Item->Status = EFI_NOT_FOUND;
870 } else {
871 //
872 // Part of addresses are detected to be duplicates, so update the
873 // data with those passed.
874 //
875 PassedAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) AllocatePool (Item->DataSize);
876 ASSERT (PassedAddr != NULL);
877
878 Item->Data.Ptr = PassedAddr;
879 Item->Status = EFI_SUCCESS;
880
881 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {
882 ManualAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) NetMapRemoveHead (&Instance->DadPassedMap, NULL);
883 CopyMem (PassedAddr, ManualAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
884
885 PassedAddr++;
886 }
887
888 ASSERT ((UINTN) PassedAddr - (UINTN) Item->Data.Ptr == Item->DataSize);
889 }
890 } else {
891 //
892 // All addresses are valid.
893 //
894 Item->Status = EFI_SUCCESS;
895 }
896
897 //
898 // Remove the tags we put in the NET_MAPs.
899 //
900 while (!NetMapIsEmpty (&Instance->DadFailedMap)) {
901 NetMapRemoveHead (&Instance->DadFailedMap, NULL);
902 }
903
904 while (!NetMapIsEmpty (&Instance->DadPassedMap)) {
905 NetMapRemoveHead (&Instance->DadPassedMap, NULL);
906 }
907
908 //
909 // Signal the waiting events.
910 //
911 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);
912 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
913 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
914 }
915 }
916
917 /**
918 The work function for EfiIp6ConfigSetData() to set the station addresses manually
919 for the EFI IPv6 network stack. It is only configurable when the policy is
920 Ip6ConfigPolicyManual.
921
922 @param[in] Instance Pointer to the IP6 configuration instance data.
923 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
924 @param[in] Data The data buffer to set.
925
926 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
927 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
928 under the current policy.
929 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
930 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.
931 @retval EFI_NOT_READY An asynchronous process is invoked to set the specified
932 configuration data, and the process is not finished.
933 @retval EFI_ABORTED The manual addresses to be set equal current
934 configuration.
935 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
936 network stack was set.
937
938 **/
939 EFI_STATUS
940 Ip6ConfigSetManualAddress (
941 IN IP6_CONFIG_INSTANCE *Instance,
942 IN UINTN DataSize,
943 IN VOID *Data
944 )
945 {
946 EFI_IP6_CONFIG_MANUAL_ADDRESS *NewAddress;
947 EFI_IP6_CONFIG_MANUAL_ADDRESS *TmpAddress;
948 IP6_CONFIG_DATA_ITEM *DataItem;
949 UINTN NewAddressCount;
950 UINTN Index1;
951 UINTN Index2;
952 IP6_SERVICE *IpSb;
953 IP6_ADDRESS_INFO *CurrentAddrInfo;
954 IP6_ADDRESS_INFO *Copy;
955 LIST_ENTRY CurrentSourceList;
956 UINT32 CurrentSourceCount;
957 LIST_ENTRY *Entry;
958 LIST_ENTRY *Entry2;
959 IP6_INTERFACE *IpIf;
960 IP6_PREFIX_LIST_ENTRY *PrefixEntry;
961 EFI_STATUS Status;
962 BOOLEAN IsUpdated;
963 LIST_ENTRY *Next;
964 IP6_DAD_ENTRY *DadEntry;
965 IP6_DELAY_JOIN_LIST *DelayNode;
966
967 NewAddress = NULL;
968 TmpAddress = NULL;
969 CurrentAddrInfo = NULL;
970 Copy = NULL;
971 Entry = NULL;
972 Entry2 = NULL;
973 IpIf = NULL;
974 PrefixEntry = NULL;
975 Next = NULL;
976 DadEntry = NULL;
977 DelayNode = NULL;
978 Status = EFI_SUCCESS;
979
980 ASSERT (Instance->DataItem[Ip6ConfigDataTypeManualAddress].Status != EFI_NOT_READY);
981
982 if ((DataSize != 0) && ((DataSize % sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)) != 0)) {
983 return EFI_BAD_BUFFER_SIZE;
984 }
985
986 if (Instance->Policy != Ip6ConfigPolicyManual) {
987 return EFI_WRITE_PROTECTED;
988 }
989
990 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
991
992 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
993
994 if (Data != NULL && DataSize != 0) {
995 NewAddressCount = DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
996 NewAddress = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) Data;
997
998 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {
999
1000 if (NetIp6IsLinkLocalAddr (&NewAddress->Address) ||
1001 !NetIp6IsValidUnicast (&NewAddress->Address) ||
1002 (NewAddress->PrefixLength > 128)
1003 ) {
1004 //
1005 // make sure the IPv6 address is unicast and not link-local address &&
1006 // the prefix length is valid.
1007 //
1008 return EFI_INVALID_PARAMETER;
1009 }
1010
1011 TmpAddress = NewAddress + 1;
1012 for (Index2 = Index1 + 1; Index2 < NewAddressCount; Index2++, TmpAddress++) {
1013 //
1014 // Any two addresses in the array can't be equal.
1015 //
1016 if (EFI_IP6_EQUAL (&TmpAddress->Address, &NewAddress->Address)) {
1017
1018 return EFI_INVALID_PARAMETER;
1019 }
1020 }
1021 }
1022
1023 //
1024 // Build the current source address list.
1025 //
1026 InitializeListHead (&CurrentSourceList);
1027 CurrentSourceCount = 0;
1028
1029 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
1030 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
1031
1032 NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {
1033 CurrentAddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
1034
1035 Copy = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), CurrentAddrInfo);
1036 if (Copy == NULL) {
1037 break;
1038 }
1039
1040 InsertTailList (&CurrentSourceList, &Copy->Link);
1041 CurrentSourceCount++;
1042 }
1043 }
1044
1045 //
1046 // Update the value... a long journey starts
1047 //
1048 NewAddress = AllocateCopyPool (DataSize, Data);
1049 if (NewAddress == NULL) {
1050 Ip6RemoveAddr (NULL, &CurrentSourceList, &CurrentSourceCount, NULL, 0);
1051
1052 return EFI_OUT_OF_RESOURCES;
1053 }
1054
1055 //
1056 // Store the new data, and init the DataItem status to EFI_NOT_READY because
1057 // we may have an asynchronous configuration process.
1058 //
1059 if (DataItem->Data.Ptr != NULL) {
1060 FreePool (DataItem->Data.Ptr);
1061 }
1062 DataItem->Data.Ptr = NewAddress;
1063 DataItem->DataSize = DataSize;
1064 DataItem->Status = EFI_NOT_READY;
1065
1066 //
1067 // Trigger DAD, it's an asynchronous process.
1068 //
1069 IsUpdated = FALSE;
1070
1071 for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {
1072 if (Ip6IsOneOfSetAddress (IpSb, &NewAddress->Address, NULL, &CurrentAddrInfo)) {
1073 ASSERT (CurrentAddrInfo != NULL);
1074 //
1075 // Remove this already existing source address from the CurrentSourceList
1076 // built before.
1077 //
1078 Ip6RemoveAddr (
1079 NULL,
1080 &CurrentSourceList,
1081 &CurrentSourceCount,
1082 &CurrentAddrInfo->Address,
1083 128
1084 );
1085
1086 //
1087 // If the new address's prefix length is not specified, just use the previous configured
1088 // prefix length for this address.
1089 //
1090 if (NewAddress->PrefixLength == 0) {
1091 NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;
1092 }
1093
1094 //
1095 // This manual address is already in use, see whether prefix length is changed.
1096 //
1097 if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {
1098 //
1099 // Remove the on-link prefix table, the route entry will be removed
1100 // implicitly.
1101 //
1102 PrefixEntry = Ip6FindPrefixListEntry (
1103 IpSb,
1104 TRUE,
1105 CurrentAddrInfo->PrefixLength,
1106 &CurrentAddrInfo->Address
1107 );
1108 if (PrefixEntry != NULL) {
1109 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);
1110 }
1111
1112 //
1113 // Save the prefix length.
1114 //
1115 CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;
1116 IsUpdated = TRUE;
1117 }
1118
1119 //
1120 // create a new on-link prefix entry.
1121 //
1122 PrefixEntry = Ip6FindPrefixListEntry (
1123 IpSb,
1124 TRUE,
1125 NewAddress->PrefixLength,
1126 &NewAddress->Address
1127 );
1128 if (PrefixEntry == NULL) {
1129 Ip6CreatePrefixListEntry (
1130 IpSb,
1131 TRUE,
1132 (UINT32) IP6_INFINIT_LIFETIME,
1133 (UINT32) IP6_INFINIT_LIFETIME,
1134 NewAddress->PrefixLength,
1135 &NewAddress->Address
1136 );
1137 }
1138
1139 CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;
1140 //
1141 // Artificially mark this address passed DAD be'coz it is already in use.
1142 //
1143 Ip6ManualAddrDadCallback (TRUE, &NewAddress->Address, Instance);
1144 } else {
1145 //
1146 // A new address.
1147 //
1148 IsUpdated = TRUE;
1149
1150 //
1151 // Set the new address, this will trigger DAD and activate the address if
1152 // DAD succeeds.
1153 //
1154 Ip6SetAddress (
1155 IpSb->DefaultInterface,
1156 &NewAddress->Address,
1157 NewAddress->IsAnycast,
1158 NewAddress->PrefixLength,
1159 (UINT32) IP6_INFINIT_LIFETIME,
1160 (UINT32) IP6_INFINIT_LIFETIME,
1161 Ip6ManualAddrDadCallback,
1162 Instance
1163 );
1164 }
1165 }
1166
1167 //
1168 // Check the CurrentSourceList, it now contains those addresses currently in
1169 // use and will be removed.
1170 //
1171 IpIf = IpSb->DefaultInterface;
1172
1173 while (!IsListEmpty (&CurrentSourceList)) {
1174 IsUpdated = TRUE;
1175
1176 CurrentAddrInfo = NET_LIST_HEAD (&CurrentSourceList, IP6_ADDRESS_INFO, Link);
1177
1178 //
1179 // This local address is going to be removed, the IP instances that are
1180 // currently using it will be destroyed.
1181 //
1182 Ip6RemoveAddr (
1183 IpSb,
1184 &IpIf->AddressList,
1185 &IpIf->AddressCount,
1186 &CurrentAddrInfo->Address,
1187 128
1188 );
1189
1190 //
1191 // Remove the on-link prefix table, the route entry will be removed
1192 // implicitly.
1193 //
1194 PrefixEntry = Ip6FindPrefixListEntry (
1195 IpSb,
1196 TRUE,
1197 CurrentAddrInfo->PrefixLength,
1198 &CurrentAddrInfo->Address
1199 );
1200 if (PrefixEntry != NULL) {
1201 Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);
1202 }
1203
1204 RemoveEntryList (&CurrentAddrInfo->Link);
1205 FreePool (CurrentAddrInfo);
1206 }
1207
1208 if (IsUpdated) {
1209 if (DataItem->Status == EFI_NOT_READY) {
1210 //
1211 // If DAD is disabled on this interface, the configuration process is
1212 // actually synchronous, and the data item's status will be changed to
1213 // the final status before we reach here, just check it.
1214 //
1215 Status = EFI_NOT_READY;
1216 } else {
1217 Status = EFI_SUCCESS;
1218 }
1219 } else {
1220 //
1221 // No update is taken, reset the status to success and return EFI_ABORTED.
1222 //
1223 DataItem->Status = EFI_SUCCESS;
1224 Status = EFI_ABORTED;
1225 }
1226 } else {
1227 //
1228 // DataSize is 0 and Data is NULL, clean up the manual address.
1229 //
1230 if (DataItem->Data.Ptr != NULL) {
1231 FreePool (DataItem->Data.Ptr);
1232 }
1233 DataItem->Data.Ptr = NULL;
1234 DataItem->DataSize = 0;
1235 DataItem->Status = EFI_NOT_FOUND;
1236
1237 Ip6CleanDefaultRouterList (IpSb);
1238 Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);
1239 Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);
1240 Ip6CleanAssembleTable (&IpSb->Assemble);
1241
1242 if (IpSb->LinkLocalOk) {
1243 Ip6CreatePrefixListEntry (
1244 IpSb,
1245 TRUE,
1246 (UINT32) IP6_INFINIT_LIFETIME,
1247 (UINT32) IP6_INFINIT_LIFETIME,
1248 IP6_LINK_LOCAL_PREFIX_LENGTH,
1249 &IpSb->LinkLocalAddr
1250 );
1251 }
1252
1253 Ip6RemoveAddr (
1254 IpSb,
1255 &IpSb->DefaultInterface->AddressList,
1256 &IpSb->DefaultInterface->AddressCount,
1257 NULL,
1258 0
1259 );
1260
1261 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
1262 //
1263 // Remove all pending delay node and DAD entries for the global addresses.
1264 //
1265 IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
1266
1267 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {
1268 DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);
1269 if (!NetIp6IsLinkLocalAddr (&DelayNode->AddressInfo->Address)) {
1270 RemoveEntryList (&DelayNode->Link);
1271 FreePool (DelayNode);
1272 }
1273 }
1274
1275 NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {
1276 DadEntry = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);
1277
1278 if (!NetIp6IsLinkLocalAddr (&DadEntry->AddressInfo->Address)) {
1279 //
1280 // Fail this DAD entry if the address is not link-local.
1281 //
1282 Ip6OnDADFinished (FALSE, IpIf, DadEntry);
1283 }
1284 }
1285 }
1286 }
1287
1288 return Status;
1289 }
1290
1291 /**
1292 The work function for EfiIp6ConfigSetData() to set the gateway addresses manually
1293 for the EFI IPv6 network stack that is running on the communication device that
1294 this EFI IPv6 Configuration Protocol manages. It is not configurable when the policy is
1295 Ip6ConfigPolicyAutomatic. The gateway addresses must be unicast IPv6 addresses.
1296
1297 @param[in] Instance The pointer to the IP6 config instance data.
1298 @param[in] DataSize The size of the buffer pointed to by Data in bytes.
1299 @param[in] Data The data buffer to set. This points to an array of
1300 EFI_IPv6_ADDRESS instances.
1301
1302 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
1303 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
1304 under the current policy.
1305 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1306 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to complete the operation.
1307 @retval EFI_ABORTED The manual gateway addresses to be set equal the
1308 current configuration.
1309 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1310 network stack was set.
1311
1312 **/
1313 EFI_STATUS
1314 Ip6ConfigSetGateway (
1315 IN IP6_CONFIG_INSTANCE *Instance,
1316 IN UINTN DataSize,
1317 IN VOID *Data
1318 )
1319 {
1320 UINTN Index1;
1321 UINTN Index2;
1322 EFI_IPv6_ADDRESS *OldGateway;
1323 EFI_IPv6_ADDRESS *NewGateway;
1324 UINTN OldGatewayCount;
1325 UINTN NewGatewayCount;
1326 IP6_CONFIG_DATA_ITEM *Item;
1327 BOOLEAN OneRemoved;
1328 BOOLEAN OneAdded;
1329 IP6_SERVICE *IpSb;
1330 IP6_DEFAULT_ROUTER *DefaultRouter;
1331 VOID *Tmp;
1332
1333 OldGateway = NULL;
1334 NewGateway = NULL;
1335 Item = NULL;
1336 DefaultRouter = NULL;
1337 Tmp = NULL;
1338 OneRemoved = FALSE;
1339 OneAdded = FALSE;
1340
1341 if ((DataSize != 0) && (DataSize % sizeof (EFI_IPv6_ADDRESS) != 0)) {
1342 return EFI_BAD_BUFFER_SIZE;
1343 }
1344
1345 if (Instance->Policy != Ip6ConfigPolicyManual) {
1346 return EFI_WRITE_PROTECTED;
1347 }
1348
1349 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1350 Item = &Instance->DataItem[Ip6ConfigDataTypeGateway];
1351 OldGateway = Item->Data.Gateway;
1352 OldGatewayCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);
1353
1354 for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {
1355 //
1356 // Remove this default router.
1357 //
1358 DefaultRouter = Ip6FindDefaultRouter (IpSb, OldGateway + Index1);
1359 if (DefaultRouter != NULL) {
1360 Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
1361 OneRemoved = TRUE;
1362 }
1363 }
1364
1365 if (Data != NULL && DataSize != 0) {
1366 NewGateway = (EFI_IPv6_ADDRESS *) Data;
1367 NewGatewayCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
1368 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1369
1370 if (!NetIp6IsValidUnicast (NewGateway + Index1)) {
1371
1372 return EFI_INVALID_PARAMETER;
1373 }
1374
1375 for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {
1376 if (EFI_IP6_EQUAL (NewGateway + Index1, NewGateway + Index2)) {
1377 return EFI_INVALID_PARAMETER;
1378 }
1379 }
1380 }
1381
1382 if (NewGatewayCount != OldGatewayCount) {
1383 Tmp = AllocatePool (DataSize);
1384 if (Tmp == NULL) {
1385 return EFI_OUT_OF_RESOURCES;
1386 }
1387 } else {
1388 Tmp = NULL;
1389 }
1390
1391 for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1392
1393 DefaultRouter = Ip6FindDefaultRouter (IpSb, NewGateway + Index1);
1394 if (DefaultRouter == NULL) {
1395 Ip6CreateDefaultRouter (IpSb, NewGateway + Index1, IP6_INF_ROUTER_LIFETIME);
1396 OneAdded = TRUE;
1397 }
1398 }
1399
1400 if (!OneRemoved && !OneAdded) {
1401 Item->Status = EFI_SUCCESS;
1402 return EFI_ABORTED;
1403 } else {
1404
1405 if (Tmp != NULL) {
1406 if (Item->Data.Ptr != NULL) {
1407 FreePool (Item->Data.Ptr);
1408 }
1409 Item->Data.Ptr = Tmp;
1410 }
1411
1412 CopyMem (Item->Data.Ptr, Data, DataSize);
1413 Item->DataSize = DataSize;
1414 Item->Status = EFI_SUCCESS;
1415 return EFI_SUCCESS;
1416 }
1417 } else {
1418 //
1419 // DataSize is 0 and Data is NULL, clean up the Gateway address.
1420 //
1421 if (Item->Data.Ptr != NULL) {
1422 FreePool (Item->Data.Ptr);
1423 }
1424 Item->Data.Ptr = NULL;
1425 Item->DataSize = 0;
1426 Item->Status = EFI_NOT_FOUND;
1427 }
1428
1429 return EFI_SUCCESS;
1430 }
1431
1432 /**
1433 The work function for EfiIp6ConfigSetData() to set the DNS server list for the
1434 EFI IPv6 network stack running on the communication device that this EFI IPv6
1435 Configuration Protocol manages. It is not configurable when the policy is
1436 Ip6ConfigPolicyAutomatic. The DNS server addresses must be unicast IPv6 addresses.
1437
1438 @param[in] Instance The pointer to the IP6 config instance data.
1439 @param[in] DataSize The size of the buffer pointed to by Data in bytes.
1440 @param[in] Data The data buffer to set, points to an array of
1441 EFI_IPv6_ADDRESS instances.
1442
1443 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.
1444 @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set
1445 under the current policy.
1446 @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1447 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
1448 @retval EFI_ABORTED The DNS server addresses to be set equal the current
1449 configuration.
1450 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1451 network stack was set.
1452
1453 **/
1454 EFI_STATUS
1455 Ip6ConfigSetDnsServer (
1456 IN IP6_CONFIG_INSTANCE *Instance,
1457 IN UINTN DataSize,
1458 IN VOID *Data
1459 )
1460 {
1461 UINTN OldIndex;
1462 UINTN NewIndex;
1463 EFI_IPv6_ADDRESS *OldDns;
1464 EFI_IPv6_ADDRESS *NewDns;
1465 UINTN OldDnsCount;
1466 UINTN NewDnsCount;
1467 IP6_CONFIG_DATA_ITEM *Item;
1468 BOOLEAN OneAdded;
1469 VOID *Tmp;
1470
1471 OldDns = NULL;
1472 NewDns = NULL;
1473 Item = NULL;
1474 Tmp = NULL;
1475
1476 if ((DataSize != 0) && (DataSize % sizeof (EFI_IPv6_ADDRESS) != 0)) {
1477 return EFI_BAD_BUFFER_SIZE;
1478 }
1479
1480 if (Instance->Policy != Ip6ConfigPolicyManual) {
1481 return EFI_WRITE_PROTECTED;
1482 }
1483
1484 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
1485
1486 if (Data != NULL && DataSize != 0) {
1487 NewDns = (EFI_IPv6_ADDRESS *) Data;
1488 OldDns = Item->Data.DnsServers;
1489 NewDnsCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
1490 OldDnsCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);
1491 OneAdded = FALSE;
1492
1493 if (NewDnsCount != OldDnsCount) {
1494 Tmp = AllocatePool (DataSize);
1495 if (Tmp == NULL) {
1496 return EFI_OUT_OF_RESOURCES;
1497 }
1498 } else {
1499 Tmp = NULL;
1500 }
1501
1502 for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {
1503
1504 if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {
1505 //
1506 // The dns server address must be unicast.
1507 //
1508 if (Tmp != NULL) {
1509 FreePool (Tmp);
1510 }
1511 return EFI_INVALID_PARAMETER;
1512 }
1513
1514 if (OneAdded) {
1515 //
1516 // If any address in the new setting is not in the old settings, skip the
1517 // comparision below.
1518 //
1519 continue;
1520 }
1521
1522 for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {
1523 if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {
1524 //
1525 // If found break out.
1526 //
1527 break;
1528 }
1529 }
1530
1531 if (OldIndex == OldDnsCount) {
1532 OneAdded = TRUE;
1533 }
1534 }
1535
1536 if (!OneAdded && (DataSize == Item->DataSize)) {
1537 //
1538 // No new item is added and the size is the same.
1539 //
1540 Item->Status = EFI_SUCCESS;
1541 return EFI_ABORTED;
1542 } else {
1543 if (Tmp != NULL) {
1544 if (Item->Data.Ptr != NULL) {
1545 FreePool (Item->Data.Ptr);
1546 }
1547 Item->Data.Ptr = Tmp;
1548 }
1549
1550 CopyMem (Item->Data.Ptr, Data, DataSize);
1551 Item->DataSize = DataSize;
1552 Item->Status = EFI_SUCCESS;
1553 }
1554 } else {
1555 //
1556 // DataSize is 0 and Data is NULL, clean up the DnsServer address.
1557 //
1558 if (Item->Data.Ptr != NULL) {
1559 FreePool (Item->Data.Ptr);
1560 }
1561 Item->Data.Ptr = NULL;
1562 Item->DataSize = 0;
1563 Item->Status = EFI_NOT_FOUND;
1564 }
1565
1566 return EFI_SUCCESS;
1567 }
1568
1569 /**
1570 Generate the operational state of the interface this IP6 config instance manages
1571 and output in EFI_IP6_CONFIG_INTERFACE_INFO.
1572
1573 @param[in] IpSb The pointer to the IP6 service binding instance.
1574 @param[out] IfInfo The pointer to the IP6 configuration interface information structure.
1575
1576 **/
1577 VOID
1578 Ip6ConfigInitIfInfo (
1579 IN IP6_SERVICE *IpSb,
1580 OUT EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo
1581 )
1582 {
1583 UnicodeSPrint (
1584 IfInfo->Name,
1585 sizeof (IfInfo->Name),
1586 L"eth%d",
1587 IpSb->Ip6ConfigInstance.IfIndex
1588 );
1589
1590 IfInfo->IfType = IpSb->SnpMode.IfType;
1591 IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;
1592 CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);
1593 }
1594
1595 /**
1596 Parse DHCPv6 reply packet to get the DNS server list.
1597 It is the work function for Ip6ConfigOnDhcp6Reply and Ip6ConfigOnDhcp6Event.
1598
1599 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL instance.
1600 @param[in, out] Instance The pointer to the IP6 configuration instance data.
1601 @param[in] Reply The pointer to the DHCPv6 reply packet.
1602
1603 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.
1604 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or
1605 the DNS server address is not valid.
1606
1607 **/
1608 EFI_STATUS
1609 Ip6ConfigParseDhcpReply (
1610 IN EFI_DHCP6_PROTOCOL *Dhcp6,
1611 IN OUT IP6_CONFIG_INSTANCE *Instance,
1612 IN EFI_DHCP6_PACKET *Reply
1613 )
1614 {
1615 EFI_STATUS Status;
1616 UINT32 OptCount;
1617 EFI_DHCP6_PACKET_OPTION **OptList;
1618 UINT16 OpCode;
1619 UINT16 Length;
1620 UINTN Index;
1621 UINTN Index2;
1622 EFI_IPv6_ADDRESS *DnsServer;
1623 IP6_CONFIG_DATA_ITEM *Item;
1624
1625 //
1626 // A DHCPv6 reply packet is received as the response to our InfoRequest
1627 // packet.
1628 //
1629 OptCount = 0;
1630 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, NULL);
1631 if (Status != EFI_BUFFER_TOO_SMALL) {
1632 return EFI_NOT_READY;
1633 }
1634
1635 OptList = AllocatePool (OptCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
1636 if (OptList == NULL) {
1637 return EFI_NOT_READY;
1638 }
1639
1640 Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, OptList);
1641 if (EFI_ERROR (Status)) {
1642 Status = EFI_NOT_READY;
1643 goto ON_EXIT;
1644 }
1645
1646 Status = EFI_SUCCESS;
1647
1648 for (Index = 0; Index < OptCount; Index++) {
1649 //
1650 // Go through all the options to check the ones we are interested in.
1651 // The OpCode and Length are in network byte-order and may not be naturally
1652 // aligned.
1653 //
1654 CopyMem (&OpCode, &OptList[Index]->OpCode, sizeof (OpCode));
1655 OpCode = NTOHS (OpCode);
1656
1657 if (OpCode == DHCP6_OPT_DNS_SERVERS) {
1658 CopyMem (&Length, &OptList[Index]->OpLen, sizeof (Length));
1659 Length = NTOHS (Length);
1660
1661 if ((Length == 0) || ((Length % sizeof (EFI_IPv6_ADDRESS)) != 0)) {
1662 //
1663 // The length should be a multiple of 16 bytes.
1664 //
1665 Status = EFI_NOT_READY;
1666 break;
1667 }
1668
1669 //
1670 // Validate the DnsServers: whether they are unicast addresses.
1671 //
1672 DnsServer = (EFI_IPv6_ADDRESS *) OptList[Index]->Data;
1673 for (Index2 = 0; Index2 < Length / sizeof (EFI_IPv6_ADDRESS); Index2++) {
1674 if (!NetIp6IsValidUnicast (DnsServer)) {
1675 Status = EFI_NOT_READY;
1676 goto ON_EXIT;
1677 }
1678
1679 DnsServer++;
1680 }
1681
1682 Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
1683
1684 if (Item->DataSize != Length) {
1685 if (Item->Data.Ptr != NULL) {
1686 FreePool (Item->Data.Ptr);
1687 }
1688
1689 Item->Data.Ptr = AllocatePool (Length);
1690 ASSERT (Item->Data.Ptr != NULL);
1691 }
1692
1693 CopyMem (Item->Data.Ptr, OptList[Index]->Data, Length);
1694 Item->DataSize = Length;
1695 Item->Status = EFI_SUCCESS;
1696
1697 //
1698 // Signal the waiting events.
1699 //
1700 NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);
1701
1702 break;
1703 }
1704 }
1705
1706 ON_EXIT:
1707
1708 FreePool (OptList);
1709 return Status;
1710 }
1711
1712 /**
1713 The callback function for Ip6SetAddr. The prototype is defined
1714 as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed
1715 on the tentative address by DHCPv6 in Ip6ConfigOnDhcp6Event().
1716
1717 @param[in] IsDadPassed If TRUE, Duplicate Address Detection passes.
1718 @param[in] TargetAddress The tentative IPv6 address to be checked.
1719 @param[in] Context Pointer to the IP6 configuration instance data.
1720
1721 **/
1722 VOID
1723 Ip6ConfigSetStatefulAddrCallback (
1724 IN BOOLEAN IsDadPassed,
1725 IN EFI_IPv6_ADDRESS *TargetAddress,
1726 IN VOID *Context
1727 )
1728 {
1729 IP6_CONFIG_INSTANCE *Instance;
1730
1731 Instance = (IP6_CONFIG_INSTANCE *) Context;
1732 NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
1733
1734 //
1735 // We should record the addresses that fail the DAD, and DECLINE them.
1736 //
1737 if (IsDadPassed) {
1738 //
1739 // Decrease the count, no interests in those passed DAD.
1740 //
1741 if (Instance->FailedIaAddressCount > 0 ) {
1742 Instance->FailedIaAddressCount--;
1743 }
1744 } else {
1745 //
1746 // Record it.
1747 //
1748 IP6_COPY_ADDRESS (Instance->DeclineAddress + Instance->DeclineAddressCount, TargetAddress);
1749 Instance->DeclineAddressCount++;
1750 }
1751
1752 if (Instance->FailedIaAddressCount == Instance->DeclineAddressCount) {
1753 //
1754 // The checking on all addresses are finished.
1755 //
1756 if (Instance->DeclineAddressCount != 0) {
1757 //
1758 // Decline those duplicates.
1759 //
1760 if (Instance->Dhcp6 != NULL) {
1761 Instance->Dhcp6->Decline (
1762 Instance->Dhcp6,
1763 Instance->DeclineAddressCount,
1764 Instance->DeclineAddress
1765 );
1766 }
1767 }
1768
1769 if (Instance->DeclineAddress != NULL) {
1770 FreePool (Instance->DeclineAddress);
1771 }
1772 Instance->DeclineAddress = NULL;
1773 Instance->DeclineAddressCount = 0;
1774 }
1775 }
1776
1777 /**
1778 The event handle routine when DHCPv6 process is finished or is updated.
1779
1780 @param[in] Event Not used.
1781 @param[in] Context The pointer to the IP6 configuration instance data.
1782
1783 **/
1784 VOID
1785 EFIAPI
1786 Ip6ConfigOnDhcp6Event (
1787 IN EFI_EVENT Event,
1788 IN VOID *Context
1789 )
1790 {
1791 IP6_CONFIG_INSTANCE *Instance;
1792 EFI_DHCP6_PROTOCOL *Dhcp6;
1793 EFI_STATUS Status;
1794 EFI_DHCP6_MODE_DATA Dhcp6ModeData;
1795 EFI_DHCP6_IA *Ia;
1796 EFI_DHCP6_IA_ADDRESS *IaAddr;
1797 UINT32 Index;
1798 IP6_SERVICE *IpSb;
1799 IP6_ADDRESS_INFO *AddrInfo;
1800 IP6_INTERFACE *IpIf;
1801
1802 Instance = (IP6_CONFIG_INSTANCE *) Context;
1803
1804 if ((Instance->Policy != Ip6ConfigPolicyAutomatic) || Instance->OtherInfoOnly) {
1805 //
1806 // IPv6 is not operating in the automatic policy now or
1807 // the DHCPv6 information request message exchange is aborted.
1808 //
1809 return ;
1810 }
1811
1812 //
1813 // The stateful address autoconfiguration is done or updated.
1814 //
1815 Dhcp6 = Instance->Dhcp6;
1816
1817 Status = Dhcp6->GetModeData (Dhcp6, &Dhcp6ModeData, NULL);
1818 if (EFI_ERROR (Status)) {
1819 return ;
1820 }
1821
1822 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1823 IpIf = IpSb->DefaultInterface;
1824 Ia = Dhcp6ModeData.Ia;
1825 IaAddr = Ia->IaAddress;
1826
1827 if (Instance->DeclineAddress != NULL) {
1828 FreePool (Instance->DeclineAddress);
1829 }
1830
1831 Instance->DeclineAddress = (EFI_IPv6_ADDRESS *) AllocatePool (Ia->IaAddressCount * sizeof (EFI_IPv6_ADDRESS));
1832 if (Instance->DeclineAddress == NULL) {
1833 goto ON_EXIT;
1834 }
1835
1836 Instance->FailedIaAddressCount = Ia->IaAddressCount;
1837 Instance->DeclineAddressCount = 0;
1838
1839 for (Index = 0; Index < Ia->IaAddressCount; Index++, IaAddr++) {
1840 if (Ia->IaAddress[Index].ValidLifetime != 0 && Ia->State == Dhcp6Bound) {
1841 //
1842 // Set this address, either it's a new address or with updated lifetimes.
1843 // An appropriate prefix length will be set.
1844 //
1845 Ip6SetAddress (
1846 IpIf,
1847 &IaAddr->IpAddress,
1848 FALSE,
1849 0,
1850 IaAddr->ValidLifetime,
1851 IaAddr->PreferredLifetime,
1852 Ip6ConfigSetStatefulAddrCallback,
1853 Instance
1854 );
1855 } else {
1856 //
1857 // discard this address, artificially decrease the count as if this address
1858 // passed DAD.
1859 //
1860 if (Ip6IsOneOfSetAddress (IpSb, &IaAddr->IpAddress, NULL, &AddrInfo)) {
1861 ASSERT (AddrInfo != NULL);
1862 Ip6RemoveAddr (
1863 IpSb,
1864 &IpIf->AddressList,
1865 &IpIf->AddressCount,
1866 &AddrInfo->Address,
1867 AddrInfo->PrefixLength
1868 );
1869 }
1870
1871 if (Instance->FailedIaAddressCount > 0) {
1872 Instance->FailedIaAddressCount--;
1873 }
1874 }
1875 }
1876
1877 //
1878 // Parse the Reply packet to get the options we need.
1879 //
1880 if (Dhcp6ModeData.Ia->ReplyPacket != NULL) {
1881 Ip6ConfigParseDhcpReply (Dhcp6, Instance, Dhcp6ModeData.Ia->ReplyPacket);
1882 }
1883
1884 ON_EXIT:
1885
1886 FreePool (Dhcp6ModeData.ClientId);
1887 FreePool (Dhcp6ModeData.Ia);
1888 }
1889
1890 /**
1891 The event process routine when the DHCPv6 server is answered with a reply packet
1892 for an information request.
1893
1894 @param[in] This Points to the EFI_DHCP6_PROTOCOL.
1895 @param[in] Context The pointer to the IP6 configuration instance data.
1896 @param[in] Packet The DHCPv6 reply packet.
1897
1898 @retval EFI_SUCCESS The DNS server address was retrieved from the reply packet.
1899 @retval EFI_NOT_READY The reply packet does not contain the DNS server option, or
1900 the DNS server address is not valid.
1901
1902 **/
1903 EFI_STATUS
1904 EFIAPI
1905 Ip6ConfigOnDhcp6Reply (
1906 IN EFI_DHCP6_PROTOCOL *This,
1907 IN VOID *Context,
1908 IN EFI_DHCP6_PACKET *Packet
1909 )
1910 {
1911 return Ip6ConfigParseDhcpReply (This, (IP6_CONFIG_INSTANCE *) Context, Packet);
1912 }
1913
1914 /**
1915 The event process routine when the DHCPv6 service binding protocol is installed
1916 in the system.
1917
1918 @param[in] Event Not used.
1919 @param[in] Context The pointer to the IP6 config instance data.
1920
1921 **/
1922 VOID
1923 EFIAPI
1924 Ip6ConfigOnDhcp6SbInstalled (
1925 IN EFI_EVENT Event,
1926 IN VOID *Context
1927 )
1928 {
1929 IP6_CONFIG_INSTANCE *Instance;
1930
1931 Instance = (IP6_CONFIG_INSTANCE *) Context;
1932
1933 if ((Instance->Dhcp6Handle != NULL) || (Instance->Policy != Ip6ConfigPolicyAutomatic)) {
1934 //
1935 // The DHCP6 child is already created or the policy is no longer AUTOMATIC.
1936 //
1937 return ;
1938 }
1939
1940 Ip6ConfigStartStatefulAutoConfig (Instance, Instance->OtherInfoOnly);
1941 }
1942
1943 /**
1944 Set the configuration for the EFI IPv6 network stack running on the communication
1945 device this EFI IPv6 Configuration Protocol instance manages.
1946
1947 This function is used to set the configuration data of type DataType for the EFI
1948 IPv6 network stack that is running on the communication device that this EFI IPv6
1949 Configuration Protocol instance manages.
1950
1951 DataSize is used to calculate the count of structure instances in the Data for
1952 a DataType in which multiple structure instances are allowed.
1953
1954 This function is always non-blocking. When setting some type of configuration data,
1955 an asynchronous process is invoked to check the correctness of the data, such as
1956 performing Duplicate Address Detection on the manually set local IPv6 addresses.
1957 EFI_NOT_READY is returned immediately to indicate that such an asynchronous process
1958 is invoked, and the process is not finished yet. The caller wanting to get the result
1959 of the asynchronous process is required to call RegisterDataNotify() to register an
1960 event on the specified configuration data. Once the event is signaled, the caller
1961 can call GetData() to obtain the configuration data and know the result.
1962 For other types of configuration data that do not require an asynchronous configuration
1963 process, the result of the operation is immediately returned.
1964
1965 @param[in] This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
1966 @param[in] DataType The type of data to set.
1967 @param[in] DataSize Size of the buffer pointed to by Data in bytes.
1968 @param[in] Data The data buffer to set. The type of the data buffer is
1969 associated with the DataType.
1970
1971 @retval EFI_SUCCESS The specified configuration data for the EFI IPv6
1972 network stack was set successfully.
1973 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
1974 - This is NULL.
1975 - One or more fields in Data and DataSizedo not match the
1976 requirement of the data type indicated by DataType.
1977 @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified
1978 configuration data cannot be set under the current policy.
1979 @retval EFI_ACCESS_DENIED Another set operation on the specified configuration
1980 data is already in process.
1981 @retval EFI_NOT_READY An asynchronous process was invoked to set the specified
1982 configuration data, and the process is not finished yet.
1983 @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type
1984 indicated by DataType.
1985 @retval EFI_UNSUPPORTED This DataType is not supported.
1986 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1987 @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.
1988
1989 **/
1990 EFI_STATUS
1991 EFIAPI
1992 EfiIp6ConfigSetData (
1993 IN EFI_IP6_CONFIG_PROTOCOL *This,
1994 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
1995 IN UINTN DataSize,
1996 IN VOID *Data
1997 )
1998 {
1999 EFI_TPL OldTpl;
2000 EFI_STATUS Status;
2001 IP6_CONFIG_INSTANCE *Instance;
2002 IP6_SERVICE *IpSb;
2003
2004 if ((This == NULL) || (Data == NULL && DataSize != 0) || (Data != NULL && DataSize == 0)) {
2005 return EFI_INVALID_PARAMETER;
2006 }
2007
2008 if (DataType >= Ip6ConfigDataTypeMaximum) {
2009 return EFI_UNSUPPORTED;
2010 }
2011
2012 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2013 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2014 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
2015
2016 if (IpSb->LinkLocalDadFail) {
2017 return EFI_DEVICE_ERROR;
2018 }
2019
2020 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2021
2022 Status = Instance->DataItem[DataType].Status;
2023 if (Status != EFI_NOT_READY) {
2024
2025 if (Instance->DataItem[DataType].SetData == NULL) {
2026 //
2027 // This type of data is readonly.
2028 //
2029 Status = EFI_WRITE_PROTECTED;
2030 } else {
2031
2032 Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);
2033 if (!EFI_ERROR (Status)) {
2034 //
2035 // Fire up the events registered with this type of data.
2036 //
2037 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);
2038 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
2039 } else if (Status == EFI_ABORTED) {
2040 //
2041 // The SetData is aborted because the data to set is the same with
2042 // the one maintained.
2043 //
2044 Status = EFI_SUCCESS;
2045 NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);
2046 }
2047 }
2048 } else {
2049 //
2050 // Another asynchronous process is on the way.
2051 //
2052 Status = EFI_ACCESS_DENIED;
2053 }
2054
2055 gBS->RestoreTPL (OldTpl);
2056
2057 return Status;
2058 }
2059
2060 /**
2061 Get the configuration data for the EFI IPv6 network stack running on the communication
2062 device that this EFI IPv6 Configuration Protocol instance manages.
2063
2064 This function returns the configuration data of type DataType for the EFI IPv6 network
2065 stack running on the communication device that this EFI IPv6 Configuration Protocol instance
2066 manages.
2067
2068 The caller is responsible for allocating the buffer used to return the specified
2069 configuration data. The required size will be returned to the caller if the size of
2070 the buffer is too small.
2071
2072 EFI_NOT_READY is returned if the specified configuration data is not ready due to an
2073 asynchronous configuration process already in progress. The caller can call RegisterDataNotify()
2074 to register an event on the specified configuration data. Once the asynchronous configuration
2075 process is finished, the event will be signaled, and a subsequent GetData() call will return
2076 the specified configuration data.
2077
2078 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
2079 @param[in] DataType The type of data to get.
2080 @param[in, out] DataSize On input, in bytes, the size of Data. On output, in bytes, the
2081 size of buffer required to store the specified configuration data.
2082 @param[in] Data The data buffer in which the configuration data is returned. The
2083 type of the data buffer is associated with the DataType.
2084 This is an optional parameter that may be NULL.
2085
2086 @retval EFI_SUCCESS The specified configuration data was obtained successfully.
2087 @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
2088 - This is NULL.
2089 - DataSize is NULL.
2090 - Data is NULL if *DataSize is not zero.
2091 @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data,
2092 and the required size is returned in DataSize.
2093 @retval EFI_NOT_READY The specified configuration data is not ready due to an
2094 asynchronous configuration process already in progress.
2095 @retval EFI_NOT_FOUND The specified configuration data is not found.
2096
2097 **/
2098 EFI_STATUS
2099 EFIAPI
2100 EfiIp6ConfigGetData (
2101 IN EFI_IP6_CONFIG_PROTOCOL *This,
2102 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
2103 IN OUT UINTN *DataSize,
2104 IN VOID *Data OPTIONAL
2105 )
2106 {
2107 EFI_TPL OldTpl;
2108 EFI_STATUS Status;
2109 IP6_CONFIG_INSTANCE *Instance;
2110 IP6_CONFIG_DATA_ITEM *DataItem;
2111
2112 if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {
2113 return EFI_INVALID_PARAMETER;
2114 }
2115
2116 if (DataType >= Ip6ConfigDataTypeMaximum) {
2117 return EFI_NOT_FOUND;
2118 }
2119
2120 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2121
2122 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2123 DataItem = &Instance->DataItem[DataType];
2124
2125 Status = Instance->DataItem[DataType].Status;
2126 if (!EFI_ERROR (Status)) {
2127
2128 if (DataItem->GetData != NULL) {
2129
2130 Status = DataItem->GetData (Instance, DataSize, Data);
2131 } else if (*DataSize < Instance->DataItem[DataType].DataSize) {
2132 //
2133 // Update the buffer length.
2134 //
2135 *DataSize = Instance->DataItem[DataType].DataSize;
2136 Status = EFI_BUFFER_TOO_SMALL;
2137 } else {
2138
2139 *DataSize = Instance->DataItem[DataType].DataSize;
2140 CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);
2141 }
2142 }
2143
2144 gBS->RestoreTPL (OldTpl);
2145
2146 return Status;
2147 }
2148
2149 /**
2150 Register an event that is signaled whenever a configuration process on the specified
2151 configuration data is done.
2152
2153 This function registers an event that is to be signaled whenever a configuration
2154 process on the specified configuration data is performed. An event can be registered
2155 for a different DataType simultaneously. The caller is responsible for determining
2156 which type of configuration data causes the signaling of the event in such an event.
2157
2158 @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
2159 @param[in] DataType The type of data to unregister the event for.
2160 @param[in] Event The event to register.
2161
2162 @retval EFI_SUCCESS The notification event for the specified configuration data is
2163 registered.
2164 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2165 @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not
2166 supported.
2167 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
2168 @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.
2169
2170 **/
2171 EFI_STATUS
2172 EFIAPI
2173 EfiIp6ConfigRegisterDataNotify (
2174 IN EFI_IP6_CONFIG_PROTOCOL *This,
2175 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
2176 IN EFI_EVENT Event
2177 )
2178 {
2179 EFI_TPL OldTpl;
2180 EFI_STATUS Status;
2181 IP6_CONFIG_INSTANCE *Instance;
2182 NET_MAP *EventMap;
2183 NET_MAP_ITEM *Item;
2184
2185 if ((This == NULL) || (Event == NULL)) {
2186 return EFI_INVALID_PARAMETER;
2187 }
2188
2189 if (DataType >= Ip6ConfigDataTypeMaximum) {
2190 return EFI_UNSUPPORTED;
2191 }
2192
2193 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2194
2195 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2196 EventMap = &Instance->DataItem[DataType].EventMap;
2197
2198 //
2199 // Check whether this event is already registered for this DataType.
2200 //
2201 Item = NetMapFindKey (EventMap, Event);
2202 if (Item == NULL) {
2203
2204 Status = NetMapInsertTail (EventMap, Event, NULL);
2205
2206 if (EFI_ERROR (Status)) {
2207
2208 Status = EFI_OUT_OF_RESOURCES;
2209 }
2210
2211 } else {
2212
2213 Status = EFI_ACCESS_DENIED;
2214 }
2215
2216 gBS->RestoreTPL (OldTpl);
2217
2218 return Status;
2219 }
2220
2221 /**
2222 Remove a previously registered event for the specified configuration data.
2223
2224 @param This The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
2225 @param DataType The type of data to remove from the previously
2226 registered event.
2227 @param Event The event to be unregistered.
2228
2229 @retval EFI_SUCCESS The event registered for the specified
2230 configuration data was removed.
2231 @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2232 @retval EFI_NOT_FOUND The Event has not been registered for the
2233 specified DataType.
2234
2235 **/
2236 EFI_STATUS
2237 EFIAPI
2238 EfiIp6ConfigUnregisterDataNotify (
2239 IN EFI_IP6_CONFIG_PROTOCOL *This,
2240 IN EFI_IP6_CONFIG_DATA_TYPE DataType,
2241 IN EFI_EVENT Event
2242 )
2243 {
2244 EFI_TPL OldTpl;
2245 EFI_STATUS Status;
2246 IP6_CONFIG_INSTANCE *Instance;
2247 NET_MAP_ITEM *Item;
2248
2249 if ((This == NULL) || (Event == NULL)) {
2250 return EFI_INVALID_PARAMETER;
2251 }
2252
2253 if (DataType >= Ip6ConfigDataTypeMaximum) {
2254 return EFI_NOT_FOUND;
2255 }
2256
2257 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2258
2259 Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2260
2261 Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);
2262 if (Item != NULL) {
2263
2264 NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);
2265 Status = EFI_SUCCESS;
2266 } else {
2267
2268 Status = EFI_NOT_FOUND;
2269 }
2270
2271 gBS->RestoreTPL (OldTpl);
2272
2273 return Status;
2274 }
2275
2276 /**
2277 Initialize an IP6_CONFIG_INSTANCE.
2278
2279 @param[out] Instance The buffer of IP6_CONFIG_INSTANCE to be initialized.
2280
2281 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
2282 @retval EFI_SUCCESS The IP6_CONFIG_INSTANCE initialized successfully.
2283
2284 **/
2285 EFI_STATUS
2286 Ip6ConfigInitInstance (
2287 OUT IP6_CONFIG_INSTANCE *Instance
2288 )
2289 {
2290 IP6_SERVICE *IpSb;
2291 IP6_CONFIG_INSTANCE *TmpInstance;
2292 LIST_ENTRY *Entry;
2293 EFI_STATUS Status;
2294 UINTN Index;
2295 UINT16 IfIndex;
2296 IP6_CONFIG_DATA_ITEM *DataItem;
2297
2298 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2299
2300 Instance->Signature = IP6_CONFIG_INSTANCE_SIGNATURE;
2301
2302 //
2303 // Determine the index of this interface.
2304 //
2305 IfIndex = 0;
2306 NET_LIST_FOR_EACH (Entry, &mIp6ConfigInstanceList) {
2307 TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_CONFIG_INSTANCE, Link, IP6_CONFIG_INSTANCE_SIGNATURE);
2308
2309 if (TmpInstance->IfIndex > IfIndex) {
2310 //
2311 // There is a sequence hole because some interface is down.
2312 //
2313 break;
2314 }
2315
2316 IfIndex++;
2317 }
2318
2319 Instance->IfIndex = IfIndex;
2320 NetListInsertBefore (Entry, &Instance->Link);
2321
2322 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
2323 //
2324 // Initialize the event map for each data item.
2325 //
2326 NetMapInit (&Instance->DataItem[Index].EventMap);
2327 }
2328
2329 //
2330 // Initialize the NET_MAPs used for DAD on manually configured source addresses.
2331 //
2332 NetMapInit (&Instance->DadFailedMap);
2333 NetMapInit (&Instance->DadPassedMap);
2334
2335 //
2336 // Initialize each data type: associate storage and set data size for the
2337 // fixed size data types, hook the SetData function, set the data attribute.
2338 //
2339 DataItem = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];
2340 DataItem->GetData = Ip6ConfigGetIfInfo;
2341 DataItem->Data.Ptr = &Instance->InterfaceInfo;
2342 DataItem->DataSize = sizeof (Instance->InterfaceInfo);
2343 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);
2344 Ip6ConfigInitIfInfo (IpSb, &Instance->InterfaceInfo);
2345
2346 DataItem = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];
2347 DataItem->SetData = Ip6ConfigSetAltIfId;
2348 DataItem->Data.Ptr = &Instance->AltIfId;
2349 DataItem->DataSize = sizeof (Instance->AltIfId);
2350 DataItem->Status = EFI_NOT_FOUND;
2351 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2352
2353 DataItem = &Instance->DataItem[Ip6ConfigDataTypePolicy];
2354 DataItem->SetData = Ip6ConfigSetPolicy;
2355 DataItem->Data.Ptr = &Instance->Policy;
2356 DataItem->DataSize = sizeof (Instance->Policy);
2357 Instance->Policy = Ip6ConfigPolicyManual;
2358 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2359
2360 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits];
2361 DataItem->SetData = Ip6ConfigSetDadXmits;
2362 DataItem->Data.Ptr = &Instance->DadXmits;
2363 DataItem->DataSize = sizeof (Instance->DadXmits);
2364 Instance->DadXmits.DupAddrDetectTransmits = IP6_CONFIG_DEFAULT_DAD_XMITS;
2365 SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2366
2367 DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
2368 DataItem->SetData = Ip6ConfigSetManualAddress;
2369 DataItem->Status = EFI_NOT_FOUND;
2370
2371 DataItem = &Instance->DataItem[Ip6ConfigDataTypeGateway];
2372 DataItem->SetData = Ip6ConfigSetGateway;
2373 DataItem->Status = EFI_NOT_FOUND;
2374
2375 DataItem = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
2376 DataItem->SetData = Ip6ConfigSetDnsServer;
2377 DataItem->Status = EFI_NOT_FOUND;
2378
2379 //
2380 // Create the event used for DHCP.
2381 //
2382 Status = gBS->CreateEvent (
2383 EVT_NOTIFY_SIGNAL,
2384 TPL_CALLBACK,
2385 Ip6ConfigOnDhcp6Event,
2386 Instance,
2387 &Instance->Dhcp6Event
2388 );
2389 ASSERT_EFI_ERROR (Status);
2390
2391 Instance->Configured = TRUE;
2392
2393 //
2394 // Try to read the config data from NV variable.
2395 //
2396 Status = Ip6ConfigReadConfigData (IpSb->MacString, Instance);
2397 if (Status == EFI_NOT_FOUND) {
2398 //
2399 // The NV variable is not set, so generate a random IAID, and write down the
2400 // fresh new configuration as the NV variable now.
2401 //
2402 Instance->IaId = NET_RANDOM (NetRandomInitSeed ());
2403
2404 for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) {
2405 Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 3) & 31));
2406 }
2407
2408 Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
2409 } else if (EFI_ERROR (Status)) {
2410 return Status;
2411 }
2412
2413 Instance->Ip6Config.SetData = EfiIp6ConfigSetData;
2414 Instance->Ip6Config.GetData = EfiIp6ConfigGetData;
2415 Instance->Ip6Config.RegisterDataNotify = EfiIp6ConfigRegisterDataNotify;
2416 Instance->Ip6Config.UnregisterDataNotify = EfiIp6ConfigUnregisterDataNotify;
2417
2418
2419 //
2420 // Publish the IP6 configuration form
2421 //
2422 return Ip6ConfigFormInit (Instance);
2423 }
2424
2425 /**
2426 Release an IP6_CONFIG_INSTANCE.
2427
2428 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.
2429
2430 **/
2431 VOID
2432 Ip6ConfigCleanInstance (
2433 IN OUT IP6_CONFIG_INSTANCE *Instance
2434 )
2435 {
2436 UINTN Index;
2437 IP6_CONFIG_DATA_ITEM *DataItem;
2438
2439 if (Instance->DeclineAddress != NULL) {
2440 FreePool (Instance->DeclineAddress);
2441 }
2442
2443 if (!Instance->Configured) {
2444 return ;
2445 }
2446
2447 if (Instance->Dhcp6Handle != NULL) {
2448
2449 Ip6ConfigDestroyDhcp6 (Instance);
2450 }
2451
2452 //
2453 // Close the event.
2454 //
2455 if (Instance->Dhcp6Event != NULL) {
2456 gBS->CloseEvent (Instance->Dhcp6Event);
2457 }
2458
2459 NetMapClean (&Instance->DadPassedMap);
2460 NetMapClean (&Instance->DadFailedMap);
2461
2462 for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
2463
2464 DataItem = &Instance->DataItem[Index];
2465
2466 if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
2467 if (DataItem->Data.Ptr != NULL) {
2468 FreePool (DataItem->Data.Ptr);
2469 }
2470 DataItem->Data.Ptr = NULL;
2471 DataItem->DataSize = 0;
2472 }
2473
2474 NetMapClean (&Instance->DataItem[Index].EventMap);
2475 }
2476
2477 Ip6ConfigFormUnload (Instance);
2478
2479 RemoveEntryList (&Instance->Link);
2480 }
2481
2482 /**
2483 Destroy the Dhcp6 child in IP6_CONFIG_INSTANCE and release the resources.
2484
2485 @param[in, out] Instance The buffer of IP6_CONFIG_INSTANCE to be freed.
2486
2487 @retval EFI_SUCCESS The child was successfully destroyed.
2488 @retval Others Failed to destroy the child.
2489
2490 **/
2491 EFI_STATUS
2492 Ip6ConfigDestroyDhcp6 (
2493 IN OUT IP6_CONFIG_INSTANCE *Instance
2494 )
2495 {
2496 IP6_SERVICE *IpSb;
2497 EFI_STATUS Status;
2498 EFI_DHCP6_PROTOCOL *Dhcp6;
2499
2500 Dhcp6 = Instance->Dhcp6;
2501 ASSERT (Dhcp6 != NULL);
2502
2503 Dhcp6->Stop (Dhcp6);
2504 Dhcp6->Configure (Dhcp6, NULL);
2505 Instance->Dhcp6 = NULL;
2506
2507 IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2508
2509 //
2510 // Close DHCPv6 protocol and destroy the child.
2511 //
2512 Status = gBS->CloseProtocol (
2513 Instance->Dhcp6Handle,
2514 &gEfiDhcp6ProtocolGuid,
2515 IpSb->Image,
2516 IpSb->Controller
2517 );
2518 if (EFI_ERROR (Status)) {
2519 return Status;
2520 }
2521
2522 Status = NetLibDestroyServiceChild (
2523 IpSb->Controller,
2524 IpSb->Image,
2525 &gEfiDhcp6ServiceBindingProtocolGuid,
2526 Instance->Dhcp6Handle
2527 );
2528
2529 Instance->Dhcp6Handle = NULL;
2530
2531 return Status;
2532 }
2533