diff options
Diffstat (limited to 'NetworkPkg/Ip6Dxe/Ip6ConfigNv.c')
-rw-r--r-- | NetworkPkg/Ip6Dxe/Ip6ConfigNv.c | 2116 |
1 files changed, 2116 insertions, 0 deletions
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.<BR>
+
+ 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 <ConfigAltResp> 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=<StringToken>". That <StringToken> (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
+ <ConfigRequest> 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
+ <MultiConfigRequest> 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
+ <ConfigAltResp> 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 <ConfigHdr> 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 <ConfigHdr> 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 <ConfigResp> 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 <BlockConfig>
+ 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
+ <ConfigString> 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 <ConfigHdr>.
+ // 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;
+}
|