summaryrefslogtreecommitdiff
path: root/ShellPkg/Library/UefiShellNetwork1CommandsLib
diff options
context:
space:
mode:
authorjcarsey <jcarsey@6f19259b-4bc3-4df7-8a09-765794883524>2011-03-25 20:47:02 +0000
committerjcarsey <jcarsey@6f19259b-4bc3-4df7-8a09-765794883524>2011-03-25 20:47:02 +0000
commit68fb05272b45b473fe030ac11dcb79d3f3c0aecd (patch)
tree8390e8e6f3ac6c3ff0bedd19a36cc92db93750d1 /ShellPkg/Library/UefiShellNetwork1CommandsLib
parent9586a3512789e7fe5e4b883a2591c6bd07ac863c (diff)
downloadedk2-platforms-68fb05272b45b473fe030ac11dcb79d3f3c0aecd.tar.xz
Add Network1 profile.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11423 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'ShellPkg/Library/UefiShellNetwork1CommandsLib')
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/Ia32/Tsc.c28
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/Ifconfig.c1746
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/Ipf/Itc.c28
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c1563
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.c94
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.h79
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf75
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.unibin0 -> 18172 bytes
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/X64/Tsc.c28
9 files changed, 3641 insertions, 0 deletions
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.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+
+/**
+ 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.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include "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 <ConfigHdr> 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 <HexCh>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.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+
+/**
+ 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.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "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. <BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "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. <BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#if !defined (_UEFI_SHELL_NETWORK1_COMMANDS_LIB_H_)
+#define _UEFI_SHELL_NETWORK1_COMMANDS_LIB_H_
+
+#include <Uefi.h>
+#include <ShellBase.h>
+
+#include <Protocol/Cpu.h>
+#include <Protocol/ServiceBinding.h>
+#include <Protocol/Ip6.h>
+#include <Protocol/Ip6Config.h>
+#include <Protocol/Ip4.h>
+#include <Protocol/Ip4Config.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/Arp.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/ShellCommandLib.h>
+#include <Library/ShellLib.h>
+#include <Library/SortLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HiiLib.h>
+#include <Library/NetLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+#include <Guid/NicIp4ConfigNvData.h>
+
+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. <BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[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 0000000000..f2303dcf4e
--- /dev/null
+++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.uni
Binary files differ
diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/X64/Tsc.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/X64/Tsc.c
new file mode 100644
index 0000000000..b3e7bdbb96
--- /dev/null
+++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/X64/Tsc.c
@@ -0,0 +1,28 @@
+/** @file
+ The implement to read TSC in X64 platform.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+
+/**
+ Reads and returns the current value of Time Stamp Counter (TSC).
+
+ @return The current value of TSC
+
+**/
+UINT64
+ReadTime ()
+{
+ return AsmReadTsc ();
+}