--- /dev/null
+/** @file\r
+ The implementation for ifcommand shell command.\r
+\r
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include "UefiShellNetwork1CommandsLib.h"\r
+\r
+#define NIC_ITEM_CONFIG_SIZE (sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE)\r
+#define EFI_IP4_TO_U32(EfiIpAddr) (*(IP4_ADDR*)((EfiIpAddr).Addr))\r
+\r
+BOOLEAN mIp4ConfigExist = FALSE;\r
+STATIC EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting = NULL;\r
+\r
+STATIC CONST UINTN SEC_TO_NS = 10000000;\r
+STATIC CONST CHAR16 DhcpString[5] = L"DHCP";\r
+STATIC CONST CHAR16 StaticString[7] = L"STATIC";\r
+STATIC CONST CHAR16 PermanentString[10] = L"PERMANENT";\r
+\r
+typedef struct {\r
+ LIST_ENTRY Link;\r
+ EFI_HANDLE Handle;\r
+ NIC_ADDR NicAddress;\r
+ CHAR16 Name[IP4_NIC_NAME_LENGTH];\r
+ BOOLEAN MediaPresentSupported;\r
+ BOOLEAN MediaPresent;\r
+ EFI_IP4_CONFIG_PROTOCOL *Ip4Config;\r
+ NIC_IP4_CONFIG_INFO *ConfigInfo;\r
+} NIC_INFO;\r
+\r
+typedef struct {\r
+ EFI_IP_ADDRESS DestIp;\r
+ EFI_MAC_ADDRESS DestMac;\r
+ EFI_IP_ADDRESS LocalIp;\r
+ EFI_MAC_ADDRESS LocalMac;\r
+ UINT8 MacLen;\r
+ EFI_EVENT OnResolved;\r
+ BOOLEAN Duplicate;\r
+} ARP_REQUEST;\r
+\r
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
+ {L"-c", TypeValue},\r
+ {L"-l", TypeValue},\r
+ {L"-s", TypeMaxValue},\r
+ {NULL, TypeMax}\r
+ };\r
+\r
+STATIC LIST_ENTRY NicInfoList;\r
+STATIC BOOLEAN ArpResolved;\r
+STATIC BOOLEAN mTimeout;\r
+\r
+/**\r
+ Count the space delimited items in a string.\r
+\r
+ @param[in] String A pointer to the string to count.\r
+\r
+ @return The number of space-delimited items.\r
+ @retval 0xFF an error occured.\r
+**/\r
+UINT8\r
+EFIAPI\r
+CountSubItems (\r
+ IN CONST CHAR16 *String\r
+ )\r
+{\r
+ CONST CHAR16 *Walker;\r
+ UINT8 Count;\r
+\r
+ if (String == NULL || *String == CHAR_NULL) {\r
+ return (0xFF);\r
+ }\r
+\r
+ for (Walker = String, Count = 0 ; Walker != NULL && *Walker != CHAR_NULL ; Walker = (StrStr(Walker, L" ")==NULL?NULL:StrStr(Walker, L" ")+1), Count++);\r
+ return (Count);\r
+}\r
+\r
+/**\r
+ Find the NIC_INFO by the specified nic name.\r
+\r
+ @param[in] Name The pointer to the string containing the NIC name.\r
+ \r
+ @return The pointer to the NIC_INFO if there is a NIC_INFO named by Name.\r
+ @retval NULL No NIC_INFO was found for Name.\r
+**/\r
+NIC_INFO*\r
+EFIAPI\r
+IfconfigFindNicByName (\r
+ IN CONST CHAR16 *Name\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+ NIC_INFO *Info;\r
+ CHAR16 *TempString;\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &NicInfoList) {\r
+ Info = BASE_CR (Entry, NIC_INFO, Link);\r
+ TempString = (CHAR16*)Info->Name;\r
+\r
+ if (StringNoCaseCompare (&Name, &TempString) == 0) {\r
+ return Info;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Tests whether a child handle is a child device of the controller.\r
+\r
+ @param[in] ControllerHandle A handle for a (parent) controller to test.\r
+ @param[in] ChildHandle A child handle to test.\r
+ @param[in] ProtocolGuid Supplies the protocol that the child controller\r
+ opens on its parent controller.\r
+\r
+ @retval EFI_SUCCESS ChildHandle is a child of the ControllerHandle.\r
+ @retval EFI_UNSUPPORTED ChildHandle is not a child of the ControllerHandle.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TestChildHandle (\r
+ IN CONST EFI_HANDLE ControllerHandle,\r
+ IN CONST EFI_HANDLE ChildHandle,\r
+ IN CONST EFI_GUID *ProtocolGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
+ UINTN EntryCount;\r
+ UINTN Index;\r
+\r
+ ASSERT (ProtocolGuid != NULL);\r
+\r
+ //\r
+ // Retrieve the list of agents that are consuming the specific protocol\r
+ // on ControllerHandle.\r
+ //\r
+ Status = gBS->OpenProtocolInformation (\r
+ ControllerHandle,\r
+ (EFI_GUID *) ProtocolGuid,\r
+ &OpenInfoBuffer,\r
+ &EntryCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Inspect if ChildHandle is one of the agents.\r
+ //\r
+ Status = EFI_UNSUPPORTED;\r
+ for (Index = 0; Index < EntryCount; Index++) {\r
+ if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&\r
+ (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (OpenInfoBuffer);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get the child handle of the NIC handle.\r
+\r
+ @param[in] Controller Routing information: GUID.\r
+ @param[in] ChildHandle Returned child handle.\r
+\r
+ @retval EFI_SUCCESS Successfully to get child handle.\r
+**/\r
+EFI_STATUS \r
+GetChildHandle (\r
+ IN EFI_HANDLE Controller,\r
+ OUT EFI_HANDLE *ChildHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *Handles;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ EFI_DEVICE_PATH_PROTOCOL *ChildDeviceDevicePath;\r
+ VENDOR_DEVICE_PATH *VendorDeviceNode;\r
+\r
+ //\r
+ // Locate all EFI Hii Config Access protocols\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &Handles\r
+ );\r
+ if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ \r
+ Status = TestChildHandle (Controller, Handles[Index], &gEfiManagedNetworkServiceBindingProtocolGuid);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Get device path on the child handle\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ Handles[Index],\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ChildDeviceDevicePath\r
+ );\r
+ \r
+ if (!EFI_ERROR (Status)) {\r
+ while (!IsDevicePathEnd (ChildDeviceDevicePath)) {\r
+ ChildDeviceDevicePath = NextDevicePathNode (ChildDeviceDevicePath);\r
+ //\r
+ // Parse one instance\r
+ //\r
+ if (ChildDeviceDevicePath->Type == HARDWARE_DEVICE_PATH && \r
+ ChildDeviceDevicePath->SubType == HW_VENDOR_DP) {\r
+ VendorDeviceNode = (VENDOR_DEVICE_PATH *) ChildDeviceDevicePath;\r
+ if (CompareMem (&VendorDeviceNode->Guid, &gEfiNicIp4ConfigVariableGuid, sizeof (EFI_GUID)) == 0) {\r
+ //\r
+ // Found item matched gEfiNicIp4ConfigVariableGuid\r
+ //\r
+ *ChildHandle = Handles[Index];\r
+ FreePool (Handles);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ } \r
+ }\r
+ }\r
+\r
+ FreePool (Handles);\r
+ return Status; \r
+}\r
+\r
+/**\r
+ Append OFFSET/WIDTH/VALUE items at the beginning of string.\r
+\r
+ @param[in,out] String The pointer to the string to append onto.\r
+ @param[in] Offset Offset value.\r
+ @param[in] Width Width value.\r
+ @param[in] Block Point to data buffer.\r
+\r
+ @return The count of unicode character that were appended.\r
+**/\r
+UINTN\r
+EFIAPI\r
+AppendOffsetWidthValue (\r
+ IN OUT CHAR16 *String,\r
+ IN UINTN Offset,\r
+ IN UINTN Width,\r
+ IN CONST UINT8 *Block\r
+ )\r
+\r
+{\r
+ CHAR16 *OriString;\r
+\r
+ OriString = String;\r
+\r
+ StrCpy (String, L"&OFFSET=");\r
+ String += StrLen (L"&OFFSET=");\r
+ String += UnicodeSPrint (String, 20, L"%x", Offset);\r
+\r
+ StrCpy (String,L"&WIDTH=");\r
+ String += StrLen (L"&WIDTH=");\r
+ String += UnicodeSPrint (String, 20, L"%x", Width);\r
+\r
+ if (Block != NULL) {\r
+ StrCpy (String,L"&VALUE=");\r
+ String += StrLen (L"&VALUE=");\r
+ while ((Width--) != 0) {\r
+ String += UnicodeSPrint (String, 20, L"%x", Block[Width]);\r
+ }\r
+ }\r
+ \r
+ return String - OriString;\r
+}\r
+\r
+/**\r
+ Converts the unicode character of the string from uppercase to lowercase.\r
+ This is a internal function.\r
+\r
+ @param ConfigString String to be converted\r
+**/\r
+CHAR16* \r
+EFIAPI\r
+HiiToLower (\r
+ IN CHAR16 *ConfigString\r
+ )\r
+{\r
+ CHAR16 *String;\r
+ BOOLEAN Lower;\r
+\r
+ //\r
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]\r
+ //\r
+ for (String = ConfigString, Lower = FALSE; String != NULL && *String != L'\0'; String++) {\r
+ if (*String == L'=') {\r
+ Lower = TRUE;\r
+ } else if (*String == L'&') {\r
+ Lower = FALSE;\r
+ } else if (Lower && *String >= L'A' && *String <= L'F') {\r
+ *String = (CHAR16) (*String - L'A' + L'a');\r
+ }\r
+ }\r
+\r
+ return (ConfigString);\r
+}\r
+\r
+\r
+/**\r
+ Construct <ConfigHdr> using routing information GUID/NAME/PATH.\r
+\r
+ @param[in] Guid Routing information: GUID.\r
+ @param[in] Name Routing information: NAME.\r
+ @param[in] DriverHandle Driver handle which contains the routing information: PATH.\r
+\r
+ @retval NULL An error occured.\r
+ @return The pointer to configHdr string.\r
+**/\r
+CHAR16 *\r
+EFIAPI\r
+ConstructConfigHdr (\r
+ IN CONST EFI_GUID *Guid,\r
+ IN CONST CHAR16 *Name,\r
+ IN EFI_HANDLE DriverHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 *ConfigHdr;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ CHAR16 *String;\r
+ UINTN Index;\r
+ UINT8 *Buffer;\r
+ UINTN DevicePathLength;\r
+ UINTN NameLength;\r
+\r
+ //\r
+ // Get the device path from handle installed EFI HII Config Access protocol\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ DriverHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ DevicePathLength = GetDevicePathSize (DevicePath);\r
+ NameLength = StrLen (Name);\r
+ ConfigHdr = AllocateZeroPool ((5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathLength * 2 + 1) * sizeof (CHAR16));\r
+ if (ConfigHdr == NULL) {\r
+ return NULL;\r
+ } \r
+\r
+ String = ConfigHdr;\r
+ StrCpy (String, L"GUID=");\r
+ String += StrLen (L"GUID=");\r
+\r
+ //\r
+ // Append Guid converted to <HexCh>32\r
+ //\r
+ for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {\r
+ String += UnicodeSPrint (String, 6, L"%02x", *Buffer++);\r
+ }\r
+\r
+ //\r
+ // Append L"&NAME="\r
+ //\r
+ StrCpy (String, L"&NAME=");\r
+ String += StrLen (L"&NAME=");\r
+ for (Index = 0; Index < NameLength ; Index++) {\r
+ String += UnicodeSPrint (String, 10, L"00%x", Name[Index]);\r
+ }\r
+ \r
+ //\r
+ // Append L"&PATH="\r
+ //\r
+ StrCpy (String, L"&PATH=");\r
+ String += StrLen (L"&PATH=");\r
+ for (Index = 0, Buffer = (UINT8 *) DevicePath; Index < DevicePathLength; Index++) {\r
+ String += UnicodeSPrint (String, 6, L"%02x", *Buffer++);\r
+ }\r
+\r
+ return (HiiToLower(ConfigHdr));\r
+}\r
+\r
+/**\r
+ Get network physical device NIC information.\r
+\r
+ @param[in] Handle The network physical device handle.\r
+ @param[out] NicAddr NIC information.\r
+\r
+ @retval EFI_SUCCESS Get NIC information successfully.\r
+**/ \r
+EFI_STATUS\r
+EFIAPI\r
+IfConfigGetNicMacInfo (\r
+ IN EFI_HANDLE Handle,\r
+ OUT NIC_ADDR *NicAddr\r
+ ) \r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE MnpHandle;\r
+ EFI_SIMPLE_NETWORK_MODE SnpMode;\r
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
+\r
+ MnpHandle = NULL;\r
+ Mnp = NULL;\r
+\r
+ Status = NetLibCreateServiceChild (\r
+ Handle,\r
+ gImageHandle, \r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ &MnpHandle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (\r
+ MnpHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ (VOID **) &Mnp\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Mnp->GetModeData (Mnp, NULL, &SnpMode);\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {\r
+ goto ON_ERROR;\r
+ }\r
+ \r
+ NicAddr->Type = (UINT16) SnpMode.IfType;\r
+ NicAddr->Len = (UINT8) SnpMode.HwAddressSize;\r
+ CopyMem (&NicAddr->MacAddr, &SnpMode.CurrentAddress, NicAddr->Len);\r
+\r
+ON_ERROR:\r
+\r
+ NetLibDestroyServiceChild (\r
+ Handle,\r
+ gImageHandle, \r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ MnpHandle\r
+ );\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ Get network physical device NIC information.\r
+\r
+ @param[in] Handle The network physical device handle.\r
+ @param[out] MediaPresentSupported\r
+ Upon successful return, TRUE is media present \r
+ is supported. FALSE otherwise.\r
+ @param[out] MediaPresent Upon successful return, TRUE is media present \r
+ is enabled. FALSE otherwise.\r
+\r
+ @retval EFI_SUCCESS The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IfConfigGetNicMediaStatus (\r
+ IN EFI_HANDLE Handle,\r
+ OUT BOOLEAN *MediaPresentSupported,\r
+ OUT BOOLEAN *MediaPresent\r
+ ) \r
+ \r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE MnpHandle;\r
+ EFI_SIMPLE_NETWORK_MODE SnpMode;\r
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
+\r
+ MnpHandle = NULL;\r
+ Mnp = NULL;\r
+\r
+ Status = NetLibCreateServiceChild (\r
+ Handle,\r
+ gImageHandle, \r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ &MnpHandle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (\r
+ MnpHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ (VOID **) &Mnp\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Status = Mnp->GetModeData (Mnp, NULL, &SnpMode);\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {\r
+ goto ON_ERROR;\r
+ }\r
+ \r
+ *MediaPresentSupported = SnpMode.MediaPresentSupported;\r
+ *MediaPresent = SnpMode.MediaPresent;\r
+\r
+ON_ERROR:\r
+\r
+ NetLibDestroyServiceChild (\r
+ Handle,\r
+ gImageHandle, \r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ MnpHandle\r
+ );\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ Get all Nic's information through HII service.\r
+\r
+ @retval EFI_SUCCESS All the nic information is collected.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IfconfigGetAllNicInfoByHii (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *Handles;\r
+ UINTN HandleCount;\r
+ CHAR16 *ConfigResp;\r
+ CHAR16 *ConfigHdr;\r
+ UINTN Index;\r
+ CHAR16 *AccessProgress;\r
+ CHAR16 *AccessResults;\r
+ UINTN BufferSize;\r
+ NIC_INFO *NicInfo;\r
+ NIC_IP4_CONFIG_INFO *NicConfigRequest;\r
+ NIC_IP4_CONFIG_INFO *NicConfig;\r
+ CHAR16 *String;\r
+ UINTN Length;\r
+ UINTN Offset;\r
+ EFI_HANDLE ChildHandle;\r
+\r
+ AccessResults = NULL;\r
+ ConfigHdr = NULL;\r
+ ConfigResp = NULL;\r
+ NicConfigRequest = NULL;\r
+ NicInfo = NULL;\r
+\r
+ InitializeListHead (&NicInfoList);\r
+\r
+ //\r
+ // Check if HII Config Routing protocol available.\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiHiiConfigRoutingProtocolGuid,\r
+ NULL,\r
+ (VOID**)&mHiiConfigRouting\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Locate all network device handles\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &Handles\r
+ );\r
+ if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = GetChildHandle (Handles[Index], &ChildHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // If failed to get Child handle, try NIC controller handle for back-compatibility.\r
+ //\r
+ ChildHandle = Handles[Index];\r
+ }\r
+ //\r
+ // Construct configuration request string header\r
+ //\r
+ ConfigHdr = ConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, ChildHandle);\r
+ Length = StrLen (ConfigHdr);\r
+ ConfigResp = AllocateZeroPool ((Length + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16));\r
+ if (ConfigResp == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+ StrCpy (ConfigResp, ConfigHdr);\r
+ \r
+ //\r
+ // Append OFFSET/WIDTH pair\r
+ //\r
+ String = ConfigResp + Length;\r
+ Offset = 0;\r
+ AppendOffsetWidthValue (String, Offset, NIC_ITEM_CONFIG_SIZE, NULL);\r
+\r
+ NicInfo = AllocateZeroPool (sizeof (NIC_INFO));\r
+ if (NicInfo == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+ NicInfo->Handle = Handles[Index];\r
+\r
+ //\r
+ // Get network physical devcie MAC information\r
+ //\r
+ IfConfigGetNicMacInfo (Handles[Index], &NicInfo->NicAddress);\r
+ if (NicInfo->NicAddress.Type == NET_IFTYPE_ETHERNET) {\r
+ UnicodeSPrint (NicInfo->Name, IP4_NIC_NAME_LENGTH, L"eth%d", Index);\r
+ } else {\r
+ UnicodeSPrint (NicInfo->Name, IP4_NIC_NAME_LENGTH, L"unk%d", Index);\r
+ }\r
+\r
+ //\r
+ // Get media status\r
+ //\r
+ IfConfigGetNicMediaStatus (Handles[Index], &NicInfo->MediaPresentSupported, &NicInfo->MediaPresent);\r
+\r
+ NicConfigRequest = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE);\r
+ if (NicConfigRequest == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ //\r
+ // Get network parameters by HII service\r
+ //\r
+ Status = mHiiConfigRouting->ExtractConfig (\r
+ mHiiConfigRouting,\r
+ ConfigResp,\r
+ &AccessProgress,\r
+ &AccessResults\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ BufferSize = NIC_ITEM_CONFIG_SIZE;\r
+ Status = mHiiConfigRouting->ConfigToBlock (\r
+ mHiiConfigRouting,\r
+ AccessResults,\r
+ (UINT8 *) NicConfigRequest,\r
+ &BufferSize,\r
+ &AccessProgress\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ BufferSize = sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * NicConfigRequest->Ip4Info.RouteTableSize;\r
+ NicConfig = AllocateZeroPool (BufferSize);\r
+ if (NicConfig == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+ CopyMem (NicConfig, NicConfigRequest, BufferSize);\r
+\r
+ //\r
+ // If succeeds to get NIC configuration, fix up routetable pointer.\r
+ //\r
+ NicConfig->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (&NicConfig->Ip4Info + 1);\r
+ NicInfo->ConfigInfo = NicConfig;\r
+\r
+ } else {\r
+ NicInfo->ConfigInfo = NULL;\r
+ }\r
+\r
+ FreePool (AccessResults);\r
+\r
+ } else {\r
+ NicInfo->ConfigInfo = NULL;\r
+ }\r
+\r
+ //\r
+ // Add the Nic's info to the global NicInfoList.\r
+ //\r
+ InsertTailList (&NicInfoList, &NicInfo->Link);\r
+\r
+ FreePool (NicConfigRequest);\r
+ FreePool (ConfigResp);\r
+ FreePool (ConfigHdr);\r
+ }\r
+\r
+ FreePool (Handles);\r
+\r
+ return EFI_SUCCESS;\r
+ \r
+ON_ERROR:\r
+ if (AccessResults != NULL) {\r
+ FreePool (AccessResults);\r
+ }\r
+ if (NicConfigRequest != NULL) {\r
+ FreePool (NicConfigRequest);\r
+ }\r
+ if (NicInfo != NULL) {\r
+ FreePool (NicInfo);\r
+ }\r
+ if (ConfigResp != NULL) {\r
+ FreePool (ConfigResp);\r
+ }\r
+ if (ConfigHdr != NULL) {\r
+ FreePool (ConfigHdr);\r
+ }\r
+\r
+ FreePool (Handles);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the address for the specified nic by HII service.\r
+\r
+ @param[in] NicInfo A pointer to the NIC_INFO of the Nic to be configured.\r
+ @param[in] Config The command line arguments for the set operation.\r
+\r
+ @retval EFI_SUCCESS The address set operation is done.\r
+**/\r
+SHELL_STATUS\r
+EFIAPI\r
+IfconfigSetNicAddrByHii (\r
+ IN CONST NIC_INFO *NicInfo,\r
+ IN CONST NIC_IP4_CONFIG_INFO *Config\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SHELL_STATUS ShellStatus;\r
+ NIC_IP4_CONFIG_INFO *NicConfig;\r
+ CHAR16 *ConfigResp;\r
+ CHAR16 *ConfigHdr;\r
+ CHAR16 *AccessProgress;\r
+ CHAR16 *AccessResults;\r
+ CHAR16 *String;\r
+ UINTN Length;\r
+ UINTN Offset;\r
+ EFI_HANDLE ChildHandle;\r
+\r
+ AccessResults = NULL;\r
+ ConfigHdr = NULL;\r
+ ConfigResp = NULL;\r
+ NicConfig = NULL;\r
+ ShellStatus = SHELL_SUCCESS;\r
+\r
+ Status = GetChildHandle (NicInfo->Handle, &ChildHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // If failed to get Child handle, try NIC controller handle for back-compatibility\r
+ //\r
+ ChildHandle = NicInfo->Handle;\r
+ }\r
+ //\r
+ // Construct config request string header\r
+ //\r
+ ConfigHdr = ConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, ChildHandle);\r
+\r
+ Length = StrLen (ConfigHdr);\r
+ ConfigResp = AllocateZeroPool ((Length + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16));\r
+ StrCpy (ConfigResp, ConfigHdr);\r
+\r
+ NicConfig = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE);\r
+ if (NicConfig == NULL) {\r
+ ShellStatus = SHELL_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (Config != NULL) {\r
+ CopyMem (NicConfig, Config, sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * Config->Ip4Info.RouteTableSize);\r
+ }\r
+\r
+ //\r
+ // Append OFFSET/WIDTH pair\r
+ //\r
+ String = ConfigResp + Length;\r
+ Offset = 0;\r
+ AppendOffsetWidthValue (String, Offset, NIC_ITEM_CONFIG_SIZE, NULL);\r
+\r
+ //\r
+ // Call HII helper function to generate configuration string\r
+ //\r
+ Status = mHiiConfigRouting->BlockToConfig (\r
+ mHiiConfigRouting,\r
+ ConfigResp,\r
+ (UINT8 *) NicConfig,\r
+ NIC_ITEM_CONFIG_SIZE,\r
+ &AccessResults,\r
+ &AccessProgress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ShellStatus = SHELL_NOT_FOUND;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Set IP setting by HII servie\r
+ //\r
+ Status = mHiiConfigRouting->RouteConfig (\r
+ mHiiConfigRouting,\r
+ AccessResults,\r
+ &AccessProgress\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ ShellStatus = SHELL_ACCESS_DENIED;\r
+ }\r
+\r
+ON_EXIT:\r
+ SHELL_FREE_NON_NULL(AccessResults);\r
+ SHELL_FREE_NON_NULL(NicConfig);\r
+ SHELL_FREE_NON_NULL(ConfigResp);\r
+ SHELL_FREE_NON_NULL(ConfigHdr);\r
+\r
+ return ShellStatus;\r
+}\r
+\r
+/**\r
+ The callback function for the Arp address resolved event.\r
+\r
+ @param[in] Event The event this function is registered to.\r
+ @param[in] Context The context registered to the event.\r
+**/\r
+VOID\r
+EFIAPI\r
+IfconfigOnArpResolved (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ ARP_REQUEST *Request;\r
+ UINT8 Index;\r
+\r
+ Request = (ARP_REQUEST *) Context;\r
+ ASSERT (Request != NULL);\r
+\r
+ Request->Duplicate = FALSE;\r
+ \r
+ if (0 == CompareMem (&Request->LocalMac, &Request->DestMac, Request->MacLen)) {\r
+ ShellPrintHiiEx(\r
+ -1, \r
+ -1, \r
+ NULL,\r
+ STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ L"Already Configured",\r
+ (UINTN)Request->DestIp.v4.Addr[0],\r
+ (UINTN)Request->DestIp.v4.Addr[1],\r
+ (UINTN)Request->DestIp.v4.Addr[2],\r
+ (UINTN)Request->DestIp.v4.Addr[3]\r
+ );\r
+ ArpResolved = TRUE;\r
+ return;\r
+ }\r
+ \r
+ for (Index = 0; Index < Request->MacLen; Index++) {\r
+ if (Request->DestMac.Addr[Index] != 0) {\r
+ Request->Duplicate = TRUE;\r
+ }\r
+ }\r
+\r
+ if (Request->Duplicate) {\r
+ ShellPrintHiiEx(\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN(STR_IFCONFIG_CONF_IP_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ (UINTN)Request->DestMac.Addr[0], \r
+ (UINTN)Request->DestMac.Addr[1], \r
+ (UINTN)Request->DestMac.Addr[2],\r
+ (UINTN)Request->DestMac.Addr[3], \r
+ (UINTN)Request->DestMac.Addr[4], \r
+ (UINTN)Request->DestMac.Addr[5]\r
+ ); \r
+ }\r
+\r
+ ArpResolved = TRUE;\r
+ return ;\r
+}\r
+\r
+/**\r
+ Check whether the address to be configured conflicts with other hosts.\r
+\r
+ @param[in] NicInfo The pointer to the NIC_INFO of the Nic to be configured.\r
+ @param[in] IpAddr The IPv4 address to be configured to the Nic.\r
+\r
+ @return TRUE Some other host already uses the IpAddr.\r
+ @return FALSE The address is unused.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IfconfigIsIpDuplicate (\r
+ IN NIC_INFO *NicInfo,\r
+ IN IP4_ADDR IpAddr\r
+ )\r
+{\r
+ EFI_ARP_PROTOCOL *Arp;\r
+ EFI_ARP_CONFIG_DATA ArpCfgData;\r
+ EFI_HANDLE ArpHandle;\r
+ ARP_REQUEST Request;\r
+ EFI_STATUS Status;\r
+\r
+ Arp = NULL;\r
+ ArpHandle = NULL;\r
+ ZeroMem (&Request, sizeof (ARP_REQUEST));\r
+\r
+ Status = NetLibCreateServiceChild (\r
+ NicInfo->Handle,\r
+ gImageHandle, \r
+ &gEfiArpServiceBindingProtocolGuid,\r
+ &ArpHandle\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ArpHandle,\r
+ &gEfiArpProtocolGuid,\r
+ (VOID**)&Arp,\r
+ gImageHandle,\r
+ ArpHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Set up the Arp requests\r
+ //\r
+ EFI_IP4_TO_U32 (Request.DestIp.v4) = IpAddr;\r
+ EFI_IP4_TO_U32 (Request.LocalIp.v4) = 0xffffffff;\r
+ Request.LocalMac = NicInfo->NicAddress.MacAddr;\r
+ Request.MacLen = NicInfo->NicAddress.Len;\r
+ \r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ IfconfigOnArpResolved,\r
+ (VOID *) &Request,\r
+ &Request.OnResolved\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ \r
+ ArpCfgData.SwAddressType = 0x0800;\r
+ ArpCfgData.SwAddressLength = 4;\r
+ ArpCfgData.StationAddress = &Request.LocalIp;\r
+ ArpCfgData.EntryTimeOut = 0;\r
+ ArpCfgData.RetryCount = 3;\r
+ ArpCfgData.RetryTimeOut = 0;\r
+ \r
+ Status = Arp->Configure (Arp, &ArpCfgData);\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Arp->Request (\r
+ Arp,\r
+ &Request.DestIp,\r
+ Request.OnResolved,\r
+ &Request.DestMac\r
+ );\r
+ \r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ while (!ArpResolved) {\r
+ \r
+ }\r
+\r
+ON_EXIT:\r
+ if (Request.OnResolved != NULL) {\r
+ gBS->CloseEvent (Request.OnResolved);\r
+ }\r
+\r
+ NetLibDestroyServiceChild (\r
+ NicInfo->Handle, \r
+ gImageHandle, \r
+ &gEfiArpServiceBindingProtocolGuid, \r
+ ArpHandle\r
+ );\r
+\r
+ return Request.Duplicate;\r
+}\r
+\r
+/**\r
+ The callback function for the timer event used to get map.\r
+\r
+ @param[in] Event The event this function is registered to.\r
+ @param[in] Context The context registered to the event.\r
+**/\r
+VOID\r
+EFIAPI\r
+TimeoutToGetMap (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ mTimeout = TRUE;\r
+ return ;\r
+}\r
+\r
+/**\r
+ Create an IP child, use it to start the auto configuration, then destory it.\r
+\r
+ @param[in] NicInfo The pointer to the NIC_INFO of the Nic to be configured.\r
+\r
+ @retval EFI_SUCCESS The configuration is done.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IfconfigStartIp4(\r
+ IN NIC_INFO *NicInfo\r
+ )\r
+{\r
+ EFI_IP4_PROTOCOL *Ip4;\r
+ EFI_HANDLE Ip4Handle;\r
+ EFI_HANDLE TimerToGetMap;\r
+ EFI_IP4_CONFIG_DATA Ip4ConfigData;\r
+ EFI_IP4_MODE_DATA Ip4Mode;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get the Ip4ServiceBinding Protocol\r
+ //\r
+ Ip4Handle = NULL;\r
+ Ip4 = NULL;\r
+ TimerToGetMap = NULL;\r
+\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_START_SET_ADDR), gShellNetwork1HiiHandle);\r
+\r
+ Status = NetLibCreateServiceChild (\r
+ NicInfo->Handle,\r
+ gImageHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ &Ip4Handle\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Ip4Handle,\r
+ &gEfiIp4ProtocolGuid,\r
+ (VOID **) &Ip4,\r
+ NicInfo->Handle,\r
+ gImageHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Ip4ConfigData.DefaultProtocol = EFI_IP_PROTO_ICMP;\r
+ Ip4ConfigData.AcceptAnyProtocol = FALSE;\r
+ Ip4ConfigData.AcceptIcmpErrors = FALSE;\r
+ Ip4ConfigData.AcceptBroadcast = FALSE;\r
+ Ip4ConfigData.AcceptPromiscuous = FALSE;\r
+ Ip4ConfigData.UseDefaultAddress = TRUE;\r
+ ZeroMem (&Ip4ConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));\r
+ ZeroMem (&Ip4ConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+ Ip4ConfigData.TypeOfService = 0;\r
+ Ip4ConfigData.TimeToLive = 1;\r
+ Ip4ConfigData.DoNotFragment = FALSE;\r
+ Ip4ConfigData.RawData = FALSE;\r
+ Ip4ConfigData.ReceiveTimeout = 0;\r
+ Ip4ConfigData.TransmitTimeout = 0;\r
+\r
+ Status = Ip4->Configure (Ip4, &Ip4ConfigData);\r
+\r
+ if (Status == EFI_NO_MAPPING) {\r
+ mTimeout = FALSE;\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
+ TPL_CALLBACK - 1,\r
+ TimeoutToGetMap,\r
+ NULL,\r
+ &TimerToGetMap\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ \r
+ Status = gBS->SetTimer (\r
+ TimerToGetMap,\r
+ TimerRelative,\r
+ MultU64x32 (SEC_TO_NS, 5)\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_WAIT_SET_DONE), gShellNetwork1HiiHandle);\r
+ \r
+ while (!mTimeout) {\r
+ Ip4->Poll (Ip4);\r
+ \r
+ if (!EFI_ERROR (Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL)) && \r
+ Ip4Mode.IsConfigured) { \r
+ break;\r
+ }\r
+ } \r
+ }\r
+\r
+ Status = Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL);\r
+\r
+ if ((Status == EFI_SUCCESS) && Ip4Mode.IsConfigured) {\r
+ ShellPrintHiiEx(\r
+ -1, \r
+ -1, \r
+ NULL,\r
+ STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ L"Default",\r
+ (UINTN)Ip4Mode.ConfigData.StationAddress.Addr[0],\r
+ (UINTN)Ip4Mode.ConfigData.StationAddress.Addr[1],\r
+ (UINTN)Ip4Mode.ConfigData.StationAddress.Addr[2],\r
+ (UINTN)Ip4Mode.ConfigData.StationAddress.Addr[3]\r
+ );\r
+ }\r
+ \r
+ON_EXIT: \r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_GET_DEF_ADDR_FAIL), gShellNetwork1HiiHandle);\r
+ }\r
+\r
+ if (TimerToGetMap != NULL) {\r
+ gBS->SetTimer (TimerToGetMap, TimerCancel, 0);\r
+ gBS->CloseEvent (TimerToGetMap);\r
+ }\r
+\r
+ NetLibDestroyServiceChild (\r
+ NicInfo->Handle,\r
+ gImageHandle,\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ Ip4Handle\r
+ );\r
+ \r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the address for the nic specified by the params.\r
+\r
+ @param[in] Argc The count of the passed in Params.\r
+ @param[in] Params The command line arguments for the set operation.\r
+\r
+ @retval EFI_SUCCESS The address set operation is done.\r
+ @return Some error occurs.\r
+**/\r
+SHELL_STATUS\r
+EFIAPI\r
+IfconfigSetNicAddr (\r
+ IN UINTN Argc,\r
+ IN CONST CHAR16 *Params\r
+ )\r
+{\r
+ NIC_IP4_CONFIG_INFO *Config;\r
+ NIC_IP4_CONFIG_INFO *OldConfig;\r
+ EFI_IP_ADDRESS Ip;\r
+ EFI_IP_ADDRESS Mask;\r
+ EFI_IP_ADDRESS Gateway;\r
+ NIC_INFO *Info;\r
+ BOOLEAN Permanent;\r
+ SHELL_STATUS ShellStatus;\r
+ CONST CHAR16 *Walker;\r
+ CHAR16 *Temp;\r
+ CONST CHAR16 *DhcpTemp;\r
+ CONST CHAR16 *StaticTemp;\r
+ CONST CHAR16 *PermTemp;\r
+ UINT32 NetworkBytes1;\r
+ UINT32 NetworkBytes2;\r
+ EFI_STATUS Status;\r
+\r
+ Walker = Params;\r
+ Temp = NULL;\r
+ Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")-Walker);\r
+ Info = IfconfigFindNicByName (Temp);\r
+\r
+ if (Info == NULL) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INTERFACE_NOT_FOUND), gShellNetwork1HiiHandle, Temp);\r
+ return SHELL_NOT_FOUND;\r
+ }\r
+\r
+ Walker += StrLen(Temp) + 1;\r
+ FreePool(Temp);\r
+ Temp = NULL;\r
+ Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")==NULL?0:StrStr(Walker, L" ")-Walker);\r
+\r
+ Config = AllocateZeroPool (sizeof (NIC_IP4_CONFIG_INFO) + 2 * sizeof (EFI_IP4_ROUTE_TABLE));\r
+ if (Config == NULL) {\r
+ return SHELL_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Config->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (Config + 1);\r
+\r
+ OldConfig = Info->ConfigInfo;\r
+ Permanent = FALSE;\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+\r
+ DhcpTemp = DhcpString;\r
+ StaticTemp = StaticString;\r
+ \r
+ if (StringNoCaseCompare(&Temp, &DhcpTemp) == 0) {\r
+ //\r
+ // Validate the parameter for DHCP, two valid forms: eth0 DHCP and eth0 DHCP perment\r
+ //\r
+ if ((Argc != 2) && (Argc!= 3)) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, Temp);\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (Argc == 3) {\r
+ Walker += StrLen(Temp) + 1;\r
+ FreePool(Temp);\r
+ Temp = NULL;\r
+ Temp = StrnCatGrow(&Temp, NULL, Walker, 0);\r
+\r
+ PermTemp = PermanentString;\r
+ if (StringNoCaseCompare(&Temp, &PermTemp) != 0) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_OP2), gShellNetwork1HiiHandle, Temp, PermanentString, L"Nothing");\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Permanent = TRUE;\r
+ }\r
+\r
+ if ((OldConfig != NULL) && (OldConfig->Source == IP4_CONFIG_SOURCE_DHCP) &&\r
+ (OldConfig->Perment == Permanent)) {\r
+\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INTERFACE_CONFIGURED), gShellNetwork1HiiHandle, Info->Name);\r
+ ShellStatus = SHELL_ALREADY_STARTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Config->Source = IP4_CONFIG_SOURCE_DHCP;\r
+ } else if (StringNoCaseCompare(&Temp, &StaticTemp) == 0) {\r
+ //\r
+ // validate the parameter, two forms: eth0 static IP NETMASK GATEWAY and\r
+ // eth0 static IP NETMASK GATEWAY perment\r
+ //\r
+ if ((Argc != 5) && (Argc != 6)) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, Temp);\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Walker += StrLen(Temp) + 1;\r
+ FreePool(Temp);\r
+ Temp = NULL;\r
+ Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")-Walker);\r
+\r
+ if (EFI_ERROR (NetLibStrToIp4 (Temp, &Ip.v4))) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IP_STR), gShellNetwork1HiiHandle, Temp);\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Walker += StrLen(Temp) + 1;\r
+ FreePool(Temp);\r
+ Temp = NULL;\r
+ Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")-Walker);\r
+ if (EFI_ERROR (NetLibStrToIp4 (Temp, &Mask.v4))) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IP_STR), gShellNetwork1HiiHandle, Temp);\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Walker += StrLen(Temp) + 1;\r
+ FreePool(Temp);\r
+ Temp = NULL;\r
+ if (Argc == 6) {\r
+ Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")-Walker);\r
+ } else {\r
+ Temp = StrnCatGrow(&Temp, NULL, Walker, 0);\r
+ }\r
+ if (EFI_ERROR (NetLibStrToIp4 (Temp, &Gateway.v4))) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IP_STR), gShellNetwork1HiiHandle, Temp);\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (Argc == 6) {\r
+ Walker += StrLen(Temp) + 1;\r
+ FreePool(Temp);\r
+ Temp = NULL;\r
+ Temp = StrnCatGrow(&Temp, NULL, Walker, 0);\r
+\r
+ PermTemp = PermanentString;\r
+ if (StringNoCaseCompare(&Temp, &PermTemp) != 0) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_OP2), gShellNetwork1HiiHandle, Temp, PermanentString, L"Nothing");\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Permanent = TRUE;\r
+ }\r
+\r
+ NetworkBytes1 = NTOHL (Ip.Addr[0]);\r
+ NetworkBytes2 = NTOHL (Mask.Addr[0]);\r
+ if ((Ip.Addr[0] == 0) || (Mask.Addr[0] == 0) ||\r
+ !NetIp4IsUnicast (NetworkBytes1, NetworkBytes2)) {\r
+\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_ADDR_PAIR), gShellNetwork1HiiHandle);\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ NetworkBytes1 = NTOHL (Gateway.Addr[0]);\r
+ if (!IP4_NET_EQUAL (Ip.Addr[0], Gateway.Addr[0], Mask.Addr[0]) ||\r
+ !NetIp4IsUnicast (NetworkBytes1, NetworkBytes2)) {\r
+ \r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_GATEWAY), gShellNetwork1HiiHandle);\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Set the configuration up, two route table entries are added:\r
+ // one for the direct connected network, and another for the \r
+ // default gateway. Remember, some structure members are cleared\r
+ // by AllocateZeroPool\r
+ //\r
+ Config->Source = IP4_CONFIG_SOURCE_STATIC;\r
+ Config->Ip4Info.RouteTableSize = 2;\r
+\r
+ CopyMem (&Config->Ip4Info.StationAddress, &Ip.v4, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&Config->Ip4Info.SubnetMask, &Mask.v4, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Ip.Addr[0] = Ip.Addr[0] & Mask.Addr[0];\r
+\r
+ CopyMem (&Config->Ip4Info.RouteTable[0].SubnetAddress, &Ip.v4, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&Config->Ip4Info.RouteTable[0].SubnetMask, &Mask.v4, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&Config->Ip4Info.RouteTable[1].GatewayAddress, &Gateway.v4, sizeof (EFI_IPv4_ADDRESS));\r
+ } else {\r
+ // neither static or DHCP. error.\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle);\r
+ ASSERT(ShellStatus == SHELL_INVALID_PARAMETER);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ CopyMem (&Config->NicAddr, &Info->NicAddress, sizeof (NIC_ADDR));\r
+ Config->Perment = Permanent;\r
+\r
+ //\r
+ // Use HII service to set NIC address\r
+ //\r
+ ShellStatus = IfconfigSetNicAddrByHii (Info, Config);\r
+ if (ShellStatus != SHELL_SUCCESS) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_SET_FAIL), gShellNetwork1HiiHandle, ShellStatus^MAX_BIT);\r
+ goto ON_EXIT;\r
+ } \r
+\r
+ Status = IfconfigStartIp4 (Info);\r
+ if (EFI_ERROR(Status)) {\r
+ ShellStatus = SHELL_ACCESS_DENIED;\r
+ }\r
+\r
+ if (ShellStatus != SHELL_SUCCESS) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_IP_CHILD_FAIL), gShellNetwork1HiiHandle, ShellStatus^MAX_BIT);\r
+ }\r
+ \r
+ON_EXIT:\r
+ SHELL_FREE_NON_NULL(Config);\r
+ \r
+ return ShellStatus;\r
+}\r
+\r
+/**\r
+ Show the address information for the nic specified.\r
+\r
+ @param[in] Name A pointer to the string containg the nic's name, if NULL, \r
+ all nics' information is shown.\r
+**/\r
+VOID\r
+EFIAPI\r
+IfconfigShowNicInfo (\r
+ IN CONST CHAR16 *Name\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+ NIC_INFO *NicInfo;\r
+ UINT32 Index;\r
+ EFI_IP4_IPCONFIG_DATA *Ip4Config;\r
+ EFI_IPv4_ADDRESS Gateway;\r
+ CONST CHAR16 *TempString;\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &NicInfoList) {\r
+ NicInfo = BASE_CR (Entry, NIC_INFO, Link);\r
+\r
+ TempString = (CHAR16*)NicInfo->Name;\r
+ if ((Name != NULL) && (StringNoCaseCompare (&Name, &TempString) != 0)) {\r
+ continue;\r
+ }\r
+\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_NIC_NAME), gShellNetwork1HiiHandle, NicInfo->Name);\r
+\r
+ ShellPrintHiiEx(\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN(STR_IFCONFIG_SHOW_MAC_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ (UINTN)NicInfo->NicAddress.MacAddr.Addr[0], \r
+ (UINTN)NicInfo->NicAddress.MacAddr.Addr[1], \r
+ (UINTN)NicInfo->NicAddress.MacAddr.Addr[2],\r
+ (UINTN)NicInfo->NicAddress.MacAddr.Addr[3], \r
+ (UINTN)NicInfo->NicAddress.MacAddr.Addr[4], \r
+ (UINTN)NicInfo->NicAddress.MacAddr.Addr[5]\r
+ ); \r
+\r
+ Print (L" Media State: %s\n", NicInfo->MediaPresent ? L"Media present" : L"Media disconnected");\r
+\r
+ if (NicInfo->ConfigInfo == NULL) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_NIC_NOT_CONFIGURED), gShellNetwork1HiiHandle);\r
+ continue;\r
+ } \r
+\r
+ if (NicInfo->ConfigInfo->Source == IP4_CONFIG_SOURCE_DHCP) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_CONFIG_SOURCE), gShellNetwork1HiiHandle, L"DHCP");\r
+ } else if (NicInfo->ConfigInfo->Source == IP4_CONFIG_SOURCE_STATIC) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_CONFIG_SOURCE), gShellNetwork1HiiHandle, L"STATIC");\r
+ } else {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_CONFIG_SOURCE), gShellNetwork1HiiHandle, L"Unknown");\r
+ }\r
+\r
+ ShellPrintHiiEx(-1, -1, NULL,\r
+ STRING_TOKEN (STR_IFCONFIG_PERMENT_STATUS),\r
+ gShellNetwork1HiiHandle,\r
+ (NicInfo->ConfigInfo->Perment? L"TRUE":L"FALSE")\r
+ );\r
+\r
+ Ip4Config = &NicInfo->ConfigInfo->Ip4Info;\r
+\r
+ ShellPrintHiiEx(\r
+ -1, \r
+ -1, \r
+ NULL,\r
+ STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ L"IP address",\r
+ (UINTN)Ip4Config->StationAddress.Addr[0],\r
+ (UINTN)Ip4Config->StationAddress.Addr[1],\r
+ (UINTN)Ip4Config->StationAddress.Addr[2],\r
+ (UINTN)Ip4Config->StationAddress.Addr[3]\r
+ );\r
+ ShellPrintHiiEx(\r
+ -1, \r
+ -1, \r
+ NULL,\r
+ STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ L"Mask",\r
+ (UINTN)Ip4Config->SubnetMask.Addr[0],\r
+ (UINTN)Ip4Config->SubnetMask.Addr[1],\r
+ (UINTN)Ip4Config->SubnetMask.Addr[2],\r
+ (UINTN)Ip4Config->SubnetMask.Addr[3]\r
+ );\r
+\r
+ ZeroMem (&Gateway, sizeof (EFI_IPv4_ADDRESS));\r
+ \r
+ for (Index = 0; Index < Ip4Config->RouteTableSize; Index++) {\r
+ if ((CompareMem (&Ip4Config->RouteTable[Index].SubnetAddress, &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0) &&\r
+ (CompareMem (&Ip4Config->RouteTable[Index].SubnetMask , &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0) ){\r
+ CopyMem (&Gateway, &Ip4Config->RouteTable[Index].GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
+ }\r
+ }\r
+ \r
+ ShellPrintHiiEx(\r
+ -1, \r
+ -1, \r
+ NULL,\r
+ STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ L"Gateway",\r
+ (UINTN)Gateway.Addr[0],\r
+ (UINTN)Gateway.Addr[1],\r
+ (UINTN)Gateway.Addr[2],\r
+ (UINTN)Gateway.Addr[3]\r
+ );\r
+\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_ROUTES_SIZE), gShellNetwork1HiiHandle, Ip4Config->RouteTableSize);\r
+\r
+ for (Index = 0; Index < Ip4Config->RouteTableSize; Index++) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_ROUTES_ENTRY_INDEX), gShellNetwork1HiiHandle, Index);\r
+\r
+ ShellPrintHiiEx(\r
+ -1, \r
+ -1, \r
+ NULL,\r
+ STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ L"Subnet",\r
+ (UINTN)Ip4Config->RouteTable[Index].SubnetAddress.Addr[0],\r
+ (UINTN)Ip4Config->RouteTable[Index].SubnetAddress.Addr[1],\r
+ (UINTN)Ip4Config->RouteTable[Index].SubnetAddress.Addr[2],\r
+ (UINTN)Ip4Config->RouteTable[Index].SubnetAddress.Addr[3]\r
+ );\r
+\r
+ ShellPrintHiiEx(\r
+ -1, \r
+ -1, \r
+ NULL,\r
+ STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ L"Netmask",\r
+ (UINTN)Ip4Config->RouteTable[Index].SubnetMask.Addr[0],\r
+ (UINTN)Ip4Config->RouteTable[Index].SubnetMask.Addr[1],\r
+ (UINTN)Ip4Config->RouteTable[Index].SubnetMask.Addr[2],\r
+ (UINTN)Ip4Config->RouteTable[Index].SubnetMask.Addr[3]\r
+ );\r
+\r
+ ShellPrintHiiEx(\r
+ -1, \r
+ -1, \r
+ NULL,\r
+ STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), \r
+ gShellNetwork1HiiHandle, \r
+ L"Gateway",\r
+ (UINTN)Ip4Config->RouteTable[Index].GatewayAddress.Addr[0],\r
+ (UINTN)Ip4Config->RouteTable[Index].GatewayAddress.Addr[1],\r
+ (UINTN)Ip4Config->RouteTable[Index].GatewayAddress.Addr[2],\r
+ (UINTN)Ip4Config->RouteTable[Index].GatewayAddress.Addr[3]\r
+ );\r
+ }\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Clear address configuration for the nic specified.\r
+\r
+ @param[in] Name A pointer to the string containg the nic's name, \r
+ if NULL, all nics address configurations are cleared.\r
+\r
+ @retval EFI_SUCCESS The address configuration is cleared.\r
+ @return Some error occurs.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IfconfigClearNicAddr (\r
+ IN CONST CHAR16 *Name\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+ NIC_INFO *Info;\r
+ EFI_STATUS Status;\r
+ \r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &NicInfoList) {\r
+ Info = BASE_CR (Entry, NIC_INFO, Link);\r
+\r
+ if ((Name != NULL) && (StrCmp (Name, Info->Name) != 0)) {\r
+ continue;\r
+ }\r
+\r
+// if (Info->NicIp4Config == NULL) { \r
+ Status = IfconfigSetNicAddrByHii (Info, NULL);\r
+// } else {\r
+// Status = Info->NicIp4Config->SetInfo (Info->NicIp4Config, NULL, TRUE);\r
+// }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ \r
+}\r
+\r
+/**\r
+ Function for 'ifconfig' command.\r
+\r
+ @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
+ @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
+**/\r
+SHELL_STATUS\r
+EFIAPI\r
+ShellCommandRunIfconfig (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Package;\r
+ CHAR16 *ProblemParam;\r
+ SHELL_STATUS ShellStatus;\r
+ BOOLEAN ListOperation;\r
+ BOOLEAN ClearOperation;\r
+ BOOLEAN SetOperation;\r
+ CONST CHAR16 *Item;\r
+ LIST_ENTRY *Entry;\r
+ NIC_INFO *Info;\r
+\r
+ InitializeListHead (&NicInfoList);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ ShellStatus = SHELL_SUCCESS;\r
+\r
+ //\r
+ // initialize the shell lib (we must be in non-auto-init...)\r
+ //\r
+ Status = ShellInitialize();\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ //\r
+ // parse the command line\r
+ //\r
+ Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
+ if (EFI_ERROR(Status)) {\r
+ if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ProblemParam);\r
+ FreePool(ProblemParam);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ } else {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ goto Done;\r
+ }\r
+\r
+ ClearOperation = ShellCommandLineGetFlag(Package, L"-c");\r
+ ListOperation = ShellCommandLineGetFlag(Package, L"-l");\r
+ SetOperation = ShellCommandLineGetFlag(Package, L"-s");\r
+\r
+ if (ClearOperation && ListOperation \r
+ ||SetOperation && ListOperation \r
+ ||ClearOperation && SetOperation \r
+ ) {\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellNetwork1HiiHandle);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto Done;\r
+ } else if (!ClearOperation && !ListOperation && !SetOperation) {\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+ \r
+ \r
+ Status = IfconfigGetAllNicInfoByHii ();\r
+ if (EFI_ERROR (Status)) {\r
+ if (mIp4ConfigExist) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_GET_NIC_FAIL), gShellNetwork1HiiHandle, Status);\r
+ } else {\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROTOCOL_NF), gShellNetwork1HiiHandle, L"gEfiIp4ConfigProtocolGuid", &gEfiIp4ConfigProtocolGuid);\r
+ }\r
+\r
+ return SHELL_NOT_FOUND;\r
+ }\r
+\r
+ if (ListOperation) {\r
+ Item = ShellCommandLineGetValue (Package, L"-l");\r
+\r
+ if (Item != NULL && CountSubItems(Item) > 1) {\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, L"-l");\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto Done;\r
+ } \r
+ \r
+ //\r
+ // Show the configuration.\r
+ //\r
+ IfconfigShowNicInfo (Item);\r
+ } else if (SetOperation) {\r
+ Item = ShellCommandLineGetValue (Package, L"-s");\r
+\r
+ //\r
+ // The correct command line arguments for setting address are:\r
+ // IfConfig -s eth0 DHCP [perment]\r
+ // IfConfig -s eth0 static ip netmask gateway [perment]\r
+ //\r
+ if (Item == NULL || (CountSubItems(Item) < 2) || (CountSubItems(Item) > 6) || (CountSubItems(Item) == 4)) {\r
+ ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, L"-s");\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ ShellStatus = IfconfigSetNicAddr (CountSubItems(Item), Item);\r
+ } else if (ClearOperation) {\r
+ Item = ShellCommandLineGetValue (Package, L"-c");\r
+\r
+ if (Item != NULL && CountSubItems(Item) > 1) {\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, L"-c");\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ IfconfigClearNicAddr (Item);\r
+ } else {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+Done:\r
+ while (!IsListEmpty (&NicInfoList)) {\r
+ Entry = NicInfoList.ForwardLink;\r
+ Info = BASE_CR (Entry, NIC_INFO, Link);\r
+\r
+ RemoveEntryList (Entry);\r
+\r
+ if (Info->ConfigInfo != NULL) {\r
+ FreePool (Info->ConfigInfo);\r
+ }\r
+\r
+ FreePool (Info);\r
+ }\r
+\r
+ if (Package != NULL) {\r
+ ShellCommandLineFreeVarList(Package);\r
+ }\r
+\r
+ return (ShellStatus);\r
+}\r
--- /dev/null
+/** @file\r
+ The implementation for Ping shell command.\r
+\r
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UefiShellNetwork1CommandsLib.h"\r
+\r
+#define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))\r
+\r
+\r
+//\r
+// Function templates to match the IPv4 and IPv6 commands that we use.\r
+//\r
+typedef \r
+EFI_STATUS\r
+(EFIAPI *PING_IPX_POLL)(\r
+ IN VOID *This\r
+ ); \r
+\r
+typedef \r
+EFI_STATUS\r
+(EFIAPI *PING_IPX_TRANSMIT)(\r
+ IN VOID *This,\r
+ IN VOID *Token\r
+ );\r
+\r
+typedef \r
+EFI_STATUS\r
+(EFIAPI *PING_IPX_RECEIVE)(\r
+ IN VOID *This,\r
+ IN VOID *Token\r
+ ); \r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PING_IPX_CANCEL)(\r
+ IN VOID *This,\r
+ IN VOID *Token OPTIONAL\r
+ );\r
+\r
+///\r
+/// A set of pointers to either IPv6 or IPv4 functions. \r
+/// Unknown which one to the ping command.\r
+///\r
+typedef struct {\r
+ PING_IPX_TRANSMIT Transmit;\r
+ PING_IPX_RECEIVE Receive;\r
+ PING_IPX_CANCEL Cancel;\r
+ PING_IPX_POLL Poll;\r
+}PING_IPX_PROTOCOL;\r
+\r
+\r
+typedef union {\r
+ VOID *RxData;\r
+ VOID *TxData;\r
+} PING_PACKET;\r
+\r
+//\r
+// PING_IPX_COMPLETION_TOKEN\r
+// structures are used for both transmit and receive operations. \r
+// This version is IP-unaware.\r
+//\r
+typedef struct {\r
+ EFI_EVENT Event;\r
+ EFI_STATUS Status;\r
+ PING_PACKET Packet;\r
+} PING_IPX_COMPLETION_TOKEN;\r
+\r
+#pragma pack(1)\r
+typedef struct _ICMPX_ECHO_REQUEST_REPLY {\r
+ UINT8 Type;\r
+ UINT8 Code;\r
+ UINT16 Checksum;\r
+ UINT16 Identifier;\r
+ UINT16 SequenceNum;\r
+ UINT64 TimeStamp;\r
+ UINT8 Data[1];\r
+} ICMPX_ECHO_REQUEST_REPLY;\r
+#pragma pack()\r
+\r
+typedef struct _PING_ICMP_TX_INFO {\r
+ LIST_ENTRY Link;\r
+ UINT16 SequenceNum;\r
+ UINT64 TimeStamp;\r
+ PING_IPX_COMPLETION_TOKEN *Token;\r
+} PING_ICMPX_TX_INFO;\r
+\r
+#define DEFAULT_TIMEOUT 5000\r
+#define MAX_SEND_NUMBER 10000\r
+#define MAX_BUFFER_SIZE 32768\r
+#define DEFAULT_TIMER_PERIOD 358049\r
+#define ONE_SECOND 10000000\r
+#define PING_IP_CHOICE_IP4 1\r
+#define PING_IP_CHOICE_IP6 2\r
+#define DEFAULT_SEND_COUNT 10\r
+#define DEFAULT_BUFFER_SIZE 16\r
+#define ICMP_V4_ECHO_REQUEST 0x8\r
+#define ICMP_V4_ECHO_REPLY 0x0\r
+\r
+#define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')\r
+typedef struct _PING_PRIVATE_DATA {\r
+ UINT32 Signature;\r
+ EFI_HANDLE NicHandle;\r
+ EFI_HANDLE IpChildHandle;\r
+ EFI_EVENT Timer;\r
+\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY TxList;\r
+ UINT16 RxCount;\r
+ UINT16 TxCount;\r
+ UINT64 RttSum;\r
+ UINT64 RttMin;\r
+ UINT64 RttMax;\r
+ UINT32 SequenceNum;\r
+\r
+ UINT32 SendNum;\r
+ UINT32 BufferSize;\r
+ UINT32 IpChoice;\r
+\r
+ PING_IPX_PROTOCOL ProtocolPointers;\r
+ VOID *IpProtocol;\r
+ UINT8 SrcAddress[MAX(sizeof(EFI_IPv6_ADDRESS) , sizeof(EFI_IPv4_ADDRESS) )];\r
+ UINT8 DstAddress[MAX(sizeof(EFI_IPv6_ADDRESS) , sizeof(EFI_IPv4_ADDRESS) )];\r
+ PING_IPX_COMPLETION_TOKEN RxToken;\r
+} PING_PRIVATE_DATA;\r
+\r
+UINT16\r
+EFIAPI\r
+NetChecksum (\r
+ IN UINT8 *Buffer,\r
+ IN UINT32 Length\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Calculate the internet checksum (see RFC 1071)\r
+\r
+Arguments:\r
+\r
+ Packet - Buffer which contains the data to be checksummed\r
+ Length - Length to be checksummed\r
+\r
+Returns:\r
+\r
+ Checksum - Returns the 16 bit ones complement of \r
+ ones complement sum of 16 bit words\r
+\r
+--*/\r
+{\r
+ UINT32 Sum;\r
+ UINT8 Odd;\r
+ UINT16 *Packet;\r
+\r
+ Packet = (UINT16 *) Buffer;\r
+\r
+ Sum = 0;\r
+ Odd = (UINT8) (Length & 1);\r
+ Length >>= 1;\r
+ while (Length--) {\r
+ Sum += *Packet++;\r
+ }\r
+\r
+ if (Odd) {\r
+ Sum += *(UINT8 *) Packet;\r
+ }\r
+\r
+ Sum = (Sum & 0xffff) + (Sum >> 16);\r
+\r
+ //\r
+ // in case above carried\r
+ //\r
+ Sum += Sum >> 16;\r
+\r
+ return (UINT16) Sum;\r
+}\r
+\r
+/**\r
+ Reads and returns the current value of register.\r
+ In IA64, the register is the Interval Timer Vector (ITV).\r
+ In X86(IA32/X64), the register is the Time Stamp Counter (TSC)\r
+\r
+ @return The current value of the register.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+ReadTime (\r
+ VOID\r
+ );\r
+\r
+STATIC CONST SHELL_PARAM_ITEM PingParamList[] = {\r
+ {\r
+ L"-l",\r
+ TypeValue\r
+ },\r
+ {\r
+ L"-n",\r
+ TypeValue\r
+ },\r
+ {\r
+ L"-_s",\r
+ TypeValue\r
+ },\r
+ {\r
+ L"-_ip6",\r
+ TypeFlag\r
+ },\r
+ {\r
+ NULL,\r
+ TypeMax\r
+ },\r
+};\r
+\r
+//\r
+// Global Variables in Ping command.\r
+//\r
+STATIC CONST CHAR16 *mDstString;\r
+STATIC CONST CHAR16 *mSrcString;\r
+STATIC UINT64 mFrequency = 0;\r
+\r
+/**\r
+ Get and caculate the frequency in tick/ms.\r
+ The result is saved in the globle variable mFrequency\r
+\r
+ @retval EFI_SUCCESS Caculated the frequency successfully.\r
+ @retval Others Failed to caculate the frequency.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetFrequency (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_CPU_ARCH_PROTOCOL *Cpu;\r
+ UINT64 CurrentTick;\r
+ UINT64 TimerPeriod;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ TimerPeriod = DEFAULT_TIMER_PERIOD;\r
+ }\r
+\r
+ //\r
+ // The timer period is in femtosecond (1 femtosecond is 1e-15 second).\r
+ // So 1e+12 is divided by timer period to produce the freq in tick/ms.\r
+ //\r
+ mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Caculate a duration in ms.\r
+\r
+ @param[in] Begin The start point of time.\r
+ @param[in] End The end point of time.\r
+\r
+ @return The duration in ms.\r
+ @retval 0 The parameters were not valid.\r
+**/\r
+UINT64\r
+EFIAPI\r
+CalculateTick (\r
+ IN UINT64 Begin,\r
+ IN UINT64 End\r
+ )\r
+{\r
+ if (End <= Begin) {\r
+ return (0);\r
+ }\r
+ return DivU64x64Remainder (End - Begin, mFrequency, NULL);\r
+}\r
+\r
+/**\r
+ Destroy PING_ICMPX_TX_INFO, and recollect the memory.\r
+\r
+ @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.\r
+ @param[in] IpChoice Whether the token is IPv4 or IPv6\r
+**/\r
+VOID\r
+EFIAPI\r
+PingDestroyTxInfo (\r
+ IN PING_ICMPX_TX_INFO *TxInfo,\r
+ IN UINT32 IpChoice\r
+ )\r
+{\r
+ EFI_IP6_TRANSMIT_DATA *Ip6TxData;\r
+ EFI_IP4_TRANSMIT_DATA *Ip4TxData;\r
+ EFI_IP6_FRAGMENT_DATA *FragData;\r
+ UINTN Index;\r
+\r
+ if (TxInfo == NULL) {\r
+ return;\r
+ }\r
+\r
+ if (TxInfo->Token != NULL) {\r
+\r
+ if (TxInfo->Token->Event != NULL) {\r
+ gBS->CloseEvent (TxInfo->Token->Event);\r
+ }\r
+\r
+ if (TxInfo->Token->Packet.TxData != NULL) {\r
+ if (IpChoice == PING_IP_CHOICE_IP6) {\r
+ Ip6TxData = TxInfo->Token->Packet.TxData;\r
+\r
+ if (Ip6TxData->OverrideData != NULL) {\r
+ FreePool (Ip6TxData->OverrideData);\r
+ }\r
+\r
+ if (Ip6TxData->ExtHdrs != NULL) {\r
+ FreePool (Ip6TxData->ExtHdrs);\r
+ }\r
+\r
+ for (Index = 0; Index < Ip6TxData->FragmentCount; Index++) {\r
+ FragData = Ip6TxData->FragmentTable[Index].FragmentBuffer;\r
+ if (FragData != NULL) {\r
+ FreePool (FragData);\r
+ }\r
+ }\r
+ } else {\r
+ Ip4TxData = TxInfo->Token->Packet.TxData;\r
+\r
+ if (Ip4TxData->OverrideData != NULL) {\r
+ FreePool (Ip4TxData->OverrideData);\r
+ }\r
+\r
+ for (Index = 0; Index < Ip4TxData->FragmentCount; Index++) {\r
+ FragData = Ip4TxData->FragmentTable[Index].FragmentBuffer;\r
+ if (FragData != NULL) {\r
+ FreePool (FragData);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (TxInfo->Token);\r
+ }\r
+\r
+ FreePool (TxInfo);\r
+}\r
+\r
+/**\r
+ Match the request, and reply with SequenceNum/TimeStamp.\r
+\r
+ @param[in] Private The pointer to PING_PRIVATE_DATA.\r
+ @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.\r
+\r
+ @retval EFI_SUCCESS The match is successful.\r
+ @retval EFI_NOT_FOUND The reply can't be matched with any request.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Ping6MatchEchoReply (\r
+ IN PING_PRIVATE_DATA *Private,\r
+ IN ICMPX_ECHO_REQUEST_REPLY *Packet\r
+ )\r
+{\r
+ PING_ICMPX_TX_INFO *TxInfo;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
+ TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
+\r
+ if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) {\r
+ Private->RxCount++;\r
+ RemoveEntryList (&TxInfo->Link);\r
+ PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ The original intention is to send a request.\r
+ Currently, the application retransmits an icmp6 echo request packet\r
+ per second in sendnumber times that is specified by the user.\r
+ Because nothing can be done here, all things move to the timer rountine.\r
+\r
+ @param[in] Event A EFI_EVENT type event.\r
+ @param[in] Context The pointer to Context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ping6OnEchoRequestSent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ receive reply, match and print reply infomation.\r
+\r
+ @param[in] Event A EFI_EVENT type event.\r
+ @param[in] Context The pointer to context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ping6OnEchoReplyReceived (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PING_PRIVATE_DATA *Private;\r
+ ICMPX_ECHO_REQUEST_REPLY *Reply;\r
+ UINT32 PayLoad;\r
+ UINT64 Rtt;\r
+ CHAR8 Near;\r
+\r
+ Private = (PING_PRIVATE_DATA *) Context;\r
+\r
+ if (Private == NULL || Private->Status == EFI_ABORTED || Private->Signature != PING_PRIVATE_DATA_SIGNATURE) {\r
+ return;\r
+ }\r
+\r
+ if (Private->RxToken.Packet.RxData == NULL) {\r
+ return;\r
+ }\r
+\r
+ if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
+ Reply = ((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer;\r
+ PayLoad = ((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->DataLength;\r
+ if (((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->NextHeader != IP6_ICMP) {\r
+ goto ON_EXIT;\r
+ }\r
+ if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS*)&Private->DstAddress) && \r
+ !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv6_ADDRESS*)&Private->DstAddress)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) {\r
+ goto ON_EXIT;\r
+ }\r
+ } else {\r
+ Reply = ((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer;\r
+ PayLoad = ((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->DataLength;\r
+ if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS*)Private->DstAddress)) && \r
+ !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv4_ADDRESS*)&Private->DstAddress)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if ((Reply->Type != ICMP_V4_ECHO_REPLY) || (Reply->Code != 0)) {\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+ \r
+\r
+ if (PayLoad != Private->BufferSize) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Check whether the reply matches the sent request before.\r
+ //\r
+ Status = Ping6MatchEchoReply (Private, Reply);\r
+ if (EFI_ERROR(Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Display statistics on this icmp6 echo reply packet.\r
+ //\r
+ Rtt = CalculateTick (Reply->TimeStamp, ReadTime ());\r
+ if (Rtt != 0) {\r
+ Near = (CHAR8) '=';\r
+ } else {\r
+ Near = (CHAR8) '<';\r
+ }\r
+\r
+ Private->RttSum += Rtt;\r
+ Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;\r
+ Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax;\r
+\r
+ ShellPrintHiiEx (\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN (STR_PING_REPLY_INFO),\r
+ gShellNetwork1HiiHandle,\r
+ PayLoad,\r
+ mDstString,\r
+ Reply->SequenceNum,\r
+ Private->IpChoice == PING_IP_CHOICE_IP6?((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->HopLimit:0,\r
+ Near,\r
+ Rtt\r
+ );\r
+\r
+ON_EXIT:\r
+\r
+ if (Private->RxCount < Private->SendNum) {\r
+ //\r
+ // Continue to receive icmp echo reply packets.\r
+ //\r
+ Private->RxToken.Status = EFI_ABORTED;\r
+\r
+ Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Private->Status = EFI_ABORTED;\r
+ }\r
+ } else {\r
+ //\r
+ // All reply have already been received from the dest host.\r
+ //\r
+ Private->Status = EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Singal to recycle the each rxdata here, not at the end of process.\r
+ //\r
+ gBS->SignalEvent (Private->IpChoice == PING_IP_CHOICE_IP6?((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->RecycleSignal:((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->RecycleSignal);\r
+}\r
+\r
+/**\r
+ Create a PING_IPX_COMPLETION_TOKEN.\r
+\r
+ @param[in] Private The pointer of PING_PRIVATE_DATA.\r
+ @param[in] TimeStamp The TimeStamp of request.\r
+ @param[in] SequenceNum The SequenceNum of request.\r
+\r
+ @return The pointer of PING_IPX_COMPLETION_TOKEN.\r
+\r
+**/\r
+PING_IPX_COMPLETION_TOKEN *\r
+EFIAPI\r
+PingGenerateToken (\r
+ IN PING_PRIVATE_DATA *Private,\r
+ IN UINT64 TimeStamp,\r
+ IN UINT16 SequenceNum\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PING_IPX_COMPLETION_TOKEN *Token;\r
+ VOID *TxData;\r
+ ICMPX_ECHO_REQUEST_REPLY *Request;\r
+ UINT16 HeadSum;\r
+ UINT16 TempChecksum;\r
+\r
+ Request = AllocateZeroPool (Private->BufferSize);\r
+ if (Request == NULL) {\r
+ return NULL;\r
+ }\r
+ TxData = AllocateZeroPool (Private->IpChoice==PING_IP_CHOICE_IP6?sizeof (EFI_IP6_TRANSMIT_DATA):sizeof (EFI_IP4_TRANSMIT_DATA));\r
+ if (TxData == NULL) {\r
+ FreePool (Request);\r
+ return NULL;\r
+ }\r
+ Token = AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN));\r
+ if (Token == NULL) {\r
+ FreePool (Request);\r
+ FreePool (TxData);\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Assembly echo request packet.\r
+ //\r
+ Request->Type = (UINT8)(Private->IpChoice==PING_IP_CHOICE_IP6?ICMP_V6_ECHO_REQUEST:ICMP_V4_ECHO_REQUEST);\r
+ Request->Code = 0;\r
+ Request->SequenceNum = SequenceNum;\r
+ Request->Identifier = 0;\r
+ Request->Checksum = 0;\r
+\r
+ //\r
+ // Assembly token for transmit.\r
+ //\r
+ if (Private->IpChoice==PING_IP_CHOICE_IP6) {\r
+ ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrsLength = 0;\r
+ ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrs = NULL;\r
+ ((EFI_IP6_TRANSMIT_DATA*)TxData)->OverrideData = 0;\r
+ ((EFI_IP6_TRANSMIT_DATA*)TxData)->DataLength = Private->BufferSize;\r
+ ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentCount = 1;\r
+ ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentBuffer = (VOID *) Request;\r
+ ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize;\r
+ } else {\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->OptionsLength = 0;\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->OptionsBuffer = NULL;\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->OverrideData = 0;\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->TotalDataLength = Private->BufferSize;\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentCount = 1;\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentBuffer = (VOID *) Request;\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize;\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[0] = Private->DstAddress[0];\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[1] = Private->DstAddress[1];\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[2] = Private->DstAddress[2];\r
+ ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[3] = Private->DstAddress[3];\r
+\r
+ HeadSum = NetChecksum ((UINT8 *) Request, Private->BufferSize);\r
+ Request->TimeStamp = TimeStamp;\r
+ TempChecksum = NetChecksum ((UINT8 *) &Request->TimeStamp, sizeof (UINT64));\r
+ Request->Checksum = (UINT16)(~NetAddChecksum (HeadSum, TempChecksum));\r
+ }\r
+\r
+\r
+ Token->Status = EFI_ABORTED;\r
+ Token->Packet.TxData = TxData;\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ Ping6OnEchoRequestSent,\r
+ Private,\r
+ &Token->Event\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Request);\r
+ FreePool (TxData);\r
+ FreePool (Token);\r
+ return NULL;\r
+ }\r
+\r
+ return Token;\r
+}\r
+\r
+/**\r
+ Transmit the PING_IPX_COMPLETION_TOKEN.\r
+\r
+ @param[in] Private The pointer of PING_PRIVATE_DATA.\r
+\r
+ @retval EFI_SUCCESS Transmitted successfully.\r
+ @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
+ @retval others Transmitted unsuccessfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PingSendEchoRequest (\r
+ IN PING_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PING_ICMPX_TX_INFO *TxInfo;\r
+\r
+ TxInfo = AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO));\r
+\r
+ if (TxInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ TxInfo->TimeStamp = ReadTime ();\r
+ TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);\r
+ TxInfo->Token = PingGenerateToken (\r
+ Private,\r
+ TxInfo->TimeStamp,\r
+ TxInfo->SequenceNum\r
+ );\r
+\r
+ if (TxInfo->Token == NULL) {\r
+ PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ASSERT(Private->ProtocolPointers.Transmit != NULL);\r
+ Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
+ return Status;\r
+ }\r
+\r
+ InsertTailList (&Private->TxList, &TxInfo->Link);\r
+ Private->TxCount++;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Place a completion token into the receive packet queue to receive the echo reply.\r
+\r
+ @param[in] Private The pointer of PING_PRIVATE_DATA.\r
+\r
+ @retval EFI_SUCCESS Put the token into the receive packet queue successfully.\r
+ @retval others Put the token into the receive packet queue unsuccessfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Ping6ReceiveEchoReply (\r
+ IN PING_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&Private->RxToken, sizeof (PING_IPX_COMPLETION_TOKEN));\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ Ping6OnEchoReplyReceived,\r
+ Private,\r
+ &Private->RxToken.Event\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Private->RxToken.Status = EFI_NOT_READY;\r
+\r
+ return (Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken));\r
+}\r
+\r
+/**\r
+ Remove the timeout request from the list.\r
+\r
+ @param[in] Event A EFI_EVENT type event.\r
+ @param[in] Context The pointer to Context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ping6OnTimerRoutine (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PING_PRIVATE_DATA *Private;\r
+ PING_ICMPX_TX_INFO *TxInfo;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+ UINT64 Time;\r
+\r
+ Private = (PING_PRIVATE_DATA *) Context;\r
+ if (Private->Signature != PING_PRIVATE_DATA_SIGNATURE) {\r
+ Private->Status = EFI_NOT_FOUND;\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Retransmit icmp6 echo request packets per second in sendnumber times.\r
+ //\r
+ if (Private->TxCount < Private->SendNum) {\r
+\r
+ Status = PingSendEchoRequest (Private);\r
+ if (Private->TxCount != 0){\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_SEND_REQUEST), gShellNetwork1HiiHandle, Private->TxCount + 1);\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Check whether any icmp6 echo request in the list timeout.\r
+ //\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
+ TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
+ Time = CalculateTick (TxInfo->TimeStamp, ReadTime ());\r
+\r
+ //\r
+ // Remove the timeout echo request from txlist.\r
+ //\r
+ if (Time > DEFAULT_TIMEOUT) {\r
+\r
+ if (EFI_ERROR (TxInfo->Token->Status)) {\r
+ Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);\r
+ }\r
+ //\r
+ // Remove the timeout icmp6 echo request from list.\r
+ //\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_TIMEOUT), gShellNetwork1HiiHandle, TxInfo->SequenceNum);\r
+\r
+ RemoveEntryList (&TxInfo->Link);\r
+ PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
+\r
+ //\r
+ // We dont need to wait for this some other time...\r
+ //\r
+ Private->RxCount++;\r
+\r
+ if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
+ //\r
+ // All the left icmp6 echo request in the list timeout.\r
+ //\r
+ Private->Status = EFI_TIMEOUT;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Determine if a IP4 address is Link Local.\r
+\r
+ 169.254.1.0 through 169.254.254.255 is link local.\r
+\r
+ @param[in] Address The address to test.\r
+\r
+ @retval TRUE It is.\r
+ @retval FALSE It is not.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+PingNetIp4IsLinkLocalAddr (\r
+ IN CONST EFI_IPv4_ADDRESS *Address\r
+ )\r
+{\r
+ return ((BOOLEAN)(Address->Addr[0] == 169 && Address->Addr[1] == 254 && Address->Addr[2] >= 1 && Address->Addr[2] <= 254));\r
+}\r
+\r
+/**\r
+ Determine if a IP4 address is unspecified.\r
+\r
+ @param[in] Address The address to test.\r
+\r
+ @retval TRUE It is.\r
+ @retval FALSE It is not.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+PingNetIp4IsUnspecifiedAddr (\r
+ IN CONST EFI_IPv4_ADDRESS *Address\r
+ )\r
+{\r
+ return ((BOOLEAN)((ReadUnaligned32 ((UINT32*)&Address->Addr[0])) == 0x00000000));\r
+}\r
+\r
+/**\r
+ Create a valid IP instance.\r
+\r
+ @param[in] Private The pointer of PING_PRIVATE_DATA.\r
+\r
+ @retval EFI_SUCCESS Create a valid IPx instance successfully.\r
+ @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.\r
+ @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.\r
+ @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
+ @retval EFI_NOT_FOUND The source address is not found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PingCreateIpInstance (\r
+ IN PING_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN HandleIndex;\r
+ UINTN HandleNum;\r
+ EFI_HANDLE *HandleBuffer;\r
+ EFI_SERVICE_BINDING_PROTOCOL *EfiSb;\r
+ VOID *IpXCfg;\r
+ EFI_IP6_CONFIG_DATA Ip6Config;\r
+ EFI_IP4_CONFIG_DATA Ip4Config;\r
+ VOID *IpXInterfaceInfo;\r
+ UINTN IfInfoSize;\r
+ EFI_IPv6_ADDRESS *Addr;\r
+ UINTN AddrIndex;\r
+\r
+ HandleBuffer = NULL;\r
+ EfiSb = NULL;\r
+ IpXInterfaceInfo = NULL;\r
+ IfInfoSize = 0;\r
+\r
+ //\r
+ // Locate all the handles with ip6 service binding protocol.\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
+ NULL,\r
+ &HandleNum,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status) || (HandleNum == 0)) {\r
+ return EFI_ABORTED;\r
+ }\r
+ //\r
+ // Source address is required when pinging a link-local address on multi-\r
+ // interfaces host.\r
+ //\r
+ if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
+ if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS*)&Private->DstAddress) &&\r
+ NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress) &&\r
+ (HandleNum > 1)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, mSrcString);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_ERROR;\r
+ }\r
+ } else {\r
+ ASSERT(Private->IpChoice == PING_IP_CHOICE_IP4);\r
+ if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS*)&Private->DstAddress) &&\r
+ PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&Private->SrcAddress) &&\r
+ (HandleNum > 1)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, mSrcString);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // For each ip6 protocol, check interface addresses list.\r
+ //\r
+ for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {\r
+\r
+ EfiSb = NULL;\r
+ IpXInterfaceInfo = NULL;\r
+ IfInfoSize = 0;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[HandleIndex],\r
+ Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
+ (VOID **) &EfiSb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (Private->IpChoice == PING_IP_CHOICE_IP6?NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress):PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&Private->SrcAddress)) {\r
+ //\r
+ // No need to match interface address.\r
+ //\r
+ break;\r
+ } else {\r
+ //\r
+ // Ip6config protocol and ip6 service binding protocol are installed\r
+ // on the same handle.\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[HandleIndex],\r
+ Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ConfigProtocolGuid:&gEfiIp4ConfigProtocolGuid,\r
+ (VOID **) &IpXCfg\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+ //\r
+ // Get the interface information size.\r
+ //\r
+ if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
+ Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
+ IpXCfg,\r
+ Ip6ConfigDataTypeInterfaceInfo,\r
+ &IfInfoSize,\r
+ NULL\r
+ );\r
+ } else {\r
+ Status = ((EFI_IP4_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
+ IpXCfg,\r
+ &IfInfoSize,\r
+ NULL\r
+ );\r
+ }\r
+ \r
+ //\r
+ // Skip the ones not in current use.\r
+ //\r
+ if (Status == EFI_NOT_STARTED) {\r
+ continue;\r
+ }\r
+\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);\r
+\r
+ if (IpXInterfaceInfo == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_ERROR;\r
+ }\r
+ //\r
+ // Get the interface info.\r
+ //\r
+ if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
+ Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
+ IpXCfg,\r
+ Ip6ConfigDataTypeInterfaceInfo,\r
+ &IfInfoSize,\r
+ IpXInterfaceInfo\r
+ );\r
+ } else {\r
+ Status = ((EFI_IP4_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
+ IpXCfg,\r
+ &IfInfoSize,\r
+ IpXInterfaceInfo\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
+ goto ON_ERROR;\r
+ }\r
+ //\r
+ // Check whether the source address is one of the interface addresses.\r
+ //\r
+ if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
+ for (AddrIndex = 0; AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount; AddrIndex++) {\r
+\r
+ Addr = &(((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfo[AddrIndex].Address);\r
+ if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
+ //\r
+ // Match a certain interface address.\r
+ //\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount) {\r
+ //\r
+ // Found a nic handle with right interface address.\r
+ //\r
+ break;\r
+ }\r
+ } else {\r
+ //\r
+ // IP4 address check\r
+ //\r
+ if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_IPCONFIG_DATA*)IpXInterfaceInfo)->StationAddress)) {\r
+ //\r
+ // Match a certain interface address.\r
+ //\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (IpXInterfaceInfo);\r
+ IpXInterfaceInfo = NULL;\r
+ }\r
+ //\r
+ // No exact interface address matched.\r
+ //\r
+\r
+ if (HandleIndex == HandleNum) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, mSrcString);\r
+ Status = EFI_NOT_FOUND;\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Private->NicHandle = HandleBuffer[HandleIndex];\r
+\r
+ ASSERT (EfiSb != NULL);\r
+ Status = EfiSb->CreateChild (EfiSb, &Private->IpChildHandle);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+ if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
+ Status = gBS->OpenProtocol (\r
+ Private->IpChildHandle,\r
+ &gEfiIp6ProtocolGuid,\r
+ &Private->IpProtocol,\r
+ gImageHandle,\r
+ Private->IpChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+\r
+ ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));\r
+\r
+ //\r
+ // Configure the ip6 instance for icmp6 packet exchange.\r
+ //\r
+ Ip6Config.DefaultProtocol = 58;\r
+ Ip6Config.AcceptAnyProtocol = FALSE;\r
+ Ip6Config.AcceptIcmpErrors = TRUE;\r
+ Ip6Config.AcceptPromiscuous = FALSE;\r
+ Ip6Config.TrafficClass = 0;\r
+ Ip6Config.HopLimit = 128;\r
+ Ip6Config.FlowLabel = 0;\r
+ Ip6Config.ReceiveTimeout = 0;\r
+ Ip6Config.TransmitTimeout = 0;\r
+\r
+ IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);\r
+ IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);\r
+\r
+ Status = ((EFI_IP6_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip6Config);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Transmit;\r
+ Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Receive;\r
+ Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Cancel;\r
+ Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Poll;\r
+ } else {\r
+ Status = gBS->OpenProtocol (\r
+ Private->IpChildHandle,\r
+ &gEfiIp4ProtocolGuid,\r
+ &Private->IpProtocol,\r
+ gImageHandle,\r
+ Private->IpChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+\r
+ ZeroMem (&Ip4Config, sizeof (EFI_IP4_CONFIG_DATA));\r
+\r
+ //\r
+ // Configure the ip4 instance for icmp4 packet exchange.\r
+ //\r
+// PING_IP4_COPY_ADDRESS (&Ip4Config.StationAddress, &Private->SrcAddress);\r
+// Ip4Config.SubnetMask.Addr[0] = 0xFF;\r
+// Ip4Config.SubnetMask.Addr[1] = 0xFF;\r
+// Ip4Config.SubnetMask.Addr[2] = 0xFF;\r
+// Ip4Config.SubnetMask.Addr[3] = 0x00;\r
+ Ip4Config.DefaultProtocol = 1;\r
+ Ip4Config.AcceptAnyProtocol = FALSE;\r
+ Ip4Config.AcceptBroadcast = FALSE;\r
+ Ip4Config.AcceptIcmpErrors = TRUE;\r
+ Ip4Config.AcceptPromiscuous = FALSE;\r
+ Ip4Config.DoNotFragment = FALSE;\r
+ Ip4Config.RawData = FALSE;\r
+ Ip4Config.ReceiveTimeout = 0;\r
+ Ip4Config.TransmitTimeout = 0;\r
+ Ip4Config.UseDefaultAddress = TRUE;\r
+ Ip4Config.TimeToLive = 128;\r
+ Ip4Config.TypeOfService = 0;\r
+\r
+ Status = ((EFI_IP4_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip4Config);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status);\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Transmit;\r
+ Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Receive;\r
+ Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Cancel;\r
+ Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Poll; \r
+ }\r
+\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ if (HandleBuffer != NULL) {\r
+ FreePool (HandleBuffer);\r
+ }\r
+\r
+ if (IpXInterfaceInfo != NULL) {\r
+ FreePool (IpXInterfaceInfo);\r
+ }\r
+\r
+ if ((EfiSb != NULL) && (Private->IpChildHandle != NULL)) {\r
+ EfiSb->DestroyChild (EfiSb, Private->IpChildHandle);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Destory the IP instance.\r
+\r
+ @param[in] Private The pointer of PING_PRIVATE_DATA.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ping6DestoryIp6Instance (\r
+ IN PING_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SERVICE_BINDING_PROTOCOL *IpSb;\r
+\r
+ gBS->CloseProtocol (\r
+ Private->IpChildHandle,\r
+ Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ProtocolGuid:&gEfiIp4ProtocolGuid,\r
+ gImageHandle,\r
+ Private->IpChildHandle\r
+ );\r
+\r
+ Status = gBS->HandleProtocol (\r
+ Private->NicHandle,\r
+ Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
+ (VOID **) &IpSb\r
+ );\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ IpSb->DestroyChild (IpSb, Private->IpChildHandle);\r
+ }\r
+}\r
+\r
+/**\r
+ The Ping Process.\r
+\r
+ @param[in] SendNumber The send request count.\r
+ @param[in] BufferSize The send buffer size.\r
+ @param[in] SrcAddress The source address.\r
+ @param[in] DstAddress The destination address.\r
+ @param[in] IpChoice The choice between IPv4 and IPv6.\r
+\r
+ @retval SHELL_SUCCESS The ping processed successfullly.\r
+ @retval others The ping processed unsuccessfully.\r
+**/\r
+SHELL_STATUS\r
+EFIAPI\r
+ShellPing (\r
+ IN UINT32 SendNumber,\r
+ IN UINT32 BufferSize,\r
+ IN EFI_IPv6_ADDRESS *SrcAddress,\r
+ IN EFI_IPv6_ADDRESS *DstAddress,\r
+ IN UINT32 IpChoice\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PING_PRIVATE_DATA *Private;\r
+ PING_ICMPX_TX_INFO *TxInfo;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+ SHELL_STATUS ShellStatus;\r
+\r
+ ShellStatus = SHELL_SUCCESS;\r
+ Private = AllocateZeroPool (sizeof (PING_PRIVATE_DATA));\r
+\r
+ if (Private == NULL) {\r
+ return (SHELL_OUT_OF_RESOURCES);\r
+ }\r
+\r
+ Private->IpChoice = IpChoice;\r
+ Private->Signature = PING_PRIVATE_DATA_SIGNATURE;\r
+ Private->SendNum = SendNumber;\r
+ Private->BufferSize = BufferSize;\r
+ Private->RttMin = ~((UINT64 )(0x0));\r
+ Private->Status = EFI_NOT_READY;\r
+\r
+ CopyMem(&Private->SrcAddress, SrcAddress, sizeof(Private->SrcAddress));\r
+ CopyMem(&Private->DstAddress, DstAddress, sizeof(Private->DstAddress));\r
+\r
+ InitializeListHead (&Private->TxList);\r
+\r
+ //\r
+ // Open and configure a ip instance for us.\r
+ //\r
+ Status = PingCreateIpInstance (Private);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ShellStatus = SHELL_ACCESS_DENIED;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Print the command line itself.\r
+ //\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_START), gShellNetwork1HiiHandle, mDstString, Private->BufferSize);\r
+ //\r
+ // Create a ipv6 token to receive the first icmp6 echo reply packet.\r
+ //\r
+ Status = Ping6ReceiveEchoReply (Private);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ShellStatus = SHELL_ACCESS_DENIED;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Create and start timer to send icmp6 echo request packet per second.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ Ping6OnTimerRoutine,\r
+ Private,\r
+ &Private->Timer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ShellStatus = SHELL_ACCESS_DENIED;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Create a ipv6 token to send the first icmp6 echo request packet.\r
+ //\r
+ Status = PingSendEchoRequest (Private);\r
+ //\r
+ // EFI_NOT_READY for IPsec is enable and IKE is not established.\r
+ //\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
+ ShellStatus = SHELL_ACCESS_DENIED;\r
+ if(Status == EFI_NOT_FOUND) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOSOURCE_INDO), gShellNetwork1HiiHandle, mDstString);\r
+ } else if (Status == RETURN_NO_MAPPING) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOROUTE_FOUND), gShellNetwork1HiiHandle, mDstString, mSrcString);\r
+ } else {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, Status);\r
+ }\r
+\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = gBS->SetTimer (\r
+ Private->Timer,\r
+ TimerPeriodic,\r
+ ONE_SECOND\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ShellStatus = SHELL_ACCESS_DENIED;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Control the ping6 process by two factors:\r
+ // 1. Hot key\r
+ // 2. Private->Status\r
+ // 2.1. success means all icmp6 echo request packets get reply packets.\r
+ // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.\r
+ // 2.3. noready means ping6 process is on-the-go.\r
+ //\r
+ while (Private->Status == EFI_NOT_READY) {\r
+ Status = Private->ProtocolPointers.Poll (Private->IpProtocol);\r
+ if (ShellGetExecutionBreakFlag()) {\r
+ Private->Status = EFI_ABORTED;\r
+ goto ON_STAT;\r
+ }\r
+ }\r
+\r
+ON_STAT:\r
+ //\r
+ // Display the statistics in all.\r
+ //\r
+ gBS->SetTimer (Private->Timer, TimerCancel, 0);\r
+\r
+ if (Private->TxCount != 0) {\r
+ ShellPrintHiiEx (\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN (STR_PING_STAT),\r
+ gShellNetwork1HiiHandle,\r
+ Private->TxCount,\r
+ Private->RxCount,\r
+ (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount,\r
+ Private->RttSum\r
+ );\r
+ }\r
+\r
+ if (Private->RxCount != 0) {\r
+ ShellPrintHiiEx (\r
+ -1,\r
+ -1,\r
+ NULL,\r
+ STRING_TOKEN (STR_PING_RTT),\r
+ gShellNetwork1HiiHandle,\r
+ Private->RttMin,\r
+ Private->RttMax,\r
+ DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL)\r
+ );\r
+ }\r
+\r
+ON_EXIT:\r
+\r
+ if (Private != NULL) {\r
+\r
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
+ TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
+\r
+ if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) {\r
+ Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token);\r
+ }\r
+\r
+ RemoveEntryList (&TxInfo->Link);\r
+ PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
+ }\r
+\r
+ if (Private->Timer != NULL) {\r
+ gBS->CloseEvent (Private->Timer);\r
+ }\r
+\r
+ if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) {\r
+ Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, &Private->RxToken);\r
+ }\r
+\r
+ if (Private->RxToken.Event != NULL) {\r
+ gBS->CloseEvent (Private->RxToken.Event);\r
+ }\r
+\r
+ if (Private->IpChildHandle != NULL) {\r
+ Ping6DestoryIp6Instance (Private);\r
+ }\r
+\r
+ FreePool (Private);\r
+ }\r
+\r
+ return ShellStatus;\r
+}\r
+\r
+/**\r
+ Function for 'ping' command.\r
+\r
+ @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
+ @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
+**/\r
+SHELL_STATUS\r
+EFIAPI\r
+ShellCommandRunPing (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SHELL_STATUS ShellStatus;\r
+ EFI_IPv6_ADDRESS DstAddress;\r
+ EFI_IPv6_ADDRESS SrcAddress;\r
+ UINT64 BufferSize;\r
+ UINTN SendNumber;\r
+ LIST_ENTRY *ParamPackage;\r
+ CONST CHAR16 *ValueStr;\r
+ UINTN NonOptionCount;\r
+ UINT32 IpChoice;\r
+\r
+ //\r
+ // we use IPv6 buffers to hold items... \r
+ // make sure this is enough space!\r
+ //\r
+ ASSERT(sizeof(EFI_IPv4_ADDRESS ) <= sizeof(EFI_IPv6_ADDRESS ));\r
+ ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN) <= sizeof(EFI_IP6_COMPLETION_TOKEN ));\r
+\r
+ IpChoice = PING_IP_CHOICE_IP4;\r
+\r
+ ShellStatus = SHELL_SUCCESS;\r
+\r
+ Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, NULL, TRUE, FALSE);\r
+ if (EFI_ERROR(Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (ShellCommandLineGetFlag (ParamPackage, L"-_ip6")) {\r
+ IpChoice = PING_IP_CHOICE_IP6;\r
+ }\r
+\r
+ //\r
+ // Parse the paramter of count number.\r
+ //\r
+ ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
+ if (ValueStr != NULL) {\r
+ SendNumber = ShellStrToUintn (ValueStr);\r
+\r
+ //\r
+ // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
+ //\r
+ if ((SendNumber == 0) || (SendNumber > MAX_SEND_NUMBER)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ } else {\r
+ SendNumber = DEFAULT_SEND_COUNT;\r
+ }\r
+ //\r
+ // Parse the paramter of buffer size.\r
+ //\r
+ ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
+ if (ValueStr != NULL) {\r
+ BufferSize = ShellStrToUintn (ValueStr);\r
+\r
+ //\r
+ // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
+ //\r
+ if ((BufferSize < 16) || (BufferSize > MAX_BUFFER_SIZE)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ } else {\r
+ BufferSize = DEFAULT_BUFFER_SIZE;\r
+ }\r
+\r
+ ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));\r
+ ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
+\r
+ //\r
+ // Parse the paramter of source ip address.\r
+ //\r
+ ValueStr = ShellCommandLineGetValue (ParamPackage, L"-_s");\r
+ if (ValueStr != NULL) {\r
+ mSrcString = ValueStr;\r
+ if (IpChoice == PING_IP_CHOICE_IP6) {\r
+ Status = NetLibStrToIp6 (ValueStr, &SrcAddress);\r
+ } else {\r
+ Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&SrcAddress);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+ //\r
+ // Parse the paramter of destination ip address.\r
+ //\r
+ NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
+ if (NonOptionCount < 2) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ if (NonOptionCount > 2) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);\r
+ if (ValueStr != NULL) {\r
+ mDstString = ValueStr;\r
+ if (IpChoice == PING_IP_CHOICE_IP6) {\r
+ Status = NetLibStrToIp6 (ValueStr, &DstAddress);\r
+ } else {\r
+ Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&DstAddress);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr);\r
+ ShellStatus = SHELL_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+ //\r
+ // Get frequency to calculate the time from ticks.\r
+ //\r
+ Status = GetFrequency ();\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Enter into ping process.\r
+ //\r
+ ShellStatus = ShellPing (\r
+ (UINT32)SendNumber,\r
+ (UINT32)BufferSize,\r
+ &SrcAddress,\r
+ &DstAddress,\r
+ IpChoice\r
+ );\r
+\r
+ON_EXIT:\r
+ ShellCommandLineFreeVarList (ParamPackage);\r
+ return ShellStatus;\r
+}\r