2 The implementation for Ping shell command.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php.
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "UefiShellNetwork1CommandsLib.h"
20 #define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))
22 UINT64 mCurrentTick
= 0;
25 // Function templates to match the IPv4 and IPv6 commands that we use.
29 (EFIAPI
*PING_IPX_POLL
)(
35 (EFIAPI
*PING_IPX_TRANSMIT
)(
42 (EFIAPI
*PING_IPX_RECEIVE
)(
49 (EFIAPI
*PING_IPX_CANCEL
)(
51 IN VOID
*Token OPTIONAL
55 /// A set of pointers to either IPv6 or IPv4 functions.
56 /// Unknown which one to the ping command.
59 PING_IPX_TRANSMIT Transmit
;
60 PING_IPX_RECEIVE Receive
;
61 PING_IPX_CANCEL Cancel
;
72 // PING_IPX_COMPLETION_TOKEN
73 // structures are used for both transmit and receive operations.
74 // This version is IP-unaware.
80 } PING_IPX_COMPLETION_TOKEN
;
83 typedef struct _ICMPX_ECHO_REQUEST_REPLY
{
91 } ICMPX_ECHO_REQUEST_REPLY
;
94 typedef struct _PING_ICMP_TX_INFO
{
98 PING_IPX_COMPLETION_TOKEN
*Token
;
101 #define DEFAULT_TIMEOUT 5000
102 #define MAX_SEND_NUMBER 10000
103 #define MAX_BUFFER_SIZE 32768
104 #define DEFAULT_TIMER_PERIOD 358049
105 #define ONE_SECOND 10000000
106 #define PING_IP_CHOICE_IP4 1
107 #define PING_IP_CHOICE_IP6 2
108 #define DEFAULT_SEND_COUNT 10
109 #define DEFAULT_BUFFER_SIZE 16
110 #define ICMP_V4_ECHO_REQUEST 0x8
111 #define ICMP_V4_ECHO_REPLY 0x0
112 #define STALL_1_MILLI_SECOND 1000
114 #define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')
115 typedef struct _PING_PRIVATE_DATA
{
117 EFI_HANDLE NicHandle
;
118 EFI_HANDLE IpChildHandle
;
138 PING_IPX_PROTOCOL ProtocolPointers
;
140 UINT8 SrcAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
141 UINT8 DstAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
142 PING_IPX_COMPLETION_TOKEN RxToken
;
147 Calculate the internet checksum (see RFC 1071).
149 @param[in] Packet Buffer which contains the data to be checksummed.
150 @param[in] Length Length to be checksummed.
152 @retval Checksum Returns the 16 bit ones complement of
153 ones complement sum of 16 bit words
165 Packet
= (UINT16
*) Buffer
;
168 Odd
= (UINT8
) (Length
& 1);
170 while ((Length
--) != 0) {
175 Sum
+= *(UINT8
*) Packet
;
178 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
181 // in case above carried
189 Reads and returns the current value of register.
190 In IA64, the register is the Interval Timer Vector (ITV).
191 In X86(IA32/X64), the register is the Time Stamp Counter (TSC)
193 @return The current value of the register.
197 STATIC CONST SHELL_PARAM_ITEM PingParamList
[] = {
225 // Global Variables in Ping command.
227 STATIC CONST CHAR16
*mDstString
;
228 STATIC CONST CHAR16
*mSrcString
;
231 RTT timer tick routine.
233 @param[in] Event A EFI_EVENT type event.
234 @param[in] Context The pointer to Context.
239 RttTimerTickRoutine (
244 UINT32
*RttTimerTick
;
246 RttTimerTick
= (UINT32
*) Context
;
251 Get the timer period of the system.
253 This function tries to get the system timer period by creating
256 @return System timer period in MS, or 0 if operation failed.
266 EFI_EVENT TimerEvent
;
273 Status
= gBS
->CreateEvent (
274 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
280 if (EFI_ERROR (Status
)) {
284 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
285 Status
= gBS
->SetTimer (
290 if (EFI_ERROR (Status
)) {
291 gBS
->CloseEvent (TimerEvent
);
295 while (RttTimerTick
< 10) {
296 gBS
->Stall (STALL_1_MILLI_SECOND
);
300 gBS
->RestoreTPL (OldTpl
);
302 gBS
->SetTimer (TimerEvent
, TimerCancel
, 0);
303 gBS
->CloseEvent (TimerEvent
);
305 return StallCounter
/ RttTimerTick
;
309 Initialize the timer event for RTT (round trip time).
311 @param[in] Private The pointer to PING_PRIVATE_DATA.
313 @retval EFI_SUCCESS RTT timer is started.
314 @retval Others Failed to start the RTT timer.
319 PING_PRIVATE_DATA
*Private
324 Private
->TimerPeriod
= GetTimerPeriod ();
325 if (Private
->TimerPeriod
== 0) {
329 Private
->RttTimerTick
= 0;
330 Status
= gBS
->CreateEvent (
331 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
334 &Private
->RttTimerTick
,
337 if (EFI_ERROR (Status
)) {
341 Status
= gBS
->SetTimer (
346 if (EFI_ERROR (Status
)) {
347 gBS
->CloseEvent (Private
->RttTimer
);
355 Free RTT timer event resource.
357 @param[in] Private The pointer to PING_PRIVATE_DATA.
362 PING_PRIVATE_DATA
*Private
365 if (Private
->RttTimer
!= NULL
) {
366 gBS
->SetTimer (Private
->RttTimer
, TimerCancel
, 0);
367 gBS
->CloseEvent (Private
->RttTimer
);
372 Read the current time.
374 @param[in] Private The pointer to PING_PRIVATE_DATA.
376 @retval the current tick value.
380 PING_PRIVATE_DATA
*Private
383 return Private
->RttTimerTick
;
387 Calculate a duration in ms.
389 @param[in] Private The pointer to PING_PRIVATE_DATA.
390 @param[in] Begin The start point of time.
391 @param[in] End The end point of time.
393 @return The duration in ms.
394 @retval 0 The parameters were not valid.
398 PING_PRIVATE_DATA
*Private
,
407 return (End
- Begin
) * Private
->TimerPeriod
;
411 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
413 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
414 @param[in] IpChoice Whether the token is IPv4 or IPv6
418 IN PING_ICMPX_TX_INFO
*TxInfo
,
422 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
423 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
424 EFI_IP6_FRAGMENT_DATA
*FragData
;
427 if (TxInfo
== NULL
) {
431 if (TxInfo
->Token
!= NULL
) {
433 if (TxInfo
->Token
->Event
!= NULL
) {
434 gBS
->CloseEvent (TxInfo
->Token
->Event
);
437 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
438 if (IpChoice
== PING_IP_CHOICE_IP6
) {
439 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
441 if (Ip6TxData
->OverrideData
!= NULL
) {
442 FreePool (Ip6TxData
->OverrideData
);
445 if (Ip6TxData
->ExtHdrs
!= NULL
) {
446 FreePool (Ip6TxData
->ExtHdrs
);
449 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
450 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
451 if (FragData
!= NULL
) {
456 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
458 if (Ip4TxData
->OverrideData
!= NULL
) {
459 FreePool (Ip4TxData
->OverrideData
);
462 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
463 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
464 if (FragData
!= NULL
) {
471 FreePool (TxInfo
->Token
);
478 Match the request, and reply with SequenceNum/TimeStamp.
480 @param[in] Private The pointer to PING_PRIVATE_DATA.
481 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
483 @retval EFI_SUCCESS The match is successful.
484 @retval EFI_NOT_FOUND The reply can't be matched with any request.
488 Ping6MatchEchoReply (
489 IN PING_PRIVATE_DATA
*Private
,
490 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
493 PING_ICMPX_TX_INFO
*TxInfo
;
495 LIST_ENTRY
*NextEntry
;
497 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
498 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
500 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
502 RemoveEntryList (&TxInfo
->Link
);
503 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
508 return EFI_NOT_FOUND
;
512 The original intention is to send a request.
513 Currently, the application retransmits an icmp6 echo request packet
514 per second in sendnumber times that is specified by the user.
515 Because nothing can be done here, all things move to the timer rountine.
517 @param[in] Event A EFI_EVENT type event.
518 @param[in] Context The pointer to Context.
523 Ping6OnEchoRequestSent (
531 receive reply, match and print reply infomation.
533 @param[in] Event A EFI_EVENT type event.
534 @param[in] Context The pointer to context.
539 Ping6OnEchoReplyReceived (
545 PING_PRIVATE_DATA
*Private
;
546 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
550 Private
= (PING_PRIVATE_DATA
*) Context
;
552 if (Private
== NULL
|| Private
->Status
== EFI_ABORTED
|| Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
556 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
560 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
561 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
562 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
563 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
566 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
567 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
)) {
571 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
575 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
576 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
577 if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
578 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
)) {
582 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
588 if (PayLoad
!= Private
->BufferSize
) {
592 // Check whether the reply matches the sent request before.
594 Status
= Ping6MatchEchoReply (Private
, Reply
);
595 if (EFI_ERROR(Status
)) {
599 // Display statistics on this icmp6 echo reply packet.
601 Rtt
= CalculateTick (Private
, Reply
->TimeStamp
, ReadTime (Private
));
603 Private
->RttSum
+= Rtt
;
604 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
605 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
611 STRING_TOKEN (STR_PING_REPLY_INFO
),
612 gShellNetwork1HiiHandle
,
616 Private
->IpChoice
== PING_IP_CHOICE_IP6
?((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
:0,
618 Rtt
+ Private
->TimerPeriod
623 if (Private
->RxCount
< Private
->SendNum
) {
625 // Continue to receive icmp echo reply packets.
627 Private
->RxToken
.Status
= EFI_ABORTED
;
629 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
631 if (EFI_ERROR (Status
)) {
632 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
633 Private
->Status
= EFI_ABORTED
;
637 // All reply have already been received from the dest host.
639 Private
->Status
= EFI_SUCCESS
;
642 // Singal to recycle the each rxdata here, not at the end of process.
644 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
);
648 Create a PING_IPX_COMPLETION_TOKEN.
650 @param[in] Private The pointer of PING_PRIVATE_DATA.
651 @param[in] TimeStamp The TimeStamp of request.
652 @param[in] SequenceNum The SequenceNum of request.
654 @return The pointer of PING_IPX_COMPLETION_TOKEN.
657 PING_IPX_COMPLETION_TOKEN
*
659 IN PING_PRIVATE_DATA
*Private
,
661 IN UINT16 SequenceNum
665 PING_IPX_COMPLETION_TOKEN
*Token
;
667 ICMPX_ECHO_REQUEST_REPLY
*Request
;
671 Request
= AllocateZeroPool (Private
->BufferSize
);
672 if (Request
== NULL
) {
675 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
676 if (TxData
== NULL
) {
680 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
688 // Assembly echo request packet.
690 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
692 Request
->SequenceNum
= SequenceNum
;
693 Request
->Identifier
= 0;
694 Request
->Checksum
= 0;
697 // Assembly token for transmit.
699 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
700 Request
->TimeStamp
= TimeStamp
;
701 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
702 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
703 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
704 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
705 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
706 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
707 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
709 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
710 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
711 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
712 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
713 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
714 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
715 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
716 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
717 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
718 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
719 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
721 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
722 Request
->TimeStamp
= TimeStamp
;
723 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
724 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
728 Token
->Status
= EFI_ABORTED
;
729 Token
->Packet
.TxData
= TxData
;
731 Status
= gBS
->CreateEvent (
734 Ping6OnEchoRequestSent
,
739 if (EFI_ERROR (Status
)) {
750 Transmit the PING_IPX_COMPLETION_TOKEN.
752 @param[in] Private The pointer of PING_PRIVATE_DATA.
754 @retval EFI_SUCCESS Transmitted successfully.
755 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
756 @retval others Transmitted unsuccessfully.
760 PingSendEchoRequest (
761 IN PING_PRIVATE_DATA
*Private
765 PING_ICMPX_TX_INFO
*TxInfo
;
767 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
769 if (TxInfo
== NULL
) {
770 return EFI_OUT_OF_RESOURCES
;
773 TxInfo
->TimeStamp
= ReadTime (Private
);
774 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
775 TxInfo
->Token
= PingGenerateToken (
781 if (TxInfo
->Token
== NULL
) {
782 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
783 return EFI_OUT_OF_RESOURCES
;
786 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
788 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
790 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
792 if (EFI_ERROR (Status
)) {
793 RemoveEntryList (&TxInfo
->Link
);
794 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
804 Place a completion token into the receive packet queue to receive the echo reply.
806 @param[in] Private The pointer of PING_PRIVATE_DATA.
808 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
809 @retval others Put the token into the receive packet queue unsuccessfully.
813 Ping6ReceiveEchoReply (
814 IN PING_PRIVATE_DATA
*Private
819 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
821 Status
= gBS
->CreateEvent (
824 Ping6OnEchoReplyReceived
,
826 &Private
->RxToken
.Event
829 if (EFI_ERROR (Status
)) {
833 Private
->RxToken
.Status
= EFI_NOT_READY
;
835 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
836 if (EFI_ERROR (Status
)) {
837 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
843 Remove the timeout request from the list.
845 @param[in] Event A EFI_EVENT type event.
846 @param[in] Context The pointer to Context.
851 Ping6OnTimerRoutine (
857 PING_PRIVATE_DATA
*Private
;
858 PING_ICMPX_TX_INFO
*TxInfo
;
860 LIST_ENTRY
*NextEntry
;
863 Private
= (PING_PRIVATE_DATA
*) Context
;
864 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
865 Private
->Status
= EFI_NOT_FOUND
;
870 // Retransmit icmp6 echo request packets per second in sendnumber times.
872 if (Private
->TxCount
< Private
->SendNum
) {
874 Status
= PingSendEchoRequest (Private
);
875 if (Private
->TxCount
!= 0){
876 if (EFI_ERROR (Status
)) {
877 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
882 // Check whether any icmp6 echo request in the list timeout.
884 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
885 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
886 Time
= CalculateTick (Private
, TxInfo
->TimeStamp
, ReadTime (Private
));
889 // Remove the timeout echo request from txlist.
891 if (Time
> DEFAULT_TIMEOUT
) {
893 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
894 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
897 // Remove the timeout icmp6 echo request from list.
899 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
901 RemoveEntryList (&TxInfo
->Link
);
902 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
905 Private
->FailedCount
++;
907 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
909 // All the left icmp6 echo request in the list timeout.
911 Private
->Status
= EFI_TIMEOUT
;
918 Determine if a IP4 address is Link Local.
920 169.254.1.0 through 169.254.254.255 is link local.
922 @param[in] Address The address to test.
925 @retval FALSE It is not.
928 PingNetIp4IsLinkLocalAddr (
929 IN CONST EFI_IPv4_ADDRESS
*Address
932 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
936 Determine if a IP4 address is unspecified.
938 @param[in] Address The address to test.
941 @retval FALSE It is not.
944 PingNetIp4IsUnspecifiedAddr (
945 IN CONST EFI_IPv4_ADDRESS
*Address
948 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
952 Create a valid IP instance.
954 @param[in] Private The pointer of PING_PRIVATE_DATA.
956 @retval EFI_SUCCESS Create a valid IPx instance successfully.
957 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
958 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
959 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
960 @retval EFI_NOT_FOUND The source address is not found.
963 PingCreateIpInstance (
964 IN PING_PRIVATE_DATA
*Private
970 EFI_HANDLE
*HandleBuffer
;
971 BOOLEAN UnspecifiedSrc
;
972 EFI_STATUS MediaStatus
;
973 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
975 EFI_IP6_CONFIG_DATA Ip6Config
;
976 EFI_IP4_CONFIG_DATA Ip4Config
;
977 VOID
*IpXInterfaceInfo
;
979 EFI_IPv6_ADDRESS
*Addr
;
983 UnspecifiedSrc
= FALSE
;
984 MediaStatus
= EFI_SUCCESS
;
986 IpXInterfaceInfo
= NULL
;
990 // Locate all the handles with ip6 service binding protocol.
992 Status
= gBS
->LocateHandleBuffer (
994 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
999 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
1003 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
1004 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
1006 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
1008 UnspecifiedSrc
= TRUE
;
1012 // Source address is required when pinging a link-local address.
1014 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1015 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1016 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1017 Status
= EFI_INVALID_PARAMETER
;
1021 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
1022 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1023 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1024 Status
= EFI_INVALID_PARAMETER
;
1030 // For each ip6 protocol, check interface addresses list.
1032 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
1034 IpXInterfaceInfo
= NULL
;
1037 if (UnspecifiedSrc
) {
1041 NetLibDetectMediaWaitTimeout (HandleBuffer
[HandleIndex
], 0, &MediaStatus
);
1042 if (MediaStatus
!= EFI_SUCCESS
) {
1050 Status
= gBS
->HandleProtocol (
1051 HandleBuffer
[HandleIndex
],
1052 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1055 if (EFI_ERROR (Status
)) {
1060 // Ip6config protocol and ip6 service binding protocol are installed
1061 // on the same handle.
1063 Status
= gBS
->HandleProtocol (
1064 HandleBuffer
[HandleIndex
],
1065 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4Config2ProtocolGuid
,
1069 if (EFI_ERROR (Status
)) {
1073 // Get the interface information size.
1075 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1076 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1078 Ip6ConfigDataTypeInterfaceInfo
,
1083 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1085 Ip4Config2DataTypeInterfaceInfo
,
1092 // Skip the ones not in current use.
1094 if (Status
== EFI_NOT_STARTED
) {
1098 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1099 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1103 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1105 if (IpXInterfaceInfo
== NULL
) {
1106 Status
= EFI_OUT_OF_RESOURCES
;
1110 // Get the interface info.
1112 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1113 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1115 Ip6ConfigDataTypeInterfaceInfo
,
1120 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1122 Ip4Config2DataTypeInterfaceInfo
,
1128 if (EFI_ERROR (Status
)) {
1129 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1133 // Check whether the source address is one of the interface addresses.
1135 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1136 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1137 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1139 if (UnspecifiedSrc
) {
1140 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1142 // Select the interface automatically.
1144 CopyMem(&Private
->SrcAddress
, Addr
, sizeof(Private
->SrcAddress
));
1147 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1149 // Match a certain interface address.
1155 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1157 // Found a nic handle with right interface address.
1162 if (UnspecifiedSrc
) {
1163 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1164 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1166 // Select the interface automatically.
1170 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1172 // Match a certain interface address.
1178 FreePool (IpXInterfaceInfo
);
1179 IpXInterfaceInfo
= NULL
;
1182 // No exact interface address matched.
1185 if (HandleIndex
== HandleNum
) {
1186 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1187 Status
= EFI_NOT_FOUND
;
1191 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1193 ASSERT (EfiSb
!= NULL
);
1194 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1196 if (EFI_ERROR (Status
)) {
1199 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1200 Status
= gBS
->OpenProtocol (
1201 Private
->IpChildHandle
,
1202 &gEfiIp6ProtocolGuid
,
1203 &Private
->IpProtocol
,
1205 Private
->IpChildHandle
,
1206 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1208 if (EFI_ERROR (Status
)) {
1213 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1216 // Configure the ip6 instance for icmp6 packet exchange.
1218 Ip6Config
.DefaultProtocol
= 58;
1219 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1220 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1221 Ip6Config
.AcceptPromiscuous
= FALSE
;
1222 Ip6Config
.TrafficClass
= 0;
1223 Ip6Config
.HopLimit
= 128;
1224 Ip6Config
.FlowLabel
= 0;
1225 Ip6Config
.ReceiveTimeout
= 0;
1226 Ip6Config
.TransmitTimeout
= 0;
1228 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1229 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1231 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1233 if (EFI_ERROR (Status
)) {
1234 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1238 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1239 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1240 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1241 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1243 Status
= gBS
->OpenProtocol (
1244 Private
->IpChildHandle
,
1245 &gEfiIp4ProtocolGuid
,
1246 &Private
->IpProtocol
,
1248 Private
->IpChildHandle
,
1249 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1251 if (EFI_ERROR (Status
)) {
1256 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1259 // Configure the ip4 instance for icmp4 packet exchange.
1261 Ip4Config
.DefaultProtocol
= 1;
1262 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1263 Ip4Config
.AcceptBroadcast
= FALSE
;
1264 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1265 Ip4Config
.AcceptPromiscuous
= FALSE
;
1266 Ip4Config
.DoNotFragment
= FALSE
;
1267 Ip4Config
.RawData
= FALSE
;
1268 Ip4Config
.ReceiveTimeout
= 0;
1269 Ip4Config
.TransmitTimeout
= 0;
1270 Ip4Config
.UseDefaultAddress
= TRUE
;
1271 Ip4Config
.TimeToLive
= 128;
1272 Ip4Config
.TypeOfService
= 0;
1274 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1276 if (EFI_ERROR (Status
)) {
1277 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1281 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1282 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1283 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1284 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1287 if (HandleBuffer
!= NULL
) {
1288 FreePool (HandleBuffer
);
1294 if (HandleBuffer
!= NULL
) {
1295 FreePool (HandleBuffer
);
1298 if (IpXInterfaceInfo
!= NULL
) {
1299 FreePool (IpXInterfaceInfo
);
1302 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1303 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1310 Destroy the IP instance.
1312 @param[in] Private The pointer of PING_PRIVATE_DATA.
1316 Ping6DestroyIp6Instance (
1317 IN PING_PRIVATE_DATA
*Private
1321 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1323 gBS
->CloseProtocol (
1324 Private
->IpChildHandle
,
1325 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1327 Private
->IpChildHandle
1330 Status
= gBS
->HandleProtocol (
1332 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1336 if (!EFI_ERROR(Status
)) {
1337 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1345 @param[in] SendNumber The send request count.
1346 @param[in] BufferSize The send buffer size.
1347 @param[in] SrcAddress The source address.
1348 @param[in] DstAddress The destination address.
1349 @param[in] IpChoice The choice between IPv4 and IPv6.
1351 @retval SHELL_SUCCESS The ping processed successfullly.
1352 @retval others The ping processed unsuccessfully.
1356 IN UINT32 SendNumber
,
1357 IN UINT32 BufferSize
,
1358 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1359 IN EFI_IPv6_ADDRESS
*DstAddress
,
1364 PING_PRIVATE_DATA
*Private
;
1365 PING_ICMPX_TX_INFO
*TxInfo
;
1367 LIST_ENTRY
*NextEntry
;
1368 SHELL_STATUS ShellStatus
;
1370 ShellStatus
= SHELL_SUCCESS
;
1371 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1373 if (Private
== NULL
) {
1374 return (SHELL_OUT_OF_RESOURCES
);
1377 Private
->IpChoice
= IpChoice
;
1378 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1379 Private
->SendNum
= SendNumber
;
1380 Private
->BufferSize
= BufferSize
;
1381 Private
->RttMin
= ~((UINT64
)(0x0));
1382 Private
->Status
= EFI_NOT_READY
;
1384 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1385 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1387 InitializeListHead (&Private
->TxList
);
1390 // Open and configure a ip instance for us.
1392 Status
= PingCreateIpInstance (Private
);
1394 if (EFI_ERROR (Status
)) {
1395 ShellStatus
= SHELL_ACCESS_DENIED
;
1399 // Print the command line itself.
1401 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1403 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1405 Status
= Ping6ReceiveEchoReply (Private
);
1407 if (EFI_ERROR (Status
)) {
1408 ShellStatus
= SHELL_ACCESS_DENIED
;
1412 // Create and start timer to send icmp6 echo request packet per second.
1414 Status
= gBS
->CreateEvent (
1415 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1417 Ping6OnTimerRoutine
,
1422 if (EFI_ERROR (Status
)) {
1423 ShellStatus
= SHELL_ACCESS_DENIED
;
1428 // Start a timer to calculate the RTT.
1430 Status
= PingInitRttTimer (Private
);
1431 if (EFI_ERROR (Status
)) {
1432 ShellStatus
= SHELL_ACCESS_DENIED
;
1437 // Create a ipv6 token to send the first icmp6 echo request packet.
1439 Status
= PingSendEchoRequest (Private
);
1441 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1443 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1444 ShellStatus
= SHELL_ACCESS_DENIED
;
1445 if(Status
== EFI_NOT_FOUND
) {
1446 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1447 } else if (Status
== RETURN_NO_MAPPING
) {
1448 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1450 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1456 Status
= gBS
->SetTimer (
1462 if (EFI_ERROR (Status
)) {
1463 ShellStatus
= SHELL_ACCESS_DENIED
;
1467 // Control the ping6 process by two factors:
1469 // 2. Private->Status
1470 // 2.1. success means all icmp6 echo request packets get reply packets.
1471 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1472 // 2.3. noready means ping6 process is on-the-go.
1474 while (Private
->Status
== EFI_NOT_READY
) {
1475 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1476 if (ShellGetExecutionBreakFlag()) {
1477 Private
->Status
= EFI_ABORTED
;
1484 // Display the statistics in all.
1486 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1488 if (Private
->TxCount
!= 0) {
1493 STRING_TOKEN (STR_PING_STAT
),
1494 gShellNetwork1HiiHandle
,
1496 (Private
->RxCount
- Private
->FailedCount
),
1497 (100 - ((100 * (Private
->RxCount
- Private
->FailedCount
)) / Private
->TxCount
)),
1502 if (Private
->RxCount
> Private
->FailedCount
) {
1507 STRING_TOKEN (STR_PING_RTT
),
1508 gShellNetwork1HiiHandle
,
1510 Private
->RttMin
+ Private
->TimerPeriod
,
1512 Private
->RttMax
+ Private
->TimerPeriod
,
1513 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
),
1514 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
) + Private
->TimerPeriod
1520 if (Private
!= NULL
) {
1522 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1523 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1525 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1526 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1529 RemoveEntryList (&TxInfo
->Link
);
1530 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1533 PingFreeRttTimer (Private
);
1535 if (Private
->Timer
!= NULL
) {
1536 gBS
->CloseEvent (Private
->Timer
);
1539 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1540 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1543 if (Private
->RxToken
.Event
!= NULL
) {
1544 gBS
->CloseEvent (Private
->RxToken
.Event
);
1547 if (Private
->IpChildHandle
!= NULL
) {
1548 Ping6DestroyIp6Instance (Private
);
1558 Function for 'ping' command.
1560 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1561 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1563 @retval SHELL_SUCCESS The ping processed successfullly.
1564 @retval others The ping processed unsuccessfully.
1569 ShellCommandRunPing (
1570 IN EFI_HANDLE ImageHandle
,
1571 IN EFI_SYSTEM_TABLE
*SystemTable
1575 SHELL_STATUS ShellStatus
;
1576 EFI_IPv6_ADDRESS DstAddress
;
1577 EFI_IPv6_ADDRESS SrcAddress
;
1580 LIST_ENTRY
*ParamPackage
;
1581 CONST CHAR16
*ValueStr
;
1582 UINTN NonOptionCount
;
1584 CHAR16
*ProblemParam
;
1587 // we use IPv6 buffers to hold items...
1588 // make sure this is enough space!
1590 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1591 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1593 IpChoice
= PING_IP_CHOICE_IP4
;
1595 ShellStatus
= SHELL_SUCCESS
;
1596 ProblemParam
= NULL
;
1598 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1599 if (EFI_ERROR(Status
)) {
1600 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1601 ShellStatus
= SHELL_INVALID_PARAMETER
;
1605 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1606 IpChoice
= PING_IP_CHOICE_IP6
;
1610 // Parse the parameter of count number.
1612 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1613 if (ValueStr
!= NULL
) {
1614 SendNumber
= ShellStrToUintn (ValueStr
);
1617 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1619 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1620 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1621 ShellStatus
= SHELL_INVALID_PARAMETER
;
1625 SendNumber
= DEFAULT_SEND_COUNT
;
1628 // Parse the parameter of buffer size.
1630 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1631 if (ValueStr
!= NULL
) {
1632 BufferSize
= ShellStrToUintn (ValueStr
);
1635 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1637 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1638 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1639 ShellStatus
= SHELL_INVALID_PARAMETER
;
1643 BufferSize
= DEFAULT_BUFFER_SIZE
;
1646 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1647 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1650 // Parse the parameter of source ip address.
1652 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1653 if (ValueStr
== NULL
) {
1654 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1657 if (ValueStr
!= NULL
) {
1658 mSrcString
= ValueStr
;
1659 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1660 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1662 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1664 if (EFI_ERROR (Status
)) {
1665 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1666 ShellStatus
= SHELL_INVALID_PARAMETER
;
1671 // Parse the parameter of destination ip address.
1673 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1674 if (NonOptionCount
< 2) {
1675 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1676 ShellStatus
= SHELL_INVALID_PARAMETER
;
1679 if (NonOptionCount
> 2) {
1680 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1681 ShellStatus
= SHELL_INVALID_PARAMETER
;
1684 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1685 if (ValueStr
!= NULL
) {
1686 mDstString
= ValueStr
;
1687 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1688 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1690 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1692 if (EFI_ERROR (Status
)) {
1693 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1694 ShellStatus
= SHELL_INVALID_PARAMETER
;
1700 // Enter into ping process.
1702 ShellStatus
= ShellPing (
1711 ShellCommandLineFreeVarList (ParamPackage
);