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
;
266 Status
= gBS
->CreateEvent (
267 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
273 if (EFI_ERROR (Status
)) {
277 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
278 Status
= gBS
->SetTimer (
283 if (EFI_ERROR (Status
)) {
284 gBS
->CloseEvent (TimerEvent
);
288 while (RttTimerTick
< 10) {
289 gBS
->Stall (STALL_1_MILLI_SECOND
);
293 gBS
->RestoreTPL (OldTpl
);
295 gBS
->SetTimer (TimerEvent
, TimerCancel
, 0);
296 gBS
->CloseEvent (TimerEvent
);
298 return StallCounter
/ RttTimerTick
;
302 Initialize the timer event for RTT (round trip time).
304 @param[in] Private The pointer to PING_PRIVATE_DATA.
306 @retval EFI_SUCCESS RTT timer is started.
307 @retval Others Failed to start the RTT timer.
312 PING_PRIVATE_DATA
*Private
317 Private
->TimerPeriod
= GetTimerPeriod ();
318 if (Private
->TimerPeriod
== 0) {
322 Private
->RttTimerTick
= 0;
323 Status
= gBS
->CreateEvent (
324 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
327 &Private
->RttTimerTick
,
330 if (EFI_ERROR (Status
)) {
334 Status
= gBS
->SetTimer (
339 if (EFI_ERROR (Status
)) {
340 gBS
->CloseEvent (Private
->RttTimer
);
348 Free RTT timer event resource.
350 @param[in] Private The pointer to PING_PRIVATE_DATA.
355 PING_PRIVATE_DATA
*Private
358 if (Private
->RttTimer
!= NULL
) {
359 gBS
->SetTimer (Private
->RttTimer
, TimerCancel
, 0);
360 gBS
->CloseEvent (Private
->RttTimer
);
365 Read the current time.
367 @param[in] Private The pointer to PING_PRIVATE_DATA.
369 @retval the current tick value.
373 PING_PRIVATE_DATA
*Private
376 return Private
->RttTimerTick
;
380 Calculate a duration in ms.
382 @param[in] Private The pointer to PING_PRIVATE_DATA.
383 @param[in] Begin The start point of time.
384 @param[in] End The end point of time.
386 @return The duration in ms.
387 @retval 0 The parameters were not valid.
391 PING_PRIVATE_DATA
*Private
,
400 return (End
- Begin
) * Private
->TimerPeriod
;
404 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
406 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
407 @param[in] IpChoice Whether the token is IPv4 or IPv6
411 IN PING_ICMPX_TX_INFO
*TxInfo
,
415 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
416 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
417 EFI_IP6_FRAGMENT_DATA
*FragData
;
420 if (TxInfo
== NULL
) {
424 if (TxInfo
->Token
!= NULL
) {
425 if (TxInfo
->Token
->Event
!= NULL
) {
426 gBS
->CloseEvent (TxInfo
->Token
->Event
);
429 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
430 if (IpChoice
== PING_IP_CHOICE_IP6
) {
431 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
433 if (Ip6TxData
->OverrideData
!= NULL
) {
434 FreePool (Ip6TxData
->OverrideData
);
437 if (Ip6TxData
->ExtHdrs
!= NULL
) {
438 FreePool (Ip6TxData
->ExtHdrs
);
441 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
442 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
443 if (FragData
!= NULL
) {
448 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
450 if (Ip4TxData
->OverrideData
!= NULL
) {
451 FreePool (Ip4TxData
->OverrideData
);
454 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
455 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
456 if (FragData
!= NULL
) {
463 FreePool (TxInfo
->Token
);
470 Match the request, and reply with SequenceNum/TimeStamp.
472 @param[in] Private The pointer to PING_PRIVATE_DATA.
473 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
475 @retval EFI_SUCCESS The match is successful.
476 @retval EFI_NOT_FOUND The reply can't be matched with any request.
480 Ping6MatchEchoReply (
481 IN PING_PRIVATE_DATA
*Private
,
482 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
485 PING_ICMPX_TX_INFO
*TxInfo
;
487 LIST_ENTRY
*NextEntry
;
489 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
490 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
492 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
494 RemoveEntryList (&TxInfo
->Link
);
495 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
500 return EFI_NOT_FOUND
;
504 The original intention is to send a request.
505 Currently, the application retransmits an icmp6 echo request packet
506 per second in sendnumber times that is specified by the user.
507 Because nothing can be done here, all things move to the timer rountine.
509 @param[in] Event A EFI_EVENT type event.
510 @param[in] Context The pointer to Context.
515 Ping6OnEchoRequestSent (
523 receive reply, match and print reply infomation.
525 @param[in] Event A EFI_EVENT type event.
526 @param[in] Context The pointer to context.
531 Ping6OnEchoReplyReceived (
537 PING_PRIVATE_DATA
*Private
;
538 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
542 Private
= (PING_PRIVATE_DATA
*)Context
;
544 if ((Private
== NULL
) || (Private
->Status
== EFI_ABORTED
) || (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
)) {
548 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
552 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
553 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
554 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
555 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
559 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
560 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
))
565 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
569 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
570 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
571 if (!IP4_IS_MULTICAST (EFI_IP4 (*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
572 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
))
577 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
582 if (PayLoad
!= Private
->BufferSize
) {
587 // Check whether the reply matches the sent request before.
589 Status
= Ping6MatchEchoReply (Private
, Reply
);
590 if (EFI_ERROR (Status
)) {
595 // Display statistics on this icmp6 echo reply packet.
597 Rtt
= CalculateTick (Private
, Reply
->TimeStamp
, ReadTime (Private
));
599 Private
->RttSum
+= Rtt
;
600 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
601 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
607 STRING_TOKEN (STR_PING_REPLY_INFO
),
608 gShellNetwork1HiiHandle
,
612 Private
->IpChoice
== PING_IP_CHOICE_IP6
? ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
: 0,
614 Rtt
+ Private
->TimerPeriod
620 // Recycle the packet before reusing RxToken
622 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
);
624 if (Private
->RxCount
< Private
->SendNum
) {
626 // Continue to receive icmp echo reply packets.
628 Private
->RxToken
.Status
= EFI_ABORTED
;
630 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
632 if (EFI_ERROR (Status
)) {
633 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
634 Private
->Status
= EFI_ABORTED
;
638 // All reply have already been received from the dest host.
640 Private
->Status
= EFI_SUCCESS
;
645 Create a PING_IPX_COMPLETION_TOKEN.
647 @param[in] Private The pointer of PING_PRIVATE_DATA.
648 @param[in] TimeStamp The TimeStamp of request.
649 @param[in] SequenceNum The SequenceNum of request.
651 @return The pointer of PING_IPX_COMPLETION_TOKEN.
654 PING_IPX_COMPLETION_TOKEN
*
656 IN PING_PRIVATE_DATA
*Private
,
658 IN UINT16 SequenceNum
662 PING_IPX_COMPLETION_TOKEN
*Token
;
664 ICMPX_ECHO_REQUEST_REPLY
*Request
;
668 Request
= AllocateZeroPool (Private
->BufferSize
);
669 if (Request
== NULL
) {
673 TxData
= AllocateZeroPool (Private
->IpChoice
== PING_IP_CHOICE_IP6
? sizeof (EFI_IP6_TRANSMIT_DATA
) : sizeof (EFI_IP4_TRANSMIT_DATA
));
674 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
));
726 Token
->Status
= EFI_ABORTED
;
727 Token
->Packet
.TxData
= TxData
;
729 Status
= gBS
->CreateEvent (
732 Ping6OnEchoRequestSent
,
737 if (EFI_ERROR (Status
)) {
748 Transmit the PING_IPX_COMPLETION_TOKEN.
750 @param[in] Private The pointer of PING_PRIVATE_DATA.
752 @retval EFI_SUCCESS Transmitted successfully.
753 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
754 @retval others Transmitted unsuccessfully.
758 PingSendEchoRequest (
759 IN PING_PRIVATE_DATA
*Private
763 PING_ICMPX_TX_INFO
*TxInfo
;
765 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
767 if (TxInfo
== NULL
) {
768 return EFI_OUT_OF_RESOURCES
;
771 TxInfo
->TimeStamp
= ReadTime (Private
);
772 TxInfo
->SequenceNum
= (UINT16
)(Private
->TxCount
+ 1);
773 TxInfo
->Token
= PingGenerateToken (
779 if (TxInfo
->Token
== NULL
) {
780 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
781 return EFI_OUT_OF_RESOURCES
;
784 ASSERT (Private
->ProtocolPointers
.Transmit
!= NULL
);
786 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
788 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
790 if (EFI_ERROR (Status
)) {
791 RemoveEntryList (&TxInfo
->Link
);
792 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
802 Place a completion token into the receive packet queue to receive the echo reply.
804 @param[in] Private The pointer of PING_PRIVATE_DATA.
806 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
807 @retval others Put the token into the receive packet queue unsuccessfully.
811 Ping6ReceiveEchoReply (
812 IN PING_PRIVATE_DATA
*Private
817 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
819 Status
= gBS
->CreateEvent (
822 Ping6OnEchoReplyReceived
,
824 &Private
->RxToken
.Event
827 if (EFI_ERROR (Status
)) {
831 Private
->RxToken
.Status
= EFI_NOT_READY
;
833 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
834 if (EFI_ERROR (Status
)) {
835 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_RECEIVE
), gShellNetwork1HiiHandle
, Status
);
842 Remove the timeout request from the list.
844 @param[in] Event A EFI_EVENT type event.
845 @param[in] Context The pointer to Context.
850 Ping6OnTimerRoutine (
856 PING_PRIVATE_DATA
*Private
;
857 PING_ICMPX_TX_INFO
*TxInfo
;
859 LIST_ENTRY
*NextEntry
;
862 Private
= (PING_PRIVATE_DATA
*)Context
;
863 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
864 Private
->Status
= EFI_NOT_FOUND
;
869 // Retransmit icmp6 echo request packets per second in sendnumber times.
871 if (Private
->TxCount
< Private
->SendNum
) {
872 Status
= PingSendEchoRequest (Private
);
873 if (Private
->TxCount
!= 0) {
874 if (EFI_ERROR (Status
)) {
875 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
881 // Check whether any icmp6 echo request in the list timeout.
883 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
884 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
885 Time
= CalculateTick (Private
, TxInfo
->TimeStamp
, ReadTime (Private
));
888 // Remove the timeout echo request from txlist.
890 if (Time
> DEFAULT_TIMEOUT
) {
891 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
892 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
896 // Remove the timeout icmp6 echo request from list.
898 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
900 RemoveEntryList (&TxInfo
->Link
);
901 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
904 Private
->FailedCount
++;
906 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
908 // All the left icmp6 echo request in the list timeout.
910 Private
->Status
= EFI_TIMEOUT
;
917 Determine if a IP4 address is Link Local.
919 169.254.1.0 through 169.254.254.255 is link local.
921 @param[in] Address The address to test.
924 @retval FALSE It is not.
927 PingNetIp4IsLinkLocalAddr (
928 IN CONST EFI_IPv4_ADDRESS
*Address
931 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
935 Determine if a IP4 address is unspecified.
937 @param[in] Address The address to test.
940 @retval FALSE It is not.
943 PingNetIp4IsUnspecifiedAddr (
944 IN CONST EFI_IPv4_ADDRESS
*Address
947 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
951 Create a valid IP instance.
953 @param[in] Private The pointer of PING_PRIVATE_DATA.
955 @retval EFI_SUCCESS Create a valid IPx instance successfully.
956 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
957 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
958 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
959 @retval EFI_NOT_FOUND The source address is not found.
962 PingCreateIpInstance (
963 IN PING_PRIVATE_DATA
*Private
969 EFI_HANDLE
*HandleBuffer
;
970 BOOLEAN UnspecifiedSrc
;
971 EFI_STATUS MediaStatus
;
972 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
974 EFI_IP6_CONFIG_DATA Ip6Config
;
975 EFI_IP4_CONFIG_DATA Ip4Config
;
976 VOID
*IpXInterfaceInfo
;
978 EFI_IPv6_ADDRESS
*Addr
;
982 UnspecifiedSrc
= FALSE
;
983 MediaStatus
= EFI_SUCCESS
;
985 IpXInterfaceInfo
= NULL
;
989 // Locate all the handles with ip6 service binding protocol.
991 Status
= gBS
->LocateHandleBuffer (
993 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ServiceBindingProtocolGuid
: &gEfiIp4ServiceBindingProtocolGuid
,
998 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
1002 if ((Private
->IpChoice
== PING_IP_CHOICE_IP6
) ? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
1003 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
))
1006 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
1008 UnspecifiedSrc
= TRUE
;
1012 // Source address is required when pinging a link-local address.
1014 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1015 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1016 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1017 Status
= EFI_INVALID_PARAMETER
;
1021 ASSERT (Private
->IpChoice
== PING_IP_CHOICE_IP4
);
1022 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
1023 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
1024 Status
= EFI_INVALID_PARAMETER
;
1030 // For each ip6 protocol, check interface addresses list.
1032 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
1034 IpXInterfaceInfo
= NULL
;
1037 if (UnspecifiedSrc
) {
1041 NetLibDetectMediaWaitTimeout (HandleBuffer
[HandleIndex
], 0, &MediaStatus
);
1042 if (MediaStatus
!= EFI_SUCCESS
) {
1050 Status
= gBS
->HandleProtocol (
1051 HandleBuffer
[HandleIndex
],
1052 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ServiceBindingProtocolGuid
: &gEfiIp4ServiceBindingProtocolGuid
,
1055 if (EFI_ERROR (Status
)) {
1060 // Ip6config protocol and ip6 service binding protocol are installed
1061 // on the same handle.
1063 Status
= gBS
->HandleProtocol (
1064 HandleBuffer
[HandleIndex
],
1065 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ConfigProtocolGuid
: &gEfiIp4Config2ProtocolGuid
,
1069 if (EFI_ERROR (Status
)) {
1074 // Get the interface information size.
1076 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1077 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1079 Ip6ConfigDataTypeInterfaceInfo
,
1084 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1086 Ip4Config2DataTypeInterfaceInfo
,
1093 // Skip the ones not in current use.
1095 if (Status
== EFI_NOT_STARTED
) {
1099 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1100 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1104 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1106 if (IpXInterfaceInfo
== NULL
) {
1107 Status
= EFI_OUT_OF_RESOURCES
;
1112 // Get the interface info.
1114 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1115 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1117 Ip6ConfigDataTypeInterfaceInfo
,
1122 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1124 Ip4Config2DataTypeInterfaceInfo
,
1130 if (EFI_ERROR (Status
)) {
1131 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1136 // Check whether the source address is one of the interface addresses.
1138 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1139 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1140 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1142 if (UnspecifiedSrc
) {
1143 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1145 // Select the interface automatically.
1147 CopyMem (&Private
->SrcAddress
, Addr
, sizeof (Private
->SrcAddress
));
1150 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1152 // Match a certain interface address.
1158 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1160 // Found a nic handle with right interface address.
1165 if (UnspecifiedSrc
) {
1166 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1167 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
))
1170 // Select the interface automatically.
1174 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1176 // Match a certain interface address.
1182 FreePool (IpXInterfaceInfo
);
1183 IpXInterfaceInfo
= NULL
;
1187 // No exact interface address matched.
1190 if (HandleIndex
== HandleNum
) {
1191 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1192 Status
= EFI_NOT_FOUND
;
1196 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1198 ASSERT (EfiSb
!= NULL
);
1199 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1201 if (EFI_ERROR (Status
)) {
1205 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1206 Status
= gBS
->OpenProtocol (
1207 Private
->IpChildHandle
,
1208 &gEfiIp6ProtocolGuid
,
1209 &Private
->IpProtocol
,
1211 Private
->IpChildHandle
,
1212 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1214 if (EFI_ERROR (Status
)) {
1218 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1221 // Configure the ip6 instance for icmp6 packet exchange.
1223 Ip6Config
.DefaultProtocol
= 58;
1224 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1225 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1226 Ip6Config
.AcceptPromiscuous
= FALSE
;
1227 Ip6Config
.TrafficClass
= 0;
1228 Ip6Config
.HopLimit
= 128;
1229 Ip6Config
.FlowLabel
= 0;
1230 Ip6Config
.ReceiveTimeout
= 0;
1231 Ip6Config
.TransmitTimeout
= 0;
1233 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1234 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1236 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1238 if (EFI_ERROR (Status
)) {
1239 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1243 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1244 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1245 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1246 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1248 Status
= gBS
->OpenProtocol (
1249 Private
->IpChildHandle
,
1250 &gEfiIp4ProtocolGuid
,
1251 &Private
->IpProtocol
,
1253 Private
->IpChildHandle
,
1254 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1256 if (EFI_ERROR (Status
)) {
1260 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1263 // Configure the ip4 instance for icmp4 packet exchange.
1265 Ip4Config
.DefaultProtocol
= 1;
1266 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1267 Ip4Config
.AcceptBroadcast
= FALSE
;
1268 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1269 Ip4Config
.AcceptPromiscuous
= FALSE
;
1270 Ip4Config
.DoNotFragment
= FALSE
;
1271 Ip4Config
.RawData
= FALSE
;
1272 Ip4Config
.ReceiveTimeout
= 0;
1273 Ip4Config
.TransmitTimeout
= 0;
1274 Ip4Config
.UseDefaultAddress
= TRUE
;
1275 Ip4Config
.TimeToLive
= 128;
1276 Ip4Config
.TypeOfService
= 0;
1278 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1280 if (EFI_ERROR (Status
)) {
1281 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1285 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1286 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1287 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1288 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1291 if (HandleBuffer
!= NULL
) {
1292 FreePool (HandleBuffer
);
1298 if (HandleBuffer
!= NULL
) {
1299 FreePool (HandleBuffer
);
1302 if (IpXInterfaceInfo
!= NULL
) {
1303 FreePool (IpXInterfaceInfo
);
1306 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1307 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1314 Destroy the IP instance.
1316 @param[in] Private The pointer of PING_PRIVATE_DATA.
1320 Ping6DestroyIp6Instance (
1321 IN PING_PRIVATE_DATA
*Private
1325 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1327 gBS
->CloseProtocol (
1328 Private
->IpChildHandle
,
1329 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ProtocolGuid
: &gEfiIp4ProtocolGuid
,
1331 Private
->IpChildHandle
1334 Status
= gBS
->HandleProtocol (
1336 Private
->IpChoice
== PING_IP_CHOICE_IP6
? &gEfiIp6ServiceBindingProtocolGuid
: &gEfiIp4ServiceBindingProtocolGuid
,
1340 if (!EFI_ERROR (Status
)) {
1341 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1348 @param[in] SendNumber The send request count.
1349 @param[in] BufferSize The send buffer size.
1350 @param[in] SrcAddress The source address.
1351 @param[in] DstAddress The destination address.
1352 @param[in] IpChoice The choice between IPv4 and IPv6.
1354 @retval SHELL_SUCCESS The ping processed successfullly.
1355 @retval others The ping processed unsuccessfully.
1359 IN UINT32 SendNumber
,
1360 IN UINT32 BufferSize
,
1361 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1362 IN EFI_IPv6_ADDRESS
*DstAddress
,
1367 PING_PRIVATE_DATA
*Private
;
1368 PING_ICMPX_TX_INFO
*TxInfo
;
1370 LIST_ENTRY
*NextEntry
;
1371 SHELL_STATUS ShellStatus
;
1373 ShellStatus
= SHELL_SUCCESS
;
1374 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1376 if (Private
== NULL
) {
1377 return (SHELL_OUT_OF_RESOURCES
);
1380 Private
->IpChoice
= IpChoice
;
1381 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1382 Private
->SendNum
= SendNumber
;
1383 Private
->BufferSize
= BufferSize
;
1384 Private
->RttMin
= ~((UINT64
)(0x0));
1385 Private
->Status
= EFI_NOT_READY
;
1387 CopyMem (&Private
->SrcAddress
, SrcAddress
, sizeof (Private
->SrcAddress
));
1388 CopyMem (&Private
->DstAddress
, DstAddress
, sizeof (Private
->DstAddress
));
1390 InitializeListHead (&Private
->TxList
);
1393 // Open and configure a ip instance for us.
1395 Status
= PingCreateIpInstance (Private
);
1397 if (EFI_ERROR (Status
)) {
1398 ShellStatus
= SHELL_ACCESS_DENIED
;
1403 // Print the command line itself.
1405 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1407 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1409 Status
= Ping6ReceiveEchoReply (Private
);
1411 if (EFI_ERROR (Status
)) {
1412 ShellStatus
= SHELL_ACCESS_DENIED
;
1417 // Create and start timer to send icmp6 echo request packet per second.
1419 Status
= gBS
->CreateEvent (
1420 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1422 Ping6OnTimerRoutine
,
1427 if (EFI_ERROR (Status
)) {
1428 ShellStatus
= SHELL_ACCESS_DENIED
;
1433 // Start a timer to calculate the RTT.
1435 Status
= PingInitRttTimer (Private
);
1436 if (EFI_ERROR (Status
)) {
1437 ShellStatus
= SHELL_ACCESS_DENIED
;
1442 // Create a ipv6 token to send the first icmp6 echo request packet.
1444 Status
= PingSendEchoRequest (Private
);
1446 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1448 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1449 ShellStatus
= SHELL_ACCESS_DENIED
;
1450 if (Status
== EFI_NOT_FOUND
) {
1451 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1452 } else if (Status
== RETURN_NO_MAPPING
) {
1453 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1455 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1461 Status
= gBS
->SetTimer (
1467 if (EFI_ERROR (Status
)) {
1468 ShellStatus
= SHELL_ACCESS_DENIED
;
1473 // Control the ping6 process by two factors:
1475 // 2. Private->Status
1476 // 2.1. success means all icmp6 echo request packets get reply packets.
1477 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1478 // 2.3. noready means ping6 process is on-the-go.
1480 while (Private
->Status
== EFI_NOT_READY
) {
1481 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1482 if (ShellGetExecutionBreakFlag ()) {
1483 Private
->Status
= EFI_ABORTED
;
1490 // Display the statistics in all.
1492 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1494 if (Private
->TxCount
!= 0) {
1499 STRING_TOKEN (STR_PING_STAT
),
1500 gShellNetwork1HiiHandle
,
1502 (Private
->RxCount
- Private
->FailedCount
),
1503 (100 - ((100 * (Private
->RxCount
- Private
->FailedCount
)) / Private
->TxCount
)),
1508 if (Private
->RxCount
> Private
->FailedCount
) {
1513 STRING_TOKEN (STR_PING_RTT
),
1514 gShellNetwork1HiiHandle
,
1516 Private
->RttMin
+ Private
->TimerPeriod
,
1518 Private
->RttMax
+ Private
->TimerPeriod
,
1519 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
),
1520 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
) + Private
->TimerPeriod
1526 if (Private
!= NULL
) {
1527 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1528 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1530 if ((Private
->IpProtocol
!= NULL
) && (Private
->ProtocolPointers
.Cancel
!= NULL
)) {
1531 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1534 RemoveEntryList (&TxInfo
->Link
);
1535 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1538 PingFreeRttTimer (Private
);
1540 if (Private
->Timer
!= NULL
) {
1541 gBS
->CloseEvent (Private
->Timer
);
1544 if ((Private
->IpProtocol
!= NULL
) && (Private
->ProtocolPointers
.Cancel
!= NULL
)) {
1545 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1548 if (Private
->RxToken
.Event
!= NULL
) {
1549 gBS
->CloseEvent (Private
->RxToken
.Event
);
1552 if (Private
->IpChildHandle
!= NULL
) {
1553 Ping6DestroyIp6Instance (Private
);
1563 Function for 'ping' command.
1565 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1566 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1568 @retval SHELL_SUCCESS The ping processed successfullly.
1569 @retval others The ping processed unsuccessfully.
1574 ShellCommandRunPing (
1575 IN EFI_HANDLE ImageHandle
,
1576 IN EFI_SYSTEM_TABLE
*SystemTable
1580 SHELL_STATUS ShellStatus
;
1581 EFI_IPv6_ADDRESS DstAddress
;
1582 EFI_IPv6_ADDRESS SrcAddress
;
1585 LIST_ENTRY
*ParamPackage
;
1586 CONST CHAR16
*ValueStr
;
1587 UINTN NonOptionCount
;
1589 CHAR16
*ProblemParam
;
1592 // we use IPv6 buffers to hold items...
1593 // make sure this is enough space!
1595 ASSERT (sizeof (EFI_IPv4_ADDRESS
) <= sizeof (EFI_IPv6_ADDRESS
));
1596 ASSERT (sizeof (EFI_IP4_COMPLETION_TOKEN
) <= sizeof (EFI_IP6_COMPLETION_TOKEN
));
1598 IpChoice
= PING_IP_CHOICE_IP4
;
1600 ShellStatus
= SHELL_SUCCESS
;
1601 ProblemParam
= NULL
;
1603 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1604 if (EFI_ERROR (Status
)) {
1605 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1606 ShellStatus
= SHELL_INVALID_PARAMETER
;
1610 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1611 IpChoice
= PING_IP_CHOICE_IP6
;
1615 // Parse the parameter of count number.
1617 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1618 if (ValueStr
!= NULL
) {
1619 SendNumber
= ShellStrToUintn (ValueStr
);
1622 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1624 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1625 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1626 ShellStatus
= SHELL_INVALID_PARAMETER
;
1630 SendNumber
= DEFAULT_SEND_COUNT
;
1634 // Parse the parameter of buffer size.
1636 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1637 if (ValueStr
!= NULL
) {
1638 BufferSize
= ShellStrToUintn (ValueStr
);
1641 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1643 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1644 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1645 ShellStatus
= SHELL_INVALID_PARAMETER
;
1649 BufferSize
= DEFAULT_BUFFER_SIZE
;
1652 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1653 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1656 // Parse the parameter of source ip address.
1658 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1659 if (ValueStr
== NULL
) {
1660 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1663 if (ValueStr
!= NULL
) {
1664 mSrcString
= ValueStr
;
1665 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1666 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1668 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1671 if (EFI_ERROR (Status
)) {
1672 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1673 ShellStatus
= SHELL_INVALID_PARAMETER
;
1679 // Parse the parameter of destination ip address.
1681 NonOptionCount
= ShellCommandLineGetCount (ParamPackage
);
1682 if (NonOptionCount
< 2) {
1683 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1684 ShellStatus
= SHELL_INVALID_PARAMETER
;
1688 if (NonOptionCount
> 2) {
1689 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1690 ShellStatus
= SHELL_INVALID_PARAMETER
;
1694 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1695 if (ValueStr
!= NULL
) {
1696 mDstString
= ValueStr
;
1697 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1698 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1700 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1703 if (EFI_ERROR (Status
)) {
1704 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1705 ShellStatus
= SHELL_INVALID_PARAMETER
;
1711 // Enter into ping process.
1713 ShellStatus
= ShellPing (
1722 ShellCommandLineFreeVarList (ParamPackage
);