--- /dev/null
+/** @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