Home | History | Annotate | Download | only in Ip6Dxe
      1 /** @file
      2   Helper functions for configuring or obtaining the parameters relating to IP6.
      3 
      4   Copyright (c) 2010 - 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 CHAR16    mIp6ConfigStorageName[]     = L"IP6_CONFIG_IFR_NVDATA";
     19 
     20 /**
     21   The notify function of create event when performing a manual configuration.
     22 
     23   @param[in]    Event        The pointer of Event.
     24   @param[in]    Context      The pointer of Context.
     25 
     26 **/
     27 VOID
     28 EFIAPI
     29 Ip6ConfigManualAddressNotify (
     30   IN EFI_EVENT    Event,
     31   IN VOID         *Context
     32   )
     33 {
     34   *((BOOLEAN *) Context) = TRUE;
     35 }
     36 
     37 /**
     38   Get the configuration data for the EFI IPv6 network stack running on the
     39   communication. It is a help function to the call EfiIp6ConfigGetData().
     40 
     41   @param[in]      Ip6Config      The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.
     42   @param[in]      DataType       The type of data to get.
     43   @param[out]     DataSize       The size of buffer required in bytes.
     44   @param[out]     Data           The data buffer in which the configuration data is returned. The
     45                                  type of the data buffer associated with the DataType.
     46                                  It is the caller's responsibility to free the resource.
     47 
     48   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
     49   @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
     50                                 - Ip6Config is NULL or invalid.
     51                                 - DataSize is NULL.
     52                                 - Data is NULL.
     53   @retval EFI_OUT_OF_RESOURCES  Fail to perform the operation due to lack of resources.
     54   @retval EFI_NOT_READY         The specified configuration data is not ready due to an
     55                                 asynchronous configuration process already in progress.
     56   @retval EFI_NOT_FOUND         The specified configuration data was not found.
     57 
     58 **/
     59 EFI_STATUS
     60 Ip6ConfigNvGetData (
     61   IN  EFI_IP6_CONFIG_PROTOCOL                *Ip6Config,
     62   IN  EFI_IP6_CONFIG_DATA_TYPE               DataType,
     63   OUT UINTN                                  *DataSize,
     64   OUT VOID                                   **Data
     65   )
     66 {
     67   UINTN                   BufferSize;
     68   VOID                    *Buffer;
     69   EFI_STATUS              Status;
     70 
     71   if ((Ip6Config == NULL) || (Data == NULL) || (DataSize == NULL)) {
     72     return EFI_INVALID_PARAMETER;
     73   }
     74 
     75   BufferSize = 0;
     76   Status = Ip6Config->GetData (
     77                         Ip6Config,
     78                         DataType,
     79                         &BufferSize,
     80                         NULL
     81                         );
     82   if (Status != EFI_BUFFER_TOO_SMALL) {
     83     return Status;
     84   }
     85 
     86   Buffer = AllocateZeroPool (BufferSize);
     87   if (Buffer == NULL) {
     88     return EFI_OUT_OF_RESOURCES;
     89   }
     90 
     91   Status = Ip6Config->GetData (
     92                         Ip6Config,
     93                         DataType,
     94                         &BufferSize,
     95                         Buffer
     96                         );
     97   if (EFI_ERROR (Status)) {
     98     FreePool (Buffer);
     99     return Status;
    100   }
    101 
    102   *DataSize = BufferSize;
    103   *Data     = Buffer;
    104 
    105   return EFI_SUCCESS;
    106 }
    107 
    108 /**
    109   Free all nodes in IP6_ADDRESS_INFO_ENTRY in the list array specified
    110   with ListHead.
    111 
    112   @param[in]      ListHead  The head of the list array in IP6_ADDRESS_INFO_ENTRY.
    113 
    114 **/
    115 VOID
    116 Ip6FreeAddressInfoList (
    117   IN LIST_ENTRY                  *ListHead
    118   )
    119 {
    120   IP6_ADDRESS_INFO_ENTRY         *Node;
    121   LIST_ENTRY                     *Entry;
    122   LIST_ENTRY                     *NextEntry;
    123 
    124   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, ListHead) {
    125     Node = NET_LIST_USER_STRUCT (Entry, IP6_ADDRESS_INFO_ENTRY, Link);
    126     RemoveEntryList (&Node->Link);
    127     FreePool (Node);
    128   }
    129 }
    130 
    131 /**
    132   Convert the IPv6 address into a formatted string.
    133 
    134   @param[in]  Ip6       The IPv6 address.
    135   @param[out] Str       The formatted IP string.
    136 
    137 **/
    138 VOID
    139 Ip6ToStr (
    140   IN  EFI_IPv6_ADDRESS  *Ip6,
    141   OUT CHAR16            *Str
    142   )
    143 {
    144   UINTN                 Index;
    145   BOOLEAN               Short;
    146   UINTN                 Number;
    147   CHAR16                FormatString[8];
    148 
    149   Short = FALSE;
    150 
    151   for (Index = 0; Index < 15; Index = Index + 2) {
    152     if (!Short &&
    153         Index % 2 == 0 &&
    154         Ip6->Addr[Index] == 0 &&
    155         Ip6->Addr[Index + 1] == 0
    156         ) {
    157       //
    158       // Deal with the case of ::.
    159       //
    160       if (Index == 0) {
    161         *Str       = L':';
    162         *(Str + 1) = L':';
    163         Str        = Str + 2;
    164       } else {
    165         *Str       = L':';
    166         Str        = Str + 1;
    167       }
    168 
    169       while ((Index < 15) && (Ip6->Addr[Index] == 0) && (Ip6->Addr[Index + 1] == 0)) {
    170         Index = Index + 2;
    171       }
    172 
    173       Short = TRUE;
    174 
    175       if (Index == 16) {
    176         //
    177         // :: is at the end of the address.
    178         //
    179         *Str = L'\0';
    180         break;
    181       }
    182     }
    183 
    184     ASSERT (Index < 15);
    185 
    186     if (Ip6->Addr[Index] == 0) {
    187       Number = UnicodeSPrint (Str, 2 * IP6_STR_MAX_SIZE, L"%x:", (UINTN) Ip6->Addr[Index + 1]);
    188     } else {
    189       if (Ip6->Addr[Index + 1] < 0x10) {
    190         CopyMem (FormatString, L"%x0%x:", StrSize (L"%x0%x:"));
    191       } else {
    192         CopyMem (FormatString, L"%x%x:", StrSize (L"%x%x:"));
    193       }
    194 
    195       Number = UnicodeSPrint (
    196                  Str,
    197                  2 * IP6_STR_MAX_SIZE,
    198                  (CONST CHAR16 *) FormatString,
    199                  (UINTN) Ip6->Addr[Index],
    200                  (UINTN) Ip6->Addr[Index + 1]
    201                  );
    202     }
    203 
    204     Str = Str + Number;
    205 
    206     if (Index + 2 == 16) {
    207       *Str = L'\0';
    208       if (*(Str - 1) == L':') {
    209         *(Str - 1) = L'\0';
    210       }
    211     }
    212   }
    213 }
    214 
    215 /**
    216   Convert EFI_IP6_CONFIG_INTERFACE_ID to string format.
    217 
    218   @param[out]      String  The buffer to store the converted string.
    219   @param[in]       IfId    The pointer of EFI_IP6_CONFIG_INTERFACE_ID.
    220 
    221   @retval EFI_SUCCESS              The string converted successfully.
    222   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
    223 
    224 **/
    225 EFI_STATUS
    226 Ip6ConvertInterfaceIdToString (
    227   OUT CHAR16                         *String,
    228   IN  EFI_IP6_CONFIG_INTERFACE_ID    *IfId
    229   )
    230 {
    231   UINT8                          Index;
    232   UINTN                          Number;
    233 
    234   if ((String == NULL) || (IfId == NULL)) {
    235     return EFI_INVALID_PARAMETER;
    236   }
    237 
    238   for (Index = 0; Index < 8; Index++) {
    239     Number = UnicodeSPrint (
    240                String,
    241                2 * INTERFACE_ID_STR_STORAGE,
    242                L"%x:",
    243                (UINTN) IfId->Id[Index]
    244                );
    245     String = String + Number;
    246   }
    247 
    248   *(String - 1) = '\0';
    249 
    250   return EFI_SUCCESS;
    251 }
    252 
    253 /**
    254   Parse InterfaceId in string format and convert it to EFI_IP6_CONFIG_INTERFACE_ID.
    255 
    256   @param[in]        String  The buffer of the string to be parsed.
    257   @param[out]       IfId    The pointer of EFI_IP6_CONFIG_INTERFACE_ID.
    258 
    259   @retval EFI_SUCCESS              The operation finished successfully.
    260   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
    261 
    262 **/
    263 EFI_STATUS
    264 Ip6ParseInterfaceIdFromString (
    265   IN CONST CHAR16                    *String,
    266   OUT EFI_IP6_CONFIG_INTERFACE_ID    *IfId
    267   )
    268 {
    269   UINT8                          Index;
    270   CHAR16                         *IfIdStr;
    271   CHAR16                         *TempStr;
    272   UINTN                          NodeVal;
    273 
    274   if ((String == NULL) || (IfId == NULL)) {
    275     return EFI_INVALID_PARAMETER;
    276   }
    277 
    278   IfIdStr = (CHAR16 *) String;
    279 
    280   ZeroMem (IfId, sizeof (EFI_IP6_CONFIG_INTERFACE_ID));
    281 
    282   for (Index = 0; Index < 8; Index++) {
    283     TempStr = IfIdStr;
    284 
    285     while ((*IfIdStr != L'\0') && (*IfIdStr != L':')) {
    286       IfIdStr++;
    287     }
    288 
    289     //
    290     // The InterfaceId format is X:X:X:X, the number of X should not exceed 8.
    291     // If the number of X is less than 8, zero is appended to the InterfaceId.
    292     //
    293     if ((*IfIdStr == ':') && (Index == 7)) {
    294       return EFI_INVALID_PARAMETER;
    295     }
    296 
    297     //
    298     // Convert the string to interface id. AsciiStrHexToUintn stops at the
    299     // first character that is not a valid hex character, ':' or '\0' here.
    300     //
    301     NodeVal = StrHexToUintn (TempStr);
    302     if (NodeVal > 0xFF) {
    303       return EFI_INVALID_PARAMETER;
    304     }
    305 
    306     IfId->Id[Index] = (UINT8) NodeVal;
    307 
    308     IfIdStr++;
    309   }
    310 
    311   return EFI_SUCCESS;
    312 }
    313 
    314 /**
    315   Create Hii Extend Label OpCode as the start opcode and end opcode. It is
    316   a help function.
    317 
    318   @param[in]  StartLabelNumber   The number of start label.
    319   @param[out] StartOpCodeHandle  Points to the start opcode handle.
    320   @param[out] StartLabel         Points to the created start opcode.
    321   @param[out] EndOpCodeHandle    Points to the end opcode handle.
    322   @param[out] EndLabel           Points to the created end opcode.
    323 
    324   @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this
    325                                  operation.
    326   @retval EFI_INVALID_PARAMETER  Any input parameter is invalid.
    327   @retval EFI_SUCCESS            The operation completed successfully.
    328 
    329 **/
    330 EFI_STATUS
    331 Ip6CreateOpCode (
    332   IN  UINT16                        StartLabelNumber,
    333   OUT VOID                          **StartOpCodeHandle,
    334   OUT EFI_IFR_GUID_LABEL            **StartLabel,
    335   OUT VOID                          **EndOpCodeHandle,
    336   OUT EFI_IFR_GUID_LABEL            **EndLabel
    337   )
    338 {
    339   EFI_STATUS                        Status;
    340   EFI_IFR_GUID_LABEL                *InternalStartLabel;
    341   EFI_IFR_GUID_LABEL                *InternalEndLabel;
    342 
    343   if (StartOpCodeHandle == NULL || StartLabel == NULL || EndOpCodeHandle == NULL || EndLabel == NULL) {
    344     return EFI_INVALID_PARAMETER;
    345   }
    346 
    347   *StartOpCodeHandle = NULL;
    348   *EndOpCodeHandle   = NULL;
    349   Status             = EFI_OUT_OF_RESOURCES;
    350 
    351   //
    352   // Initialize the container for dynamic opcodes.
    353   //
    354   *StartOpCodeHandle = HiiAllocateOpCodeHandle ();
    355   if (*StartOpCodeHandle == NULL) {
    356     return Status;
    357   }
    358 
    359   *EndOpCodeHandle = HiiAllocateOpCodeHandle ();
    360   if (*EndOpCodeHandle == NULL) {
    361     goto Exit;
    362   }
    363 
    364   //
    365   // Create Hii Extend Label OpCode as the start opcode.
    366   //
    367   InternalStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
    368                                                 *StartOpCodeHandle,
    369                                                 &gEfiIfrTianoGuid,
    370                                                 NULL,
    371                                                 sizeof (EFI_IFR_GUID_LABEL)
    372                                                 );
    373   if (InternalStartLabel == NULL) {
    374     goto Exit;
    375   }
    376 
    377   InternalStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    378   InternalStartLabel->Number       = StartLabelNumber;
    379 
    380   //
    381   // Create Hii Extend Label OpCode as the end opcode.
    382   //
    383   InternalEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
    384                                               *EndOpCodeHandle,
    385                                               &gEfiIfrTianoGuid,
    386                                               NULL,
    387                                               sizeof (EFI_IFR_GUID_LABEL)
    388                                               );
    389   if (InternalEndLabel == NULL) {
    390     goto Exit;
    391   }
    392 
    393   InternalEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    394   InternalEndLabel->Number       = LABEL_END;
    395 
    396   *StartLabel = InternalStartLabel;
    397   *EndLabel   = InternalEndLabel;
    398 
    399   return EFI_SUCCESS;
    400 
    401 Exit:
    402 
    403   if (*StartOpCodeHandle != NULL) {
    404     HiiFreeOpCodeHandle (*StartOpCodeHandle);
    405   }
    406 
    407   if (*EndOpCodeHandle != NULL) {
    408     HiiFreeOpCodeHandle (*EndOpCodeHandle);
    409   }
    410 
    411   return Status;
    412 }
    413 
    414 /**
    415   This function converts the different format of address list to string format and
    416   then generates the corresponding text opcode to illustarate the address info in
    417   IP6 configuration page. Currently, the following formats are supported:
    418   EFI_IP6_ADDRESS_INFO AddressType: Ip6ConfigNvHostAddress;
    419   EFI_IPv6_ADDRESS     AddressType: Ip6ConfigNvGatewayAddress and Ip6ConfigNvDnsAddress;
    420   EFI_IP6_ROUTE_TABLE  AddressType: Ip6ConfigNvRouteTable.
    421 
    422   @param[in, out] String           The pointer to the buffer to store the converted
    423                                    string.
    424   @param[in]      HiiHandle        A handle that was previously registered in the
    425                                    HII Database.
    426   @param[in]      AddressType      The address type.
    427   @param[in]      AddressInfo      Pointer to the address list.
    428   @param[in]      AddressCount     The address count of the address list.
    429 
    430   @retval EFI_SUCCESS              The operation finished successfully.
    431   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
    432   @retval EFI_UNSUPPORTED          The AddressType is not supported.
    433 
    434 
    435 **/
    436 EFI_STATUS
    437 Ip6ConvertAddressListToString (
    438   IN OUT CHAR16                         *String,
    439   IN     EFI_HII_HANDLE                 HiiHandle,
    440   IN     IP6_CONFIG_NV_ADDRESS_TYPE     AddressType,
    441   IN     VOID                           *AddressInfo,
    442   IN     UINTN                          AddressCount
    443   )
    444 {
    445   UINTN                          Index;
    446   UINTN                          Number;
    447   CHAR16                         *TempStr;
    448   EFI_STATUS                     Status;
    449   VOID                           *StartOpCodeHandle;
    450   EFI_IFR_GUID_LABEL             *StartLabel;
    451   VOID                           *EndOpCodeHandle;
    452   EFI_IFR_GUID_LABEL             *EndLabel;
    453   UINT16                         StartLabelNumber;
    454   EFI_STRING_ID                  TextTwo;
    455   UINT8                          *AddressHead;
    456   UINT8                          PrefixLength;
    457   EFI_IPv6_ADDRESS               *Address;
    458 
    459   if ((String == NULL) || (HiiHandle == NULL) || (AddressInfo == NULL)) {
    460     return EFI_INVALID_PARAMETER;
    461   }
    462 
    463   if (AddressType == Ip6ConfigNvHostAddress) {
    464     StartLabelNumber = HOST_ADDRESS_LABEL;
    465   } else if (AddressType == Ip6ConfigNvGatewayAddress) {
    466     StartLabelNumber = GATEWAY_ADDRESS_LABEL;
    467   } else if (AddressType == Ip6ConfigNvDnsAddress) {
    468     StartLabelNumber = DNS_ADDRESS_LABEL;
    469   } else if (AddressType == Ip6ConfigNvRouteTable) {
    470     StartLabelNumber = ROUTE_TABLE_LABEL;
    471   } else {
    472     ASSERT (FALSE);
    473     return EFI_UNSUPPORTED;
    474   }
    475 
    476   Status = Ip6CreateOpCode (
    477              StartLabelNumber,
    478              &StartOpCodeHandle,
    479              &StartLabel,
    480              &EndOpCodeHandle,
    481              &EndLabel
    482              );
    483   if (EFI_ERROR (Status)) {
    484     return Status;
    485   }
    486 
    487   AddressHead = (UINT8 *) AddressInfo;
    488 
    489   for (Index = 0; Index < AddressCount; Index++) {
    490     if (AddressType == Ip6ConfigNvHostAddress) {
    491       AddressInfo = AddressHead + sizeof (EFI_IP6_ADDRESS_INFO) * Index;
    492       Address     = &((EFI_IP6_ADDRESS_INFO *) AddressInfo)->Address;
    493     } else if (AddressType == Ip6ConfigNvRouteTable) {
    494       AddressInfo = AddressHead + sizeof (EFI_IP6_ROUTE_TABLE) * Index;
    495       Address     = &((EFI_IP6_ROUTE_TABLE *) AddressInfo)->Destination;
    496     } else {
    497       AddressInfo = AddressHead + sizeof (EFI_IPv6_ADDRESS) * Index;
    498       Address     = AddressInfo;
    499     }
    500 
    501     //
    502     // Convert the IP address info to string.
    503     //
    504     Ip6ToStr (Address, String);
    505     TempStr = String + StrLen (String);
    506 
    507     if ((AddressType == Ip6ConfigNvHostAddress) || (AddressType == Ip6ConfigNvRouteTable)) {
    508       if (AddressType == Ip6ConfigNvHostAddress) {
    509         PrefixLength = ((EFI_IP6_ADDRESS_INFO *) AddressInfo)->PrefixLength;
    510       } else {
    511         PrefixLength = ((EFI_IP6_ROUTE_TABLE *) AddressInfo)->PrefixLength;
    512       }
    513 
    514       //
    515       // Append the prefix length to the string.
    516       //
    517       *TempStr = L'/';
    518       TempStr++;
    519       Number  = UnicodeSPrint (TempStr, 6, L"%d", PrefixLength);
    520       TempStr = TempStr + Number;
    521     }
    522 
    523     if (AddressType == Ip6ConfigNvRouteTable) {
    524       //
    525       // Append " >> " to the string.
    526       //
    527       Number   = UnicodeSPrint (TempStr, 8, L" >>  ");
    528       TempStr  = TempStr + Number;
    529 
    530       //
    531       // Append the gateway address to the string.
    532       //
    533       Ip6ToStr (&((EFI_IP6_ROUTE_TABLE *) AddressInfo)->Gateway, TempStr);
    534       TempStr = TempStr + StrLen (TempStr);
    535     }
    536 
    537     //
    538     // Generate a text opcode and update the UI.
    539     //
    540     TextTwo = HiiSetString (HiiHandle, 0, String, NULL);
    541     if (TextTwo == 0) {
    542       Status = EFI_INVALID_PARAMETER;
    543       goto Exit;
    544     }
    545 
    546     HiiCreateTextOpCode (StartOpCodeHandle, STR_NULL, STR_NULL, TextTwo);
    547 
    548     String = TempStr;
    549     *String = IP6_ADDRESS_DELIMITER;
    550     String++;
    551   }
    552 
    553   *(String - 1) = '\0';
    554 
    555   Status = HiiUpdateForm (
    556              HiiHandle,                       // HII handle
    557              &gIp6ConfigNvDataGuid,           // Formset GUID
    558              FORMID_MAIN_FORM,                // Form ID
    559              StartOpCodeHandle,               // Label for where to insert opcodes
    560              EndOpCodeHandle                  // Replace data
    561              );
    562 
    563 Exit:
    564   HiiFreeOpCodeHandle (StartOpCodeHandle);
    565   HiiFreeOpCodeHandle (EndOpCodeHandle);
    566 
    567   return Status;
    568 }
    569 
    570 /**
    571   Parse address list in string format and convert it to a list array of node in
    572   IP6_ADDRESS_INFO_ENTRY.
    573 
    574   @param[in]        String         The buffer to string to be parsed.
    575   @param[out]       ListHead       The list head of array.
    576   @param[out]       AddressCount   The number of list nodes in the array.
    577 
    578   @retval EFI_SUCCESS              The operation finished successfully.
    579   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
    580   @retval EFI_OUT_OF_RESOURCES     Failed to perform the operation due to lack of resource.
    581 
    582 **/
    583 EFI_STATUS
    584 Ip6ParseAddressListFromString (
    585   IN CONST CHAR16                    *String,
    586   OUT LIST_ENTRY                     *ListHead,
    587   OUT UINT32                         *AddressCount
    588   )
    589 {
    590   EFI_STATUS                     Status;
    591   CHAR16                         *LocalString;
    592   CHAR16                         *Temp;
    593   CHAR16                         *TempStr;
    594   EFI_IP6_ADDRESS_INFO           AddressInfo;
    595   IP6_ADDRESS_INFO_ENTRY         *Node;
    596   BOOLEAN                        Last;
    597   UINT32                         Count;
    598 
    599   if ((String == NULL) || (ListHead == NULL) || (AddressCount == NULL)) {
    600     return EFI_INVALID_PARAMETER;
    601   }
    602 
    603   ZeroMem (&AddressInfo, sizeof (EFI_IP6_ADDRESS_INFO));
    604   LocalString = (CHAR16 *) AllocateCopyPool (StrSize (String), String);
    605   if (LocalString == NULL) {
    606     return EFI_OUT_OF_RESOURCES;
    607   }
    608 
    609   //
    610   // Clean the original address list.
    611   //
    612   Ip6FreeAddressInfoList (ListHead);
    613 
    614   Temp  = LocalString;
    615   Last  = FALSE;
    616   Count = 0;
    617 
    618   while (*LocalString != L'\0') {
    619     TempStr = LocalString;
    620     while ((*LocalString != L'\0') && (*LocalString != IP6_ADDRESS_DELIMITER)) {
    621       LocalString++;
    622     }
    623 
    624     if (*LocalString == L'\0') {
    625       Last = TRUE;
    626     }
    627 
    628     *LocalString = L'\0';
    629 
    630     Status = NetLibStrToIp6andPrefix (TempStr, &AddressInfo.Address, &AddressInfo.PrefixLength);
    631     if (EFI_ERROR (Status)) {
    632       goto Error;
    633     }
    634 
    635     if (AddressInfo.PrefixLength == 0xFF) {
    636       AddressInfo.PrefixLength = 0;
    637     }
    638 
    639     if (!NetIp6IsValidUnicast (&AddressInfo.Address)) {
    640       Status = EFI_INVALID_PARAMETER;
    641       goto Error;
    642     }
    643 
    644     Node = AllocatePool (sizeof (IP6_ADDRESS_INFO_ENTRY));
    645     if (Node == NULL) {
    646       Status = EFI_OUT_OF_RESOURCES;
    647       goto Error;
    648     }
    649 
    650     CopyMem (&Node->AddrInfo, &AddressInfo, sizeof (EFI_IP6_ADDRESS_INFO));
    651     InsertTailList (ListHead, &Node->Link);
    652     Count++;
    653 
    654     if (Last) {
    655       break;
    656     }
    657 
    658     LocalString++;
    659   }
    660 
    661   FreePool (Temp);
    662   *AddressCount = Count;
    663   return EFI_SUCCESS;
    664 
    665 Error:
    666   Ip6FreeAddressInfoList (ListHead);
    667   FreePool (Temp);
    668   return Status;
    669 }
    670 
    671 /**
    672   This function converts the interface info to string and draws it to the IP6 UI.
    673   The interface information includes interface name, interface type, hardware
    674   address and route table information.
    675 
    676   @param[in]       IfInfo          The pointer of EFI_IP6_CONFIG_INTERFACE_INFO.
    677   @param[in]       HiiHandle       The handle that was previously registered in the
    678                                    HII Database.
    679   @param[in, out]  IfrNvData       Points to IP6_CONFIG_IFR_NVDATA.
    680 
    681   @retval EFI_SUCCESS              The operation finished successfully.
    682   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
    683   @retval EFI_OUT_OF_RESOURCES     The operation failed due to lack of resources.
    684 
    685 **/
    686 EFI_STATUS
    687 Ip6ConvertInterfaceInfoToString (
    688   IN     EFI_IP6_CONFIG_INTERFACE_INFO  *IfInfo,
    689   IN     EFI_HII_HANDLE                 HiiHandle,
    690   IN OUT IP6_CONFIG_IFR_NVDATA          *IfrNvData
    691   )
    692 {
    693   UINT32                         Index;
    694   UINTN                          Number;
    695   CHAR16                         *String;
    696   CHAR16                         PortString[ADDRESS_STR_MAX_SIZE];
    697   CHAR16                         FormatString[8];
    698   EFI_STRING_ID                  StringId;
    699 
    700   if ((IfInfo == NULL) || (HiiHandle == NULL) || (IfrNvData == NULL)) {
    701     return EFI_INVALID_PARAMETER;
    702   }
    703 
    704   //
    705   // Print the interface name.
    706   //
    707   StringId = HiiSetString (
    708                HiiHandle,
    709                STRING_TOKEN (STR_IP6_INTERFACE_NAME_CONTENT),
    710                IfInfo->Name,
    711                NULL
    712                );
    713   if (StringId == 0) {
    714     return EFI_OUT_OF_RESOURCES;
    715   }
    716 
    717   //
    718   // Print the interface type.
    719   //
    720   if (IfInfo->IfType == Ip6InterfaceTypeEthernet) {
    721     CopyMem (PortString, IP6_ETHERNET, sizeof (IP6_ETHERNET));
    722   } else if (IfInfo->IfType == Ip6InterfaceTypeExperimentalEthernet) {
    723     CopyMem (PortString, IP6_EXPERIMENTAL_ETHERNET, sizeof (IP6_EXPERIMENTAL_ETHERNET));
    724   } else {
    725     //
    726     // Refer to RFC1700, chapter Number Hardware Type.
    727     //
    728     UnicodeSPrint (PortString, 6, L"%d", IfInfo->IfType);
    729   }
    730 
    731   StringId = HiiSetString (
    732                HiiHandle,
    733                STRING_TOKEN (STR_IP6_INTERFACE_TYPE_CONTENT),
    734                PortString,
    735                NULL
    736                );
    737   if (StringId == 0) {
    738     return EFI_OUT_OF_RESOURCES;
    739   }
    740 
    741   //
    742   // Convert the hardware address.
    743   //
    744   String = PortString;
    745   ASSERT (IfInfo->HwAddressSize <= 32);
    746 
    747   for (Index = 0; Index < IfInfo->HwAddressSize; Index++) {
    748 
    749     if (IfInfo->HwAddress.Addr[Index] < 0x10) {
    750       CopyMem (FormatString, L"0%x-", sizeof (L"0%x-"));
    751     } else {
    752       CopyMem (FormatString, L"%x-", sizeof (L"%x-"));
    753     }
    754 
    755     Number = UnicodeSPrint (
    756                String,
    757                8,
    758                (CONST CHAR16 *) FormatString,
    759                (UINTN) IfInfo->HwAddress.Addr[Index]
    760                );
    761     String = String + Number;
    762   }
    763 
    764   if (Index != 0) {
    765     ASSERT (String > PortString);
    766     String--;
    767     *String = '\0';
    768   }
    769 
    770   //
    771   // Print the hardware address.
    772   //
    773   StringId = HiiSetString (
    774                HiiHandle,
    775                STRING_TOKEN (STR_IP6_MAC_ADDRESS_CONTENT),
    776                PortString,
    777                NULL
    778                );
    779   if (StringId == 0) {
    780     return EFI_OUT_OF_RESOURCES;
    781   }
    782 
    783   return EFI_SUCCESS;
    784 }
    785 
    786 /**
    787   Build the address info list from list array of node in IP6_ADDRESS_INFO_ENTRY.
    788 
    789   @param[in]      Instance         Points to IP6 config instance data.
    790   @param[in]      AddressType      The address type.
    791   @param[out]     AddressInfo      The pointer to the buffer to store the address list.
    792   @param[out]     AddressSize      The address size of the address list.
    793 
    794   @retval EFI_SUCCESS              The operation finished successfully.
    795   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
    796   @retval EFI_UNSUPPORTED          The AddressType is not supported.
    797 
    798 **/
    799 EFI_STATUS
    800 Ip6BuildNvAddressInfo (
    801   IN  IP6_CONFIG_INSTANCE            *Instance,
    802   IN  IP6_CONFIG_NV_ADDRESS_TYPE     AddressType,
    803   OUT VOID                           **AddressInfo,
    804   OUT UINTN                          *AddressSize
    805   )
    806 {
    807   IP6_CONFIG_NVDATA                  *Ip6NvData;
    808   LIST_ENTRY                         *Entry;
    809   LIST_ENTRY                         *ListHead;
    810   IP6_ADDRESS_INFO_ENTRY             *Node;
    811   VOID                               *AddressList;
    812   VOID                               *TmpStr;
    813   UINTN                              DataSize;
    814   EFI_IPv6_ADDRESS                   *Ip6Address;
    815   EFI_IP6_CONFIG_MANUAL_ADDRESS      *ManualAddress;
    816 
    817   if ((Instance == NULL) || (AddressInfo == NULL) || (AddressSize == NULL)) {
    818     return EFI_INVALID_PARAMETER;
    819   }
    820 
    821   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
    822 
    823   Ip6NvData = &Instance->Ip6NvData;
    824 
    825   if (AddressType == Ip6ConfigNvHostAddress) {
    826     ListHead = &Ip6NvData->ManualAddress;
    827     DataSize = sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS) * Ip6NvData->ManualAddressCount;
    828   } else if (AddressType == Ip6ConfigNvGatewayAddress) {
    829     ListHead = &Ip6NvData->GatewayAddress;
    830     DataSize = sizeof (EFI_IPv6_ADDRESS) * Ip6NvData->GatewayAddressCount;
    831   } else if (AddressType == Ip6ConfigNvDnsAddress) {
    832     ListHead = &Ip6NvData->DnsAddress;
    833     DataSize = sizeof (EFI_IPv6_ADDRESS) * Ip6NvData->DnsAddressCount;
    834   } else {
    835     return EFI_UNSUPPORTED;
    836   }
    837 
    838   AddressList = AllocateZeroPool (DataSize);
    839   if (AddressList  == NULL) {
    840     return EFI_OUT_OF_RESOURCES;
    841   }
    842 
    843   TmpStr = AddressList;
    844 
    845   NET_LIST_FOR_EACH (Entry, ListHead) {
    846     Node = NET_LIST_USER_STRUCT (Entry, IP6_ADDRESS_INFO_ENTRY, Link);
    847     if (AddressType == Ip6ConfigNvHostAddress) {
    848       ManualAddress = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) AddressList;
    849       IP6_COPY_ADDRESS (&ManualAddress->Address, &Node->AddrInfo.Address);
    850       ManualAddress->PrefixLength = Node->AddrInfo.PrefixLength;
    851       AddressList = (UINT8 *) AddressList + sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);
    852     } else {
    853       Ip6Address = (EFI_IPv6_ADDRESS *) AddressList;
    854       IP6_COPY_ADDRESS (Ip6Address, &Node->AddrInfo.Address);
    855       AddressList = (UINT8 *) AddressList + sizeof (EFI_IPv6_ADDRESS);
    856     }
    857   }
    858 
    859   *AddressInfo = TmpStr;
    860   *AddressSize = DataSize;
    861   return EFI_SUCCESS;
    862 }
    863 
    864 /**
    865   Convert the IP6 configuration data into the IFR data.
    866 
    867   @param[in, out]  IfrNvData       The IFR NV data.
    868   @param[in]       Instance        The IP6 config instance data.
    869 
    870   @retval EFI_SUCCESS              The operation finished successfully.
    871   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
    872   @retval EFI_UNSUPPORTED          The policy is not supported in the current implementation.
    873   @retval Others                   Other errors as indicated.
    874 
    875 **/
    876 EFI_STATUS
    877 Ip6ConvertConfigNvDataToIfrNvData (
    878   IN OUT IP6_CONFIG_IFR_NVDATA       *IfrNvData,
    879   IN     IP6_CONFIG_INSTANCE         *Instance
    880   )
    881 {
    882   IP6_CONFIG_NVDATA                          *Ip6NvData;
    883   EFI_IP6_CONFIG_PROTOCOL                    *Ip6Config;
    884   UINTN                                      DataSize;
    885   VOID                                       *Data;
    886   EFI_STATUS                                 Status;
    887   EFI_IP6_CONFIG_POLICY                      Policy;
    888   EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS   DadXmits;
    889   EFI_HII_HANDLE                             HiiHandle;
    890 
    891   if ((IfrNvData == NULL) || (Instance == NULL)) {
    892     return EFI_INVALID_PARAMETER;
    893   }
    894 
    895   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
    896 
    897   Ip6Config = &Instance->Ip6Config;
    898   Ip6NvData = &Instance->Ip6NvData;
    899   Data      = NULL;
    900   DataSize  = 0;
    901   HiiHandle = Instance->CallbackInfo.RegisteredHandle;
    902 
    903   //
    904   // Get the current interface info.
    905   //
    906   Status = Ip6ConfigNvGetData (
    907              Ip6Config,
    908              Ip6ConfigDataTypeInterfaceInfo,
    909              &DataSize,
    910              (VOID **) &Data
    911              );
    912   if (EFI_ERROR (Status)) {
    913     goto Exit;
    914   }
    915 
    916   //
    917   // Convert the interface info to string and print.
    918   //
    919   Status = Ip6ConvertInterfaceInfoToString (
    920              (EFI_IP6_CONFIG_INTERFACE_INFO *) Data,
    921              HiiHandle,
    922              IfrNvData
    923              );
    924   if (EFI_ERROR (Status)) {
    925     goto Exit;
    926   }
    927 
    928   //
    929   // Get the interface id.
    930   //
    931   DataSize = sizeof (EFI_IP6_CONFIG_INTERFACE_ID);
    932   ZeroMem (&Ip6NvData->InterfaceId, DataSize);
    933   Status = Ip6Config->GetData (
    934                         Ip6Config,
    935                         Ip6ConfigDataTypeAltInterfaceId,
    936                         &DataSize,
    937                         &Ip6NvData->InterfaceId
    938                         );
    939   if (EFI_ERROR (Status)) {
    940     goto Exit;
    941   }
    942 
    943   Ip6ConvertInterfaceIdToString (IfrNvData->InterfaceId, &Ip6NvData->InterfaceId);
    944 
    945   //
    946   // Get current policy.
    947   //
    948   DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
    949   Status   = Ip6Config->GetData (
    950                           Ip6Config,
    951                           Ip6ConfigDataTypePolicy,
    952                           &DataSize,
    953                           &Policy
    954                           );
    955 
    956   if (EFI_ERROR (Status)) {
    957     goto Exit;
    958   }
    959 
    960   if (Policy == Ip6ConfigPolicyManual) {
    961     IfrNvData->Policy = IP6_POLICY_MANUAL;
    962   } else if (Policy == Ip6ConfigPolicyAutomatic) {
    963     IfrNvData->Policy = IP6_POLICY_AUTO;
    964   } else {
    965     ASSERT (FALSE);
    966     Status = EFI_UNSUPPORTED;
    967     goto Exit;
    968   }
    969 
    970   //
    971   // Get Duplicate Address Detection Transmits count.
    972   //
    973   DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
    974   Status   = Ip6Config->GetData (
    975                           Ip6Config,
    976                           Ip6ConfigDataTypeDupAddrDetectTransmits,
    977                           &DataSize,
    978                           &DadXmits
    979                           );
    980 
    981   if (EFI_ERROR (Status)) {
    982     goto Exit;
    983   }
    984 
    985   IfrNvData->DadTransmitCount = DadXmits.DupAddrDetectTransmits;
    986 
    987 Exit:
    988   if (Data != NULL) {
    989      FreePool (Data);
    990   }
    991 
    992   return Status;
    993 }
    994 
    995 /**
    996   Convert IFR data into IP6 configuration data. The policy, alternative interface
    997   ID, and DAD transmit counts, and will be saved.
    998 
    999   @param[in]       IfrNvData       The IFR NV data.
   1000   @param[in, out]  Instance        The IP6 config instance data.
   1001 
   1002   @retval EFI_SUCCESS              The operation finished successfully.
   1003   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
   1004   @retval Others                   Other errors as indicated.
   1005 
   1006 **/
   1007 EFI_STATUS
   1008 Ip6ConvertIfrNvDataToConfigNvDataGeneral (
   1009   IN     IP6_CONFIG_IFR_NVDATA       *IfrNvData,
   1010   IN OUT IP6_CONFIG_INSTANCE         *Instance
   1011   )
   1012 {
   1013   IP6_CONFIG_NVDATA                  *Ip6NvData;
   1014   EFI_IP6_CONFIG_PROTOCOL            *Ip6Config;
   1015   EFI_STATUS                         Status;
   1016 
   1017   if ((IfrNvData == NULL) || (Instance == NULL)) {
   1018     return EFI_INVALID_PARAMETER;
   1019   }
   1020 
   1021   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
   1022   Ip6NvData = &Instance->Ip6NvData;
   1023   Ip6Config = &Instance->Ip6Config;
   1024 
   1025   //
   1026   // Update those fields which don't have INTERACTIVE attribute.
   1027   //
   1028   if (IfrNvData->Policy == IP6_POLICY_AUTO) {
   1029     Ip6NvData->Policy = Ip6ConfigPolicyAutomatic;
   1030   } else if (IfrNvData->Policy == IP6_POLICY_MANUAL) {
   1031     Ip6NvData->Policy = Ip6ConfigPolicyManual;
   1032   }
   1033 
   1034   Ip6NvData->DadTransmitCount.DupAddrDetectTransmits = IfrNvData->DadTransmitCount;
   1035 
   1036   //
   1037   // Set the configured policy.
   1038   //
   1039   Status = Ip6Config->SetData (
   1040                         Ip6Config,
   1041                         Ip6ConfigDataTypePolicy,
   1042                         sizeof (EFI_IP6_CONFIG_POLICY),
   1043                         &Ip6NvData->Policy
   1044                         );
   1045   if (EFI_ERROR (Status)) {
   1046     return Status;
   1047   }
   1048 
   1049   //
   1050   // Set the duplicate address detection transmits count.
   1051   //
   1052   Status = Ip6Config->SetData (
   1053                         Ip6Config,
   1054                         Ip6ConfigDataTypeDupAddrDetectTransmits,
   1055                         sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS),
   1056                         &Ip6NvData->DadTransmitCount
   1057                         );
   1058   if (EFI_ERROR (Status)) {
   1059     return Status;
   1060   }
   1061 
   1062   //
   1063   // Set the alternative interface ID
   1064   //
   1065   Status = Ip6Config->SetData (
   1066                         Ip6Config,
   1067                         Ip6ConfigDataTypeAltInterfaceId,
   1068                         sizeof (EFI_IP6_CONFIG_INTERFACE_ID),
   1069                         &Ip6NvData->InterfaceId
   1070                         );
   1071   if (EFI_ERROR (Status)) {
   1072     return Status;
   1073   }
   1074 
   1075   return EFI_SUCCESS;
   1076 }
   1077 
   1078 /**
   1079   Convert IFR data into IP6 configuration data. The policy, configured
   1080   manual address, gateway address, and DNS server address will be saved.
   1081 
   1082   @param[in]       IfrNvData       The IFR NV data.
   1083   @param[in, out]  Instance        The IP6 config instance data.
   1084 
   1085   @retval EFI_SUCCESS              The operation finished successfully.
   1086   @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.
   1087   @retval Others                   Other errors as indicated.
   1088 
   1089 **/
   1090 EFI_STATUS
   1091 Ip6ConvertIfrNvDataToConfigNvDataAdvanced (
   1092   IN     IP6_CONFIG_IFR_NVDATA       *IfrNvData,
   1093   IN OUT IP6_CONFIG_INSTANCE         *Instance
   1094   )
   1095 {
   1096   IP6_CONFIG_NVDATA                  *Ip6NvData;
   1097   EFI_IP6_CONFIG_PROTOCOL            *Ip6Config;
   1098   EFI_STATUS                         Status;
   1099   EFI_IP6_CONFIG_MANUAL_ADDRESS      *ManualAddress;
   1100   EFI_IPv6_ADDRESS                   *Address;
   1101   BOOLEAN                            IsAddressOk;
   1102   EFI_EVENT                          SetAddressEvent;
   1103   EFI_EVENT                          TimeoutEvent;
   1104   UINTN                              DataSize;
   1105 
   1106   if ((IfrNvData == NULL) || (Instance == NULL)) {
   1107     return EFI_INVALID_PARAMETER;
   1108   }
   1109 
   1110   if (IfrNvData->Policy == IP6_POLICY_AUTO) {
   1111     return EFI_SUCCESS;
   1112   }
   1113 
   1114   NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);
   1115   Ip6NvData = &Instance->Ip6NvData;
   1116   Ip6Config = &Instance->Ip6Config;
   1117 
   1118   //
   1119   // Update those fields which don't have INTERACTIVE attribute.
   1120   //
   1121   Ip6NvData->Policy = Ip6ConfigPolicyManual;
   1122 
   1123   //
   1124   // Set the configured policy.
   1125   //
   1126   Status = Ip6Config->SetData (
   1127                         Ip6Config,
   1128                         Ip6ConfigDataTypePolicy,
   1129                         sizeof (EFI_IP6_CONFIG_POLICY),
   1130                         &Ip6NvData->Policy
   1131                         );
   1132   if (EFI_ERROR (Status)) {
   1133     return Status;
   1134   }
   1135 
   1136   //
   1137   // Create events & timers for asynchronous settings.
   1138   //
   1139   SetAddressEvent = NULL;
   1140   TimeoutEvent    = NULL;
   1141   ManualAddress   = NULL;
   1142   Address         = NULL;
   1143 
   1144   Status = gBS->CreateEvent (
   1145                   EVT_NOTIFY_SIGNAL,
   1146                   TPL_NOTIFY,
   1147                   Ip6ConfigManualAddressNotify,
   1148                   &IsAddressOk,
   1149                   &SetAddressEvent
   1150                   );
   1151   if (EFI_ERROR (Status)) {
   1152     goto Exit;
   1153   }
   1154 
   1155   Status = gBS->CreateEvent (
   1156                   EVT_TIMER,
   1157                   TPL_CALLBACK,
   1158                   NULL,
   1159                   NULL,
   1160                   &TimeoutEvent
   1161                   );
   1162   if (EFI_ERROR (Status)) {
   1163     goto Exit;
   1164   }
   1165 
   1166   //
   1167   // Set the manual address list. This is an asynchronous process.
   1168   //
   1169   if (!IsListEmpty (&Ip6NvData->ManualAddress) && (Ip6NvData->ManualAddressCount != 0)) {
   1170     Status = Ip6BuildNvAddressInfo (
   1171                Instance,
   1172                Ip6ConfigNvHostAddress,
   1173                (VOID **) &ManualAddress,
   1174                &DataSize
   1175                );
   1176     if (EFI_ERROR (Status)) {
   1177       goto Exit;
   1178     }
   1179 
   1180     IsAddressOk = FALSE;
   1181 
   1182     Status = Ip6Config->RegisterDataNotify (
   1183                           Ip6Config,
   1184                           Ip6ConfigDataTypeManualAddress,
   1185                           SetAddressEvent
   1186                           );
   1187     if (EFI_ERROR (Status)) {
   1188       goto Exit;
   1189     }
   1190 
   1191     Status = Ip6Config->SetData (
   1192                           Ip6Config,
   1193                           Ip6ConfigDataTypeManualAddress,
   1194                           DataSize,
   1195                           (VOID *) ManualAddress
   1196                           );
   1197     if (Status == EFI_NOT_READY) {
   1198       gBS->SetTimer (TimeoutEvent, TimerRelative, 50000000);
   1199       while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
   1200         if (IsAddressOk) {
   1201           Status = EFI_SUCCESS;
   1202         }
   1203         break;
   1204       }
   1205     }
   1206 
   1207     Status = Ip6Config->UnregisterDataNotify (
   1208                           Ip6Config,
   1209                           Ip6ConfigDataTypeManualAddress,
   1210                           SetAddressEvent
   1211                           );
   1212     if (EFI_ERROR (Status)) {
   1213       goto Exit;
   1214     }
   1215   }
   1216 
   1217   //
   1218   // Set gateway address list.
   1219   //
   1220   if (!IsListEmpty (&Ip6NvData->GatewayAddress) && (Ip6NvData->GatewayAddressCount != 0)) {
   1221     Status = Ip6BuildNvAddressInfo (
   1222                Instance,
   1223                Ip6ConfigNvGatewayAddress,
   1224                (VOID **) &Address,
   1225                &DataSize
   1226                );
   1227     if (EFI_ERROR (Status)) {
   1228       goto Exit;
   1229     }
   1230 
   1231     Status = Ip6Config->SetData (
   1232                           Ip6Config,
   1233                           Ip6ConfigDataTypeGateway,
   1234                           DataSize,
   1235                           (VOID *) Address
   1236                           );
   1237     if (EFI_ERROR (Status)) {
   1238       goto Exit;
   1239     }
   1240 
   1241     FreePool (Address);
   1242     Address = NULL;
   1243   }
   1244 
   1245   //
   1246   // Set DNS server address list.
   1247   //
   1248   if (!IsListEmpty (&Ip6NvData->DnsAddress) && (Ip6NvData->DnsAddressCount != 0)) {
   1249     Status = Ip6BuildNvAddressInfo (
   1250                Instance,
   1251                Ip6ConfigNvDnsAddress,
   1252                (VOID **) &Address,
   1253                &DataSize
   1254                );
   1255     if (EFI_ERROR (Status)) {
   1256       goto Exit;
   1257     }
   1258 
   1259     Status = Ip6Config->SetData (
   1260                           Ip6Config,
   1261                           Ip6ConfigDataTypeDnsServer,
   1262                           DataSize,
   1263                           (VOID *) Address
   1264                           );
   1265     if (EFI_ERROR (Status)) {
   1266       goto Exit;
   1267     }
   1268   }
   1269 
   1270   Status = EFI_SUCCESS;
   1271 
   1272 Exit:
   1273   if (SetAddressEvent != NULL) {
   1274     gBS->CloseEvent (SetAddressEvent);
   1275   }
   1276 
   1277   if (TimeoutEvent != NULL) {
   1278     gBS->CloseEvent (TimeoutEvent);
   1279   }
   1280 
   1281   if (ManualAddress != NULL) {
   1282     FreePool (ManualAddress);
   1283   }
   1284 
   1285   if (Address != NULL) {
   1286     FreePool (Address);
   1287   }
   1288 
   1289   return Status;
   1290 }
   1291 
   1292 
   1293 /**
   1294   This function allows the caller to request the current
   1295   configuration for one or more named elements. The resulting
   1296   string is in <ConfigAltResp> format. Any and all alternative
   1297   configuration strings shall also be appended to the end of the
   1298   current configuration string. If they are, they must appear
   1299   after the current configuration. They must contain the same
   1300   routing (GUID, NAME, PATH) as the current configuration string.
   1301   They must have an additional description indicating the type of
   1302   alternative configuration the string represents,
   1303   "ALTCFG=<StringToken>". That <StringToken> (when
   1304   converted from Hex UNICODE to binary) is a reference to a
   1305   string in the associated string pack.
   1306 
   1307   @param[in] This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
   1308   @param[in] Request    A null-terminated Unicode string in
   1309                         <ConfigRequest> format. Note that this
   1310                         includes the routing information as well as
   1311                         the configurable name / value pairs. It is
   1312                         invalid for this string to be in
   1313                         <MultiConfigRequest> format.
   1314   @param[out] Progress  On return, points to a character in the
   1315                         Request string. Points to the string's null
   1316                         terminator if request was successful. Points
   1317                         to the most recent "&" before the first
   1318                         failing name / value pair (or the beginning
   1319                         of the string if the failure is in the first
   1320                         name / value pair) if the request was not
   1321                         successful.
   1322   @param[out] Results   A null-terminated Unicode string in
   1323                         <ConfigAltResp> format which has all values
   1324                         filled in for the names in the Request string.
   1325                         String to be allocated by the called function.
   1326 
   1327   @retval EFI_SUCCESS             The Results string is filled with the
   1328                                   values corresponding to all requested
   1329                                   names.
   1330   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
   1331                                   parts of the results that must be
   1332                                   stored awaiting possible future
   1333                                   protocols.
   1334   @retval EFI_INVALID_PARAMETER   For example, passing in a NULL
   1335                                   for the Request parameter
   1336                                   would result in this type of
   1337                                   error. In this case, the
   1338                                   Progress parameter would be
   1339                                   set to NULL.
   1340   @retval EFI_NOT_FOUND           Routing data doesn't match any
   1341                                   known driver. Progress set to the
   1342                                   first character in the routing header.
   1343                                   Note: There is no requirement that the
   1344                                   driver validate the routing data. It
   1345                                   must skip the <ConfigHdr> in order to
   1346                                   process the names.
   1347   @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set
   1348                                   to most recent & before the
   1349                                   error or the beginning of the
   1350                                   string.
   1351   @retval EFI_INVALID_PARAMETER   Unknown name. Progress points
   1352                                   to the & before the name in
   1353                                   question. Currently not implemented.
   1354 **/
   1355 EFI_STATUS
   1356 EFIAPI
   1357 Ip6FormExtractConfig (
   1358   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
   1359   IN  CONST EFI_STRING                       Request,
   1360   OUT EFI_STRING                             *Progress,
   1361   OUT EFI_STRING                             *Results
   1362   )
   1363 {
   1364 
   1365   EFI_STATUS                                 Status;
   1366   IP6_FORM_CALLBACK_INFO                     *Private;
   1367   IP6_CONFIG_INSTANCE                        *Ip6ConfigInstance;
   1368   IP6_CONFIG_IFR_NVDATA                      *IfrNvData;
   1369   EFI_STRING                                 ConfigRequestHdr;
   1370   EFI_STRING                                 ConfigRequest;
   1371   BOOLEAN                                    AllocatedRequest;
   1372   UINTN                                      Size;
   1373   UINTN                                      BufferSize;
   1374 
   1375   if (This == NULL || Progress == NULL || Results == NULL) {
   1376     return EFI_INVALID_PARAMETER;
   1377   }
   1378 
   1379   *Progress = Request;
   1380   if ((Request != NULL) &&
   1381       !HiiIsConfigHdrMatch (Request, &gIp6ConfigNvDataGuid, mIp6ConfigStorageName)) {
   1382     return EFI_NOT_FOUND;
   1383   }
   1384 
   1385   ConfigRequestHdr = NULL;
   1386   ConfigRequest    = NULL;
   1387   AllocatedRequest = FALSE;
   1388   Size             = 0;
   1389 
   1390   Private = IP6_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
   1391   Ip6ConfigInstance = IP6_CONFIG_INSTANCE_FROM_FORM_CALLBACK (Private);
   1392   BufferSize = sizeof (IP6_CONFIG_IFR_NVDATA);
   1393 
   1394   IfrNvData = (IP6_CONFIG_IFR_NVDATA *) AllocateZeroPool (BufferSize);
   1395   if (IfrNvData == NULL) {
   1396     return EFI_OUT_OF_RESOURCES;
   1397   }
   1398 
   1399   Status = Ip6ConvertConfigNvDataToIfrNvData (IfrNvData, Ip6ConfigInstance);
   1400   if (EFI_ERROR (Status)) {
   1401     goto Exit;
   1402   }
   1403 
   1404   ConfigRequest = Request;
   1405   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
   1406     //
   1407     // Request has no request element, construct full request string.
   1408     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
   1409     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.
   1410     //
   1411     ConfigRequestHdr = HiiConstructConfigHdr (
   1412                          &gIp6ConfigNvDataGuid,
   1413                          mIp6ConfigStorageName,
   1414                          Private->ChildHandle
   1415                          );
   1416     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
   1417     ConfigRequest = AllocateZeroPool (Size);
   1418     ASSERT (ConfigRequest != NULL);
   1419     AllocatedRequest = TRUE;
   1420     UnicodeSPrint (
   1421       ConfigRequest,
   1422       Size,
   1423       L"%s&OFFSET=0&WIDTH=%016LX",
   1424       ConfigRequestHdr,
   1425       (UINT64) BufferSize
   1426       );
   1427     FreePool (ConfigRequestHdr);
   1428   }
   1429 
   1430   //
   1431   // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
   1432   //
   1433   Status = gHiiConfigRouting->BlockToConfig (
   1434                                 gHiiConfigRouting,
   1435                                 ConfigRequest,
   1436                                 (UINT8 *) IfrNvData,
   1437                                 BufferSize,
   1438                                 Results,
   1439                                 Progress
   1440                                 );
   1441 
   1442 Exit:
   1443   FreePool (IfrNvData);
   1444   //
   1445   // Free the allocated config request string.
   1446   //
   1447   if (AllocatedRequest) {
   1448     FreePool (ConfigRequest);
   1449     ConfigRequest = NULL;
   1450   }
   1451   //
   1452   // Set Progress string to the original request string.
   1453   //
   1454   if (Request == NULL) {
   1455     *Progress = NULL;
   1456   } else if (StrStr (Request, L"OFFSET") == NULL) {
   1457     *Progress = Request + StrLen (Request);
   1458   }
   1459 
   1460   return Status;
   1461 }
   1462 
   1463 /**
   1464   This function applies changes in a driver's configuration.
   1465   Input is a Configuration, which has the routing data for this
   1466   driver followed by name / value configuration pairs. The driver
   1467   must apply those pairs to its configurable storage. If the
   1468   driver's configuration is stored in a linear block of data
   1469   and the driver's name / value pairs are in <BlockConfig>
   1470   format, it may use the ConfigToBlock helper function (above) to
   1471   simplify the job. Currently not implemented.
   1472 
   1473   @param[in]  This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
   1474   @param[in]  Configuration  A null-terminated Unicode string in
   1475                              <ConfigString> format.
   1476   @param[out] Progress       A pointer to a string filled in with the
   1477                              offset of the most recent '&' before the
   1478                              first failing name / value pair (or the
   1479                              beginn ing of the string if the failure
   1480                              is in the first name / value pair) or
   1481                              the terminating NULL if all was
   1482                              successful.
   1483 
   1484   @retval EFI_SUCCESS             The results have been distributed or are
   1485                                   awaiting distribution.
   1486   @retval EFI_OUT_OF_MEMORY       Not enough memory to store the
   1487                                   parts of the results that must be
   1488                                   stored awaiting possible future
   1489                                   protocols.
   1490   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
   1491                                   Results parameter would result
   1492                                   in this type of error.
   1493   @retval EFI_NOT_FOUND           Target for the specified routing data
   1494                                   was not found.
   1495 **/
   1496 EFI_STATUS
   1497 EFIAPI
   1498 Ip6FormRouteConfig (
   1499   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
   1500   IN  CONST EFI_STRING                       Configuration,
   1501   OUT EFI_STRING                             *Progress
   1502   )
   1503 {
   1504   if (This == NULL || Configuration == NULL || Progress == NULL) {
   1505     return EFI_INVALID_PARAMETER;
   1506   }
   1507 
   1508   //
   1509   // Check routing data in <ConfigHdr>.
   1510   // Note: if only one Storage is used, then this checking could be skipped.
   1511   //
   1512   if (!HiiIsConfigHdrMatch (Configuration, &gIp6ConfigNvDataGuid, mIp6ConfigStorageName)) {
   1513     *Progress = Configuration;
   1514     return EFI_NOT_FOUND;
   1515   }
   1516 
   1517   *Progress = Configuration + StrLen (Configuration);
   1518 
   1519   return EFI_SUCCESS;
   1520 }
   1521 
   1522 /**
   1523   Display host addresses, route table, DNS addresses and gateway addresses in
   1524   "IPv6 Current Setting" page.
   1525 
   1526   @param[in]       Instance        The IP6 config instance data.
   1527 
   1528   @retval EFI_SUCCESS              The operation finished successfully.
   1529   @retval Others                   Other errors as indicated.
   1530 
   1531 **/
   1532 EFI_STATUS
   1533 Ip6GetCurrentSetting (
   1534   IN IP6_CONFIG_INSTANCE        *Instance
   1535   )
   1536 {
   1537   EFI_IP6_CONFIG_PROTOCOL       *Ip6Config;
   1538   EFI_HII_HANDLE                HiiHandle;
   1539   EFI_IP6_CONFIG_INTERFACE_INFO *Data;
   1540   UINTN                         DataSize;
   1541   EFI_STATUS                    Status;
   1542   CHAR16                        PortString[ADDRESS_STR_MAX_SIZE];
   1543   EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;
   1544 
   1545 
   1546   Ip6Config = &Instance->Ip6Config;
   1547   HiiHandle = Instance->CallbackInfo.RegisteredHandle;
   1548   Data      = NULL;
   1549 
   1550   //
   1551   // Get current interface info.
   1552   //
   1553   Status = Ip6ConfigNvGetData (
   1554              Ip6Config,
   1555              Ip6ConfigDataTypeInterfaceInfo,
   1556              &DataSize,
   1557              (VOID **) &Data
   1558              );
   1559   if (EFI_ERROR (Status)) {
   1560     return Status;
   1561   }
   1562 
   1563   //
   1564   // Generate dynamic text opcode for host address and draw it.
   1565   //
   1566   IfInfo = (EFI_IP6_CONFIG_INTERFACE_INFO *) Data;
   1567   Status = Ip6ConvertAddressListToString (
   1568              PortString,
   1569              HiiHandle,
   1570              Ip6ConfigNvHostAddress,
   1571              IfInfo->AddressInfo,
   1572              IfInfo->AddressInfoCount
   1573              );
   1574   if (EFI_ERROR (Status)) {
   1575     FreePool (Data);
   1576     return Status;
   1577   }
   1578 
   1579   //
   1580   // Generate the dynamic text opcode for route table and draw it.
   1581   //
   1582   Status = Ip6ConvertAddressListToString (
   1583              PortString,
   1584              HiiHandle,
   1585              Ip6ConfigNvRouteTable,
   1586              IfInfo->RouteTable,
   1587              IfInfo->RouteCount
   1588              );
   1589   if (EFI_ERROR (Status)) {
   1590     FreePool (Data);
   1591     return Status;
   1592   }
   1593 
   1594   //
   1595   // Get DNS server list.
   1596   //
   1597   FreePool (Data);
   1598   DataSize = 0;
   1599   Data = NULL;
   1600   Status = Ip6ConfigNvGetData (
   1601              Ip6Config,
   1602              Ip6ConfigDataTypeDnsServer,
   1603              &DataSize,
   1604              (VOID **) &Data
   1605              );
   1606   if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
   1607     if (Data != NULL) {
   1608       FreePool (Data);
   1609     }
   1610     return Status;
   1611   }
   1612 
   1613   if (DataSize > 0) {
   1614     //
   1615     // Generate the dynamic text opcode for DNS server and draw it.
   1616     //
   1617     Status = Ip6ConvertAddressListToString (
   1618                PortString,
   1619                HiiHandle,
   1620                Ip6ConfigNvDnsAddress,
   1621                Data,
   1622                DataSize / sizeof (EFI_IPv6_ADDRESS)
   1623                );
   1624     if (EFI_ERROR (Status)) {
   1625       FreePool (Data);
   1626       return Status;
   1627     }
   1628   }
   1629 
   1630   //
   1631   // Get gateway adderss list.
   1632   //
   1633   if (Data != NULL) {
   1634     FreePool (Data);
   1635   }
   1636 
   1637   DataSize = 0;
   1638   Data = NULL;
   1639   Status = Ip6ConfigNvGetData (
   1640              Ip6Config,
   1641              Ip6ConfigDataTypeGateway,
   1642              &DataSize,
   1643              (VOID **) &Data
   1644              );
   1645   if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
   1646     if (Data != NULL) {
   1647       FreePool (Data);
   1648     }
   1649     return Status;
   1650   }
   1651 
   1652   if (DataSize > 0) {
   1653     //
   1654     // Generate the dynamic text opcode for gateway and draw it.
   1655     //
   1656     Status = Ip6ConvertAddressListToString (
   1657                PortString,
   1658                HiiHandle,
   1659                Ip6ConfigNvGatewayAddress,
   1660                Data,
   1661                DataSize / sizeof (EFI_IPv6_ADDRESS)
   1662                );
   1663     if (EFI_ERROR (Status)) {
   1664       FreePool (Data);
   1665       return Status;
   1666     }
   1667   }
   1668 
   1669   if (Data != NULL) {
   1670     FreePool (Data);
   1671   }
   1672 
   1673   return EFI_SUCCESS;
   1674 }
   1675 
   1676 /**
   1677   This function is called to provide results data to the driver.
   1678   This data consists of a unique key that is used to identify
   1679   which data is either being passed back or being asked for.
   1680 
   1681   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
   1682   @param[in]  Action             Specifies the type of action taken by the browser.
   1683   @param[in]  QuestionId         A unique value which is sent to the original
   1684                                  exporting driver so that it can identify the type
   1685                                  of data to expect. The format of the data tends to
   1686                                  vary based on the opcode that generated the callback.
   1687   @param[in]  Type               The type of value for the question.
   1688   @param[in]  Value              A pointer to the data being sent to the original
   1689                                  exporting driver.
   1690   @param[out]  ActionRequest     On return, points to the action requested by the
   1691                                  callback function.
   1692 
   1693   @retval EFI_SUCCESS            The callback successfully handled the action.
   1694   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
   1695                                  variable and its data.
   1696   @retval EFI_DEVICE_ERROR       The variable could not be saved.
   1697   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
   1698                                  callback. Currently not implemented.
   1699   @retval EFI_INVALID_PARAMETER  Passed in the wrong parameter.
   1700   @retval Others                 Other errors as indicated.
   1701 
   1702 **/
   1703 EFI_STATUS
   1704 EFIAPI
   1705 Ip6FormCallback (
   1706   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
   1707   IN  EFI_BROWSER_ACTION                     Action,
   1708   IN  EFI_QUESTION_ID                        QuestionId,
   1709   IN  UINT8                                  Type,
   1710   IN  EFI_IFR_TYPE_VALUE                     *Value,
   1711   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
   1712   )
   1713 {
   1714   IP6_FORM_CALLBACK_INFO        *Private;
   1715   UINTN                         BufferSize;
   1716   IP6_CONFIG_IFR_NVDATA         *IfrNvData;
   1717   EFI_STATUS                    Status;
   1718   EFI_INPUT_KEY                 Key;
   1719   IP6_CONFIG_INSTANCE           *Instance;
   1720   IP6_CONFIG_NVDATA             *Ip6NvData;
   1721 
   1722   if (This == NULL) {
   1723     return EFI_INVALID_PARAMETER;
   1724   }
   1725 
   1726   Private   = IP6_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);
   1727   Instance  = IP6_CONFIG_INSTANCE_FROM_FORM_CALLBACK (Private);
   1728   Ip6NvData = &Instance->Ip6NvData;
   1729 
   1730   if ((Action == EFI_BROWSER_ACTION_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)){
   1731     return EFI_SUCCESS;
   1732   }
   1733 
   1734   if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
   1735     return EFI_UNSUPPORTED;
   1736   }
   1737 
   1738   if ((Value == NULL) || (ActionRequest == NULL)) {
   1739     return EFI_INVALID_PARAMETER;
   1740   }
   1741 
   1742   //
   1743   // Retrieve uncommitted data from Browser
   1744   //
   1745 
   1746   BufferSize = sizeof (IP6_CONFIG_IFR_NVDATA);
   1747   IfrNvData = AllocateZeroPool (BufferSize);
   1748   if (IfrNvData == NULL) {
   1749     return EFI_OUT_OF_RESOURCES;
   1750   }
   1751 
   1752   Status = EFI_SUCCESS;
   1753 
   1754   HiiGetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData);
   1755 
   1756   if (Action == EFI_BROWSER_ACTION_CHANGING) {
   1757     switch (QuestionId) {
   1758     case KEY_GET_CURRENT_SETTING:
   1759       Status = Ip6GetCurrentSetting (Instance);
   1760       break;
   1761 
   1762     default:
   1763       break;
   1764     }
   1765   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
   1766     switch (QuestionId) {
   1767     case KEY_SAVE_CONFIG_CHANGES:
   1768       Status = Ip6ConvertIfrNvDataToConfigNvDataAdvanced (IfrNvData, Instance);
   1769       if (EFI_ERROR (Status)) {
   1770         break;
   1771       }
   1772 
   1773       Status = Ip6GetCurrentSetting (Instance);
   1774 
   1775       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
   1776       break;
   1777 
   1778     case KEY_IGNORE_CONFIG_CHANGES:
   1779       Ip6FreeAddressInfoList (&Ip6NvData->ManualAddress);
   1780       Ip6FreeAddressInfoList (&Ip6NvData->GatewayAddress);
   1781       Ip6FreeAddressInfoList (&Ip6NvData->DnsAddress);
   1782 
   1783       Ip6NvData->ManualAddressCount  = 0;
   1784       Ip6NvData->GatewayAddressCount = 0;
   1785       Ip6NvData->DnsAddressCount     = 0;
   1786 
   1787       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
   1788       break;
   1789 
   1790     case KEY_SAVE_CHANGES:
   1791       Status = Ip6ConvertIfrNvDataToConfigNvDataGeneral (IfrNvData, Instance);
   1792       if (EFI_ERROR (Status)) {
   1793         break;
   1794       }
   1795       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
   1796       break;
   1797 
   1798     case KEY_INTERFACE_ID:
   1799       Status = Ip6ParseInterfaceIdFromString (IfrNvData->InterfaceId, &Ip6NvData->InterfaceId);
   1800       if (EFI_ERROR (Status)) {
   1801         CreatePopUp (
   1802           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   1803           &Key,
   1804           L"Invalid Interface ID!",
   1805           NULL
   1806           );
   1807       }
   1808 
   1809       break;
   1810 
   1811     case KEY_MANUAL_ADDRESS:
   1812       Status = Ip6ParseAddressListFromString (
   1813                  IfrNvData->ManualAddress,
   1814                  &Ip6NvData->ManualAddress,
   1815                  &Ip6NvData->ManualAddressCount
   1816                  );
   1817       if (EFI_ERROR (Status)) {
   1818         CreatePopUp (
   1819           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   1820           &Key,
   1821           L"Invalid Host Addresses!",
   1822           NULL
   1823           );
   1824       }
   1825 
   1826       break;
   1827 
   1828     case KEY_GATEWAY_ADDRESS:
   1829       Status = Ip6ParseAddressListFromString (
   1830                  IfrNvData->GatewayAddress,
   1831                  &Ip6NvData->GatewayAddress,
   1832                  &Ip6NvData->GatewayAddressCount
   1833                  );
   1834       if (EFI_ERROR (Status)) {
   1835         CreatePopUp (
   1836           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   1837           &Key,
   1838           L"Invalid Gateway Addresses!",
   1839           NULL
   1840           );
   1841       }
   1842 
   1843       break;
   1844 
   1845     case KEY_DNS_ADDRESS:
   1846       Status = Ip6ParseAddressListFromString (
   1847                  IfrNvData->DnsAddress,
   1848                  &Ip6NvData->DnsAddress,
   1849                  &Ip6NvData->DnsAddressCount
   1850                  );
   1851       if (EFI_ERROR (Status)) {
   1852         CreatePopUp (
   1853           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
   1854           &Key,
   1855           L"Invalid DNS Addresses!",
   1856           NULL
   1857           );
   1858       }
   1859 
   1860       break;
   1861 
   1862     default:
   1863       break;
   1864     }
   1865   }
   1866 
   1867   if (!EFI_ERROR (Status)) {
   1868     //
   1869     // Pass changed uncommitted data back to Form Browser.
   1870     //
   1871     BufferSize = sizeof (IP6_CONFIG_IFR_NVDATA);
   1872     HiiSetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData, NULL);
   1873   }
   1874 
   1875   FreePool (IfrNvData);
   1876   return Status;
   1877 }
   1878 
   1879 /**
   1880   Install HII Config Access protocol for network device and allocate resources.
   1881 
   1882   @param[in, out]  Instance      The IP6_CONFIG_INSTANCE to create a form.
   1883 
   1884   @retval EFI_SUCCESS            The HII Config Access protocol is installed.
   1885   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
   1886   @retval Others                 Other errors as indicated.
   1887 
   1888 **/
   1889 EFI_STATUS
   1890 Ip6ConfigFormInit (
   1891   IN OUT IP6_CONFIG_INSTANCE     *Instance
   1892   )
   1893 {
   1894   EFI_STATUS                     Status;
   1895   IP6_SERVICE                    *IpSb;
   1896   IP6_FORM_CALLBACK_INFO         *CallbackInfo;
   1897   EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
   1898   VENDOR_DEVICE_PATH             VendorDeviceNode;
   1899   EFI_SERVICE_BINDING_PROTOCOL   *MnpSb;
   1900   CHAR16                         *MacString;
   1901   CHAR16                         MenuString[128];
   1902   CHAR16                         PortString[128];
   1903   CHAR16                         *OldMenuString;
   1904   EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath;
   1905 
   1906   IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
   1907   ASSERT (IpSb != NULL);
   1908 
   1909   Status = gBS->HandleProtocol (
   1910                   IpSb->Controller,
   1911                   &gEfiDevicePathProtocolGuid,
   1912                   (VOID **) &ParentDevicePath
   1913                   );
   1914   if (EFI_ERROR (Status)) {
   1915     return Status;
   1916   }
   1917 
   1918   CallbackInfo = &Instance->CallbackInfo;
   1919   CallbackInfo->Signature = IP6_FORM_CALLBACK_INFO_SIGNATURE;
   1920 
   1921   //
   1922   // Construct device path node for EFI HII Config Access protocol,
   1923   // which consists of controller physical device path and one hardware
   1924   // vendor guid node.
   1925   //
   1926   ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));
   1927   VendorDeviceNode.Header.Type    = HARDWARE_DEVICE_PATH;
   1928   VendorDeviceNode.Header.SubType = HW_VENDOR_DP;
   1929 
   1930   CopyGuid (&VendorDeviceNode.Guid, &gEfiCallerIdGuid);
   1931 
   1932   SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));
   1933   CallbackInfo->HiiVendorDevicePath = AppendDevicePathNode (
   1934                                         ParentDevicePath,
   1935                                         (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode
   1936                                         );
   1937   if (CallbackInfo->HiiVendorDevicePath == NULL) {
   1938     Status = EFI_OUT_OF_RESOURCES;
   1939     goto Error;
   1940   }
   1941 
   1942   ConfigAccess                = &CallbackInfo->HiiConfigAccess;
   1943   ConfigAccess->ExtractConfig = Ip6FormExtractConfig;
   1944   ConfigAccess->RouteConfig   = Ip6FormRouteConfig;
   1945   ConfigAccess->Callback      = Ip6FormCallback;
   1946 
   1947   //
   1948   // Install Device Path Protocol and Config Access protocol on new handle
   1949   //
   1950   Status = gBS->InstallMultipleProtocolInterfaces (
   1951                   &CallbackInfo->ChildHandle,
   1952                   &gEfiDevicePathProtocolGuid,
   1953                   CallbackInfo->HiiVendorDevicePath,
   1954                   &gEfiHiiConfigAccessProtocolGuid,
   1955                   ConfigAccess,
   1956                   NULL
   1957                   );
   1958   if (!EFI_ERROR (Status)) {
   1959     //
   1960     // Open the Parent Handle for the child
   1961     //
   1962     Status = gBS->OpenProtocol (
   1963                     IpSb->Controller,
   1964                     &gEfiManagedNetworkServiceBindingProtocolGuid,
   1965                     (VOID **) &MnpSb,
   1966                     IpSb->Image,
   1967                     CallbackInfo->ChildHandle,
   1968                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1969                     );
   1970   }
   1971 
   1972   if (EFI_ERROR (Status)) {
   1973     goto Error;
   1974   }
   1975 
   1976   //
   1977   // Publish our HII data
   1978   //
   1979   CallbackInfo->RegisteredHandle = HiiAddPackages (
   1980                                      &gIp6ConfigNvDataGuid,
   1981                                      CallbackInfo->ChildHandle,
   1982                                      Ip6DxeStrings,
   1983                                      Ip6ConfigBin,
   1984                                      NULL
   1985                                      );
   1986   if (CallbackInfo->RegisteredHandle == NULL) {
   1987     Status = EFI_OUT_OF_RESOURCES;
   1988     goto Error;
   1989   }
   1990 
   1991   //
   1992   // Append MAC string in the menu help string and tile help string
   1993   //
   1994   Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &MacString);
   1995   if (!EFI_ERROR (Status)) {
   1996     OldMenuString = HiiGetString (
   1997                       CallbackInfo->RegisteredHandle,
   1998                       STRING_TOKEN (STR_IP6_CONFIG_FORM_HELP),
   1999                       NULL)
   2000                       ;
   2001     UnicodeSPrint (MenuString, 128, L"%s (MAC:%s)", OldMenuString, MacString);
   2002     HiiSetString (
   2003       CallbackInfo->RegisteredHandle,
   2004       STRING_TOKEN (STR_IP6_CONFIG_FORM_HELP),
   2005       MenuString,
   2006       NULL
   2007       );
   2008     UnicodeSPrint (PortString, 128, L"MAC:%s", MacString);
   2009     HiiSetString (
   2010       CallbackInfo->RegisteredHandle,
   2011       STRING_TOKEN (STR_IP6_DEVICE_FORM_HELP),
   2012       PortString,
   2013       NULL
   2014       );
   2015 
   2016     FreePool (MacString);
   2017     FreePool (OldMenuString);
   2018 
   2019     InitializeListHead (&Instance->Ip6NvData.ManualAddress);
   2020     InitializeListHead (&Instance->Ip6NvData.GatewayAddress);
   2021     InitializeListHead (&Instance->Ip6NvData.DnsAddress);
   2022 
   2023     return EFI_SUCCESS;
   2024   }
   2025 
   2026 Error:
   2027   Ip6ConfigFormUnload (Instance);
   2028   return Status;
   2029 }
   2030 
   2031 /**
   2032   Uninstall the HII Config Access protocol for network devices and free up the resources.
   2033 
   2034   @param[in, out]  Instance      The IP6_CONFIG_INSTANCE to unload a form.
   2035 
   2036 **/
   2037 VOID
   2038 Ip6ConfigFormUnload (
   2039   IN OUT IP6_CONFIG_INSTANCE     *Instance
   2040   )
   2041 {
   2042   IP6_SERVICE                    *IpSb;
   2043   IP6_FORM_CALLBACK_INFO         *CallbackInfo;
   2044   IP6_CONFIG_NVDATA              *Ip6NvData;
   2045 
   2046   IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);
   2047   ASSERT (IpSb != NULL);
   2048 
   2049   CallbackInfo = &Instance->CallbackInfo;
   2050 
   2051   if (CallbackInfo->ChildHandle != NULL) {
   2052 
   2053     //
   2054     // Close the child handle
   2055     //
   2056     gBS->CloseProtocol (
   2057            IpSb->Controller,
   2058            &gEfiManagedNetworkServiceBindingProtocolGuid,
   2059            IpSb->Image,
   2060            CallbackInfo->ChildHandle
   2061            );
   2062     //
   2063     // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
   2064     //
   2065     gBS->UninstallMultipleProtocolInterfaces (
   2066            CallbackInfo->ChildHandle,
   2067            &gEfiDevicePathProtocolGuid,
   2068            CallbackInfo->HiiVendorDevicePath,
   2069            &gEfiHiiConfigAccessProtocolGuid,
   2070            &CallbackInfo->HiiConfigAccess,
   2071            NULL
   2072            );
   2073   }
   2074 
   2075   if (CallbackInfo->HiiVendorDevicePath != NULL) {
   2076     FreePool (CallbackInfo->HiiVendorDevicePath);
   2077   }
   2078 
   2079   if (CallbackInfo->RegisteredHandle != NULL) {
   2080     //
   2081     // Remove HII package list
   2082     //
   2083     HiiRemovePackages (CallbackInfo->RegisteredHandle);
   2084   }
   2085 
   2086   Ip6NvData = &Instance->Ip6NvData;
   2087 
   2088   Ip6FreeAddressInfoList (&Ip6NvData->ManualAddress);
   2089   Ip6FreeAddressInfoList (&Ip6NvData->GatewayAddress);
   2090   Ip6FreeAddressInfoList (&Ip6NvData->DnsAddress);
   2091 
   2092   Ip6NvData->ManualAddressCount  = 0;
   2093   Ip6NvData->GatewayAddressCount = 0;
   2094   Ip6NvData->DnsAddressCount     = 0;
   2095 }
   2096