2 The implementation for Ping shell command.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php.
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "UefiShellNetwork1CommandsLib.h"
19 #define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))
21 UINT64 mCurrentTick
= 0;
24 // Function templates to match the IPv4 and IPv6 commands that we use.
28 (EFIAPI
*PING_IPX_POLL
)(
34 (EFIAPI
*PING_IPX_TRANSMIT
)(
41 (EFIAPI
*PING_IPX_RECEIVE
)(
48 (EFIAPI
*PING_IPX_CANCEL
)(
50 IN VOID
*Token OPTIONAL
54 /// A set of pointers to either IPv6 or IPv4 functions.
55 /// Unknown which one to the ping command.
58 PING_IPX_TRANSMIT Transmit
;
59 PING_IPX_RECEIVE Receive
;
60 PING_IPX_CANCEL Cancel
;
71 // PING_IPX_COMPLETION_TOKEN
72 // structures are used for both transmit and receive operations.
73 // This version is IP-unaware.
79 } PING_IPX_COMPLETION_TOKEN
;
82 typedef struct _ICMPX_ECHO_REQUEST_REPLY
{
90 } ICMPX_ECHO_REQUEST_REPLY
;
93 typedef struct _PING_ICMP_TX_INFO
{
97 PING_IPX_COMPLETION_TOKEN
*Token
;
100 #define DEFAULT_TIMEOUT 5000
101 #define MAX_SEND_NUMBER 10000
102 #define MAX_BUFFER_SIZE 32768
103 #define DEFAULT_TIMER_PERIOD 358049
104 #define ONE_SECOND 10000000
105 #define PING_IP_CHOICE_IP4 1
106 #define PING_IP_CHOICE_IP6 2
107 #define DEFAULT_SEND_COUNT 10
108 #define DEFAULT_BUFFER_SIZE 16
109 #define ICMP_V4_ECHO_REQUEST 0x8
110 #define ICMP_V4_ECHO_REPLY 0x0
112 #define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')
113 typedef struct _PING_PRIVATE_DATA
{
115 EFI_HANDLE NicHandle
;
116 EFI_HANDLE IpChildHandle
;
132 PING_IPX_PROTOCOL ProtocolPointers
;
134 UINT8 SrcAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
135 UINT8 DstAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
136 PING_IPX_COMPLETION_TOKEN RxToken
;
140 Calculate the internet checksum (see RFC 1071).
142 @param[in] Packet Buffer which contains the data to be checksummed.
143 @param[in] Length Length to be checksummed.
145 @retval Checksum Returns the 16 bit ones complement of
146 ones complement sum of 16 bit words
159 Packet
= (UINT16
*) Buffer
;
162 Odd
= (UINT8
) (Length
& 1);
164 while ((Length
--) != 0) {
169 Sum
+= *(UINT8
*) Packet
;
172 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
175 // in case above carried
183 Reads and returns the current value of register.
184 In IA64, the register is the Interval Timer Vector (ITV).
185 In X86(IA32/X64), the register is the Time Stamp Counter (TSC)
187 @return The current value of the register.
191 STATIC CONST SHELL_PARAM_ITEM PingParamList
[] = {
215 // Global Variables in Ping command.
217 STATIC CONST CHAR16
*mDstString
;
218 STATIC CONST CHAR16
*mSrcString
;
219 STATIC UINT64 mFrequency
= 0;
220 EFI_CPU_ARCH_PROTOCOL
*gCpu
= NULL
;
223 Read the current time.
225 @retval the current tick value.
236 ASSERT (gCpu
!= NULL
);
238 Status
= gCpu
->GetTimerValue (gCpu
, 0, &mCurrentTick
, &TimerPeriod
);
239 if (EFI_ERROR (Status
)) {
241 // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the
242 // TimerPeriod by ourselves.
244 mCurrentTick
+= 1000000;
252 Get and calculate the frequency in ticks/ms.
253 The result is saved in the global variable mFrequency
255 @retval EFI_SUCCESS Calculated the frequency successfully.
256 @retval Others Failed to calculate the frequency.
269 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &gCpu
);
270 if (EFI_ERROR (Status
)) {
274 Status
= gCpu
->GetTimerValue (gCpu
, 0, &CurrentTick
, &TimerPeriod
);
276 if (EFI_ERROR (Status
)) {
277 TimerPeriod
= DEFAULT_TIMER_PERIOD
;
281 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
282 // So 1e+12 is divided by timer period to produce the freq in ticks/ms.
284 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
290 Calculate a duration in ms.
292 @param[in] Begin The start point of time.
293 @param[in] End The end point of time.
295 @return The duration in ms.
296 @retval 0 The parameters were not valid.
308 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
312 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
314 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
315 @param[in] IpChoice Whether the token is IPv4 or IPv6
320 IN PING_ICMPX_TX_INFO
*TxInfo
,
324 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
325 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
326 EFI_IP6_FRAGMENT_DATA
*FragData
;
329 if (TxInfo
== NULL
) {
333 if (TxInfo
->Token
!= NULL
) {
335 if (TxInfo
->Token
->Event
!= NULL
) {
336 gBS
->CloseEvent (TxInfo
->Token
->Event
);
339 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
340 if (IpChoice
== PING_IP_CHOICE_IP6
) {
341 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
343 if (Ip6TxData
->OverrideData
!= NULL
) {
344 FreePool (Ip6TxData
->OverrideData
);
347 if (Ip6TxData
->ExtHdrs
!= NULL
) {
348 FreePool (Ip6TxData
->ExtHdrs
);
351 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
352 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
353 if (FragData
!= NULL
) {
358 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
360 if (Ip4TxData
->OverrideData
!= NULL
) {
361 FreePool (Ip4TxData
->OverrideData
);
364 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
365 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
366 if (FragData
!= NULL
) {
373 FreePool (TxInfo
->Token
);
380 Match the request, and reply with SequenceNum/TimeStamp.
382 @param[in] Private The pointer to PING_PRIVATE_DATA.
383 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
385 @retval EFI_SUCCESS The match is successful.
386 @retval EFI_NOT_FOUND The reply can't be matched with any request.
391 Ping6MatchEchoReply (
392 IN PING_PRIVATE_DATA
*Private
,
393 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
396 PING_ICMPX_TX_INFO
*TxInfo
;
398 LIST_ENTRY
*NextEntry
;
400 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
401 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
403 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
405 RemoveEntryList (&TxInfo
->Link
);
406 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
411 return EFI_NOT_FOUND
;
415 The original intention is to send a request.
416 Currently, the application retransmits an icmp6 echo request packet
417 per second in sendnumber times that is specified by the user.
418 Because nothing can be done here, all things move to the timer rountine.
420 @param[in] Event A EFI_EVENT type event.
421 @param[in] Context The pointer to Context.
426 Ping6OnEchoRequestSent (
434 receive reply, match and print reply infomation.
436 @param[in] Event A EFI_EVENT type event.
437 @param[in] Context The pointer to context.
442 Ping6OnEchoReplyReceived (
448 PING_PRIVATE_DATA
*Private
;
449 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
454 Private
= (PING_PRIVATE_DATA
*) Context
;
456 if (Private
== NULL
|| Private
->Status
== EFI_ABORTED
|| Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
460 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
464 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
465 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
466 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
467 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
470 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
471 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
)) {
475 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
479 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
480 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
481 if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
482 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
)) {
486 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
492 if (PayLoad
!= Private
->BufferSize
) {
496 // Check whether the reply matches the sent request before.
498 Status
= Ping6MatchEchoReply (Private
, Reply
);
499 if (EFI_ERROR(Status
)) {
503 // Display statistics on this icmp6 echo reply packet.
505 Rtt
= CalculateTick (Reply
->TimeStamp
, ReadTime ());
512 Private
->RttSum
+= Rtt
;
513 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
514 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
520 STRING_TOKEN (STR_PING_REPLY_INFO
),
521 gShellNetwork1HiiHandle
,
525 Private
->IpChoice
== PING_IP_CHOICE_IP6
?((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
:0,
532 if (Private
->RxCount
< Private
->SendNum
) {
534 // Continue to receive icmp echo reply packets.
536 Private
->RxToken
.Status
= EFI_ABORTED
;
538 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
540 if (EFI_ERROR (Status
)) {
541 Private
->Status
= EFI_ABORTED
;
545 // All reply have already been received from the dest host.
547 Private
->Status
= EFI_SUCCESS
;
550 // Singal to recycle the each rxdata here, not at the end of process.
552 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
);
556 Create a PING_IPX_COMPLETION_TOKEN.
558 @param[in] Private The pointer of PING_PRIVATE_DATA.
559 @param[in] TimeStamp The TimeStamp of request.
560 @param[in] SequenceNum The SequenceNum of request.
562 @return The pointer of PING_IPX_COMPLETION_TOKEN.
565 PING_IPX_COMPLETION_TOKEN
*
568 IN PING_PRIVATE_DATA
*Private
,
570 IN UINT16 SequenceNum
574 PING_IPX_COMPLETION_TOKEN
*Token
;
576 ICMPX_ECHO_REQUEST_REPLY
*Request
;
580 Request
= AllocateZeroPool (Private
->BufferSize
);
581 if (Request
== NULL
) {
584 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
585 if (TxData
== NULL
) {
589 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
597 // Assembly echo request packet.
599 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
601 Request
->SequenceNum
= SequenceNum
;
602 Request
->Identifier
= 0;
603 Request
->Checksum
= 0;
606 // Assembly token for transmit.
608 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
609 Request
->TimeStamp
= TimeStamp
;
610 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
611 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
612 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
613 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
614 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
615 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
616 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
618 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
619 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
620 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
621 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
622 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
623 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
624 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
625 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
626 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
627 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
628 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
630 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
631 Request
->TimeStamp
= TimeStamp
;
632 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
633 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
637 Token
->Status
= EFI_ABORTED
;
638 Token
->Packet
.TxData
= TxData
;
640 Status
= gBS
->CreateEvent (
643 Ping6OnEchoRequestSent
,
648 if (EFI_ERROR (Status
)) {
659 Transmit the PING_IPX_COMPLETION_TOKEN.
661 @param[in] Private The pointer of PING_PRIVATE_DATA.
663 @retval EFI_SUCCESS Transmitted successfully.
664 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
665 @retval others Transmitted unsuccessfully.
670 PingSendEchoRequest (
671 IN PING_PRIVATE_DATA
*Private
675 PING_ICMPX_TX_INFO
*TxInfo
;
677 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
679 if (TxInfo
== NULL
) {
680 return EFI_OUT_OF_RESOURCES
;
683 TxInfo
->TimeStamp
= ReadTime ();
684 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
685 TxInfo
->Token
= PingGenerateToken (
691 if (TxInfo
->Token
== NULL
) {
692 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
693 return EFI_OUT_OF_RESOURCES
;
696 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
697 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
699 if (EFI_ERROR (Status
)) {
700 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
704 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
711 Place a completion token into the receive packet queue to receive the echo reply.
713 @param[in] Private The pointer of PING_PRIVATE_DATA.
715 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
716 @retval others Put the token into the receive packet queue unsuccessfully.
721 Ping6ReceiveEchoReply (
722 IN PING_PRIVATE_DATA
*Private
727 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
729 Status
= gBS
->CreateEvent (
732 Ping6OnEchoReplyReceived
,
734 &Private
->RxToken
.Event
737 if (EFI_ERROR (Status
)) {
741 Private
->RxToken
.Status
= EFI_NOT_READY
;
743 return (Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
));
747 Remove the timeout request from the list.
749 @param[in] Event A EFI_EVENT type event.
750 @param[in] Context The pointer to Context.
755 Ping6OnTimerRoutine (
761 PING_PRIVATE_DATA
*Private
;
762 PING_ICMPX_TX_INFO
*TxInfo
;
764 LIST_ENTRY
*NextEntry
;
767 Private
= (PING_PRIVATE_DATA
*) Context
;
768 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
769 Private
->Status
= EFI_NOT_FOUND
;
774 // Retransmit icmp6 echo request packets per second in sendnumber times.
776 if (Private
->TxCount
< Private
->SendNum
) {
778 Status
= PingSendEchoRequest (Private
);
779 if (Private
->TxCount
!= 0){
780 if (EFI_ERROR (Status
)) {
781 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
786 // Check whether any icmp6 echo request in the list timeout.
788 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
789 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
790 Time
= CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
793 // Remove the timeout echo request from txlist.
795 if (Time
> DEFAULT_TIMEOUT
) {
797 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
798 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
801 // Remove the timeout icmp6 echo request from list.
803 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
805 RemoveEntryList (&TxInfo
->Link
);
806 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
808 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
810 // All the left icmp6 echo request in the list timeout.
812 Private
->Status
= EFI_TIMEOUT
;
819 Determine if a IP4 address is Link Local.
821 169.254.1.0 through 169.254.254.255 is link local.
823 @param[in] Address The address to test.
826 @retval FALSE It is not.
830 PingNetIp4IsLinkLocalAddr (
831 IN CONST EFI_IPv4_ADDRESS
*Address
834 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
838 Determine if a IP4 address is unspecified.
840 @param[in] Address The address to test.
843 @retval FALSE It is not.
847 PingNetIp4IsUnspecifiedAddr (
848 IN CONST EFI_IPv4_ADDRESS
*Address
851 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
855 Create a valid IP instance.
857 @param[in] Private The pointer of PING_PRIVATE_DATA.
859 @retval EFI_SUCCESS Create a valid IPx instance successfully.
860 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
861 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
862 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
863 @retval EFI_NOT_FOUND The source address is not found.
867 PingCreateIpInstance (
868 IN PING_PRIVATE_DATA
*Private
874 EFI_HANDLE
*HandleBuffer
;
875 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
877 EFI_IP6_CONFIG_DATA Ip6Config
;
878 EFI_IP4_CONFIG_DATA Ip4Config
;
879 VOID
*IpXInterfaceInfo
;
881 EFI_IPv6_ADDRESS
*Addr
;
886 IpXInterfaceInfo
= NULL
;
890 // Locate all the handles with ip6 service binding protocol.
892 Status
= gBS
->LocateHandleBuffer (
894 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
899 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
903 // Source address is required when pinging a link-local address on multi-
906 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
907 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
908 NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) &&
910 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", mSrcString
);
911 Status
= EFI_INVALID_PARAMETER
;
915 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
916 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) &&
917 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
) &&
919 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", mSrcString
);
920 Status
= EFI_INVALID_PARAMETER
;
925 // For each ip6 protocol, check interface addresses list.
927 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
930 IpXInterfaceInfo
= NULL
;
933 Status
= gBS
->HandleProtocol (
934 HandleBuffer
[HandleIndex
],
935 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
938 if (EFI_ERROR (Status
)) {
942 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
?NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
):PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
944 // No need to match interface address.
949 // Ip6config protocol and ip6 service binding protocol are installed
950 // on the same handle.
952 Status
= gBS
->HandleProtocol (
953 HandleBuffer
[HandleIndex
],
954 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4Config2ProtocolGuid
,
958 if (EFI_ERROR (Status
)) {
962 // Get the interface information size.
964 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
965 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
967 Ip6ConfigDataTypeInterfaceInfo
,
972 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
974 Ip4Config2DataTypeInterfaceInfo
,
981 // Skip the ones not in current use.
983 if (Status
== EFI_NOT_STARTED
) {
987 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
988 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
992 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
994 if (IpXInterfaceInfo
== NULL
) {
995 Status
= EFI_OUT_OF_RESOURCES
;
999 // Get the interface info.
1001 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1002 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1004 Ip6ConfigDataTypeInterfaceInfo
,
1009 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1011 Ip4Config2DataTypeInterfaceInfo
,
1017 if (EFI_ERROR (Status
)) {
1018 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1022 // Check whether the source address is one of the interface addresses.
1024 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1025 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1027 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1028 if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1030 // Match a certain interface address.
1036 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1038 // Found a nic handle with right interface address.
1044 // IP4 address check
1046 if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1048 // Match a certain interface address.
1055 FreePool (IpXInterfaceInfo
);
1056 IpXInterfaceInfo
= NULL
;
1059 // No exact interface address matched.
1062 if (HandleIndex
== HandleNum
) {
1063 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1064 Status
= EFI_NOT_FOUND
;
1068 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1070 ASSERT (EfiSb
!= NULL
);
1071 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1073 if (EFI_ERROR (Status
)) {
1076 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1077 Status
= gBS
->OpenProtocol (
1078 Private
->IpChildHandle
,
1079 &gEfiIp6ProtocolGuid
,
1080 &Private
->IpProtocol
,
1082 Private
->IpChildHandle
,
1083 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1085 if (EFI_ERROR (Status
)) {
1090 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1093 // Configure the ip6 instance for icmp6 packet exchange.
1095 Ip6Config
.DefaultProtocol
= 58;
1096 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1097 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1098 Ip6Config
.AcceptPromiscuous
= FALSE
;
1099 Ip6Config
.TrafficClass
= 0;
1100 Ip6Config
.HopLimit
= 128;
1101 Ip6Config
.FlowLabel
= 0;
1102 Ip6Config
.ReceiveTimeout
= 0;
1103 Ip6Config
.TransmitTimeout
= 0;
1105 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1106 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1108 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1110 if (EFI_ERROR (Status
)) {
1111 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1115 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1116 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1117 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1118 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1120 Status
= gBS
->OpenProtocol (
1121 Private
->IpChildHandle
,
1122 &gEfiIp4ProtocolGuid
,
1123 &Private
->IpProtocol
,
1125 Private
->IpChildHandle
,
1126 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1128 if (EFI_ERROR (Status
)) {
1133 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1136 // Configure the ip4 instance for icmp4 packet exchange.
1138 Ip4Config
.DefaultProtocol
= 1;
1139 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1140 Ip4Config
.AcceptBroadcast
= FALSE
;
1141 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1142 Ip4Config
.AcceptPromiscuous
= FALSE
;
1143 Ip4Config
.DoNotFragment
= FALSE
;
1144 Ip4Config
.RawData
= FALSE
;
1145 Ip4Config
.ReceiveTimeout
= 0;
1146 Ip4Config
.TransmitTimeout
= 0;
1147 Ip4Config
.UseDefaultAddress
= TRUE
;
1148 Ip4Config
.TimeToLive
= 128;
1149 Ip4Config
.TypeOfService
= 0;
1151 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1153 if (EFI_ERROR (Status
)) {
1154 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1158 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1159 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1160 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1161 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1164 if (HandleBuffer
!= NULL
) {
1165 FreePool (HandleBuffer
);
1171 if (HandleBuffer
!= NULL
) {
1172 FreePool (HandleBuffer
);
1175 if (IpXInterfaceInfo
!= NULL
) {
1176 FreePool (IpXInterfaceInfo
);
1179 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1180 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1187 Destroy the IP instance.
1189 @param[in] Private The pointer of PING_PRIVATE_DATA.
1194 Ping6DestroyIp6Instance (
1195 IN PING_PRIVATE_DATA
*Private
1199 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1201 gBS
->CloseProtocol (
1202 Private
->IpChildHandle
,
1203 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1205 Private
->IpChildHandle
1208 Status
= gBS
->HandleProtocol (
1210 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1214 if (!EFI_ERROR(Status
)) {
1215 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1222 @param[in] SendNumber The send request count.
1223 @param[in] BufferSize The send buffer size.
1224 @param[in] SrcAddress The source address.
1225 @param[in] DstAddress The destination address.
1226 @param[in] IpChoice The choice between IPv4 and IPv6.
1228 @retval SHELL_SUCCESS The ping processed successfullly.
1229 @retval others The ping processed unsuccessfully.
1234 IN UINT32 SendNumber
,
1235 IN UINT32 BufferSize
,
1236 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1237 IN EFI_IPv6_ADDRESS
*DstAddress
,
1242 PING_PRIVATE_DATA
*Private
;
1243 PING_ICMPX_TX_INFO
*TxInfo
;
1245 LIST_ENTRY
*NextEntry
;
1246 SHELL_STATUS ShellStatus
;
1248 ShellStatus
= SHELL_SUCCESS
;
1249 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1251 if (Private
== NULL
) {
1252 return (SHELL_OUT_OF_RESOURCES
);
1255 Private
->IpChoice
= IpChoice
;
1256 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1257 Private
->SendNum
= SendNumber
;
1258 Private
->BufferSize
= BufferSize
;
1259 Private
->RttMin
= ~((UINT64
)(0x0));
1260 Private
->Status
= EFI_NOT_READY
;
1262 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1263 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1265 InitializeListHead (&Private
->TxList
);
1268 // Open and configure a ip instance for us.
1270 Status
= PingCreateIpInstance (Private
);
1272 if (EFI_ERROR (Status
)) {
1273 ShellStatus
= SHELL_ACCESS_DENIED
;
1277 // Print the command line itself.
1279 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1281 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1283 Status
= Ping6ReceiveEchoReply (Private
);
1285 if (EFI_ERROR (Status
)) {
1286 ShellStatus
= SHELL_ACCESS_DENIED
;
1290 // Create and start timer to send icmp6 echo request packet per second.
1292 Status
= gBS
->CreateEvent (
1293 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1295 Ping6OnTimerRoutine
,
1300 if (EFI_ERROR (Status
)) {
1301 ShellStatus
= SHELL_ACCESS_DENIED
;
1305 // Create a ipv6 token to send the first icmp6 echo request packet.
1307 Status
= PingSendEchoRequest (Private
);
1309 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1311 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1312 ShellStatus
= SHELL_ACCESS_DENIED
;
1313 if(Status
== EFI_NOT_FOUND
) {
1314 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1315 } else if (Status
== RETURN_NO_MAPPING
) {
1316 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1318 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1324 Status
= gBS
->SetTimer (
1330 if (EFI_ERROR (Status
)) {
1331 ShellStatus
= SHELL_ACCESS_DENIED
;
1335 // Control the ping6 process by two factors:
1337 // 2. Private->Status
1338 // 2.1. success means all icmp6 echo request packets get reply packets.
1339 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1340 // 2.3. noready means ping6 process is on-the-go.
1342 while (Private
->Status
== EFI_NOT_READY
) {
1343 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1344 if (ShellGetExecutionBreakFlag()) {
1345 Private
->Status
= EFI_ABORTED
;
1352 // Display the statistics in all.
1354 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1356 if (Private
->TxCount
!= 0) {
1361 STRING_TOKEN (STR_PING_STAT
),
1362 gShellNetwork1HiiHandle
,
1365 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
1370 if (Private
->RxCount
!= 0) {
1375 STRING_TOKEN (STR_PING_RTT
),
1376 gShellNetwork1HiiHandle
,
1379 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
1385 if (Private
!= NULL
) {
1387 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1388 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1390 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1391 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1394 RemoveEntryList (&TxInfo
->Link
);
1395 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1398 if (Private
->Timer
!= NULL
) {
1399 gBS
->CloseEvent (Private
->Timer
);
1402 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1403 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1406 if (Private
->RxToken
.Event
!= NULL
) {
1407 gBS
->CloseEvent (Private
->RxToken
.Event
);
1410 if (Private
->IpChildHandle
!= NULL
) {
1411 Ping6DestroyIp6Instance (Private
);
1421 Function for 'ping' command.
1423 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1424 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1426 @retval SHELL_SUCCESS The ping processed successfullly.
1427 @retval others The ping processed unsuccessfully.
1432 ShellCommandRunPing (
1433 IN EFI_HANDLE ImageHandle
,
1434 IN EFI_SYSTEM_TABLE
*SystemTable
1438 SHELL_STATUS ShellStatus
;
1439 EFI_IPv6_ADDRESS DstAddress
;
1440 EFI_IPv6_ADDRESS SrcAddress
;
1443 LIST_ENTRY
*ParamPackage
;
1444 CONST CHAR16
*ValueStr
;
1445 UINTN NonOptionCount
;
1447 CHAR16
*ProblemParam
;
1450 // we use IPv6 buffers to hold items...
1451 // make sure this is enough space!
1453 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1454 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1456 IpChoice
= PING_IP_CHOICE_IP4
;
1458 ShellStatus
= SHELL_SUCCESS
;
1459 ProblemParam
= NULL
;
1461 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1462 if (EFI_ERROR(Status
)) {
1463 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1464 ShellStatus
= SHELL_INVALID_PARAMETER
;
1468 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1469 IpChoice
= PING_IP_CHOICE_IP6
;
1473 // Parse the paramter of count number.
1475 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1476 if (ValueStr
!= NULL
) {
1477 SendNumber
= ShellStrToUintn (ValueStr
);
1480 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1482 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1483 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1484 ShellStatus
= SHELL_INVALID_PARAMETER
;
1488 SendNumber
= DEFAULT_SEND_COUNT
;
1491 // Parse the paramter of buffer size.
1493 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1494 if (ValueStr
!= NULL
) {
1495 BufferSize
= ShellStrToUintn (ValueStr
);
1498 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1500 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1501 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1502 ShellStatus
= SHELL_INVALID_PARAMETER
;
1506 BufferSize
= DEFAULT_BUFFER_SIZE
;
1509 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1510 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1513 // Parse the paramter of source ip address.
1515 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1516 if (ValueStr
!= NULL
) {
1517 mSrcString
= ValueStr
;
1518 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1519 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1521 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1523 if (EFI_ERROR (Status
)) {
1524 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1525 ShellStatus
= SHELL_INVALID_PARAMETER
;
1530 // Parse the paramter of destination ip address.
1532 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1533 if (NonOptionCount
< 2) {
1534 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1535 ShellStatus
= SHELL_INVALID_PARAMETER
;
1538 if (NonOptionCount
> 2) {
1539 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1540 ShellStatus
= SHELL_INVALID_PARAMETER
;
1543 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1544 if (ValueStr
!= NULL
) {
1545 mDstString
= ValueStr
;
1546 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1547 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1549 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1551 if (EFI_ERROR (Status
)) {
1552 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1553 ShellStatus
= SHELL_INVALID_PARAMETER
;
1558 // Get frequency to calculate the time from ticks.
1560 Status
= GetFrequency ();
1562 if (EFI_ERROR(Status
)) {
1566 // Enter into ping process.
1568 ShellStatus
= ShellPing (
1577 ShellCommandLineFreeVarList (ParamPackage
);