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