2 The implementation for Ping shell command.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "UefiShellNetwork1CommandsLib.h"
14 #define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))
16 UINT64 mCurrentTick
= 0;
19 // Function templates to match the IPv4 and IPv6 commands that we use.
23 (EFIAPI
*PING_IPX_POLL
)(
29 (EFIAPI
*PING_IPX_TRANSMIT
)(
36 (EFIAPI
*PING_IPX_RECEIVE
)(
43 (EFIAPI
*PING_IPX_CANCEL
)(
45 IN VOID
*Token OPTIONAL
49 /// A set of pointers to either IPv6 or IPv4 functions.
50 /// Unknown which one to the ping command.
53 PING_IPX_TRANSMIT Transmit
;
54 PING_IPX_RECEIVE Receive
;
55 PING_IPX_CANCEL Cancel
;
66 // PING_IPX_COMPLETION_TOKEN
67 // structures are used for both transmit and receive operations.
68 // This version is IP-unaware.
74 } PING_IPX_COMPLETION_TOKEN
;
77 typedef struct _ICMPX_ECHO_REQUEST_REPLY
{
85 } ICMPX_ECHO_REQUEST_REPLY
;
88 typedef struct _PING_ICMP_TX_INFO
{
92 PING_IPX_COMPLETION_TOKEN
*Token
;
95 #define DEFAULT_TIMEOUT 5000
96 #define MAX_SEND_NUMBER 10000
97 #define MAX_BUFFER_SIZE 32768
98 #define DEFAULT_TIMER_PERIOD 358049
99 #define ONE_SECOND 10000000
100 #define PING_IP_CHOICE_IP4 1
101 #define PING_IP_CHOICE_IP6 2
102 #define DEFAULT_SEND_COUNT 10
103 #define DEFAULT_BUFFER_SIZE 16
104 #define ICMP_V4_ECHO_REQUEST 0x8
105 #define ICMP_V4_ECHO_REPLY 0x0
106 #define STALL_1_MILLI_SECOND 1000
108 #define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')
109 typedef struct _PING_PRIVATE_DATA
{
111 EFI_HANDLE NicHandle
;
112 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
;
141 Calculate the internet checksum (see RFC 1071).
143 @param[in] Packet Buffer which contains the data to be checksummed.
144 @param[in] Length Length to be checksummed.
146 @retval Checksum Returns the 16 bit ones complement of
147 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
[] = {
219 // Global Variables in Ping command.
221 STATIC CONST CHAR16
*mDstString
;
222 STATIC CONST CHAR16
*mSrcString
;
225 RTT timer tick routine.
227 @param[in] Event A EFI_EVENT type event.
228 @param[in] Context The pointer to Context.
233 RttTimerTickRoutine (
238 UINT32
*RttTimerTick
;
240 RttTimerTick
= (UINT32
*) Context
;
245 Get the timer period of the system.
247 This function tries to get the system timer period by creating
250 @return System timer period in MS, or 0 if operation failed.
260 EFI_EVENT TimerEvent
;
267 Status
= gBS
->CreateEvent (
268 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
274 if (EFI_ERROR (Status
)) {
278 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
279 Status
= gBS
->SetTimer (
284 if (EFI_ERROR (Status
)) {
285 gBS
->CloseEvent (TimerEvent
);
289 while (RttTimerTick
< 10) {
290 gBS
->Stall (STALL_1_MILLI_SECOND
);
294 gBS
->RestoreTPL (OldTpl
);
296 gBS
->SetTimer (TimerEvent
, TimerCancel
, 0);
297 gBS
->CloseEvent (TimerEvent
);
299 return StallCounter
/ RttTimerTick
;
303 Initialize the timer event for RTT (round trip time).
305 @param[in] Private The pointer to PING_PRIVATE_DATA.
307 @retval EFI_SUCCESS RTT timer is started.
308 @retval Others Failed to start the RTT timer.
313 PING_PRIVATE_DATA
*Private
318 Private
->TimerPeriod
= GetTimerPeriod ();
319 if (Private
->TimerPeriod
== 0) {
323 Private
->RttTimerTick
= 0;
324 Status
= gBS
->CreateEvent (
325 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
328 &Private
->RttTimerTick
,
331 if (EFI_ERROR (Status
)) {
335 Status
= gBS
->SetTimer (
340 if (EFI_ERROR (Status
)) {
341 gBS
->CloseEvent (Private
->RttTimer
);
349 Free RTT timer event resource.
351 @param[in] Private The pointer to PING_PRIVATE_DATA.
356 PING_PRIVATE_DATA
*Private
359 if (Private
->RttTimer
!= NULL
) {
360 gBS
->SetTimer (Private
->RttTimer
, TimerCancel
, 0);
361 gBS
->CloseEvent (Private
->RttTimer
);
366 Read the current time.
368 @param[in] Private The pointer to PING_PRIVATE_DATA.
370 @retval the current tick value.
374 PING_PRIVATE_DATA
*Private
377 return Private
->RttTimerTick
;
381 Calculate a duration in ms.
383 @param[in] Private The pointer to PING_PRIVATE_DATA.
384 @param[in] Begin The start point of time.
385 @param[in] End The end point of time.
387 @return The duration in ms.
388 @retval 0 The parameters were not valid.
392 PING_PRIVATE_DATA
*Private
,
401 return (End
- Begin
) * Private
->TimerPeriod
;
405 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
407 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
408 @param[in] IpChoice Whether the token is IPv4 or IPv6
412 IN PING_ICMPX_TX_INFO
*TxInfo
,
416 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
417 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
418 EFI_IP6_FRAGMENT_DATA
*FragData
;
421 if (TxInfo
== NULL
) {
425 if (TxInfo
->Token
!= NULL
) {
427 if (TxInfo
->Token
->Event
!= NULL
) {
428 gBS
->CloseEvent (TxInfo
->Token
->Event
);
431 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
432 if (IpChoice
== PING_IP_CHOICE_IP6
) {
433 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
435 if (Ip6TxData
->OverrideData
!= NULL
) {
436 FreePool (Ip6TxData
->OverrideData
);
439 if (Ip6TxData
->ExtHdrs
!= NULL
) {
440 FreePool (Ip6TxData
->ExtHdrs
);
443 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
444 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
445 if (FragData
!= NULL
) {
450 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
452 if (Ip4TxData
->OverrideData
!= NULL
) {
453 FreePool (Ip4TxData
->OverrideData
);
456 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
457 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
458 if (FragData
!= NULL
) {
465 FreePool (TxInfo
->Token
);
472 Match the request, and reply with SequenceNum/TimeStamp.
474 @param[in] Private The pointer to PING_PRIVATE_DATA.
475 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
477 @retval EFI_SUCCESS The match is successful.
478 @retval EFI_NOT_FOUND The reply can't be matched with any request.
482 Ping6MatchEchoReply (
483 IN PING_PRIVATE_DATA
*Private
,
484 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
487 PING_ICMPX_TX_INFO
*TxInfo
;
489 LIST_ENTRY
*NextEntry
;
491 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
492 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
494 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
496 RemoveEntryList (&TxInfo
->Link
);
497 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
502 return EFI_NOT_FOUND
;
506 The original intention is to send a request.
507 Currently, the application retransmits an icmp6 echo request packet
508 per second in sendnumber times that is specified by the user.
509 Because nothing can be done here, all things move to the timer rountine.
511 @param[in] Event A EFI_EVENT type event.
512 @param[in] Context The pointer to Context.
517 Ping6OnEchoRequestSent (
525 receive reply, match and print reply infomation.
527 @param[in] Event A EFI_EVENT type event.
528 @param[in] Context The pointer to context.
533 Ping6OnEchoReplyReceived (
539 PING_PRIVATE_DATA
*Private
;
540 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
544 Private
= (PING_PRIVATE_DATA
*) Context
;
546 if (Private
== NULL
|| Private
->Status
== EFI_ABORTED
|| Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
550 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
554 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
555 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
556 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
557 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
560 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
561 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
)) {
565 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
569 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
570 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
571 if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
572 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
)) {
576 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
582 if (PayLoad
!= Private
->BufferSize
) {
586 // Check whether the reply matches the sent request before.
588 Status
= Ping6MatchEchoReply (Private
, Reply
);
589 if (EFI_ERROR(Status
)) {
593 // Display statistics on this icmp6 echo reply packet.
595 Rtt
= CalculateTick (Private
, Reply
->TimeStamp
, ReadTime (Private
));
597 Private
->RttSum
+= Rtt
;
598 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
599 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
605 STRING_TOKEN (STR_PING_REPLY_INFO
),
606 gShellNetwork1HiiHandle
,
610 Private
->IpChoice
== PING_IP_CHOICE_IP6
?((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
:0,
612 Rtt
+ Private
->TimerPeriod
618 // Recycle the packet before reusing RxToken
620 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
);
622 if (Private
->RxCount
< Private
->SendNum
) {
624 // Continue to receive icmp echo reply packets.
626 Private
->RxToken
.Status
= EFI_ABORTED
;
628 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
630 if (EFI_ERROR (Status
)) {
631 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
632 Private
->Status
= EFI_ABORTED
;
636 // All reply have already been received from the dest host.
638 Private
->Status
= EFI_SUCCESS
;
643 Create a PING_IPX_COMPLETION_TOKEN.
645 @param[in] Private The pointer of PING_PRIVATE_DATA.
646 @param[in] TimeStamp The TimeStamp of request.
647 @param[in] SequenceNum The SequenceNum of request.
649 @return The pointer of PING_IPX_COMPLETION_TOKEN.
652 PING_IPX_COMPLETION_TOKEN
*
654 IN PING_PRIVATE_DATA
*Private
,
656 IN UINT16 SequenceNum
660 PING_IPX_COMPLETION_TOKEN
*Token
;
662 ICMPX_ECHO_REQUEST_REPLY
*Request
;
666 Request
= AllocateZeroPool (Private
->BufferSize
);
667 if (Request
== NULL
) {
670 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
671 if (TxData
== NULL
) {
675 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
683 // Assembly echo request packet.
685 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
687 Request
->SequenceNum
= SequenceNum
;
688 Request
->Identifier
= 0;
689 Request
->Checksum
= 0;
692 // Assembly token for transmit.
694 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
695 Request
->TimeStamp
= TimeStamp
;
696 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
697 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
698 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
699 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
700 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
701 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
702 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
704 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
705 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
706 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
707 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
708 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
709 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
710 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
711 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
712 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
713 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
714 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
716 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
717 Request
->TimeStamp
= TimeStamp
;
718 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
719 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
723 Token
->Status
= EFI_ABORTED
;
724 Token
->Packet
.TxData
= TxData
;
726 Status
= gBS
->CreateEvent (
729 Ping6OnEchoRequestSent
,
734 if (EFI_ERROR (Status
)) {
745 Transmit the PING_IPX_COMPLETION_TOKEN.
747 @param[in] Private The pointer of PING_PRIVATE_DATA.
749 @retval EFI_SUCCESS Transmitted successfully.
750 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
751 @retval others Transmitted unsuccessfully.
755 PingSendEchoRequest (
756 IN PING_PRIVATE_DATA
*Private
760 PING_ICMPX_TX_INFO
*TxInfo
;
762 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
764 if (TxInfo
== NULL
) {
765 return EFI_OUT_OF_RESOURCES
;
768 TxInfo
->TimeStamp
= ReadTime (Private
);
769 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
770 TxInfo
->Token
= PingGenerateToken (
776 if (TxInfo
->Token
== NULL
) {
777 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
778 return EFI_OUT_OF_RESOURCES
;
781 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
783 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
785 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
787 if (EFI_ERROR (Status
)) {
788 RemoveEntryList (&TxInfo
->Link
);
789 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
799 Place a completion token into the receive packet queue to receive the echo reply.
801 @param[in] Private The pointer of PING_PRIVATE_DATA.
803 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
804 @retval others Put the token into the receive packet queue unsuccessfully.
808 Ping6ReceiveEchoReply (
809 IN PING_PRIVATE_DATA
*Private
814 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
816 Status
= gBS
->CreateEvent (
819 Ping6OnEchoReplyReceived
,
821 &Private
->RxToken
.Event
824 if (EFI_ERROR (Status
)) {
828 Private
->RxToken
.Status
= EFI_NOT_READY
;
830 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
831 if (EFI_ERROR (Status
)) {
832 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
838 Remove the timeout request from the list.
840 @param[in] Event A EFI_EVENT type event.
841 @param[in] Context The pointer to Context.
846 Ping6OnTimerRoutine (
852 PING_PRIVATE_DATA
*Private
;
853 PING_ICMPX_TX_INFO
*TxInfo
;
855 LIST_ENTRY
*NextEntry
;
858 Private
= (PING_PRIVATE_DATA
*) Context
;
859 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
860 Private
->Status
= EFI_NOT_FOUND
;
865 // Retransmit icmp6 echo request packets per second in sendnumber times.
867 if (Private
->TxCount
< Private
->SendNum
) {
869 Status
= PingSendEchoRequest (Private
);
870 if (Private
->TxCount
!= 0){
871 if (EFI_ERROR (Status
)) {
872 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
877 // Check whether any icmp6 echo request in the list timeout.
879 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
880 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
881 Time
= CalculateTick (Private
, TxInfo
->TimeStamp
, ReadTime (Private
));
884 // Remove the timeout echo request from txlist.
886 if (Time
> DEFAULT_TIMEOUT
) {
888 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
889 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
892 // Remove the timeout icmp6 echo request from list.
894 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
896 RemoveEntryList (&TxInfo
->Link
);
897 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
900 Private
->FailedCount
++;
902 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
904 // All the left icmp6 echo request in the list timeout.
906 Private
->Status
= EFI_TIMEOUT
;
913 Determine if a IP4 address is Link Local.
915 169.254.1.0 through 169.254.254.255 is link local.
917 @param[in] Address The address to test.
920 @retval FALSE It is not.
923 PingNetIp4IsLinkLocalAddr (
924 IN CONST EFI_IPv4_ADDRESS
*Address
927 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
931 Determine if a IP4 address is unspecified.
933 @param[in] Address The address to test.
936 @retval FALSE It is not.
939 PingNetIp4IsUnspecifiedAddr (
940 IN CONST EFI_IPv4_ADDRESS
*Address
943 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
947 Create a valid IP instance.
949 @param[in] Private The pointer of PING_PRIVATE_DATA.
951 @retval EFI_SUCCESS Create a valid IPx instance successfully.
952 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
953 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
954 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
955 @retval EFI_NOT_FOUND The source address is not found.
958 PingCreateIpInstance (
959 IN PING_PRIVATE_DATA
*Private
965 EFI_HANDLE
*HandleBuffer
;
966 BOOLEAN UnspecifiedSrc
;
967 EFI_STATUS MediaStatus
;
968 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
970 EFI_IP6_CONFIG_DATA Ip6Config
;
971 EFI_IP4_CONFIG_DATA Ip4Config
;
972 VOID
*IpXInterfaceInfo
;
974 EFI_IPv6_ADDRESS
*Addr
;
978 UnspecifiedSrc
= FALSE
;
979 MediaStatus
= EFI_SUCCESS
;
981 IpXInterfaceInfo
= NULL
;
985 // Locate all the handles with ip6 service binding protocol.
987 Status
= gBS
->LocateHandleBuffer (
989 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
994 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
998 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
999 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
1001 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
1003 UnspecifiedSrc
= TRUE
;
1007 // Source address is required when pinging a link-local address.
1009 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1010 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1011 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1012 Status
= EFI_INVALID_PARAMETER
;
1016 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
1017 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1018 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1019 Status
= EFI_INVALID_PARAMETER
;
1025 // For each ip6 protocol, check interface addresses list.
1027 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
1029 IpXInterfaceInfo
= NULL
;
1032 if (UnspecifiedSrc
) {
1036 NetLibDetectMediaWaitTimeout (HandleBuffer
[HandleIndex
], 0, &MediaStatus
);
1037 if (MediaStatus
!= EFI_SUCCESS
) {
1045 Status
= gBS
->HandleProtocol (
1046 HandleBuffer
[HandleIndex
],
1047 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1050 if (EFI_ERROR (Status
)) {
1055 // Ip6config protocol and ip6 service binding protocol are installed
1056 // on the same handle.
1058 Status
= gBS
->HandleProtocol (
1059 HandleBuffer
[HandleIndex
],
1060 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4Config2ProtocolGuid
,
1064 if (EFI_ERROR (Status
)) {
1068 // Get the interface information size.
1070 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1071 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1073 Ip6ConfigDataTypeInterfaceInfo
,
1078 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1080 Ip4Config2DataTypeInterfaceInfo
,
1087 // Skip the ones not in current use.
1089 if (Status
== EFI_NOT_STARTED
) {
1093 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1094 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1098 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1100 if (IpXInterfaceInfo
== NULL
) {
1101 Status
= EFI_OUT_OF_RESOURCES
;
1105 // Get the interface info.
1107 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1108 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1110 Ip6ConfigDataTypeInterfaceInfo
,
1115 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1117 Ip4Config2DataTypeInterfaceInfo
,
1123 if (EFI_ERROR (Status
)) {
1124 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1128 // Check whether the source address is one of the interface addresses.
1130 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1131 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1132 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1134 if (UnspecifiedSrc
) {
1135 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1137 // Select the interface automatically.
1139 CopyMem(&Private
->SrcAddress
, Addr
, sizeof(Private
->SrcAddress
));
1142 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1144 // Match a certain interface address.
1150 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1152 // Found a nic handle with right interface address.
1157 if (UnspecifiedSrc
) {
1158 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1159 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1161 // Select the interface automatically.
1165 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1167 // Match a certain interface address.
1173 FreePool (IpXInterfaceInfo
);
1174 IpXInterfaceInfo
= NULL
;
1177 // No exact interface address matched.
1180 if (HandleIndex
== HandleNum
) {
1181 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1182 Status
= EFI_NOT_FOUND
;
1186 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1188 ASSERT (EfiSb
!= NULL
);
1189 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1191 if (EFI_ERROR (Status
)) {
1194 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1195 Status
= gBS
->OpenProtocol (
1196 Private
->IpChildHandle
,
1197 &gEfiIp6ProtocolGuid
,
1198 &Private
->IpProtocol
,
1200 Private
->IpChildHandle
,
1201 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1203 if (EFI_ERROR (Status
)) {
1208 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1211 // Configure the ip6 instance for icmp6 packet exchange.
1213 Ip6Config
.DefaultProtocol
= 58;
1214 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1215 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1216 Ip6Config
.AcceptPromiscuous
= FALSE
;
1217 Ip6Config
.TrafficClass
= 0;
1218 Ip6Config
.HopLimit
= 128;
1219 Ip6Config
.FlowLabel
= 0;
1220 Ip6Config
.ReceiveTimeout
= 0;
1221 Ip6Config
.TransmitTimeout
= 0;
1223 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1224 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1226 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1228 if (EFI_ERROR (Status
)) {
1229 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1233 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1234 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1235 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1236 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1238 Status
= gBS
->OpenProtocol (
1239 Private
->IpChildHandle
,
1240 &gEfiIp4ProtocolGuid
,
1241 &Private
->IpProtocol
,
1243 Private
->IpChildHandle
,
1244 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1246 if (EFI_ERROR (Status
)) {
1251 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1254 // Configure the ip4 instance for icmp4 packet exchange.
1256 Ip4Config
.DefaultProtocol
= 1;
1257 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1258 Ip4Config
.AcceptBroadcast
= FALSE
;
1259 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1260 Ip4Config
.AcceptPromiscuous
= FALSE
;
1261 Ip4Config
.DoNotFragment
= FALSE
;
1262 Ip4Config
.RawData
= FALSE
;
1263 Ip4Config
.ReceiveTimeout
= 0;
1264 Ip4Config
.TransmitTimeout
= 0;
1265 Ip4Config
.UseDefaultAddress
= TRUE
;
1266 Ip4Config
.TimeToLive
= 128;
1267 Ip4Config
.TypeOfService
= 0;
1269 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1271 if (EFI_ERROR (Status
)) {
1272 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1276 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1277 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1278 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1279 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1282 if (HandleBuffer
!= NULL
) {
1283 FreePool (HandleBuffer
);
1289 if (HandleBuffer
!= NULL
) {
1290 FreePool (HandleBuffer
);
1293 if (IpXInterfaceInfo
!= NULL
) {
1294 FreePool (IpXInterfaceInfo
);
1297 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1298 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1305 Destroy the IP instance.
1307 @param[in] Private The pointer of PING_PRIVATE_DATA.
1311 Ping6DestroyIp6Instance (
1312 IN PING_PRIVATE_DATA
*Private
1316 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1318 gBS
->CloseProtocol (
1319 Private
->IpChildHandle
,
1320 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1322 Private
->IpChildHandle
1325 Status
= gBS
->HandleProtocol (
1327 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1331 if (!EFI_ERROR(Status
)) {
1332 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1340 @param[in] SendNumber The send request count.
1341 @param[in] BufferSize The send buffer size.
1342 @param[in] SrcAddress The source address.
1343 @param[in] DstAddress The destination address.
1344 @param[in] IpChoice The choice between IPv4 and IPv6.
1346 @retval SHELL_SUCCESS The ping processed successfullly.
1347 @retval others The ping processed unsuccessfully.
1351 IN UINT32 SendNumber
,
1352 IN UINT32 BufferSize
,
1353 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1354 IN EFI_IPv6_ADDRESS
*DstAddress
,
1359 PING_PRIVATE_DATA
*Private
;
1360 PING_ICMPX_TX_INFO
*TxInfo
;
1362 LIST_ENTRY
*NextEntry
;
1363 SHELL_STATUS ShellStatus
;
1365 ShellStatus
= SHELL_SUCCESS
;
1366 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1368 if (Private
== NULL
) {
1369 return (SHELL_OUT_OF_RESOURCES
);
1372 Private
->IpChoice
= IpChoice
;
1373 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1374 Private
->SendNum
= SendNumber
;
1375 Private
->BufferSize
= BufferSize
;
1376 Private
->RttMin
= ~((UINT64
)(0x0));
1377 Private
->Status
= EFI_NOT_READY
;
1379 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1380 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1382 InitializeListHead (&Private
->TxList
);
1385 // Open and configure a ip instance for us.
1387 Status
= PingCreateIpInstance (Private
);
1389 if (EFI_ERROR (Status
)) {
1390 ShellStatus
= SHELL_ACCESS_DENIED
;
1394 // Print the command line itself.
1396 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1398 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1400 Status
= Ping6ReceiveEchoReply (Private
);
1402 if (EFI_ERROR (Status
)) {
1403 ShellStatus
= SHELL_ACCESS_DENIED
;
1407 // Create and start timer to send icmp6 echo request packet per second.
1409 Status
= gBS
->CreateEvent (
1410 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1412 Ping6OnTimerRoutine
,
1417 if (EFI_ERROR (Status
)) {
1418 ShellStatus
= SHELL_ACCESS_DENIED
;
1423 // Start a timer to calculate the RTT.
1425 Status
= PingInitRttTimer (Private
);
1426 if (EFI_ERROR (Status
)) {
1427 ShellStatus
= SHELL_ACCESS_DENIED
;
1432 // Create a ipv6 token to send the first icmp6 echo request packet.
1434 Status
= PingSendEchoRequest (Private
);
1436 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1438 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1439 ShellStatus
= SHELL_ACCESS_DENIED
;
1440 if(Status
== EFI_NOT_FOUND
) {
1441 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1442 } else if (Status
== RETURN_NO_MAPPING
) {
1443 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1445 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1451 Status
= gBS
->SetTimer (
1457 if (EFI_ERROR (Status
)) {
1458 ShellStatus
= SHELL_ACCESS_DENIED
;
1462 // Control the ping6 process by two factors:
1464 // 2. Private->Status
1465 // 2.1. success means all icmp6 echo request packets get reply packets.
1466 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1467 // 2.3. noready means ping6 process is on-the-go.
1469 while (Private
->Status
== EFI_NOT_READY
) {
1470 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1471 if (ShellGetExecutionBreakFlag()) {
1472 Private
->Status
= EFI_ABORTED
;
1479 // Display the statistics in all.
1481 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1483 if (Private
->TxCount
!= 0) {
1488 STRING_TOKEN (STR_PING_STAT
),
1489 gShellNetwork1HiiHandle
,
1491 (Private
->RxCount
- Private
->FailedCount
),
1492 (100 - ((100 * (Private
->RxCount
- Private
->FailedCount
)) / Private
->TxCount
)),
1497 if (Private
->RxCount
> Private
->FailedCount
) {
1502 STRING_TOKEN (STR_PING_RTT
),
1503 gShellNetwork1HiiHandle
,
1505 Private
->RttMin
+ Private
->TimerPeriod
,
1507 Private
->RttMax
+ Private
->TimerPeriod
,
1508 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
),
1509 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
) + Private
->TimerPeriod
1515 if (Private
!= NULL
) {
1517 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1518 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1520 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1521 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1524 RemoveEntryList (&TxInfo
->Link
);
1525 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1528 PingFreeRttTimer (Private
);
1530 if (Private
->Timer
!= NULL
) {
1531 gBS
->CloseEvent (Private
->Timer
);
1534 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1535 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1538 if (Private
->RxToken
.Event
!= NULL
) {
1539 gBS
->CloseEvent (Private
->RxToken
.Event
);
1542 if (Private
->IpChildHandle
!= NULL
) {
1543 Ping6DestroyIp6Instance (Private
);
1553 Function for 'ping' command.
1555 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1556 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1558 @retval SHELL_SUCCESS The ping processed successfullly.
1559 @retval others The ping processed unsuccessfully.
1564 ShellCommandRunPing (
1565 IN EFI_HANDLE ImageHandle
,
1566 IN EFI_SYSTEM_TABLE
*SystemTable
1570 SHELL_STATUS ShellStatus
;
1571 EFI_IPv6_ADDRESS DstAddress
;
1572 EFI_IPv6_ADDRESS SrcAddress
;
1575 LIST_ENTRY
*ParamPackage
;
1576 CONST CHAR16
*ValueStr
;
1577 UINTN NonOptionCount
;
1579 CHAR16
*ProblemParam
;
1582 // we use IPv6 buffers to hold items...
1583 // make sure this is enough space!
1585 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1586 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1588 IpChoice
= PING_IP_CHOICE_IP4
;
1590 ShellStatus
= SHELL_SUCCESS
;
1591 ProblemParam
= NULL
;
1593 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1594 if (EFI_ERROR(Status
)) {
1595 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1596 ShellStatus
= SHELL_INVALID_PARAMETER
;
1600 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1601 IpChoice
= PING_IP_CHOICE_IP6
;
1605 // Parse the parameter of count number.
1607 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1608 if (ValueStr
!= NULL
) {
1609 SendNumber
= ShellStrToUintn (ValueStr
);
1612 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1614 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1615 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1616 ShellStatus
= SHELL_INVALID_PARAMETER
;
1620 SendNumber
= DEFAULT_SEND_COUNT
;
1623 // Parse the parameter of buffer size.
1625 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1626 if (ValueStr
!= NULL
) {
1627 BufferSize
= ShellStrToUintn (ValueStr
);
1630 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1632 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1633 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1634 ShellStatus
= SHELL_INVALID_PARAMETER
;
1638 BufferSize
= DEFAULT_BUFFER_SIZE
;
1641 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1642 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1645 // Parse the parameter of source ip address.
1647 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1648 if (ValueStr
== NULL
) {
1649 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1652 if (ValueStr
!= NULL
) {
1653 mSrcString
= ValueStr
;
1654 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1655 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1657 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1659 if (EFI_ERROR (Status
)) {
1660 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1661 ShellStatus
= SHELL_INVALID_PARAMETER
;
1666 // Parse the parameter of destination ip address.
1668 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1669 if (NonOptionCount
< 2) {
1670 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1671 ShellStatus
= SHELL_INVALID_PARAMETER
;
1674 if (NonOptionCount
> 2) {
1675 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1676 ShellStatus
= SHELL_INVALID_PARAMETER
;
1679 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1680 if (ValueStr
!= NULL
) {
1681 mDstString
= ValueStr
;
1682 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1683 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1685 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1687 if (EFI_ERROR (Status
)) {
1688 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1689 ShellStatus
= SHELL_INVALID_PARAMETER
;
1695 // Enter into ping process.
1697 ShellStatus
= ShellPing (
1706 ShellCommandLineFreeVarList (ParamPackage
);