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