2 The implementation for Ping shell command.
4 Copyright (c) 2015, Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2012, 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 CurrentTick
= 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, &CurrentTick
, &TimerPeriod
);
239 if (EFI_ERROR (Status
)) {
241 // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the
242 // TimerPeriod by ourselves.
244 CurrentTick
+= 1000000;
252 Get and caculate the frequency in tick/ms.
253 The result is saved in the globle variable mFrequency
255 @retval EFI_SUCCESS Caculated the frequency successfully.
256 @retval Others Failed to caculate 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 tick/ms.
284 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
290 Caculate 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 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
610 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
611 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
612 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
613 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
614 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
615 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
617 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
618 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
619 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
620 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
621 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
622 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
623 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
624 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
625 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
626 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
627 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
629 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
630 Request
->TimeStamp
= TimeStamp
;
631 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
632 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
636 Token
->Status
= EFI_ABORTED
;
637 Token
->Packet
.TxData
= TxData
;
639 Status
= gBS
->CreateEvent (
642 Ping6OnEchoRequestSent
,
647 if (EFI_ERROR (Status
)) {
658 Transmit the PING_IPX_COMPLETION_TOKEN.
660 @param[in] Private The pointer of PING_PRIVATE_DATA.
662 @retval EFI_SUCCESS Transmitted successfully.
663 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
664 @retval others Transmitted unsuccessfully.
669 PingSendEchoRequest (
670 IN PING_PRIVATE_DATA
*Private
674 PING_ICMPX_TX_INFO
*TxInfo
;
676 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
678 if (TxInfo
== NULL
) {
679 return EFI_OUT_OF_RESOURCES
;
682 TxInfo
->TimeStamp
= ReadTime ();
683 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
684 TxInfo
->Token
= PingGenerateToken (
690 if (TxInfo
->Token
== NULL
) {
691 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
692 return EFI_OUT_OF_RESOURCES
;
695 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
696 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
698 if (EFI_ERROR (Status
)) {
699 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
703 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
710 Place a completion token into the receive packet queue to receive the echo reply.
712 @param[in] Private The pointer of PING_PRIVATE_DATA.
714 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
715 @retval others Put the token into the receive packet queue unsuccessfully.
720 Ping6ReceiveEchoReply (
721 IN PING_PRIVATE_DATA
*Private
726 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
728 Status
= gBS
->CreateEvent (
731 Ping6OnEchoReplyReceived
,
733 &Private
->RxToken
.Event
736 if (EFI_ERROR (Status
)) {
740 Private
->RxToken
.Status
= EFI_NOT_READY
;
742 return (Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
));
746 Remove the timeout request from the list.
748 @param[in] Event A EFI_EVENT type event.
749 @param[in] Context The pointer to Context.
754 Ping6OnTimerRoutine (
760 PING_PRIVATE_DATA
*Private
;
761 PING_ICMPX_TX_INFO
*TxInfo
;
763 LIST_ENTRY
*NextEntry
;
766 Private
= (PING_PRIVATE_DATA
*) Context
;
767 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
768 Private
->Status
= EFI_NOT_FOUND
;
773 // Retransmit icmp6 echo request packets per second in sendnumber times.
775 if (Private
->TxCount
< Private
->SendNum
) {
777 Status
= PingSendEchoRequest (Private
);
778 if (Private
->TxCount
!= 0){
779 if (EFI_ERROR (Status
)) {
780 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
785 // Check whether any icmp6 echo request in the list timeout.
787 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
788 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
789 Time
= CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
792 // Remove the timeout echo request from txlist.
794 if (Time
> DEFAULT_TIMEOUT
) {
796 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
797 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
800 // Remove the timeout icmp6 echo request from list.
802 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
804 RemoveEntryList (&TxInfo
->Link
);
805 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
808 // We dont need to wait for this some other time...
812 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
814 // All the left icmp6 echo request in the list timeout.
816 Private
->Status
= EFI_TIMEOUT
;
823 Determine if a IP4 address is Link Local.
825 169.254.1.0 through 169.254.254.255 is link local.
827 @param[in] Address The address to test.
830 @retval FALSE It is not.
834 PingNetIp4IsLinkLocalAddr (
835 IN CONST EFI_IPv4_ADDRESS
*Address
838 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
842 Determine if a IP4 address is unspecified.
844 @param[in] Address The address to test.
847 @retval FALSE It is not.
851 PingNetIp4IsUnspecifiedAddr (
852 IN CONST EFI_IPv4_ADDRESS
*Address
855 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
859 Create a valid IP instance.
861 @param[in] Private The pointer of PING_PRIVATE_DATA.
863 @retval EFI_SUCCESS Create a valid IPx instance successfully.
864 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
865 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
866 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
867 @retval EFI_NOT_FOUND The source address is not found.
871 PingCreateIpInstance (
872 IN PING_PRIVATE_DATA
*Private
878 EFI_HANDLE
*HandleBuffer
;
879 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
881 EFI_IP6_CONFIG_DATA Ip6Config
;
882 EFI_IP4_CONFIG_DATA Ip4Config
;
883 VOID
*IpXInterfaceInfo
;
885 EFI_IPv6_ADDRESS
*Addr
;
890 IpXInterfaceInfo
= NULL
;
894 // Locate all the handles with ip6 service binding protocol.
896 Status
= gBS
->LocateHandleBuffer (
898 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
903 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
907 // Source address is required when pinging a link-local address on multi-
910 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
911 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
912 NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) &&
914 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", mSrcString
);
915 Status
= EFI_INVALID_PARAMETER
;
919 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
920 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) &&
921 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
) &&
923 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", mSrcString
);
924 Status
= EFI_INVALID_PARAMETER
;
929 // For each ip6 protocol, check interface addresses list.
931 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
934 IpXInterfaceInfo
= NULL
;
937 Status
= gBS
->HandleProtocol (
938 HandleBuffer
[HandleIndex
],
939 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
942 if (EFI_ERROR (Status
)) {
946 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
?NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
):PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
948 // No need to match interface address.
953 // Ip6config protocol and ip6 service binding protocol are installed
954 // on the same handle.
956 Status
= gBS
->HandleProtocol (
957 HandleBuffer
[HandleIndex
],
958 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4ConfigProtocolGuid
,
962 if (EFI_ERROR (Status
)) {
966 // Get the interface information size.
968 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
969 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
971 Ip6ConfigDataTypeInterfaceInfo
,
976 Status
= ((EFI_IP4_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
984 // Skip the ones not in current use.
986 if (Status
== EFI_NOT_STARTED
) {
990 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
991 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
995 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
997 if (IpXInterfaceInfo
== NULL
) {
998 Status
= EFI_OUT_OF_RESOURCES
;
1002 // Get the interface info.
1004 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1005 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1007 Ip6ConfigDataTypeInterfaceInfo
,
1012 Status
= ((EFI_IP4_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1019 if (EFI_ERROR (Status
)) {
1020 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1024 // Check whether the source address is one of the interface addresses.
1026 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1027 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1029 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1030 if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1032 // Match a certain interface address.
1038 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1040 // Found a nic handle with right interface address.
1046 // IP4 address check
1048 if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_IPCONFIG_DATA
*)IpXInterfaceInfo
)->StationAddress
)) {
1050 // Match a certain interface address.
1057 FreePool (IpXInterfaceInfo
);
1058 IpXInterfaceInfo
= NULL
;
1061 // No exact interface address matched.
1064 if (HandleIndex
== HandleNum
) {
1065 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1066 Status
= EFI_NOT_FOUND
;
1070 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1072 ASSERT (EfiSb
!= NULL
);
1073 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1075 if (EFI_ERROR (Status
)) {
1078 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1079 Status
= gBS
->OpenProtocol (
1080 Private
->IpChildHandle
,
1081 &gEfiIp6ProtocolGuid
,
1082 &Private
->IpProtocol
,
1084 Private
->IpChildHandle
,
1085 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1087 if (EFI_ERROR (Status
)) {
1092 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1095 // Configure the ip6 instance for icmp6 packet exchange.
1097 Ip6Config
.DefaultProtocol
= 58;
1098 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1099 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1100 Ip6Config
.AcceptPromiscuous
= FALSE
;
1101 Ip6Config
.TrafficClass
= 0;
1102 Ip6Config
.HopLimit
= 128;
1103 Ip6Config
.FlowLabel
= 0;
1104 Ip6Config
.ReceiveTimeout
= 0;
1105 Ip6Config
.TransmitTimeout
= 0;
1107 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1108 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1110 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1112 if (EFI_ERROR (Status
)) {
1113 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1117 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1118 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1119 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1120 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1122 Status
= gBS
->OpenProtocol (
1123 Private
->IpChildHandle
,
1124 &gEfiIp4ProtocolGuid
,
1125 &Private
->IpProtocol
,
1127 Private
->IpChildHandle
,
1128 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1130 if (EFI_ERROR (Status
)) {
1135 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1138 // Configure the ip4 instance for icmp4 packet exchange.
1140 // PING_IP4_COPY_ADDRESS (&Ip4Config.StationAddress, &Private->SrcAddress);
1141 // Ip4Config.SubnetMask.Addr[0] = 0xFF;
1142 // Ip4Config.SubnetMask.Addr[1] = 0xFF;
1143 // Ip4Config.SubnetMask.Addr[2] = 0xFF;
1144 // Ip4Config.SubnetMask.Addr[3] = 0x00;
1145 Ip4Config
.DefaultProtocol
= 1;
1146 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1147 Ip4Config
.AcceptBroadcast
= FALSE
;
1148 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1149 Ip4Config
.AcceptPromiscuous
= FALSE
;
1150 Ip4Config
.DoNotFragment
= FALSE
;
1151 Ip4Config
.RawData
= FALSE
;
1152 Ip4Config
.ReceiveTimeout
= 0;
1153 Ip4Config
.TransmitTimeout
= 0;
1154 Ip4Config
.UseDefaultAddress
= TRUE
;
1155 Ip4Config
.TimeToLive
= 128;
1156 Ip4Config
.TypeOfService
= 0;
1158 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1160 if (EFI_ERROR (Status
)) {
1161 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1165 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1166 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1167 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1168 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1171 if (HandleBuffer
!= NULL
) {
1172 FreePool (HandleBuffer
);
1178 if (HandleBuffer
!= NULL
) {
1179 FreePool (HandleBuffer
);
1182 if (IpXInterfaceInfo
!= NULL
) {
1183 FreePool (IpXInterfaceInfo
);
1186 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1187 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1194 Destroy the IP instance.
1196 @param[in] Private The pointer of PING_PRIVATE_DATA.
1201 Ping6DestroyIp6Instance (
1202 IN PING_PRIVATE_DATA
*Private
1206 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1208 gBS
->CloseProtocol (
1209 Private
->IpChildHandle
,
1210 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1212 Private
->IpChildHandle
1215 Status
= gBS
->HandleProtocol (
1217 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1221 if (!EFI_ERROR(Status
)) {
1222 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1229 @param[in] SendNumber The send request count.
1230 @param[in] BufferSize The send buffer size.
1231 @param[in] SrcAddress The source address.
1232 @param[in] DstAddress The destination address.
1233 @param[in] IpChoice The choice between IPv4 and IPv6.
1235 @retval SHELL_SUCCESS The ping processed successfullly.
1236 @retval others The ping processed unsuccessfully.
1241 IN UINT32 SendNumber
,
1242 IN UINT32 BufferSize
,
1243 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1244 IN EFI_IPv6_ADDRESS
*DstAddress
,
1249 PING_PRIVATE_DATA
*Private
;
1250 PING_ICMPX_TX_INFO
*TxInfo
;
1252 LIST_ENTRY
*NextEntry
;
1253 SHELL_STATUS ShellStatus
;
1255 ShellStatus
= SHELL_SUCCESS
;
1256 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1258 if (Private
== NULL
) {
1259 return (SHELL_OUT_OF_RESOURCES
);
1262 Private
->IpChoice
= IpChoice
;
1263 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1264 Private
->SendNum
= SendNumber
;
1265 Private
->BufferSize
= BufferSize
;
1266 Private
->RttMin
= ~((UINT64
)(0x0));
1267 Private
->Status
= EFI_NOT_READY
;
1269 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1270 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1272 InitializeListHead (&Private
->TxList
);
1275 // Open and configure a ip instance for us.
1277 Status
= PingCreateIpInstance (Private
);
1279 if (EFI_ERROR (Status
)) {
1280 ShellStatus
= SHELL_ACCESS_DENIED
;
1284 // Print the command line itself.
1286 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1288 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1290 Status
= Ping6ReceiveEchoReply (Private
);
1292 if (EFI_ERROR (Status
)) {
1293 ShellStatus
= SHELL_ACCESS_DENIED
;
1297 // Create and start timer to send icmp6 echo request packet per second.
1299 Status
= gBS
->CreateEvent (
1300 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1302 Ping6OnTimerRoutine
,
1307 if (EFI_ERROR (Status
)) {
1308 ShellStatus
= SHELL_ACCESS_DENIED
;
1312 // Create a ipv6 token to send the first icmp6 echo request packet.
1314 Status
= PingSendEchoRequest (Private
);
1316 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1318 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1319 ShellStatus
= SHELL_ACCESS_DENIED
;
1320 if(Status
== EFI_NOT_FOUND
) {
1321 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1322 } else if (Status
== RETURN_NO_MAPPING
) {
1323 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1325 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1331 Status
= gBS
->SetTimer (
1337 if (EFI_ERROR (Status
)) {
1338 ShellStatus
= SHELL_ACCESS_DENIED
;
1342 // Control the ping6 process by two factors:
1344 // 2. Private->Status
1345 // 2.1. success means all icmp6 echo request packets get reply packets.
1346 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1347 // 2.3. noready means ping6 process is on-the-go.
1349 while (Private
->Status
== EFI_NOT_READY
) {
1350 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1351 if (ShellGetExecutionBreakFlag()) {
1352 Private
->Status
= EFI_ABORTED
;
1359 // Display the statistics in all.
1361 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1363 if (Private
->TxCount
!= 0) {
1368 STRING_TOKEN (STR_PING_STAT
),
1369 gShellNetwork1HiiHandle
,
1372 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
1377 if (Private
->RxCount
!= 0) {
1382 STRING_TOKEN (STR_PING_RTT
),
1383 gShellNetwork1HiiHandle
,
1386 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
1392 if (Private
!= NULL
) {
1394 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1395 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1397 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1398 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1401 RemoveEntryList (&TxInfo
->Link
);
1402 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1405 if (Private
->Timer
!= NULL
) {
1406 gBS
->CloseEvent (Private
->Timer
);
1409 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1410 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1413 if (Private
->RxToken
.Event
!= NULL
) {
1414 gBS
->CloseEvent (Private
->RxToken
.Event
);
1417 if (Private
->IpChildHandle
!= NULL
) {
1418 Ping6DestroyIp6Instance (Private
);
1428 Function for 'ping' command.
1430 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1431 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1435 ShellCommandRunPing (
1436 IN EFI_HANDLE ImageHandle
,
1437 IN EFI_SYSTEM_TABLE
*SystemTable
1441 SHELL_STATUS ShellStatus
;
1442 EFI_IPv6_ADDRESS DstAddress
;
1443 EFI_IPv6_ADDRESS SrcAddress
;
1446 LIST_ENTRY
*ParamPackage
;
1447 CONST CHAR16
*ValueStr
;
1448 UINTN NonOptionCount
;
1450 CHAR16
*ProblemParam
;
1453 // we use IPv6 buffers to hold items...
1454 // make sure this is enough space!
1456 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1457 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1459 IpChoice
= PING_IP_CHOICE_IP4
;
1461 ShellStatus
= SHELL_SUCCESS
;
1462 ProblemParam
= NULL
;
1464 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1465 if (EFI_ERROR(Status
)) {
1466 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1467 ShellStatus
= SHELL_INVALID_PARAMETER
;
1471 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1472 IpChoice
= PING_IP_CHOICE_IP6
;
1476 // Parse the paramter of count number.
1478 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1479 if (ValueStr
!= NULL
) {
1480 SendNumber
= ShellStrToUintn (ValueStr
);
1483 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1485 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1486 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1487 ShellStatus
= SHELL_INVALID_PARAMETER
;
1491 SendNumber
= DEFAULT_SEND_COUNT
;
1494 // Parse the paramter of buffer size.
1496 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1497 if (ValueStr
!= NULL
) {
1498 BufferSize
= ShellStrToUintn (ValueStr
);
1501 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1503 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1504 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1505 ShellStatus
= SHELL_INVALID_PARAMETER
;
1509 BufferSize
= DEFAULT_BUFFER_SIZE
;
1512 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1513 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1516 // Parse the paramter of source ip address.
1518 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1519 if (ValueStr
!= NULL
) {
1520 mSrcString
= ValueStr
;
1521 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1522 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1524 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1526 if (EFI_ERROR (Status
)) {
1527 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1528 ShellStatus
= SHELL_INVALID_PARAMETER
;
1533 // Parse the paramter of destination ip address.
1535 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1536 if (NonOptionCount
< 2) {
1537 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1538 ShellStatus
= SHELL_INVALID_PARAMETER
;
1541 if (NonOptionCount
> 2) {
1542 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1543 ShellStatus
= SHELL_INVALID_PARAMETER
;
1546 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1547 if (ValueStr
!= NULL
) {
1548 mDstString
= ValueStr
;
1549 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1550 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1552 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1554 if (EFI_ERROR (Status
)) {
1555 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1556 ShellStatus
= SHELL_INVALID_PARAMETER
;
1561 // Get frequency to calculate the time from ticks.
1563 Status
= GetFrequency ();
1565 if (EFI_ERROR(Status
)) {
1569 // Enter into ping process.
1571 ShellStatus
= ShellPing (
1580 ShellCommandLineFreeVarList (ParamPackage
);