]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/Ip6Dxe/Ip6ConfigNv.c
Add NetworkPkg (P.UDK2010.UP3.Network.P1)
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6ConfigNv.c
diff --git a/NetworkPkg/Ip6Dxe/Ip6ConfigNv.c b/NetworkPkg/Ip6Dxe/Ip6ConfigNv.c
new file mode 100644 (file)
index 0000000..9ec4886
--- /dev/null
@@ -0,0 +1,2116 @@
+/** @file\r
+  Helper functions for configuring or obtaining the parameters relating to IP6.\r
+\r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Ip6Impl.h"\r
+\r
+EFI_GUID  mIp6HiiVendorDevicePathGuid = IP6_HII_VENDOR_DEVICE_PATH_GUID;\r
+EFI_GUID  mIp6ConfigNvDataGuid        = IP6_CONFIG_NVDATA_GUID;\r
+CHAR16    mIp6ConfigStorageName[]     = L"IP6_CONFIG_IFR_NVDATA";\r
+\r
+/**\r
+  The notify function of create event when performing a manual configuration.\r
+\r
+  @param[in]    Event        The pointer of Event.\r
+  @param[in]    Context      The pointer of Context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip6ConfigManualAddressNotify (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID         *Context\r
+  )\r
+{\r
+  *((BOOLEAN *) Context) = TRUE;\r
+}\r
+\r
+/**\r
+  Get the configuration data for the EFI IPv6 network stack running on the\r
+  communication. It is a help function to the call EfiIp6ConfigGetData().\r
+\r
+  @param[in]      Ip6Config      The pointer to the EFI_IP6_CONFIG_PROTOCOL instance.\r
+  @param[in]      DataType       The type of data to get.\r
+  @param[out]     DataSize       The size of buffer required in bytes.\r
+  @param[out]     Data           The data buffer in which the configuration data is returned. The\r
+                                 type of the data buffer associated with the DataType.\r
+                                 It is the caller's responsibility to free the resource.\r
+\r
+  @retval EFI_SUCCESS           The specified configuration data was obtained successfully.\r
+  @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:\r
+                                - Ip6Config is NULL or invalid.\r
+                                - DataSize is NULL.\r
+                                - Data is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to perform the operation due to lack of resources.\r
+  @retval EFI_NOT_READY         The specified configuration data is not ready due to an\r
+                                asynchronous configuration process already in progress.\r
+  @retval EFI_NOT_FOUND         The specified configuration data was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6ConfigNvGetData (\r
+  IN  EFI_IP6_CONFIG_PROTOCOL                *Ip6Config,\r
+  IN  EFI_IP6_CONFIG_DATA_TYPE               DataType,\r
+  OUT UINTN                                  *DataSize,\r
+  OUT VOID                                   **Data\r
+  )\r
+{\r
+  UINTN                   BufferSize;\r
+  VOID                    *Buffer;\r
+  EFI_STATUS              Status;\r
+\r
+  if ((Ip6Config == NULL) || (Data == NULL) || (DataSize == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BufferSize = 0;\r
+  Status = Ip6Config->GetData (\r
+                        Ip6Config,\r
+                        DataType,\r
+                        &BufferSize,\r
+                        NULL\r
+                        );\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return Status;\r
+  }\r
+\r
+  Buffer = AllocateZeroPool (BufferSize);\r
+  if (Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = Ip6Config->GetData (\r
+                        Ip6Config,\r
+                        DataType,\r
+                        &BufferSize,\r
+                        Buffer\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Buffer);\r
+    return Status;\r
+  }\r
+\r
+  *DataSize = BufferSize;\r
+  *Data     = Buffer;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free all nodes in IP6_ADDRESS_INFO_ENTRY in the list array specified\r
+  with ListHead.\r
+\r
+  @param[in]      ListHead  The head of the list array in IP6_ADDRESS_INFO_ENTRY.\r
+\r
+**/\r
+VOID\r
+Ip6FreeAddressInfoList (\r
+  IN LIST_ENTRY                  *ListHead\r
+  )\r
+{\r
+  IP6_ADDRESS_INFO_ENTRY         *Node;\r
+  LIST_ENTRY                     *Entry;\r
+  LIST_ENTRY                     *NextEntry;\r
+\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, ListHead) {\r
+    Node = NET_LIST_USER_STRUCT (Entry, IP6_ADDRESS_INFO_ENTRY, Link);\r
+    RemoveEntryList (&Node->Link);\r
+    FreePool (Node);\r
+  }\r
+}\r
+\r
+/**\r
+  Convert the IPv6 address into a formatted string.\r
+\r
+  @param[in]  Ip6       The IPv6 address.\r
+  @param[out] Str       The formatted IP string.\r
+\r
+**/\r
+VOID\r
+Ip6ToStr (\r
+  IN  EFI_IPv6_ADDRESS  *Ip6,\r
+  OUT CHAR16            *Str\r
+  )\r
+{\r
+  UINTN                 Index;\r
+  BOOLEAN               Short;\r
+  UINTN                 Number;\r
+  CHAR16                FormatString[8];\r
+\r
+  Short = FALSE;\r
+\r
+  for (Index = 0; Index < 15; Index = Index + 2) {\r
+    if (!Short &&\r
+        Index % 2 == 0 &&\r
+        Ip6->Addr[Index] == 0 &&\r
+        Ip6->Addr[Index + 1] == 0\r
+        ) {\r
+      //\r
+      // Deal with the case of ::.\r
+      //\r
+      if (Index == 0) {\r
+        *Str       = L':';\r
+        *(Str + 1) = L':';\r
+        Str        = Str + 2;\r
+      } else {\r
+        *Str       = L':';\r
+        Str        = Str + 1;\r
+      }\r
+\r
+      while ((Index < 15) && (Ip6->Addr[Index] == 0) && (Ip6->Addr[Index + 1] == 0)) {\r
+        Index = Index + 2;\r
+      }\r
+\r
+      Short = TRUE;\r
+\r
+      if (Index == 16) {\r
+        //\r
+        // :: is at the end of the address.\r
+        //\r
+        *Str = L'\0';\r
+        break;\r
+      }\r
+    }\r
+\r
+    ASSERT (Index < 15);\r
+\r
+    if (Ip6->Addr[Index] == 0) {\r
+      Number = UnicodeSPrint (Str, 2 * IP6_STR_MAX_SIZE, L"%x:", (UINTN) Ip6->Addr[Index + 1]);\r
+    } else {\r
+      if (Ip6->Addr[Index + 1] < 0x10) {\r
+        CopyMem (FormatString, L"%x0%x:", StrSize (L"%x0%x:"));\r
+      } else {\r
+        CopyMem (FormatString, L"%x%x:", StrSize (L"%x%x:"));\r
+      }\r
+\r
+      Number = UnicodeSPrint (\r
+                 Str,\r
+                 2 * IP6_STR_MAX_SIZE,\r
+                 (CONST CHAR16 *) FormatString,\r
+                 (UINTN) Ip6->Addr[Index],\r
+                 (UINTN) Ip6->Addr[Index + 1]\r
+                 );\r
+    }\r
+\r
+    Str = Str + Number;\r
+\r
+    if (Index + 2 == 16) {\r
+      *Str = L'\0';\r
+      if (*(Str - 1) == L':') {\r
+        *(Str - 1) = L'\0';\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Convert EFI_IP6_CONFIG_INTERFACE_ID to string format.\r
+\r
+  @param[out]      String  The buffer to store the converted string.\r
+  @param[in]       IfId    The pointer of EFI_IP6_CONFIG_INTERFACE_ID.\r
+\r
+  @retval EFI_SUCCESS              The string converted successfully.\r
+  @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6ConvertInterfaceIdToString (\r
+  OUT CHAR16                         *String,\r
+  IN  EFI_IP6_CONFIG_INTERFACE_ID    *IfId\r
+  )\r
+{\r
+  UINT8                          Index;\r
+  UINTN                          Number;\r
+\r
+  if ((String == NULL) || (IfId == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  for (Index = 0; Index < 8; Index++) {\r
+    Number = UnicodeSPrint (\r
+               String,\r
+               2 * INTERFACE_ID_STR_STORAGE,\r
+               L"%x:",\r
+               (UINTN) IfId->Id[Index]\r
+               );\r
+    String = String + Number;\r
+  }\r
+\r
+  *(String - 1) = '\0';\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Parse InterfaceId in string format and convert it to EFI_IP6_CONFIG_INTERFACE_ID.\r
+\r
+  @param[in]        String  The buffer of the string to be parsed.\r
+  @param[out]       IfId    The pointer of EFI_IP6_CONFIG_INTERFACE_ID.\r
+\r
+  @retval EFI_SUCCESS              The operation finished successfully.\r
+  @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6ParseInterfaceIdFromString (\r
+  IN CONST CHAR16                    *String,\r
+  OUT EFI_IP6_CONFIG_INTERFACE_ID    *IfId\r
+  )\r
+{\r
+  UINT8                          Index;\r
+  CHAR16                         *IfIdStr;\r
+  CHAR16                         *TempStr;\r
+  UINTN                          NodeVal;\r
+\r
+  if ((String == NULL) || (IfId == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  IfIdStr = (CHAR16 *) String;\r
+\r
+  ZeroMem (IfId, sizeof (EFI_IP6_CONFIG_INTERFACE_ID));\r
+\r
+  for (Index = 0; Index < 8; Index++) {\r
+    TempStr = IfIdStr;\r
+\r
+    while ((*IfIdStr != L'\0') && (*IfIdStr != L':')) {\r
+      IfIdStr++;\r
+    }\r
+\r
+    //\r
+    // The InterfaceId format is X:X:X:X, the number of X should not exceed 8.\r
+    // If the number of X is less than 8, zero is appended to the InterfaceId.\r
+    //\r
+    if ((*IfIdStr == ':') && (Index == 7)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // Convert the string to interface id. AsciiStrHexToUintn stops at the\r
+    // first character that is not a valid hex character, ':' or '\0' here.\r
+    //\r
+    NodeVal = StrHexToUintn (TempStr);\r
+    if (NodeVal > 0xFF) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    IfId->Id[Index] = (UINT8) NodeVal;\r
+\r
+    IfIdStr++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create Hii Extend Label OpCode as the start opcode and end opcode. It is\r
+  a help function.\r
+\r
+  @param[in]  StartLabelNumber   The number of start label.\r
+  @param[out] StartOpCodeHandle  Points to the start opcode handle.\r
+  @param[out] StartLabel         Points to the created start opcode.\r
+  @param[out] EndOpCodeHandle    Points to the end opcode handle.\r
+  @param[out] EndLabel           Points to the created end opcode.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   Does not have sufficient resources to finish this\r
+                                 operation.\r
+  @retval EFI_INVALID_PARAMETER  Any input parameter is invalid.\r
+  @retval EFI_SUCCESS            The operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6CreateOpCode (\r
+  IN  UINT16                        StartLabelNumber,\r
+  OUT VOID                          **StartOpCodeHandle,\r
+  OUT EFI_IFR_GUID_LABEL            **StartLabel,\r
+  OUT VOID                          **EndOpCodeHandle,\r
+  OUT EFI_IFR_GUID_LABEL            **EndLabel\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_IFR_GUID_LABEL                *InternalStartLabel;\r
+  EFI_IFR_GUID_LABEL                *InternalEndLabel;\r
+\r
+  if (StartOpCodeHandle == NULL || StartLabel == NULL || EndOpCodeHandle == NULL || EndLabel == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *StartOpCodeHandle = NULL;\r
+  *EndOpCodeHandle   = NULL;\r
+  Status             = EFI_OUT_OF_RESOURCES;\r
+\r
+  //\r
+  // Initialize the container for dynamic opcodes.\r
+  //\r
+  *StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  if (*StartOpCodeHandle == NULL) {\r
+    return Status;\r
+  }\r
+\r
+  *EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  if (*EndOpCodeHandle == NULL) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode as the start opcode.\r
+  //\r
+  InternalStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                                *StartOpCodeHandle,\r
+                                                &gEfiIfrTianoGuid,\r
+                                                NULL,\r
+                                                sizeof (EFI_IFR_GUID_LABEL)\r
+                                                );\r
+  if (InternalStartLabel == NULL) {\r
+    goto Exit;\r
+  }\r
+\r
+  InternalStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+  InternalStartLabel->Number       = StartLabelNumber;\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode as the end opcode.\r
+  //\r
+  InternalEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                              *EndOpCodeHandle,\r
+                                              &gEfiIfrTianoGuid,\r
+                                              NULL,\r
+                                              sizeof (EFI_IFR_GUID_LABEL)\r
+                                              );\r
+  if (InternalEndLabel == NULL) {\r
+    goto Exit;\r
+  }\r
+\r
+  InternalEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+  InternalEndLabel->Number       = LABEL_END;\r
+\r
+  *StartLabel = InternalStartLabel;\r
+  *EndLabel   = InternalEndLabel;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+Exit:\r
+\r
+  if (*StartOpCodeHandle != NULL) {\r
+    HiiFreeOpCodeHandle (*StartOpCodeHandle);\r
+  }\r
+\r
+  if (*EndOpCodeHandle != NULL) {\r
+    HiiFreeOpCodeHandle (*EndOpCodeHandle);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function converts the different format of address list to string format and\r
+  then generates the corresponding text opcode to illustarate the address info in\r
+  IP6 configuration page. Currently, the following formats are supported:\r
+  EFI_IP6_ADDRESS_INFO AddressType: Ip6ConfigNvHostAddress;\r
+  EFI_IPv6_ADDRESS     AddressType: Ip6ConfigNvGatewayAddress and Ip6ConfigNvDnsAddress;\r
+  EFI_IP6_ROUTE_TABLE  AddressType: Ip6ConfigNvRouteTable.\r
+\r
+  @param[in, out] String           The pointer to the buffer to store the converted\r
+                                   string.\r
+  @param[in]      HiiHandle        A handle that was previously registered in the\r
+                                   HII Database.\r
+  @param[in]      AddressType      The address type.\r
+  @param[in]      AddressInfo      Pointer to the address list.\r
+  @param[in]      AddressCount     The address count of the address list.\r
+\r
+  @retval EFI_SUCCESS              The operation finished successfully.\r
+  @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.\r
+  @retval EFI_UNSUPPORTED          The AddressType is not supported.\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6ConvertAddressListToString (\r
+  IN OUT CHAR16                         *String,\r
+  IN     EFI_HII_HANDLE                 HiiHandle,\r
+  IN     IP6_CONFIG_NV_ADDRESS_TYPE     AddressType,\r
+  IN     VOID                           *AddressInfo,\r
+  IN     UINTN                          AddressCount\r
+  )\r
+{\r
+  UINTN                          Index;\r
+  UINTN                          Number;\r
+  CHAR16                         *TempStr;\r
+  EFI_STATUS                     Status;\r
+  VOID                           *StartOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL             *StartLabel;\r
+  VOID                           *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL             *EndLabel;\r
+  UINT16                         StartLabelNumber;\r
+  EFI_STRING_ID                  TextTwo;\r
+  UINT8                          *AddressHead;\r
+  UINT8                          PrefixLength;\r
+  EFI_IPv6_ADDRESS               *Address;\r
+\r
+  if ((String == NULL) || (HiiHandle == NULL) || (AddressInfo == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (AddressType == Ip6ConfigNvHostAddress) {\r
+    StartLabelNumber = HOST_ADDRESS_LABEL;\r
+  } else if (AddressType == Ip6ConfigNvGatewayAddress) {\r
+    StartLabelNumber = GATEWAY_ADDRESS_LABEL;\r
+  } else if (AddressType == Ip6ConfigNvDnsAddress) {\r
+    StartLabelNumber = DNS_ADDRESS_LABEL;\r
+  } else if (AddressType == Ip6ConfigNvRouteTable) {\r
+    StartLabelNumber = ROUTE_TABLE_LABEL;\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = Ip6CreateOpCode (\r
+             StartLabelNumber,\r
+             &StartOpCodeHandle,\r
+             &StartLabel,\r
+             &EndOpCodeHandle,\r
+             &EndLabel\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  AddressHead = (UINT8 *) AddressInfo;\r
+\r
+  for (Index = 0; Index < AddressCount; Index++) {\r
+    if (AddressType == Ip6ConfigNvHostAddress) {\r
+      AddressInfo = AddressHead + sizeof (EFI_IP6_ADDRESS_INFO) * Index;\r
+      Address     = &((EFI_IP6_ADDRESS_INFO *) AddressInfo)->Address;\r
+    } else if (AddressType == Ip6ConfigNvRouteTable) {\r
+      AddressInfo = AddressHead + sizeof (EFI_IP6_ROUTE_TABLE) * Index;\r
+      Address     = &((EFI_IP6_ROUTE_TABLE *) AddressInfo)->Destination;\r
+    } else {\r
+      AddressInfo = AddressHead + sizeof (EFI_IPv6_ADDRESS) * Index;\r
+      Address     = AddressInfo;\r
+    }\r
+\r
+    //\r
+    // Convert the IP address info to string.\r
+    //\r
+    Ip6ToStr (Address, String);\r
+    TempStr = String + StrLen (String);\r
+\r
+    if ((AddressType == Ip6ConfigNvHostAddress) || (AddressType == Ip6ConfigNvRouteTable)) {\r
+      if (AddressType == Ip6ConfigNvHostAddress) {\r
+        PrefixLength = ((EFI_IP6_ADDRESS_INFO *) AddressInfo)->PrefixLength;\r
+      } else {\r
+        PrefixLength = ((EFI_IP6_ROUTE_TABLE *) AddressInfo)->PrefixLength;\r
+      }\r
+\r
+      //\r
+      // Append the prefix length to the string.\r
+      //\r
+      *TempStr = L'/';\r
+      TempStr++;\r
+      Number  = UnicodeSPrint (TempStr, 6, L"%d", PrefixLength);\r
+      TempStr = TempStr + Number;\r
+    }\r
+\r
+    if (AddressType == Ip6ConfigNvRouteTable) {\r
+      //\r
+      // Append " >> " to the string.\r
+      //\r
+      Number   = UnicodeSPrint (TempStr, 8, L" >>  ");\r
+      TempStr  = TempStr + Number;\r
+\r
+      //\r
+      // Append the gateway address to the string.\r
+      //\r
+      Ip6ToStr (&((EFI_IP6_ROUTE_TABLE *) AddressInfo)->Gateway, TempStr);\r
+      TempStr = TempStr + StrLen (TempStr);\r
+    }\r
+\r
+    //\r
+    // Generate a text opcode and update the UI.\r
+    //\r
+    TextTwo = HiiSetString (HiiHandle, 0, String, NULL);\r
+    if (TextTwo == 0) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+\r
+    HiiCreateTextOpCode (StartOpCodeHandle, STR_NULL, STR_NULL, TextTwo);\r
+\r
+    String = TempStr;\r
+    *String = IP6_ADDRESS_DELIMITER;\r
+    String++;\r
+  }\r
+\r
+  *(String - 1) = '\0';\r
+\r
+  Status = HiiUpdateForm (\r
+             HiiHandle,                       // HII handle\r
+             &mIp6ConfigNvDataGuid,           // Formset GUID\r
+             FORMID_MAIN_FORM,                // Form ID\r
+             StartOpCodeHandle,               // Label for where to insert opcodes\r
+             EndOpCodeHandle                  // Replace data\r
+             );\r
+\r
+Exit:\r
+  HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+  HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Parse address list in string format and convert it to a list array of node in\r
+  IP6_ADDRESS_INFO_ENTRY.\r
+\r
+  @param[in]        String         The buffer to string to be parsed.\r
+  @param[out]       ListHead       The list head of array.\r
+  @param[out]       AddressCount   The number of list nodes in the array.\r
+\r
+  @retval EFI_SUCCESS              The operation finished successfully.\r
+  @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.\r
+  @retval EFI_OUT_OF_RESOURCES     Failed to perform the operation due to lack of resource.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6ParseAddressListFromString (\r
+  IN CONST CHAR16                    *String,\r
+  OUT LIST_ENTRY                     *ListHead,\r
+  OUT UINT32                         *AddressCount\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  CHAR16                         *LocalString;\r
+  CHAR16                         *Temp;\r
+  CHAR16                         *TempStr;\r
+  EFI_IP6_ADDRESS_INFO           AddressInfo;\r
+  IP6_ADDRESS_INFO_ENTRY         *Node;\r
+  BOOLEAN                        Last;\r
+  UINT32                         Count;\r
+\r
+  if ((String == NULL) || (ListHead == NULL) || (AddressCount == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  LocalString = (CHAR16 *) AllocateCopyPool (StrSize (String), String);\r
+  if (LocalString == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Clean the original address list.\r
+  //\r
+  Ip6FreeAddressInfoList (ListHead);\r
+\r
+  Temp  = LocalString;\r
+  Last  = FALSE;\r
+  Count = 0;\r
+\r
+  while (*LocalString != L'\0') {\r
+    TempStr = LocalString;\r
+    while ((*LocalString != L'\0') && (*LocalString != IP6_ADDRESS_DELIMITER)) {\r
+      LocalString++;\r
+    }\r
+\r
+    if (*LocalString == L'\0') {\r
+      Last = TRUE;\r
+    }\r
+\r
+    *LocalString = L'\0';\r
+\r
+    Status = NetLibStrToIp6andPrefix (TempStr, &AddressInfo.Address, &AddressInfo.PrefixLength);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+\r
+    if (AddressInfo.PrefixLength == 0xFF) {\r
+      AddressInfo.PrefixLength = 0;\r
+    }\r
+\r
+    if (!NetIp6IsValidUnicast (&AddressInfo.Address)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Error;\r
+    }\r
+\r
+    Node = AllocatePool (sizeof (IP6_ADDRESS_INFO_ENTRY));\r
+    if (Node == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Error;\r
+    }\r
+\r
+    CopyMem (&Node->AddrInfo, &AddressInfo, sizeof (EFI_IP6_ADDRESS_INFO));\r
+    InsertTailList (ListHead, &Node->Link);\r
+    Count++;\r
+\r
+    if (Last) {\r
+      break;\r
+    }\r
+\r
+    LocalString++;\r
+  }\r
+\r
+  FreePool (Temp);\r
+  *AddressCount = Count;\r
+  return EFI_SUCCESS;\r
+\r
+Error:\r
+  Ip6FreeAddressInfoList (ListHead);\r
+  FreePool (Temp);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function converts the interface info to string and draws it to the IP6 UI.\r
+  The interface information includes interface name, interface type, hardware address,\r
+  address info, and route table information. The address information is also used as the\r
+  content of manual addresses in IP6 UI.\r
+\r
+  @param[in]       IfInfo          The pointer of EFI_IP6_CONFIG_INTERFACE_INFO.\r
+  @param[in]       HiiHandle       The handle that was previously registered in the\r
+                                   HII Database.\r
+  @param[in, out]  IfrNvData       Points to IP6_CONFIG_IFR_NVDATA.\r
+\r
+  @retval EFI_SUCCESS              The operation finished successfully.\r
+  @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.\r
+  @retval EFI_OUT_OF_RESOURCES     The operation failed due to lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6ConvertInterfaceInfoToString (\r
+  IN     EFI_IP6_CONFIG_INTERFACE_INFO  *IfInfo,\r
+  IN     EFI_HII_HANDLE                 HiiHandle,\r
+  IN OUT IP6_CONFIG_IFR_NVDATA          *IfrNvData\r
+  )\r
+{\r
+  UINT32                         Index;\r
+  UINTN                          Number;\r
+  CHAR16                         *String;\r
+  CHAR16                         *LinkLocalStr;\r
+  CHAR16                         PortString[ADDRESS_STR_MAX_SIZE];\r
+  CHAR16                         FormatString[8];\r
+  EFI_STRING_ID                  StringId;\r
+  EFI_STATUS                     Status;\r
+\r
+  if ((IfInfo == NULL) || (HiiHandle == NULL) || (IfrNvData == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Print the interface name.\r
+  //\r
+  StringId = HiiSetString (\r
+               HiiHandle,\r
+               STRING_TOKEN (STR_IP6_INTERFACE_NAME_CONTENT),\r
+               IfInfo->Name,\r
+               NULL\r
+               );\r
+  if (StringId == 0) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Print the interface type.\r
+  //\r
+  if (IfInfo->IfType == Ip6InterfaceTypeEthernet) {\r
+    StrCpy (PortString, IP6_ETHERNET);\r
+  } else if (IfInfo->IfType == Ip6InterfaceTypeExperimentalEthernet) {\r
+    StrCpy (PortString, IP6_EXPERIMENTAL_ETHERNET);\r
+  } else {\r
+    //\r
+    // Refer to RFC1700, chapter Number Hardware Type.\r
+    //\r
+    UnicodeSPrint (PortString, 6, L"%d", IfInfo->IfType);\r
+  }\r
+\r
+  StringId = HiiSetString (\r
+               HiiHandle,\r
+               STRING_TOKEN (STR_IP6_INTERFACE_TYPE_CONTENT),\r
+               PortString,\r
+               NULL\r
+               );\r
+  if (StringId == 0) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Convert the hardware address.\r
+  //\r
+  String = PortString;\r
+  ASSERT (IfInfo->HwAddressSize <= 32);\r
+\r
+  for (Index = 0; Index < IfInfo->HwAddressSize; Index++) {\r
+\r
+    if (IfInfo->HwAddress.Addr[Index] < 0x10) {\r
+      StrCpy (FormatString, L"0%x-");\r
+    } else {\r
+      StrCpy (FormatString, L"%x-");\r
+    }\r
+\r
+    Number = UnicodeSPrint (\r
+               String,\r
+               8,\r
+               (CONST CHAR16 *) FormatString,\r
+               (UINTN) IfInfo->HwAddress.Addr[Index]\r
+               );\r
+    String = String + Number;\r
+  }\r
+\r
+  if (Index != 0) {\r
+    ASSERT (String > PortString);\r
+    String--;\r
+    *String = '\0';\r
+  }\r
+\r
+  //\r
+  // Print the hardware address.\r
+  //\r
+  StringId = HiiSetString (\r
+               HiiHandle,\r
+               STRING_TOKEN (STR_IP6_MAC_ADDRESS_CONTENT),\r
+               PortString,\r
+               NULL\r
+               );\r
+  if (StringId == 0) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Print the host address Information.\r
+  //\r
+  Status = Ip6ConvertAddressListToString (\r
+             PortString,\r
+             HiiHandle,\r
+             Ip6ConfigNvHostAddress,\r
+             IfInfo->AddressInfo,\r
+             IfInfo->AddressInfoCount\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Copy the Host Address Info to manual address field.\r
+  // Do not copy the link local address.\r
+  //\r
+  LinkLocalStr = StrStr (PortString, IP6_LINK_LOCAL_PREFIX);\r
+  if (LinkLocalStr != NULL) {\r
+    Number = LinkLocalStr - PortString;\r
+    if (Number > 0) {\r
+      CopyMem (IfrNvData->ManualAddress, PortString, Number * sizeof (CHAR16));\r
+    }\r
+\r
+    while ((*LinkLocalStr != L' ') && (*LinkLocalStr != L'\0')) {\r
+      LinkLocalStr++;\r
+    }\r
+\r
+    if (*LinkLocalStr != L'\0') {\r
+      LinkLocalStr++;\r
+      StrCat (IfrNvData->ManualAddress, LinkLocalStr);\r
+    }\r
+  } else {\r
+    StrCpy (IfrNvData->ManualAddress, PortString);\r
+  }\r
+\r
+  //\r
+  // Print the route table information.\r
+  //\r
+  Status = Ip6ConvertAddressListToString (\r
+             PortString,\r
+             HiiHandle,\r
+             Ip6ConfigNvRouteTable,\r
+             IfInfo->RouteTable,\r
+             IfInfo->RouteCount\r
+             );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Build the address info list from list array of node in IP6_ADDRESS_INFO_ENTRY.\r
+\r
+  @param[in]      Instance         Points to IP6 config instance data.\r
+  @param[in]      AddressType      The address type.\r
+  @param[out]     AddressInfo      The pointer to the buffer to store the address list.\r
+  @param[out]     AddressSize      The address size of the address list.\r
+\r
+  @retval EFI_SUCCESS              The operation finished successfully.\r
+  @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.\r
+  @retval EFI_UNSUPPORTED          The AddressType is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6BuildNvAddressInfo (\r
+  IN  IP6_CONFIG_INSTANCE            *Instance,\r
+  IN  IP6_CONFIG_NV_ADDRESS_TYPE     AddressType,\r
+  OUT VOID                           **AddressInfo,\r
+  OUT UINTN                          *AddressSize\r
+  )\r
+{\r
+  IP6_CONFIG_NVDATA                  *Ip6NvData;\r
+  LIST_ENTRY                         *Entry;\r
+  LIST_ENTRY                         *ListHead;\r
+  IP6_ADDRESS_INFO_ENTRY             *Node;\r
+  VOID                               *AddressList;\r
+  VOID                               *TmpStr;\r
+  UINTN                              DataSize;\r
+  EFI_IPv6_ADDRESS                   *Ip6Address;\r
+  EFI_IP6_CONFIG_MANUAL_ADDRESS      *ManualAddress;\r
+\r
+  if ((Instance == NULL) || (AddressInfo == NULL) || (AddressSize == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);\r
+\r
+  Ip6NvData = &Instance->Ip6NvData;\r
+\r
+  if (AddressType == Ip6ConfigNvHostAddress) {\r
+    ListHead = &Ip6NvData->ManualAddress;\r
+    DataSize = sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS) * Ip6NvData->ManualAddressCount;\r
+  } else if (AddressType == Ip6ConfigNvGatewayAddress) {\r
+    ListHead = &Ip6NvData->GatewayAddress;\r
+    DataSize = sizeof (EFI_IPv6_ADDRESS) * Ip6NvData->GatewayAddressCount;\r
+  } else if (AddressType == Ip6ConfigNvDnsAddress) {\r
+    ListHead = &Ip6NvData->DnsAddress;\r
+    DataSize = sizeof (EFI_IPv6_ADDRESS) * Ip6NvData->DnsAddressCount;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  AddressList = AllocateZeroPool (DataSize);\r
+  if (AddressList  == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  TmpStr = AddressList;\r
+\r
+  NET_LIST_FOR_EACH (Entry, ListHead) {\r
+    Node = NET_LIST_USER_STRUCT (Entry, IP6_ADDRESS_INFO_ENTRY, Link);\r
+    if (AddressType == Ip6ConfigNvHostAddress) {\r
+      ManualAddress = (EFI_IP6_CONFIG_MANUAL_ADDRESS *) AddressList;\r
+      IP6_COPY_ADDRESS (&ManualAddress->Address, &Node->AddrInfo.Address);\r
+      ManualAddress->PrefixLength = Node->AddrInfo.PrefixLength;\r
+      AddressList = (UINT8 *) AddressList + sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS);\r
+    } else {\r
+      Ip6Address = (EFI_IPv6_ADDRESS *) AddressList;\r
+      IP6_COPY_ADDRESS (Ip6Address, &Node->AddrInfo.Address);\r
+      AddressList = (UINT8 *) AddressList + sizeof (EFI_IPv6_ADDRESS);\r
+    }\r
+  }\r
+\r
+  *AddressInfo = TmpStr;\r
+  *AddressSize = DataSize;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Convert the IP6 configuration data into the IFR data.\r
+\r
+  @param[in, out]  IfrNvData       The IFR NV data.\r
+  @param[in]       Instance        The IP6 config instance data.\r
+\r
+  @retval EFI_SUCCESS              The operation finished successfully.\r
+  @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.\r
+  @retval EFI_UNSUPPORTED          The policy is not supported in the current implementation.\r
+  @retval Others                   Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6ConvertConfigNvDataToIfrNvData (\r
+  IN OUT IP6_CONFIG_IFR_NVDATA       *IfrNvData,\r
+  IN     IP6_CONFIG_INSTANCE         *Instance\r
+  )\r
+{\r
+  EFI_IP6_CONFIG_PROTOCOL                    *Ip6Config;\r
+  UINTN                                      DataSize;\r
+  VOID                                       *Data;\r
+  EFI_STATUS                                 Status;\r
+  EFI_IP6_CONFIG_INTERFACE_ID                InterfaceId;\r
+  EFI_IP6_CONFIG_POLICY                      Policy;\r
+  EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS   DadXmits;\r
+  EFI_HII_HANDLE                             HiiHandle;\r
+\r
+  if ((IfrNvData == NULL) || (Instance == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);\r
+\r
+  Ip6Config = &Instance->Ip6Config;\r
+  Data      = NULL;\r
+  DataSize  = 0;\r
+  HiiHandle = Instance->CallbackInfo.RegisteredHandle;\r
+\r
+  //\r
+  // Get the current interface info.\r
+  //\r
+  Status = Ip6ConfigNvGetData (\r
+             Ip6Config,\r
+             Ip6ConfigDataTypeInterfaceInfo,\r
+             &DataSize,\r
+             (VOID **) &Data\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Convert the interface info to string and print.\r
+  //\r
+  Status = Ip6ConvertInterfaceInfoToString (\r
+             (EFI_IP6_CONFIG_INTERFACE_INFO *) Data,\r
+             HiiHandle,\r
+             IfrNvData\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Get the interface id.\r
+  //\r
+  DataSize = sizeof (EFI_IP6_CONFIG_INTERFACE_ID);\r
+  ZeroMem (&InterfaceId, DataSize);\r
+  Status = Ip6Config->GetData (\r
+                        Ip6Config,\r
+                        Ip6ConfigDataTypeAltInterfaceId,\r
+                        &DataSize,\r
+                        &InterfaceId\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  Ip6ConvertInterfaceIdToString (IfrNvData->InterfaceId, &InterfaceId);\r
+\r
+  //\r
+  // Get current policy.\r
+  //\r
+  DataSize = sizeof (EFI_IP6_CONFIG_POLICY);\r
+  Status   = Ip6Config->GetData (\r
+                          Ip6Config,\r
+                          Ip6ConfigDataTypePolicy,\r
+                          &DataSize,\r
+                          &Policy\r
+                          );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (Policy == Ip6ConfigPolicyManual) {\r
+    IfrNvData->Policy = IP6_POLICY_MANUAL;\r
+  } else if (Policy == Ip6ConfigPolicyAutomatic) {\r
+    IfrNvData->Policy = IP6_POLICY_AUTO;\r
+  } else {\r
+    ASSERT (FALSE);\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Get Duplicate Address Detection Transmits count.\r
+  //\r
+  DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);\r
+  Status   = Ip6Config->GetData (\r
+                          Ip6Config,\r
+                          Ip6ConfigDataTypeDupAddrDetectTransmits,\r
+                          &DataSize,\r
+                          &DadXmits\r
+                          );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  IfrNvData->DadTransmitCount = DadXmits.DupAddrDetectTransmits;\r
+\r
+  //\r
+  // Get DNS server list.\r
+  //\r
+  FreePool (Data);\r
+  Data     = NULL;\r
+  DataSize = 0;\r
+  Status   = Ip6ConfigNvGetData (\r
+               Ip6Config,\r
+               Ip6ConfigDataTypeDnsServer,\r
+               &DataSize,\r
+               (VOID **) &Data\r
+               );\r
+\r
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (DataSize > 0) {\r
+    //\r
+    // Convert the DNS server address to string and draw it to UI.\r
+    //\r
+    Status = Ip6ConvertAddressListToString (\r
+               IfrNvData->DnsAddress,\r
+               HiiHandle,\r
+               Ip6ConfigNvDnsAddress,\r
+               Data,\r
+               DataSize / sizeof (EFI_IPv6_ADDRESS)\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    FreePool (Data);\r
+    Data = NULL;\r
+  }\r
+\r
+  //\r
+  // Get gateway adderss list.\r
+  //\r
+  DataSize = 0;\r
+  Status   = Ip6ConfigNvGetData (\r
+               Ip6Config,\r
+               Ip6ConfigDataTypeGateway,\r
+               &DataSize,\r
+               (VOID **) &Data\r
+               );\r
+\r
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (DataSize > 0) {\r
+    //\r
+    // Convert the gateway address to string and draw it to UI.\r
+    //\r
+    Status = Ip6ConvertAddressListToString (\r
+               IfrNvData->GatewayAddress,\r
+               HiiHandle,\r
+               Ip6ConfigNvGatewayAddress,\r
+               Data,\r
+               DataSize / sizeof (EFI_IPv6_ADDRESS)\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+Exit:\r
+  if (Data != NULL) {\r
+     FreePool (Data);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Convert IFR data into IP6 configuration data. The policy, alternative interface\r
+  ID, and DAD transmit counts, and will be saved. If under manual policy, the configured\r
+  manual address, gateway address, and DNS server address will be saved.\r
+\r
+  @param[in]       IfrNvData       The IFR NV data.\r
+  @param[in, out]  Instance        The IP6 config instance data.\r
+\r
+  @retval EFI_SUCCESS              The operation finished successfully.\r
+  @retval EFI_INVALID_PARAMETER    Any input parameter is invalid.\r
+  @retval Others                   Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6ConvertIfrNvDataToConfigNvData (\r
+  IN     IP6_CONFIG_IFR_NVDATA       *IfrNvData,\r
+  IN OUT IP6_CONFIG_INSTANCE         *Instance\r
+  )\r
+{\r
+  IP6_CONFIG_NVDATA                  *Ip6NvData;\r
+  EFI_IP6_CONFIG_PROTOCOL            *Ip6Config;\r
+  EFI_STATUS                         Status;\r
+  EFI_IP6_CONFIG_MANUAL_ADDRESS      *ManualAddress;\r
+  EFI_IPv6_ADDRESS                   *Address;\r
+  BOOLEAN                            IsAddressOk;\r
+  EFI_EVENT                          SetAddressEvent;\r
+  EFI_EVENT                          TimeoutEvent;\r
+  UINTN                              DataSize;\r
+\r
+  if ((IfrNvData == NULL) || (Instance == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NET_CHECK_SIGNATURE (Instance, IP6_CONFIG_INSTANCE_SIGNATURE);\r
+  Ip6NvData = &Instance->Ip6NvData;\r
+  Ip6Config = &Instance->Ip6Config;\r
+\r
+  //\r
+  // Update those fields which don't have INTERACTIVE attribute.\r
+  //\r
+  if (IfrNvData->Policy == IP6_POLICY_AUTO) {\r
+    Ip6NvData->Policy = Ip6ConfigPolicyAutomatic;\r
+  } else if (IfrNvData->Policy == IP6_POLICY_MANUAL) {\r
+    Ip6NvData->Policy = Ip6ConfigPolicyManual;\r
+  }\r
+\r
+  Ip6NvData->DadTransmitCount.DupAddrDetectTransmits = IfrNvData->DadTransmitCount;\r
+\r
+  //\r
+  // Set the configured policy.\r
+  //\r
+  Status = Ip6Config->SetData (\r
+                        Ip6Config,\r
+                        Ip6ConfigDataTypePolicy,\r
+                        sizeof (EFI_IP6_CONFIG_POLICY),\r
+                        &Ip6NvData->Policy\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set the duplicate address detection transmits count.\r
+  //\r
+  Status = Ip6Config->SetData (\r
+                        Ip6Config,\r
+                        Ip6ConfigDataTypeDupAddrDetectTransmits,\r
+                        sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS),\r
+                        &Ip6NvData->DadTransmitCount\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set the alternative interface ID\r
+  //\r
+  Status = Ip6Config->SetData (\r
+                        Ip6Config,\r
+                        Ip6ConfigDataTypeAltInterfaceId,\r
+                        sizeof (EFI_IP6_CONFIG_INTERFACE_ID),\r
+                        &Ip6NvData->InterfaceId\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+\r
+  if (Ip6NvData->Policy == Ip6ConfigPolicyAutomatic) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Create events & timers for asynchronous settings.\r
+  //\r
+  SetAddressEvent = NULL;\r
+  TimeoutEvent    = NULL;\r
+  ManualAddress   = NULL;\r
+  Address         = NULL;\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  Ip6ConfigManualAddressNotify,\r
+                  &IsAddressOk,\r
+                  &SetAddressEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER,\r
+                  TPL_CALLBACK,\r
+                  NULL,\r
+                  NULL,\r
+                  &TimeoutEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Set the manual address list. This is an asynchronous process.\r
+  //\r
+  if (!IsListEmpty (&Ip6NvData->ManualAddress) && (Ip6NvData->ManualAddressCount != 0)) {\r
+    Status = Ip6BuildNvAddressInfo (\r
+               Instance,\r
+               Ip6ConfigNvHostAddress,\r
+               (VOID **) &ManualAddress,\r
+               &DataSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    IsAddressOk = FALSE;\r
+\r
+    Status = Ip6Config->RegisterDataNotify (\r
+                          Ip6Config,\r
+                          Ip6ConfigDataTypeManualAddress,\r
+                          SetAddressEvent\r
+                          );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    Status = Ip6Config->SetData (\r
+                          Ip6Config,\r
+                          Ip6ConfigDataTypeManualAddress,\r
+                          DataSize,\r
+                          (VOID *) ManualAddress\r
+                          );\r
+    if (Status == EFI_NOT_READY) {\r
+      gBS->SetTimer (TimeoutEvent, TimerRelative, 50000000);\r
+      while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
+        if (IsAddressOk) {\r
+          Status = EFI_SUCCESS;\r
+        }\r
+        break;\r
+      }\r
+    }\r
+\r
+    Status = Ip6Config->UnregisterDataNotify (\r
+                          Ip6Config,\r
+                          Ip6ConfigDataTypeManualAddress,\r
+                          SetAddressEvent\r
+                          );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set gateway address list.\r
+  //\r
+  if (!IsListEmpty (&Ip6NvData->GatewayAddress) && (Ip6NvData->GatewayAddressCount != 0)) {\r
+    Status = Ip6BuildNvAddressInfo (\r
+               Instance,\r
+               Ip6ConfigNvGatewayAddress,\r
+               (VOID **) &Address,\r
+               &DataSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    Status = Ip6Config->SetData (\r
+                          Ip6Config,\r
+                          Ip6ConfigDataTypeGateway,\r
+                          DataSize,\r
+                          (VOID *) Address\r
+                          );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    FreePool (Address);\r
+    Address = NULL;\r
+  }\r
+\r
+  //\r
+  // Set DNS server address list.\r
+  //\r
+  if (!IsListEmpty (&Ip6NvData->DnsAddress) && (Ip6NvData->DnsAddressCount != 0)) {\r
+    Status = Ip6BuildNvAddressInfo (\r
+               Instance,\r
+               Ip6ConfigNvDnsAddress,\r
+               (VOID **) &Address,\r
+               &DataSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    Status = Ip6Config->SetData (\r
+                          Ip6Config,\r
+                          Ip6ConfigDataTypeDnsServer,\r
+                          DataSize,\r
+                          (VOID *) Address\r
+                          );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+Exit:\r
+  if (SetAddressEvent != NULL) {\r
+    gBS->CloseEvent (SetAddressEvent);\r
+  }\r
+\r
+  if (TimeoutEvent != NULL) {\r
+    gBS->CloseEvent (TimeoutEvent);\r
+  }\r
+\r
+  if (ManualAddress != NULL) {\r
+    FreePool (ManualAddress);\r
+  }\r
+\r
+  if (Address != NULL) {\r
+    FreePool (Address);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function allows the caller to request the current\r
+  configuration for one or more named elements. The resulting\r
+  string is in <ConfigAltResp> format. Any and all alternative\r
+  configuration strings shall also be appended to the end of the\r
+  current configuration string. If they are, they must appear\r
+  after the current configuration. They must contain the same\r
+  routing (GUID, NAME, PATH) as the current configuration string.\r
+  They must have an additional description indicating the type of\r
+  alternative configuration the string represents,\r
+  "ALTCFG=<StringToken>". That <StringToken> (when\r
+  converted from Hex UNICODE to binary) is a reference to a\r
+  string in the associated string pack.\r
+\r
+  @param[in] This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param[in] Request    A null-terminated Unicode string in\r
+                        <ConfigRequest> format. Note that this\r
+                        includes the routing information as well as\r
+                        the configurable name / value pairs. It is\r
+                        invalid for this string to be in\r
+                        <MultiConfigRequest> format.\r
+  @param[out] Progress  On return, points to a character in the\r
+                        Request string. Points to the string's null\r
+                        terminator if request was successful. Points\r
+                        to the most recent "&" before the first\r
+                        failing name / value pair (or the beginning\r
+                        of the string if the failure is in the first\r
+                        name / value pair) if the request was not\r
+                        successful.\r
+  @param[out] Results   A null-terminated Unicode string in\r
+                        <ConfigAltResp> format which has all values\r
+                        filled in for the names in the Request string.\r
+                        String to be allocated by the called function.\r
+\r
+  @retval EFI_SUCCESS             The Results string is filled with the\r
+                                  values corresponding to all requested\r
+                                  names.\r
+  @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the\r
+                                  parts of the results that must be\r
+                                  stored awaiting possible future\r
+                                  protocols.\r
+  @retval EFI_INVALID_PARAMETER   For example, passing in a NULL\r
+                                  for the Request parameter\r
+                                  would result in this type of\r
+                                  error. In this case, the\r
+                                  Progress parameter would be\r
+                                  set to NULL.\r
+  @retval EFI_NOT_FOUND           Routing data doesn't match any\r
+                                  known driver. Progress set to the\r
+                                  first character in the routing header.\r
+                                  Note: There is no requirement that the\r
+                                  driver validate the routing data. It\r
+                                  must skip the <ConfigHdr> in order to\r
+                                  process the names.\r
+  @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set\r
+                                  to most recent & before the\r
+                                  error or the beginning of the\r
+                                  string.\r
+  @retval EFI_INVALID_PARAMETER   Unknown name. Progress points\r
+                                  to the & before the name in\r
+                                  question. Currently not implemented.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Ip6FormExtractConfig (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  CONST EFI_STRING                       Request,\r
+  OUT EFI_STRING                             *Progress,\r
+  OUT EFI_STRING                             *Results\r
+  )\r
+{\r
+\r
+  EFI_STATUS                                 Status;\r
+  IP6_FORM_CALLBACK_INFO                     *Private;\r
+  IP6_CONFIG_INSTANCE                        *Ip6ConfigInstance;\r
+  IP6_CONFIG_IFR_NVDATA                      *IfrNvData;\r
+  EFI_STRING                                 ConfigRequestHdr;\r
+  EFI_STRING                                 ConfigRequest;\r
+  BOOLEAN                                    AllocatedRequest;\r
+  UINTN                                      Size;\r
+  UINTN                                      BufferSize;\r
+\r
+  if (This == NULL || Progress == NULL || Results == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Progress = Request;\r
+  if ((Request != NULL) &&\r
+      !HiiIsConfigHdrMatch (Request, &mIp6ConfigNvDataGuid, mIp6ConfigStorageName)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  ConfigRequestHdr = NULL;\r
+  ConfigRequest    = NULL;\r
+  AllocatedRequest = FALSE;\r
+  Size             = 0;\r
+\r
+  Private = IP6_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);\r
+  Ip6ConfigInstance = IP6_CONFIG_INSTANCE_FROM_FORM_CALLBACK (Private);\r
+  BufferSize = sizeof (IP6_CONFIG_IFR_NVDATA);\r
+\r
+  IfrNvData = (IP6_CONFIG_IFR_NVDATA *) AllocateZeroPool (BufferSize);\r
+  if (IfrNvData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = Ip6ConvertConfigNvDataToIfrNvData (IfrNvData, Ip6ConfigInstance);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  ConfigRequest = Request;\r
+  if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
+    //\r
+    // Request has no request element, construct full request string.\r
+    // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
+    // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.\r
+    //\r
+    ConfigRequestHdr = HiiConstructConfigHdr (\r
+                         &mIp6ConfigNvDataGuid,\r
+                         mIp6ConfigStorageName,\r
+                         Private->ChildHandle\r
+                         );\r
+    Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
+    ConfigRequest = AllocateZeroPool (Size);\r
+    ASSERT (ConfigRequest != NULL);\r
+    AllocatedRequest = TRUE;\r
+    UnicodeSPrint (\r
+      ConfigRequest,\r
+      Size,\r
+      L"%s&OFFSET=0&WIDTH=%016LX",\r
+      ConfigRequestHdr,\r
+      (UINT64) BufferSize\r
+      );\r
+    FreePool (ConfigRequestHdr);\r
+  }\r
+\r
+  //\r
+  // Convert buffer data to <ConfigResp> by helper function BlockToConfig()\r
+  //\r
+  Status = gHiiConfigRouting->BlockToConfig (\r
+                                gHiiConfigRouting,\r
+                                ConfigRequest,\r
+                                (UINT8 *) IfrNvData,\r
+                                BufferSize,\r
+                                Results,\r
+                                Progress\r
+                                );\r
+\r
+Exit:\r
+  FreePool (IfrNvData);\r
+  //\r
+  // Free the allocated config request string.\r
+  //\r
+  if (AllocatedRequest) {\r
+    FreePool (ConfigRequest);\r
+    ConfigRequest = NULL;\r
+  }\r
+  //\r
+  // Set Progress string to the original request string.\r
+  //\r
+  if (Request == NULL) {\r
+    *Progress = NULL;\r
+  } else if (StrStr (Request, L"OFFSET") == NULL) {\r
+    *Progress = Request + StrLen (Request);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function applies changes in a driver's configuration.\r
+  Input is a Configuration, which has the routing data for this\r
+  driver followed by name / value configuration pairs. The driver\r
+  must apply those pairs to its configurable storage. If the\r
+  driver's configuration is stored in a linear block of data\r
+  and the driver's name / value pairs are in <BlockConfig>\r
+  format, it may use the ConfigToBlock helper function (above) to\r
+  simplify the job. Currently not implemented.\r
+\r
+  @param[in]  This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param[in]  Configuration  A null-terminated Unicode string in\r
+                             <ConfigString> format.\r
+  @param[out] Progress       A pointer to a string filled in with the\r
+                             offset of the most recent '&' before the\r
+                             first failing name / value pair (or the\r
+                             beginn ing of the string if the failure\r
+                             is in the first name / value pair) or\r
+                             the terminating NULL if all was\r
+                             successful.\r
+\r
+  @retval EFI_SUCCESS             The results have been distributed or are\r
+                                  awaiting distribution.\r
+  @retval EFI_OUT_OF_MEMORY       Not enough memory to store the\r
+                                  parts of the results that must be\r
+                                  stored awaiting possible future\r
+                                  protocols.\r
+  @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the\r
+                                  Results parameter would result\r
+                                  in this type of error.\r
+  @retval EFI_NOT_FOUND           Target for the specified routing data\r
+                                  was not found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Ip6FormRouteConfig (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  CONST EFI_STRING                       Configuration,\r
+  OUT EFI_STRING                             *Progress\r
+  )\r
+{\r
+  if (This == NULL || Configuration == NULL || Progress == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check routing data in <ConfigHdr>.\r
+  // Note: if only one Storage is used, then this checking could be skipped.\r
+  //\r
+  if (!HiiIsConfigHdrMatch (Configuration, &mIp6ConfigNvDataGuid, mIp6ConfigStorageName)) {\r
+    *Progress = Configuration;\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *Progress = Configuration + StrLen (Configuration);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is called to provide results data to the driver.\r
+  This data consists of a unique key that is used to identify\r
+  which data is either being passed back or being asked for.\r
+\r
+  @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param[in]  Action             Specifies the type of action taken by the browser.\r
+  @param[in]  QuestionId         A unique value which is sent to the original\r
+                                 exporting driver so that it can identify the type\r
+                                 of data to expect. The format of the data tends to\r
+                                 vary based on the opcode that generated the callback.\r
+  @param[in]  Type               The type of value for the question.\r
+  @param[in]  Value              A pointer to the data being sent to the original\r
+                                 exporting driver.\r
+  @param[out]  ActionRequest     On return, points to the action requested by the\r
+                                 callback function.\r
+\r
+  @retval EFI_SUCCESS            The callback successfully handled the action.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the\r
+                                 variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be saved.\r
+  @retval EFI_UNSUPPORTED        The specified Action is not supported by the\r
+                                 callback. Currently not implemented.\r
+  @retval EFI_INVALID_PARAMETER  Passed in the wrong parameter.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Ip6FormCallback (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  EFI_BROWSER_ACTION                     Action,\r
+  IN  EFI_QUESTION_ID                        QuestionId,\r
+  IN  UINT8                                  Type,\r
+  IN  EFI_IFR_TYPE_VALUE                     *Value,\r
+  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest\r
+  )\r
+{\r
+  IP6_FORM_CALLBACK_INFO        *Private;\r
+  UINTN                         BufferSize;\r
+  IP6_CONFIG_IFR_NVDATA         *IfrNvData;\r
+  IP6_CONFIG_IFR_NVDATA         OldIfrNvData;\r
+  EFI_STATUS                    Status;\r
+  EFI_INPUT_KEY                 Key;\r
+  IP6_CONFIG_INSTANCE           *Instance;\r
+  IP6_CONFIG_NVDATA             *Ip6NvData;\r
+  EFI_IP6_CONFIG_PROTOCOL       *Ip6Config;\r
+  EFI_IP6_CONFIG_INTERFACE_INFO *Data;\r
+  UINTN                         DataSize;\r
+  CHAR16                        PortString[ADDRESS_STR_MAX_SIZE];\r
+  EFI_HII_HANDLE                HiiHandle;\r
+  EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private   = IP6_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS (This);\r
+  Instance  = IP6_CONFIG_INSTANCE_FROM_FORM_CALLBACK (Private);\r
+  Ip6NvData = &Instance->Ip6NvData;\r
+\r
+  if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {\r
+    //\r
+    // Update main Form when main Form is opened.\r
+    // This will be done only in FORM_OPEN CallBack of question with KEY_INTERFACE_ID from main Form.\r
+    //\r
+    if (QuestionId != KEY_INTERFACE_ID) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    Ip6Config = &Instance->Ip6Config;\r
+    HiiHandle = Instance->CallbackInfo.RegisteredHandle;\r
+\r
+    //\r
+    // Get the current interface info.\r
+    //\r
+    Status = Ip6ConfigNvGetData (\r
+               Ip6Config,\r
+               Ip6ConfigDataTypeInterfaceInfo,\r
+               &DataSize,\r
+               (VOID **) &Data\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // Generate the dynamic text opcode for host address and draw it.\r
+    //\r
+    IfInfo = (EFI_IP6_CONFIG_INTERFACE_INFO *) Data;\r
+    Status = Ip6ConvertAddressListToString (\r
+               PortString,\r
+               HiiHandle,\r
+               Ip6ConfigNvHostAddress,\r
+               IfInfo->AddressInfo,\r
+               IfInfo->AddressInfoCount\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // Generate the dynamic text opcode for route table and draw it.\r
+    //\r
+    Status = Ip6ConvertAddressListToString (\r
+               PortString,\r
+               HiiHandle,\r
+               Ip6ConfigNvRouteTable,\r
+               IfInfo->RouteTable,\r
+               IfInfo->RouteCount\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // Get DNS server list.\r
+    //\r
+    DataSize = 0;\r
+    Status = Ip6ConfigNvGetData (\r
+               Ip6Config,\r
+               Ip6ConfigDataTypeDnsServer,\r
+               &DataSize,\r
+               (VOID **) &Data\r
+               );\r
+    if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+      goto Exit;\r
+    }\r
+\r
+    if (DataSize > 0) {\r
+      //\r
+      // Generate the dynamic text opcode for DNS server and draw it.\r
+      //\r
+      Status = Ip6ConvertAddressListToString (\r
+                 PortString,\r
+                 HiiHandle,\r
+                 Ip6ConfigNvDnsAddress,\r
+                 Data,\r
+                 DataSize / sizeof (EFI_IPv6_ADDRESS)\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Exit;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Get gateway adderss list.\r
+    //\r
+    DataSize = 0;\r
+    Status = Ip6ConfigNvGetData (\r
+               Ip6Config,\r
+               Ip6ConfigDataTypeGateway,\r
+               &DataSize,\r
+               (VOID **) &Data\r
+               );\r
+    if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+      goto Exit;\r
+    }\r
+\r
+    if (DataSize > 0) {\r
+      //\r
+      // Generate the dynamic text opcode for gateway and draw it.\r
+      //\r
+      Status = Ip6ConvertAddressListToString (\r
+                 PortString,\r
+                 HiiHandle,\r
+                 Ip6ConfigNvGatewayAddress,\r
+                 Data,\r
+                 DataSize / sizeof (EFI_IPv6_ADDRESS)\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Exit;\r
+      }\r
+    }\r
+\r
+Exit:\r
+    FreePool (Data);\r
+    return Status;\r
+  }\r
+\r
+  if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {\r
+    //\r
+    // Do nothing for UEFI FORM_CLOSE action\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((Value == NULL) || (ActionRequest == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Retrieve uncommitted data from Browser\r
+  //\r
+\r
+  BufferSize = sizeof (IP6_CONFIG_IFR_NVDATA);\r
+  IfrNvData = AllocateZeroPool (BufferSize);\r
+  if (IfrNvData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  ZeroMem (&OldIfrNvData, BufferSize);\r
+\r
+  HiiGetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData);\r
+\r
+  CopyMem (&OldIfrNvData, IfrNvData, BufferSize);\r
+\r
+  switch (QuestionId) {\r
+  case KEY_INTERFACE_ID:\r
+    Status = Ip6ParseInterfaceIdFromString (IfrNvData->InterfaceId, &Ip6NvData->InterfaceId);\r
+    if (EFI_ERROR (Status)) {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Invalid Interface ID!",\r
+        NULL\r
+        );\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_MANUAL_ADDRESS:\r
+    Status = Ip6ParseAddressListFromString (\r
+               IfrNvData->ManualAddress,\r
+               &Ip6NvData->ManualAddress,\r
+               &Ip6NvData->ManualAddressCount\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Invalid Host Addresses!",\r
+        NULL\r
+        );\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_GATEWAY_ADDRESS:\r
+    Status = Ip6ParseAddressListFromString (\r
+               IfrNvData->GatewayAddress,\r
+               &Ip6NvData->GatewayAddress,\r
+               &Ip6NvData->GatewayAddressCount\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Invalid Gateway Addresses!",\r
+        NULL\r
+        );\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_DNS_ADDRESS:\r
+    Status = Ip6ParseAddressListFromString (\r
+               IfrNvData->DnsAddress,\r
+               &Ip6NvData->DnsAddress,\r
+               &Ip6NvData->DnsAddressCount\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Invalid DNS Addresses!",\r
+        NULL\r
+        );\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_SAVE_CONFIG_CHANGES:\r
+    CopyMem (&OldIfrNvData, IfrNvData, sizeof (IP6_CONFIG_IFR_NVDATA));\r
+    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+    break;\r
+\r
+  case KEY_IGNORE_CONFIG_CHANGES:\r
+    CopyMem (IfrNvData, &OldIfrNvData, sizeof (IP6_CONFIG_IFR_NVDATA));\r
+    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+    break;\r
+\r
+  case KEY_SAVE_CHANGES:\r
+    Status = Ip6ConvertIfrNvDataToConfigNvData (IfrNvData, Instance);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Pass changed uncommitted data back to Form Browser.\r
+    //\r
+    BufferSize = sizeof (IP6_CONFIG_IFR_NVDATA);\r
+    HiiSetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData, NULL);\r
+  }\r
+\r
+  FreePool (IfrNvData);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Install HII Config Access protocol for network device and allocate resources.\r
+\r
+  @param[in, out]  Instance      The IP6_CONFIG_INSTANCE to create a form.\r
+\r
+  @retval EFI_SUCCESS            The HII Config Access protocol is installed.\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip6ConfigFormInit (\r
+  IN OUT IP6_CONFIG_INSTANCE     *Instance\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  IP6_SERVICE                    *IpSb;\r
+  IP6_FORM_CALLBACK_INFO         *CallbackInfo;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
+  VENDOR_DEVICE_PATH             VendorDeviceNode;\r
+  EFI_SERVICE_BINDING_PROTOCOL   *MnpSb;\r
+  CHAR16                         *MacString;\r
+  CHAR16                         MenuString[128];\r
+  CHAR16                         PortString[128];\r
+  CHAR16                         *OldMenuString;\r
+  EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath;\r
+\r
+  IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
+  ASSERT (IpSb != NULL);\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  IpSb->Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CallbackInfo = &Instance->CallbackInfo;\r
+  CallbackInfo->Signature = IP6_FORM_CALLBACK_INFO_SIGNATURE;\r
+\r
+  //\r
+  // Construct device path node for EFI HII Config Access protocol,\r
+  // which consists of controller physical device path and one hardware\r
+  // vendor guid node.\r
+  //\r
+  ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));\r
+  VendorDeviceNode.Header.Type    = HARDWARE_DEVICE_PATH;\r
+  VendorDeviceNode.Header.SubType = HW_VENDOR_DP;\r
+\r
+  CopyGuid (&VendorDeviceNode.Guid, &mIp6HiiVendorDevicePathGuid);\r
+\r
+  SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));\r
+  CallbackInfo->HiiVendorDevicePath = AppendDevicePathNode (\r
+                                        ParentDevicePath,\r
+                                        (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode\r
+                                        );\r
+  if (CallbackInfo->HiiVendorDevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  ConfigAccess                = &CallbackInfo->HiiConfigAccess;\r
+  ConfigAccess->ExtractConfig = Ip6FormExtractConfig;\r
+  ConfigAccess->RouteConfig   = Ip6FormRouteConfig;\r
+  ConfigAccess->Callback      = Ip6FormCallback;\r
+\r
+  //\r
+  // Install Device Path Protocol and Config Access protocol on new handle\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &CallbackInfo->ChildHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  CallbackInfo->HiiVendorDevicePath,\r
+                  &gEfiHiiConfigAccessProtocolGuid,\r
+                  ConfigAccess,\r
+                  NULL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Open the Parent Handle for the child\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    IpSb->Controller,\r
+                    &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+                    (VOID **) &MnpSb,\r
+                    IpSb->Image,\r
+                    CallbackInfo->ChildHandle,\r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                    );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // Publish our HII data\r
+  //\r
+  CallbackInfo->RegisteredHandle = HiiAddPackages (\r
+                                     &mIp6ConfigNvDataGuid,\r
+                                     CallbackInfo->ChildHandle,\r
+                                     Ip6DxeStrings,\r
+                                     Ip6ConfigBin,\r
+                                     NULL\r
+                                     );\r
+  if (CallbackInfo->RegisteredHandle == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // Append MAC string in the menu string and tile string\r
+  //\r
+  Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &MacString);\r
+  if (!EFI_ERROR (Status)) {\r
+    OldMenuString = HiiGetString (\r
+                      CallbackInfo->RegisteredHandle,\r
+                      STRING_TOKEN (STR_IP6_CONFIG_FORM_TITLE),\r
+                      NULL)\r
+                      ;\r
+    UnicodeSPrint (MenuString, 128, L"%s (MAC:%s)", OldMenuString, MacString);\r
+    HiiSetString (\r
+      CallbackInfo->RegisteredHandle,\r
+      STRING_TOKEN (STR_IP6_CONFIG_FORM_TITLE),\r
+      MenuString,\r
+      NULL\r
+      );\r
+    UnicodeSPrint (PortString, 128, L"MAC:%s", MacString);\r
+    HiiSetString (\r
+      CallbackInfo->RegisteredHandle,\r
+      STRING_TOKEN (STR_IP6_DEVICE_FORM_TITLE),\r
+      PortString,\r
+      NULL\r
+      );\r
+\r
+    FreePool (MacString);\r
+    FreePool (OldMenuString);\r
+\r
+    InitializeListHead (&Instance->Ip6NvData.ManualAddress);\r
+    InitializeListHead (&Instance->Ip6NvData.GatewayAddress);\r
+    InitializeListHead (&Instance->Ip6NvData.DnsAddress);\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+Error:\r
+  Ip6ConfigFormUnload (Instance);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Uninstall the HII Config Access protocol for network devices and free up the resources.\r
+\r
+  @param[in, out]  Instance      The IP6_CONFIG_INSTANCE to unload a form.\r
+\r
+**/\r
+VOID\r
+Ip6ConfigFormUnload (\r
+  IN OUT IP6_CONFIG_INSTANCE     *Instance\r
+  )\r
+{\r
+  IP6_SERVICE                    *IpSb;\r
+  IP6_FORM_CALLBACK_INFO         *CallbackInfo;\r
+  IP6_CONFIG_NVDATA              *Ip6NvData;\r
+\r
+  IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance);\r
+  ASSERT (IpSb != NULL);\r
+\r
+  CallbackInfo = &Instance->CallbackInfo;\r
+\r
+  if (CallbackInfo->ChildHandle != NULL) {\r
+\r
+    //\r
+    // Close the child handle\r
+    //\r
+    gBS->CloseProtocol (\r
+           IpSb->Controller,\r
+           &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+           IpSb->Image,\r
+           CallbackInfo->ChildHandle\r
+           );\r
+    //\r
+    // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL\r
+    //\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+           CallbackInfo->ChildHandle,\r
+           &gEfiDevicePathProtocolGuid,\r
+           CallbackInfo->HiiVendorDevicePath,\r
+           &gEfiHiiConfigAccessProtocolGuid,\r
+           &CallbackInfo->HiiConfigAccess,\r
+           NULL\r
+           );\r
+  }\r
+\r
+  if (CallbackInfo->HiiVendorDevicePath != NULL) {\r
+    FreePool (CallbackInfo->HiiVendorDevicePath);\r
+  }\r
+\r
+  if (CallbackInfo->RegisteredHandle != NULL) {\r
+    //\r
+    // Remove HII package list\r
+    //\r
+    HiiRemovePackages (CallbackInfo->RegisteredHandle);\r
+  }\r
+\r
+  Ip6NvData = &Instance->Ip6NvData;\r
+\r
+  Ip6FreeAddressInfoList (&Ip6NvData->ManualAddress);\r
+  Ip6FreeAddressInfoList (&Ip6NvData->GatewayAddress);\r
+  Ip6FreeAddressInfoList (&Ip6NvData->DnsAddress);\r
+\r
+  Ip6NvData->ManualAddressCount  = 0;\r
+  Ip6NvData->GatewayAddressCount = 0;\r
+  Ip6NvData->DnsAddressCount     = 0;\r
+}\r