2 The implementation for Ping shell command.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2016, 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 Private
->Status
= EFI_ABORTED
;
636 // All reply have already been received from the dest host.
638 Private
->Status
= EFI_SUCCESS
;
641 // Singal to recycle the each rxdata here, not at the end of process.
643 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
);
647 Create a PING_IPX_COMPLETION_TOKEN.
649 @param[in] Private The pointer of PING_PRIVATE_DATA.
650 @param[in] TimeStamp The TimeStamp of request.
651 @param[in] SequenceNum The SequenceNum of request.
653 @return The pointer of PING_IPX_COMPLETION_TOKEN.
656 PING_IPX_COMPLETION_TOKEN
*
658 IN PING_PRIVATE_DATA
*Private
,
660 IN UINT16 SequenceNum
664 PING_IPX_COMPLETION_TOKEN
*Token
;
666 ICMPX_ECHO_REQUEST_REPLY
*Request
;
670 Request
= AllocateZeroPool (Private
->BufferSize
);
671 if (Request
== NULL
) {
674 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
675 if (TxData
== NULL
) {
679 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
687 // Assembly echo request packet.
689 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
691 Request
->SequenceNum
= SequenceNum
;
692 Request
->Identifier
= 0;
693 Request
->Checksum
= 0;
696 // Assembly token for transmit.
698 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
699 Request
->TimeStamp
= TimeStamp
;
700 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
701 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
702 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
703 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
704 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
705 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
706 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
708 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
709 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
710 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
711 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
712 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
713 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
714 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
715 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
716 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
717 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
718 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
720 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
721 Request
->TimeStamp
= TimeStamp
;
722 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
723 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
727 Token
->Status
= EFI_ABORTED
;
728 Token
->Packet
.TxData
= TxData
;
730 Status
= gBS
->CreateEvent (
733 Ping6OnEchoRequestSent
,
738 if (EFI_ERROR (Status
)) {
749 Transmit the PING_IPX_COMPLETION_TOKEN.
751 @param[in] Private The pointer of PING_PRIVATE_DATA.
753 @retval EFI_SUCCESS Transmitted successfully.
754 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
755 @retval others Transmitted unsuccessfully.
759 PingSendEchoRequest (
760 IN PING_PRIVATE_DATA
*Private
764 PING_ICMPX_TX_INFO
*TxInfo
;
766 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
768 if (TxInfo
== NULL
) {
769 return EFI_OUT_OF_RESOURCES
;
772 TxInfo
->TimeStamp
= ReadTime (Private
);
773 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
774 TxInfo
->Token
= PingGenerateToken (
780 if (TxInfo
->Token
== NULL
) {
781 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
782 return EFI_OUT_OF_RESOURCES
;
785 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
786 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
788 if (EFI_ERROR (Status
)) {
789 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
793 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
800 Place a completion token into the receive packet queue to receive the echo reply.
802 @param[in] Private The pointer of PING_PRIVATE_DATA.
804 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
805 @retval others Put the token into the receive packet queue unsuccessfully.
809 Ping6ReceiveEchoReply (
810 IN PING_PRIVATE_DATA
*Private
815 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
817 Status
= gBS
->CreateEvent (
820 Ping6OnEchoReplyReceived
,
822 &Private
->RxToken
.Event
825 if (EFI_ERROR (Status
)) {
829 Private
->RxToken
.Status
= EFI_NOT_READY
;
831 return (Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
));
835 Remove the timeout request from the list.
837 @param[in] Event A EFI_EVENT type event.
838 @param[in] Context The pointer to Context.
843 Ping6OnTimerRoutine (
849 PING_PRIVATE_DATA
*Private
;
850 PING_ICMPX_TX_INFO
*TxInfo
;
852 LIST_ENTRY
*NextEntry
;
855 Private
= (PING_PRIVATE_DATA
*) Context
;
856 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
857 Private
->Status
= EFI_NOT_FOUND
;
862 // Retransmit icmp6 echo request packets per second in sendnumber times.
864 if (Private
->TxCount
< Private
->SendNum
) {
866 Status
= PingSendEchoRequest (Private
);
867 if (Private
->TxCount
!= 0){
868 if (EFI_ERROR (Status
)) {
869 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
874 // Check whether any icmp6 echo request in the list timeout.
876 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
877 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
878 Time
= CalculateTick (Private
, TxInfo
->TimeStamp
, ReadTime (Private
));
881 // Remove the timeout echo request from txlist.
883 if (Time
> DEFAULT_TIMEOUT
) {
885 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
886 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
889 // Remove the timeout icmp6 echo request from list.
891 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
893 RemoveEntryList (&TxInfo
->Link
);
894 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
897 Private
->FailedCount
++;
899 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
901 // All the left icmp6 echo request in the list timeout.
903 Private
->Status
= EFI_TIMEOUT
;
910 Determine if a IP4 address is Link Local.
912 169.254.1.0 through 169.254.254.255 is link local.
914 @param[in] Address The address to test.
917 @retval FALSE It is not.
920 PingNetIp4IsLinkLocalAddr (
921 IN CONST EFI_IPv4_ADDRESS
*Address
924 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
928 Determine if a IP4 address is unspecified.
930 @param[in] Address The address to test.
933 @retval FALSE It is not.
936 PingNetIp4IsUnspecifiedAddr (
937 IN CONST EFI_IPv4_ADDRESS
*Address
940 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
944 Create a valid IP instance.
946 @param[in] Private The pointer of PING_PRIVATE_DATA.
948 @retval EFI_SUCCESS Create a valid IPx instance successfully.
949 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
950 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
951 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
952 @retval EFI_NOT_FOUND The source address is not found.
955 PingCreateIpInstance (
956 IN PING_PRIVATE_DATA
*Private
962 EFI_HANDLE
*HandleBuffer
;
963 BOOLEAN UnspecifiedSrc
;
964 BOOLEAN MediaPresent
;
965 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
967 EFI_IP6_CONFIG_DATA Ip6Config
;
968 EFI_IP4_CONFIG_DATA Ip4Config
;
969 VOID
*IpXInterfaceInfo
;
971 EFI_IPv6_ADDRESS
*Addr
;
975 UnspecifiedSrc
= FALSE
;
978 IpXInterfaceInfo
= NULL
;
982 // Locate all the handles with ip6 service binding protocol.
984 Status
= gBS
->LocateHandleBuffer (
986 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
991 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
995 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
996 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
998 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
1000 UnspecifiedSrc
= TRUE
;
1004 // Source address is required when pinging a link-local address.
1006 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1007 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1008 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1009 Status
= EFI_INVALID_PARAMETER
;
1013 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
1014 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1015 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1016 Status
= EFI_INVALID_PARAMETER
;
1022 // For each ip6 protocol, check interface addresses list.
1024 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
1026 IpXInterfaceInfo
= NULL
;
1029 if (UnspecifiedSrc
) {
1033 NetLibDetectMedia (HandleBuffer
[HandleIndex
], &MediaPresent
);
1034 if (!MediaPresent
) {
1042 Status
= gBS
->HandleProtocol (
1043 HandleBuffer
[HandleIndex
],
1044 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1047 if (EFI_ERROR (Status
)) {
1052 // Ip6config protocol and ip6 service binding protocol are installed
1053 // on the same handle.
1055 Status
= gBS
->HandleProtocol (
1056 HandleBuffer
[HandleIndex
],
1057 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4Config2ProtocolGuid
,
1061 if (EFI_ERROR (Status
)) {
1065 // Get the interface information size.
1067 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1068 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1070 Ip6ConfigDataTypeInterfaceInfo
,
1075 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1077 Ip4Config2DataTypeInterfaceInfo
,
1084 // Skip the ones not in current use.
1086 if (Status
== EFI_NOT_STARTED
) {
1090 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1091 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1095 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1097 if (IpXInterfaceInfo
== NULL
) {
1098 Status
= EFI_OUT_OF_RESOURCES
;
1102 // Get the interface info.
1104 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1105 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1107 Ip6ConfigDataTypeInterfaceInfo
,
1112 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1114 Ip4Config2DataTypeInterfaceInfo
,
1120 if (EFI_ERROR (Status
)) {
1121 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1125 // Check whether the source address is one of the interface addresses.
1127 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1128 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1129 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1131 if (UnspecifiedSrc
) {
1132 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1134 // Select the interface automatically.
1136 CopyMem(&Private
->SrcAddress
, Addr
, sizeof(Private
->SrcAddress
));
1139 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1141 // Match a certain interface address.
1147 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1149 // Found a nic handle with right interface address.
1154 if (UnspecifiedSrc
) {
1155 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1156 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1158 // Select the interface automatically.
1162 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1164 // Match a certain interface address.
1170 FreePool (IpXInterfaceInfo
);
1171 IpXInterfaceInfo
= NULL
;
1174 // No exact interface address matched.
1177 if (HandleIndex
== HandleNum
) {
1178 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1179 Status
= EFI_NOT_FOUND
;
1183 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1185 ASSERT (EfiSb
!= NULL
);
1186 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1188 if (EFI_ERROR (Status
)) {
1191 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1192 Status
= gBS
->OpenProtocol (
1193 Private
->IpChildHandle
,
1194 &gEfiIp6ProtocolGuid
,
1195 &Private
->IpProtocol
,
1197 Private
->IpChildHandle
,
1198 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1200 if (EFI_ERROR (Status
)) {
1205 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1208 // Configure the ip6 instance for icmp6 packet exchange.
1210 Ip6Config
.DefaultProtocol
= 58;
1211 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1212 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1213 Ip6Config
.AcceptPromiscuous
= FALSE
;
1214 Ip6Config
.TrafficClass
= 0;
1215 Ip6Config
.HopLimit
= 128;
1216 Ip6Config
.FlowLabel
= 0;
1217 Ip6Config
.ReceiveTimeout
= 0;
1218 Ip6Config
.TransmitTimeout
= 0;
1220 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1221 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1223 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1225 if (EFI_ERROR (Status
)) {
1226 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1230 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1231 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1232 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1233 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1235 Status
= gBS
->OpenProtocol (
1236 Private
->IpChildHandle
,
1237 &gEfiIp4ProtocolGuid
,
1238 &Private
->IpProtocol
,
1240 Private
->IpChildHandle
,
1241 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1243 if (EFI_ERROR (Status
)) {
1248 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1251 // Configure the ip4 instance for icmp4 packet exchange.
1253 Ip4Config
.DefaultProtocol
= 1;
1254 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1255 Ip4Config
.AcceptBroadcast
= FALSE
;
1256 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1257 Ip4Config
.AcceptPromiscuous
= FALSE
;
1258 Ip4Config
.DoNotFragment
= FALSE
;
1259 Ip4Config
.RawData
= FALSE
;
1260 Ip4Config
.ReceiveTimeout
= 0;
1261 Ip4Config
.TransmitTimeout
= 0;
1262 Ip4Config
.UseDefaultAddress
= TRUE
;
1263 Ip4Config
.TimeToLive
= 128;
1264 Ip4Config
.TypeOfService
= 0;
1266 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1268 if (EFI_ERROR (Status
)) {
1269 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1273 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1274 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1275 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1276 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1279 if (HandleBuffer
!= NULL
) {
1280 FreePool (HandleBuffer
);
1286 if (HandleBuffer
!= NULL
) {
1287 FreePool (HandleBuffer
);
1290 if (IpXInterfaceInfo
!= NULL
) {
1291 FreePool (IpXInterfaceInfo
);
1294 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1295 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1302 Destroy the IP instance.
1304 @param[in] Private The pointer of PING_PRIVATE_DATA.
1308 Ping6DestroyIp6Instance (
1309 IN PING_PRIVATE_DATA
*Private
1313 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1315 gBS
->CloseProtocol (
1316 Private
->IpChildHandle
,
1317 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1319 Private
->IpChildHandle
1322 Status
= gBS
->HandleProtocol (
1324 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1328 if (!EFI_ERROR(Status
)) {
1329 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1337 @param[in] SendNumber The send request count.
1338 @param[in] BufferSize The send buffer size.
1339 @param[in] SrcAddress The source address.
1340 @param[in] DstAddress The destination address.
1341 @param[in] IpChoice The choice between IPv4 and IPv6.
1343 @retval SHELL_SUCCESS The ping processed successfullly.
1344 @retval others The ping processed unsuccessfully.
1348 IN UINT32 SendNumber
,
1349 IN UINT32 BufferSize
,
1350 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1351 IN EFI_IPv6_ADDRESS
*DstAddress
,
1356 PING_PRIVATE_DATA
*Private
;
1357 PING_ICMPX_TX_INFO
*TxInfo
;
1359 LIST_ENTRY
*NextEntry
;
1360 SHELL_STATUS ShellStatus
;
1362 ShellStatus
= SHELL_SUCCESS
;
1363 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1365 if (Private
== NULL
) {
1366 return (SHELL_OUT_OF_RESOURCES
);
1369 Private
->IpChoice
= IpChoice
;
1370 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1371 Private
->SendNum
= SendNumber
;
1372 Private
->BufferSize
= BufferSize
;
1373 Private
->RttMin
= ~((UINT64
)(0x0));
1374 Private
->Status
= EFI_NOT_READY
;
1376 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1377 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1379 InitializeListHead (&Private
->TxList
);
1382 // Open and configure a ip instance for us.
1384 Status
= PingCreateIpInstance (Private
);
1386 if (EFI_ERROR (Status
)) {
1387 ShellStatus
= SHELL_ACCESS_DENIED
;
1391 // Print the command line itself.
1393 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1395 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1397 Status
= Ping6ReceiveEchoReply (Private
);
1399 if (EFI_ERROR (Status
)) {
1400 ShellStatus
= SHELL_ACCESS_DENIED
;
1404 // Create and start timer to send icmp6 echo request packet per second.
1406 Status
= gBS
->CreateEvent (
1407 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1409 Ping6OnTimerRoutine
,
1414 if (EFI_ERROR (Status
)) {
1415 ShellStatus
= SHELL_ACCESS_DENIED
;
1420 // Start a timer to calculate the RTT.
1422 Status
= PingInitRttTimer (Private
);
1423 if (EFI_ERROR (Status
)) {
1424 ShellStatus
= SHELL_ACCESS_DENIED
;
1429 // Create a ipv6 token to send the first icmp6 echo request packet.
1431 Status
= PingSendEchoRequest (Private
);
1433 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1435 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1436 ShellStatus
= SHELL_ACCESS_DENIED
;
1437 if(Status
== EFI_NOT_FOUND
) {
1438 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1439 } else if (Status
== RETURN_NO_MAPPING
) {
1440 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1442 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1448 Status
= gBS
->SetTimer (
1454 if (EFI_ERROR (Status
)) {
1455 ShellStatus
= SHELL_ACCESS_DENIED
;
1459 // Control the ping6 process by two factors:
1461 // 2. Private->Status
1462 // 2.1. success means all icmp6 echo request packets get reply packets.
1463 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1464 // 2.3. noready means ping6 process is on-the-go.
1466 while (Private
->Status
== EFI_NOT_READY
) {
1467 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1468 if (ShellGetExecutionBreakFlag()) {
1469 Private
->Status
= EFI_ABORTED
;
1476 // Display the statistics in all.
1478 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1480 if (Private
->TxCount
!= 0) {
1485 STRING_TOKEN (STR_PING_STAT
),
1486 gShellNetwork1HiiHandle
,
1488 (Private
->RxCount
- Private
->FailedCount
),
1489 (100 - ((100 * (Private
->RxCount
- Private
->FailedCount
)) / Private
->TxCount
)),
1494 if (Private
->RxCount
> Private
->FailedCount
) {
1499 STRING_TOKEN (STR_PING_RTT
),
1500 gShellNetwork1HiiHandle
,
1502 Private
->RttMin
+ Private
->TimerPeriod
,
1504 Private
->RttMax
+ Private
->TimerPeriod
,
1505 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
),
1506 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
) + Private
->TimerPeriod
1512 if (Private
!= NULL
) {
1514 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1515 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1517 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1518 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1521 RemoveEntryList (&TxInfo
->Link
);
1522 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1525 PingFreeRttTimer (Private
);
1527 if (Private
->Timer
!= NULL
) {
1528 gBS
->CloseEvent (Private
->Timer
);
1531 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1532 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1535 if (Private
->RxToken
.Event
!= NULL
) {
1536 gBS
->CloseEvent (Private
->RxToken
.Event
);
1539 if (Private
->IpChildHandle
!= NULL
) {
1540 Ping6DestroyIp6Instance (Private
);
1550 Function for 'ping' command.
1552 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1553 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1555 @retval SHELL_SUCCESS The ping processed successfullly.
1556 @retval others The ping processed unsuccessfully.
1561 ShellCommandRunPing (
1562 IN EFI_HANDLE ImageHandle
,
1563 IN EFI_SYSTEM_TABLE
*SystemTable
1567 SHELL_STATUS ShellStatus
;
1568 EFI_IPv6_ADDRESS DstAddress
;
1569 EFI_IPv6_ADDRESS SrcAddress
;
1572 LIST_ENTRY
*ParamPackage
;
1573 CONST CHAR16
*ValueStr
;
1574 UINTN NonOptionCount
;
1576 CHAR16
*ProblemParam
;
1579 // we use IPv6 buffers to hold items...
1580 // make sure this is enough space!
1582 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1583 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1585 IpChoice
= PING_IP_CHOICE_IP4
;
1587 ShellStatus
= SHELL_SUCCESS
;
1588 ProblemParam
= NULL
;
1590 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1591 if (EFI_ERROR(Status
)) {
1592 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1593 ShellStatus
= SHELL_INVALID_PARAMETER
;
1597 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1598 IpChoice
= PING_IP_CHOICE_IP6
;
1602 // Parse the parameter of count number.
1604 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1605 if (ValueStr
!= NULL
) {
1606 SendNumber
= ShellStrToUintn (ValueStr
);
1609 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1611 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1612 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1613 ShellStatus
= SHELL_INVALID_PARAMETER
;
1617 SendNumber
= DEFAULT_SEND_COUNT
;
1620 // Parse the parameter of buffer size.
1622 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1623 if (ValueStr
!= NULL
) {
1624 BufferSize
= ShellStrToUintn (ValueStr
);
1627 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1629 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1630 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1631 ShellStatus
= SHELL_INVALID_PARAMETER
;
1635 BufferSize
= DEFAULT_BUFFER_SIZE
;
1638 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1639 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1642 // Parse the parameter of source ip address.
1644 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1645 if (ValueStr
== NULL
) {
1646 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1649 if (ValueStr
!= NULL
) {
1650 mSrcString
= ValueStr
;
1651 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1652 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1654 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1656 if (EFI_ERROR (Status
)) {
1657 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1658 ShellStatus
= SHELL_INVALID_PARAMETER
;
1663 // Parse the parameter of destination ip address.
1665 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1666 if (NonOptionCount
< 2) {
1667 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1668 ShellStatus
= SHELL_INVALID_PARAMETER
;
1671 if (NonOptionCount
> 2) {
1672 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1673 ShellStatus
= SHELL_INVALID_PARAMETER
;
1676 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1677 if (ValueStr
!= NULL
) {
1678 mDstString
= ValueStr
;
1679 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1680 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1682 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1684 if (EFI_ERROR (Status
)) {
1685 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1686 ShellStatus
= SHELL_INVALID_PARAMETER
;
1692 // Enter into ping process.
1694 ShellStatus
= ShellPing (
1703 ShellCommandLineFreeVarList (ParamPackage
);