• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   The implementation of EFI IPv6 Configuration Protocol.
3 
4   Copyright (c) 2009 - 2017, 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 parameters 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 (DHCP6_OPT_ORO);
223   Oro->OpLen                  = HTONS (2);
224   *((UINT16 *) &Oro->Data[0]) = HTONS (DHCP6_OPT_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     // Clean the ManualAddress, Gateway and DnsServers, shrink the variable
670     // data size, and fire up all the related events.
671     //
672     DataItem           = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
673     if (DataItem->Data.Ptr != NULL) {
674       FreePool (DataItem->Data.Ptr);
675     }
676     DataItem->Data.Ptr = NULL;
677     DataItem->DataSize = 0;
678     DataItem->Status   = EFI_NOT_FOUND;
679     NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);
680 
681     DataItem           = &Instance->DataItem[Ip6ConfigDataTypeGateway];
682     if (DataItem->Data.Ptr != NULL) {
683       FreePool (DataItem->Data.Ptr);
684     }
685     DataItem->Data.Ptr = NULL;
686     DataItem->DataSize = 0;
687     DataItem->Status   = EFI_NOT_FOUND;
688     NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);
689 
690     DataItem           = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
691     DataItem->Data.Ptr = NULL;
692     DataItem->DataSize = 0;
693     DataItem->Status   = EFI_NOT_FOUND;
694     NetMapIterate (&DataItem->EventMap, Ip6ConfigSignalEvent, NULL);
695 
696     if (NewPolicy == Ip6ConfigPolicyManual) {
697       //
698       // The policy is changed from automatic to manual. Stop the DHCPv6 process
699       // and destroy the DHCPv6 child.
700       //
701       if (Instance->Dhcp6Handle != NULL) {
702         Ip6ConfigDestroyDhcp6 (Instance);
703       }
704     }
705 
706     IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
707     Ip6ConfigOnPolicyChanged (IpSb, NewPolicy);
708 
709     Instance->Policy = NewPolicy;
710 
711     return EFI_SUCCESS;
712   }
713 }
714 
715 /**
716   The work function for EfiIp6ConfigSetData() to set the number of consecutive
717   Neighbor Solicitation messages sent while performing Duplicate Address Detection
718   on a tentative address. A value of ZERO indicates that Duplicate Address Detection
719   will not be performed on a tentative address.
720 
721   @param[in]     Instance The Instance Pointer to the IP6 config instance data.
722   @param[in]     DataSize Size of the buffer pointed to by Data in bytes.
723   @param[in]     Data     The data buffer to set.
724 
725   @retval EFI_BAD_BUFFER_SIZE  The DataSize does not match the size of the type.
726   @retval EFI_ABORTED          The new transmit count equals the current configuration.
727   @retval EFI_SUCCESS          The specified configuration data for the EFI IPv6
728                                network stack was set.
729 
730 **/
731 EFI_STATUS
Ip6ConfigSetDadXmits(IN IP6_CONFIG_INSTANCE * Instance,IN UINTN DataSize,IN VOID * Data)732 Ip6ConfigSetDadXmits (
733   IN IP6_CONFIG_INSTANCE  *Instance,
734   IN UINTN                DataSize,
735   IN VOID                 *Data
736   )
737 {
738   EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS  *OldDadXmits;
739 
740   if (DataSize != sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS)) {
741     return EFI_BAD_BUFFER_SIZE;
742   }
743 
744   OldDadXmits = Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits].Data.DadXmits;
745 
746   if ((*(UINT32 *) Data) == OldDadXmits->DupAddrDetectTransmits) {
747 
748     return EFI_ABORTED;
749   } else {
750 
751     OldDadXmits->DupAddrDetectTransmits = *((UINT32 *) Data);
752     return EFI_SUCCESS;
753   }
754 }
755 
756 /**
757   The callback function for Ip6SetAddr. The prototype is defined
758   as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed
759   for the manual address set by Ip6ConfigSetMaunualAddress.
760 
761   @param[in]     IsDadPassed   If TRUE, Duplicate Address Detection passed.
762   @param[in]     TargetAddress The tentative IPv6 address to be checked.
763   @param[in]     Context       Pointer to the IP6 configuration instance data.
764 
765 **/
766 VOID
Ip6ManualAddrDadCallback(IN BOOLEAN IsDadPassed,IN EFI_IPv6_ADDRESS * TargetAddress,IN VOID * Context)767 Ip6ManualAddrDadCallback (
768   IN BOOLEAN           IsDadPassed,
769   IN EFI_IPv6_ADDRESS  *TargetAddress,
770   IN VOID              *Context
771   )
772 {
773   IP6_CONFIG_INSTANCE            *Instance;
774   UINTN                          Index;
775   IP6_CONFIG_DATA_ITEM           *Item;
776   EFI_IP6_CONFIG_MANUAL_ADDRESS  *ManualAddr;
777   EFI_IP6_CONFIG_MANUAL_ADDRESS  *PassedAddr;
778   UINTN                          DadPassCount;
779   UINTN                          DadFailCount;
780   IP6_SERVICE                    *IpSb;
781 
782   Instance   = (IP6_CONFIG_INSTANCE *) Context;
783   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
784   Item       = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
785   ManualAddr = NULL;
786 
787   for (Index = 0; Index < Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS); Index++) {
788     //
789     // Find the original tag used to place into the NET_MAP.
790     //
791     ManualAddr = Item->Data.ManualAddress + Index;
792     if (EFI_IP6_EQUAL (TargetAddress, &ManualAddr->Address)) {
793       break;
794     }
795   }
796 
797   ASSERT (Index != Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
798 
799   if (IsDadPassed) {
800     NetMapInsertTail (&Instance->DadPassedMap, ManualAddr, NULL);
801   } else {
802     NetMapInsertTail (&Instance->DadFailedMap, ManualAddr, NULL);
803   }
804 
805   DadPassCount = NetMapGetCount (&Instance->DadPassedMap);
806   DadFailCount = NetMapGetCount (&Instance->DadFailedMap);
807 
808   if ((DadPassCount + DadFailCount) == (Item->DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS))) {
809     //
810     // All addresses have finished the configuration process.
811     //
812     if (DadFailCount != 0) {
813       //
814       // There is at least one duplicate address.
815       //
816       FreePool (Item->Data.Ptr);
817 
818       Item->DataSize = DadPassCount * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
819       if (Item->DataSize == 0) {
820         //
821         // All failed, bad luck.
822         //
823         Item->Data.Ptr = NULL;
824         Item->Status   = EFI_NOT_FOUND;
825       } else {
826         //
827         // Part of addresses are detected to be duplicates, so update the
828         // data with those passed.
829         //
830         PassedAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) AllocatePool (Item->DataSize);
831         ASSERT (PassedAddr != NULL);
832 
833         Item->Data.Ptr = PassedAddr;
834         Item->Status   = EFI_SUCCESS;
835 
836         while (!NetMapIsEmpty (&Instance->DadPassedMap)) {
837           ManualAddr = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) NetMapRemoveHead (&Instance->DadPassedMap, NULL);
838           CopyMem (PassedAddr, ManualAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
839 
840           PassedAddr++;
841         }
842 
843         ASSERT ((UINTN) PassedAddr - (UINTN) Item->Data.Ptr == Item->DataSize);
844       }
845     } else {
846       //
847       // All addresses are valid.
848       //
849       Item->Status = EFI_SUCCESS;
850     }
851 
852     //
853     // Remove the tags we put in the NET_MAPs.
854     //
855     while (!NetMapIsEmpty (&Instance->DadFailedMap)) {
856       NetMapRemoveHead (&Instance->DadFailedMap, NULL);
857     }
858 
859     while (!NetMapIsEmpty (&Instance->DadPassedMap)) {
860       NetMapRemoveHead (&Instance->DadPassedMap, NULL);
861     }
862 
863     //
864     // Signal the waiting events.
865     //
866     NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);
867     IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
868     Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
869   }
870 }
871 
872 /**
873   The work function for EfiIp6ConfigSetData() to set the station addresses manually
874   for the EFI IPv6 network stack. It is only configurable when the policy is
875   Ip6ConfigPolicyManual.
876 
877   @param[in]     Instance Pointer to the IP6 configuration instance data.
878   @param[in]     DataSize Size of the buffer pointed to by Data in bytes.
879   @param[in]     Data     The data buffer to set.
880 
881   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
882   @retval EFI_WRITE_PROTECTED   The specified configuration data cannot be set
883                                 under the current policy.
884   @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
885   @retval EFI_OUT_OF_RESOURCES  Fail to allocate resource to complete the operation.
886   @retval EFI_NOT_READY         An asynchrous process is invoked to set the specified
887                                 configuration data, and the process is not finished.
888   @retval EFI_ABORTED           The manual addresses to be set equal current
889                                 configuration.
890   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
891                                 network stack was set.
892 
893 **/
894 EFI_STATUS
Ip6ConfigSetMaunualAddress(IN IP6_CONFIG_INSTANCE * Instance,IN UINTN DataSize,IN VOID * Data)895 Ip6ConfigSetMaunualAddress (
896   IN IP6_CONFIG_INSTANCE  *Instance,
897   IN UINTN                DataSize,
898   IN VOID                 *Data
899   )
900 {
901   EFI_IP6_CONFIG_MANUAL_ADDRESS  *NewAddress;
902   EFI_IP6_CONFIG_MANUAL_ADDRESS  *TmpAddress;
903   IP6_CONFIG_DATA_ITEM           *DataItem;
904   UINTN                          NewAddressCount;
905   UINTN                          Index1;
906   UINTN                          Index2;
907   IP6_SERVICE                    *IpSb;
908   IP6_ADDRESS_INFO               *CurrentAddrInfo;
909   IP6_ADDRESS_INFO               *Copy;
910   LIST_ENTRY                     CurrentSourceList;
911   UINT32                         CurrentSourceCount;
912   LIST_ENTRY                     *Entry;
913   LIST_ENTRY                     *Entry2;
914   IP6_INTERFACE                  *IpIf;
915   IP6_PREFIX_LIST_ENTRY          *PrefixEntry;
916   EFI_STATUS                     Status;
917   BOOLEAN                        IsUpdated;
918 
919   ASSERT (Instance->DataItem[Ip6ConfigDataTypeManualAddress].Status != EFI_NOT_READY);
920 
921   if (((DataSize % sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)) != 0) || (DataSize == 0)) {
922     return EFI_BAD_BUFFER_SIZE;
923   }
924 
925   if (Instance->Policy != Ip6ConfigPolicyManual) {
926     return EFI_WRITE_PROTECTED;
927   }
928 
929   NewAddressCount = DataSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
930   NewAddress      = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) Data;
931 
932   for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {
933 
934     if (NetIp6IsLinkLocalAddr (&NewAddress->Address)    ||
935         !NetIp6IsValidUnicast (&NewAddress->Address)    ||
936         (NewAddress->PrefixLength > 128)
937         ) {
938       //
939       // make sure the IPv6 address is unicast and not link-local address &&
940       // the prefix length is valid.
941       //
942       return EFI_INVALID_PARAMETER;
943     }
944 
945     TmpAddress = NewAddress + 1;
946     for (Index2 = Index1 + 1; Index2 < NewAddressCount; Index2++, TmpAddress++) {
947       //
948       // Any two addresses in the array can't be equal.
949       //
950       if (EFI_IP6_EQUAL (&TmpAddress->Address, &NewAddress->Address)) {
951 
952         return EFI_INVALID_PARAMETER;
953       }
954     }
955   }
956 
957   IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
958 
959   //
960   // Build the current source address list.
961   //
962   InitializeListHead (&CurrentSourceList);
963   CurrentSourceCount = 0;
964 
965   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
966     IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
967 
968     NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {
969       CurrentAddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
970 
971       Copy            = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), CurrentAddrInfo);
972       if (Copy == NULL) {
973         break;
974       }
975 
976       InsertTailList (&CurrentSourceList, &Copy->Link);
977       CurrentSourceCount++;
978     }
979   }
980 
981   //
982   // Update the value... a long journey starts
983   //
984   NewAddress = AllocateCopyPool (DataSize, Data);
985   if (NewAddress == NULL) {
986     Ip6RemoveAddr (NULL, &CurrentSourceList, &CurrentSourceCount, NULL, 0);
987 
988     return EFI_OUT_OF_RESOURCES;
989   }
990 
991   //
992   // Store the new data, and init the DataItem status to EFI_NOT_READY because
993   // we may have an asynchronous configuration process.
994   //
995   DataItem = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
996   if (DataItem->Data.Ptr != NULL) {
997     FreePool (DataItem->Data.Ptr);
998   }
999   DataItem->Data.Ptr = NewAddress;
1000   DataItem->DataSize = DataSize;
1001   DataItem->Status   = EFI_NOT_READY;
1002 
1003   //
1004   // Trigger DAD, it's an asynchronous process.
1005   //
1006   IsUpdated  = FALSE;
1007 
1008   for (Index1 = 0; Index1 < NewAddressCount; Index1++, NewAddress++) {
1009     if (Ip6IsOneOfSetAddress (IpSb, &NewAddress->Address, NULL, &CurrentAddrInfo)) {
1010       ASSERT (CurrentAddrInfo != NULL);
1011       //
1012       // Remove this already existing source address from the CurrentSourceList
1013       // built before.
1014       //
1015       Ip6RemoveAddr (
1016         NULL,
1017         &CurrentSourceList,
1018         &CurrentSourceCount,
1019         &CurrentAddrInfo->Address,
1020         128
1021         );
1022 
1023       //
1024       // If the new address's prefix length is not specified, just use the previous configured
1025       // prefix length for this address.
1026       //
1027       if (NewAddress->PrefixLength == 0) {
1028         NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;
1029       }
1030 
1031       //
1032       // This manual address is already in use, see whether prefix length is changed.
1033       //
1034       if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {
1035         //
1036         // Remove the on-link prefix table, the route entry will be removed
1037         // implicitly.
1038         //
1039         PrefixEntry = Ip6FindPrefixListEntry (
1040                         IpSb,
1041                         TRUE,
1042                         CurrentAddrInfo->PrefixLength,
1043                         &CurrentAddrInfo->Address
1044                         );
1045         if (PrefixEntry != NULL) {
1046           Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);
1047         }
1048 
1049         //
1050         // Save the prefix length.
1051         //
1052         CurrentAddrInfo->PrefixLength = NewAddress->PrefixLength;
1053         IsUpdated = TRUE;
1054       }
1055 
1056       //
1057       // create a new on-link prefix entry.
1058       //
1059       PrefixEntry = Ip6FindPrefixListEntry (
1060                       IpSb,
1061                       TRUE,
1062                       NewAddress->PrefixLength,
1063                       &NewAddress->Address
1064                       );
1065       if (PrefixEntry == NULL) {
1066         Ip6CreatePrefixListEntry (
1067           IpSb,
1068           TRUE,
1069           (UINT32) IP6_INFINIT_LIFETIME,
1070           (UINT32) IP6_INFINIT_LIFETIME,
1071           NewAddress->PrefixLength,
1072           &NewAddress->Address
1073           );
1074       }
1075 
1076       CurrentAddrInfo->IsAnycast = NewAddress->IsAnycast;
1077       //
1078       // Artificially mark this address passed DAD be'coz it is already in use.
1079       //
1080       Ip6ManualAddrDadCallback (TRUE, &NewAddress->Address, Instance);
1081     } else {
1082       //
1083       // A new address.
1084       //
1085       IsUpdated = TRUE;
1086 
1087       //
1088       // Set the new address, this will trigger DAD and activate the address if
1089       // DAD succeeds.
1090       //
1091       Ip6SetAddress (
1092         IpSb->DefaultInterface,
1093         &NewAddress->Address,
1094         NewAddress->IsAnycast,
1095         NewAddress->PrefixLength,
1096         (UINT32) IP6_INFINIT_LIFETIME,
1097         (UINT32) IP6_INFINIT_LIFETIME,
1098         Ip6ManualAddrDadCallback,
1099         Instance
1100         );
1101     }
1102   }
1103 
1104   //
1105   // Check the CurrentSourceList, it now contains those addresses currently in
1106   // use and will be removed.
1107   //
1108   IpIf = IpSb->DefaultInterface;
1109 
1110   while (!IsListEmpty (&CurrentSourceList)) {
1111     IsUpdated = TRUE;
1112 
1113     CurrentAddrInfo = NET_LIST_HEAD (&CurrentSourceList, IP6_ADDRESS_INFO, Link);
1114 
1115     //
1116     // This local address is going to be removed, the IP instances that are
1117     // currently using it will be destroyed.
1118     //
1119     Ip6RemoveAddr (
1120       IpSb,
1121       &IpIf->AddressList,
1122       &IpIf->AddressCount,
1123       &CurrentAddrInfo->Address,
1124       128
1125       );
1126 
1127     //
1128     // Remove the on-link prefix table, the route entry will be removed
1129     // implicitly.
1130     //
1131     PrefixEntry = Ip6FindPrefixListEntry (
1132                     IpSb,
1133                     TRUE,
1134                     CurrentAddrInfo->PrefixLength,
1135                     &CurrentAddrInfo->Address
1136                     );
1137     if (PrefixEntry != NULL) {
1138       Ip6DestroyPrefixListEntry (IpSb, PrefixEntry, TRUE, FALSE);
1139     }
1140 
1141     RemoveEntryList (&CurrentAddrInfo->Link);
1142     FreePool (CurrentAddrInfo);
1143   }
1144 
1145   if (IsUpdated) {
1146     if (DataItem->Status == EFI_NOT_READY) {
1147       //
1148       // If DAD is disabled on this interface, the configuration process is
1149       // actually synchronous, and the data item's status will be changed to
1150       // the final status before we reach here, just check it.
1151       //
1152       Status = EFI_NOT_READY;
1153     } else {
1154       Status = EFI_SUCCESS;
1155     }
1156   } else {
1157     //
1158     // No update is taken, reset the status to success and return EFI_ABORTED.
1159     //
1160     DataItem->Status = EFI_SUCCESS;
1161     Status           = EFI_ABORTED;
1162   }
1163 
1164   return Status;
1165 }
1166 
1167 /**
1168   The work function for EfiIp6ConfigSetData() to set the gateway addresses manually
1169   for the EFI IPv6 network stack that is running on the communication device that
1170   this EFI IPv6 Configuration Protocol manages. It is not configurable when the policy is
1171   Ip6ConfigPolicyAutomatic. The gateway addresses must be unicast IPv6 addresses.
1172 
1173   @param[in]     Instance The pointer to the IP6 config instance data.
1174   @param[in]     DataSize The size of the buffer pointed to by Data in bytes.
1175   @param[in]     Data     The data buffer to set. This points to an array of
1176                           EFI_IPv6_ADDRESS instances.
1177 
1178   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
1179   @retval EFI_WRITE_PROTECTED   The specified configuration data cannot be set
1180                                 under the current policy.
1181   @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1182   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to complete the operation.
1183   @retval EFI_ABORTED           The manual gateway addresses to be set equal the
1184                                 current configuration.
1185   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
1186                                 network stack was set.
1187 
1188 **/
1189 EFI_STATUS
Ip6ConfigSetGateway(IN IP6_CONFIG_INSTANCE * Instance,IN UINTN DataSize,IN VOID * Data)1190 Ip6ConfigSetGateway (
1191   IN IP6_CONFIG_INSTANCE  *Instance,
1192   IN UINTN                DataSize,
1193   IN VOID                 *Data
1194   )
1195 {
1196   UINTN                 Index1;
1197   UINTN                 Index2;
1198   EFI_IPv6_ADDRESS      *OldGateway;
1199   EFI_IPv6_ADDRESS      *NewGateway;
1200   UINTN                 OldGatewayCount;
1201   UINTN                 NewGatewayCount;
1202   IP6_CONFIG_DATA_ITEM  *Item;
1203   BOOLEAN               OneRemoved;
1204   BOOLEAN               OneAdded;
1205   IP6_SERVICE           *IpSb;
1206   IP6_DEFAULT_ROUTER    *DefaultRouter;
1207   VOID                  *Tmp;
1208 
1209   if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {
1210     return EFI_BAD_BUFFER_SIZE;
1211   }
1212 
1213   if (Instance->Policy != Ip6ConfigPolicyManual) {
1214     return EFI_WRITE_PROTECTED;
1215   }
1216 
1217   NewGateway      = (EFI_IPv6_ADDRESS *) Data;
1218   NewGatewayCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
1219   for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1220 
1221     if (!NetIp6IsValidUnicast (NewGateway + Index1)) {
1222 
1223       return EFI_INVALID_PARAMETER;
1224     }
1225 
1226     for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {
1227       if (EFI_IP6_EQUAL (NewGateway + Index1, NewGateway + Index2)) {
1228         return EFI_INVALID_PARAMETER;
1229       }
1230     }
1231   }
1232 
1233   IpSb            = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1234   Item            = &Instance->DataItem[Ip6ConfigDataTypeGateway];
1235   OldGateway      = Item->Data.Gateway;
1236   OldGatewayCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);
1237   OneRemoved      = FALSE;
1238   OneAdded        = FALSE;
1239 
1240   if (NewGatewayCount != OldGatewayCount) {
1241     Tmp = AllocatePool (DataSize);
1242     if (Tmp == NULL) {
1243       return EFI_OUT_OF_RESOURCES;
1244     }
1245   } else {
1246     Tmp = NULL;
1247   }
1248 
1249   for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {
1250     //
1251     // Find the gateways that are no long in the new setting and remove them.
1252     //
1253     for (Index2 = 0; Index2 < NewGatewayCount; Index2++) {
1254       if (EFI_IP6_EQUAL (OldGateway + Index1, NewGateway + Index2)) {
1255         OneRemoved = TRUE;
1256         break;
1257       }
1258     }
1259 
1260     if (Index2 == NewGatewayCount) {
1261       //
1262       // Remove this default router.
1263       //
1264       DefaultRouter = Ip6FindDefaultRouter (IpSb, OldGateway + Index1);
1265       if (DefaultRouter != NULL) {
1266         Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
1267       }
1268     }
1269   }
1270 
1271   for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
1272 
1273     DefaultRouter = Ip6FindDefaultRouter (IpSb, NewGateway + Index1);
1274     if (DefaultRouter == NULL) {
1275       Ip6CreateDefaultRouter (IpSb, NewGateway + Index1, IP6_INF_ROUTER_LIFETIME);
1276       OneAdded = TRUE;
1277     }
1278   }
1279 
1280   if (!OneRemoved && !OneAdded) {
1281     Item->Status = EFI_SUCCESS;
1282     return EFI_ABORTED;
1283   } else {
1284 
1285     if (Tmp != NULL) {
1286       if (Item->Data.Ptr != NULL) {
1287         FreePool (Item->Data.Ptr);
1288       }
1289       Item->Data.Ptr = Tmp;
1290     }
1291 
1292     CopyMem (Item->Data.Ptr, Data, DataSize);
1293     Item->DataSize = DataSize;
1294     Item->Status   = EFI_SUCCESS;
1295     return EFI_SUCCESS;
1296   }
1297 }
1298 
1299 /**
1300   The work function for EfiIp6ConfigSetData() to set the DNS server list for the
1301   EFI IPv6 network stack running on the communication device that this EFI IPv6
1302   Configuration Protocol manages. It is not configurable when the policy is
1303   Ip6ConfigPolicyAutomatic. The DNS server addresses must be unicast IPv6 addresses.
1304 
1305   @param[in]     Instance The pointer to the IP6 config instance data.
1306   @param[in]     DataSize The size of the buffer pointed to by Data in bytes.
1307   @param[in]     Data     The data buffer to set, points to an array of
1308                           EFI_IPv6_ADDRESS instances.
1309 
1310   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
1311   @retval EFI_WRITE_PROTECTED   The specified configuration data cannot be set
1312                                 under the current policy.
1313   @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
1314   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources to complete the operation.
1315   @retval EFI_ABORTED           The DNS server addresses to be set equal the current
1316                                 configuration.
1317   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
1318                                 network stack was set.
1319 
1320 **/
1321 EFI_STATUS
Ip6ConfigSetDnsServer(IN IP6_CONFIG_INSTANCE * Instance,IN UINTN DataSize,IN VOID * Data)1322 Ip6ConfigSetDnsServer (
1323   IN IP6_CONFIG_INSTANCE  *Instance,
1324   IN UINTN                DataSize,
1325   IN VOID                 *Data
1326   )
1327 {
1328   UINTN                 OldIndex;
1329   UINTN                 NewIndex;
1330   UINTN                 Index1;
1331   EFI_IPv6_ADDRESS      *OldDns;
1332   EFI_IPv6_ADDRESS      *NewDns;
1333   UINTN                 OldDnsCount;
1334   UINTN                 NewDnsCount;
1335   IP6_CONFIG_DATA_ITEM  *Item;
1336   BOOLEAN               OneAdded;
1337   VOID                  *Tmp;
1338 
1339   if ((DataSize % sizeof (EFI_IPv6_ADDRESS) != 0) || (DataSize == 0)) {
1340     return EFI_BAD_BUFFER_SIZE;
1341   }
1342 
1343   if (Instance->Policy != Ip6ConfigPolicyManual) {
1344     return EFI_WRITE_PROTECTED;
1345   }
1346 
1347   Item        = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
1348   NewDns      = (EFI_IPv6_ADDRESS *) Data;
1349   OldDns      = Item->Data.DnsServers;
1350   NewDnsCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
1351   OldDnsCount = Item->DataSize / sizeof (EFI_IPv6_ADDRESS);
1352   OneAdded    = FALSE;
1353 
1354   if (NewDnsCount != OldDnsCount) {
1355     Tmp = AllocatePool (DataSize);
1356     if (Tmp == NULL) {
1357       return EFI_OUT_OF_RESOURCES;
1358     }
1359   } else {
1360     Tmp = NULL;
1361   }
1362 
1363   for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {
1364 
1365     if (!NetIp6IsValidUnicast (NewDns + NewIndex)) {
1366       //
1367       // The dns server address must be unicast.
1368       //
1369       if (Tmp != NULL) {
1370         FreePool (Tmp);
1371       }
1372       return EFI_INVALID_PARAMETER;
1373     }
1374 
1375     for (Index1 = NewIndex + 1; Index1 < NewDnsCount; Index1++) {
1376       if (EFI_IP6_EQUAL (NewDns + NewIndex, NewDns + Index1)) {
1377         if (Tmp != NULL) {
1378           FreePool (Tmp);
1379         }
1380         return EFI_INVALID_PARAMETER;
1381       }
1382     }
1383 
1384     if (OneAdded) {
1385       //
1386       // If any address in the new setting is not in the old settings, skip the
1387       // comparision below.
1388       //
1389       continue;
1390     }
1391 
1392     for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {
1393       if (EFI_IP6_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {
1394         //
1395         // If found break out.
1396         //
1397         break;
1398       }
1399     }
1400 
1401     if (OldIndex == OldDnsCount) {
1402       OneAdded = TRUE;
1403     }
1404   }
1405 
1406   if (!OneAdded && (DataSize == Item->DataSize)) {
1407     //
1408     // No new item is added and the size is the same.
1409     //
1410     Item->Status = EFI_SUCCESS;
1411     return EFI_ABORTED;
1412   } else {
1413     if (Tmp != NULL) {
1414       if (Item->Data.Ptr != NULL) {
1415         FreePool (Item->Data.Ptr);
1416       }
1417       Item->Data.Ptr = Tmp;
1418     }
1419 
1420     CopyMem (Item->Data.Ptr, Data, DataSize);
1421     Item->DataSize = DataSize;
1422     Item->Status   = EFI_SUCCESS;
1423     return EFI_SUCCESS;
1424   }
1425 }
1426 
1427 /**
1428   Generate the operational state of the interface this IP6 config instance manages
1429   and output in EFI_IP6_CONFIG_INTERFACE_INFO.
1430 
1431   @param[in]      IpSb     The pointer to the IP6 service binding instance.
1432   @param[out]     IfInfo   The pointer to the IP6 configuration interface information structure.
1433 
1434 **/
1435 VOID
Ip6ConfigInitIfInfo(IN IP6_SERVICE * IpSb,OUT EFI_IP6_CONFIG_INTERFACE_INFO * IfInfo)1436 Ip6ConfigInitIfInfo (
1437   IN  IP6_SERVICE                    *IpSb,
1438   OUT EFI_IP6_CONFIG_INTERFACE_INFO  *IfInfo
1439   )
1440 {
1441   IfInfo->Name[0] = L'e';
1442   IfInfo->Name[1] = L't';
1443   IfInfo->Name[2] = L'h';
1444   IfInfo->Name[3] = (CHAR16) (L'0' + IpSb->Ip6ConfigInstance.IfIndex);
1445   IfInfo->Name[4] = 0;
1446 
1447   IfInfo->IfType        = IpSb->SnpMode.IfType;
1448   IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;
1449   CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);
1450 }
1451 
1452 /**
1453   Parse DHCPv6 reply packet to get the DNS server list.
1454   It is the work function for Ip6ConfigOnDhcp6Reply and Ip6ConfigOnDhcp6Event.
1455 
1456   @param[in]      Dhcp6    The pointer to the EFI_DHCP6_PROTOCOL instance.
1457   @param[in, out] Instance The pointer to the IP6 configuration instance data.
1458   @param[in]      Reply    The pointer to the DHCPv6 reply packet.
1459 
1460   @retval EFI_SUCCESS      The DNS server address was retrieved from the reply packet.
1461   @retval EFI_NOT_READY    The reply packet does not contain the DNS server option, or
1462                            the DNS server address is not valid.
1463 
1464 **/
1465 EFI_STATUS
Ip6ConfigParseDhcpReply(IN EFI_DHCP6_PROTOCOL * Dhcp6,IN OUT IP6_CONFIG_INSTANCE * Instance,IN EFI_DHCP6_PACKET * Reply)1466 Ip6ConfigParseDhcpReply (
1467   IN     EFI_DHCP6_PROTOCOL  *Dhcp6,
1468   IN OUT IP6_CONFIG_INSTANCE *Instance,
1469   IN     EFI_DHCP6_PACKET    *Reply
1470   )
1471 {
1472   EFI_STATUS               Status;
1473   UINT32                   OptCount;
1474   EFI_DHCP6_PACKET_OPTION  **OptList;
1475   UINT16                   OpCode;
1476   UINT16                   Length;
1477   UINTN                    Index;
1478   UINTN                    Index2;
1479   EFI_IPv6_ADDRESS         *DnsServer;
1480   IP6_CONFIG_DATA_ITEM     *Item;
1481 
1482   //
1483   // A DHCPv6 reply packet is received as the response to our InfoRequest
1484   // packet.
1485   //
1486   OptCount = 0;
1487   Status   = Dhcp6->Parse (Dhcp6, Reply, &OptCount, NULL);
1488   if (Status != EFI_BUFFER_TOO_SMALL) {
1489     return EFI_NOT_READY;
1490   }
1491 
1492   OptList = AllocatePool (OptCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
1493   if (OptList == NULL) {
1494     return EFI_NOT_READY;
1495   }
1496 
1497   Status = Dhcp6->Parse (Dhcp6, Reply, &OptCount, OptList);
1498   if (EFI_ERROR (Status)) {
1499     Status = EFI_NOT_READY;
1500     goto ON_EXIT;
1501   }
1502 
1503   Status = EFI_SUCCESS;
1504 
1505   for (Index = 0; Index < OptCount; Index++) {
1506     //
1507     // Go through all the options to check the ones we are interested in.
1508     // The OpCode and Length are in network byte-order and may not be naturally
1509     // aligned.
1510     //
1511     CopyMem (&OpCode, &OptList[Index]->OpCode, sizeof (OpCode));
1512     OpCode = NTOHS (OpCode);
1513 
1514     if (OpCode == DHCP6_OPT_DNS_SERVERS) {
1515       CopyMem (&Length, &OptList[Index]->OpLen, sizeof (Length));
1516       Length = NTOHS (Length);
1517 
1518       if ((Length == 0) || ((Length % sizeof (EFI_IPv6_ADDRESS)) != 0)) {
1519         //
1520         // The length should be a multiple of 16 bytes.
1521         //
1522         Status = EFI_NOT_READY;
1523         break;
1524       }
1525 
1526       //
1527       // Validate the DnsServers: whether they are unicast addresses.
1528       //
1529       DnsServer = (EFI_IPv6_ADDRESS *) OptList[Index]->Data;
1530       for (Index2 = 0; Index2 < Length / sizeof (EFI_IPv6_ADDRESS); Index2++) {
1531         if (!NetIp6IsValidUnicast (DnsServer)) {
1532           Status = EFI_NOT_READY;
1533           goto ON_EXIT;
1534         }
1535 
1536         DnsServer++;
1537       }
1538 
1539       Item = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
1540 
1541       if (Item->DataSize != Length) {
1542         if (Item->Data.Ptr != NULL) {
1543           FreePool (Item->Data.Ptr);
1544         }
1545 
1546         Item->Data.Ptr = AllocatePool (Length);
1547         ASSERT (Item->Data.Ptr != NULL);
1548       }
1549 
1550       CopyMem (Item->Data.Ptr, OptList[Index]->Data, Length);
1551       Item->DataSize = Length;
1552       Item->Status   = EFI_SUCCESS;
1553 
1554       //
1555       // Signal the waiting events.
1556       //
1557       NetMapIterate (&Item->EventMap, Ip6ConfigSignalEvent, NULL);
1558 
1559       break;
1560     }
1561   }
1562 
1563 ON_EXIT:
1564 
1565   FreePool (OptList);
1566   return Status;
1567 }
1568 
1569 /**
1570   The callback function for Ip6SetAddr. The prototype is defined
1571   as IP6_DAD_CALLBACK. It is called after Duplicate Address Detection is performed
1572   on the tentative address by DHCPv6 in Ip6ConfigOnDhcp6Event().
1573 
1574   @param[in]     IsDadPassed   If TRUE, Duplicate Address Detection passes.
1575   @param[in]     TargetAddress The tentative IPv6 address to be checked.
1576   @param[in]     Context       Pointer to the IP6 configuration instance data.
1577 
1578 **/
1579 VOID
Ip6ConfigSetStatefulAddrCallback(IN BOOLEAN IsDadPassed,IN EFI_IPv6_ADDRESS * TargetAddress,IN VOID * Context)1580 Ip6ConfigSetStatefulAddrCallback (
1581   IN BOOLEAN           IsDadPassed,
1582   IN EFI_IPv6_ADDRESS  *TargetAddress,
1583   IN VOID              *Context
1584   )
1585 {
1586   IP6_CONFIG_INSTANCE  *Instance;
1587 
1588   Instance = (IP6_CONFIG_INSTANCE *) Context;
1589   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
1590 
1591   //
1592   // We should record the addresses that fail the DAD, and DECLINE them.
1593   //
1594   if (IsDadPassed) {
1595     //
1596     // Decrease the count, no interests in those passed DAD.
1597     //
1598     if (Instance->FailedIaAddressCount > 0 ) {
1599       Instance->FailedIaAddressCount--;
1600     }
1601   } else {
1602     //
1603     // Record it.
1604     //
1605     IP6_COPY_ADDRESS (Instance->DeclineAddress + Instance->DeclineAddressCount, TargetAddress);
1606     Instance->DeclineAddressCount++;
1607   }
1608 
1609   if (Instance->FailedIaAddressCount == Instance->DeclineAddressCount) {
1610     //
1611     // The checking on all addresses are finished.
1612     //
1613     if (Instance->DeclineAddressCount != 0) {
1614       //
1615       // Decline those duplicates.
1616       //
1617       if (Instance->Dhcp6 != NULL) {
1618         Instance->Dhcp6->Decline (
1619                            Instance->Dhcp6,
1620                            Instance->DeclineAddressCount,
1621                            Instance->DeclineAddress
1622                            );
1623       }
1624     }
1625 
1626     if (Instance->DeclineAddress != NULL) {
1627       FreePool (Instance->DeclineAddress);
1628     }
1629     Instance->DeclineAddress      = NULL;
1630     Instance->DeclineAddressCount = 0;
1631   }
1632 }
1633 
1634 /**
1635   The event handle routine when DHCPv6 process is finished or is updated.
1636 
1637   @param[in]     Event         Not used.
1638   @param[in]     Context       The pointer to the IP6 configuration instance data.
1639 
1640 **/
1641 VOID
1642 EFIAPI
Ip6ConfigOnDhcp6Event(IN EFI_EVENT Event,IN VOID * Context)1643 Ip6ConfigOnDhcp6Event (
1644   IN EFI_EVENT  Event,
1645   IN VOID       *Context
1646   )
1647 {
1648   IP6_CONFIG_INSTANCE      *Instance;
1649   EFI_DHCP6_PROTOCOL       *Dhcp6;
1650   EFI_STATUS               Status;
1651   EFI_DHCP6_MODE_DATA      Dhcp6ModeData;
1652   EFI_DHCP6_IA             *Ia;
1653   EFI_DHCP6_IA_ADDRESS     *IaAddr;
1654   UINT32                   Index;
1655   IP6_SERVICE              *IpSb;
1656   IP6_ADDRESS_INFO         *AddrInfo;
1657   IP6_INTERFACE            *IpIf;
1658 
1659   Instance = (IP6_CONFIG_INSTANCE *) Context;
1660 
1661   if ((Instance->Policy != Ip6ConfigPolicyAutomatic) || Instance->OtherInfoOnly) {
1662     //
1663     // IPv6 is not operating in the automatic policy now or
1664     // the DHCPv6 information request message exchange is aborted.
1665     //
1666     return ;
1667   }
1668 
1669   //
1670   // The stateful address autoconfiguration is done or updated.
1671   //
1672   Dhcp6 = Instance->Dhcp6;
1673 
1674   Status = Dhcp6->GetModeData (Dhcp6, &Dhcp6ModeData, NULL);
1675   if (EFI_ERROR (Status)) {
1676     return ;
1677   }
1678 
1679   IpSb   = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1680   IpIf   = IpSb->DefaultInterface;
1681   Ia     = Dhcp6ModeData.Ia;
1682   IaAddr = Ia->IaAddress;
1683 
1684   if (Instance->DeclineAddress != NULL) {
1685     FreePool (Instance->DeclineAddress);
1686   }
1687 
1688   Instance->DeclineAddress = (EFI_IPv6_ADDRESS *) AllocatePool (Ia->IaAddressCount * sizeof (EFI_IPv6_ADDRESS));
1689   if (Instance->DeclineAddress == NULL) {
1690     goto ON_EXIT;
1691   }
1692 
1693   Instance->FailedIaAddressCount = Ia->IaAddressCount;
1694   Instance->DeclineAddressCount   = 0;
1695 
1696   for (Index = 0; Index < Ia->IaAddressCount; Index++, IaAddr++) {
1697     if (Ia->IaAddress[Index].ValidLifetime != 0 && Ia->State == Dhcp6Bound) {
1698       //
1699       // Set this address, either it's a new address or with updated lifetimes.
1700       // An appropriate prefix length will be set.
1701       //
1702       Ip6SetAddress (
1703         IpIf,
1704         &IaAddr->IpAddress,
1705         FALSE,
1706         0,
1707         IaAddr->ValidLifetime,
1708         IaAddr->PreferredLifetime,
1709         Ip6ConfigSetStatefulAddrCallback,
1710         Instance
1711         );
1712     } else {
1713       //
1714       // discard this address, artificially decrease the count as if this address
1715       // passed DAD.
1716       //
1717       if (Ip6IsOneOfSetAddress (IpSb, &IaAddr->IpAddress, NULL, &AddrInfo)) {
1718         ASSERT (AddrInfo != NULL);
1719         Ip6RemoveAddr (
1720           IpSb,
1721           &IpIf->AddressList,
1722           &IpIf->AddressCount,
1723           &AddrInfo->Address,
1724           AddrInfo->PrefixLength
1725           );
1726       }
1727 
1728       if (Instance->FailedIaAddressCount > 0) {
1729         Instance->FailedIaAddressCount--;
1730       }
1731     }
1732   }
1733 
1734   //
1735   // Parse the Reply packet to get the options we need.
1736   //
1737   if (Dhcp6ModeData.Ia->ReplyPacket != NULL) {
1738     Ip6ConfigParseDhcpReply (Dhcp6, Instance, Dhcp6ModeData.Ia->ReplyPacket);
1739   }
1740 
1741 ON_EXIT:
1742 
1743   FreePool (Dhcp6ModeData.ClientId);
1744   FreePool (Dhcp6ModeData.Ia);
1745 }
1746 
1747 /**
1748   The event process routine when the DHCPv6 server is answered with a reply packet
1749   for an information request.
1750 
1751   @param[in]     This          Points to the EFI_DHCP6_PROTOCOL.
1752   @param[in]     Context       The pointer to the IP6 configuration instance data.
1753   @param[in]     Packet        The DHCPv6 reply packet.
1754 
1755   @retval EFI_SUCCESS      The DNS server address was retrieved from the reply packet.
1756   @retval EFI_NOT_READY    The reply packet does not contain the DNS server option, or
1757                            the DNS server address is not valid.
1758 
1759 **/
1760 EFI_STATUS
1761 EFIAPI
Ip6ConfigOnDhcp6Reply(IN EFI_DHCP6_PROTOCOL * This,IN VOID * Context,IN EFI_DHCP6_PACKET * Packet)1762 Ip6ConfigOnDhcp6Reply (
1763   IN EFI_DHCP6_PROTOCOL  *This,
1764   IN VOID                *Context,
1765   IN EFI_DHCP6_PACKET    *Packet
1766   )
1767 {
1768   return Ip6ConfigParseDhcpReply (This, (IP6_CONFIG_INSTANCE *) Context, Packet);
1769 }
1770 
1771 /**
1772   The event process routine when the DHCPv6 service binding protocol is installed
1773   in the system.
1774 
1775   @param[in]     Event         Not used.
1776   @param[in]     Context       The pointer to the IP6 config instance data.
1777 
1778 **/
1779 VOID
1780 EFIAPI
Ip6ConfigOnDhcp6SbInstalled(IN EFI_EVENT Event,IN VOID * Context)1781 Ip6ConfigOnDhcp6SbInstalled (
1782   IN EFI_EVENT  Event,
1783   IN VOID       *Context
1784   )
1785 {
1786   IP6_CONFIG_INSTANCE  *Instance;
1787 
1788   Instance = (IP6_CONFIG_INSTANCE *) Context;
1789 
1790   if ((Instance->Dhcp6Handle != NULL) || (Instance->Policy != Ip6ConfigPolicyAutomatic)) {
1791     //
1792     // The DHCP6 child is already created or the policy is no longer AUTOMATIC.
1793     //
1794     return ;
1795   }
1796 
1797   Ip6ConfigStartStatefulAutoConfig (Instance, Instance->OtherInfoOnly);
1798 }
1799 
1800 /**
1801   Set the configuration for the EFI IPv6 network stack running on the communication
1802   device this EFI IPv6 Configuration Protocol instance manages.
1803 
1804   This function is used to set the configuration data of type DataType for the EFI
1805   IPv6 network stack that is running on the communication device that this EFI IPv6
1806   Configuration Protocol instance manages.
1807 
1808   DataSize is used to calculate the count of structure instances in the Data for
1809   a DataType in which multiple structure instances are allowed.
1810 
1811   This function is always non-blocking. When setting some type of configuration data,
1812   an asynchronous process is invoked to check the correctness of the data, such as
1813   performing Duplicate Address Detection on the manually set local IPv6 addresses.
1814   EFI_NOT_READY is returned immediately to indicate that such an asynchronous process
1815   is invoked, and the process is not finished yet. The caller wanting to get the result
1816   of the asynchronous process is required to call RegisterDataNotify() to register an
1817   event on the specified configuration data. Once the event is signaled, the caller
1818   can call GetData() to obtain the configuration data and know the result.
1819   For other types of configuration data that do not require an asynchronous configuration
1820   process, the result of the operation is immediately returned.
1821 
1822   @param[in]     This           The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
1823   @param[in]     DataType       The type of data to set.
1824   @param[in]     DataSize       Size of the buffer pointed to by Data in bytes.
1825   @param[in]     Data           The data buffer to set. The type of the data buffer is
1826                                 associated with the DataType.
1827 
1828   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
1829                                 network stack was set successfully.
1830   @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
1831                                 - This is NULL.
1832                                 - Data is NULL.
1833                                 - One or more fields in Data do not match the requirement of the
1834                                   data type indicated by DataType.
1835   @retval EFI_WRITE_PROTECTED   The specified configuration data is read-only or the specified
1836                                 configuration data cannot be set under the current policy.
1837   @retval EFI_ACCESS_DENIED     Another set operation on the specified configuration
1838                                 data is already in process.
1839   @retval EFI_NOT_READY         An asynchronous process was invoked to set the specified
1840                                 configuration data, and the process is not finished yet.
1841   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type
1842                                 indicated by DataType.
1843   @retval EFI_UNSUPPORTED       This DataType is not supported.
1844   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
1845   @retval EFI_DEVICE_ERROR      An unexpected system error or network error occurred.
1846 
1847 **/
1848 EFI_STATUS
1849 EFIAPI
EfiIp6ConfigSetData(IN EFI_IP6_CONFIG_PROTOCOL * This,IN EFI_IP6_CONFIG_DATA_TYPE DataType,IN UINTN DataSize,IN VOID * Data)1850 EfiIp6ConfigSetData (
1851   IN EFI_IP6_CONFIG_PROTOCOL    *This,
1852   IN EFI_IP6_CONFIG_DATA_TYPE   DataType,
1853   IN UINTN                      DataSize,
1854   IN VOID                       *Data
1855   )
1856 {
1857   EFI_TPL              OldTpl;
1858   EFI_STATUS           Status;
1859   IP6_CONFIG_INSTANCE  *Instance;
1860   IP6_SERVICE          *IpSb;
1861 
1862   if ((This == NULL) || (Data == NULL)) {
1863     return EFI_INVALID_PARAMETER;
1864   }
1865 
1866   if (DataType >= Ip6ConfigDataTypeMaximum) {
1867     return EFI_UNSUPPORTED;
1868   }
1869 
1870   Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
1871   IpSb     = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
1872   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
1873 
1874   if (IpSb->LinkLocalDadFail) {
1875     return EFI_DEVICE_ERROR;
1876   }
1877 
1878   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1879 
1880   Status = Instance->DataItem[DataType].Status;
1881   if (Status != EFI_NOT_READY) {
1882 
1883     if (Instance->DataItem[DataType].SetData == NULL) {
1884       //
1885       // This type of data is readonly.
1886       //
1887       Status = EFI_WRITE_PROTECTED;
1888     } else {
1889 
1890       Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);
1891       if (!EFI_ERROR (Status)) {
1892         //
1893         // Fire up the events registered with this type of data.
1894         //
1895         NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);
1896         Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
1897       } else if (Status == EFI_ABORTED) {
1898         //
1899         // The SetData is aborted because the data to set is the same with
1900         // the one maintained.
1901         //
1902         Status = EFI_SUCCESS;
1903         NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip6ConfigSignalEvent, NULL);
1904       }
1905     }
1906   } else {
1907     //
1908     // Another asynchornous process is on the way.
1909     //
1910     Status = EFI_ACCESS_DENIED;
1911   }
1912 
1913   gBS->RestoreTPL (OldTpl);
1914 
1915   return Status;
1916 }
1917 
1918 /**
1919   Get the configuration data for the EFI IPv6 network stack running on the communication
1920   device that this EFI IPv6 Configuration Protocol instance manages.
1921 
1922   This function returns the configuration data of type DataType for the EFI IPv6 network
1923   stack running on the communication device that this EFI IPv6 Configuration Protocol instance
1924   manages.
1925 
1926   The caller is responsible for allocating the buffer used to return the specified
1927   configuration data. The required size will be returned to the caller if the size of
1928   the buffer is too small.
1929 
1930   EFI_NOT_READY is returned if the specified configuration data is not ready due to an
1931   asynchronous configuration process already in progress. The caller can call RegisterDataNotify()
1932   to register an event on the specified configuration data. Once the asynchronous configuration
1933   process is finished, the event will be signaled, and a subsequent GetData() call will return
1934   the specified configuration data.
1935 
1936   @param[in]      This           Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
1937   @param[in]      DataType       The type of data to get.
1938   @param[in, out] DataSize       On input, in bytes, the size of Data. On output, in bytes, the
1939                                  size of buffer required to store the specified configuration data.
1940   @param[in]     Data            The data buffer in which the configuration data is returned. The
1941                                  type of the data buffer is associated with the DataType.
1942                                  This is an optional parameter that may be NULL.
1943 
1944   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
1945   @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
1946                                 - This is NULL.
1947                                 - DataSize is NULL.
1948                                 - Data is NULL if *DataSize is not zero.
1949   @retval EFI_BUFFER_TOO_SMALL  The size of Data is too small for the specified configuration data,
1950                                 and the required size is returned in DataSize.
1951   @retval EFI_NOT_READY         The specified configuration data is not ready due to an
1952                                 asynchronous configuration process already in progress.
1953   @retval EFI_NOT_FOUND         The specified configuration data is not found.
1954 
1955 **/
1956 EFI_STATUS
1957 EFIAPI
EfiIp6ConfigGetData(IN EFI_IP6_CONFIG_PROTOCOL * This,IN EFI_IP6_CONFIG_DATA_TYPE DataType,IN OUT UINTN * DataSize,IN VOID * Data OPTIONAL)1958 EfiIp6ConfigGetData (
1959   IN EFI_IP6_CONFIG_PROTOCOL    *This,
1960   IN EFI_IP6_CONFIG_DATA_TYPE   DataType,
1961   IN OUT UINTN                  *DataSize,
1962   IN VOID                       *Data   OPTIONAL
1963   )
1964 {
1965   EFI_TPL               OldTpl;
1966   EFI_STATUS            Status;
1967   IP6_CONFIG_INSTANCE   *Instance;
1968   IP6_CONFIG_DATA_ITEM  *DataItem;
1969 
1970   if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {
1971     return EFI_INVALID_PARAMETER;
1972   }
1973 
1974   if (DataType >= Ip6ConfigDataTypeMaximum) {
1975     return EFI_NOT_FOUND;
1976   }
1977 
1978   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1979 
1980   Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
1981   DataItem = &Instance->DataItem[DataType];
1982 
1983   Status   = Instance->DataItem[DataType].Status;
1984   if (!EFI_ERROR (Status)) {
1985 
1986     if (DataItem->GetData != NULL) {
1987 
1988       Status = DataItem->GetData (Instance, DataSize, Data);
1989     } else if (*DataSize < Instance->DataItem[DataType].DataSize) {
1990       //
1991       // Update the buffer length.
1992       //
1993       *DataSize = Instance->DataItem[DataType].DataSize;
1994       Status    = EFI_BUFFER_TOO_SMALL;
1995     } else {
1996 
1997       *DataSize = Instance->DataItem[DataType].DataSize;
1998       CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);
1999     }
2000   }
2001 
2002   gBS->RestoreTPL (OldTpl);
2003 
2004   return Status;
2005 }
2006 
2007 /**
2008   Register an event that is signaled whenever a configuration process on the specified
2009   configuration data is done.
2010 
2011   This function registers an event that is to be signaled whenever a configuration
2012   process on the specified configuration data is performed. An event can be registered
2013   for a different DataType simultaneously. The caller is responsible for determining
2014   which type of configuration data causes the signaling of the event in such an event.
2015 
2016   @param[in]     This           Pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
2017   @param[in]     DataType       The type of data to unregister the event for.
2018   @param[in]     Event          The event to register.
2019 
2020   @retval EFI_SUCCESS           The notification event for the specified configuration data is
2021                                 registered.
2022   @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
2023   @retval EFI_UNSUPPORTED       The configuration data type specified by DataType is not
2024                                 supported.
2025   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
2026   @retval EFI_ACCESS_DENIED     The Event is already registered for the DataType.
2027 
2028 **/
2029 EFI_STATUS
2030 EFIAPI
EfiIp6ConfigRegisterDataNotify(IN EFI_IP6_CONFIG_PROTOCOL * This,IN EFI_IP6_CONFIG_DATA_TYPE DataType,IN EFI_EVENT Event)2031 EfiIp6ConfigRegisterDataNotify (
2032   IN EFI_IP6_CONFIG_PROTOCOL    *This,
2033   IN EFI_IP6_CONFIG_DATA_TYPE   DataType,
2034   IN EFI_EVENT                  Event
2035   )
2036 {
2037   EFI_TPL              OldTpl;
2038   EFI_STATUS           Status;
2039   IP6_CONFIG_INSTANCE  *Instance;
2040   NET_MAP              *EventMap;
2041   NET_MAP_ITEM         *Item;
2042 
2043   if ((This == NULL) || (Event == NULL)) {
2044     return EFI_INVALID_PARAMETER;
2045   }
2046 
2047   if (DataType >= Ip6ConfigDataTypeMaximum) {
2048     return EFI_UNSUPPORTED;
2049   }
2050 
2051   OldTpl    = gBS->RaiseTPL (TPL_CALLBACK);
2052 
2053   Instance  = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2054   EventMap  = &Instance->DataItem[DataType].EventMap;
2055 
2056   //
2057   // Check whether this event is already registered for this DataType.
2058   //
2059   Item = NetMapFindKey (EventMap, Event);
2060   if (Item == NULL) {
2061 
2062     Status = NetMapInsertTail (EventMap, Event, NULL);
2063 
2064     if (EFI_ERROR (Status)) {
2065 
2066       Status = EFI_OUT_OF_RESOURCES;
2067     }
2068 
2069   } else {
2070 
2071     Status = EFI_ACCESS_DENIED;
2072   }
2073 
2074   gBS->RestoreTPL (OldTpl);
2075 
2076   return Status;
2077 }
2078 
2079 /**
2080   Remove a previously registered event for the specified configuration data.
2081 
2082   @param  This                   The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
2083   @param  DataType               The type of data to remove from the previously
2084                                  registered event.
2085   @param  Event                  The event to be unregistered.
2086 
2087   @retval EFI_SUCCESS            The event registered for the specified
2088                                  configuration data was removed.
2089   @retval EFI_INVALID_PARAMETER  This is NULL or Event is NULL.
2090   @retval EFI_NOT_FOUND          The Event has not been registered for the
2091                                  specified DataType.
2092 
2093 **/
2094 EFI_STATUS
2095 EFIAPI
EfiIp6ConfigUnregisterDataNotify(IN EFI_IP6_CONFIG_PROTOCOL * This,IN EFI_IP6_CONFIG_DATA_TYPE DataType,IN EFI_EVENT Event)2096 EfiIp6ConfigUnregisterDataNotify (
2097   IN EFI_IP6_CONFIG_PROTOCOL    *This,
2098   IN EFI_IP6_CONFIG_DATA_TYPE   DataType,
2099   IN EFI_EVENT                  Event
2100   )
2101 {
2102   EFI_TPL              OldTpl;
2103   EFI_STATUS           Status;
2104   IP6_CONFIG_INSTANCE  *Instance;
2105   NET_MAP_ITEM         *Item;
2106 
2107   if ((This == NULL) || (Event == NULL)) {
2108     return EFI_INVALID_PARAMETER;
2109   }
2110 
2111   if (DataType >= Ip6ConfigDataTypeMaximum) {
2112     return EFI_NOT_FOUND;
2113   }
2114 
2115   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
2116 
2117   Instance = IP6_CONFIG_INSTANCE_FROM_PROTOCOL (This);
2118 
2119   Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);
2120   if (Item != NULL) {
2121 
2122     NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);
2123     Status = EFI_SUCCESS;
2124   } else {
2125 
2126     Status = EFI_NOT_FOUND;
2127   }
2128 
2129   gBS->RestoreTPL (OldTpl);
2130 
2131   return Status;
2132 }
2133 
2134 /**
2135   Initialize an IP6_CONFIG_INSTANCE.
2136 
2137   @param[out]    Instance       The buffer of IP6_CONFIG_INSTANCE to be initialized.
2138 
2139   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources to complete the operation.
2140   @retval EFI_SUCCESS           The IP6_CONFIG_INSTANCE initialized successfully.
2141 
2142 **/
2143 EFI_STATUS
Ip6ConfigInitInstance(OUT IP6_CONFIG_INSTANCE * Instance)2144 Ip6ConfigInitInstance (
2145   OUT IP6_CONFIG_INSTANCE  *Instance
2146   )
2147 {
2148   IP6_SERVICE           *IpSb;
2149   IP6_CONFIG_INSTANCE   *TmpInstance;
2150   LIST_ENTRY            *Entry;
2151   EFI_STATUS            Status;
2152   UINTN                 Index;
2153   UINT16                IfIndex;
2154   IP6_CONFIG_DATA_ITEM  *DataItem;
2155 
2156   IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2157 
2158   Instance->Signature = IP6_CONFIG_INSTANCE_SIGNATURE;
2159 
2160   //
2161   // Determine the index of this interface.
2162   //
2163   IfIndex = 0;
2164   NET_LIST_FOR_EACH (Entry, &mIp6ConfigInstanceList) {
2165     TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_CONFIG_INSTANCE, Link, IP6_CONFIG_INSTANCE_SIGNATURE);
2166 
2167     if (TmpInstance->IfIndex > IfIndex) {
2168       //
2169       // There is a sequence hole because some interface is down.
2170       //
2171       break;
2172     }
2173 
2174     IfIndex++;
2175   }
2176 
2177   Instance->IfIndex = IfIndex;
2178   NetListInsertBefore (Entry, &Instance->Link);
2179 
2180   for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
2181     //
2182     // Initialize the event map for each data item.
2183     //
2184     NetMapInit (&Instance->DataItem[Index].EventMap);
2185   }
2186 
2187   //
2188   // Initialize the NET_MAPs used for DAD on manually configured source addresses.
2189   //
2190   NetMapInit (&Instance->DadFailedMap);
2191   NetMapInit (&Instance->DadPassedMap);
2192 
2193   //
2194   // Initialize each data type: associate storage and set data size for the
2195   // fixed size data types, hook the SetData function, set the data attribute.
2196   //
2197   DataItem           = &Instance->DataItem[Ip6ConfigDataTypeInterfaceInfo];
2198   DataItem->GetData  = Ip6ConfigGetIfInfo;
2199   DataItem->Data.Ptr = &Instance->InterfaceInfo;
2200   DataItem->DataSize = sizeof (Instance->InterfaceInfo);
2201   SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);
2202   Ip6ConfigInitIfInfo (IpSb, &Instance->InterfaceInfo);
2203 
2204   DataItem           = &Instance->DataItem[Ip6ConfigDataTypeAltInterfaceId];
2205   DataItem->SetData  = Ip6ConfigSetAltIfId;
2206   DataItem->Data.Ptr = &Instance->AltIfId;
2207   DataItem->DataSize = sizeof (Instance->AltIfId);
2208   DataItem->Status   = EFI_NOT_FOUND;
2209   SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2210 
2211   DataItem           = &Instance->DataItem[Ip6ConfigDataTypePolicy];
2212   DataItem->SetData  = Ip6ConfigSetPolicy;
2213   DataItem->Data.Ptr = &Instance->Policy;
2214   DataItem->DataSize = sizeof (Instance->Policy);
2215   Instance->Policy   = Ip6ConfigPolicyManual;
2216   SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2217 
2218   DataItem           = &Instance->DataItem[Ip6ConfigDataTypeDupAddrDetectTransmits];
2219   DataItem->SetData  = Ip6ConfigSetDadXmits;
2220   DataItem->Data.Ptr = &Instance->DadXmits;
2221   DataItem->DataSize = sizeof (Instance->DadXmits);
2222   Instance->DadXmits.DupAddrDetectTransmits = IP6_CONFIG_DEFAULT_DAD_XMITS;
2223   SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
2224 
2225   DataItem           = &Instance->DataItem[Ip6ConfigDataTypeManualAddress];
2226   DataItem->SetData  = Ip6ConfigSetMaunualAddress;
2227   DataItem->Status   = EFI_NOT_FOUND;
2228 
2229   DataItem           = &Instance->DataItem[Ip6ConfigDataTypeGateway];
2230   DataItem->SetData  = Ip6ConfigSetGateway;
2231   DataItem->Status   = EFI_NOT_FOUND;
2232 
2233   DataItem           = &Instance->DataItem[Ip6ConfigDataTypeDnsServer];
2234   DataItem->SetData  = Ip6ConfigSetDnsServer;
2235   DataItem->Status   = EFI_NOT_FOUND;
2236 
2237   //
2238   // Create the event used for DHCP.
2239   //
2240   Status = gBS->CreateEvent (
2241                   EVT_NOTIFY_SIGNAL,
2242                   TPL_CALLBACK,
2243                   Ip6ConfigOnDhcp6Event,
2244                   Instance,
2245                   &Instance->Dhcp6Event
2246                   );
2247   ASSERT_EFI_ERROR (Status);
2248 
2249   Instance->Configured  = TRUE;
2250 
2251   //
2252   // Try to read the config data from NV variable.
2253   //
2254   Status = Ip6ConfigReadConfigData (IpSb->MacString, Instance);
2255   if (Status == EFI_NOT_FOUND) {
2256     //
2257     // The NV variable is not set, so generate a random IAID, and write down the
2258     // fresh new configuration as the NV variable now.
2259     //
2260     Instance->IaId = NET_RANDOM (NetRandomInitSeed ());
2261 
2262     for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) {
2263       Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 3) & 31));
2264     }
2265 
2266     Ip6ConfigWriteConfigData (IpSb->MacString, Instance);
2267   } else if (EFI_ERROR (Status)) {
2268     return Status;
2269   }
2270 
2271   Instance->Ip6Config.SetData              = EfiIp6ConfigSetData;
2272   Instance->Ip6Config.GetData              = EfiIp6ConfigGetData;
2273   Instance->Ip6Config.RegisterDataNotify   = EfiIp6ConfigRegisterDataNotify;
2274   Instance->Ip6Config.UnregisterDataNotify = EfiIp6ConfigUnregisterDataNotify;
2275 
2276 
2277   //
2278   // Publish the IP6 configuration form
2279   //
2280   return Ip6ConfigFormInit (Instance);
2281 }
2282 
2283 /**
2284   Release an IP6_CONFIG_INSTANCE.
2285 
2286   @param[in, out] Instance    The buffer of IP6_CONFIG_INSTANCE to be freed.
2287 
2288 **/
2289 VOID
Ip6ConfigCleanInstance(IN OUT IP6_CONFIG_INSTANCE * Instance)2290 Ip6ConfigCleanInstance (
2291   IN OUT IP6_CONFIG_INSTANCE  *Instance
2292   )
2293 {
2294   UINTN                 Index;
2295   IP6_CONFIG_DATA_ITEM  *DataItem;
2296 
2297   if (Instance->DeclineAddress != NULL) {
2298     FreePool (Instance->DeclineAddress);
2299   }
2300 
2301   if (!Instance->Configured) {
2302     return ;
2303   }
2304 
2305   if (Instance->Dhcp6Handle != NULL) {
2306 
2307     Ip6ConfigDestroyDhcp6 (Instance);
2308   }
2309 
2310   //
2311   // Close the event.
2312   //
2313   if (Instance->Dhcp6Event != NULL) {
2314     gBS->CloseEvent (Instance->Dhcp6Event);
2315   }
2316 
2317   NetMapClean (&Instance->DadPassedMap);
2318   NetMapClean (&Instance->DadFailedMap);
2319 
2320   for (Index = 0; Index < Ip6ConfigDataTypeMaximum; Index++) {
2321 
2322     DataItem = &Instance->DataItem[Index];
2323 
2324     if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
2325       if (DataItem->Data.Ptr != NULL) {
2326         FreePool (DataItem->Data.Ptr);
2327       }
2328       DataItem->Data.Ptr = NULL;
2329       DataItem->DataSize = 0;
2330     }
2331 
2332     NetMapClean (&Instance->DataItem[Index].EventMap);
2333   }
2334 
2335   Ip6ConfigFormUnload (Instance);
2336 
2337   RemoveEntryList (&Instance->Link);
2338 }
2339 
2340 /**
2341   Destroy the Dhcp6 child in IP6_CONFIG_INSTANCE and release the resources.
2342 
2343   @param[in, out] Instance    The buffer of IP6_CONFIG_INSTANCE to be freed.
2344 
2345   @retval EFI_SUCCESS         The child was successfully destroyed.
2346   @retval Others              Failed to destroy the child.
2347 
2348 **/
2349 EFI_STATUS
Ip6ConfigDestroyDhcp6(IN OUT IP6_CONFIG_INSTANCE * Instance)2350 Ip6ConfigDestroyDhcp6 (
2351   IN OUT IP6_CONFIG_INSTANCE  *Instance
2352   )
2353 {
2354   IP6_SERVICE                 *IpSb;
2355   EFI_STATUS                  Status;
2356   EFI_DHCP6_PROTOCOL          *Dhcp6;
2357 
2358   Dhcp6 = Instance->Dhcp6;
2359   ASSERT (Dhcp6 != NULL);
2360 
2361   Dhcp6->Stop (Dhcp6);
2362   Dhcp6->Configure (Dhcp6, NULL);
2363   Instance->Dhcp6 = NULL;
2364 
2365   IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
2366 
2367   //
2368   // Close DHCPv6 protocol and destroy the child.
2369   //
2370   Status = gBS->CloseProtocol (
2371                   Instance->Dhcp6Handle,
2372                   &gEfiDhcp6ProtocolGuid,
2373                   IpSb->Image,
2374                   IpSb->Controller
2375                   );
2376   if (EFI_ERROR (Status)) {
2377     return Status;
2378   }
2379 
2380   Status = NetLibDestroyServiceChild (
2381              IpSb->Controller,
2382              IpSb->Image,
2383              &gEfiDhcp6ServiceBindingProtocolGuid,
2384              Instance->Dhcp6Handle
2385              );
2386 
2387   Instance->Dhcp6Handle = NULL;
2388 
2389   return Status;
2390 }
2391 
2392