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