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
;
147 Calculate the internet checksum (see RFC 1071)
151 Packet - Buffer which contains the data to be checksummed
152 Length - Length to be checksummed
156 Checksum - Returns the 16 bit ones complement of
157 ones complement sum of 16 bit words
165 Packet
= (UINT16
*) Buffer
;
168 Odd
= (UINT8
) (Length
& 1);
175 Sum
+= *(UINT8
*) Packet
;
178 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
181 // in case above carried
189 Reads and returns the current value of register.
190 In IA64, the register is the Interval Timer Vector (ITV).
191 In X86(IA32/X64), the register is the Time Stamp Counter (TSC)
193 @return The current value of the register.
202 STATIC CONST SHELL_PARAM_ITEM PingParamList
[] = {
226 // Global Variables in Ping command.
228 STATIC CONST CHAR16
*mDstString
;
229 STATIC CONST CHAR16
*mSrcString
;
230 STATIC UINT64 mFrequency
= 0;
233 Get and caculate the frequency in tick/ms.
234 The result is saved in the globle variable mFrequency
236 @retval EFI_SUCCESS Caculated the frequency successfully.
237 @retval Others Failed to caculate the frequency.
247 EFI_CPU_ARCH_PROTOCOL
*Cpu
;
251 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &Cpu
);
253 if (EFI_ERROR (Status
)) {
257 Status
= Cpu
->GetTimerValue (Cpu
, 0, &CurrentTick
, &TimerPeriod
);
259 if (EFI_ERROR (Status
)) {
260 TimerPeriod
= DEFAULT_TIMER_PERIOD
;
264 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
265 // So 1e+12 is divided by timer period to produce the freq in tick/ms.
267 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
273 Caculate a duration in ms.
275 @param[in] Begin The start point of time.
276 @param[in] End The end point of time.
278 @return The duration in ms.
279 @retval 0 The parameters were not valid.
291 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
295 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
297 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
298 @param[in] IpChoice Whether the token is IPv4 or IPv6
303 IN PING_ICMPX_TX_INFO
*TxInfo
,
307 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
308 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
309 EFI_IP6_FRAGMENT_DATA
*FragData
;
312 if (TxInfo
== NULL
) {
316 if (TxInfo
->Token
!= NULL
) {
318 if (TxInfo
->Token
->Event
!= NULL
) {
319 gBS
->CloseEvent (TxInfo
->Token
->Event
);
322 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
323 if (IpChoice
== PING_IP_CHOICE_IP6
) {
324 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
326 if (Ip6TxData
->OverrideData
!= NULL
) {
327 FreePool (Ip6TxData
->OverrideData
);
330 if (Ip6TxData
->ExtHdrs
!= NULL
) {
331 FreePool (Ip6TxData
->ExtHdrs
);
334 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
335 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
336 if (FragData
!= NULL
) {
341 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
343 if (Ip4TxData
->OverrideData
!= NULL
) {
344 FreePool (Ip4TxData
->OverrideData
);
347 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
348 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
349 if (FragData
!= NULL
) {
356 FreePool (TxInfo
->Token
);
363 Match the request, and reply with SequenceNum/TimeStamp.
365 @param[in] Private The pointer to PING_PRIVATE_DATA.
366 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
368 @retval EFI_SUCCESS The match is successful.
369 @retval EFI_NOT_FOUND The reply can't be matched with any request.
374 Ping6MatchEchoReply (
375 IN PING_PRIVATE_DATA
*Private
,
376 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
379 PING_ICMPX_TX_INFO
*TxInfo
;
381 LIST_ENTRY
*NextEntry
;
383 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
384 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
386 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
388 RemoveEntryList (&TxInfo
->Link
);
389 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
394 return EFI_NOT_FOUND
;
398 The original intention is to send a request.
399 Currently, the application retransmits an icmp6 echo request packet
400 per second in sendnumber times that is specified by the user.
401 Because nothing can be done here, all things move to the timer rountine.
403 @param[in] Event A EFI_EVENT type event.
404 @param[in] Context The pointer to Context.
409 Ping6OnEchoRequestSent (
417 receive reply, match and print reply infomation.
419 @param[in] Event A EFI_EVENT type event.
420 @param[in] Context The pointer to context.
425 Ping6OnEchoReplyReceived (
431 PING_PRIVATE_DATA
*Private
;
432 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
437 Private
= (PING_PRIVATE_DATA
*) Context
;
439 if (Private
== NULL
|| Private
->Status
== EFI_ABORTED
|| Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
443 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
447 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
448 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
449 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
450 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
453 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
454 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
)) {
458 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
462 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
463 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
464 if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
465 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
)) {
469 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
475 if (PayLoad
!= Private
->BufferSize
) {
479 // Check whether the reply matches the sent request before.
481 Status
= Ping6MatchEchoReply (Private
, Reply
);
482 if (EFI_ERROR(Status
)) {
486 // Display statistics on this icmp6 echo reply packet.
488 Rtt
= CalculateTick (Reply
->TimeStamp
, ReadTime ());
495 Private
->RttSum
+= Rtt
;
496 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
497 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
503 STRING_TOKEN (STR_PING_REPLY_INFO
),
504 gShellNetwork1HiiHandle
,
508 Private
->IpChoice
== PING_IP_CHOICE_IP6
?((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
:0,
515 if (Private
->RxCount
< Private
->SendNum
) {
517 // Continue to receive icmp echo reply packets.
519 Private
->RxToken
.Status
= EFI_ABORTED
;
521 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
523 if (EFI_ERROR (Status
)) {
524 Private
->Status
= EFI_ABORTED
;
528 // All reply have already been received from the dest host.
530 Private
->Status
= EFI_SUCCESS
;
533 // Singal to recycle the each rxdata here, not at the end of process.
535 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
);
539 Create a PING_IPX_COMPLETION_TOKEN.
541 @param[in] Private The pointer of PING_PRIVATE_DATA.
542 @param[in] TimeStamp The TimeStamp of request.
543 @param[in] SequenceNum The SequenceNum of request.
545 @return The pointer of PING_IPX_COMPLETION_TOKEN.
548 PING_IPX_COMPLETION_TOKEN
*
551 IN PING_PRIVATE_DATA
*Private
,
553 IN UINT16 SequenceNum
557 PING_IPX_COMPLETION_TOKEN
*Token
;
559 ICMPX_ECHO_REQUEST_REPLY
*Request
;
563 Request
= AllocateZeroPool (Private
->BufferSize
);
564 if (Request
== NULL
) {
567 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
568 if (TxData
== NULL
) {
572 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
580 // Assembly echo request packet.
582 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
584 Request
->SequenceNum
= SequenceNum
;
585 Request
->Identifier
= 0;
586 Request
->Checksum
= 0;
589 // Assembly token for transmit.
591 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
592 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
593 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
594 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
595 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
596 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
597 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
598 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
600 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
601 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
602 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
603 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
604 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
605 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
606 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
607 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
608 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
609 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
610 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
612 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
613 Request
->TimeStamp
= TimeStamp
;
614 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
615 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
619 Token
->Status
= EFI_ABORTED
;
620 Token
->Packet
.TxData
= TxData
;
622 Status
= gBS
->CreateEvent (
625 Ping6OnEchoRequestSent
,
630 if (EFI_ERROR (Status
)) {
641 Transmit the PING_IPX_COMPLETION_TOKEN.
643 @param[in] Private The pointer of PING_PRIVATE_DATA.
645 @retval EFI_SUCCESS Transmitted successfully.
646 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
647 @retval others Transmitted unsuccessfully.
652 PingSendEchoRequest (
653 IN PING_PRIVATE_DATA
*Private
657 PING_ICMPX_TX_INFO
*TxInfo
;
659 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
661 if (TxInfo
== NULL
) {
662 return EFI_OUT_OF_RESOURCES
;
665 TxInfo
->TimeStamp
= ReadTime ();
666 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
667 TxInfo
->Token
= PingGenerateToken (
673 if (TxInfo
->Token
== NULL
) {
674 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
675 return EFI_OUT_OF_RESOURCES
;
678 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
679 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
681 if (EFI_ERROR (Status
)) {
682 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
686 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
693 Place a completion token into the receive packet queue to receive the echo reply.
695 @param[in] Private The pointer of PING_PRIVATE_DATA.
697 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
698 @retval others Put the token into the receive packet queue unsuccessfully.
703 Ping6ReceiveEchoReply (
704 IN PING_PRIVATE_DATA
*Private
709 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
711 Status
= gBS
->CreateEvent (
714 Ping6OnEchoReplyReceived
,
716 &Private
->RxToken
.Event
719 if (EFI_ERROR (Status
)) {
723 Private
->RxToken
.Status
= EFI_NOT_READY
;
725 return (Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
));
729 Remove the timeout request from the list.
731 @param[in] Event A EFI_EVENT type event.
732 @param[in] Context The pointer to Context.
737 Ping6OnTimerRoutine (
743 PING_PRIVATE_DATA
*Private
;
744 PING_ICMPX_TX_INFO
*TxInfo
;
746 LIST_ENTRY
*NextEntry
;
749 Private
= (PING_PRIVATE_DATA
*) Context
;
750 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
751 Private
->Status
= EFI_NOT_FOUND
;
756 // Retransmit icmp6 echo request packets per second in sendnumber times.
758 if (Private
->TxCount
< Private
->SendNum
) {
760 Status
= PingSendEchoRequest (Private
);
761 if (Private
->TxCount
!= 0){
762 if (EFI_ERROR (Status
)) {
763 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
768 // Check whether any icmp6 echo request in the list timeout.
770 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
771 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
772 Time
= CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
775 // Remove the timeout echo request from txlist.
777 if (Time
> DEFAULT_TIMEOUT
) {
779 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
780 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
783 // Remove the timeout icmp6 echo request from list.
785 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
787 RemoveEntryList (&TxInfo
->Link
);
788 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
791 // We dont need to wait for this some other time...
795 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
797 // All the left icmp6 echo request in the list timeout.
799 Private
->Status
= EFI_TIMEOUT
;
806 Determine if a IP4 address is Link Local.
808 169.254.1.0 through 169.254.254.255 is link local.
810 @param[in] Address The address to test.
813 @retval FALSE It is not.
817 PingNetIp4IsLinkLocalAddr (
818 IN CONST EFI_IPv4_ADDRESS
*Address
821 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
825 Determine if a IP4 address is unspecified.
827 @param[in] Address The address to test.
830 @retval FALSE It is not.
834 PingNetIp4IsUnspecifiedAddr (
835 IN CONST EFI_IPv4_ADDRESS
*Address
838 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
842 Create a valid IP instance.
844 @param[in] Private The pointer of PING_PRIVATE_DATA.
846 @retval EFI_SUCCESS Create a valid IPx instance successfully.
847 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
848 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
849 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
850 @retval EFI_NOT_FOUND The source address is not found.
854 PingCreateIpInstance (
855 IN PING_PRIVATE_DATA
*Private
861 EFI_HANDLE
*HandleBuffer
;
862 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
864 EFI_IP6_CONFIG_DATA Ip6Config
;
865 EFI_IP4_CONFIG_DATA Ip4Config
;
866 VOID
*IpXInterfaceInfo
;
868 EFI_IPv6_ADDRESS
*Addr
;
873 IpXInterfaceInfo
= NULL
;
877 // Locate all the handles with ip6 service binding protocol.
879 Status
= gBS
->LocateHandleBuffer (
881 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
886 if (EFI_ERROR (Status
) || (HandleNum
== 0)) {
890 // Source address is required when pinging a link-local address on multi-
893 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
894 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
895 NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) &&
897 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, mSrcString
);
898 Status
= EFI_INVALID_PARAMETER
;
902 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
903 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) &&
904 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
) &&
906 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, mSrcString
);
907 Status
= EFI_INVALID_PARAMETER
;
912 // For each ip6 protocol, check interface addresses list.
914 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
917 IpXInterfaceInfo
= NULL
;
920 Status
= gBS
->HandleProtocol (
921 HandleBuffer
[HandleIndex
],
922 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
925 if (EFI_ERROR (Status
)) {
929 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
?NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
):PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
931 // No need to match interface address.
936 // Ip6config protocol and ip6 service binding protocol are installed
937 // on the same handle.
939 Status
= gBS
->HandleProtocol (
940 HandleBuffer
[HandleIndex
],
941 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4ConfigProtocolGuid
,
945 if (EFI_ERROR (Status
)) {
949 // Get the interface information size.
951 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
952 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
954 Ip6ConfigDataTypeInterfaceInfo
,
959 Status
= ((EFI_IP4_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
967 // Skip the ones not in current use.
969 if (Status
== EFI_NOT_STARTED
) {
973 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
974 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
978 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
980 if (IpXInterfaceInfo
== NULL
) {
981 Status
= EFI_OUT_OF_RESOURCES
;
985 // Get the interface info.
987 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
988 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
990 Ip6ConfigDataTypeInterfaceInfo
,
995 Status
= ((EFI_IP4_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1002 if (EFI_ERROR (Status
)) {
1003 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1007 // Check whether the source address is one of the interface addresses.
1009 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1010 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1012 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1013 if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1015 // Match a certain interface address.
1021 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1023 // Found a nic handle with right interface address.
1029 // IP4 address check
1031 if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_IPCONFIG_DATA
*)IpXInterfaceInfo
)->StationAddress
)) {
1033 // Match a certain interface address.
1040 FreePool (IpXInterfaceInfo
);
1041 IpXInterfaceInfo
= NULL
;
1044 // No exact interface address matched.
1047 if (HandleIndex
== HandleNum
) {
1048 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, mSrcString
);
1049 Status
= EFI_NOT_FOUND
;
1053 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1055 ASSERT (EfiSb
!= NULL
);
1056 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1058 if (EFI_ERROR (Status
)) {
1061 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1062 Status
= gBS
->OpenProtocol (
1063 Private
->IpChildHandle
,
1064 &gEfiIp6ProtocolGuid
,
1065 &Private
->IpProtocol
,
1067 Private
->IpChildHandle
,
1068 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1070 if (EFI_ERROR (Status
)) {
1075 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1078 // Configure the ip6 instance for icmp6 packet exchange.
1080 Ip6Config
.DefaultProtocol
= 58;
1081 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1082 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1083 Ip6Config
.AcceptPromiscuous
= FALSE
;
1084 Ip6Config
.TrafficClass
= 0;
1085 Ip6Config
.HopLimit
= 128;
1086 Ip6Config
.FlowLabel
= 0;
1087 Ip6Config
.ReceiveTimeout
= 0;
1088 Ip6Config
.TransmitTimeout
= 0;
1090 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1091 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1093 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1095 if (EFI_ERROR (Status
)) {
1096 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1100 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1101 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1102 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1103 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1105 Status
= gBS
->OpenProtocol (
1106 Private
->IpChildHandle
,
1107 &gEfiIp4ProtocolGuid
,
1108 &Private
->IpProtocol
,
1110 Private
->IpChildHandle
,
1111 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1113 if (EFI_ERROR (Status
)) {
1118 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1121 // Configure the ip4 instance for icmp4 packet exchange.
1123 // PING_IP4_COPY_ADDRESS (&Ip4Config.StationAddress, &Private->SrcAddress);
1124 // Ip4Config.SubnetMask.Addr[0] = 0xFF;
1125 // Ip4Config.SubnetMask.Addr[1] = 0xFF;
1126 // Ip4Config.SubnetMask.Addr[2] = 0xFF;
1127 // Ip4Config.SubnetMask.Addr[3] = 0x00;
1128 Ip4Config
.DefaultProtocol
= 1;
1129 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1130 Ip4Config
.AcceptBroadcast
= FALSE
;
1131 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1132 Ip4Config
.AcceptPromiscuous
= FALSE
;
1133 Ip4Config
.DoNotFragment
= FALSE
;
1134 Ip4Config
.RawData
= FALSE
;
1135 Ip4Config
.ReceiveTimeout
= 0;
1136 Ip4Config
.TransmitTimeout
= 0;
1137 Ip4Config
.UseDefaultAddress
= TRUE
;
1138 Ip4Config
.TimeToLive
= 128;
1139 Ip4Config
.TypeOfService
= 0;
1141 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1143 if (EFI_ERROR (Status
)) {
1144 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1148 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1149 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1150 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1151 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1154 if (HandleBuffer
!= NULL
) {
1155 FreePool (HandleBuffer
);
1161 if (HandleBuffer
!= NULL
) {
1162 FreePool (HandleBuffer
);
1165 if (IpXInterfaceInfo
!= NULL
) {
1166 FreePool (IpXInterfaceInfo
);
1169 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1170 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1177 Destory the IP instance.
1179 @param[in] Private The pointer of PING_PRIVATE_DATA.
1184 Ping6DestoryIp6Instance (
1185 IN PING_PRIVATE_DATA
*Private
1189 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1191 gBS
->CloseProtocol (
1192 Private
->IpChildHandle
,
1193 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1195 Private
->IpChildHandle
1198 Status
= gBS
->HandleProtocol (
1200 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1204 if (!EFI_ERROR(Status
)) {
1205 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1212 @param[in] SendNumber The send request count.
1213 @param[in] BufferSize The send buffer size.
1214 @param[in] SrcAddress The source address.
1215 @param[in] DstAddress The destination address.
1216 @param[in] IpChoice The choice between IPv4 and IPv6.
1218 @retval SHELL_SUCCESS The ping processed successfullly.
1219 @retval others The ping processed unsuccessfully.
1224 IN UINT32 SendNumber
,
1225 IN UINT32 BufferSize
,
1226 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1227 IN EFI_IPv6_ADDRESS
*DstAddress
,
1232 PING_PRIVATE_DATA
*Private
;
1233 PING_ICMPX_TX_INFO
*TxInfo
;
1235 LIST_ENTRY
*NextEntry
;
1236 SHELL_STATUS ShellStatus
;
1238 ShellStatus
= SHELL_SUCCESS
;
1239 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1241 if (Private
== NULL
) {
1242 return (SHELL_OUT_OF_RESOURCES
);
1245 Private
->IpChoice
= IpChoice
;
1246 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1247 Private
->SendNum
= SendNumber
;
1248 Private
->BufferSize
= BufferSize
;
1249 Private
->RttMin
= ~((UINT64
)(0x0));
1250 Private
->Status
= EFI_NOT_READY
;
1252 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1253 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1255 InitializeListHead (&Private
->TxList
);
1258 // Open and configure a ip instance for us.
1260 Status
= PingCreateIpInstance (Private
);
1262 if (EFI_ERROR (Status
)) {
1263 ShellStatus
= SHELL_ACCESS_DENIED
;
1267 // Print the command line itself.
1269 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1271 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1273 Status
= Ping6ReceiveEchoReply (Private
);
1275 if (EFI_ERROR (Status
)) {
1276 ShellStatus
= SHELL_ACCESS_DENIED
;
1280 // Create and start timer to send icmp6 echo request packet per second.
1282 Status
= gBS
->CreateEvent (
1283 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1285 Ping6OnTimerRoutine
,
1290 if (EFI_ERROR (Status
)) {
1291 ShellStatus
= SHELL_ACCESS_DENIED
;
1295 // Create a ipv6 token to send the first icmp6 echo request packet.
1297 Status
= PingSendEchoRequest (Private
);
1299 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1301 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1302 ShellStatus
= SHELL_ACCESS_DENIED
;
1303 if(Status
== EFI_NOT_FOUND
) {
1304 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1305 } else if (Status
== RETURN_NO_MAPPING
) {
1306 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1308 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, Status
);
1314 Status
= gBS
->SetTimer (
1320 if (EFI_ERROR (Status
)) {
1321 ShellStatus
= SHELL_ACCESS_DENIED
;
1325 // Control the ping6 process by two factors:
1327 // 2. Private->Status
1328 // 2.1. success means all icmp6 echo request packets get reply packets.
1329 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1330 // 2.3. noready means ping6 process is on-the-go.
1332 while (Private
->Status
== EFI_NOT_READY
) {
1333 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1334 if (ShellGetExecutionBreakFlag()) {
1335 Private
->Status
= EFI_ABORTED
;
1342 // Display the statistics in all.
1344 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1346 if (Private
->TxCount
!= 0) {
1351 STRING_TOKEN (STR_PING_STAT
),
1352 gShellNetwork1HiiHandle
,
1355 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
1360 if (Private
->RxCount
!= 0) {
1365 STRING_TOKEN (STR_PING_RTT
),
1366 gShellNetwork1HiiHandle
,
1369 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
1375 if (Private
!= NULL
) {
1377 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1378 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1380 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1381 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1384 RemoveEntryList (&TxInfo
->Link
);
1385 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1388 if (Private
->Timer
!= NULL
) {
1389 gBS
->CloseEvent (Private
->Timer
);
1392 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1393 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1396 if (Private
->RxToken
.Event
!= NULL
) {
1397 gBS
->CloseEvent (Private
->RxToken
.Event
);
1400 if (Private
->IpChildHandle
!= NULL
) {
1401 Ping6DestoryIp6Instance (Private
);
1411 Function for 'ping' command.
1413 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1414 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1418 ShellCommandRunPing (
1419 IN EFI_HANDLE ImageHandle
,
1420 IN EFI_SYSTEM_TABLE
*SystemTable
1424 SHELL_STATUS ShellStatus
;
1425 EFI_IPv6_ADDRESS DstAddress
;
1426 EFI_IPv6_ADDRESS SrcAddress
;
1429 LIST_ENTRY
*ParamPackage
;
1430 CONST CHAR16
*ValueStr
;
1431 UINTN NonOptionCount
;
1435 // we use IPv6 buffers to hold items...
1436 // make sure this is enough space!
1438 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1439 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1441 IpChoice
= PING_IP_CHOICE_IP4
;
1443 ShellStatus
= SHELL_SUCCESS
;
1445 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, NULL
, TRUE
, FALSE
);
1446 if (EFI_ERROR(Status
)) {
1447 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
);
1448 ShellStatus
= SHELL_INVALID_PARAMETER
;
1452 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1453 IpChoice
= PING_IP_CHOICE_IP6
;
1457 // Parse the paramter of count number.
1459 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1460 if (ValueStr
!= NULL
) {
1461 SendNumber
= ShellStrToUintn (ValueStr
);
1464 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1466 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1467 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1468 ShellStatus
= SHELL_INVALID_PARAMETER
;
1472 SendNumber
= DEFAULT_SEND_COUNT
;
1475 // Parse the paramter of buffer size.
1477 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1478 if (ValueStr
!= NULL
) {
1479 BufferSize
= ShellStrToUintn (ValueStr
);
1482 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1484 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1485 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1486 ShellStatus
= SHELL_INVALID_PARAMETER
;
1490 BufferSize
= DEFAULT_BUFFER_SIZE
;
1493 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1494 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1497 // Parse the paramter of source ip address.
1499 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1500 if (ValueStr
!= NULL
) {
1501 mSrcString
= ValueStr
;
1502 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1503 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1505 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1507 if (EFI_ERROR (Status
)) {
1508 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1509 ShellStatus
= SHELL_INVALID_PARAMETER
;
1514 // Parse the paramter of destination ip address.
1516 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1517 if (NonOptionCount
< 2) {
1518 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
);
1519 ShellStatus
= SHELL_INVALID_PARAMETER
;
1522 if (NonOptionCount
> 2) {
1523 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
);
1524 ShellStatus
= SHELL_INVALID_PARAMETER
;
1527 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1528 if (ValueStr
!= NULL
) {
1529 mDstString
= ValueStr
;
1530 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1531 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1533 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1535 if (EFI_ERROR (Status
)) {
1536 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellNetwork1HiiHandle
, ValueStr
);
1537 ShellStatus
= SHELL_INVALID_PARAMETER
;
1542 // Get frequency to calculate the time from ticks.
1544 Status
= GetFrequency ();
1546 if (EFI_ERROR(Status
)) {
1550 // Enter into ping process.
1552 ShellStatus
= ShellPing (
1561 ShellCommandLineFreeVarList (ParamPackage
);