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)))
22 // Function templates to match the IPv4 and IPv6 commands that we use.
26 (EFIAPI
*PING_IPX_POLL
)(
32 (EFIAPI
*PING_IPX_TRANSMIT
)(
39 (EFIAPI
*PING_IPX_RECEIVE
)(
46 (EFIAPI
*PING_IPX_CANCEL
)(
48 IN VOID
*Token OPTIONAL
52 /// A set of pointers to either IPv6 or IPv4 functions.
53 /// Unknown which one to the ping command.
56 PING_IPX_TRANSMIT Transmit
;
57 PING_IPX_RECEIVE Receive
;
58 PING_IPX_CANCEL Cancel
;
69 // PING_IPX_COMPLETION_TOKEN
70 // structures are used for both transmit and receive operations.
71 // This version is IP-unaware.
77 } PING_IPX_COMPLETION_TOKEN
;
80 typedef struct _ICMPX_ECHO_REQUEST_REPLY
{
88 } ICMPX_ECHO_REQUEST_REPLY
;
91 typedef struct _PING_ICMP_TX_INFO
{
95 PING_IPX_COMPLETION_TOKEN
*Token
;
98 #define DEFAULT_TIMEOUT 5000
99 #define MAX_SEND_NUMBER 10000
100 #define MAX_BUFFER_SIZE 32768
101 #define DEFAULT_TIMER_PERIOD 358049
102 #define ONE_SECOND 10000000
103 #define PING_IP_CHOICE_IP4 1
104 #define PING_IP_CHOICE_IP6 2
105 #define DEFAULT_SEND_COUNT 10
106 #define DEFAULT_BUFFER_SIZE 16
107 #define ICMP_V4_ECHO_REQUEST 0x8
108 #define ICMP_V4_ECHO_REPLY 0x0
110 #define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')
111 typedef struct _PING_PRIVATE_DATA
{
113 EFI_HANDLE NicHandle
;
114 EFI_HANDLE IpChildHandle
;
130 PING_IPX_PROTOCOL ProtocolPointers
;
132 UINT8 SrcAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
133 UINT8 DstAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
134 PING_IPX_COMPLETION_TOKEN RxToken
;
138 Calculate the internet checksum (see RFC 1071).
140 @param[in] Packet Buffer which contains the data to be checksummed.
141 @param[in] Length Length to be checksummed.
143 @retval Checksum Returns the 16 bit ones complement of
144 ones complement sum of 16 bit words
157 Packet
= (UINT16
*) Buffer
;
160 Odd
= (UINT8
) (Length
& 1);
162 while ((Length
--) != 0) {
167 Sum
+= *(UINT8
*) Packet
;
170 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
173 // in case above carried
181 Reads and returns the current value of register.
182 In IA64, the register is the Interval Timer Vector (ITV).
183 In X86(IA32/X64), the register is the Time Stamp Counter (TSC)
185 @return The current value of the register.
189 STATIC CONST SHELL_PARAM_ITEM PingParamList
[] = {
213 // Global Variables in Ping command.
215 STATIC CONST CHAR16
*mDstString
;
216 STATIC CONST CHAR16
*mSrcString
;
217 STATIC UINT64 mFrequency
= 0;
218 EFI_CPU_ARCH_PROTOCOL
*gCpu
= NULL
;
226 static UINT64 CurrentTick
= 0;
230 ASSERT (gCpu
!= NULL
);
232 Status
= gCpu
->GetTimerValue (gCpu
, 0, &CurrentTick
, &TimerPeriod
);
233 if (EFI_ERROR (Status
)) {
235 // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the
236 // TimerPeriod by ourselves.
238 CurrentTick
+= 1000000;
246 Get and caculate the frequency in tick/ms.
247 The result is saved in the globle variable mFrequency
249 @retval EFI_SUCCESS Caculated the frequency successfully.
250 @retval Others Failed to caculate the frequency.
263 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &gCpu
);
264 if (EFI_ERROR (Status
)) {
268 Status
= gCpu
->GetTimerValue (gCpu
, 0, &CurrentTick
, &TimerPeriod
);
270 if (EFI_ERROR (Status
)) {
271 TimerPeriod
= DEFAULT_TIMER_PERIOD
;
275 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
276 // So 1e+12 is divided by timer period to produce the freq in tick/ms.
278 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
284 Caculate a duration in ms.
286 @param[in] Begin The start point of time.
287 @param[in] End The end point of time.
289 @return The duration in ms.
290 @retval 0 The parameters were not valid.
302 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
306 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
308 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
309 @param[in] IpChoice Whether the token is IPv4 or IPv6
314 IN PING_ICMPX_TX_INFO
*TxInfo
,
318 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
319 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
320 EFI_IP6_FRAGMENT_DATA
*FragData
;
323 if (TxInfo
== NULL
) {
327 if (TxInfo
->Token
!= NULL
) {
329 if (TxInfo
->Token
->Event
!= NULL
) {
330 gBS
->CloseEvent (TxInfo
->Token
->Event
);
333 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
334 if (IpChoice
== PING_IP_CHOICE_IP6
) {
335 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
337 if (Ip6TxData
->OverrideData
!= NULL
) {
338 FreePool (Ip6TxData
->OverrideData
);
341 if (Ip6TxData
->ExtHdrs
!= NULL
) {
342 FreePool (Ip6TxData
->ExtHdrs
);
345 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
346 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
347 if (FragData
!= NULL
) {
352 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
354 if (Ip4TxData
->OverrideData
!= NULL
) {
355 FreePool (Ip4TxData
->OverrideData
);
358 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
359 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
360 if (FragData
!= NULL
) {
367 FreePool (TxInfo
->Token
);
374 Match the request, and reply with SequenceNum/TimeStamp.
376 @param[in] Private The pointer to PING_PRIVATE_DATA.
377 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
379 @retval EFI_SUCCESS The match is successful.
380 @retval EFI_NOT_FOUND The reply can't be matched with any request.
385 Ping6MatchEchoReply (
386 IN PING_PRIVATE_DATA
*Private
,
387 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
390 PING_ICMPX_TX_INFO
*TxInfo
;
392 LIST_ENTRY
*NextEntry
;
394 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
395 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
397 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
399 RemoveEntryList (&TxInfo
->Link
);
400 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
405 return EFI_NOT_FOUND
;
409 The original intention is to send a request.
410 Currently, the application retransmits an icmp6 echo request packet
411 per second in sendnumber times that is specified by the user.
412 Because nothing can be done here, all things move to the timer rountine.
414 @param[in] Event A EFI_EVENT type event.
415 @param[in] Context The pointer to Context.
420 Ping6OnEchoRequestSent (
428 receive reply, match and print reply infomation.
430 @param[in] Event A EFI_EVENT type event.
431 @param[in] Context The pointer to context.
436 Ping6OnEchoReplyReceived (
442 PING_PRIVATE_DATA
*Private
;
443 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
448 Private
= (PING_PRIVATE_DATA
*) Context
;
450 if (Private
== NULL
|| Private
->Status
== EFI_ABORTED
|| Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
454 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
458 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
459 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
460 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
461 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
464 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
465 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
)) {
469 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
473 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
474 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
475 if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
476 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
)) {
480 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
486 if (PayLoad
!= Private
->BufferSize
) {
490 // Check whether the reply matches the sent request before.
492 Status
= Ping6MatchEchoReply (Private
, Reply
);
493 if (EFI_ERROR(Status
)) {
497 // Display statistics on this icmp6 echo reply packet.
499 Rtt
= CalculateTick (Reply
->TimeStamp
, ReadTime ());
506 Private
->RttSum
+= Rtt
;
507 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
508 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
514 STRING_TOKEN (STR_PING_REPLY_INFO
),
515 gShellNetwork1HiiHandle
,
519 Private
->IpChoice
== PING_IP_CHOICE_IP6
?((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
:0,
526 if (Private
->RxCount
< Private
->SendNum
) {
528 // Continue to receive icmp echo reply packets.
530 Private
->RxToken
.Status
= EFI_ABORTED
;
532 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
534 if (EFI_ERROR (Status
)) {
535 Private
->Status
= EFI_ABORTED
;
539 // All reply have already been received from the dest host.
541 Private
->Status
= EFI_SUCCESS
;
544 // Singal to recycle the each rxdata here, not at the end of process.
546 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
);
550 Create a PING_IPX_COMPLETION_TOKEN.
552 @param[in] Private The pointer of PING_PRIVATE_DATA.
553 @param[in] TimeStamp The TimeStamp of request.
554 @param[in] SequenceNum The SequenceNum of request.
556 @return The pointer of PING_IPX_COMPLETION_TOKEN.
559 PING_IPX_COMPLETION_TOKEN
*
562 IN PING_PRIVATE_DATA
*Private
,
564 IN UINT16 SequenceNum
568 PING_IPX_COMPLETION_TOKEN
*Token
;
570 ICMPX_ECHO_REQUEST_REPLY
*Request
;
574 Request
= AllocateZeroPool (Private
->BufferSize
);
575 if (Request
== NULL
) {
578 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
579 if (TxData
== NULL
) {
583 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
591 // Assembly echo request packet.
593 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
595 Request
->SequenceNum
= SequenceNum
;
596 Request
->Identifier
= 0;
597 Request
->Checksum
= 0;
600 // Assembly token for transmit.
602 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
603 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
604 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
605 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
606 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
607 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
608 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
609 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
611 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
612 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
613 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
614 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
615 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
616 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
617 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
618 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
619 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
620 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
621 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
623 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
624 Request
->TimeStamp
= TimeStamp
;
625 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
626 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
630 Token
->Status
= EFI_ABORTED
;
631 Token
->Packet
.TxData
= TxData
;
633 Status
= gBS
->CreateEvent (
636 Ping6OnEchoRequestSent
,
641 if (EFI_ERROR (Status
)) {
652 Transmit the PING_IPX_COMPLETION_TOKEN.
654 @param[in] Private The pointer of PING_PRIVATE_DATA.
656 @retval EFI_SUCCESS Transmitted successfully.
657 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
658 @retval others Transmitted unsuccessfully.
663 PingSendEchoRequest (
664 IN PING_PRIVATE_DATA
*Private
668 PING_ICMPX_TX_INFO
*TxInfo
;
670 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
672 if (TxInfo
== NULL
) {
673 return EFI_OUT_OF_RESOURCES
;
676 TxInfo
->TimeStamp
= ReadTime ();
677 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
678 TxInfo
->Token
= PingGenerateToken (
684 if (TxInfo
->Token
== NULL
) {
685 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
686 return EFI_OUT_OF_RESOURCES
;
689 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
690 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
692 if (EFI_ERROR (Status
)) {
693 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
697 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
704 Place a completion token into the receive packet queue to receive the echo reply.
706 @param[in] Private The pointer of PING_PRIVATE_DATA.
708 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
709 @retval others Put the token into the receive packet queue unsuccessfully.
714 Ping6ReceiveEchoReply (
715 IN PING_PRIVATE_DATA
*Private
720 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
722 Status
= gBS
->CreateEvent (
725 Ping6OnEchoReplyReceived
,
727 &Private
->RxToken
.Event
730 if (EFI_ERROR (Status
)) {
734 Private
->RxToken
.Status
= EFI_NOT_READY
;
736 return (Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
));
740 Remove the timeout request from the list.
742 @param[in] Event A EFI_EVENT type event.
743 @param[in] Context The pointer to Context.
748 Ping6OnTimerRoutine (
754 PING_PRIVATE_DATA
*Private
;
755 PING_ICMPX_TX_INFO
*TxInfo
;
757 LIST_ENTRY
*NextEntry
;
760 Private
= (PING_PRIVATE_DATA
*) Context
;
761 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
762 Private
->Status
= EFI_NOT_FOUND
;
767 // Retransmit icmp6 echo request packets per second in sendnumber times.
769 if (Private
->TxCount
< Private
->SendNum
) {
771 Status
= PingSendEchoRequest (Private
);
772 if (Private
->TxCount
!= 0){
773 if (EFI_ERROR (Status
)) {
774 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
779 // Check whether any icmp6 echo request in the list timeout.
781 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
782 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
783 Time
= CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
786 // Remove the timeout echo request from txlist.
788 if (Time
> DEFAULT_TIMEOUT
) {
790 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
791 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
794 // Remove the timeout icmp6 echo request from list.
796 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
798 RemoveEntryList (&TxInfo
->Link
);
799 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
802 // We dont need to wait for this some other time...
806 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
808 // All the left icmp6 echo request in the list timeout.
810 Private
->Status
= EFI_TIMEOUT
;
817 Determine if a IP4 address is Link Local.
819 169.254.1.0 through 169.254.254.255 is link local.
821 @param[in] Address The address to test.
824 @retval FALSE It is not.
828 PingNetIp4IsLinkLocalAddr (
829 IN CONST EFI_IPv4_ADDRESS
*Address
832 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
836 Determine if a IP4 address is unspecified.
838 @param[in] Address The address to test.
841 @retval FALSE It is not.
845 PingNetIp4IsUnspecifiedAddr (
846 IN CONST EFI_IPv4_ADDRESS
*Address
849 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
853 Create a valid IP instance.
855 @param[in] Private The pointer of PING_PRIVATE_DATA.
857 @retval EFI_SUCCESS Create a valid IPx instance successfully.
858 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
859 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
860 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
861 @retval EFI_NOT_FOUND The source address is not found.
865 PingCreateIpInstance (
866 IN PING_PRIVATE_DATA
*Private
872 EFI_HANDLE
*HandleBuffer
;
873 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
875 EFI_IP6_CONFIG_DATA Ip6Config
;
876 EFI_IP4_CONFIG_DATA Ip4Config
;
877 VOID
*IpXInterfaceInfo
;
879 EFI_IPv6_ADDRESS
*Addr
;
884 IpXInterfaceInfo
= NULL
;
888 // Locate all the handles with ip6 service binding protocol.
890 Status
= gBS
->LocateHandleBuffer (
892 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
897 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
901 // Source address is required when pinging a link-local address on multi-
904 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
905 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
906 NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) &&
908 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, mSrcString
);
909 Status
= EFI_INVALID_PARAMETER
;
913 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
914 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) &&
915 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
) &&
917 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, mSrcString
);
918 Status
= EFI_INVALID_PARAMETER
;
923 // For each ip6 protocol, check interface addresses list.
925 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
928 IpXInterfaceInfo
= NULL
;
931 Status
= gBS
->HandleProtocol (
932 HandleBuffer
[HandleIndex
],
933 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
936 if (EFI_ERROR (Status
)) {
940 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
?NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
):PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
942 // No need to match interface address.
947 // Ip6config protocol and ip6 service binding protocol are installed
948 // on the same handle.
950 Status
= gBS
->HandleProtocol (
951 HandleBuffer
[HandleIndex
],
952 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4ConfigProtocolGuid
,
956 if (EFI_ERROR (Status
)) {
960 // Get the interface information size.
962 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
963 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
965 Ip6ConfigDataTypeInterfaceInfo
,
970 Status
= ((EFI_IP4_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
978 // Skip the ones not in current use.
980 if (Status
== EFI_NOT_STARTED
) {
984 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
985 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
989 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
991 if (IpXInterfaceInfo
== NULL
) {
992 Status
= EFI_OUT_OF_RESOURCES
;
996 // Get the interface info.
998 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
999 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1001 Ip6ConfigDataTypeInterfaceInfo
,
1006 Status
= ((EFI_IP4_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1013 if (EFI_ERROR (Status
)) {
1014 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1018 // Check whether the source address is one of the interface addresses.
1020 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1021 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1023 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1024 if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1026 // Match a certain interface address.
1032 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1034 // Found a nic handle with right interface address.
1040 // IP4 address check
1042 if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_IPCONFIG_DATA
*)IpXInterfaceInfo
)->StationAddress
)) {
1044 // Match a certain interface address.
1051 FreePool (IpXInterfaceInfo
);
1052 IpXInterfaceInfo
= NULL
;
1055 // No exact interface address matched.
1058 if (HandleIndex
== HandleNum
) {
1059 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, mSrcString
);
1060 Status
= EFI_NOT_FOUND
;
1064 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1066 ASSERT (EfiSb
!= NULL
);
1067 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1069 if (EFI_ERROR (Status
)) {
1072 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1073 Status
= gBS
->OpenProtocol (
1074 Private
->IpChildHandle
,
1075 &gEfiIp6ProtocolGuid
,
1076 &Private
->IpProtocol
,
1078 Private
->IpChildHandle
,
1079 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1081 if (EFI_ERROR (Status
)) {
1086 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1089 // Configure the ip6 instance for icmp6 packet exchange.
1091 Ip6Config
.DefaultProtocol
= 58;
1092 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1093 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1094 Ip6Config
.AcceptPromiscuous
= FALSE
;
1095 Ip6Config
.TrafficClass
= 0;
1096 Ip6Config
.HopLimit
= 128;
1097 Ip6Config
.FlowLabel
= 0;
1098 Ip6Config
.ReceiveTimeout
= 0;
1099 Ip6Config
.TransmitTimeout
= 0;
1101 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1102 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1104 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1106 if (EFI_ERROR (Status
)) {
1107 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1111 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1112 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1113 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1114 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1116 Status
= gBS
->OpenProtocol (
1117 Private
->IpChildHandle
,
1118 &gEfiIp4ProtocolGuid
,
1119 &Private
->IpProtocol
,
1121 Private
->IpChildHandle
,
1122 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1124 if (EFI_ERROR (Status
)) {
1129 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1132 // Configure the ip4 instance for icmp4 packet exchange.
1134 // PING_IP4_COPY_ADDRESS (&Ip4Config.StationAddress, &Private->SrcAddress);
1135 // Ip4Config.SubnetMask.Addr[0] = 0xFF;
1136 // Ip4Config.SubnetMask.Addr[1] = 0xFF;
1137 // Ip4Config.SubnetMask.Addr[2] = 0xFF;
1138 // Ip4Config.SubnetMask.Addr[3] = 0x00;
1139 Ip4Config
.DefaultProtocol
= 1;
1140 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1141 Ip4Config
.AcceptBroadcast
= FALSE
;
1142 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1143 Ip4Config
.AcceptPromiscuous
= FALSE
;
1144 Ip4Config
.DoNotFragment
= FALSE
;
1145 Ip4Config
.RawData
= FALSE
;
1146 Ip4Config
.ReceiveTimeout
= 0;
1147 Ip4Config
.TransmitTimeout
= 0;
1148 Ip4Config
.UseDefaultAddress
= TRUE
;
1149 Ip4Config
.TimeToLive
= 128;
1150 Ip4Config
.TypeOfService
= 0;
1152 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1154 if (EFI_ERROR (Status
)) {
1155 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1159 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1160 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1161 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1162 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1165 if (HandleBuffer
!= NULL
) {
1166 FreePool (HandleBuffer
);
1172 if (HandleBuffer
!= NULL
) {
1173 FreePool (HandleBuffer
);
1176 if (IpXInterfaceInfo
!= NULL
) {
1177 FreePool (IpXInterfaceInfo
);
1180 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1181 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1188 Destory the IP instance.
1190 @param[in] Private The pointer of PING_PRIVATE_DATA.
1195 Ping6DestoryIp6Instance (
1196 IN PING_PRIVATE_DATA
*Private
1200 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1202 gBS
->CloseProtocol (
1203 Private
->IpChildHandle
,
1204 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1206 Private
->IpChildHandle
1209 Status
= gBS
->HandleProtocol (
1211 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1215 if (!EFI_ERROR(Status
)) {
1216 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1223 @param[in] SendNumber The send request count.
1224 @param[in] BufferSize The send buffer size.
1225 @param[in] SrcAddress The source address.
1226 @param[in] DstAddress The destination address.
1227 @param[in] IpChoice The choice between IPv4 and IPv6.
1229 @retval SHELL_SUCCESS The ping processed successfullly.
1230 @retval others The ping processed unsuccessfully.
1235 IN UINT32 SendNumber
,
1236 IN UINT32 BufferSize
,
1237 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1238 IN EFI_IPv6_ADDRESS
*DstAddress
,
1243 PING_PRIVATE_DATA
*Private
;
1244 PING_ICMPX_TX_INFO
*TxInfo
;
1246 LIST_ENTRY
*NextEntry
;
1247 SHELL_STATUS ShellStatus
;
1249 ShellStatus
= SHELL_SUCCESS
;
1250 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1252 if (Private
== NULL
) {
1253 return (SHELL_OUT_OF_RESOURCES
);
1256 Private
->IpChoice
= IpChoice
;
1257 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1258 Private
->SendNum
= SendNumber
;
1259 Private
->BufferSize
= BufferSize
;
1260 Private
->RttMin
= ~((UINT64
)(0x0));
1261 Private
->Status
= EFI_NOT_READY
;
1263 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1264 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1266 InitializeListHead (&Private
->TxList
);
1269 // Open and configure a ip instance for us.
1271 Status
= PingCreateIpInstance (Private
);
1273 if (EFI_ERROR (Status
)) {
1274 ShellStatus
= SHELL_ACCESS_DENIED
;
1278 // Print the command line itself.
1280 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1282 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1284 Status
= Ping6ReceiveEchoReply (Private
);
1286 if (EFI_ERROR (Status
)) {
1287 ShellStatus
= SHELL_ACCESS_DENIED
;
1291 // Create and start timer to send icmp6 echo request packet per second.
1293 Status
= gBS
->CreateEvent (
1294 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1296 Ping6OnTimerRoutine
,
1301 if (EFI_ERROR (Status
)) {
1302 ShellStatus
= SHELL_ACCESS_DENIED
;
1306 // Create a ipv6 token to send the first icmp6 echo request packet.
1308 Status
= PingSendEchoRequest (Private
);
1310 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1312 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1313 ShellStatus
= SHELL_ACCESS_DENIED
;
1314 if(Status
== EFI_NOT_FOUND
) {
1315 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1316 } else if (Status
== RETURN_NO_MAPPING
) {
1317 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1319 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, Status
);
1325 Status
= gBS
->SetTimer (
1331 if (EFI_ERROR (Status
)) {
1332 ShellStatus
= SHELL_ACCESS_DENIED
;
1336 // Control the ping6 process by two factors:
1338 // 2. Private->Status
1339 // 2.1. success means all icmp6 echo request packets get reply packets.
1340 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1341 // 2.3. noready means ping6 process is on-the-go.
1343 while (Private
->Status
== EFI_NOT_READY
) {
1344 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1345 if (ShellGetExecutionBreakFlag()) {
1346 Private
->Status
= EFI_ABORTED
;
1353 // Display the statistics in all.
1355 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1357 if (Private
->TxCount
!= 0) {
1362 STRING_TOKEN (STR_PING_STAT
),
1363 gShellNetwork1HiiHandle
,
1366 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
1371 if (Private
->RxCount
!= 0) {
1376 STRING_TOKEN (STR_PING_RTT
),
1377 gShellNetwork1HiiHandle
,
1380 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
1386 if (Private
!= NULL
) {
1388 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1389 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1391 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1392 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1395 RemoveEntryList (&TxInfo
->Link
);
1396 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1399 if (Private
->Timer
!= NULL
) {
1400 gBS
->CloseEvent (Private
->Timer
);
1403 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1404 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1407 if (Private
->RxToken
.Event
!= NULL
) {
1408 gBS
->CloseEvent (Private
->RxToken
.Event
);
1411 if (Private
->IpChildHandle
!= NULL
) {
1412 Ping6DestoryIp6Instance (Private
);
1422 Function for 'ping' command.
1424 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1425 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1429 ShellCommandRunPing (
1430 IN EFI_HANDLE ImageHandle
,
1431 IN EFI_SYSTEM_TABLE
*SystemTable
1435 SHELL_STATUS ShellStatus
;
1436 EFI_IPv6_ADDRESS DstAddress
;
1437 EFI_IPv6_ADDRESS SrcAddress
;
1440 LIST_ENTRY
*ParamPackage
;
1441 CONST CHAR16
*ValueStr
;
1442 UINTN NonOptionCount
;
1446 // we use IPv6 buffers to hold items...
1447 // make sure this is enough space!
1449 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1450 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1452 IpChoice
= PING_IP_CHOICE_IP4
;
1454 ShellStatus
= SHELL_SUCCESS
;
1456 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, NULL
, TRUE
, FALSE
);
1457 if (EFI_ERROR(Status
)) {
1458 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
);
1459 ShellStatus
= SHELL_INVALID_PARAMETER
;
1463 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1464 IpChoice
= PING_IP_CHOICE_IP6
;
1468 // Parse the paramter of count number.
1470 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1471 if (ValueStr
!= NULL
) {
1472 SendNumber
= ShellStrToUintn (ValueStr
);
1475 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1477 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1478 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1479 ShellStatus
= SHELL_INVALID_PARAMETER
;
1483 SendNumber
= DEFAULT_SEND_COUNT
;
1486 // Parse the paramter of buffer size.
1488 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1489 if (ValueStr
!= NULL
) {
1490 BufferSize
= ShellStrToUintn (ValueStr
);
1493 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1495 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1496 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1497 ShellStatus
= SHELL_INVALID_PARAMETER
;
1501 BufferSize
= DEFAULT_BUFFER_SIZE
;
1504 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1505 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1508 // Parse the paramter of source ip address.
1510 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1511 if (ValueStr
!= NULL
) {
1512 mSrcString
= ValueStr
;
1513 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1514 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1516 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1518 if (EFI_ERROR (Status
)) {
1519 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1520 ShellStatus
= SHELL_INVALID_PARAMETER
;
1525 // Parse the paramter of destination ip address.
1527 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1528 if (NonOptionCount
< 2) {
1529 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
);
1530 ShellStatus
= SHELL_INVALID_PARAMETER
;
1533 if (NonOptionCount
> 2) {
1534 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
);
1535 ShellStatus
= SHELL_INVALID_PARAMETER
;
1538 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1539 if (ValueStr
!= NULL
) {
1540 mDstString
= ValueStr
;
1541 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1542 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1544 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1546 if (EFI_ERROR (Status
)) {
1547 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1548 ShellStatus
= SHELL_INVALID_PARAMETER
;
1553 // Get frequency to calculate the time from ticks.
1555 Status
= GetFrequency ();
1557 if (EFI_ERROR(Status
)) {
1561 // Enter into ping process.
1563 ShellStatus
= ShellPing (
1572 ShellCommandLineFreeVarList (ParamPackage
);