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>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php.
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "UefiShellNetwork1CommandsLib.h"
19 #define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))
21 UINT64 mCurrentTick
= 0;
24 // Function templates to match the IPv4 and IPv6 commands that we use.
28 (EFIAPI
*PING_IPX_POLL
)(
34 (EFIAPI
*PING_IPX_TRANSMIT
)(
41 (EFIAPI
*PING_IPX_RECEIVE
)(
48 (EFIAPI
*PING_IPX_CANCEL
)(
50 IN VOID
*Token OPTIONAL
54 /// A set of pointers to either IPv6 or IPv4 functions.
55 /// Unknown which one to the ping command.
58 PING_IPX_TRANSMIT Transmit
;
59 PING_IPX_RECEIVE Receive
;
60 PING_IPX_CANCEL Cancel
;
71 // PING_IPX_COMPLETION_TOKEN
72 // structures are used for both transmit and receive operations.
73 // This version is IP-unaware.
79 } PING_IPX_COMPLETION_TOKEN
;
82 typedef struct _ICMPX_ECHO_REQUEST_REPLY
{
90 } ICMPX_ECHO_REQUEST_REPLY
;
93 typedef struct _PING_ICMP_TX_INFO
{
97 PING_IPX_COMPLETION_TOKEN
*Token
;
100 #define DEFAULT_TIMEOUT 5000
101 #define MAX_SEND_NUMBER 10000
102 #define MAX_BUFFER_SIZE 32768
103 #define DEFAULT_TIMER_PERIOD 358049
104 #define ONE_SECOND 10000000
105 #define PING_IP_CHOICE_IP4 1
106 #define PING_IP_CHOICE_IP6 2
107 #define DEFAULT_SEND_COUNT 10
108 #define DEFAULT_BUFFER_SIZE 16
109 #define ICMP_V4_ECHO_REQUEST 0x8
110 #define ICMP_V4_ECHO_REPLY 0x0
112 #define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')
113 typedef struct _PING_PRIVATE_DATA
{
115 EFI_HANDLE NicHandle
;
116 EFI_HANDLE IpChildHandle
;
132 PING_IPX_PROTOCOL ProtocolPointers
;
134 UINT8 SrcAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
135 UINT8 DstAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
136 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
159 Packet
= (UINT16
*) Buffer
;
162 Odd
= (UINT8
) (Length
& 1);
164 while ((Length
--) != 0) {
169 Sum
+= *(UINT8
*) Packet
;
172 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
175 // in case above carried
183 Reads and returns the current value of register.
184 In IA64, the register is the Interval Timer Vector (ITV).
185 In X86(IA32/X64), the register is the Time Stamp Counter (TSC)
187 @return The current value of the register.
191 STATIC CONST SHELL_PARAM_ITEM PingParamList
[] = {
219 // Global Variables in Ping command.
221 STATIC CONST CHAR16
*mDstString
;
222 STATIC CONST CHAR16
*mSrcString
;
223 STATIC UINT64 mFrequency
= 0;
224 EFI_CPU_ARCH_PROTOCOL
*gCpu
= NULL
;
227 Read the current time.
229 @retval the current tick value.
240 ASSERT (gCpu
!= NULL
);
242 Status
= gCpu
->GetTimerValue (gCpu
, 0, &mCurrentTick
, &TimerPeriod
);
243 if (EFI_ERROR (Status
)) {
245 // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the
246 // TimerPeriod by ourselves.
248 mCurrentTick
+= 1000000;
256 Get and calculate the frequency in ticks/ms.
257 The result is saved in the global variable mFrequency
259 @retval EFI_SUCCESS Calculated the frequency successfully.
260 @retval Others Failed to calculate the frequency.
273 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &gCpu
);
274 if (EFI_ERROR (Status
)) {
278 Status
= gCpu
->GetTimerValue (gCpu
, 0, &CurrentTick
, &TimerPeriod
);
280 if (EFI_ERROR (Status
)) {
281 TimerPeriod
= DEFAULT_TIMER_PERIOD
;
285 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
286 // So 1e+12 is divided by timer period to produce the freq in ticks/ms.
288 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
294 Calculate a duration in ms.
296 @param[in] Begin The start point of time.
297 @param[in] End The end point of time.
299 @return The duration in ms.
300 @retval 0 The parameters were not valid.
312 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
316 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
318 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
319 @param[in] IpChoice Whether the token is IPv4 or IPv6
324 IN PING_ICMPX_TX_INFO
*TxInfo
,
328 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
329 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
330 EFI_IP6_FRAGMENT_DATA
*FragData
;
333 if (TxInfo
== NULL
) {
337 if (TxInfo
->Token
!= NULL
) {
339 if (TxInfo
->Token
->Event
!= NULL
) {
340 gBS
->CloseEvent (TxInfo
->Token
->Event
);
343 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
344 if (IpChoice
== PING_IP_CHOICE_IP6
) {
345 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
347 if (Ip6TxData
->OverrideData
!= NULL
) {
348 FreePool (Ip6TxData
->OverrideData
);
351 if (Ip6TxData
->ExtHdrs
!= NULL
) {
352 FreePool (Ip6TxData
->ExtHdrs
);
355 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
356 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
357 if (FragData
!= NULL
) {
362 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
364 if (Ip4TxData
->OverrideData
!= NULL
) {
365 FreePool (Ip4TxData
->OverrideData
);
368 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
369 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
370 if (FragData
!= NULL
) {
377 FreePool (TxInfo
->Token
);
384 Match the request, and reply with SequenceNum/TimeStamp.
386 @param[in] Private The pointer to PING_PRIVATE_DATA.
387 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
389 @retval EFI_SUCCESS The match is successful.
390 @retval EFI_NOT_FOUND The reply can't be matched with any request.
395 Ping6MatchEchoReply (
396 IN PING_PRIVATE_DATA
*Private
,
397 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
400 PING_ICMPX_TX_INFO
*TxInfo
;
402 LIST_ENTRY
*NextEntry
;
404 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
405 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
407 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
409 RemoveEntryList (&TxInfo
->Link
);
410 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
415 return EFI_NOT_FOUND
;
419 The original intention is to send a request.
420 Currently, the application retransmits an icmp6 echo request packet
421 per second in sendnumber times that is specified by the user.
422 Because nothing can be done here, all things move to the timer rountine.
424 @param[in] Event A EFI_EVENT type event.
425 @param[in] Context The pointer to Context.
430 Ping6OnEchoRequestSent (
438 receive reply, match and print reply infomation.
440 @param[in] Event A EFI_EVENT type event.
441 @param[in] Context The pointer to context.
446 Ping6OnEchoReplyReceived (
452 PING_PRIVATE_DATA
*Private
;
453 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
458 Private
= (PING_PRIVATE_DATA
*) Context
;
460 if (Private
== NULL
|| Private
->Status
== EFI_ABORTED
|| Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
464 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
468 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
469 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
470 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
471 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
474 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
475 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
)) {
479 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
483 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
484 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
485 if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
486 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
)) {
490 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
496 if (PayLoad
!= Private
->BufferSize
) {
500 // Check whether the reply matches the sent request before.
502 Status
= Ping6MatchEchoReply (Private
, Reply
);
503 if (EFI_ERROR(Status
)) {
507 // Display statistics on this icmp6 echo reply packet.
509 Rtt
= CalculateTick (Reply
->TimeStamp
, ReadTime ());
516 Private
->RttSum
+= Rtt
;
517 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
518 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
524 STRING_TOKEN (STR_PING_REPLY_INFO
),
525 gShellNetwork1HiiHandle
,
529 Private
->IpChoice
== PING_IP_CHOICE_IP6
?((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
:0,
536 if (Private
->RxCount
< Private
->SendNum
) {
538 // Continue to receive icmp echo reply packets.
540 Private
->RxToken
.Status
= EFI_ABORTED
;
542 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
544 if (EFI_ERROR (Status
)) {
545 Private
->Status
= EFI_ABORTED
;
549 // All reply have already been received from the dest host.
551 Private
->Status
= EFI_SUCCESS
;
554 // Singal to recycle the each rxdata here, not at the end of process.
556 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
);
560 Create a PING_IPX_COMPLETION_TOKEN.
562 @param[in] Private The pointer of PING_PRIVATE_DATA.
563 @param[in] TimeStamp The TimeStamp of request.
564 @param[in] SequenceNum The SequenceNum of request.
566 @return The pointer of PING_IPX_COMPLETION_TOKEN.
569 PING_IPX_COMPLETION_TOKEN
*
572 IN PING_PRIVATE_DATA
*Private
,
574 IN UINT16 SequenceNum
578 PING_IPX_COMPLETION_TOKEN
*Token
;
580 ICMPX_ECHO_REQUEST_REPLY
*Request
;
584 Request
= AllocateZeroPool (Private
->BufferSize
);
585 if (Request
== NULL
) {
588 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
589 if (TxData
== NULL
) {
593 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
601 // Assembly echo request packet.
603 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
605 Request
->SequenceNum
= SequenceNum
;
606 Request
->Identifier
= 0;
607 Request
->Checksum
= 0;
610 // Assembly token for transmit.
612 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
613 Request
->TimeStamp
= TimeStamp
;
614 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
615 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
616 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
617 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
618 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
619 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
620 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
622 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
623 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
624 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
625 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
626 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
627 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
628 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
629 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
630 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
631 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
632 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
634 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
635 Request
->TimeStamp
= TimeStamp
;
636 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
637 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
641 Token
->Status
= EFI_ABORTED
;
642 Token
->Packet
.TxData
= TxData
;
644 Status
= gBS
->CreateEvent (
647 Ping6OnEchoRequestSent
,
652 if (EFI_ERROR (Status
)) {
663 Transmit the PING_IPX_COMPLETION_TOKEN.
665 @param[in] Private The pointer of PING_PRIVATE_DATA.
667 @retval EFI_SUCCESS Transmitted successfully.
668 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
669 @retval others Transmitted unsuccessfully.
674 PingSendEchoRequest (
675 IN PING_PRIVATE_DATA
*Private
679 PING_ICMPX_TX_INFO
*TxInfo
;
681 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
683 if (TxInfo
== NULL
) {
684 return EFI_OUT_OF_RESOURCES
;
687 TxInfo
->TimeStamp
= ReadTime ();
688 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
689 TxInfo
->Token
= PingGenerateToken (
695 if (TxInfo
->Token
== NULL
) {
696 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
697 return EFI_OUT_OF_RESOURCES
;
700 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
701 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
703 if (EFI_ERROR (Status
)) {
704 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
708 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
715 Place a completion token into the receive packet queue to receive the echo reply.
717 @param[in] Private The pointer of PING_PRIVATE_DATA.
719 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
720 @retval others Put the token into the receive packet queue unsuccessfully.
725 Ping6ReceiveEchoReply (
726 IN PING_PRIVATE_DATA
*Private
731 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
733 Status
= gBS
->CreateEvent (
736 Ping6OnEchoReplyReceived
,
738 &Private
->RxToken
.Event
741 if (EFI_ERROR (Status
)) {
745 Private
->RxToken
.Status
= EFI_NOT_READY
;
747 return (Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
));
751 Remove the timeout request from the list.
753 @param[in] Event A EFI_EVENT type event.
754 @param[in] Context The pointer to Context.
759 Ping6OnTimerRoutine (
765 PING_PRIVATE_DATA
*Private
;
766 PING_ICMPX_TX_INFO
*TxInfo
;
768 LIST_ENTRY
*NextEntry
;
771 Private
= (PING_PRIVATE_DATA
*) Context
;
772 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
773 Private
->Status
= EFI_NOT_FOUND
;
778 // Retransmit icmp6 echo request packets per second in sendnumber times.
780 if (Private
->TxCount
< Private
->SendNum
) {
782 Status
= PingSendEchoRequest (Private
);
783 if (Private
->TxCount
!= 0){
784 if (EFI_ERROR (Status
)) {
785 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
790 // Check whether any icmp6 echo request in the list timeout.
792 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
793 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
794 Time
= CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
797 // Remove the timeout echo request from txlist.
799 if (Time
> DEFAULT_TIMEOUT
) {
801 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
802 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
805 // Remove the timeout icmp6 echo request from list.
807 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
809 RemoveEntryList (&TxInfo
->Link
);
810 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
812 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
814 // All the left icmp6 echo request in the list timeout.
816 Private
->Status
= EFI_TIMEOUT
;
823 Determine if a IP4 address is Link Local.
825 169.254.1.0 through 169.254.254.255 is link local.
827 @param[in] Address The address to test.
830 @retval FALSE It is not.
834 PingNetIp4IsLinkLocalAddr (
835 IN CONST EFI_IPv4_ADDRESS
*Address
838 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
842 Determine if a IP4 address is unspecified.
844 @param[in] Address The address to test.
847 @retval FALSE It is not.
851 PingNetIp4IsUnspecifiedAddr (
852 IN CONST EFI_IPv4_ADDRESS
*Address
855 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
859 Create a valid IP instance.
861 @param[in] Private The pointer of PING_PRIVATE_DATA.
863 @retval EFI_SUCCESS Create a valid IPx instance successfully.
864 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
865 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
866 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
867 @retval EFI_NOT_FOUND The source address is not found.
871 PingCreateIpInstance (
872 IN PING_PRIVATE_DATA
*Private
878 EFI_HANDLE
*HandleBuffer
;
879 BOOLEAN UnspecifiedSrc
;
880 BOOLEAN MediaPresent
;
881 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
883 EFI_IP6_CONFIG_DATA Ip6Config
;
884 EFI_IP4_CONFIG_DATA Ip4Config
;
885 VOID
*IpXInterfaceInfo
;
887 EFI_IPv6_ADDRESS
*Addr
;
891 UnspecifiedSrc
= FALSE
;
894 IpXInterfaceInfo
= NULL
;
898 // Locate all the handles with ip6 service binding protocol.
900 Status
= gBS
->LocateHandleBuffer (
902 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
907 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
911 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
912 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
914 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
916 UnspecifiedSrc
= TRUE
;
920 // Source address is required when pinging a link-local address.
922 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
923 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
924 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
925 Status
= EFI_INVALID_PARAMETER
;
929 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
930 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
931 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
932 Status
= EFI_INVALID_PARAMETER
;
938 // For each ip6 protocol, check interface addresses list.
940 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
942 IpXInterfaceInfo
= NULL
;
945 if (UnspecifiedSrc
) {
949 NetLibDetectMedia (HandleBuffer
[HandleIndex
], &MediaPresent
);
958 Status
= gBS
->HandleProtocol (
959 HandleBuffer
[HandleIndex
],
960 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
963 if (EFI_ERROR (Status
)) {
968 // Ip6config protocol and ip6 service binding protocol are installed
969 // on the same handle.
971 Status
= gBS
->HandleProtocol (
972 HandleBuffer
[HandleIndex
],
973 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4Config2ProtocolGuid
,
977 if (EFI_ERROR (Status
)) {
981 // Get the interface information size.
983 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
984 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
986 Ip6ConfigDataTypeInterfaceInfo
,
991 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
993 Ip4Config2DataTypeInterfaceInfo
,
1000 // Skip the ones not in current use.
1002 if (Status
== EFI_NOT_STARTED
) {
1006 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1007 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1011 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1013 if (IpXInterfaceInfo
== NULL
) {
1014 Status
= EFI_OUT_OF_RESOURCES
;
1018 // Get the interface info.
1020 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1021 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1023 Ip6ConfigDataTypeInterfaceInfo
,
1028 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1030 Ip4Config2DataTypeInterfaceInfo
,
1036 if (EFI_ERROR (Status
)) {
1037 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1041 // Check whether the source address is one of the interface addresses.
1043 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1044 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1045 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1047 if (UnspecifiedSrc
) {
1048 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1050 // Select the interface automatically.
1052 CopyMem(&Private
->SrcAddress
, Addr
, sizeof(Private
->SrcAddress
));
1055 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1057 // Match a certain interface address.
1063 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1065 // Found a nic handle with right interface address.
1070 if (UnspecifiedSrc
) {
1071 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1072 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1074 // Select the interface automatically.
1078 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1080 // Match a certain interface address.
1086 FreePool (IpXInterfaceInfo
);
1087 IpXInterfaceInfo
= NULL
;
1090 // No exact interface address matched.
1093 if (HandleIndex
== HandleNum
) {
1094 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1095 Status
= EFI_NOT_FOUND
;
1099 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1101 ASSERT (EfiSb
!= NULL
);
1102 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1104 if (EFI_ERROR (Status
)) {
1107 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1108 Status
= gBS
->OpenProtocol (
1109 Private
->IpChildHandle
,
1110 &gEfiIp6ProtocolGuid
,
1111 &Private
->IpProtocol
,
1113 Private
->IpChildHandle
,
1114 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1116 if (EFI_ERROR (Status
)) {
1121 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1124 // Configure the ip6 instance for icmp6 packet exchange.
1126 Ip6Config
.DefaultProtocol
= 58;
1127 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1128 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1129 Ip6Config
.AcceptPromiscuous
= FALSE
;
1130 Ip6Config
.TrafficClass
= 0;
1131 Ip6Config
.HopLimit
= 128;
1132 Ip6Config
.FlowLabel
= 0;
1133 Ip6Config
.ReceiveTimeout
= 0;
1134 Ip6Config
.TransmitTimeout
= 0;
1136 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1137 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1139 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1141 if (EFI_ERROR (Status
)) {
1142 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1146 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1147 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1148 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1149 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1151 Status
= gBS
->OpenProtocol (
1152 Private
->IpChildHandle
,
1153 &gEfiIp4ProtocolGuid
,
1154 &Private
->IpProtocol
,
1156 Private
->IpChildHandle
,
1157 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1159 if (EFI_ERROR (Status
)) {
1164 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1167 // Configure the ip4 instance for icmp4 packet exchange.
1169 Ip4Config
.DefaultProtocol
= 1;
1170 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1171 Ip4Config
.AcceptBroadcast
= FALSE
;
1172 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1173 Ip4Config
.AcceptPromiscuous
= FALSE
;
1174 Ip4Config
.DoNotFragment
= FALSE
;
1175 Ip4Config
.RawData
= FALSE
;
1176 Ip4Config
.ReceiveTimeout
= 0;
1177 Ip4Config
.TransmitTimeout
= 0;
1178 Ip4Config
.UseDefaultAddress
= TRUE
;
1179 Ip4Config
.TimeToLive
= 128;
1180 Ip4Config
.TypeOfService
= 0;
1182 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1184 if (EFI_ERROR (Status
)) {
1185 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1189 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1190 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1191 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1192 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1195 if (HandleBuffer
!= NULL
) {
1196 FreePool (HandleBuffer
);
1202 if (HandleBuffer
!= NULL
) {
1203 FreePool (HandleBuffer
);
1206 if (IpXInterfaceInfo
!= NULL
) {
1207 FreePool (IpXInterfaceInfo
);
1210 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1211 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1218 Destroy the IP instance.
1220 @param[in] Private The pointer of PING_PRIVATE_DATA.
1225 Ping6DestroyIp6Instance (
1226 IN PING_PRIVATE_DATA
*Private
1230 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1232 gBS
->CloseProtocol (
1233 Private
->IpChildHandle
,
1234 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1236 Private
->IpChildHandle
1239 Status
= gBS
->HandleProtocol (
1241 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1245 if (!EFI_ERROR(Status
)) {
1246 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1253 @param[in] SendNumber The send request count.
1254 @param[in] BufferSize The send buffer size.
1255 @param[in] SrcAddress The source address.
1256 @param[in] DstAddress The destination address.
1257 @param[in] IpChoice The choice between IPv4 and IPv6.
1259 @retval SHELL_SUCCESS The ping processed successfullly.
1260 @retval others The ping processed unsuccessfully.
1265 IN UINT32 SendNumber
,
1266 IN UINT32 BufferSize
,
1267 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1268 IN EFI_IPv6_ADDRESS
*DstAddress
,
1273 PING_PRIVATE_DATA
*Private
;
1274 PING_ICMPX_TX_INFO
*TxInfo
;
1276 LIST_ENTRY
*NextEntry
;
1277 SHELL_STATUS ShellStatus
;
1279 ShellStatus
= SHELL_SUCCESS
;
1280 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1282 if (Private
== NULL
) {
1283 return (SHELL_OUT_OF_RESOURCES
);
1286 Private
->IpChoice
= IpChoice
;
1287 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1288 Private
->SendNum
= SendNumber
;
1289 Private
->BufferSize
= BufferSize
;
1290 Private
->RttMin
= ~((UINT64
)(0x0));
1291 Private
->Status
= EFI_NOT_READY
;
1293 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1294 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1296 InitializeListHead (&Private
->TxList
);
1299 // Open and configure a ip instance for us.
1301 Status
= PingCreateIpInstance (Private
);
1303 if (EFI_ERROR (Status
)) {
1304 ShellStatus
= SHELL_ACCESS_DENIED
;
1308 // Print the command line itself.
1310 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1312 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1314 Status
= Ping6ReceiveEchoReply (Private
);
1316 if (EFI_ERROR (Status
)) {
1317 ShellStatus
= SHELL_ACCESS_DENIED
;
1321 // Create and start timer to send icmp6 echo request packet per second.
1323 Status
= gBS
->CreateEvent (
1324 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1326 Ping6OnTimerRoutine
,
1331 if (EFI_ERROR (Status
)) {
1332 ShellStatus
= SHELL_ACCESS_DENIED
;
1336 // Create a ipv6 token to send the first icmp6 echo request packet.
1338 Status
= PingSendEchoRequest (Private
);
1340 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1342 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1343 ShellStatus
= SHELL_ACCESS_DENIED
;
1344 if(Status
== EFI_NOT_FOUND
) {
1345 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1346 } else if (Status
== RETURN_NO_MAPPING
) {
1347 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1349 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1355 Status
= gBS
->SetTimer (
1361 if (EFI_ERROR (Status
)) {
1362 ShellStatus
= SHELL_ACCESS_DENIED
;
1366 // Control the ping6 process by two factors:
1368 // 2. Private->Status
1369 // 2.1. success means all icmp6 echo request packets get reply packets.
1370 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1371 // 2.3. noready means ping6 process is on-the-go.
1373 while (Private
->Status
== EFI_NOT_READY
) {
1374 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1375 if (ShellGetExecutionBreakFlag()) {
1376 Private
->Status
= EFI_ABORTED
;
1383 // Display the statistics in all.
1385 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1387 if (Private
->TxCount
!= 0) {
1392 STRING_TOKEN (STR_PING_STAT
),
1393 gShellNetwork1HiiHandle
,
1396 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
1401 if (Private
->RxCount
!= 0) {
1406 STRING_TOKEN (STR_PING_RTT
),
1407 gShellNetwork1HiiHandle
,
1410 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
1416 if (Private
!= NULL
) {
1418 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1419 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1421 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1422 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1425 RemoveEntryList (&TxInfo
->Link
);
1426 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1429 if (Private
->Timer
!= NULL
) {
1430 gBS
->CloseEvent (Private
->Timer
);
1433 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1434 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1437 if (Private
->RxToken
.Event
!= NULL
) {
1438 gBS
->CloseEvent (Private
->RxToken
.Event
);
1441 if (Private
->IpChildHandle
!= NULL
) {
1442 Ping6DestroyIp6Instance (Private
);
1452 Function for 'ping' command.
1454 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1455 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1457 @retval SHELL_SUCCESS The ping processed successfullly.
1458 @retval others The ping processed unsuccessfully.
1463 ShellCommandRunPing (
1464 IN EFI_HANDLE ImageHandle
,
1465 IN EFI_SYSTEM_TABLE
*SystemTable
1469 SHELL_STATUS ShellStatus
;
1470 EFI_IPv6_ADDRESS DstAddress
;
1471 EFI_IPv6_ADDRESS SrcAddress
;
1474 LIST_ENTRY
*ParamPackage
;
1475 CONST CHAR16
*ValueStr
;
1476 UINTN NonOptionCount
;
1478 CHAR16
*ProblemParam
;
1481 // we use IPv6 buffers to hold items...
1482 // make sure this is enough space!
1484 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1485 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1487 IpChoice
= PING_IP_CHOICE_IP4
;
1489 ShellStatus
= SHELL_SUCCESS
;
1490 ProblemParam
= NULL
;
1492 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1493 if (EFI_ERROR(Status
)) {
1494 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1495 ShellStatus
= SHELL_INVALID_PARAMETER
;
1499 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1500 IpChoice
= PING_IP_CHOICE_IP6
;
1504 // Parse the paramter of count number.
1506 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1507 if (ValueStr
!= NULL
) {
1508 SendNumber
= ShellStrToUintn (ValueStr
);
1511 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1513 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1514 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1515 ShellStatus
= SHELL_INVALID_PARAMETER
;
1519 SendNumber
= DEFAULT_SEND_COUNT
;
1522 // Parse the paramter of buffer size.
1524 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1525 if (ValueStr
!= NULL
) {
1526 BufferSize
= ShellStrToUintn (ValueStr
);
1529 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1531 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1532 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1533 ShellStatus
= SHELL_INVALID_PARAMETER
;
1537 BufferSize
= DEFAULT_BUFFER_SIZE
;
1540 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1541 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1544 // Parse the paramter of source ip address.
1546 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1547 if (ValueStr
== NULL
) {
1548 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1551 if (ValueStr
!= NULL
) {
1552 mSrcString
= ValueStr
;
1553 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1554 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1556 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1558 if (EFI_ERROR (Status
)) {
1559 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1560 ShellStatus
= SHELL_INVALID_PARAMETER
;
1565 // Parse the paramter of destination ip address.
1567 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1568 if (NonOptionCount
< 2) {
1569 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1570 ShellStatus
= SHELL_INVALID_PARAMETER
;
1573 if (NonOptionCount
> 2) {
1574 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1575 ShellStatus
= SHELL_INVALID_PARAMETER
;
1578 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1579 if (ValueStr
!= NULL
) {
1580 mDstString
= ValueStr
;
1581 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1582 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1584 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1586 if (EFI_ERROR (Status
)) {
1587 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1588 ShellStatus
= SHELL_INVALID_PARAMETER
;
1593 // Get frequency to calculate the time from ticks.
1595 Status
= GetFrequency ();
1597 if (EFI_ERROR(Status
)) {
1601 // Enter into ping process.
1603 ShellStatus
= ShellPing (
1612 ShellCommandLineFreeVarList (ParamPackage
);