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
617 if (Private
->RxCount
< Private
->SendNum
) {
619 // Continue to receive icmp echo reply packets.
621 Private
->RxToken
.Status
= EFI_ABORTED
;
623 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
625 if (EFI_ERROR (Status
)) {
626 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
627 Private
->Status
= EFI_ABORTED
;
631 // All reply have already been received from the dest host.
633 Private
->Status
= EFI_SUCCESS
;
636 // Singal to recycle the each rxdata here, not at the end of process.
638 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
);
642 Create a PING_IPX_COMPLETION_TOKEN.
644 @param[in] Private The pointer of PING_PRIVATE_DATA.
645 @param[in] TimeStamp The TimeStamp of request.
646 @param[in] SequenceNum The SequenceNum of request.
648 @return The pointer of PING_IPX_COMPLETION_TOKEN.
651 PING_IPX_COMPLETION_TOKEN
*
653 IN PING_PRIVATE_DATA
*Private
,
655 IN UINT16 SequenceNum
659 PING_IPX_COMPLETION_TOKEN
*Token
;
661 ICMPX_ECHO_REQUEST_REPLY
*Request
;
665 Request
= AllocateZeroPool (Private
->BufferSize
);
666 if (Request
== NULL
) {
669 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
670 if (TxData
== NULL
) {
674 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
682 // Assembly echo request packet.
684 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
686 Request
->SequenceNum
= SequenceNum
;
687 Request
->Identifier
= 0;
688 Request
->Checksum
= 0;
691 // Assembly token for transmit.
693 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
694 Request
->TimeStamp
= TimeStamp
;
695 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
696 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
697 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
698 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
699 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
700 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
701 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
703 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
704 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
705 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
706 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
707 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
708 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
709 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
710 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
711 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
712 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
713 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
715 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
716 Request
->TimeStamp
= TimeStamp
;
717 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
718 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
722 Token
->Status
= EFI_ABORTED
;
723 Token
->Packet
.TxData
= TxData
;
725 Status
= gBS
->CreateEvent (
728 Ping6OnEchoRequestSent
,
733 if (EFI_ERROR (Status
)) {
744 Transmit the PING_IPX_COMPLETION_TOKEN.
746 @param[in] Private The pointer of PING_PRIVATE_DATA.
748 @retval EFI_SUCCESS Transmitted successfully.
749 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
750 @retval others Transmitted unsuccessfully.
754 PingSendEchoRequest (
755 IN PING_PRIVATE_DATA
*Private
759 PING_ICMPX_TX_INFO
*TxInfo
;
761 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
763 if (TxInfo
== NULL
) {
764 return EFI_OUT_OF_RESOURCES
;
767 TxInfo
->TimeStamp
= ReadTime (Private
);
768 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
769 TxInfo
->Token
= PingGenerateToken (
775 if (TxInfo
->Token
== NULL
) {
776 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
777 return EFI_OUT_OF_RESOURCES
;
780 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
782 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
784 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
786 if (EFI_ERROR (Status
)) {
787 RemoveEntryList (&TxInfo
->Link
);
788 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
798 Place a completion token into the receive packet queue to receive the echo reply.
800 @param[in] Private The pointer of PING_PRIVATE_DATA.
802 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
803 @retval others Put the token into the receive packet queue unsuccessfully.
807 Ping6ReceiveEchoReply (
808 IN PING_PRIVATE_DATA
*Private
813 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
815 Status
= gBS
->CreateEvent (
818 Ping6OnEchoReplyReceived
,
820 &Private
->RxToken
.Event
823 if (EFI_ERROR (Status
)) {
827 Private
->RxToken
.Status
= EFI_NOT_READY
;
829 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
830 if (EFI_ERROR (Status
)) {
831 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
837 Remove the timeout request from the list.
839 @param[in] Event A EFI_EVENT type event.
840 @param[in] Context The pointer to Context.
845 Ping6OnTimerRoutine (
851 PING_PRIVATE_DATA
*Private
;
852 PING_ICMPX_TX_INFO
*TxInfo
;
854 LIST_ENTRY
*NextEntry
;
857 Private
= (PING_PRIVATE_DATA
*) Context
;
858 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
859 Private
->Status
= EFI_NOT_FOUND
;
864 // Retransmit icmp6 echo request packets per second in sendnumber times.
866 if (Private
->TxCount
< Private
->SendNum
) {
868 Status
= PingSendEchoRequest (Private
);
869 if (Private
->TxCount
!= 0){
870 if (EFI_ERROR (Status
)) {
871 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
876 // Check whether any icmp6 echo request in the list timeout.
878 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
879 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
880 Time
= CalculateTick (Private
, TxInfo
->TimeStamp
, ReadTime (Private
));
883 // Remove the timeout echo request from txlist.
885 if (Time
> DEFAULT_TIMEOUT
) {
887 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
888 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
891 // Remove the timeout icmp6 echo request from list.
893 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
895 RemoveEntryList (&TxInfo
->Link
);
896 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
899 Private
->FailedCount
++;
901 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
903 // All the left icmp6 echo request in the list timeout.
905 Private
->Status
= EFI_TIMEOUT
;
912 Determine if a IP4 address is Link Local.
914 169.254.1.0 through 169.254.254.255 is link local.
916 @param[in] Address The address to test.
919 @retval FALSE It is not.
922 PingNetIp4IsLinkLocalAddr (
923 IN CONST EFI_IPv4_ADDRESS
*Address
926 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
930 Determine if a IP4 address is unspecified.
932 @param[in] Address The address to test.
935 @retval FALSE It is not.
938 PingNetIp4IsUnspecifiedAddr (
939 IN CONST EFI_IPv4_ADDRESS
*Address
942 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
946 Create a valid IP instance.
948 @param[in] Private The pointer of PING_PRIVATE_DATA.
950 @retval EFI_SUCCESS Create a valid IPx instance successfully.
951 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
952 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
953 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
954 @retval EFI_NOT_FOUND The source address is not found.
957 PingCreateIpInstance (
958 IN PING_PRIVATE_DATA
*Private
964 EFI_HANDLE
*HandleBuffer
;
965 BOOLEAN UnspecifiedSrc
;
966 EFI_STATUS MediaStatus
;
967 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
969 EFI_IP6_CONFIG_DATA Ip6Config
;
970 EFI_IP4_CONFIG_DATA Ip4Config
;
971 VOID
*IpXInterfaceInfo
;
973 EFI_IPv6_ADDRESS
*Addr
;
977 UnspecifiedSrc
= FALSE
;
978 MediaStatus
= EFI_SUCCESS
;
980 IpXInterfaceInfo
= NULL
;
984 // Locate all the handles with ip6 service binding protocol.
986 Status
= gBS
->LocateHandleBuffer (
988 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
993 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
997 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
998 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
1000 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
1002 UnspecifiedSrc
= TRUE
;
1006 // Source address is required when pinging a link-local address.
1008 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1009 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1010 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1011 Status
= EFI_INVALID_PARAMETER
;
1015 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
1016 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1017 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1018 Status
= EFI_INVALID_PARAMETER
;
1024 // For each ip6 protocol, check interface addresses list.
1026 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
1028 IpXInterfaceInfo
= NULL
;
1031 if (UnspecifiedSrc
) {
1035 NetLibDetectMediaWaitTimeout (HandleBuffer
[HandleIndex
], 0, &MediaStatus
);
1036 if (MediaStatus
!= EFI_SUCCESS
) {
1044 Status
= gBS
->HandleProtocol (
1045 HandleBuffer
[HandleIndex
],
1046 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1049 if (EFI_ERROR (Status
)) {
1054 // Ip6config protocol and ip6 service binding protocol are installed
1055 // on the same handle.
1057 Status
= gBS
->HandleProtocol (
1058 HandleBuffer
[HandleIndex
],
1059 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4Config2ProtocolGuid
,
1063 if (EFI_ERROR (Status
)) {
1067 // Get the interface information size.
1069 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1070 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1072 Ip6ConfigDataTypeInterfaceInfo
,
1077 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1079 Ip4Config2DataTypeInterfaceInfo
,
1086 // Skip the ones not in current use.
1088 if (Status
== EFI_NOT_STARTED
) {
1092 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1093 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1097 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1099 if (IpXInterfaceInfo
== NULL
) {
1100 Status
= EFI_OUT_OF_RESOURCES
;
1104 // Get the interface info.
1106 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1107 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1109 Ip6ConfigDataTypeInterfaceInfo
,
1114 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1116 Ip4Config2DataTypeInterfaceInfo
,
1122 if (EFI_ERROR (Status
)) {
1123 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1127 // Check whether the source address is one of the interface addresses.
1129 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1130 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1131 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1133 if (UnspecifiedSrc
) {
1134 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1136 // Select the interface automatically.
1138 CopyMem(&Private
->SrcAddress
, Addr
, sizeof(Private
->SrcAddress
));
1141 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1143 // Match a certain interface address.
1149 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1151 // Found a nic handle with right interface address.
1156 if (UnspecifiedSrc
) {
1157 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1158 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1160 // Select the interface automatically.
1164 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1166 // Match a certain interface address.
1172 FreePool (IpXInterfaceInfo
);
1173 IpXInterfaceInfo
= NULL
;
1176 // No exact interface address matched.
1179 if (HandleIndex
== HandleNum
) {
1180 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1181 Status
= EFI_NOT_FOUND
;
1185 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1187 ASSERT (EfiSb
!= NULL
);
1188 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1190 if (EFI_ERROR (Status
)) {
1193 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1194 Status
= gBS
->OpenProtocol (
1195 Private
->IpChildHandle
,
1196 &gEfiIp6ProtocolGuid
,
1197 &Private
->IpProtocol
,
1199 Private
->IpChildHandle
,
1200 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1202 if (EFI_ERROR (Status
)) {
1207 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1210 // Configure the ip6 instance for icmp6 packet exchange.
1212 Ip6Config
.DefaultProtocol
= 58;
1213 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1214 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1215 Ip6Config
.AcceptPromiscuous
= FALSE
;
1216 Ip6Config
.TrafficClass
= 0;
1217 Ip6Config
.HopLimit
= 128;
1218 Ip6Config
.FlowLabel
= 0;
1219 Ip6Config
.ReceiveTimeout
= 0;
1220 Ip6Config
.TransmitTimeout
= 0;
1222 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1223 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1225 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1227 if (EFI_ERROR (Status
)) {
1228 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1232 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1233 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1234 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1235 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1237 Status
= gBS
->OpenProtocol (
1238 Private
->IpChildHandle
,
1239 &gEfiIp4ProtocolGuid
,
1240 &Private
->IpProtocol
,
1242 Private
->IpChildHandle
,
1243 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1245 if (EFI_ERROR (Status
)) {
1250 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1253 // Configure the ip4 instance for icmp4 packet exchange.
1255 Ip4Config
.DefaultProtocol
= 1;
1256 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1257 Ip4Config
.AcceptBroadcast
= FALSE
;
1258 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1259 Ip4Config
.AcceptPromiscuous
= FALSE
;
1260 Ip4Config
.DoNotFragment
= FALSE
;
1261 Ip4Config
.RawData
= FALSE
;
1262 Ip4Config
.ReceiveTimeout
= 0;
1263 Ip4Config
.TransmitTimeout
= 0;
1264 Ip4Config
.UseDefaultAddress
= TRUE
;
1265 Ip4Config
.TimeToLive
= 128;
1266 Ip4Config
.TypeOfService
= 0;
1268 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1270 if (EFI_ERROR (Status
)) {
1271 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1275 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1276 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1277 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1278 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1281 if (HandleBuffer
!= NULL
) {
1282 FreePool (HandleBuffer
);
1288 if (HandleBuffer
!= NULL
) {
1289 FreePool (HandleBuffer
);
1292 if (IpXInterfaceInfo
!= NULL
) {
1293 FreePool (IpXInterfaceInfo
);
1296 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1297 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1304 Destroy the IP instance.
1306 @param[in] Private The pointer of PING_PRIVATE_DATA.
1310 Ping6DestroyIp6Instance (
1311 IN PING_PRIVATE_DATA
*Private
1315 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1317 gBS
->CloseProtocol (
1318 Private
->IpChildHandle
,
1319 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1321 Private
->IpChildHandle
1324 Status
= gBS
->HandleProtocol (
1326 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1330 if (!EFI_ERROR(Status
)) {
1331 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1339 @param[in] SendNumber The send request count.
1340 @param[in] BufferSize The send buffer size.
1341 @param[in] SrcAddress The source address.
1342 @param[in] DstAddress The destination address.
1343 @param[in] IpChoice The choice between IPv4 and IPv6.
1345 @retval SHELL_SUCCESS The ping processed successfullly.
1346 @retval others The ping processed unsuccessfully.
1350 IN UINT32 SendNumber
,
1351 IN UINT32 BufferSize
,
1352 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1353 IN EFI_IPv6_ADDRESS
*DstAddress
,
1358 PING_PRIVATE_DATA
*Private
;
1359 PING_ICMPX_TX_INFO
*TxInfo
;
1361 LIST_ENTRY
*NextEntry
;
1362 SHELL_STATUS ShellStatus
;
1364 ShellStatus
= SHELL_SUCCESS
;
1365 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1367 if (Private
== NULL
) {
1368 return (SHELL_OUT_OF_RESOURCES
);
1371 Private
->IpChoice
= IpChoice
;
1372 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1373 Private
->SendNum
= SendNumber
;
1374 Private
->BufferSize
= BufferSize
;
1375 Private
->RttMin
= ~((UINT64
)(0x0));
1376 Private
->Status
= EFI_NOT_READY
;
1378 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1379 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1381 InitializeListHead (&Private
->TxList
);
1384 // Open and configure a ip instance for us.
1386 Status
= PingCreateIpInstance (Private
);
1388 if (EFI_ERROR (Status
)) {
1389 ShellStatus
= SHELL_ACCESS_DENIED
;
1393 // Print the command line itself.
1395 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1397 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1399 Status
= Ping6ReceiveEchoReply (Private
);
1401 if (EFI_ERROR (Status
)) {
1402 ShellStatus
= SHELL_ACCESS_DENIED
;
1406 // Create and start timer to send icmp6 echo request packet per second.
1408 Status
= gBS
->CreateEvent (
1409 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1411 Ping6OnTimerRoutine
,
1416 if (EFI_ERROR (Status
)) {
1417 ShellStatus
= SHELL_ACCESS_DENIED
;
1422 // Start a timer to calculate the RTT.
1424 Status
= PingInitRttTimer (Private
);
1425 if (EFI_ERROR (Status
)) {
1426 ShellStatus
= SHELL_ACCESS_DENIED
;
1431 // Create a ipv6 token to send the first icmp6 echo request packet.
1433 Status
= PingSendEchoRequest (Private
);
1435 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1437 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1438 ShellStatus
= SHELL_ACCESS_DENIED
;
1439 if(Status
== EFI_NOT_FOUND
) {
1440 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1441 } else if (Status
== RETURN_NO_MAPPING
) {
1442 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1444 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1450 Status
= gBS
->SetTimer (
1456 if (EFI_ERROR (Status
)) {
1457 ShellStatus
= SHELL_ACCESS_DENIED
;
1461 // Control the ping6 process by two factors:
1463 // 2. Private->Status
1464 // 2.1. success means all icmp6 echo request packets get reply packets.
1465 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1466 // 2.3. noready means ping6 process is on-the-go.
1468 while (Private
->Status
== EFI_NOT_READY
) {
1469 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1470 if (ShellGetExecutionBreakFlag()) {
1471 Private
->Status
= EFI_ABORTED
;
1478 // Display the statistics in all.
1480 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1482 if (Private
->TxCount
!= 0) {
1487 STRING_TOKEN (STR_PING_STAT
),
1488 gShellNetwork1HiiHandle
,
1490 (Private
->RxCount
- Private
->FailedCount
),
1491 (100 - ((100 * (Private
->RxCount
- Private
->FailedCount
)) / Private
->TxCount
)),
1496 if (Private
->RxCount
> Private
->FailedCount
) {
1501 STRING_TOKEN (STR_PING_RTT
),
1502 gShellNetwork1HiiHandle
,
1504 Private
->RttMin
+ Private
->TimerPeriod
,
1506 Private
->RttMax
+ Private
->TimerPeriod
,
1507 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
),
1508 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
) + Private
->TimerPeriod
1514 if (Private
!= NULL
) {
1516 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1517 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1519 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1520 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1523 RemoveEntryList (&TxInfo
->Link
);
1524 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1527 PingFreeRttTimer (Private
);
1529 if (Private
->Timer
!= NULL
) {
1530 gBS
->CloseEvent (Private
->Timer
);
1533 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1534 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1537 if (Private
->RxToken
.Event
!= NULL
) {
1538 gBS
->CloseEvent (Private
->RxToken
.Event
);
1541 if (Private
->IpChildHandle
!= NULL
) {
1542 Ping6DestroyIp6Instance (Private
);
1552 Function for 'ping' command.
1554 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1555 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1557 @retval SHELL_SUCCESS The ping processed successfullly.
1558 @retval others The ping processed unsuccessfully.
1563 ShellCommandRunPing (
1564 IN EFI_HANDLE ImageHandle
,
1565 IN EFI_SYSTEM_TABLE
*SystemTable
1569 SHELL_STATUS ShellStatus
;
1570 EFI_IPv6_ADDRESS DstAddress
;
1571 EFI_IPv6_ADDRESS SrcAddress
;
1574 LIST_ENTRY
*ParamPackage
;
1575 CONST CHAR16
*ValueStr
;
1576 UINTN NonOptionCount
;
1578 CHAR16
*ProblemParam
;
1581 // we use IPv6 buffers to hold items...
1582 // make sure this is enough space!
1584 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1585 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1587 IpChoice
= PING_IP_CHOICE_IP4
;
1589 ShellStatus
= SHELL_SUCCESS
;
1590 ProblemParam
= NULL
;
1592 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1593 if (EFI_ERROR(Status
)) {
1594 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1595 ShellStatus
= SHELL_INVALID_PARAMETER
;
1599 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1600 IpChoice
= PING_IP_CHOICE_IP6
;
1604 // Parse the parameter of count number.
1606 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1607 if (ValueStr
!= NULL
) {
1608 SendNumber
= ShellStrToUintn (ValueStr
);
1611 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1613 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1614 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1615 ShellStatus
= SHELL_INVALID_PARAMETER
;
1619 SendNumber
= DEFAULT_SEND_COUNT
;
1622 // Parse the parameter of buffer size.
1624 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1625 if (ValueStr
!= NULL
) {
1626 BufferSize
= ShellStrToUintn (ValueStr
);
1629 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1631 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1632 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1633 ShellStatus
= SHELL_INVALID_PARAMETER
;
1637 BufferSize
= DEFAULT_BUFFER_SIZE
;
1640 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1641 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1644 // Parse the parameter of source ip address.
1646 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1647 if (ValueStr
== NULL
) {
1648 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1651 if (ValueStr
!= NULL
) {
1652 mSrcString
= ValueStr
;
1653 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1654 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1656 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1658 if (EFI_ERROR (Status
)) {
1659 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1660 ShellStatus
= SHELL_INVALID_PARAMETER
;
1665 // Parse the parameter of destination ip address.
1667 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1668 if (NonOptionCount
< 2) {
1669 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1670 ShellStatus
= SHELL_INVALID_PARAMETER
;
1673 if (NonOptionCount
> 2) {
1674 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1675 ShellStatus
= SHELL_INVALID_PARAMETER
;
1678 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1679 if (ValueStr
!= NULL
) {
1680 mDstString
= ValueStr
;
1681 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1682 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1684 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1686 if (EFI_ERROR (Status
)) {
1687 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1688 ShellStatus
= SHELL_INVALID_PARAMETER
;
1694 // Enter into ping process.
1696 ShellStatus
= ShellPing (
1705 ShellCommandLineFreeVarList (ParamPackage
);