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
);
787 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
789 if (EFI_ERROR (Status
)) {
790 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
794 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
801 Place a completion token into the receive packet queue to receive the echo reply.
803 @param[in] Private The pointer of PING_PRIVATE_DATA.
805 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
806 @retval others Put the token into the receive packet queue unsuccessfully.
810 Ping6ReceiveEchoReply (
811 IN PING_PRIVATE_DATA
*Private
816 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
818 Status
= gBS
->CreateEvent (
821 Ping6OnEchoReplyReceived
,
823 &Private
->RxToken
.Event
826 if (EFI_ERROR (Status
)) {
830 Private
->RxToken
.Status
= EFI_NOT_READY
;
832 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
833 if (EFI_ERROR (Status
)) {
834 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
840 Remove the timeout request from the list.
842 @param[in] Event A EFI_EVENT type event.
843 @param[in] Context The pointer to Context.
848 Ping6OnTimerRoutine (
854 PING_PRIVATE_DATA
*Private
;
855 PING_ICMPX_TX_INFO
*TxInfo
;
857 LIST_ENTRY
*NextEntry
;
860 Private
= (PING_PRIVATE_DATA
*) Context
;
861 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
862 Private
->Status
= EFI_NOT_FOUND
;
867 // Retransmit icmp6 echo request packets per second in sendnumber times.
869 if (Private
->TxCount
< Private
->SendNum
) {
871 Status
= PingSendEchoRequest (Private
);
872 if (Private
->TxCount
!= 0){
873 if (EFI_ERROR (Status
)) {
874 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
879 // Check whether any icmp6 echo request in the list timeout.
881 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
882 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
883 Time
= CalculateTick (Private
, TxInfo
->TimeStamp
, ReadTime (Private
));
886 // Remove the timeout echo request from txlist.
888 if (Time
> DEFAULT_TIMEOUT
) {
890 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
891 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
894 // Remove the timeout icmp6 echo request from list.
896 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
898 RemoveEntryList (&TxInfo
->Link
);
899 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
902 Private
->FailedCount
++;
904 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
906 // All the left icmp6 echo request in the list timeout.
908 Private
->Status
= EFI_TIMEOUT
;
915 Determine if a IP4 address is Link Local.
917 169.254.1.0 through 169.254.254.255 is link local.
919 @param[in] Address The address to test.
922 @retval FALSE It is not.
925 PingNetIp4IsLinkLocalAddr (
926 IN CONST EFI_IPv4_ADDRESS
*Address
929 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
933 Determine if a IP4 address is unspecified.
935 @param[in] Address The address to test.
938 @retval FALSE It is not.
941 PingNetIp4IsUnspecifiedAddr (
942 IN CONST EFI_IPv4_ADDRESS
*Address
945 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
949 Create a valid IP instance.
951 @param[in] Private The pointer of PING_PRIVATE_DATA.
953 @retval EFI_SUCCESS Create a valid IPx instance successfully.
954 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
955 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
956 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
957 @retval EFI_NOT_FOUND The source address is not found.
960 PingCreateIpInstance (
961 IN PING_PRIVATE_DATA
*Private
967 EFI_HANDLE
*HandleBuffer
;
968 BOOLEAN UnspecifiedSrc
;
969 EFI_STATUS MediaStatus
;
970 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
972 EFI_IP6_CONFIG_DATA Ip6Config
;
973 EFI_IP4_CONFIG_DATA Ip4Config
;
974 VOID
*IpXInterfaceInfo
;
976 EFI_IPv6_ADDRESS
*Addr
;
980 UnspecifiedSrc
= FALSE
;
981 MediaStatus
= EFI_SUCCESS
;
983 IpXInterfaceInfo
= NULL
;
987 // Locate all the handles with ip6 service binding protocol.
989 Status
= gBS
->LocateHandleBuffer (
991 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
996 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
1000 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
1001 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
1003 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
1005 UnspecifiedSrc
= TRUE
;
1009 // Source address is required when pinging a link-local address.
1011 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1012 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1013 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1014 Status
= EFI_INVALID_PARAMETER
;
1018 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
1019 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1020 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1021 Status
= EFI_INVALID_PARAMETER
;
1027 // For each ip6 protocol, check interface addresses list.
1029 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
1031 IpXInterfaceInfo
= NULL
;
1034 if (UnspecifiedSrc
) {
1038 NetLibDetectMediaWaitTimeout (HandleBuffer
[HandleIndex
], 0, &MediaStatus
);
1039 if (MediaStatus
!= EFI_SUCCESS
) {
1047 Status
= gBS
->HandleProtocol (
1048 HandleBuffer
[HandleIndex
],
1049 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1052 if (EFI_ERROR (Status
)) {
1057 // Ip6config protocol and ip6 service binding protocol are installed
1058 // on the same handle.
1060 Status
= gBS
->HandleProtocol (
1061 HandleBuffer
[HandleIndex
],
1062 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4Config2ProtocolGuid
,
1066 if (EFI_ERROR (Status
)) {
1070 // Get the interface information size.
1072 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1073 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1075 Ip6ConfigDataTypeInterfaceInfo
,
1080 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1082 Ip4Config2DataTypeInterfaceInfo
,
1089 // Skip the ones not in current use.
1091 if (Status
== EFI_NOT_STARTED
) {
1095 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1096 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1100 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1102 if (IpXInterfaceInfo
== NULL
) {
1103 Status
= EFI_OUT_OF_RESOURCES
;
1107 // Get the interface info.
1109 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1110 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1112 Ip6ConfigDataTypeInterfaceInfo
,
1117 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1119 Ip4Config2DataTypeInterfaceInfo
,
1125 if (EFI_ERROR (Status
)) {
1126 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1130 // Check whether the source address is one of the interface addresses.
1132 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1133 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1134 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1136 if (UnspecifiedSrc
) {
1137 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1139 // Select the interface automatically.
1141 CopyMem(&Private
->SrcAddress
, Addr
, sizeof(Private
->SrcAddress
));
1144 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1146 // Match a certain interface address.
1152 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1154 // Found a nic handle with right interface address.
1159 if (UnspecifiedSrc
) {
1160 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1161 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1163 // Select the interface automatically.
1167 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1169 // Match a certain interface address.
1175 FreePool (IpXInterfaceInfo
);
1176 IpXInterfaceInfo
= NULL
;
1179 // No exact interface address matched.
1182 if (HandleIndex
== HandleNum
) {
1183 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1184 Status
= EFI_NOT_FOUND
;
1188 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1190 ASSERT (EfiSb
!= NULL
);
1191 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1193 if (EFI_ERROR (Status
)) {
1196 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1197 Status
= gBS
->OpenProtocol (
1198 Private
->IpChildHandle
,
1199 &gEfiIp6ProtocolGuid
,
1200 &Private
->IpProtocol
,
1202 Private
->IpChildHandle
,
1203 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1205 if (EFI_ERROR (Status
)) {
1210 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1213 // Configure the ip6 instance for icmp6 packet exchange.
1215 Ip6Config
.DefaultProtocol
= 58;
1216 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1217 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1218 Ip6Config
.AcceptPromiscuous
= FALSE
;
1219 Ip6Config
.TrafficClass
= 0;
1220 Ip6Config
.HopLimit
= 128;
1221 Ip6Config
.FlowLabel
= 0;
1222 Ip6Config
.ReceiveTimeout
= 0;
1223 Ip6Config
.TransmitTimeout
= 0;
1225 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1226 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1228 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1230 if (EFI_ERROR (Status
)) {
1231 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1235 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1236 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1237 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1238 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1240 Status
= gBS
->OpenProtocol (
1241 Private
->IpChildHandle
,
1242 &gEfiIp4ProtocolGuid
,
1243 &Private
->IpProtocol
,
1245 Private
->IpChildHandle
,
1246 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1248 if (EFI_ERROR (Status
)) {
1253 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1256 // Configure the ip4 instance for icmp4 packet exchange.
1258 Ip4Config
.DefaultProtocol
= 1;
1259 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1260 Ip4Config
.AcceptBroadcast
= FALSE
;
1261 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1262 Ip4Config
.AcceptPromiscuous
= FALSE
;
1263 Ip4Config
.DoNotFragment
= FALSE
;
1264 Ip4Config
.RawData
= FALSE
;
1265 Ip4Config
.ReceiveTimeout
= 0;
1266 Ip4Config
.TransmitTimeout
= 0;
1267 Ip4Config
.UseDefaultAddress
= TRUE
;
1268 Ip4Config
.TimeToLive
= 128;
1269 Ip4Config
.TypeOfService
= 0;
1271 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1273 if (EFI_ERROR (Status
)) {
1274 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1278 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1279 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1280 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1281 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1284 if (HandleBuffer
!= NULL
) {
1285 FreePool (HandleBuffer
);
1291 if (HandleBuffer
!= NULL
) {
1292 FreePool (HandleBuffer
);
1295 if (IpXInterfaceInfo
!= NULL
) {
1296 FreePool (IpXInterfaceInfo
);
1299 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1300 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1307 Destroy the IP instance.
1309 @param[in] Private The pointer of PING_PRIVATE_DATA.
1313 Ping6DestroyIp6Instance (
1314 IN PING_PRIVATE_DATA
*Private
1318 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1320 gBS
->CloseProtocol (
1321 Private
->IpChildHandle
,
1322 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1324 Private
->IpChildHandle
1327 Status
= gBS
->HandleProtocol (
1329 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1333 if (!EFI_ERROR(Status
)) {
1334 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1342 @param[in] SendNumber The send request count.
1343 @param[in] BufferSize The send buffer size.
1344 @param[in] SrcAddress The source address.
1345 @param[in] DstAddress The destination address.
1346 @param[in] IpChoice The choice between IPv4 and IPv6.
1348 @retval SHELL_SUCCESS The ping processed successfullly.
1349 @retval others The ping processed unsuccessfully.
1353 IN UINT32 SendNumber
,
1354 IN UINT32 BufferSize
,
1355 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1356 IN EFI_IPv6_ADDRESS
*DstAddress
,
1361 PING_PRIVATE_DATA
*Private
;
1362 PING_ICMPX_TX_INFO
*TxInfo
;
1364 LIST_ENTRY
*NextEntry
;
1365 SHELL_STATUS ShellStatus
;
1367 ShellStatus
= SHELL_SUCCESS
;
1368 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1370 if (Private
== NULL
) {
1371 return (SHELL_OUT_OF_RESOURCES
);
1374 Private
->IpChoice
= IpChoice
;
1375 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1376 Private
->SendNum
= SendNumber
;
1377 Private
->BufferSize
= BufferSize
;
1378 Private
->RttMin
= ~((UINT64
)(0x0));
1379 Private
->Status
= EFI_NOT_READY
;
1381 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1382 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1384 InitializeListHead (&Private
->TxList
);
1387 // Open and configure a ip instance for us.
1389 Status
= PingCreateIpInstance (Private
);
1391 if (EFI_ERROR (Status
)) {
1392 ShellStatus
= SHELL_ACCESS_DENIED
;
1396 // Print the command line itself.
1398 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1400 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1402 Status
= Ping6ReceiveEchoReply (Private
);
1404 if (EFI_ERROR (Status
)) {
1405 ShellStatus
= SHELL_ACCESS_DENIED
;
1409 // Create and start timer to send icmp6 echo request packet per second.
1411 Status
= gBS
->CreateEvent (
1412 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1414 Ping6OnTimerRoutine
,
1419 if (EFI_ERROR (Status
)) {
1420 ShellStatus
= SHELL_ACCESS_DENIED
;
1425 // Start a timer to calculate the RTT.
1427 Status
= PingInitRttTimer (Private
);
1428 if (EFI_ERROR (Status
)) {
1429 ShellStatus
= SHELL_ACCESS_DENIED
;
1434 // Create a ipv6 token to send the first icmp6 echo request packet.
1436 Status
= PingSendEchoRequest (Private
);
1438 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1440 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1441 ShellStatus
= SHELL_ACCESS_DENIED
;
1442 if(Status
== EFI_NOT_FOUND
) {
1443 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1444 } else if (Status
== RETURN_NO_MAPPING
) {
1445 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1447 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1453 Status
= gBS
->SetTimer (
1459 if (EFI_ERROR (Status
)) {
1460 ShellStatus
= SHELL_ACCESS_DENIED
;
1464 // Control the ping6 process by two factors:
1466 // 2. Private->Status
1467 // 2.1. success means all icmp6 echo request packets get reply packets.
1468 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1469 // 2.3. noready means ping6 process is on-the-go.
1471 while (Private
->Status
== EFI_NOT_READY
) {
1472 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1473 if (ShellGetExecutionBreakFlag()) {
1474 Private
->Status
= EFI_ABORTED
;
1481 // Display the statistics in all.
1483 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1485 if (Private
->TxCount
!= 0) {
1490 STRING_TOKEN (STR_PING_STAT
),
1491 gShellNetwork1HiiHandle
,
1493 (Private
->RxCount
- Private
->FailedCount
),
1494 (100 - ((100 * (Private
->RxCount
- Private
->FailedCount
)) / Private
->TxCount
)),
1499 if (Private
->RxCount
> Private
->FailedCount
) {
1504 STRING_TOKEN (STR_PING_RTT
),
1505 gShellNetwork1HiiHandle
,
1507 Private
->RttMin
+ Private
->TimerPeriod
,
1509 Private
->RttMax
+ Private
->TimerPeriod
,
1510 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
),
1511 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
) + Private
->TimerPeriod
1517 if (Private
!= NULL
) {
1519 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1520 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1522 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1523 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1526 RemoveEntryList (&TxInfo
->Link
);
1527 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1530 PingFreeRttTimer (Private
);
1532 if (Private
->Timer
!= NULL
) {
1533 gBS
->CloseEvent (Private
->Timer
);
1536 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1537 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1540 if (Private
->RxToken
.Event
!= NULL
) {
1541 gBS
->CloseEvent (Private
->RxToken
.Event
);
1544 if (Private
->IpChildHandle
!= NULL
) {
1545 Ping6DestroyIp6Instance (Private
);
1555 Function for 'ping' command.
1557 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1558 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1560 @retval SHELL_SUCCESS The ping processed successfullly.
1561 @retval others The ping processed unsuccessfully.
1566 ShellCommandRunPing (
1567 IN EFI_HANDLE ImageHandle
,
1568 IN EFI_SYSTEM_TABLE
*SystemTable
1572 SHELL_STATUS ShellStatus
;
1573 EFI_IPv6_ADDRESS DstAddress
;
1574 EFI_IPv6_ADDRESS SrcAddress
;
1577 LIST_ENTRY
*ParamPackage
;
1578 CONST CHAR16
*ValueStr
;
1579 UINTN NonOptionCount
;
1581 CHAR16
*ProblemParam
;
1584 // we use IPv6 buffers to hold items...
1585 // make sure this is enough space!
1587 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1588 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1590 IpChoice
= PING_IP_CHOICE_IP4
;
1592 ShellStatus
= SHELL_SUCCESS
;
1593 ProblemParam
= NULL
;
1595 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1596 if (EFI_ERROR(Status
)) {
1597 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1598 ShellStatus
= SHELL_INVALID_PARAMETER
;
1602 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1603 IpChoice
= PING_IP_CHOICE_IP6
;
1607 // Parse the parameter of count number.
1609 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1610 if (ValueStr
!= NULL
) {
1611 SendNumber
= ShellStrToUintn (ValueStr
);
1614 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1616 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1617 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1618 ShellStatus
= SHELL_INVALID_PARAMETER
;
1622 SendNumber
= DEFAULT_SEND_COUNT
;
1625 // Parse the parameter of buffer size.
1627 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1628 if (ValueStr
!= NULL
) {
1629 BufferSize
= ShellStrToUintn (ValueStr
);
1632 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1634 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1635 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1636 ShellStatus
= SHELL_INVALID_PARAMETER
;
1640 BufferSize
= DEFAULT_BUFFER_SIZE
;
1643 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1644 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1647 // Parse the parameter of source ip address.
1649 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1650 if (ValueStr
== NULL
) {
1651 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1654 if (ValueStr
!= NULL
) {
1655 mSrcString
= ValueStr
;
1656 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1657 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1659 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1661 if (EFI_ERROR (Status
)) {
1662 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1663 ShellStatus
= SHELL_INVALID_PARAMETER
;
1668 // Parse the parameter of destination ip address.
1670 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1671 if (NonOptionCount
< 2) {
1672 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1673 ShellStatus
= SHELL_INVALID_PARAMETER
;
1676 if (NonOptionCount
> 2) {
1677 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1678 ShellStatus
= SHELL_INVALID_PARAMETER
;
1681 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1682 if (ValueStr
!= NULL
) {
1683 mDstString
= ValueStr
;
1684 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1685 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1687 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1689 if (EFI_ERROR (Status
)) {
1690 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1691 ShellStatus
= SHELL_INVALID_PARAMETER
;
1697 // Enter into ping process.
1699 ShellStatus
= ShellPing (
1708 ShellCommandLineFreeVarList (ParamPackage
);