2 The implementation for Ping shell command.
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "UefiShellNetwork1CommandsLib.h"
18 #define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))
20 UINT64 CurrentTick
= 0;
23 // Function templates to match the IPv4 and IPv6 commands that we use.
27 (EFIAPI
*PING_IPX_POLL
)(
33 (EFIAPI
*PING_IPX_TRANSMIT
)(
40 (EFIAPI
*PING_IPX_RECEIVE
)(
47 (EFIAPI
*PING_IPX_CANCEL
)(
49 IN VOID
*Token OPTIONAL
53 /// A set of pointers to either IPv6 or IPv4 functions.
54 /// Unknown which one to the ping command.
57 PING_IPX_TRANSMIT Transmit
;
58 PING_IPX_RECEIVE Receive
;
59 PING_IPX_CANCEL Cancel
;
70 // PING_IPX_COMPLETION_TOKEN
71 // structures are used for both transmit and receive operations.
72 // This version is IP-unaware.
78 } PING_IPX_COMPLETION_TOKEN
;
81 typedef struct _ICMPX_ECHO_REQUEST_REPLY
{
89 } ICMPX_ECHO_REQUEST_REPLY
;
92 typedef struct _PING_ICMP_TX_INFO
{
96 PING_IPX_COMPLETION_TOKEN
*Token
;
99 #define DEFAULT_TIMEOUT 5000
100 #define MAX_SEND_NUMBER 10000
101 #define MAX_BUFFER_SIZE 32768
102 #define DEFAULT_TIMER_PERIOD 358049
103 #define ONE_SECOND 10000000
104 #define PING_IP_CHOICE_IP4 1
105 #define PING_IP_CHOICE_IP6 2
106 #define DEFAULT_SEND_COUNT 10
107 #define DEFAULT_BUFFER_SIZE 16
108 #define ICMP_V4_ECHO_REQUEST 0x8
109 #define ICMP_V4_ECHO_REPLY 0x0
111 #define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')
112 typedef struct _PING_PRIVATE_DATA
{
114 EFI_HANDLE NicHandle
;
115 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
;
139 Calculate the internet checksum (see RFC 1071).
141 @param[in] Packet Buffer which contains the data to be checksummed.
142 @param[in] Length Length to be checksummed.
144 @retval Checksum Returns the 16 bit ones complement of
145 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
[] = {
214 // Global Variables in Ping command.
216 STATIC CONST CHAR16
*mDstString
;
217 STATIC CONST CHAR16
*mSrcString
;
218 STATIC UINT64 mFrequency
= 0;
219 EFI_CPU_ARCH_PROTOCOL
*gCpu
= NULL
;
222 Read the current time.
224 @retval the current tick value.
235 ASSERT (gCpu
!= NULL
);
237 Status
= gCpu
->GetTimerValue (gCpu
, 0, &CurrentTick
, &TimerPeriod
);
238 if (EFI_ERROR (Status
)) {
240 // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the
241 // TimerPeriod by ourselves.
243 CurrentTick
+= 1000000;
251 Get and caculate the frequency in tick/ms.
252 The result is saved in the globle variable mFrequency
254 @retval EFI_SUCCESS Caculated the frequency successfully.
255 @retval Others Failed to caculate the frequency.
268 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &gCpu
);
269 if (EFI_ERROR (Status
)) {
273 Status
= gCpu
->GetTimerValue (gCpu
, 0, &CurrentTick
, &TimerPeriod
);
275 if (EFI_ERROR (Status
)) {
276 TimerPeriod
= DEFAULT_TIMER_PERIOD
;
280 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
281 // So 1e+12 is divided by timer period to produce the freq in tick/ms.
283 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
289 Caculate a duration in ms.
291 @param[in] Begin The start point of time.
292 @param[in] End The end point of time.
294 @return The duration in ms.
295 @retval 0 The parameters were not valid.
307 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
311 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
313 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
314 @param[in] IpChoice Whether the token is IPv4 or IPv6
319 IN PING_ICMPX_TX_INFO
*TxInfo
,
323 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
324 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
325 EFI_IP6_FRAGMENT_DATA
*FragData
;
328 if (TxInfo
== NULL
) {
332 if (TxInfo
->Token
!= NULL
) {
334 if (TxInfo
->Token
->Event
!= NULL
) {
335 gBS
->CloseEvent (TxInfo
->Token
->Event
);
338 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
339 if (IpChoice
== PING_IP_CHOICE_IP6
) {
340 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
342 if (Ip6TxData
->OverrideData
!= NULL
) {
343 FreePool (Ip6TxData
->OverrideData
);
346 if (Ip6TxData
->ExtHdrs
!= NULL
) {
347 FreePool (Ip6TxData
->ExtHdrs
);
350 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
351 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
352 if (FragData
!= NULL
) {
357 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
359 if (Ip4TxData
->OverrideData
!= NULL
) {
360 FreePool (Ip4TxData
->OverrideData
);
363 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
364 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
365 if (FragData
!= NULL
) {
372 FreePool (TxInfo
->Token
);
379 Match the request, and reply with SequenceNum/TimeStamp.
381 @param[in] Private The pointer to PING_PRIVATE_DATA.
382 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
384 @retval EFI_SUCCESS The match is successful.
385 @retval EFI_NOT_FOUND The reply can't be matched with any request.
390 Ping6MatchEchoReply (
391 IN PING_PRIVATE_DATA
*Private
,
392 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
395 PING_ICMPX_TX_INFO
*TxInfo
;
397 LIST_ENTRY
*NextEntry
;
399 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
400 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
402 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
404 RemoveEntryList (&TxInfo
->Link
);
405 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
410 return EFI_NOT_FOUND
;
414 The original intention is to send a request.
415 Currently, the application retransmits an icmp6 echo request packet
416 per second in sendnumber times that is specified by the user.
417 Because nothing can be done here, all things move to the timer rountine.
419 @param[in] Event A EFI_EVENT type event.
420 @param[in] Context The pointer to Context.
425 Ping6OnEchoRequestSent (
433 receive reply, match and print reply infomation.
435 @param[in] Event A EFI_EVENT type event.
436 @param[in] Context The pointer to context.
441 Ping6OnEchoReplyReceived (
447 PING_PRIVATE_DATA
*Private
;
448 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
453 Private
= (PING_PRIVATE_DATA
*) Context
;
455 if (Private
== NULL
|| Private
->Status
== EFI_ABORTED
|| Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
459 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
463 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
464 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
465 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
466 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
469 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
470 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
)) {
474 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
478 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
479 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
480 if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
481 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
)) {
485 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
491 if (PayLoad
!= Private
->BufferSize
) {
495 // Check whether the reply matches the sent request before.
497 Status
= Ping6MatchEchoReply (Private
, Reply
);
498 if (EFI_ERROR(Status
)) {
502 // Display statistics on this icmp6 echo reply packet.
504 Rtt
= CalculateTick (Reply
->TimeStamp
, ReadTime ());
511 Private
->RttSum
+= Rtt
;
512 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
513 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
519 STRING_TOKEN (STR_PING_REPLY_INFO
),
520 gShellNetwork1HiiHandle
,
524 Private
->IpChoice
== PING_IP_CHOICE_IP6
?((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
:0,
531 if (Private
->RxCount
< Private
->SendNum
) {
533 // Continue to receive icmp echo reply packets.
535 Private
->RxToken
.Status
= EFI_ABORTED
;
537 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
539 if (EFI_ERROR (Status
)) {
540 Private
->Status
= EFI_ABORTED
;
544 // All reply have already been received from the dest host.
546 Private
->Status
= EFI_SUCCESS
;
549 // Singal to recycle the each rxdata here, not at the end of process.
551 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
);
555 Create a PING_IPX_COMPLETION_TOKEN.
557 @param[in] Private The pointer of PING_PRIVATE_DATA.
558 @param[in] TimeStamp The TimeStamp of request.
559 @param[in] SequenceNum The SequenceNum of request.
561 @return The pointer of PING_IPX_COMPLETION_TOKEN.
564 PING_IPX_COMPLETION_TOKEN
*
567 IN PING_PRIVATE_DATA
*Private
,
569 IN UINT16 SequenceNum
573 PING_IPX_COMPLETION_TOKEN
*Token
;
575 ICMPX_ECHO_REQUEST_REPLY
*Request
;
579 Request
= AllocateZeroPool (Private
->BufferSize
);
580 if (Request
== NULL
) {
583 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
584 if (TxData
== NULL
) {
588 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
596 // Assembly echo request packet.
598 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
600 Request
->SequenceNum
= SequenceNum
;
601 Request
->Identifier
= 0;
602 Request
->Checksum
= 0;
605 // Assembly token for transmit.
607 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
608 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
609 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
610 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
611 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
612 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
613 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
614 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
616 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
617 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
618 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
619 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
620 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
621 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
622 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
623 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
624 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
625 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
626 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
628 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
629 Request
->TimeStamp
= TimeStamp
;
630 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
631 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
635 Token
->Status
= EFI_ABORTED
;
636 Token
->Packet
.TxData
= TxData
;
638 Status
= gBS
->CreateEvent (
641 Ping6OnEchoRequestSent
,
646 if (EFI_ERROR (Status
)) {
657 Transmit the PING_IPX_COMPLETION_TOKEN.
659 @param[in] Private The pointer of PING_PRIVATE_DATA.
661 @retval EFI_SUCCESS Transmitted successfully.
662 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
663 @retval others Transmitted unsuccessfully.
668 PingSendEchoRequest (
669 IN PING_PRIVATE_DATA
*Private
673 PING_ICMPX_TX_INFO
*TxInfo
;
675 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
677 if (TxInfo
== NULL
) {
678 return EFI_OUT_OF_RESOURCES
;
681 TxInfo
->TimeStamp
= ReadTime ();
682 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
683 TxInfo
->Token
= PingGenerateToken (
689 if (TxInfo
->Token
== NULL
) {
690 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
691 return EFI_OUT_OF_RESOURCES
;
694 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
695 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
697 if (EFI_ERROR (Status
)) {
698 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
702 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
709 Place a completion token into the receive packet queue to receive the echo reply.
711 @param[in] Private The pointer of PING_PRIVATE_DATA.
713 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
714 @retval others Put the token into the receive packet queue unsuccessfully.
719 Ping6ReceiveEchoReply (
720 IN PING_PRIVATE_DATA
*Private
725 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
727 Status
= gBS
->CreateEvent (
730 Ping6OnEchoReplyReceived
,
732 &Private
->RxToken
.Event
735 if (EFI_ERROR (Status
)) {
739 Private
->RxToken
.Status
= EFI_NOT_READY
;
741 return (Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
));
745 Remove the timeout request from the list.
747 @param[in] Event A EFI_EVENT type event.
748 @param[in] Context The pointer to Context.
753 Ping6OnTimerRoutine (
759 PING_PRIVATE_DATA
*Private
;
760 PING_ICMPX_TX_INFO
*TxInfo
;
762 LIST_ENTRY
*NextEntry
;
765 Private
= (PING_PRIVATE_DATA
*) Context
;
766 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
767 Private
->Status
= EFI_NOT_FOUND
;
772 // Retransmit icmp6 echo request packets per second in sendnumber times.
774 if (Private
->TxCount
< Private
->SendNum
) {
776 Status
= PingSendEchoRequest (Private
);
777 if (Private
->TxCount
!= 0){
778 if (EFI_ERROR (Status
)) {
779 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
784 // Check whether any icmp6 echo request in the list timeout.
786 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
787 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
788 Time
= CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
791 // Remove the timeout echo request from txlist.
793 if (Time
> DEFAULT_TIMEOUT
) {
795 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
796 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
799 // Remove the timeout icmp6 echo request from list.
801 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
803 RemoveEntryList (&TxInfo
->Link
);
804 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
807 // We dont need to wait for this some other time...
811 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
813 // All the left icmp6 echo request in the list timeout.
815 Private
->Status
= EFI_TIMEOUT
;
822 Determine if a IP4 address is Link Local.
824 169.254.1.0 through 169.254.254.255 is link local.
826 @param[in] Address The address to test.
829 @retval FALSE It is not.
833 PingNetIp4IsLinkLocalAddr (
834 IN CONST EFI_IPv4_ADDRESS
*Address
837 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
841 Determine if a IP4 address is unspecified.
843 @param[in] Address The address to test.
846 @retval FALSE It is not.
850 PingNetIp4IsUnspecifiedAddr (
851 IN CONST EFI_IPv4_ADDRESS
*Address
854 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
858 Create a valid IP instance.
860 @param[in] Private The pointer of PING_PRIVATE_DATA.
862 @retval EFI_SUCCESS Create a valid IPx instance successfully.
863 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
864 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
865 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
866 @retval EFI_NOT_FOUND The source address is not found.
870 PingCreateIpInstance (
871 IN PING_PRIVATE_DATA
*Private
877 EFI_HANDLE
*HandleBuffer
;
878 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
880 EFI_IP6_CONFIG_DATA Ip6Config
;
881 EFI_IP4_CONFIG_DATA Ip4Config
;
882 VOID
*IpXInterfaceInfo
;
884 EFI_IPv6_ADDRESS
*Addr
;
889 IpXInterfaceInfo
= NULL
;
893 // Locate all the handles with ip6 service binding protocol.
895 Status
= gBS
->LocateHandleBuffer (
897 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
902 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
906 // Source address is required when pinging a link-local address on multi-
909 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
910 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
911 NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) &&
913 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, mSrcString
);
914 Status
= EFI_INVALID_PARAMETER
;
918 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
919 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) &&
920 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
) &&
922 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, mSrcString
);
923 Status
= EFI_INVALID_PARAMETER
;
928 // For each ip6 protocol, check interface addresses list.
930 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
933 IpXInterfaceInfo
= NULL
;
936 Status
= gBS
->HandleProtocol (
937 HandleBuffer
[HandleIndex
],
938 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
941 if (EFI_ERROR (Status
)) {
945 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
?NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
):PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
947 // No need to match interface address.
952 // Ip6config protocol and ip6 service binding protocol are installed
953 // on the same handle.
955 Status
= gBS
->HandleProtocol (
956 HandleBuffer
[HandleIndex
],
957 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4ConfigProtocolGuid
,
961 if (EFI_ERROR (Status
)) {
965 // Get the interface information size.
967 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
968 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
970 Ip6ConfigDataTypeInterfaceInfo
,
975 Status
= ((EFI_IP4_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
983 // Skip the ones not in current use.
985 if (Status
== EFI_NOT_STARTED
) {
989 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
990 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
994 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
996 if (IpXInterfaceInfo
== NULL
) {
997 Status
= EFI_OUT_OF_RESOURCES
;
1001 // Get the interface info.
1003 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1004 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1006 Ip6ConfigDataTypeInterfaceInfo
,
1011 Status
= ((EFI_IP4_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1018 if (EFI_ERROR (Status
)) {
1019 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1023 // Check whether the source address is one of the interface addresses.
1025 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1026 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1028 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1029 if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1031 // Match a certain interface address.
1037 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1039 // Found a nic handle with right interface address.
1045 // IP4 address check
1047 if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_IPCONFIG_DATA
*)IpXInterfaceInfo
)->StationAddress
)) {
1049 // Match a certain interface address.
1056 FreePool (IpXInterfaceInfo
);
1057 IpXInterfaceInfo
= NULL
;
1060 // No exact interface address matched.
1063 if (HandleIndex
== HandleNum
) {
1064 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, mSrcString
);
1065 Status
= EFI_NOT_FOUND
;
1069 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1071 ASSERT (EfiSb
!= NULL
);
1072 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1074 if (EFI_ERROR (Status
)) {
1077 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1078 Status
= gBS
->OpenProtocol (
1079 Private
->IpChildHandle
,
1080 &gEfiIp6ProtocolGuid
,
1081 &Private
->IpProtocol
,
1083 Private
->IpChildHandle
,
1084 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1086 if (EFI_ERROR (Status
)) {
1091 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1094 // Configure the ip6 instance for icmp6 packet exchange.
1096 Ip6Config
.DefaultProtocol
= 58;
1097 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1098 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1099 Ip6Config
.AcceptPromiscuous
= FALSE
;
1100 Ip6Config
.TrafficClass
= 0;
1101 Ip6Config
.HopLimit
= 128;
1102 Ip6Config
.FlowLabel
= 0;
1103 Ip6Config
.ReceiveTimeout
= 0;
1104 Ip6Config
.TransmitTimeout
= 0;
1106 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1107 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1109 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1111 if (EFI_ERROR (Status
)) {
1112 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1116 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1117 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1118 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1119 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1121 Status
= gBS
->OpenProtocol (
1122 Private
->IpChildHandle
,
1123 &gEfiIp4ProtocolGuid
,
1124 &Private
->IpProtocol
,
1126 Private
->IpChildHandle
,
1127 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1129 if (EFI_ERROR (Status
)) {
1134 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1137 // Configure the ip4 instance for icmp4 packet exchange.
1139 // PING_IP4_COPY_ADDRESS (&Ip4Config.StationAddress, &Private->SrcAddress);
1140 // Ip4Config.SubnetMask.Addr[0] = 0xFF;
1141 // Ip4Config.SubnetMask.Addr[1] = 0xFF;
1142 // Ip4Config.SubnetMask.Addr[2] = 0xFF;
1143 // Ip4Config.SubnetMask.Addr[3] = 0x00;
1144 Ip4Config
.DefaultProtocol
= 1;
1145 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1146 Ip4Config
.AcceptBroadcast
= FALSE
;
1147 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1148 Ip4Config
.AcceptPromiscuous
= FALSE
;
1149 Ip4Config
.DoNotFragment
= FALSE
;
1150 Ip4Config
.RawData
= FALSE
;
1151 Ip4Config
.ReceiveTimeout
= 0;
1152 Ip4Config
.TransmitTimeout
= 0;
1153 Ip4Config
.UseDefaultAddress
= TRUE
;
1154 Ip4Config
.TimeToLive
= 128;
1155 Ip4Config
.TypeOfService
= 0;
1157 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1159 if (EFI_ERROR (Status
)) {
1160 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1164 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1165 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1166 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1167 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1170 if (HandleBuffer
!= NULL
) {
1171 FreePool (HandleBuffer
);
1177 if (HandleBuffer
!= NULL
) {
1178 FreePool (HandleBuffer
);
1181 if (IpXInterfaceInfo
!= NULL
) {
1182 FreePool (IpXInterfaceInfo
);
1185 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1186 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1193 Destory the IP instance.
1195 @param[in] Private The pointer of PING_PRIVATE_DATA.
1200 Ping6DestoryIp6Instance (
1201 IN PING_PRIVATE_DATA
*Private
1205 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1207 gBS
->CloseProtocol (
1208 Private
->IpChildHandle
,
1209 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1211 Private
->IpChildHandle
1214 Status
= gBS
->HandleProtocol (
1216 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1220 if (!EFI_ERROR(Status
)) {
1221 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1228 @param[in] SendNumber The send request count.
1229 @param[in] BufferSize The send buffer size.
1230 @param[in] SrcAddress The source address.
1231 @param[in] DstAddress The destination address.
1232 @param[in] IpChoice The choice between IPv4 and IPv6.
1234 @retval SHELL_SUCCESS The ping processed successfullly.
1235 @retval others The ping processed unsuccessfully.
1240 IN UINT32 SendNumber
,
1241 IN UINT32 BufferSize
,
1242 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1243 IN EFI_IPv6_ADDRESS
*DstAddress
,
1248 PING_PRIVATE_DATA
*Private
;
1249 PING_ICMPX_TX_INFO
*TxInfo
;
1251 LIST_ENTRY
*NextEntry
;
1252 SHELL_STATUS ShellStatus
;
1254 ShellStatus
= SHELL_SUCCESS
;
1255 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1257 if (Private
== NULL
) {
1258 return (SHELL_OUT_OF_RESOURCES
);
1261 Private
->IpChoice
= IpChoice
;
1262 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1263 Private
->SendNum
= SendNumber
;
1264 Private
->BufferSize
= BufferSize
;
1265 Private
->RttMin
= ~((UINT64
)(0x0));
1266 Private
->Status
= EFI_NOT_READY
;
1268 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1269 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1271 InitializeListHead (&Private
->TxList
);
1274 // Open and configure a ip instance for us.
1276 Status
= PingCreateIpInstance (Private
);
1278 if (EFI_ERROR (Status
)) {
1279 ShellStatus
= SHELL_ACCESS_DENIED
;
1283 // Print the command line itself.
1285 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1287 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1289 Status
= Ping6ReceiveEchoReply (Private
);
1291 if (EFI_ERROR (Status
)) {
1292 ShellStatus
= SHELL_ACCESS_DENIED
;
1296 // Create and start timer to send icmp6 echo request packet per second.
1298 Status
= gBS
->CreateEvent (
1299 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1301 Ping6OnTimerRoutine
,
1306 if (EFI_ERROR (Status
)) {
1307 ShellStatus
= SHELL_ACCESS_DENIED
;
1311 // Create a ipv6 token to send the first icmp6 echo request packet.
1313 Status
= PingSendEchoRequest (Private
);
1315 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1317 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1318 ShellStatus
= SHELL_ACCESS_DENIED
;
1319 if(Status
== EFI_NOT_FOUND
) {
1320 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1321 } else if (Status
== RETURN_NO_MAPPING
) {
1322 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1324 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, Status
);
1330 Status
= gBS
->SetTimer (
1336 if (EFI_ERROR (Status
)) {
1337 ShellStatus
= SHELL_ACCESS_DENIED
;
1341 // Control the ping6 process by two factors:
1343 // 2. Private->Status
1344 // 2.1. success means all icmp6 echo request packets get reply packets.
1345 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1346 // 2.3. noready means ping6 process is on-the-go.
1348 while (Private
->Status
== EFI_NOT_READY
) {
1349 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1350 if (ShellGetExecutionBreakFlag()) {
1351 Private
->Status
= EFI_ABORTED
;
1358 // Display the statistics in all.
1360 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1362 if (Private
->TxCount
!= 0) {
1367 STRING_TOKEN (STR_PING_STAT
),
1368 gShellNetwork1HiiHandle
,
1371 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
1376 if (Private
->RxCount
!= 0) {
1381 STRING_TOKEN (STR_PING_RTT
),
1382 gShellNetwork1HiiHandle
,
1385 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
1391 if (Private
!= NULL
) {
1393 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1394 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1396 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1397 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1400 RemoveEntryList (&TxInfo
->Link
);
1401 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1404 if (Private
->Timer
!= NULL
) {
1405 gBS
->CloseEvent (Private
->Timer
);
1408 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1409 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1412 if (Private
->RxToken
.Event
!= NULL
) {
1413 gBS
->CloseEvent (Private
->RxToken
.Event
);
1416 if (Private
->IpChildHandle
!= NULL
) {
1417 Ping6DestoryIp6Instance (Private
);
1427 Function for 'ping' command.
1429 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1430 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1434 ShellCommandRunPing (
1435 IN EFI_HANDLE ImageHandle
,
1436 IN EFI_SYSTEM_TABLE
*SystemTable
1440 SHELL_STATUS ShellStatus
;
1441 EFI_IPv6_ADDRESS DstAddress
;
1442 EFI_IPv6_ADDRESS SrcAddress
;
1445 LIST_ENTRY
*ParamPackage
;
1446 CONST CHAR16
*ValueStr
;
1447 UINTN NonOptionCount
;
1451 // we use IPv6 buffers to hold items...
1452 // make sure this is enough space!
1454 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1455 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1457 IpChoice
= PING_IP_CHOICE_IP4
;
1459 ShellStatus
= SHELL_SUCCESS
;
1461 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, NULL
, TRUE
, FALSE
);
1462 if (EFI_ERROR(Status
)) {
1463 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
);
1464 ShellStatus
= SHELL_INVALID_PARAMETER
;
1468 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1469 IpChoice
= PING_IP_CHOICE_IP6
;
1473 // Parse the paramter of count number.
1475 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1476 if (ValueStr
!= NULL
) {
1477 SendNumber
= ShellStrToUintn (ValueStr
);
1480 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1482 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1483 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1484 ShellStatus
= SHELL_INVALID_PARAMETER
;
1488 SendNumber
= DEFAULT_SEND_COUNT
;
1491 // Parse the paramter of buffer size.
1493 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1494 if (ValueStr
!= NULL
) {
1495 BufferSize
= ShellStrToUintn (ValueStr
);
1498 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1500 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1501 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1502 ShellStatus
= SHELL_INVALID_PARAMETER
;
1506 BufferSize
= DEFAULT_BUFFER_SIZE
;
1509 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1510 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1513 // Parse the paramter of source ip address.
1515 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1516 if (ValueStr
!= NULL
) {
1517 mSrcString
= ValueStr
;
1518 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1519 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1521 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1523 if (EFI_ERROR (Status
)) {
1524 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1525 ShellStatus
= SHELL_INVALID_PARAMETER
;
1530 // Parse the paramter of destination ip address.
1532 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1533 if (NonOptionCount
< 2) {
1534 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
);
1535 ShellStatus
= SHELL_INVALID_PARAMETER
;
1538 if (NonOptionCount
> 2) {
1539 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
);
1540 ShellStatus
= SHELL_INVALID_PARAMETER
;
1543 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1544 if (ValueStr
!= NULL
) {
1545 mDstString
= ValueStr
;
1546 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1547 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1549 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1551 if (EFI_ERROR (Status
)) {
1552 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1553 ShellStatus
= SHELL_INVALID_PARAMETER
;
1558 // Get frequency to calculate the time from ticks.
1560 Status
= GetFrequency ();
1562 if (EFI_ERROR(Status
)) {
1566 // Enter into ping process.
1568 ShellStatus
= ShellPing (
1577 ShellCommandLineFreeVarList (ParamPackage
);