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
;
65 // PING_IPX_COMPLETION_TOKEN
66 // structures are used for both transmit and receive operations.
67 // This version is IP-unaware.
73 } PING_IPX_COMPLETION_TOKEN
;
76 typedef struct _ICMPX_ECHO_REQUEST_REPLY
{
84 } ICMPX_ECHO_REQUEST_REPLY
;
87 typedef struct _PING_ICMP_TX_INFO
{
91 PING_IPX_COMPLETION_TOKEN
*Token
;
94 #define DEFAULT_TIMEOUT 5000
95 #define MAX_SEND_NUMBER 10000
96 #define MAX_BUFFER_SIZE 32768
97 #define DEFAULT_TIMER_PERIOD 358049
98 #define ONE_SECOND 10000000
99 #define PING_IP_CHOICE_IP4 1
100 #define PING_IP_CHOICE_IP6 2
101 #define DEFAULT_SEND_COUNT 10
102 #define DEFAULT_BUFFER_SIZE 16
103 #define ICMP_V4_ECHO_REQUEST 0x8
104 #define ICMP_V4_ECHO_REPLY 0x0
105 #define STALL_1_MILLI_SECOND 1000
107 #define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')
108 typedef struct _PING_PRIVATE_DATA
{
110 EFI_HANDLE NicHandle
;
111 EFI_HANDLE IpChildHandle
;
131 PING_IPX_PROTOCOL ProtocolPointers
;
133 UINT8 SrcAddress
[MAX (sizeof (EFI_IPv6_ADDRESS
), sizeof (EFI_IPv4_ADDRESS
))];
134 UINT8 DstAddress
[MAX (sizeof (EFI_IPv6_ADDRESS
), sizeof (EFI_IPv4_ADDRESS
))];
135 PING_IPX_COMPLETION_TOKEN RxToken
;
140 Calculate the internet checksum (see RFC 1071).
142 @param[in] Packet Buffer which contains the data to be checksummed.
143 @param[in] Length Length to be checksummed.
145 @retval Checksum Returns the 16 bit ones complement of
146 ones complement sum of 16 bit words
158 Packet
= (UINT16
*)Buffer
;
161 Odd
= (UINT8
)(Length
& 1);
163 while ((Length
--) != 0) {
168 Sum
+= *(UINT8
*)Packet
;
171 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
174 // in case above carried
182 Reads and returns the current value of register.
183 In IA64, the register is the Interval Timer Vector (ITV).
184 In X86(IA32/X64), the register is the Time Stamp Counter (TSC)
186 @return The current value of the register.
190 STATIC CONST SHELL_PARAM_ITEM PingParamList
[] = {
218 // Global Variables in Ping command.
220 STATIC CONST CHAR16
*mDstString
;
221 STATIC CONST CHAR16
*mSrcString
;
224 RTT timer tick routine.
226 @param[in] Event A EFI_EVENT type event.
227 @param[in] Context The pointer to Context.
232 RttTimerTickRoutine (
237 UINT32
*RttTimerTick
;
239 RttTimerTick
= (UINT32
*)Context
;
244 Get the timer period of the system.
246 This function tries to get the system timer period by creating
249 @return System timer period in MS, or 0 if operation failed.
259 EFI_EVENT TimerEvent
;
268 Status
= gBS
->CreateEvent (
269 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
275 if (EFI_ERROR (Status
)) {
279 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
280 Status
= gBS
->SetTimer (
285 if (EFI_ERROR (Status
)) {
286 gBS
->CloseEvent (TimerEvent
);
290 while (RttTimerTick
< 10) {
291 gBS
->Stall (STALL_1_MILLI_SECOND
);
295 gBS
->RestoreTPL (OldTpl
);
297 gBS
->SetTimer (TimerEvent
, TimerCancel
, 0);
298 gBS
->CloseEvent (TimerEvent
);
300 TimerPeriod
= StallCounter
/ RttTimerTick
;
301 if (TimerPeriod
!= 0) {
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
) {
432 if (TxInfo
->Token
->Event
!= NULL
) {
433 gBS
->CloseEvent (TxInfo
->Token
->Event
);
436 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
437 if (IpChoice
== PING_IP_CHOICE_IP6
) {
438 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
440 if (Ip6TxData
->OverrideData
!= NULL
) {
441 FreePool (Ip6TxData
->OverrideData
);
444 if (Ip6TxData
->ExtHdrs
!= NULL
) {
445 FreePool (Ip6TxData
->ExtHdrs
);
448 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
449 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
450 if (FragData
!= NULL
) {
455 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
457 if (Ip4TxData
->OverrideData
!= NULL
) {
458 FreePool (Ip4TxData
->OverrideData
);
461 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
462 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
463 if (FragData
!= NULL
) {
470 FreePool (TxInfo
->Token
);
477 Match the request, and reply with SequenceNum/TimeStamp.
479 @param[in] Private The pointer to PING_PRIVATE_DATA.
480 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
482 @retval EFI_SUCCESS The match is successful.
483 @retval EFI_NOT_FOUND The reply can't be matched with any request.
487 Ping6MatchEchoReply (
488 IN PING_PRIVATE_DATA
*Private
,
489 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
492 PING_ICMPX_TX_INFO
*TxInfo
;
494 LIST_ENTRY
*NextEntry
;
496 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
497 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
499 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
501 RemoveEntryList (&TxInfo
->Link
);
502 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
507 return EFI_NOT_FOUND
;
511 The original intention is to send a request.
512 Currently, the application retransmits an icmp6 echo request packet
513 per second in sendnumber times that is specified by the user.
514 Because nothing can be done here, all things move to the timer rountine.
516 @param[in] Event A EFI_EVENT type event.
517 @param[in] Context The pointer to Context.
522 Ping6OnEchoRequestSent (
530 receive reply, match and print reply infomation.
532 @param[in] Event A EFI_EVENT type event.
533 @param[in] Context The pointer to context.
538 Ping6OnEchoReplyReceived (
544 PING_PRIVATE_DATA
*Private
;
545 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
549 Private
= (PING_PRIVATE_DATA
*)Context
;
551 if ((Private
== NULL
) || (Private
->Status
== EFI_ABORTED
) || (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
)) {
555 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
559 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
560 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
561 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
562 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
))
572 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
576 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
577 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
578 if (!IP4_IS_MULTICAST (EFI_IP4 (*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
579 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
))
584 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
589 if (PayLoad
!= Private
->BufferSize
) {
594 // Check whether the reply matches the sent request before.
596 Status
= Ping6MatchEchoReply (Private
, Reply
);
597 if (EFI_ERROR (Status
)) {
602 // Display statistics on this icmp6 echo reply packet.
604 Rtt
= CalculateTick (Private
, Reply
->TimeStamp
, ReadTime (Private
));
606 Private
->RttSum
+= Rtt
;
607 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
608 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
614 STRING_TOKEN (STR_PING_REPLY_INFO
),
615 gShellNetwork1HiiHandle
,
619 Private
->IpChoice
== PING_IP_CHOICE_IP6
? ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
: 0,
621 Rtt
+ Private
->TimerPeriod
627 // Recycle the packet before reusing RxToken
629 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
);
631 if (Private
->RxCount
< Private
->SendNum
) {
633 // Continue to receive icmp echo reply packets.
635 Private
->RxToken
.Status
= EFI_ABORTED
;
637 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
639 if (EFI_ERROR (Status
)) {
640 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
641 Private
->Status
= EFI_ABORTED
;
645 // All reply have already been received from the dest host.
647 Private
->Status
= EFI_SUCCESS
;
652 Create a PING_IPX_COMPLETION_TOKEN.
654 @param[in] Private The pointer of PING_PRIVATE_DATA.
655 @param[in] TimeStamp The TimeStamp of request.
656 @param[in] SequenceNum The SequenceNum of request.
658 @return The pointer of PING_IPX_COMPLETION_TOKEN.
661 PING_IPX_COMPLETION_TOKEN
*
663 IN PING_PRIVATE_DATA
*Private
,
665 IN UINT16 SequenceNum
669 PING_IPX_COMPLETION_TOKEN
*Token
;
671 ICMPX_ECHO_REQUEST_REPLY
*Request
;
675 Request
= AllocateZeroPool (Private
->BufferSize
);
676 if (Request
== NULL
) {
680 TxData
= AllocateZeroPool (Private
->IpChoice
== PING_IP_CHOICE_IP6
? sizeof (EFI_IP6_TRANSMIT_DATA
) : sizeof (EFI_IP4_TRANSMIT_DATA
));
681 if (TxData
== NULL
) {
686 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
694 // Assembly echo request packet.
696 Request
->Type
= (UINT8
)(Private
->IpChoice
== PING_IP_CHOICE_IP6
? ICMP_V6_ECHO_REQUEST
: ICMP_V4_ECHO_REQUEST
);
698 Request
->SequenceNum
= SequenceNum
;
699 Request
->Identifier
= 0;
700 Request
->Checksum
= 0;
703 // Assembly token for transmit.
705 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
706 Request
->TimeStamp
= TimeStamp
;
707 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
708 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
709 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
710 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
711 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
712 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*)Request
;
713 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
715 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
716 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
717 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
718 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
719 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
720 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*)Request
;
721 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
722 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
723 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
724 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
725 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
727 HeadSum
= NetChecksum ((UINT8
*)Request
, Private
->BufferSize
);
728 Request
->TimeStamp
= TimeStamp
;
729 TempChecksum
= NetChecksum ((UINT8
*)&Request
->TimeStamp
, sizeof (UINT64
));
730 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
733 Token
->Status
= EFI_ABORTED
;
734 Token
->Packet
.TxData
= TxData
;
736 Status
= gBS
->CreateEvent (
739 Ping6OnEchoRequestSent
,
744 if (EFI_ERROR (Status
)) {
755 Transmit the PING_IPX_COMPLETION_TOKEN.
757 @param[in] Private The pointer of PING_PRIVATE_DATA.
759 @retval EFI_SUCCESS Transmitted successfully.
760 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
761 @retval others Transmitted unsuccessfully.
765 PingSendEchoRequest (
766 IN PING_PRIVATE_DATA
*Private
770 PING_ICMPX_TX_INFO
*TxInfo
;
772 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
774 if (TxInfo
== NULL
) {
775 return EFI_OUT_OF_RESOURCES
;
778 TxInfo
->TimeStamp
= ReadTime (Private
);
779 TxInfo
->SequenceNum
= (UINT16
)(Private
->TxCount
+ 1);
780 TxInfo
->Token
= PingGenerateToken (
786 if (TxInfo
->Token
== NULL
) {
787 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
788 return EFI_OUT_OF_RESOURCES
;
791 ASSERT (Private
->ProtocolPointers
.Transmit
!= NULL
);
793 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
795 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
797 if (EFI_ERROR (Status
)) {
798 RemoveEntryList (&TxInfo
->Link
);
799 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
809 Place a completion token into the receive packet queue to receive the echo reply.
811 @param[in] Private The pointer of PING_PRIVATE_DATA.
813 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
814 @retval others Put the token into the receive packet queue unsuccessfully.
818 Ping6ReceiveEchoReply (
819 IN PING_PRIVATE_DATA
*Private
824 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
826 Status
= gBS
->CreateEvent (
829 Ping6OnEchoReplyReceived
,
831 &Private
->RxToken
.Event
834 if (EFI_ERROR (Status
)) {
838 Private
->RxToken
.Status
= EFI_NOT_READY
;
840 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
841 if (EFI_ERROR (Status
)) {
842 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
849 Remove the timeout request from the list.
851 @param[in] Event A EFI_EVENT type event.
852 @param[in] Context The pointer to Context.
857 Ping6OnTimerRoutine (
863 PING_PRIVATE_DATA
*Private
;
864 PING_ICMPX_TX_INFO
*TxInfo
;
866 LIST_ENTRY
*NextEntry
;
869 Private
= (PING_PRIVATE_DATA
*)Context
;
870 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
871 Private
->Status
= EFI_NOT_FOUND
;
876 // Retransmit icmp6 echo request packets per second in sendnumber times.
878 if (Private
->TxCount
< Private
->SendNum
) {
879 Status
= PingSendEchoRequest (Private
);
880 if (Private
->TxCount
!= 0) {
881 if (EFI_ERROR (Status
)) {
882 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
888 // Check whether any icmp6 echo request in the list timeout.
890 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
891 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
892 Time
= CalculateTick (Private
, TxInfo
->TimeStamp
, ReadTime (Private
));
895 // Remove the timeout echo request from txlist.
897 if (Time
> DEFAULT_TIMEOUT
) {
898 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
899 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
903 // Remove the timeout icmp6 echo request from list.
905 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
907 RemoveEntryList (&TxInfo
->Link
);
908 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
911 Private
->FailedCount
++;
913 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
915 // All the left icmp6 echo request in the list timeout.
917 Private
->Status
= EFI_TIMEOUT
;
924 Determine if a IP4 address is Link Local.
926 169.254.1.0 through 169.254.254.255 is link local.
928 @param[in] Address The address to test.
931 @retval FALSE It is not.
934 PingNetIp4IsLinkLocalAddr (
935 IN CONST EFI_IPv4_ADDRESS
*Address
938 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
942 Determine if a IP4 address is unspecified.
944 @param[in] Address The address to test.
947 @retval FALSE It is not.
950 PingNetIp4IsUnspecifiedAddr (
951 IN CONST EFI_IPv4_ADDRESS
*Address
954 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
958 Create a valid IP instance.
960 @param[in] Private The pointer of PING_PRIVATE_DATA.
962 @retval EFI_SUCCESS Create a valid IPx instance successfully.
963 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
964 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
965 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
966 @retval EFI_NOT_FOUND The source address is not found.
969 PingCreateIpInstance (
970 IN PING_PRIVATE_DATA
*Private
976 EFI_HANDLE
*HandleBuffer
;
977 BOOLEAN UnspecifiedSrc
;
978 EFI_STATUS MediaStatus
;
979 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
981 EFI_IP6_CONFIG_DATA Ip6Config
;
982 EFI_IP4_CONFIG_DATA Ip4Config
;
983 VOID
*IpXInterfaceInfo
;
985 EFI_IPv6_ADDRESS
*Addr
;
989 UnspecifiedSrc
= FALSE
;
990 MediaStatus
= EFI_SUCCESS
;
992 IpXInterfaceInfo
= NULL
;
996 // Locate all the handles with ip6 service binding protocol.
998 Status
= gBS
->LocateHandleBuffer (
1000 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ServiceBindingProtocolGuid
: &gEfiIp4ServiceBindingProtocolGuid
,
1005 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
1009 if ((Private
->IpChoice
== PING_IP_CHOICE_IP6
) ? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
1010 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
))
1013 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
1015 UnspecifiedSrc
= TRUE
;
1019 // Source address is required when pinging a link-local address.
1021 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1022 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1023 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1024 Status
= EFI_INVALID_PARAMETER
;
1028 ASSERT (Private
->IpChoice
== PING_IP_CHOICE_IP4
);
1029 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1030 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1031 Status
= EFI_INVALID_PARAMETER
;
1037 // For each ip6 protocol, check interface addresses list.
1039 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
1041 IpXInterfaceInfo
= NULL
;
1044 if (UnspecifiedSrc
) {
1048 NetLibDetectMediaWaitTimeout (HandleBuffer
[HandleIndex
], 0, &MediaStatus
);
1049 if (MediaStatus
!= EFI_SUCCESS
) {
1057 Status
= gBS
->HandleProtocol (
1058 HandleBuffer
[HandleIndex
],
1059 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ServiceBindingProtocolGuid
: &gEfiIp4ServiceBindingProtocolGuid
,
1062 if (EFI_ERROR (Status
)) {
1067 // Ip6config protocol and ip6 service binding protocol are installed
1068 // on the same handle.
1070 Status
= gBS
->HandleProtocol (
1071 HandleBuffer
[HandleIndex
],
1072 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ConfigProtocolGuid
: &gEfiIp4Config2ProtocolGuid
,
1076 if (EFI_ERROR (Status
)) {
1081 // Get the interface information size.
1083 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1084 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1086 Ip6ConfigDataTypeInterfaceInfo
,
1091 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1093 Ip4Config2DataTypeInterfaceInfo
,
1100 // Skip the ones not in current use.
1102 if (Status
== EFI_NOT_STARTED
) {
1106 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1107 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1111 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1113 if (IpXInterfaceInfo
== NULL
) {
1114 Status
= EFI_OUT_OF_RESOURCES
;
1119 // Get the interface info.
1121 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1122 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1124 Ip6ConfigDataTypeInterfaceInfo
,
1129 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1131 Ip4Config2DataTypeInterfaceInfo
,
1137 if (EFI_ERROR (Status
)) {
1138 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1143 // Check whether the source address is one of the interface addresses.
1145 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1146 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1147 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1149 if (UnspecifiedSrc
) {
1150 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1152 // Select the interface automatically.
1154 CopyMem (&Private
->SrcAddress
, Addr
, sizeof (Private
->SrcAddress
));
1157 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1159 // Match a certain interface address.
1165 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1167 // Found a nic handle with right interface address.
1172 if (UnspecifiedSrc
) {
1173 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1174 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
))
1177 // Select the interface automatically.
1181 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1183 // Match a certain interface address.
1189 FreePool (IpXInterfaceInfo
);
1190 IpXInterfaceInfo
= NULL
;
1194 // No exact interface address matched.
1197 if (HandleIndex
== HandleNum
) {
1198 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1199 Status
= EFI_NOT_FOUND
;
1203 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1205 ASSERT (EfiSb
!= NULL
);
1206 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1208 if (EFI_ERROR (Status
)) {
1212 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1213 Status
= gBS
->OpenProtocol (
1214 Private
->IpChildHandle
,
1215 &gEfiIp6ProtocolGuid
,
1216 &Private
->IpProtocol
,
1218 Private
->IpChildHandle
,
1219 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1221 if (EFI_ERROR (Status
)) {
1225 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1228 // Configure the ip6 instance for icmp6 packet exchange.
1230 Ip6Config
.DefaultProtocol
= 58;
1231 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1232 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1233 Ip6Config
.AcceptPromiscuous
= FALSE
;
1234 Ip6Config
.TrafficClass
= 0;
1235 Ip6Config
.HopLimit
= 128;
1236 Ip6Config
.FlowLabel
= 0;
1237 Ip6Config
.ReceiveTimeout
= 0;
1238 Ip6Config
.TransmitTimeout
= 0;
1240 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1241 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1243 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1245 if (EFI_ERROR (Status
)) {
1246 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1250 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1251 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1252 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1253 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1255 Status
= gBS
->OpenProtocol (
1256 Private
->IpChildHandle
,
1257 &gEfiIp4ProtocolGuid
,
1258 &Private
->IpProtocol
,
1260 Private
->IpChildHandle
,
1261 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1263 if (EFI_ERROR (Status
)) {
1267 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1270 // Configure the ip4 instance for icmp4 packet exchange.
1272 Ip4Config
.DefaultProtocol
= 1;
1273 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1274 Ip4Config
.AcceptBroadcast
= FALSE
;
1275 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1276 Ip4Config
.AcceptPromiscuous
= FALSE
;
1277 Ip4Config
.DoNotFragment
= FALSE
;
1278 Ip4Config
.RawData
= FALSE
;
1279 Ip4Config
.ReceiveTimeout
= 0;
1280 Ip4Config
.TransmitTimeout
= 0;
1281 Ip4Config
.UseDefaultAddress
= TRUE
;
1282 Ip4Config
.TimeToLive
= 128;
1283 Ip4Config
.TypeOfService
= 0;
1285 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1287 if (EFI_ERROR (Status
)) {
1288 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1292 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1293 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1294 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1295 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1298 if (HandleBuffer
!= NULL
) {
1299 FreePool (HandleBuffer
);
1305 if (HandleBuffer
!= NULL
) {
1306 FreePool (HandleBuffer
);
1309 if (IpXInterfaceInfo
!= NULL
) {
1310 FreePool (IpXInterfaceInfo
);
1313 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1314 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1321 Destroy the IP instance.
1323 @param[in] Private The pointer of PING_PRIVATE_DATA.
1327 Ping6DestroyIp6Instance (
1328 IN PING_PRIVATE_DATA
*Private
1332 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1334 gBS
->CloseProtocol (
1335 Private
->IpChildHandle
,
1336 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ProtocolGuid
: &gEfiIp4ProtocolGuid
,
1338 Private
->IpChildHandle
1341 Status
= gBS
->HandleProtocol (
1343 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ServiceBindingProtocolGuid
: &gEfiIp4ServiceBindingProtocolGuid
,
1347 if (!EFI_ERROR (Status
)) {
1348 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1355 @param[in] SendNumber The send request count.
1356 @param[in] BufferSize The send buffer size.
1357 @param[in] SrcAddress The source address.
1358 @param[in] DstAddress The destination address.
1359 @param[in] IpChoice The choice between IPv4 and IPv6.
1361 @retval SHELL_SUCCESS The ping processed successfullly.
1362 @retval others The ping processed unsuccessfully.
1366 IN UINT32 SendNumber
,
1367 IN UINT32 BufferSize
,
1368 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1369 IN EFI_IPv6_ADDRESS
*DstAddress
,
1374 PING_PRIVATE_DATA
*Private
;
1375 PING_ICMPX_TX_INFO
*TxInfo
;
1377 LIST_ENTRY
*NextEntry
;
1378 SHELL_STATUS ShellStatus
;
1380 ShellStatus
= SHELL_SUCCESS
;
1381 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1383 if (Private
== NULL
) {
1384 return (SHELL_OUT_OF_RESOURCES
);
1387 Private
->IpChoice
= IpChoice
;
1388 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1389 Private
->SendNum
= SendNumber
;
1390 Private
->BufferSize
= BufferSize
;
1391 Private
->RttMin
= ~((UINT64
)(0x0));
1392 Private
->Status
= EFI_NOT_READY
;
1394 CopyMem (&Private
->SrcAddress
, SrcAddress
, sizeof (Private
->SrcAddress
));
1395 CopyMem (&Private
->DstAddress
, DstAddress
, sizeof (Private
->DstAddress
));
1397 InitializeListHead (&Private
->TxList
);
1400 // Open and configure a ip instance for us.
1402 Status
= PingCreateIpInstance (Private
);
1404 if (EFI_ERROR (Status
)) {
1405 ShellStatus
= SHELL_ACCESS_DENIED
;
1410 // Print the command line itself.
1412 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1414 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1416 Status
= Ping6ReceiveEchoReply (Private
);
1418 if (EFI_ERROR (Status
)) {
1419 ShellStatus
= SHELL_ACCESS_DENIED
;
1424 // Create and start timer to send icmp6 echo request packet per second.
1426 Status
= gBS
->CreateEvent (
1427 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1429 Ping6OnTimerRoutine
,
1434 if (EFI_ERROR (Status
)) {
1435 ShellStatus
= SHELL_ACCESS_DENIED
;
1440 // Start a timer to calculate the RTT.
1442 Status
= PingInitRttTimer (Private
);
1443 if (EFI_ERROR (Status
)) {
1444 ShellStatus
= SHELL_ACCESS_DENIED
;
1449 // Create a ipv6 token to send the first icmp6 echo request packet.
1451 Status
= PingSendEchoRequest (Private
);
1453 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1455 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1456 ShellStatus
= SHELL_ACCESS_DENIED
;
1457 if (Status
== EFI_NOT_FOUND
) {
1458 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1459 } else if (Status
== RETURN_NO_MAPPING
) {
1460 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1462 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1468 Status
= gBS
->SetTimer (
1474 if (EFI_ERROR (Status
)) {
1475 ShellStatus
= SHELL_ACCESS_DENIED
;
1480 // Control the ping6 process by two factors:
1482 // 2. Private->Status
1483 // 2.1. success means all icmp6 echo request packets get reply packets.
1484 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1485 // 2.3. noready means ping6 process is on-the-go.
1487 while (Private
->Status
== EFI_NOT_READY
) {
1488 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1489 if (ShellGetExecutionBreakFlag ()) {
1490 Private
->Status
= EFI_ABORTED
;
1497 // Display the statistics in all.
1499 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1501 if (Private
->TxCount
!= 0) {
1506 STRING_TOKEN (STR_PING_STAT
),
1507 gShellNetwork1HiiHandle
,
1509 (Private
->RxCount
- Private
->FailedCount
),
1510 (100 - ((100 * (Private
->RxCount
- Private
->FailedCount
)) / Private
->TxCount
)),
1515 if (Private
->RxCount
> Private
->FailedCount
) {
1520 STRING_TOKEN (STR_PING_RTT
),
1521 gShellNetwork1HiiHandle
,
1523 Private
->RttMin
+ Private
->TimerPeriod
,
1525 Private
->RttMax
+ Private
->TimerPeriod
,
1526 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
),
1527 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
) + Private
->TimerPeriod
1533 if (Private
!= NULL
) {
1534 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1535 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1537 if ((Private
->IpProtocol
!= NULL
) && (Private
->ProtocolPointers
.Cancel
!= NULL
)) {
1538 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1541 RemoveEntryList (&TxInfo
->Link
);
1542 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1545 PingFreeRttTimer (Private
);
1547 if (Private
->Timer
!= NULL
) {
1548 gBS
->CloseEvent (Private
->Timer
);
1551 if ((Private
->IpProtocol
!= NULL
) && (Private
->ProtocolPointers
.Cancel
!= NULL
)) {
1552 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1555 if (Private
->RxToken
.Event
!= NULL
) {
1556 gBS
->CloseEvent (Private
->RxToken
.Event
);
1559 if (Private
->IpChildHandle
!= NULL
) {
1560 Ping6DestroyIp6Instance (Private
);
1570 Function for 'ping' command.
1572 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1573 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1575 @retval SHELL_SUCCESS The ping processed successfullly.
1576 @retval others The ping processed unsuccessfully.
1581 ShellCommandRunPing (
1582 IN EFI_HANDLE ImageHandle
,
1583 IN EFI_SYSTEM_TABLE
*SystemTable
1587 SHELL_STATUS ShellStatus
;
1588 EFI_IPv6_ADDRESS DstAddress
;
1589 EFI_IPv6_ADDRESS SrcAddress
;
1592 LIST_ENTRY
*ParamPackage
;
1593 CONST CHAR16
*ValueStr
;
1594 UINTN NonOptionCount
;
1596 CHAR16
*ProblemParam
;
1599 // we use IPv6 buffers to hold items...
1600 // make sure this is enough space!
1602 ASSERT (sizeof (EFI_IPv4_ADDRESS
) <= sizeof (EFI_IPv6_ADDRESS
));
1603 ASSERT (sizeof (EFI_IP4_COMPLETION_TOKEN
) <= sizeof (EFI_IP6_COMPLETION_TOKEN
));
1605 IpChoice
= PING_IP_CHOICE_IP4
;
1607 ShellStatus
= SHELL_SUCCESS
;
1608 ProblemParam
= NULL
;
1610 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1611 if (EFI_ERROR (Status
)) {
1612 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1613 ShellStatus
= SHELL_INVALID_PARAMETER
;
1617 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1618 IpChoice
= PING_IP_CHOICE_IP6
;
1622 // Parse the parameter of count number.
1624 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1625 if (ValueStr
!= NULL
) {
1626 SendNumber
= ShellStrToUintn (ValueStr
);
1629 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1631 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1632 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1633 ShellStatus
= SHELL_INVALID_PARAMETER
;
1637 SendNumber
= DEFAULT_SEND_COUNT
;
1641 // Parse the parameter of buffer size.
1643 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1644 if (ValueStr
!= NULL
) {
1645 BufferSize
= ShellStrToUintn (ValueStr
);
1648 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1650 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1651 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1652 ShellStatus
= SHELL_INVALID_PARAMETER
;
1656 BufferSize
= DEFAULT_BUFFER_SIZE
;
1659 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1660 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1663 // Parse the parameter of source ip address.
1665 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1666 if (ValueStr
== NULL
) {
1667 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1670 if (ValueStr
!= NULL
) {
1671 mSrcString
= ValueStr
;
1672 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1673 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1675 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1678 if (EFI_ERROR (Status
)) {
1679 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1680 ShellStatus
= SHELL_INVALID_PARAMETER
;
1686 // Parse the parameter of destination ip address.
1688 NonOptionCount
= ShellCommandLineGetCount (ParamPackage
);
1689 if (NonOptionCount
< 2) {
1690 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1691 ShellStatus
= SHELL_INVALID_PARAMETER
;
1695 if (NonOptionCount
> 2) {
1696 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1697 ShellStatus
= SHELL_INVALID_PARAMETER
;
1701 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1702 if (ValueStr
!= NULL
) {
1703 mDstString
= ValueStr
;
1704 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1705 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1707 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1710 if (EFI_ERROR (Status
)) {
1711 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1712 ShellStatus
= SHELL_INVALID_PARAMETER
;
1718 // Enter into ping process.
1720 ShellStatus
= ShellPing (
1729 ShellCommandLineFreeVarList (ParamPackage
);