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