From 68fb05272b45b473fe030ac11dcb79d3f3c0aecd Mon Sep 17 00:00:00 2001 From: jcarsey Date: Fri, 25 Mar 2011 20:47:02 +0000 Subject: [PATCH] Add Network1 profile. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11423 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UefiShellNetwork1CommandsLib/Ia32/Tsc.c | 28 + .../UefiShellNetwork1CommandsLib/Ifconfig.c | 1746 +++++++++++++++++ .../UefiShellNetwork1CommandsLib/Ipf/Itc.c | 28 + .../UefiShellNetwork1CommandsLib/Ping.c | 1563 +++++++++++++++ .../UefiShellNetwork1CommandsLib.c | 94 + .../UefiShellNetwork1CommandsLib.h | 79 + .../UefiShellNetwork1CommandsLib.inf | 75 + .../UefiShellNetwork1CommandsLib.uni | Bin 0 -> 18172 bytes .../UefiShellNetwork1CommandsLib/X64/Tsc.c | 28 + 9 files changed, 3641 insertions(+) create mode 100644 ShellPkg/Library/UefiShellNetwork1CommandsLib/Ia32/Tsc.c create mode 100644 ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c create mode 100644 ShellPkg/Library/UefiShellNetwork1CommandsLib/Ipf/Itc.c create mode 100644 ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c create mode 100644 ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.c create mode 100644 ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.h create mode 100644 ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf create mode 100644 ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni create mode 100644 ShellPkg/Library/UefiShellNetwork1CommandsLib/X64/Tsc.c diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ia32/Tsc.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ia32/Tsc.c new file mode 100644 index 0000000000..e2eae99077 --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ia32/Tsc.c @@ -0,0 +1,28 @@ +/** @file + The implement to read TSC in IA32 platform. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +/** + Reads and returns the current value of the Time Stamp Counter (TSC). + + @return The current value of TSC. + +**/ +UINT64 +ReadTime () +{ + return AsmReadTsc (); +} diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c new file mode 100644 index 0000000000..2e8a09fc33 --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c @@ -0,0 +1,1746 @@ +/** @file + The implementation for ifcommand shell command. + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include "UefiShellNetwork1CommandsLib.h" + +#define NIC_ITEM_CONFIG_SIZE (sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE) +#define EFI_IP4_TO_U32(EfiIpAddr) (*(IP4_ADDR*)((EfiIpAddr).Addr)) + +BOOLEAN mIp4ConfigExist = FALSE; +STATIC EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting = NULL; + +STATIC CONST UINTN SEC_TO_NS = 10000000; +STATIC CONST CHAR16 DhcpString[5] = L"DHCP"; +STATIC CONST CHAR16 StaticString[7] = L"STATIC"; +STATIC CONST CHAR16 PermanentString[10] = L"PERMANENT"; + +typedef struct { + LIST_ENTRY Link; + EFI_HANDLE Handle; + NIC_ADDR NicAddress; + CHAR16 Name[IP4_NIC_NAME_LENGTH]; + BOOLEAN MediaPresentSupported; + BOOLEAN MediaPresent; + EFI_IP4_CONFIG_PROTOCOL *Ip4Config; + NIC_IP4_CONFIG_INFO *ConfigInfo; +} NIC_INFO; + +typedef struct { + EFI_IP_ADDRESS DestIp; + EFI_MAC_ADDRESS DestMac; + EFI_IP_ADDRESS LocalIp; + EFI_MAC_ADDRESS LocalMac; + UINT8 MacLen; + EFI_EVENT OnResolved; + BOOLEAN Duplicate; +} ARP_REQUEST; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-c", TypeValue}, + {L"-l", TypeValue}, + {L"-s", TypeMaxValue}, + {NULL, TypeMax} + }; + +STATIC LIST_ENTRY NicInfoList; +STATIC BOOLEAN ArpResolved; +STATIC BOOLEAN mTimeout; + +/** + Count the space delimited items in a string. + + @param[in] String A pointer to the string to count. + + @return The number of space-delimited items. + @retval 0xFF an error occured. +**/ +UINT8 +EFIAPI +CountSubItems ( + IN CONST CHAR16 *String + ) +{ + CONST CHAR16 *Walker; + UINT8 Count; + + if (String == NULL || *String == CHAR_NULL) { + return (0xFF); + } + + for (Walker = String, Count = 0 ; Walker != NULL && *Walker != CHAR_NULL ; Walker = (StrStr(Walker, L" ")==NULL?NULL:StrStr(Walker, L" ")+1), Count++); + return (Count); +} + +/** + Find the NIC_INFO by the specified nic name. + + @param[in] Name The pointer to the string containing the NIC name. + + @return The pointer to the NIC_INFO if there is a NIC_INFO named by Name. + @retval NULL No NIC_INFO was found for Name. +**/ +NIC_INFO* +EFIAPI +IfconfigFindNicByName ( + IN CONST CHAR16 *Name + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + NIC_INFO *Info; + CHAR16 *TempString; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &NicInfoList) { + Info = BASE_CR (Entry, NIC_INFO, Link); + TempString = (CHAR16*)Info->Name; + + if (StringNoCaseCompare (&Name, &TempString) == 0) { + return Info; + } + } + + return NULL; +} + +/** + Tests whether a child handle is a child device of the controller. + + @param[in] ControllerHandle A handle for a (parent) controller to test. + @param[in] ChildHandle A child handle to test. + @param[in] ProtocolGuid Supplies the protocol that the child controller + opens on its parent controller. + + @retval EFI_SUCCESS ChildHandle is a child of the ControllerHandle. + @retval EFI_UNSUPPORTED ChildHandle is not a child of the ControllerHandle. +**/ +EFI_STATUS +EFIAPI +TestChildHandle ( + IN CONST EFI_HANDLE ControllerHandle, + IN CONST EFI_HANDLE ChildHandle, + IN CONST EFI_GUID *ProtocolGuid + ) +{ + EFI_STATUS Status; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + UINTN Index; + + ASSERT (ProtocolGuid != NULL); + + // + // Retrieve the list of agents that are consuming the specific protocol + // on ControllerHandle. + // + Status = gBS->OpenProtocolInformation ( + ControllerHandle, + (EFI_GUID *) ProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Inspect if ChildHandle is one of the agents. + // + Status = EFI_UNSUPPORTED; + for (Index = 0; Index < EntryCount; Index++) { + if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) && + (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + Status = EFI_SUCCESS; + break; + } + } + + FreePool (OpenInfoBuffer); + return Status; +} + +/** + Get the child handle of the NIC handle. + + @param[in] Controller Routing information: GUID. + @param[in] ChildHandle Returned child handle. + + @retval EFI_SUCCESS Successfully to get child handle. +**/ +EFI_STATUS +GetChildHandle ( + IN EFI_HANDLE Controller, + OUT EFI_HANDLE *ChildHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + UINTN HandleCount; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *ChildDeviceDevicePath; + VENDOR_DEVICE_PATH *VendorDeviceNode; + + // + // Locate all EFI Hii Config Access protocols + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiHiiConfigAccessProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status) || (HandleCount == 0)) { + return Status; + } + + Status = EFI_NOT_FOUND; + + for (Index = 0; Index < HandleCount; Index++) { + + Status = TestChildHandle (Controller, Handles[Index], &gEfiManagedNetworkServiceBindingProtocolGuid); + if (!EFI_ERROR (Status)) { + // + // Get device path on the child handle + // + Status = gBS->HandleProtocol ( + Handles[Index], + &gEfiDevicePathProtocolGuid, + (VOID **) &ChildDeviceDevicePath + ); + + if (!EFI_ERROR (Status)) { + while (!IsDevicePathEnd (ChildDeviceDevicePath)) { + ChildDeviceDevicePath = NextDevicePathNode (ChildDeviceDevicePath); + // + // Parse one instance + // + if (ChildDeviceDevicePath->Type == HARDWARE_DEVICE_PATH && + ChildDeviceDevicePath->SubType == HW_VENDOR_DP) { + VendorDeviceNode = (VENDOR_DEVICE_PATH *) ChildDeviceDevicePath; + if (CompareMem (&VendorDeviceNode->Guid, &gEfiNicIp4ConfigVariableGuid, sizeof (EFI_GUID)) == 0) { + // + // Found item matched gEfiNicIp4ConfigVariableGuid + // + *ChildHandle = Handles[Index]; + FreePool (Handles); + return EFI_SUCCESS; + } + } + } + } + } + } + + FreePool (Handles); + return Status; +} + +/** + Append OFFSET/WIDTH/VALUE items at the beginning of string. + + @param[in,out] String The pointer to the string to append onto. + @param[in] Offset Offset value. + @param[in] Width Width value. + @param[in] Block Point to data buffer. + + @return The count of unicode character that were appended. +**/ +UINTN +EFIAPI +AppendOffsetWidthValue ( + IN OUT CHAR16 *String, + IN UINTN Offset, + IN UINTN Width, + IN CONST UINT8 *Block + ) + +{ + CHAR16 *OriString; + + OriString = String; + + StrCpy (String, L"&OFFSET="); + String += StrLen (L"&OFFSET="); + String += UnicodeSPrint (String, 20, L"%x", Offset); + + StrCpy (String,L"&WIDTH="); + String += StrLen (L"&WIDTH="); + String += UnicodeSPrint (String, 20, L"%x", Width); + + if (Block != NULL) { + StrCpy (String,L"&VALUE="); + String += StrLen (L"&VALUE="); + while ((Width--) != 0) { + String += UnicodeSPrint (String, 20, L"%x", Block[Width]); + } + } + + return String - OriString; +} + +/** + Converts the unicode character of the string from uppercase to lowercase. + This is a internal function. + + @param ConfigString String to be converted +**/ +CHAR16* +EFIAPI +HiiToLower ( + IN CHAR16 *ConfigString + ) +{ + CHAR16 *String; + BOOLEAN Lower; + + // + // Convert all hex digits in range [A-F] in the configuration header to [a-f] + // + for (String = ConfigString, Lower = FALSE; String != NULL && *String != L'\0'; String++) { + if (*String == L'=') { + Lower = TRUE; + } else if (*String == L'&') { + Lower = FALSE; + } else if (Lower && *String >= L'A' && *String <= L'F') { + *String = (CHAR16) (*String - L'A' + L'a'); + } + } + + return (ConfigString); +} + + +/** + Construct using routing information GUID/NAME/PATH. + + @param[in] Guid Routing information: GUID. + @param[in] Name Routing information: NAME. + @param[in] DriverHandle Driver handle which contains the routing information: PATH. + + @retval NULL An error occured. + @return The pointer to configHdr string. +**/ +CHAR16 * +EFIAPI +ConstructConfigHdr ( + IN CONST EFI_GUID *Guid, + IN CONST CHAR16 *Name, + IN EFI_HANDLE DriverHandle + ) +{ + EFI_STATUS Status; + CHAR16 *ConfigHdr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + CHAR16 *String; + UINTN Index; + UINT8 *Buffer; + UINTN DevicePathLength; + UINTN NameLength; + + // + // Get the device path from handle installed EFI HII Config Access protocol + // + Status = gBS->HandleProtocol ( + DriverHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + DevicePathLength = GetDevicePathSize (DevicePath); + NameLength = StrLen (Name); + ConfigHdr = AllocateZeroPool ((5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathLength * 2 + 1) * sizeof (CHAR16)); + if (ConfigHdr == NULL) { + return NULL; + } + + String = ConfigHdr; + StrCpy (String, L"GUID="); + String += StrLen (L"GUID="); + + // + // Append Guid converted to 32 + // + for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) { + String += UnicodeSPrint (String, 6, L"%02x", *Buffer++); + } + + // + // Append L"&NAME=" + // + StrCpy (String, L"&NAME="); + String += StrLen (L"&NAME="); + for (Index = 0; Index < NameLength ; Index++) { + String += UnicodeSPrint (String, 10, L"00%x", Name[Index]); + } + + // + // Append L"&PATH=" + // + StrCpy (String, L"&PATH="); + String += StrLen (L"&PATH="); + for (Index = 0, Buffer = (UINT8 *) DevicePath; Index < DevicePathLength; Index++) { + String += UnicodeSPrint (String, 6, L"%02x", *Buffer++); + } + + return (HiiToLower(ConfigHdr)); +} + +/** + Get network physical device NIC information. + + @param[in] Handle The network physical device handle. + @param[out] NicAddr NIC information. + + @retval EFI_SUCCESS Get NIC information successfully. +**/ +EFI_STATUS +EFIAPI +IfConfigGetNicMacInfo ( + IN EFI_HANDLE Handle, + OUT NIC_ADDR *NicAddr + ) +{ + EFI_STATUS Status; + EFI_HANDLE MnpHandle; + EFI_SIMPLE_NETWORK_MODE SnpMode; + EFI_MANAGED_NETWORK_PROTOCOL *Mnp; + + MnpHandle = NULL; + Mnp = NULL; + + Status = NetLibCreateServiceChild ( + Handle, + gImageHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &MnpHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol ( + MnpHandle, + &gEfiManagedNetworkProtocolGuid, + (VOID **) &Mnp + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = Mnp->GetModeData (Mnp, NULL, &SnpMode); + if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) { + goto ON_ERROR; + } + + NicAddr->Type = (UINT16) SnpMode.IfType; + NicAddr->Len = (UINT8) SnpMode.HwAddressSize; + CopyMem (&NicAddr->MacAddr, &SnpMode.CurrentAddress, NicAddr->Len); + +ON_ERROR: + + NetLibDestroyServiceChild ( + Handle, + gImageHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + MnpHandle + ); + + return Status; + +} + +/** + Get network physical device NIC information. + + @param[in] Handle The network physical device handle. + @param[out] MediaPresentSupported + Upon successful return, TRUE is media present + is supported. FALSE otherwise. + @param[out] MediaPresent Upon successful return, TRUE is media present + is enabled. FALSE otherwise. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +IfConfigGetNicMediaStatus ( + IN EFI_HANDLE Handle, + OUT BOOLEAN *MediaPresentSupported, + OUT BOOLEAN *MediaPresent + ) + +{ + EFI_STATUS Status; + EFI_HANDLE MnpHandle; + EFI_SIMPLE_NETWORK_MODE SnpMode; + EFI_MANAGED_NETWORK_PROTOCOL *Mnp; + + MnpHandle = NULL; + Mnp = NULL; + + Status = NetLibCreateServiceChild ( + Handle, + gImageHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + &MnpHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol ( + MnpHandle, + &gEfiManagedNetworkProtocolGuid, + (VOID **) &Mnp + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = Mnp->GetModeData (Mnp, NULL, &SnpMode); + if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) { + goto ON_ERROR; + } + + *MediaPresentSupported = SnpMode.MediaPresentSupported; + *MediaPresent = SnpMode.MediaPresent; + +ON_ERROR: + + NetLibDestroyServiceChild ( + Handle, + gImageHandle, + &gEfiManagedNetworkServiceBindingProtocolGuid, + MnpHandle + ); + + return Status; + +} + +/** + Get all Nic's information through HII service. + + @retval EFI_SUCCESS All the nic information is collected. +**/ +EFI_STATUS +EFIAPI +IfconfigGetAllNicInfoByHii ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + UINTN HandleCount; + CHAR16 *ConfigResp; + CHAR16 *ConfigHdr; + UINTN Index; + CHAR16 *AccessProgress; + CHAR16 *AccessResults; + UINTN BufferSize; + NIC_INFO *NicInfo; + NIC_IP4_CONFIG_INFO *NicConfigRequest; + NIC_IP4_CONFIG_INFO *NicConfig; + CHAR16 *String; + UINTN Length; + UINTN Offset; + EFI_HANDLE ChildHandle; + + AccessResults = NULL; + ConfigHdr = NULL; + ConfigResp = NULL; + NicConfigRequest = NULL; + NicInfo = NULL; + + InitializeListHead (&NicInfoList); + + // + // Check if HII Config Routing protocol available. + // + Status = gBS->LocateProtocol ( + &gEfiHiiConfigRoutingProtocolGuid, + NULL, + (VOID**)&mHiiConfigRouting + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Locate all network device handles + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiManagedNetworkServiceBindingProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status) || (HandleCount == 0)) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = GetChildHandle (Handles[Index], &ChildHandle); + if (EFI_ERROR (Status)) { + // + // If failed to get Child handle, try NIC controller handle for back-compatibility. + // + ChildHandle = Handles[Index]; + } + // + // Construct configuration request string header + // + ConfigHdr = ConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, ChildHandle); + Length = StrLen (ConfigHdr); + ConfigResp = AllocateZeroPool ((Length + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16)); + if (ConfigResp == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + StrCpy (ConfigResp, ConfigHdr); + + // + // Append OFFSET/WIDTH pair + // + String = ConfigResp + Length; + Offset = 0; + AppendOffsetWidthValue (String, Offset, NIC_ITEM_CONFIG_SIZE, NULL); + + NicInfo = AllocateZeroPool (sizeof (NIC_INFO)); + if (NicInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + NicInfo->Handle = Handles[Index]; + + // + // Get network physical devcie MAC information + // + IfConfigGetNicMacInfo (Handles[Index], &NicInfo->NicAddress); + if (NicInfo->NicAddress.Type == NET_IFTYPE_ETHERNET) { + UnicodeSPrint (NicInfo->Name, IP4_NIC_NAME_LENGTH, L"eth%d", Index); + } else { + UnicodeSPrint (NicInfo->Name, IP4_NIC_NAME_LENGTH, L"unk%d", Index); + } + + // + // Get media status + // + IfConfigGetNicMediaStatus (Handles[Index], &NicInfo->MediaPresentSupported, &NicInfo->MediaPresent); + + NicConfigRequest = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE); + if (NicConfigRequest == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + // + // Get network parameters by HII service + // + Status = mHiiConfigRouting->ExtractConfig ( + mHiiConfigRouting, + ConfigResp, + &AccessProgress, + &AccessResults + ); + if (!EFI_ERROR (Status)) { + BufferSize = NIC_ITEM_CONFIG_SIZE; + Status = mHiiConfigRouting->ConfigToBlock ( + mHiiConfigRouting, + AccessResults, + (UINT8 *) NicConfigRequest, + &BufferSize, + &AccessProgress + ); + if (!EFI_ERROR (Status)) { + BufferSize = sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * NicConfigRequest->Ip4Info.RouteTableSize; + NicConfig = AllocateZeroPool (BufferSize); + if (NicConfig == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + CopyMem (NicConfig, NicConfigRequest, BufferSize); + + // + // If succeeds to get NIC configuration, fix up routetable pointer. + // + NicConfig->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (&NicConfig->Ip4Info + 1); + NicInfo->ConfigInfo = NicConfig; + + } else { + NicInfo->ConfigInfo = NULL; + } + + FreePool (AccessResults); + + } else { + NicInfo->ConfigInfo = NULL; + } + + // + // Add the Nic's info to the global NicInfoList. + // + InsertTailList (&NicInfoList, &NicInfo->Link); + + FreePool (NicConfigRequest); + FreePool (ConfigResp); + FreePool (ConfigHdr); + } + + FreePool (Handles); + + return EFI_SUCCESS; + +ON_ERROR: + if (AccessResults != NULL) { + FreePool (AccessResults); + } + if (NicConfigRequest != NULL) { + FreePool (NicConfigRequest); + } + if (NicInfo != NULL) { + FreePool (NicInfo); + } + if (ConfigResp != NULL) { + FreePool (ConfigResp); + } + if (ConfigHdr != NULL) { + FreePool (ConfigHdr); + } + + FreePool (Handles); + + return Status; +} + +/** + Set the address for the specified nic by HII service. + + @param[in] NicInfo A pointer to the NIC_INFO of the Nic to be configured. + @param[in] Config The command line arguments for the set operation. + + @retval EFI_SUCCESS The address set operation is done. +**/ +SHELL_STATUS +EFIAPI +IfconfigSetNicAddrByHii ( + IN CONST NIC_INFO *NicInfo, + IN CONST NIC_IP4_CONFIG_INFO *Config + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + NIC_IP4_CONFIG_INFO *NicConfig; + CHAR16 *ConfigResp; + CHAR16 *ConfigHdr; + CHAR16 *AccessProgress; + CHAR16 *AccessResults; + CHAR16 *String; + UINTN Length; + UINTN Offset; + EFI_HANDLE ChildHandle; + + AccessResults = NULL; + ConfigHdr = NULL; + ConfigResp = NULL; + NicConfig = NULL; + ShellStatus = SHELL_SUCCESS; + + Status = GetChildHandle (NicInfo->Handle, &ChildHandle); + if (EFI_ERROR (Status)) { + // + // If failed to get Child handle, try NIC controller handle for back-compatibility + // + ChildHandle = NicInfo->Handle; + } + // + // Construct config request string header + // + ConfigHdr = ConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, ChildHandle); + + Length = StrLen (ConfigHdr); + ConfigResp = AllocateZeroPool ((Length + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16)); + StrCpy (ConfigResp, ConfigHdr); + + NicConfig = AllocateZeroPool (NIC_ITEM_CONFIG_SIZE); + if (NicConfig == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + if (Config != NULL) { + CopyMem (NicConfig, Config, sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * Config->Ip4Info.RouteTableSize); + } + + // + // Append OFFSET/WIDTH pair + // + String = ConfigResp + Length; + Offset = 0; + AppendOffsetWidthValue (String, Offset, NIC_ITEM_CONFIG_SIZE, NULL); + + // + // Call HII helper function to generate configuration string + // + Status = mHiiConfigRouting->BlockToConfig ( + mHiiConfigRouting, + ConfigResp, + (UINT8 *) NicConfig, + NIC_ITEM_CONFIG_SIZE, + &AccessResults, + &AccessProgress + ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_NOT_FOUND; + goto ON_EXIT; + } + + // + // Set IP setting by HII servie + // + Status = mHiiConfigRouting->RouteConfig ( + mHiiConfigRouting, + AccessResults, + &AccessProgress + ); + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + } + +ON_EXIT: + SHELL_FREE_NON_NULL(AccessResults); + SHELL_FREE_NON_NULL(NicConfig); + SHELL_FREE_NON_NULL(ConfigResp); + SHELL_FREE_NON_NULL(ConfigHdr); + + return ShellStatus; +} + +/** + The callback function for the Arp address resolved event. + + @param[in] Event The event this function is registered to. + @param[in] Context The context registered to the event. +**/ +VOID +EFIAPI +IfconfigOnArpResolved ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + ARP_REQUEST *Request; + UINT8 Index; + + Request = (ARP_REQUEST *) Context; + ASSERT (Request != NULL); + + Request->Duplicate = FALSE; + + if (0 == CompareMem (&Request->LocalMac, &Request->DestMac, Request->MacLen)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Already Configured", + (UINTN)Request->DestIp.v4.Addr[0], + (UINTN)Request->DestIp.v4.Addr[1], + (UINTN)Request->DestIp.v4.Addr[2], + (UINTN)Request->DestIp.v4.Addr[3] + ); + ArpResolved = TRUE; + return; + } + + for (Index = 0; Index < Request->MacLen; Index++) { + if (Request->DestMac.Addr[Index] != 0) { + Request->Duplicate = TRUE; + } + } + + if (Request->Duplicate) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_IFCONFIG_CONF_IP_ADDR), + gShellNetwork1HiiHandle, + (UINTN)Request->DestMac.Addr[0], + (UINTN)Request->DestMac.Addr[1], + (UINTN)Request->DestMac.Addr[2], + (UINTN)Request->DestMac.Addr[3], + (UINTN)Request->DestMac.Addr[4], + (UINTN)Request->DestMac.Addr[5] + ); + } + + ArpResolved = TRUE; + return ; +} + +/** + Check whether the address to be configured conflicts with other hosts. + + @param[in] NicInfo The pointer to the NIC_INFO of the Nic to be configured. + @param[in] IpAddr The IPv4 address to be configured to the Nic. + + @return TRUE Some other host already uses the IpAddr. + @return FALSE The address is unused. +**/ +BOOLEAN +EFIAPI +IfconfigIsIpDuplicate ( + IN NIC_INFO *NicInfo, + IN IP4_ADDR IpAddr + ) +{ + EFI_ARP_PROTOCOL *Arp; + EFI_ARP_CONFIG_DATA ArpCfgData; + EFI_HANDLE ArpHandle; + ARP_REQUEST Request; + EFI_STATUS Status; + + Arp = NULL; + ArpHandle = NULL; + ZeroMem (&Request, sizeof (ARP_REQUEST)); + + Status = NetLibCreateServiceChild ( + NicInfo->Handle, + gImageHandle, + &gEfiArpServiceBindingProtocolGuid, + &ArpHandle + ); + + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = gBS->OpenProtocol ( + ArpHandle, + &gEfiArpProtocolGuid, + (VOID**)&Arp, + gImageHandle, + ArpHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Set up the Arp requests + // + EFI_IP4_TO_U32 (Request.DestIp.v4) = IpAddr; + EFI_IP4_TO_U32 (Request.LocalIp.v4) = 0xffffffff; + Request.LocalMac = NicInfo->NicAddress.MacAddr; + Request.MacLen = NicInfo->NicAddress.Len; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + IfconfigOnArpResolved, + (VOID *) &Request, + &Request.OnResolved + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + ArpCfgData.SwAddressType = 0x0800; + ArpCfgData.SwAddressLength = 4; + ArpCfgData.StationAddress = &Request.LocalIp; + ArpCfgData.EntryTimeOut = 0; + ArpCfgData.RetryCount = 3; + ArpCfgData.RetryTimeOut = 0; + + Status = Arp->Configure (Arp, &ArpCfgData); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = Arp->Request ( + Arp, + &Request.DestIp, + Request.OnResolved, + &Request.DestMac + ); + + if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) { + goto ON_EXIT; + } + + while (!ArpResolved) { + + } + +ON_EXIT: + if (Request.OnResolved != NULL) { + gBS->CloseEvent (Request.OnResolved); + } + + NetLibDestroyServiceChild ( + NicInfo->Handle, + gImageHandle, + &gEfiArpServiceBindingProtocolGuid, + ArpHandle + ); + + return Request.Duplicate; +} + +/** + The callback function for the timer event used to get map. + + @param[in] Event The event this function is registered to. + @param[in] Context The context registered to the event. +**/ +VOID +EFIAPI +TimeoutToGetMap ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + mTimeout = TRUE; + return ; +} + +/** + Create an IP child, use it to start the auto configuration, then destory it. + + @param[in] NicInfo The pointer to the NIC_INFO of the Nic to be configured. + + @retval EFI_SUCCESS The configuration is done. +**/ +EFI_STATUS +EFIAPI +IfconfigStartIp4( + IN NIC_INFO *NicInfo + ) +{ + EFI_IP4_PROTOCOL *Ip4; + EFI_HANDLE Ip4Handle; + EFI_HANDLE TimerToGetMap; + EFI_IP4_CONFIG_DATA Ip4ConfigData; + EFI_IP4_MODE_DATA Ip4Mode; + EFI_STATUS Status; + + // + // Get the Ip4ServiceBinding Protocol + // + Ip4Handle = NULL; + Ip4 = NULL; + TimerToGetMap = NULL; + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_START_SET_ADDR), gShellNetwork1HiiHandle); + + Status = NetLibCreateServiceChild ( + NicInfo->Handle, + gImageHandle, + &gEfiIp4ServiceBindingProtocolGuid, + &Ip4Handle + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Ip4Handle, + &gEfiIp4ProtocolGuid, + (VOID **) &Ip4, + NicInfo->Handle, + gImageHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Ip4ConfigData.DefaultProtocol = EFI_IP_PROTO_ICMP; + Ip4ConfigData.AcceptAnyProtocol = FALSE; + Ip4ConfigData.AcceptIcmpErrors = FALSE; + Ip4ConfigData.AcceptBroadcast = FALSE; + Ip4ConfigData.AcceptPromiscuous = FALSE; + Ip4ConfigData.UseDefaultAddress = TRUE; + ZeroMem (&Ip4ConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS)); + ZeroMem (&Ip4ConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); + Ip4ConfigData.TypeOfService = 0; + Ip4ConfigData.TimeToLive = 1; + Ip4ConfigData.DoNotFragment = FALSE; + Ip4ConfigData.RawData = FALSE; + Ip4ConfigData.ReceiveTimeout = 0; + Ip4ConfigData.TransmitTimeout = 0; + + Status = Ip4->Configure (Ip4, &Ip4ConfigData); + + if (Status == EFI_NO_MAPPING) { + mTimeout = FALSE; + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL | EVT_TIMER, + TPL_CALLBACK - 1, + TimeoutToGetMap, + NULL, + &TimerToGetMap + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = gBS->SetTimer ( + TimerToGetMap, + TimerRelative, + MultU64x32 (SEC_TO_NS, 5) + ); + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_WAIT_SET_DONE), gShellNetwork1HiiHandle); + + while (!mTimeout) { + Ip4->Poll (Ip4); + + if (!EFI_ERROR (Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL)) && + Ip4Mode.IsConfigured) { + break; + } + } + } + + Status = Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL); + + if ((Status == EFI_SUCCESS) && Ip4Mode.IsConfigured) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Default", + (UINTN)Ip4Mode.ConfigData.StationAddress.Addr[0], + (UINTN)Ip4Mode.ConfigData.StationAddress.Addr[1], + (UINTN)Ip4Mode.ConfigData.StationAddress.Addr[2], + (UINTN)Ip4Mode.ConfigData.StationAddress.Addr[3] + ); + } + +ON_EXIT: + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_GET_DEF_ADDR_FAIL), gShellNetwork1HiiHandle); + } + + if (TimerToGetMap != NULL) { + gBS->SetTimer (TimerToGetMap, TimerCancel, 0); + gBS->CloseEvent (TimerToGetMap); + } + + NetLibDestroyServiceChild ( + NicInfo->Handle, + gImageHandle, + &gEfiIp4ServiceBindingProtocolGuid, + Ip4Handle + ); + + return Status; +} + +/** + Set the address for the nic specified by the params. + + @param[in] Argc The count of the passed in Params. + @param[in] Params The command line arguments for the set operation. + + @retval EFI_SUCCESS The address set operation is done. + @return Some error occurs. +**/ +SHELL_STATUS +EFIAPI +IfconfigSetNicAddr ( + IN UINTN Argc, + IN CONST CHAR16 *Params + ) +{ + NIC_IP4_CONFIG_INFO *Config; + NIC_IP4_CONFIG_INFO *OldConfig; + EFI_IP_ADDRESS Ip; + EFI_IP_ADDRESS Mask; + EFI_IP_ADDRESS Gateway; + NIC_INFO *Info; + BOOLEAN Permanent; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Walker; + CHAR16 *Temp; + CONST CHAR16 *DhcpTemp; + CONST CHAR16 *StaticTemp; + CONST CHAR16 *PermTemp; + UINT32 NetworkBytes1; + UINT32 NetworkBytes2; + EFI_STATUS Status; + + Walker = Params; + Temp = NULL; + Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")-Walker); + Info = IfconfigFindNicByName (Temp); + + if (Info == NULL) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INTERFACE_NOT_FOUND), gShellNetwork1HiiHandle, Temp); + return SHELL_NOT_FOUND; + } + + Walker += StrLen(Temp) + 1; + FreePool(Temp); + Temp = NULL; + Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")==NULL?0:StrStr(Walker, L" ")-Walker); + + Config = AllocateZeroPool (sizeof (NIC_IP4_CONFIG_INFO) + 2 * sizeof (EFI_IP4_ROUTE_TABLE)); + if (Config == NULL) { + return SHELL_OUT_OF_RESOURCES; + } + + Config->Ip4Info.RouteTable = (EFI_IP4_ROUTE_TABLE *) (Config + 1); + + OldConfig = Info->ConfigInfo; + Permanent = FALSE; + ShellStatus = SHELL_INVALID_PARAMETER; + + DhcpTemp = DhcpString; + StaticTemp = StaticString; + + if (StringNoCaseCompare(&Temp, &DhcpTemp) == 0) { + // + // Validate the parameter for DHCP, two valid forms: eth0 DHCP and eth0 DHCP perment + // + if ((Argc != 2) && (Argc!= 3)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, Temp); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + if (Argc == 3) { + Walker += StrLen(Temp) + 1; + FreePool(Temp); + Temp = NULL; + Temp = StrnCatGrow(&Temp, NULL, Walker, 0); + + PermTemp = PermanentString; + if (StringNoCaseCompare(&Temp, &PermTemp) != 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_OP2), gShellNetwork1HiiHandle, Temp, PermanentString, L"Nothing"); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + Permanent = TRUE; + } + + if ((OldConfig != NULL) && (OldConfig->Source == IP4_CONFIG_SOURCE_DHCP) && + (OldConfig->Perment == Permanent)) { + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INTERFACE_CONFIGURED), gShellNetwork1HiiHandle, Info->Name); + ShellStatus = SHELL_ALREADY_STARTED; + goto ON_EXIT; + } + + Config->Source = IP4_CONFIG_SOURCE_DHCP; + } else if (StringNoCaseCompare(&Temp, &StaticTemp) == 0) { + // + // validate the parameter, two forms: eth0 static IP NETMASK GATEWAY and + // eth0 static IP NETMASK GATEWAY perment + // + if ((Argc != 5) && (Argc != 6)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, Temp); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + Walker += StrLen(Temp) + 1; + FreePool(Temp); + Temp = NULL; + Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")-Walker); + + if (EFI_ERROR (NetLibStrToIp4 (Temp, &Ip.v4))) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IP_STR), gShellNetwork1HiiHandle, Temp); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + Walker += StrLen(Temp) + 1; + FreePool(Temp); + Temp = NULL; + Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")-Walker); + if (EFI_ERROR (NetLibStrToIp4 (Temp, &Mask.v4))) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IP_STR), gShellNetwork1HiiHandle, Temp); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + Walker += StrLen(Temp) + 1; + FreePool(Temp); + Temp = NULL; + if (Argc == 6) { + Temp = StrnCatGrow(&Temp, NULL, Walker, StrStr(Walker, L" ")-Walker); + } else { + Temp = StrnCatGrow(&Temp, NULL, Walker, 0); + } + if (EFI_ERROR (NetLibStrToIp4 (Temp, &Gateway.v4))) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_IP_STR), gShellNetwork1HiiHandle, Temp); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + if (Argc == 6) { + Walker += StrLen(Temp) + 1; + FreePool(Temp); + Temp = NULL; + Temp = StrnCatGrow(&Temp, NULL, Walker, 0); + + PermTemp = PermanentString; + if (StringNoCaseCompare(&Temp, &PermTemp) != 0) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_OP2), gShellNetwork1HiiHandle, Temp, PermanentString, L"Nothing"); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + Permanent = TRUE; + } + + NetworkBytes1 = NTOHL (Ip.Addr[0]); + NetworkBytes2 = NTOHL (Mask.Addr[0]); + if ((Ip.Addr[0] == 0) || (Mask.Addr[0] == 0) || + !NetIp4IsUnicast (NetworkBytes1, NetworkBytes2)) { + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_ADDR_PAIR), gShellNetwork1HiiHandle); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + NetworkBytes1 = NTOHL (Gateway.Addr[0]); + if (!IP4_NET_EQUAL (Ip.Addr[0], Gateway.Addr[0], Mask.Addr[0]) || + !NetIp4IsUnicast (NetworkBytes1, NetworkBytes2)) { + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_INVALID_GATEWAY), gShellNetwork1HiiHandle); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + // + // Set the configuration up, two route table entries are added: + // one for the direct connected network, and another for the + // default gateway. Remember, some structure members are cleared + // by AllocateZeroPool + // + Config->Source = IP4_CONFIG_SOURCE_STATIC; + Config->Ip4Info.RouteTableSize = 2; + + CopyMem (&Config->Ip4Info.StationAddress, &Ip.v4, sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&Config->Ip4Info.SubnetMask, &Mask.v4, sizeof (EFI_IPv4_ADDRESS)); + + Ip.Addr[0] = Ip.Addr[0] & Mask.Addr[0]; + + CopyMem (&Config->Ip4Info.RouteTable[0].SubnetAddress, &Ip.v4, sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&Config->Ip4Info.RouteTable[0].SubnetMask, &Mask.v4, sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&Config->Ip4Info.RouteTable[1].GatewayAddress, &Gateway.v4, sizeof (EFI_IPv4_ADDRESS)); + } else { + // neither static or DHCP. error. + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle); + ASSERT(ShellStatus == SHELL_INVALID_PARAMETER); + goto ON_EXIT; + } + + CopyMem (&Config->NicAddr, &Info->NicAddress, sizeof (NIC_ADDR)); + Config->Perment = Permanent; + + // + // Use HII service to set NIC address + // + ShellStatus = IfconfigSetNicAddrByHii (Info, Config); + if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_SET_FAIL), gShellNetwork1HiiHandle, ShellStatus^MAX_BIT); + goto ON_EXIT; + } + + Status = IfconfigStartIp4 (Info); + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + } + + if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_IP_CHILD_FAIL), gShellNetwork1HiiHandle, ShellStatus^MAX_BIT); + } + +ON_EXIT: + SHELL_FREE_NON_NULL(Config); + + return ShellStatus; +} + +/** + Show the address information for the nic specified. + + @param[in] Name A pointer to the string containg the nic's name, if NULL, + all nics' information is shown. +**/ +VOID +EFIAPI +IfconfigShowNicInfo ( + IN CONST CHAR16 *Name + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + NIC_INFO *NicInfo; + UINT32 Index; + EFI_IP4_IPCONFIG_DATA *Ip4Config; + EFI_IPv4_ADDRESS Gateway; + CONST CHAR16 *TempString; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &NicInfoList) { + NicInfo = BASE_CR (Entry, NIC_INFO, Link); + + TempString = (CHAR16*)NicInfo->Name; + if ((Name != NULL) && (StringNoCaseCompare (&Name, &TempString) != 0)) { + continue; + } + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_NIC_NAME), gShellNetwork1HiiHandle, NicInfo->Name); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN(STR_IFCONFIG_SHOW_MAC_ADDR), + gShellNetwork1HiiHandle, + (UINTN)NicInfo->NicAddress.MacAddr.Addr[0], + (UINTN)NicInfo->NicAddress.MacAddr.Addr[1], + (UINTN)NicInfo->NicAddress.MacAddr.Addr[2], + (UINTN)NicInfo->NicAddress.MacAddr.Addr[3], + (UINTN)NicInfo->NicAddress.MacAddr.Addr[4], + (UINTN)NicInfo->NicAddress.MacAddr.Addr[5] + ); + + Print (L" Media State: %s\n", NicInfo->MediaPresent ? L"Media present" : L"Media disconnected"); + + if (NicInfo->ConfigInfo == NULL) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_NIC_NOT_CONFIGURED), gShellNetwork1HiiHandle); + continue; + } + + if (NicInfo->ConfigInfo->Source == IP4_CONFIG_SOURCE_DHCP) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_CONFIG_SOURCE), gShellNetwork1HiiHandle, L"DHCP"); + } else if (NicInfo->ConfigInfo->Source == IP4_CONFIG_SOURCE_STATIC) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_CONFIG_SOURCE), gShellNetwork1HiiHandle, L"STATIC"); + } else { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_CONFIG_SOURCE), gShellNetwork1HiiHandle, L"Unknown"); + } + + ShellPrintHiiEx(-1, -1, NULL, + STRING_TOKEN (STR_IFCONFIG_PERMENT_STATUS), + gShellNetwork1HiiHandle, + (NicInfo->ConfigInfo->Perment? L"TRUE":L"FALSE") + ); + + Ip4Config = &NicInfo->ConfigInfo->Ip4Info; + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"IP address", + (UINTN)Ip4Config->StationAddress.Addr[0], + (UINTN)Ip4Config->StationAddress.Addr[1], + (UINTN)Ip4Config->StationAddress.Addr[2], + (UINTN)Ip4Config->StationAddress.Addr[3] + ); + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Mask", + (UINTN)Ip4Config->SubnetMask.Addr[0], + (UINTN)Ip4Config->SubnetMask.Addr[1], + (UINTN)Ip4Config->SubnetMask.Addr[2], + (UINTN)Ip4Config->SubnetMask.Addr[3] + ); + + ZeroMem (&Gateway, sizeof (EFI_IPv4_ADDRESS)); + + for (Index = 0; Index < Ip4Config->RouteTableSize; Index++) { + if ((CompareMem (&Ip4Config->RouteTable[Index].SubnetAddress, &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0) && + (CompareMem (&Ip4Config->RouteTable[Index].SubnetMask , &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0) ){ + CopyMem (&Gateway, &Ip4Config->RouteTable[Index].GatewayAddress, sizeof (EFI_IPv4_ADDRESS)); + } + } + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Gateway", + (UINTN)Gateway.Addr[0], + (UINTN)Gateway.Addr[1], + (UINTN)Gateway.Addr[2], + (UINTN)Gateway.Addr[3] + ); + + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_ROUTES_SIZE), gShellNetwork1HiiHandle, Ip4Config->RouteTableSize); + + for (Index = 0; Index < Ip4Config->RouteTableSize; Index++) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_ROUTES_ENTRY_INDEX), gShellNetwork1HiiHandle, Index); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Subnet", + (UINTN)Ip4Config->RouteTable[Index].SubnetAddress.Addr[0], + (UINTN)Ip4Config->RouteTable[Index].SubnetAddress.Addr[1], + (UINTN)Ip4Config->RouteTable[Index].SubnetAddress.Addr[2], + (UINTN)Ip4Config->RouteTable[Index].SubnetAddress.Addr[3] + ); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Netmask", + (UINTN)Ip4Config->RouteTable[Index].SubnetMask.Addr[0], + (UINTN)Ip4Config->RouteTable[Index].SubnetMask.Addr[1], + (UINTN)Ip4Config->RouteTable[Index].SubnetMask.Addr[2], + (UINTN)Ip4Config->RouteTable[Index].SubnetMask.Addr[3] + ); + + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR), + gShellNetwork1HiiHandle, + L"Gateway", + (UINTN)Ip4Config->RouteTable[Index].GatewayAddress.Addr[0], + (UINTN)Ip4Config->RouteTable[Index].GatewayAddress.Addr[1], + (UINTN)Ip4Config->RouteTable[Index].GatewayAddress.Addr[2], + (UINTN)Ip4Config->RouteTable[Index].GatewayAddress.Addr[3] + ); + } + } + + return ; +} + +/** + Clear address configuration for the nic specified. + + @param[in] Name A pointer to the string containg the nic's name, + if NULL, all nics address configurations are cleared. + + @retval EFI_SUCCESS The address configuration is cleared. + @return Some error occurs. +**/ +EFI_STATUS +EFIAPI +IfconfigClearNicAddr ( + IN CONST CHAR16 *Name + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + NIC_INFO *Info; + EFI_STATUS Status; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &NicInfoList) { + Info = BASE_CR (Entry, NIC_INFO, Link); + + if ((Name != NULL) && (StrCmp (Name, Info->Name) != 0)) { + continue; + } + +// if (Info->NicIp4Config == NULL) { + Status = IfconfigSetNicAddrByHii (Info, NULL); +// } else { +// Status = Info->NicIp4Config->SetInfo (Info->NicIp4Config, NULL, TRUE); +// } + + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; + +} + +/** + Function for 'ifconfig' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIfconfig ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + BOOLEAN ListOperation; + BOOLEAN ClearOperation; + BOOLEAN SetOperation; + CONST CHAR16 *Item; + LIST_ENTRY *Entry; + NIC_INFO *Info; + + InitializeListHead (&NicInfoList); + Status = EFI_INVALID_PARAMETER; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + + goto Done; + } + + ClearOperation = ShellCommandLineGetFlag(Package, L"-c"); + ListOperation = ShellCommandLineGetFlag(Package, L"-l"); + SetOperation = ShellCommandLineGetFlag(Package, L"-s"); + + if (ClearOperation && ListOperation + ||SetOperation && ListOperation + ||ClearOperation && SetOperation + ) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } else if (!ClearOperation && !ListOperation && !SetOperation) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + + Status = IfconfigGetAllNicInfoByHii (); + if (EFI_ERROR (Status)) { + if (mIp4ConfigExist) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_IFCONFIG_GET_NIC_FAIL), gShellNetwork1HiiHandle, Status); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROTOCOL_NF), gShellNetwork1HiiHandle, L"gEfiIp4ConfigProtocolGuid", &gEfiIp4ConfigProtocolGuid); + } + + return SHELL_NOT_FOUND; + } + + if (ListOperation) { + Item = ShellCommandLineGetValue (Package, L"-l"); + + if (Item != NULL && CountSubItems(Item) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, L"-l"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + // + // Show the configuration. + // + IfconfigShowNicInfo (Item); + } else if (SetOperation) { + Item = ShellCommandLineGetValue (Package, L"-s"); + + // + // The correct command line arguments for setting address are: + // IfConfig -s eth0 DHCP [perment] + // IfConfig -s eth0 static ip netmask gateway [perment] + // + if (Item == NULL || (CountSubItems(Item) < 2) || (CountSubItems(Item) > 6) || (CountSubItems(Item) == 4)) { + ShellPrintHiiEx(-1, -1, NULL,STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + ShellStatus = IfconfigSetNicAddr (CountSubItems(Item), Item); + } else if (ClearOperation) { + Item = ShellCommandLineGetValue (Package, L"-c"); + + if (Item != NULL && CountSubItems(Item) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellNetwork1HiiHandle, L"-c"); + ShellStatus = SHELL_INVALID_PARAMETER; + goto Done; + } + + IfconfigClearNicAddr (Item); + } else { + ASSERT(FALSE); + } + +Done: + while (!IsListEmpty (&NicInfoList)) { + Entry = NicInfoList.ForwardLink; + Info = BASE_CR (Entry, NIC_INFO, Link); + + RemoveEntryList (Entry); + + if (Info->ConfigInfo != NULL) { + FreePool (Info->ConfigInfo); + } + + FreePool (Info); + } + + if (Package != NULL) { + ShellCommandLineFreeVarList(Package); + } + + return (ShellStatus); +} diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ipf/Itc.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ipf/Itc.c new file mode 100644 index 0000000000..131e5c0e30 --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ipf/Itc.c @@ -0,0 +1,28 @@ +/** @file + The implement to read ITC in IA64 platform. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +/** + Reads and returns the current value of the Interval Timer Counter Register (ITC). + + @return The current value of ITC. + +**/ +UINT64 +ReadTime () +{ + return AsmReadItc (); +} diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c new file mode 100644 index 0000000000..493de26f8a --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c @@ -0,0 +1,1563 @@ +/** @file + The implementation for Ping shell command. + + Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UefiShellNetwork1CommandsLib.h" + +#define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS))) + + +// +// Function templates to match the IPv4 and IPv6 commands that we use. +// +typedef +EFI_STATUS +(EFIAPI *PING_IPX_POLL)( + IN VOID *This + ); + +typedef +EFI_STATUS +(EFIAPI *PING_IPX_TRANSMIT)( + IN VOID *This, + IN VOID *Token + ); + +typedef +EFI_STATUS +(EFIAPI *PING_IPX_RECEIVE)( + IN VOID *This, + IN VOID *Token + ); + +typedef +EFI_STATUS +(EFIAPI *PING_IPX_CANCEL)( + IN VOID *This, + IN VOID *Token OPTIONAL + ); + +/// +/// A set of pointers to either IPv6 or IPv4 functions. +/// Unknown which one to the ping command. +/// +typedef struct { + PING_IPX_TRANSMIT Transmit; + PING_IPX_RECEIVE Receive; + PING_IPX_CANCEL Cancel; + PING_IPX_POLL Poll; +}PING_IPX_PROTOCOL; + + +typedef union { + VOID *RxData; + VOID *TxData; +} PING_PACKET; + +// +// PING_IPX_COMPLETION_TOKEN +// structures are used for both transmit and receive operations. +// This version is IP-unaware. +// +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; + PING_PACKET Packet; +} PING_IPX_COMPLETION_TOKEN; + +#pragma pack(1) +typedef struct _ICMPX_ECHO_REQUEST_REPLY { + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + UINT16 Identifier; + UINT16 SequenceNum; + UINT64 TimeStamp; + UINT8 Data[1]; +} ICMPX_ECHO_REQUEST_REPLY; +#pragma pack() + +typedef struct _PING_ICMP_TX_INFO { + LIST_ENTRY Link; + UINT16 SequenceNum; + UINT64 TimeStamp; + PING_IPX_COMPLETION_TOKEN *Token; +} PING_ICMPX_TX_INFO; + +#define DEFAULT_TIMEOUT 5000 +#define MAX_SEND_NUMBER 10000 +#define MAX_BUFFER_SIZE 32768 +#define DEFAULT_TIMER_PERIOD 358049 +#define ONE_SECOND 10000000 +#define PING_IP_CHOICE_IP4 1 +#define PING_IP_CHOICE_IP6 2 +#define DEFAULT_SEND_COUNT 10 +#define DEFAULT_BUFFER_SIZE 16 +#define ICMP_V4_ECHO_REQUEST 0x8 +#define ICMP_V4_ECHO_REPLY 0x0 + +#define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g') +typedef struct _PING_PRIVATE_DATA { + UINT32 Signature; + EFI_HANDLE NicHandle; + EFI_HANDLE IpChildHandle; + EFI_EVENT Timer; + + EFI_STATUS Status; + LIST_ENTRY TxList; + UINT16 RxCount; + UINT16 TxCount; + UINT64 RttSum; + UINT64 RttMin; + UINT64 RttMax; + UINT32 SequenceNum; + + UINT32 SendNum; + UINT32 BufferSize; + UINT32 IpChoice; + + PING_IPX_PROTOCOL ProtocolPointers; + VOID *IpProtocol; + UINT8 SrcAddress[MAX(sizeof(EFI_IPv6_ADDRESS) , sizeof(EFI_IPv4_ADDRESS) )]; + UINT8 DstAddress[MAX(sizeof(EFI_IPv6_ADDRESS) , sizeof(EFI_IPv4_ADDRESS) )]; + PING_IPX_COMPLETION_TOKEN RxToken; +} PING_PRIVATE_DATA; + +UINT16 +EFIAPI +NetChecksum ( + IN UINT8 *Buffer, + IN UINT32 Length + ) +/*++ + +Routine Description: + + Calculate the internet checksum (see RFC 1071) + +Arguments: + + Packet - Buffer which contains the data to be checksummed + Length - Length to be checksummed + +Returns: + + Checksum - Returns the 16 bit ones complement of + ones complement sum of 16 bit words + +--*/ +{ + UINT32 Sum; + UINT8 Odd; + UINT16 *Packet; + + Packet = (UINT16 *) Buffer; + + Sum = 0; + Odd = (UINT8) (Length & 1); + Length >>= 1; + while (Length--) { + Sum += *Packet++; + } + + if (Odd) { + Sum += *(UINT8 *) Packet; + } + + Sum = (Sum & 0xffff) + (Sum >> 16); + + // + // in case above carried + // + Sum += Sum >> 16; + + return (UINT16) Sum; +} + +/** + Reads and returns the current value of register. + In IA64, the register is the Interval Timer Vector (ITV). + In X86(IA32/X64), the register is the Time Stamp Counter (TSC) + + @return The current value of the register. + +**/ +UINT64 +EFIAPI +ReadTime ( + VOID + ); + +STATIC CONST SHELL_PARAM_ITEM PingParamList[] = { + { + L"-l", + TypeValue + }, + { + L"-n", + TypeValue + }, + { + L"-_s", + TypeValue + }, + { + L"-_ip6", + TypeFlag + }, + { + NULL, + TypeMax + }, +}; + +// +// Global Variables in Ping command. +// +STATIC CONST CHAR16 *mDstString; +STATIC CONST CHAR16 *mSrcString; +STATIC UINT64 mFrequency = 0; + +/** + Get and caculate the frequency in tick/ms. + The result is saved in the globle variable mFrequency + + @retval EFI_SUCCESS Caculated the frequency successfully. + @retval Others Failed to caculate the frequency. + +**/ +EFI_STATUS +EFIAPI +GetFrequency ( + VOID + ) +{ + EFI_STATUS Status; + EFI_CPU_ARCH_PROTOCOL *Cpu; + UINT64 CurrentTick; + UINT64 TimerPeriod; + + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod); + + if (EFI_ERROR (Status)) { + TimerPeriod = DEFAULT_TIMER_PERIOD; + } + + // + // The timer period is in femtosecond (1 femtosecond is 1e-15 second). + // So 1e+12 is divided by timer period to produce the freq in tick/ms. + // + mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL); + + return EFI_SUCCESS; +} + +/** + Caculate a duration in ms. + + @param[in] Begin The start point of time. + @param[in] End The end point of time. + + @return The duration in ms. + @retval 0 The parameters were not valid. +**/ +UINT64 +EFIAPI +CalculateTick ( + IN UINT64 Begin, + IN UINT64 End + ) +{ + if (End <= Begin) { + return (0); + } + return DivU64x64Remainder (End - Begin, mFrequency, NULL); +} + +/** + Destroy PING_ICMPX_TX_INFO, and recollect the memory. + + @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO. + @param[in] IpChoice Whether the token is IPv4 or IPv6 +**/ +VOID +EFIAPI +PingDestroyTxInfo ( + IN PING_ICMPX_TX_INFO *TxInfo, + IN UINT32 IpChoice + ) +{ + EFI_IP6_TRANSMIT_DATA *Ip6TxData; + EFI_IP4_TRANSMIT_DATA *Ip4TxData; + EFI_IP6_FRAGMENT_DATA *FragData; + UINTN Index; + + if (TxInfo == NULL) { + return; + } + + if (TxInfo->Token != NULL) { + + if (TxInfo->Token->Event != NULL) { + gBS->CloseEvent (TxInfo->Token->Event); + } + + if (TxInfo->Token->Packet.TxData != NULL) { + if (IpChoice == PING_IP_CHOICE_IP6) { + Ip6TxData = TxInfo->Token->Packet.TxData; + + if (Ip6TxData->OverrideData != NULL) { + FreePool (Ip6TxData->OverrideData); + } + + if (Ip6TxData->ExtHdrs != NULL) { + FreePool (Ip6TxData->ExtHdrs); + } + + for (Index = 0; Index < Ip6TxData->FragmentCount; Index++) { + FragData = Ip6TxData->FragmentTable[Index].FragmentBuffer; + if (FragData != NULL) { + FreePool (FragData); + } + } + } else { + Ip4TxData = TxInfo->Token->Packet.TxData; + + if (Ip4TxData->OverrideData != NULL) { + FreePool (Ip4TxData->OverrideData); + } + + for (Index = 0; Index < Ip4TxData->FragmentCount; Index++) { + FragData = Ip4TxData->FragmentTable[Index].FragmentBuffer; + if (FragData != NULL) { + FreePool (FragData); + } + } + } + } + + FreePool (TxInfo->Token); + } + + FreePool (TxInfo); +} + +/** + Match the request, and reply with SequenceNum/TimeStamp. + + @param[in] Private The pointer to PING_PRIVATE_DATA. + @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY. + + @retval EFI_SUCCESS The match is successful. + @retval EFI_NOT_FOUND The reply can't be matched with any request. + +**/ +EFI_STATUS +EFIAPI +Ping6MatchEchoReply ( + IN PING_PRIVATE_DATA *Private, + IN ICMPX_ECHO_REQUEST_REPLY *Packet + ) +{ + PING_ICMPX_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link); + + if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) { + Private->RxCount++; + RemoveEntryList (&TxInfo->Link); + PingDestroyTxInfo (TxInfo, Private->IpChoice); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + The original intention is to send a request. + Currently, the application retransmits an icmp6 echo request packet + per second in sendnumber times that is specified by the user. + Because nothing can be done here, all things move to the timer rountine. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6OnEchoRequestSent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ +} + +/** + receive reply, match and print reply infomation. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to context. + +**/ +VOID +EFIAPI +Ping6OnEchoReplyReceived ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + PING_PRIVATE_DATA *Private; + ICMPX_ECHO_REQUEST_REPLY *Reply; + UINT32 PayLoad; + UINT64 Rtt; + CHAR8 Near; + + Private = (PING_PRIVATE_DATA *) Context; + + if (Private == NULL || Private->Status == EFI_ABORTED || Private->Signature != PING_PRIVATE_DATA_SIGNATURE) { + return; + } + + if (Private->RxToken.Packet.RxData == NULL) { + return; + } + + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + Reply = ((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer; + PayLoad = ((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->DataLength; + if (((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->NextHeader != IP6_ICMP) { + goto ON_EXIT; + } + if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS*)&Private->DstAddress) && + !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv6_ADDRESS*)&Private->DstAddress)) { + goto ON_EXIT; + } + + if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) { + goto ON_EXIT; + } + } else { + Reply = ((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->FragmentTable[0].FragmentBuffer; + PayLoad = ((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->DataLength; + if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS*)Private->DstAddress)) && + !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->SourceAddress, (EFI_IPv4_ADDRESS*)&Private->DstAddress)) { + goto ON_EXIT; + } + + if ((Reply->Type != ICMP_V4_ECHO_REPLY) || (Reply->Code != 0)) { + goto ON_EXIT; + } + } + + + if (PayLoad != Private->BufferSize) { + goto ON_EXIT; + } + // + // Check whether the reply matches the sent request before. + // + Status = Ping6MatchEchoReply (Private, Reply); + if (EFI_ERROR(Status)) { + goto ON_EXIT; + } + // + // Display statistics on this icmp6 echo reply packet. + // + Rtt = CalculateTick (Reply->TimeStamp, ReadTime ()); + if (Rtt != 0) { + Near = (CHAR8) '='; + } else { + Near = (CHAR8) '<'; + } + + Private->RttSum += Rtt; + Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin; + Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax; + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING_REPLY_INFO), + gShellNetwork1HiiHandle, + PayLoad, + mDstString, + Reply->SequenceNum, + Private->IpChoice == PING_IP_CHOICE_IP6?((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->HopLimit:0, + Near, + Rtt + ); + +ON_EXIT: + + if (Private->RxCount < Private->SendNum) { + // + // Continue to receive icmp echo reply packets. + // + Private->RxToken.Status = EFI_ABORTED; + + Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken); + + if (EFI_ERROR (Status)) { + Private->Status = EFI_ABORTED; + } + } else { + // + // All reply have already been received from the dest host. + // + Private->Status = EFI_SUCCESS; + } + // + // Singal to recycle the each rxdata here, not at the end of process. + // + 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); +} + +/** + Create a PING_IPX_COMPLETION_TOKEN. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + @param[in] TimeStamp The TimeStamp of request. + @param[in] SequenceNum The SequenceNum of request. + + @return The pointer of PING_IPX_COMPLETION_TOKEN. + +**/ +PING_IPX_COMPLETION_TOKEN * +EFIAPI +PingGenerateToken ( + IN PING_PRIVATE_DATA *Private, + IN UINT64 TimeStamp, + IN UINT16 SequenceNum + ) +{ + EFI_STATUS Status; + PING_IPX_COMPLETION_TOKEN *Token; + VOID *TxData; + ICMPX_ECHO_REQUEST_REPLY *Request; + UINT16 HeadSum; + UINT16 TempChecksum; + + Request = AllocateZeroPool (Private->BufferSize); + if (Request == NULL) { + return NULL; + } + TxData = AllocateZeroPool (Private->IpChoice==PING_IP_CHOICE_IP6?sizeof (EFI_IP6_TRANSMIT_DATA):sizeof (EFI_IP4_TRANSMIT_DATA)); + if (TxData == NULL) { + FreePool (Request); + return NULL; + } + Token = AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN)); + if (Token == NULL) { + FreePool (Request); + FreePool (TxData); + return NULL; + } + + // + // Assembly echo request packet. + // + Request->Type = (UINT8)(Private->IpChoice==PING_IP_CHOICE_IP6?ICMP_V6_ECHO_REQUEST:ICMP_V4_ECHO_REQUEST); + Request->Code = 0; + Request->SequenceNum = SequenceNum; + Request->Identifier = 0; + Request->Checksum = 0; + + // + // Assembly token for transmit. + // + if (Private->IpChoice==PING_IP_CHOICE_IP6) { + ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrsLength = 0; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrs = NULL; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->OverrideData = 0; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->DataLength = Private->BufferSize; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentCount = 1; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentBuffer = (VOID *) Request; + ((EFI_IP6_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize; + } else { + ((EFI_IP4_TRANSMIT_DATA*)TxData)->OptionsLength = 0; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->OptionsBuffer = NULL; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->OverrideData = 0; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->TotalDataLength = Private->BufferSize; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentCount = 1; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentBuffer = (VOID *) Request; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->FragmentTable[0].FragmentLength = Private->BufferSize; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[0] = Private->DstAddress[0]; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[1] = Private->DstAddress[1]; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[2] = Private->DstAddress[2]; + ((EFI_IP4_TRANSMIT_DATA*)TxData)->DestinationAddress.Addr[3] = Private->DstAddress[3]; + + HeadSum = NetChecksum ((UINT8 *) Request, Private->BufferSize); + Request->TimeStamp = TimeStamp; + TempChecksum = NetChecksum ((UINT8 *) &Request->TimeStamp, sizeof (UINT64)); + Request->Checksum = (UINT16)(~NetAddChecksum (HeadSum, TempChecksum)); + } + + + Token->Status = EFI_ABORTED; + Token->Packet.TxData = TxData; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnEchoRequestSent, + Private, + &Token->Event + ); + + if (EFI_ERROR (Status)) { + FreePool (Request); + FreePool (TxData); + FreePool (Token); + return NULL; + } + + return Token; +} + +/** + Transmit the PING_IPX_COMPLETION_TOKEN. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + + @retval EFI_SUCCESS Transmitted successfully. + @retval EFI_OUT_OF_RESOURCES No memory is available on the platform. + @retval others Transmitted unsuccessfully. + +**/ +EFI_STATUS +EFIAPI +PingSendEchoRequest ( + IN PING_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + PING_ICMPX_TX_INFO *TxInfo; + + TxInfo = AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO)); + + if (TxInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TxInfo->TimeStamp = ReadTime (); + TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1); + TxInfo->Token = PingGenerateToken ( + Private, + TxInfo->TimeStamp, + TxInfo->SequenceNum + ); + + if (TxInfo->Token == NULL) { + PingDestroyTxInfo (TxInfo, Private->IpChoice); + return EFI_OUT_OF_RESOURCES; + } + + ASSERT(Private->ProtocolPointers.Transmit != NULL); + Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token); + + if (EFI_ERROR (Status)) { + PingDestroyTxInfo (TxInfo, Private->IpChoice); + return Status; + } + + InsertTailList (&Private->TxList, &TxInfo->Link); + Private->TxCount++; + + return EFI_SUCCESS; +} + +/** + Place a completion token into the receive packet queue to receive the echo reply. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + + @retval EFI_SUCCESS Put the token into the receive packet queue successfully. + @retval others Put the token into the receive packet queue unsuccessfully. + +**/ +EFI_STATUS +EFIAPI +Ping6ReceiveEchoReply ( + IN PING_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + + ZeroMem (&Private->RxToken, sizeof (PING_IPX_COMPLETION_TOKEN)); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnEchoReplyReceived, + Private, + &Private->RxToken.Event + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Private->RxToken.Status = EFI_NOT_READY; + + return (Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken)); +} + +/** + Remove the timeout request from the list. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6OnTimerRoutine ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + PING_PRIVATE_DATA *Private; + PING_ICMPX_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + UINT64 Time; + + Private = (PING_PRIVATE_DATA *) Context; + if (Private->Signature != PING_PRIVATE_DATA_SIGNATURE) { + Private->Status = EFI_NOT_FOUND; + return; + } + + // + // Retransmit icmp6 echo request packets per second in sendnumber times. + // + if (Private->TxCount < Private->SendNum) { + + Status = PingSendEchoRequest (Private); + if (Private->TxCount != 0){ + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_SEND_REQUEST), gShellNetwork1HiiHandle, Private->TxCount + 1); + } + } + } + // + // Check whether any icmp6 echo request in the list timeout. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link); + Time = CalculateTick (TxInfo->TimeStamp, ReadTime ()); + + // + // Remove the timeout echo request from txlist. + // + if (Time > DEFAULT_TIMEOUT) { + + if (EFI_ERROR (TxInfo->Token->Status)) { + Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token); + } + // + // Remove the timeout icmp6 echo request from list. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_TIMEOUT), gShellNetwork1HiiHandle, TxInfo->SequenceNum); + + RemoveEntryList (&TxInfo->Link); + PingDestroyTxInfo (TxInfo, Private->IpChoice); + + // + // We dont need to wait for this some other time... + // + Private->RxCount++; + + if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) { + // + // All the left icmp6 echo request in the list timeout. + // + Private->Status = EFI_TIMEOUT; + } + } + } +} + +/** + Determine if a IP4 address is Link Local. + + 169.254.1.0 through 169.254.254.255 is link local. + + @param[in] Address The address to test. + + @retval TRUE It is. + @retval FALSE It is not. +**/ +BOOLEAN +EFIAPI +PingNetIp4IsLinkLocalAddr ( + IN CONST EFI_IPv4_ADDRESS *Address + ) +{ + return ((BOOLEAN)(Address->Addr[0] == 169 && Address->Addr[1] == 254 && Address->Addr[2] >= 1 && Address->Addr[2] <= 254)); +} + +/** + Determine if a IP4 address is unspecified. + + @param[in] Address The address to test. + + @retval TRUE It is. + @retval FALSE It is not. +**/ +BOOLEAN +EFIAPI +PingNetIp4IsUnspecifiedAddr ( + IN CONST EFI_IPv4_ADDRESS *Address + ) +{ + return ((BOOLEAN)((ReadUnaligned32 ((UINT32*)&Address->Addr[0])) == 0x00000000)); +} + +/** + Create a valid IP instance. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + + @retval EFI_SUCCESS Create a valid IPx instance successfully. + @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully. + @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address. + @retval EFI_OUT_OF_RESOURCES No memory is available on the platform. + @retval EFI_NOT_FOUND The source address is not found. +**/ +EFI_STATUS +EFIAPI +PingCreateIpInstance ( + IN PING_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + UINTN HandleNum; + EFI_HANDLE *HandleBuffer; + EFI_SERVICE_BINDING_PROTOCOL *EfiSb; + VOID *IpXCfg; + EFI_IP6_CONFIG_DATA Ip6Config; + EFI_IP4_CONFIG_DATA Ip4Config; + VOID *IpXInterfaceInfo; + UINTN IfInfoSize; + EFI_IPv6_ADDRESS *Addr; + UINTN AddrIndex; + + HandleBuffer = NULL; + EfiSb = NULL; + IpXInterfaceInfo = NULL; + IfInfoSize = 0; + + // + // Locate all the handles with ip6 service binding protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid, + NULL, + &HandleNum, + &HandleBuffer + ); + if (EFI_ERROR (Status) || (HandleNum == 0)) { + return EFI_ABORTED; + } + // + // Source address is required when pinging a link-local address on multi- + // interfaces host. + // + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS*)&Private->DstAddress) && + NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress) && + (HandleNum > 1)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, mSrcString); + Status = EFI_INVALID_PARAMETER; + goto ON_ERROR; + } + } else { + ASSERT(Private->IpChoice == PING_IP_CHOICE_IP4); + if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS*)&Private->DstAddress) && + PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&Private->SrcAddress) && + (HandleNum > 1)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, mSrcString); + Status = EFI_INVALID_PARAMETER; + goto ON_ERROR; + } + } + // + // For each ip6 protocol, check interface addresses list. + // + for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) { + + EfiSb = NULL; + IpXInterfaceInfo = NULL; + IfInfoSize = 0; + + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid, + (VOID **) &EfiSb + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + if (Private->IpChoice == PING_IP_CHOICE_IP6?NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress):PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&Private->SrcAddress)) { + // + // No need to match interface address. + // + break; + } else { + // + // Ip6config protocol and ip6 service binding protocol are installed + // on the same handle. + // + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ConfigProtocolGuid:&gEfiIp4ConfigProtocolGuid, + (VOID **) &IpXCfg + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + // + // Get the interface information size. + // + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData ( + IpXCfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + NULL + ); + } else { + Status = ((EFI_IP4_CONFIG_PROTOCOL*)IpXCfg)->GetData ( + IpXCfg, + &IfInfoSize, + NULL + ); + } + + // + // Skip the ones not in current use. + // + if (Status == EFI_NOT_STARTED) { + continue; + } + + if (Status != EFI_BUFFER_TOO_SMALL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status); + goto ON_ERROR; + } + + IpXInterfaceInfo = AllocateZeroPool (IfInfoSize); + + if (IpXInterfaceInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // + // Get the interface info. + // + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData ( + IpXCfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + IpXInterfaceInfo + ); + } else { + Status = ((EFI_IP4_CONFIG_PROTOCOL*)IpXCfg)->GetData ( + IpXCfg, + &IfInfoSize, + IpXInterfaceInfo + ); + } + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status); + goto ON_ERROR; + } + // + // Check whether the source address is one of the interface addresses. + // + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + for (AddrIndex = 0; AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount; AddrIndex++) { + + Addr = &(((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfo[AddrIndex].Address); + if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) { + // + // Match a certain interface address. + // + break; + } + } + + if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount) { + // + // Found a nic handle with right interface address. + // + break; + } + } else { + // + // IP4 address check + // + if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_IPCONFIG_DATA*)IpXInterfaceInfo)->StationAddress)) { + // + // Match a certain interface address. + // + break; + } + } + } + + FreePool (IpXInterfaceInfo); + IpXInterfaceInfo = NULL; + } + // + // No exact interface address matched. + // + + if (HandleIndex == HandleNum) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, mSrcString); + Status = EFI_NOT_FOUND; + goto ON_ERROR; + } + + Private->NicHandle = HandleBuffer[HandleIndex]; + + ASSERT (EfiSb != NULL); + Status = EfiSb->CreateChild (EfiSb, &Private->IpChildHandle); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + if (Private->IpChoice == PING_IP_CHOICE_IP6) { + Status = gBS->OpenProtocol ( + Private->IpChildHandle, + &gEfiIp6ProtocolGuid, + &Private->IpProtocol, + gImageHandle, + Private->IpChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + + ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA)); + + // + // Configure the ip6 instance for icmp6 packet exchange. + // + Ip6Config.DefaultProtocol = 58; + Ip6Config.AcceptAnyProtocol = FALSE; + Ip6Config.AcceptIcmpErrors = TRUE; + Ip6Config.AcceptPromiscuous = FALSE; + Ip6Config.TrafficClass = 0; + Ip6Config.HopLimit = 128; + Ip6Config.FlowLabel = 0; + Ip6Config.ReceiveTimeout = 0; + Ip6Config.TransmitTimeout = 0; + + IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress); + IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress); + + Status = ((EFI_IP6_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip6Config); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status); + goto ON_ERROR; + } + + Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Transmit; + Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Receive; + Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Cancel; + Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP6_PROTOCOL*)Private->IpProtocol)->Poll; + } else { + Status = gBS->OpenProtocol ( + Private->IpChildHandle, + &gEfiIp4ProtocolGuid, + &Private->IpProtocol, + gImageHandle, + Private->IpChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + + ZeroMem (&Ip4Config, sizeof (EFI_IP4_CONFIG_DATA)); + + // + // Configure the ip4 instance for icmp4 packet exchange. + // +// PING_IP4_COPY_ADDRESS (&Ip4Config.StationAddress, &Private->SrcAddress); +// Ip4Config.SubnetMask.Addr[0] = 0xFF; +// Ip4Config.SubnetMask.Addr[1] = 0xFF; +// Ip4Config.SubnetMask.Addr[2] = 0xFF; +// Ip4Config.SubnetMask.Addr[3] = 0x00; + Ip4Config.DefaultProtocol = 1; + Ip4Config.AcceptAnyProtocol = FALSE; + Ip4Config.AcceptBroadcast = FALSE; + Ip4Config.AcceptIcmpErrors = TRUE; + Ip4Config.AcceptPromiscuous = FALSE; + Ip4Config.DoNotFragment = FALSE; + Ip4Config.RawData = FALSE; + Ip4Config.ReceiveTimeout = 0; + Ip4Config.TransmitTimeout = 0; + Ip4Config.UseDefaultAddress = TRUE; + Ip4Config.TimeToLive = 128; + Ip4Config.TypeOfService = 0; + + Status = ((EFI_IP4_PROTOCOL*)(Private->IpProtocol))->Configure (Private->IpProtocol, &Ip4Config); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIG), gShellNetwork1HiiHandle, Status); + goto ON_ERROR; + } + + Private->ProtocolPointers.Transmit = (PING_IPX_TRANSMIT )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Transmit; + Private->ProtocolPointers.Receive = (PING_IPX_RECEIVE )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Receive; + Private->ProtocolPointers.Cancel = (PING_IPX_CANCEL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Cancel; + Private->ProtocolPointers.Poll = (PING_IPX_POLL )((EFI_IP4_PROTOCOL*)Private->IpProtocol)->Poll; + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; + +ON_ERROR: + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + if (IpXInterfaceInfo != NULL) { + FreePool (IpXInterfaceInfo); + } + + if ((EfiSb != NULL) && (Private->IpChildHandle != NULL)) { + EfiSb->DestroyChild (EfiSb, Private->IpChildHandle); + } + + return Status; +} + +/** + Destory the IP instance. + + @param[in] Private The pointer of PING_PRIVATE_DATA. + +**/ +VOID +EFIAPI +Ping6DestoryIp6Instance ( + IN PING_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + EFI_SERVICE_BINDING_PROTOCOL *IpSb; + + gBS->CloseProtocol ( + Private->IpChildHandle, + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ProtocolGuid:&gEfiIp4ProtocolGuid, + gImageHandle, + Private->IpChildHandle + ); + + Status = gBS->HandleProtocol ( + Private->NicHandle, + Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid, + (VOID **) &IpSb + ); + + if (!EFI_ERROR(Status)) { + IpSb->DestroyChild (IpSb, Private->IpChildHandle); + } +} + +/** + The Ping Process. + + @param[in] SendNumber The send request count. + @param[in] BufferSize The send buffer size. + @param[in] SrcAddress The source address. + @param[in] DstAddress The destination address. + @param[in] IpChoice The choice between IPv4 and IPv6. + + @retval SHELL_SUCCESS The ping processed successfullly. + @retval others The ping processed unsuccessfully. +**/ +SHELL_STATUS +EFIAPI +ShellPing ( + IN UINT32 SendNumber, + IN UINT32 BufferSize, + IN EFI_IPv6_ADDRESS *SrcAddress, + IN EFI_IPv6_ADDRESS *DstAddress, + IN UINT32 IpChoice + ) +{ + EFI_STATUS Status; + PING_PRIVATE_DATA *Private; + PING_ICMPX_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + Private = AllocateZeroPool (sizeof (PING_PRIVATE_DATA)); + + if (Private == NULL) { + return (SHELL_OUT_OF_RESOURCES); + } + + Private->IpChoice = IpChoice; + Private->Signature = PING_PRIVATE_DATA_SIGNATURE; + Private->SendNum = SendNumber; + Private->BufferSize = BufferSize; + Private->RttMin = ~((UINT64 )(0x0)); + Private->Status = EFI_NOT_READY; + + CopyMem(&Private->SrcAddress, SrcAddress, sizeof(Private->SrcAddress)); + CopyMem(&Private->DstAddress, DstAddress, sizeof(Private->DstAddress)); + + InitializeListHead (&Private->TxList); + + // + // Open and configure a ip instance for us. + // + Status = PingCreateIpInstance (Private); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Print the command line itself. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_START), gShellNetwork1HiiHandle, mDstString, Private->BufferSize); + // + // Create a ipv6 token to receive the first icmp6 echo reply packet. + // + Status = Ping6ReceiveEchoReply (Private); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Create and start timer to send icmp6 echo request packet per second. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnTimerRoutine, + Private, + &Private->Timer + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Create a ipv6 token to send the first icmp6 echo request packet. + // + Status = PingSendEchoRequest (Private); + // + // EFI_NOT_READY for IPsec is enable and IKE is not established. + // + if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) { + ShellStatus = SHELL_ACCESS_DENIED; + if(Status == EFI_NOT_FOUND) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOSOURCE_INDO), gShellNetwork1HiiHandle, mDstString); + } else if (Status == RETURN_NO_MAPPING) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOROUTE_FOUND), gShellNetwork1HiiHandle, mDstString, mSrcString); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, Status); + } + + goto ON_EXIT; + } + + Status = gBS->SetTimer ( + Private->Timer, + TimerPeriodic, + ONE_SECOND + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Control the ping6 process by two factors: + // 1. Hot key + // 2. Private->Status + // 2.1. success means all icmp6 echo request packets get reply packets. + // 2.2. timeout means the last icmp6 echo reply request timeout to get reply. + // 2.3. noready means ping6 process is on-the-go. + // + while (Private->Status == EFI_NOT_READY) { + Status = Private->ProtocolPointers.Poll (Private->IpProtocol); + if (ShellGetExecutionBreakFlag()) { + Private->Status = EFI_ABORTED; + goto ON_STAT; + } + } + +ON_STAT: + // + // Display the statistics in all. + // + gBS->SetTimer (Private->Timer, TimerCancel, 0); + + if (Private->TxCount != 0) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING_STAT), + gShellNetwork1HiiHandle, + Private->TxCount, + Private->RxCount, + (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount, + Private->RttSum + ); + } + + if (Private->RxCount != 0) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING_RTT), + gShellNetwork1HiiHandle, + Private->RttMin, + Private->RttMax, + DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL) + ); + } + +ON_EXIT: + + if (Private != NULL) { + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link); + + if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) { + Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, TxInfo->Token); + } + + RemoveEntryList (&TxInfo->Link); + PingDestroyTxInfo (TxInfo, Private->IpChoice); + } + + if (Private->Timer != NULL) { + gBS->CloseEvent (Private->Timer); + } + + if (Private->IpProtocol != NULL && Private->ProtocolPointers.Cancel != NULL) { + Status = Private->ProtocolPointers.Cancel (Private->IpProtocol, &Private->RxToken); + } + + if (Private->RxToken.Event != NULL) { + gBS->CloseEvent (Private->RxToken.Event); + } + + if (Private->IpChildHandle != NULL) { + Ping6DestoryIp6Instance (Private); + } + + FreePool (Private); + } + + return ShellStatus; +} + +/** + Function for 'ping' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPing ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + EFI_IPv6_ADDRESS DstAddress; + EFI_IPv6_ADDRESS SrcAddress; + UINT64 BufferSize; + UINTN SendNumber; + LIST_ENTRY *ParamPackage; + CONST CHAR16 *ValueStr; + UINTN NonOptionCount; + UINT32 IpChoice; + + // + // we use IPv6 buffers to hold items... + // make sure this is enough space! + // + ASSERT(sizeof(EFI_IPv4_ADDRESS ) <= sizeof(EFI_IPv6_ADDRESS )); + ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN) <= sizeof(EFI_IP6_COMPLETION_TOKEN )); + + IpChoice = PING_IP_CHOICE_IP4; + + ShellStatus = SHELL_SUCCESS; + + Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, NULL, TRUE, FALSE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + if (ShellCommandLineGetFlag (ParamPackage, L"-_ip6")) { + IpChoice = PING_IP_CHOICE_IP6; + } + + // + // Parse the paramter of count number. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n"); + if (ValueStr != NULL) { + SendNumber = ShellStrToUintn (ValueStr); + + // + // ShellStrToUintn will return 0 when input is 0 or an invalid input string. + // + if ((SendNumber == 0) || (SendNumber > MAX_SEND_NUMBER)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } else { + SendNumber = DEFAULT_SEND_COUNT; + } + // + // Parse the paramter of buffer size. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l"); + if (ValueStr != NULL) { + BufferSize = ShellStrToUintn (ValueStr); + + // + // ShellStrToUintn will return 0 when input is 0 or an invalid input string. + // + if ((BufferSize < 16) || (BufferSize > MAX_BUFFER_SIZE)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } else { + BufferSize = DEFAULT_BUFFER_SIZE; + } + + ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS)); + ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS)); + + // + // Parse the paramter of source ip address. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-_s"); + if (ValueStr != NULL) { + mSrcString = ValueStr; + if (IpChoice == PING_IP_CHOICE_IP6) { + Status = NetLibStrToIp6 (ValueStr, &SrcAddress); + } else { + Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&SrcAddress); + } + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Parse the paramter of destination ip address. + // + NonOptionCount = ShellCommandLineGetCount(ParamPackage); + if (NonOptionCount < 2) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + if (NonOptionCount > 2) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1); + if (ValueStr != NULL) { + mDstString = ValueStr; + if (IpChoice == PING_IP_CHOICE_IP6) { + Status = NetLibStrToIp6 (ValueStr, &DstAddress); + } else { + Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&DstAddress); + } + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Get frequency to calculate the time from ticks. + // + Status = GetFrequency (); + + if (EFI_ERROR(Status)) { + goto ON_EXIT; + } + // + // Enter into ping process. + // + ShellStatus = ShellPing ( + (UINT32)SendNumber, + (UINT32)BufferSize, + &SrcAddress, + &DstAddress, + IpChoice + ); + +ON_EXIT: + ShellCommandLineFreeVarList (ParamPackage); + return ShellStatus; +} diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.c new file mode 100644 index 0000000000..d8fa88db7e --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.c @@ -0,0 +1,94 @@ +/** @file + Main file for NULL named library for network1 shell command functions. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include "UefiShellNetwork1CommandsLib.h" + +CONST CHAR16 gShellNetwork1FileName[] = L"ShellCommands"; +EFI_HANDLE gShellNetwork1HiiHandle = NULL; +STATIC CONST EFI_GUID gShellNetwork1HiiGuid = \ + { \ + 0xf3d301bb, 0xf4a5, 0x45a8, { 0xb0, 0xb7, 0xfa, 0x99, 0x9c, 0x62, 0x37, 0xae } \ + }; + +/** + return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameNetwork1 ( + VOID + ) +{ + return (gShellNetwork1FileName); +} + +/** + Constructor for the Shell Network1 Commands library. + + Install the handlers for Network1 UEFI Shell 2.0 profile commands. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS The shell command handlers were installed sucessfully. + @retval EFI_UNSUPPORTED The shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellNetwork1CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gShellNetwork1HiiHandle = NULL; + + // + // check our bit of the profiles mask + // + if ((PcdGet8(PcdShellProfileMask) & BIT3) == 0) { + return (EFI_UNSUPPORTED); + } + + gShellNetwork1HiiHandle = HiiAddPackages (&gShellNetwork1HiiGuid, gImageHandle, UefiShellNetwork1CommandsLibStrings, NULL); + if (gShellNetwork1HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + // + // install our shell command handlers + // + ShellCommandRegisterCommandName(L"ping", ShellCommandRunPing , ShellCommandGetManFileNameNetwork1, 0, L"network1", TRUE , gShellNetwork1HiiHandle, STRING_TOKEN(STR_GET_HELP_PING)); + ShellCommandRegisterCommandName(L"ifconfig",ShellCommandRunIfconfig , ShellCommandGetManFileNameNetwork1, 0, L"network1", TRUE , gShellNetwork1HiiHandle, STRING_TOKEN(STR_GET_HELP_IFCONFIG)); + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +ShellNetwork1CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellNetwork1HiiHandle != NULL) { + HiiRemovePackages(gShellNetwork1HiiHandle); + } + return (EFI_SUCCESS); +} diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.h b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.h new file mode 100644 index 0000000000..144063c615 --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.h @@ -0,0 +1,79 @@ +/** @file + header file for NULL named library for network1 shell command functions. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#if !defined (_UEFI_SHELL_NETWORK1_COMMANDS_LIB_H_) +#define _UEFI_SHELL_NETWORK1_COMMANDS_LIB_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern EFI_HANDLE gShellNetwork1HiiHandle; + +/** + Function for 'ping' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPing ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'ifconfig' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIfconfig ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif + diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf new file mode 100644 index 0000000000..51dca82b48 --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf @@ -0,0 +1,75 @@ +## @file +# Provides shell network1 functions +# +# Copyright (c) 2010, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellNetwork1CommandsLib + FILE_GUID = 9A929F7E-3861-45ce-87AB-7371219AE255 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellNetwork1CommandsLibConstructor + DESTRUCTOR = ShellNetwork1CommandsLibDestructor + +[Sources.common] + UefiShellNetwork1CommandsLib.uni + UefiShellNetwork1CommandsLib.c + UefiShellNetwork1CommandsLib.h + Ping.c + Ifconfig.c + +[Sources.IA32] + Ia32/Tsc.c + +[Sources.X64] + X64/Tsc.c + +[Sources.IPF] + Ipf/Itc.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + PcdLib + HiiLib + FileHandleLib + NetLib + +[Guids] + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask # ALWAYS_CONSUMED + +[Protocols] + gEfiCpuArchProtocolGuid # ALWAYS_CONSUMED + gEfiIp6ProtocolGuid # SOMETIMES_CONSUMED + gEfiIp6ServiceBindingProtocolGuid # SOMETIMES_CONSUMED + gEfiIp6ConfigProtocolGuid # SOMETIMES_CONSUMED + + gEfiIp6ProtocolGuid # SOMETIMES_CONSUMED + gEfiIp6ServiceBindingProtocolGuid # SOMETIMES_CONSUMED + gEfiIp6ConfigProtocolGuid # SOMETIMES_CONSUMED \ No newline at end of file diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni new file mode 100644 index 0000000000000000000000000000000000000000..f2303dcf4ef3025e4693baca874eeaee2027adbc GIT binary patch literal 18172 zcmeI4S#Mj%702f_1^U!4a3Mp8Q^c~JHbHARDP)OqgesION=aHf5VTu}mQJ z`~S`1(ac>)-b>2POF@Wtn>%y%b*TUT=W%!(3jO_FpWlYx=SD*O~~!*w_d zr{PVw(b$LKFnprpXW>bBs=p#Uy1RNBKGpepxYWqwaISM^xYite@9XZF&Mw1}o-FG* zBhuW%cy%0xdiOf~tnZ^Z@_Bd>w!>E$Tswm0Oydg8e61Nzi4mr8AwKYc|K9S+3*T=X!Riv&#q*^ZNX}eKcC(XPuvEhW&7$ zZ&rO9p+odZFBBxx%@S<)u1mglb=He?-VJ>nd%B-yNIY1VME5je5NF=h8IsKRf{x6~tP486 zh}T?wdIwt(zSDEy+Kel5y{wghtgrj)nw2>=!P$g$}&+6WBH z=Tbcs+$Rx+LiFy1HDOz1P-4ZFq7Az&!CMI8LhF`ccFI(bMYNt~H|^P%;X%ZSs|TV6 z`hF_Bfv|`lGT9qBnFmYyDcYyw(WA zE12SN5X*ecOP;tQg=&kwLg~9JK&{hi@`X zG>@_*dUv6@S;H67z+SY5_e*p4y4dg}Ek*cPlJ-J>L;dx2RY+oxA@sG3<9zt+Nhh|X z)n%+^<$!xcXg)hWz|xZ+#oJ-a(3B>M!0Gz^dFk=3By{6fpvN0YX)}il#dbtoZ$*i& z*!82$Gn}yKWj@>0hu}6E`A=bRCZ1W0wJ%s^#|uxrEo;6UV~{4Sip-OAv*yc^I-=NN zDMcTHZc+hFzbexVyH_vOf%PBZ$TzmSO{YVMRUdj4A{&m_QtM8=UmcbJJ zS~l91LgYtSr2YgdO^0?>@Okute!`d9dle>C0Ki(>kpON1k$u4|cvI}mNyGjlD?w))YvXkSHpHIiBE+G~z;$yL7 zWr^wvqeZ~vPk4@vMj4+DV>8{I>QZQaIWGlS+R&RI=>Gi?enhcK1_YR3PUPs zmNl>Hj^j9;(xzizXLSjVXbNzqN}}f;U^$fbaeWc39o3=3=y9ORQN)%CE_La49zDkg zN&ZgoZ!0F=6Gp`GR=+chrsGq!BxK0c+wuyURb}Cu*S5H0b!W>b-wA^oao#jw7EFNJ z>XPtfEuK?RoQ*SPv5hZOm#8(vDU0NQlq<3kq!a3={y>wpJdr#jm#LzjbGzvcx3Ar! ziNs&Dk4z)iL8nJs{%%F=%vK_Wu61s)4iptZn_*|^qZ<5;WX`L}WyrXiE`8nY1>B+z zXguvMX;#9_F~4;|~7bq2(*+Io182gn`3J-w_I2j(BI? zG;*O|N_X}}htup%J8oK3vKPBX8;ZsE^k;EXSvuS4l~uqOxH(tAlBdR;X5LHBrisUvX*yuZ1-OWZsZ z9{&=|jNHjE;O**)P7`2CowDjETdm5|zSh2o9ZYy&Jy`0s&9T&xAb~=u^K5?2I-pn^ z@Tk*{?qzjlsA4$!x;{G{)wi;2^e})5j?%$t3srsnDg_Oe#P_n)IXul0gx+}tqF%{e zxZ`;l-+}lB26T<62Kd}%Zw?&$8i}O?bE_qfgR_pOO9J`DK#?Y0-Xs%MiP#aBEnczM z*ZN+>#&0EmXkdbq4ltcl)03XA=;qcVcIRPLLf999U&4;l7s%hIA4@Mc`7$yZBoKWZ zk0l*mtN`zWZyi6P<79!H=1A~li||FX2DzVgyq?uoIT4gkiE6a77{&9ozo^BJbW3w&4#w2o}XI;QMU>7p%NFhUP)e!l4-3CuTtXkUAN4u3_JM;wTl0fyS@s19u1EBfamPwmc*7h_{--Sxo^cF6V?q5p}7` z*Tw%CjO)q-@Q7Y_2M4m9k0kwc&#ShA7zWS98g9Aj-AiC{sNoxsr+(*oS5s z4{Mn{wD>6XUD9k8ojOzpdc)$1VGZL+m6LVlLDpZenu+z_cSMQ4EXs%V`kc}_G_s;Q9w5xwq;9%)aJ`4{+SanW&%^{|Y#SI6KX(@nh!Dm3h@u}sT6mc@o` zdM$O_kp|;BSX=&11OPqC`Qp5|yL{L87?>=XUmyeaO2*fUb*;N>IXza}tD5X$!oJ_c zsMl;daaNh`>}10`8>O+*79Y9wK|agtk|#{t>(Gvhxr|X8vAsz1QgOWoF_C^wDf4>B z5K@BI#gd|hUg0zONfu;P@2|)XAV-IKkGHUfPNnL*c~(!&@H$d;R=VZ32#=0sWDi%; zI?nEcZe~-gYsN~|h}`sOb_vKap_jHQEX=;Ulgnn#s=8#A#~seQ~|a>2|htYvdP@UW>@cc7X3T#$i|-^Alu!wr2sW zWKler{iG3CB>X?VC`I)a4I)9zOx|YiFDb4gmhCR*UiTqaToVOc#_O`sMh2R+*yXq? zzewLK5PR(DwVx`F(sdh%iJRtw!Xm)t7zS9{K*6}ac#XBI#t@#Tbmwgj6SAE;Pl-l$ z))vORf|cg5e)(*4r0c&OYj{N07SZ4@ZFg{5qdgtBq&e5}^HzoO8Rmg8b%yBgQ}6pn zgKc1?wshPUudOFU4oFuUTW1hc_eJ+ViPePeTrWe*o(f__?>C_5-)pTd&@#3s+d}Sj ztBNJi{xFl)xJ1(XAbxdgWANnPZ75mwHt^WJYFBSP&`=n~DnWhZc*fz5GE^V{+b)JX)%K&j+VbYCPB4@C+W?JUO>HH^`|ceJBp_ z`wzT)>UvaR^6NI3*)K-UDwW+PuUC!Cy-t&UrBVGwhQ&Yhv8MmF04r*>Gc>H4fjdU^ zV;dZ+eI2mP{Z%0iqOz0U^BN4AX?5dreY<;iXMRe1Or0nWbo73zI}Zl3dh_;zpwdc= z>NI)}{tJX%G@ zJ(uoT{%cn+b(J#4uVU@`mF6)IN}ggq37D#Nb+717?l(DBb$MGB)OnYKdLLe!Ncl|B zEL|1O$pPO;uBz)3|Cj0JYpjeSa3XEzbX6kDl^Lt3dNt9m+Ew3x5IR||Vs+{9+DmuC zW+%Sqw^2}^ckA^v^HEmcq}FF=2Rg$JcxL4Id1VS{kdLz6sn@x!+Lue6Q*T4CAV2fa z&Y@~Y!zSoV#?vqFkk|22Jy0}t5T%t}apNUCf7UGLRVg#7>}qYYxiSQ9Gs>BGiZ;9g zeP6P+BnXIksCHB}6bXW6)=g)GWss)7NU8H=k|x+3j3|8yz&yN&voy7k0R zMi=I`cPGsbM79UdXS05`HxHUn4RBlGy5D3Yy4b4!%a7a6$?^ja-5QpUWu*A6GdS + + 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 + +/** + Reads and returns the current value of Time Stamp Counter (TSC). + + @return The current value of TSC + +**/ +UINT64 +ReadTime () +{ + return AsmReadTsc (); +} -- 2.39.2