summaryrefslogtreecommitdiff
path: root/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2024-06-04 06:43:08 +0300
committerkx <kx@radix.pro>2024-06-04 06:43:08 +0300
commit7e2ccccace24636f29ddc210b94606abd4c7e42b (patch)
tree545d43ea12671048956cafeb12303e84d601e571 /ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
parent27b044605cd5f6b33a3d231576003850b3fe305b (diff)
downloadedk2-trunk.tar.xz
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c')
-rw-r--r--ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c3462
1 files changed, 1731 insertions, 1731 deletions
diff --git a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
index 21e09db70d..cfd3204b1a 100644
--- a/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
+++ b/ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
@@ -1,1731 +1,1731 @@
-/** @file
- The implementation for Ping shell command.
-
- (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
-
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "UefiShellNetwork1CommandsLib.h"
-
-#define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))
-
-UINT64 mCurrentTick = 0;
-
-//
-// 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;
- UINT32 TimeStamp;
- UINT8 Data[1];
-} ICMPX_ECHO_REQUEST_REPLY;
-#pragma pack()
-
-typedef struct _PING_ICMP_TX_INFO {
- LIST_ENTRY Link;
- UINT16 SequenceNum;
- UINT32 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 STALL_1_MILLI_SECOND 1000
-
-#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;
-
- UINT32 TimerPeriod;
- UINT32 RttTimerTick;
- EFI_EVENT RttTimer;
-
- 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;
- UINT16 FailedCount;
-} PING_PRIVATE_DATA;
-
-/**
- Calculate the internet checksum (see RFC 1071).
-
- @param[in] Packet Buffer which contains the data to be checksummed.
- @param[in] Length Length to be checksummed.
-
- @retval Checksum Returns the 16 bit ones complement of
- ones complement sum of 16 bit words
-**/
-UINT16
-NetChecksum (
- IN UINT8 *Buffer,
- IN UINT32 Length
- )
-{
- UINT32 Sum;
- UINT8 Odd;
- UINT16 *Packet;
-
- Packet = (UINT16 *)Buffer;
-
- Sum = 0;
- Odd = (UINT8)(Length & 1);
- Length >>= 1;
- while ((Length--) != 0) {
- Sum += *Packet++;
- }
-
- if (Odd != 0) {
- 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.
-
-**/
-
-STATIC CONST SHELL_PARAM_ITEM PingParamList[] = {
- {
- L"-l",
- TypeValue
- },
- {
- L"-n",
- TypeValue
- },
- {
- L"-s",
- TypeValue
- },
- {
- L"-_s",
- TypeValue
- },
- {
- L"-_ip6",
- TypeFlag
- },
- {
- NULL,
- TypeMax
- },
-};
-
-//
-// Global Variables in Ping command.
-//
-STATIC CONST CHAR16 *mDstString;
-STATIC CONST CHAR16 *mSrcString;
-
-/**
- RTT timer tick routine.
-
- @param[in] Event A EFI_EVENT type event.
- @param[in] Context The pointer to Context.
-
-**/
-VOID
-EFIAPI
-RttTimerTickRoutine (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- UINT32 *RttTimerTick;
-
- RttTimerTick = (UINT32 *)Context;
- (*RttTimerTick)++;
-}
-
-/**
- Get the timer period of the system.
-
- This function tries to get the system timer period by creating
- an 1ms period timer.
-
- @return System timer period in MS, or 0 if operation failed.
-
-**/
-UINT32
-GetTimerPeriod (
- VOID
- )
-{
- EFI_STATUS Status;
- UINT32 RttTimerTick;
- EFI_EVENT TimerEvent;
- UINT32 StallCounter;
- EFI_TPL OldTpl;
- UINT32 TimerPeriod;
-
- RttTimerTick = 0;
- StallCounter = 0;
- TimerPeriod = 0;
-
- Status = gBS->CreateEvent (
- EVT_TIMER | EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- RttTimerTickRoutine,
- &RttTimerTick,
- &TimerEvent
- );
- if (EFI_ERROR (Status)) {
- return 0;
- }
-
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- Status = gBS->SetTimer (
- TimerEvent,
- TimerPeriodic,
- TICKS_PER_MS
- );
- if (EFI_ERROR (Status)) {
- gBS->CloseEvent (TimerEvent);
- return 0;
- }
-
- while (RttTimerTick < 10) {
- gBS->Stall (STALL_1_MILLI_SECOND);
- ++StallCounter;
- }
-
- gBS->RestoreTPL (OldTpl);
-
- gBS->SetTimer (TimerEvent, TimerCancel, 0);
- gBS->CloseEvent (TimerEvent);
-
- TimerPeriod = StallCounter / RttTimerTick;
- if (TimerPeriod != 0) {
- return TimerPeriod;
- } else {
- return 1;
- }
-}
-
-/**
- Initialize the timer event for RTT (round trip time).
-
- @param[in] Private The pointer to PING_PRIVATE_DATA.
-
- @retval EFI_SUCCESS RTT timer is started.
- @retval Others Failed to start the RTT timer.
-
-**/
-EFI_STATUS
-PingInitRttTimer (
- PING_PRIVATE_DATA *Private
- )
-{
- EFI_STATUS Status;
-
- Private->TimerPeriod = GetTimerPeriod ();
- if (Private->TimerPeriod == 0) {
- return EFI_ABORTED;
- }
-
- Private->RttTimerTick = 0;
- Status = gBS->CreateEvent (
- EVT_TIMER | EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- RttTimerTickRoutine,
- &Private->RttTimerTick,
- &Private->RttTimer
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = gBS->SetTimer (
- Private->RttTimer,
- TimerPeriodic,
- TICKS_PER_MS
- );
- if (EFI_ERROR (Status)) {
- gBS->CloseEvent (Private->RttTimer);
- return Status;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Free RTT timer event resource.
-
- @param[in] Private The pointer to PING_PRIVATE_DATA.
-
-**/
-VOID
-PingFreeRttTimer (
- PING_PRIVATE_DATA *Private
- )
-{
- if (Private->RttTimer != NULL) {
- gBS->SetTimer (Private->RttTimer, TimerCancel, 0);
- gBS->CloseEvent (Private->RttTimer);
- }
-}
-
-/**
- Read the current time.
-
- @param[in] Private The pointer to PING_PRIVATE_DATA.
-
- @retval the current tick value.
-**/
-UINT32
-ReadTime (
- PING_PRIVATE_DATA *Private
- )
-{
- return Private->RttTimerTick;
-}
-
-/**
- Calculate a duration in ms.
-
- @param[in] Private The pointer to PING_PRIVATE_DATA.
- @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.
-**/
-UINT32
-CalculateTick (
- PING_PRIVATE_DATA *Private,
- IN UINT32 Begin,
- IN UINT32 End
- )
-{
- if (End < Begin) {
- return (0);
- }
-
- return (End - Begin) * Private->TimerPeriod;
-}
-
-/**
- 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
-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
-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 routine.
-
- @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;
- UINT32 Rtt;
-
- 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 (Private, Reply->TimeStamp, ReadTime (Private));
-
- 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,
- Rtt,
- Rtt + Private->TimerPeriod
- );
-
-ON_EXIT:
-
- //
- // Recycle the packet before reusing RxToken
- //
- 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);
-
- 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)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);
- Private->Status = EFI_ABORTED;
- }
- } else {
- //
- // All reply have already been received from the dest host.
- //
- Private->Status = EFI_SUCCESS;
- }
-}
-
-/**
- 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 *
-PingGenerateToken (
- IN PING_PRIVATE_DATA *Private,
- IN UINT32 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) {
- Request->TimeStamp = TimeStamp;
- ((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
-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 (Private);
- 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);
-
- InsertTailList (&Private->TxList, &TxInfo->Link);
-
- Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token);
-
- if (EFI_ERROR (Status)) {
- RemoveEntryList (&TxInfo->Link);
- PingDestroyTxInfo (TxInfo, Private->IpChoice);
- return Status;
- }
-
- 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
-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;
-
- Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);
- }
-
- return Status;
-}
-
-/**
- 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 (Private, TxInfo->TimeStamp, ReadTime (Private));
-
- //
- // 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);
-
- Private->RxCount++;
- Private->FailedCount++;
-
- 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
-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
-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
-PingCreateIpInstance (
- IN PING_PRIVATE_DATA *Private
- )
-{
- EFI_STATUS Status;
- UINTN HandleIndex;
- UINTN HandleNum;
- EFI_HANDLE *HandleBuffer;
- BOOLEAN UnspecifiedSrc;
- EFI_STATUS MediaStatus;
- 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;
- UnspecifiedSrc = FALSE;
- MediaStatus = EFI_SUCCESS;
- 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) || (HandleBuffer == NULL)) {
- return EFI_ABORTED;
- }
-
- if ((Private->IpChoice == PING_IP_CHOICE_IP6) ? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS *)&Private->SrcAddress) : \
- PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS *)&Private->SrcAddress))
- {
- //
- // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
- //
- UnspecifiedSrc = TRUE;
- }
-
- //
- // Source address is required when pinging a link-local address.
- //
- if (Private->IpChoice == PING_IP_CHOICE_IP6) {
- if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);
- Status = EFI_INVALID_PARAMETER;
- goto ON_ERROR;
- }
- } else {
- ASSERT (Private->IpChoice == PING_IP_CHOICE_IP4);
- if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);
- 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;
-
- if (UnspecifiedSrc) {
- //
- // Check media.
- //
- NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus);
- if (MediaStatus != EFI_SUCCESS) {
- //
- // Skip this one.
- //
- continue;
- }
- }
-
- Status = gBS->HandleProtocol (
- HandleBuffer[HandleIndex],
- Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,
- (VOID **)&EfiSb
- );
- if (EFI_ERROR (Status)) {
- goto ON_ERROR;
- }
-
- //
- // 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 : &gEfiIp4Config2ProtocolGuid,
- (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_CONFIG2_PROTOCOL *)IpXCfg)->GetData (
- IpXCfg,
- Ip4Config2DataTypeInterfaceInfo,
- &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_CONFIG2_PROTOCOL *)IpXCfg)->GetData (
- IpXCfg,
- Ip4Config2DataTypeInterfaceInfo,
- &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 (UnspecifiedSrc) {
- if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {
- //
- // Select the interface automatically.
- //
- CopyMem (&Private->SrcAddress, Addr, sizeof (Private->SrcAddress));
- break;
- }
- } else 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 {
- if (UnspecifiedSrc) {
- if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress) &&
- !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress))
- {
- //
- // Select the interface automatically.
- //
- break;
- }
- } else if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_CONFIG2_INTERFACE_INFO *)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_PING_CONFIGD_NIC_NF), gShellNetwork1HiiHandle, L"ping");
- 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.
- //
- 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;
-}
-
-/**
- Destroy the IP instance.
-
- @param[in] Private The pointer of PING_PRIVATE_DATA.
-
-**/
-VOID
-Ping6DestroyIp6Instance (
- 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
-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;
- }
-
- //
- // Start a timer to calculate the RTT.
- //
- Status = PingInitRttTimer (Private);
- 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, L"ping", 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 - Private->FailedCount),
- (100 - ((100 * (Private->RxCount - Private->FailedCount)) / Private->TxCount)),
- Private->RttSum
- );
- }
-
- if (Private->RxCount > Private->FailedCount) {
- ShellPrintHiiEx (
- -1,
- -1,
- NULL,
- STRING_TOKEN (STR_PING_RTT),
- gShellNetwork1HiiHandle,
- Private->RttMin,
- Private->RttMin + Private->TimerPeriod,
- Private->RttMax,
- Private->RttMax + Private->TimerPeriod,
- DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL),
- DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL) + Private->TimerPeriod
- );
- }
-
-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);
- }
-
- PingFreeRttTimer (Private);
-
- 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) {
- Ping6DestroyIp6Instance (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).
-
- @retval SHELL_SUCCESS The ping processed successfullly.
- @retval others The ping processed unsuccessfully.
-
-**/
-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;
- CHAR16 *ProblemParam;
-
- //
- // 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;
- ProblemParam = NULL;
-
- Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ProblemParam);
- ShellStatus = SHELL_INVALID_PARAMETER;
- goto ON_EXIT;
- }
-
- if (ShellCommandLineGetFlag (ParamPackage, L"-_ip6")) {
- IpChoice = PING_IP_CHOICE_IP6;
- }
-
- //
- // Parse the parameter 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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
- ShellStatus = SHELL_INVALID_PARAMETER;
- goto ON_EXIT;
- }
- } else {
- SendNumber = DEFAULT_SEND_COUNT;
- }
-
- //
- // Parse the parameter 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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", 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 parameter of source ip address.
- //
- ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");
- if (ValueStr == NULL) {
- 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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
- ShellStatus = SHELL_INVALID_PARAMETER;
- goto ON_EXIT;
- }
- }
-
- //
- // Parse the parameter of destination ip address.
- //
- NonOptionCount = ShellCommandLineGetCount (ParamPackage);
- if (NonOptionCount < 2) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle, L"ping");
- ShellStatus = SHELL_INVALID_PARAMETER;
- goto ON_EXIT;
- }
-
- if (NonOptionCount > 2) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle, L"ping");
- 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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
- ShellStatus = SHELL_INVALID_PARAMETER;
- goto ON_EXIT;
- }
- }
-
- //
- // Enter into ping process.
- //
- ShellStatus = ShellPing (
- (UINT32)SendNumber,
- (UINT32)BufferSize,
- &SrcAddress,
- &DstAddress,
- IpChoice
- );
-
-ON_EXIT:
- ShellCommandLineFreeVarList (ParamPackage);
- return ShellStatus;
-}
+/** @file
+ The implementation for Ping shell command.
+
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UefiShellNetwork1CommandsLib.h"
+
+#define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))
+
+UINT64 mCurrentTick = 0;
+
+//
+// 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;
+ UINT32 TimeStamp;
+ UINT8 Data[1];
+} ICMPX_ECHO_REQUEST_REPLY;
+#pragma pack()
+
+typedef struct _PING_ICMP_TX_INFO {
+ LIST_ENTRY Link;
+ UINT16 SequenceNum;
+ UINT32 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 STALL_1_MILLI_SECOND 1000
+
+#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;
+
+ UINT32 TimerPeriod;
+ UINT32 RttTimerTick;
+ EFI_EVENT RttTimer;
+
+ 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;
+ UINT16 FailedCount;
+} PING_PRIVATE_DATA;
+
+/**
+ Calculate the internet checksum (see RFC 1071).
+
+ @param[in] Packet Buffer which contains the data to be checksummed.
+ @param[in] Length Length to be checksummed.
+
+ @retval Checksum Returns the 16 bit ones complement of
+ ones complement sum of 16 bit words
+**/
+UINT16
+NetChecksum (
+ IN UINT8 *Buffer,
+ IN UINT32 Length
+ )
+{
+ UINT32 Sum;
+ UINT8 Odd;
+ UINT16 *Packet;
+
+ Packet = (UINT16 *)Buffer;
+
+ Sum = 0;
+ Odd = (UINT8)(Length & 1);
+ Length >>= 1;
+ while ((Length--) != 0) {
+ Sum += *Packet++;
+ }
+
+ if (Odd != 0) {
+ 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.
+
+**/
+
+STATIC CONST SHELL_PARAM_ITEM PingParamList[] = {
+ {
+ L"-l",
+ TypeValue
+ },
+ {
+ L"-n",
+ TypeValue
+ },
+ {
+ L"-s",
+ TypeValue
+ },
+ {
+ L"-_s",
+ TypeValue
+ },
+ {
+ L"-_ip6",
+ TypeFlag
+ },
+ {
+ NULL,
+ TypeMax
+ },
+};
+
+//
+// Global Variables in Ping command.
+//
+STATIC CONST CHAR16 *mDstString;
+STATIC CONST CHAR16 *mSrcString;
+
+/**
+ RTT timer tick routine.
+
+ @param[in] Event A EFI_EVENT type event.
+ @param[in] Context The pointer to Context.
+
+**/
+VOID
+EFIAPI
+RttTimerTickRoutine (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINT32 *RttTimerTick;
+
+ RttTimerTick = (UINT32 *)Context;
+ (*RttTimerTick)++;
+}
+
+/**
+ Get the timer period of the system.
+
+ This function tries to get the system timer period by creating
+ an 1ms period timer.
+
+ @return System timer period in MS, or 0 if operation failed.
+
+**/
+UINT32
+GetTimerPeriod (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 RttTimerTick;
+ EFI_EVENT TimerEvent;
+ UINT32 StallCounter;
+ EFI_TPL OldTpl;
+ UINT32 TimerPeriod;
+
+ RttTimerTick = 0;
+ StallCounter = 0;
+ TimerPeriod = 0;
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ RttTimerTickRoutine,
+ &RttTimerTick,
+ &TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Status = gBS->SetTimer (
+ TimerEvent,
+ TimerPeriodic,
+ TICKS_PER_MS
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (TimerEvent);
+ return 0;
+ }
+
+ while (RttTimerTick < 10) {
+ gBS->Stall (STALL_1_MILLI_SECOND);
+ ++StallCounter;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ gBS->SetTimer (TimerEvent, TimerCancel, 0);
+ gBS->CloseEvent (TimerEvent);
+
+ TimerPeriod = StallCounter / RttTimerTick;
+ if (TimerPeriod != 0) {
+ return TimerPeriod;
+ } else {
+ return 1;
+ }
+}
+
+/**
+ Initialize the timer event for RTT (round trip time).
+
+ @param[in] Private The pointer to PING_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS RTT timer is started.
+ @retval Others Failed to start the RTT timer.
+
+**/
+EFI_STATUS
+PingInitRttTimer (
+ PING_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+
+ Private->TimerPeriod = GetTimerPeriod ();
+ if (Private->TimerPeriod == 0) {
+ return EFI_ABORTED;
+ }
+
+ Private->RttTimerTick = 0;
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ RttTimerTickRoutine,
+ &Private->RttTimerTick,
+ &Private->RttTimer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->SetTimer (
+ Private->RttTimer,
+ TimerPeriodic,
+ TICKS_PER_MS
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Private->RttTimer);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free RTT timer event resource.
+
+ @param[in] Private The pointer to PING_PRIVATE_DATA.
+
+**/
+VOID
+PingFreeRttTimer (
+ PING_PRIVATE_DATA *Private
+ )
+{
+ if (Private->RttTimer != NULL) {
+ gBS->SetTimer (Private->RttTimer, TimerCancel, 0);
+ gBS->CloseEvent (Private->RttTimer);
+ }
+}
+
+/**
+ Read the current time.
+
+ @param[in] Private The pointer to PING_PRIVATE_DATA.
+
+ @retval the current tick value.
+**/
+UINT32
+ReadTime (
+ PING_PRIVATE_DATA *Private
+ )
+{
+ return Private->RttTimerTick;
+}
+
+/**
+ Calculate a duration in ms.
+
+ @param[in] Private The pointer to PING_PRIVATE_DATA.
+ @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.
+**/
+UINT32
+CalculateTick (
+ PING_PRIVATE_DATA *Private,
+ IN UINT32 Begin,
+ IN UINT32 End
+ )
+{
+ if (End < Begin) {
+ return (0);
+ }
+
+ return (End - Begin) * Private->TimerPeriod;
+}
+
+/**
+ 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
+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
+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 routine.
+
+ @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;
+ UINT32 Rtt;
+
+ 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 (Private, Reply->TimeStamp, ReadTime (Private));
+
+ 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,
+ Rtt,
+ Rtt + Private->TimerPeriod
+ );
+
+ON_EXIT:
+
+ //
+ // Recycle the packet before reusing RxToken
+ //
+ 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);
+
+ 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)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);
+ Private->Status = EFI_ABORTED;
+ }
+ } else {
+ //
+ // All reply have already been received from the dest host.
+ //
+ Private->Status = EFI_SUCCESS;
+ }
+}
+
+/**
+ 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 *
+PingGenerateToken (
+ IN PING_PRIVATE_DATA *Private,
+ IN UINT32 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) {
+ Request->TimeStamp = TimeStamp;
+ ((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
+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 (Private);
+ 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);
+
+ InsertTailList (&Private->TxList, &TxInfo->Link);
+
+ Status = Private->ProtocolPointers.Transmit (Private->IpProtocol, TxInfo->Token);
+
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&TxInfo->Link);
+ PingDestroyTxInfo (TxInfo, Private->IpChoice);
+ return Status;
+ }
+
+ 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
+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;
+
+ Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);
+ }
+
+ return Status;
+}
+
+/**
+ 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 (Private, TxInfo->TimeStamp, ReadTime (Private));
+
+ //
+ // 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);
+
+ Private->RxCount++;
+ Private->FailedCount++;
+
+ 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
+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
+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
+PingCreateIpInstance (
+ IN PING_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleIndex;
+ UINTN HandleNum;
+ EFI_HANDLE *HandleBuffer;
+ BOOLEAN UnspecifiedSrc;
+ EFI_STATUS MediaStatus;
+ 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;
+ UnspecifiedSrc = FALSE;
+ MediaStatus = EFI_SUCCESS;
+ 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) || (HandleBuffer == NULL)) {
+ return EFI_ABORTED;
+ }
+
+ if ((Private->IpChoice == PING_IP_CHOICE_IP6) ? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS *)&Private->SrcAddress) : \
+ PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS *)&Private->SrcAddress))
+ {
+ //
+ // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
+ //
+ UnspecifiedSrc = TRUE;
+ }
+
+ //
+ // Source address is required when pinging a link-local address.
+ //
+ if (Private->IpChoice == PING_IP_CHOICE_IP6) {
+ if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_ERROR;
+ }
+ } else {
+ ASSERT (Private->IpChoice == PING_IP_CHOICE_IP4);
+ if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS *)&Private->DstAddress) && UnspecifiedSrc) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);
+ 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;
+
+ if (UnspecifiedSrc) {
+ //
+ // Check media.
+ //
+ NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus);
+ if (MediaStatus != EFI_SUCCESS) {
+ //
+ // Skip this one.
+ //
+ continue;
+ }
+ }
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[HandleIndex],
+ Private->IpChoice == PING_IP_CHOICE_IP6 ? &gEfiIp6ServiceBindingProtocolGuid : &gEfiIp4ServiceBindingProtocolGuid,
+ (VOID **)&EfiSb
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // 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 : &gEfiIp4Config2ProtocolGuid,
+ (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_CONFIG2_PROTOCOL *)IpXCfg)->GetData (
+ IpXCfg,
+ Ip4Config2DataTypeInterfaceInfo,
+ &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_CONFIG2_PROTOCOL *)IpXCfg)->GetData (
+ IpXCfg,
+ Ip4Config2DataTypeInterfaceInfo,
+ &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 (UnspecifiedSrc) {
+ if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {
+ //
+ // Select the interface automatically.
+ //
+ CopyMem (&Private->SrcAddress, Addr, sizeof (Private->SrcAddress));
+ break;
+ }
+ } else 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 {
+ if (UnspecifiedSrc) {
+ if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress) &&
+ !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO *)IpXInterfaceInfo)->StationAddress))
+ {
+ //
+ // Select the interface automatically.
+ //
+ break;
+ }
+ } else if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_CONFIG2_INTERFACE_INFO *)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_PING_CONFIGD_NIC_NF), gShellNetwork1HiiHandle, L"ping");
+ 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.
+ //
+ 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;
+}
+
+/**
+ Destroy the IP instance.
+
+ @param[in] Private The pointer of PING_PRIVATE_DATA.
+
+**/
+VOID
+Ping6DestroyIp6Instance (
+ 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
+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;
+ }
+
+ //
+ // Start a timer to calculate the RTT.
+ //
+ Status = PingInitRttTimer (Private);
+ 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, L"ping", 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 - Private->FailedCount),
+ (100 - ((100 * (Private->RxCount - Private->FailedCount)) / Private->TxCount)),
+ Private->RttSum
+ );
+ }
+
+ if (Private->RxCount > Private->FailedCount) {
+ ShellPrintHiiEx (
+ -1,
+ -1,
+ NULL,
+ STRING_TOKEN (STR_PING_RTT),
+ gShellNetwork1HiiHandle,
+ Private->RttMin,
+ Private->RttMin + Private->TimerPeriod,
+ Private->RttMax,
+ Private->RttMax + Private->TimerPeriod,
+ DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL),
+ DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL) + Private->TimerPeriod
+ );
+ }
+
+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);
+ }
+
+ PingFreeRttTimer (Private);
+
+ 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) {
+ Ping6DestroyIp6Instance (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).
+
+ @retval SHELL_SUCCESS The ping processed successfullly.
+ @retval others The ping processed unsuccessfully.
+
+**/
+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;
+ CHAR16 *ProblemParam;
+
+ //
+ // 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;
+ ProblemParam = NULL;
+
+ Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ProblemParam);
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (ShellCommandLineGetFlag (ParamPackage, L"-_ip6")) {
+ IpChoice = PING_IP_CHOICE_IP6;
+ }
+
+ //
+ // Parse the parameter 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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ } else {
+ SendNumber = DEFAULT_SEND_COUNT;
+ }
+
+ //
+ // Parse the parameter 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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", 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 parameter of source ip address.
+ //
+ ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");
+ if (ValueStr == NULL) {
+ 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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // Parse the parameter of destination ip address.
+ //
+ NonOptionCount = ShellCommandLineGetCount (ParamPackage);
+ if (NonOptionCount < 2) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle, L"ping");
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (NonOptionCount > 2) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle, L"ping");
+ 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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // Enter into ping process.
+ //
+ ShellStatus = ShellPing (
+ (UINT32)SendNumber,
+ (UINT32)BufferSize,
+ &SrcAddress,
+ &DstAddress,
+ IpChoice
+ );
+
+ON_EXIT:
+ ShellCommandLineFreeVarList (ParamPackage);
+ return ShellStatus;
+}