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