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