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