2 The implementation for Ping shell command.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php.
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "UefiShellNetwork1CommandsLib.h"
20 #define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))
22 UINT64 mCurrentTick
= 0;
25 // Function templates to match the IPv4 and IPv6 commands that we use.
29 (EFIAPI
*PING_IPX_POLL
)(
35 (EFIAPI
*PING_IPX_TRANSMIT
)(
42 (EFIAPI
*PING_IPX_RECEIVE
)(
49 (EFIAPI
*PING_IPX_CANCEL
)(
51 IN VOID
*Token OPTIONAL
55 /// A set of pointers to either IPv6 or IPv4 functions.
56 /// Unknown which one to the ping command.
59 PING_IPX_TRANSMIT Transmit
;
60 PING_IPX_RECEIVE Receive
;
61 PING_IPX_CANCEL Cancel
;
72 // PING_IPX_COMPLETION_TOKEN
73 // structures are used for both transmit and receive operations.
74 // This version is IP-unaware.
80 } PING_IPX_COMPLETION_TOKEN
;
83 typedef struct _ICMPX_ECHO_REQUEST_REPLY
{
91 } ICMPX_ECHO_REQUEST_REPLY
;
94 typedef struct _PING_ICMP_TX_INFO
{
98 PING_IPX_COMPLETION_TOKEN
*Token
;
101 #define DEFAULT_TIMEOUT 5000
102 #define MAX_SEND_NUMBER 10000
103 #define MAX_BUFFER_SIZE 32768
104 #define DEFAULT_TIMER_PERIOD 358049
105 #define ONE_SECOND 10000000
106 #define PING_IP_CHOICE_IP4 1
107 #define PING_IP_CHOICE_IP6 2
108 #define DEFAULT_SEND_COUNT 10
109 #define DEFAULT_BUFFER_SIZE 16
110 #define ICMP_V4_ECHO_REQUEST 0x8
111 #define ICMP_V4_ECHO_REPLY 0x0
113 #define PING_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'i', 'n', 'g')
114 typedef struct _PING_PRIVATE_DATA
{
116 EFI_HANDLE NicHandle
;
117 EFI_HANDLE IpChildHandle
;
133 PING_IPX_PROTOCOL ProtocolPointers
;
135 UINT8 SrcAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
136 UINT8 DstAddress
[MAX(sizeof(EFI_IPv6_ADDRESS
) , sizeof(EFI_IPv4_ADDRESS
) )];
137 PING_IPX_COMPLETION_TOKEN RxToken
;
142 Calculate the internet checksum (see RFC 1071).
144 @param[in] Packet Buffer which contains the data to be checksummed.
145 @param[in] Length Length to be checksummed.
147 @retval Checksum Returns the 16 bit ones complement of
148 ones complement sum of 16 bit words
161 Packet
= (UINT16
*) Buffer
;
164 Odd
= (UINT8
) (Length
& 1);
166 while ((Length
--) != 0) {
171 Sum
+= *(UINT8
*) Packet
;
174 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
177 // in case above carried
185 Reads and returns the current value of register.
186 In IA64, the register is the Interval Timer Vector (ITV).
187 In X86(IA32/X64), the register is the Time Stamp Counter (TSC)
189 @return The current value of the register.
193 STATIC CONST SHELL_PARAM_ITEM PingParamList
[] = {
221 // Global Variables in Ping command.
223 STATIC CONST CHAR16
*mDstString
;
224 STATIC CONST CHAR16
*mSrcString
;
225 STATIC UINT64 mFrequency
= 0;
226 EFI_CPU_ARCH_PROTOCOL
*gCpu
= NULL
;
229 Read the current time.
231 @retval the current tick value.
242 ASSERT (gCpu
!= NULL
);
244 Status
= gCpu
->GetTimerValue (gCpu
, 0, &mCurrentTick
, &TimerPeriod
);
245 if (EFI_ERROR (Status
)) {
247 // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the
248 // TimerPeriod by ourselves.
250 mCurrentTick
+= 1000000;
258 Get and calculate the frequency in ticks/ms.
259 The result is saved in the global variable mFrequency
261 @retval EFI_SUCCESS Calculated the frequency successfully.
262 @retval Others Failed to calculate the frequency.
275 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &gCpu
);
276 if (EFI_ERROR (Status
)) {
280 Status
= gCpu
->GetTimerValue (gCpu
, 0, &CurrentTick
, &TimerPeriod
);
282 if (EFI_ERROR (Status
)) {
283 TimerPeriod
= DEFAULT_TIMER_PERIOD
;
287 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
288 // So 1e+12 is divided by timer period to produce the freq in ticks/ms.
290 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
296 Calculate a duration in ms.
298 @param[in] Begin The start point of time.
299 @param[in] End The end point of time.
301 @return The duration in ms.
302 @retval 0 The parameters were not valid.
314 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
318 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
320 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
321 @param[in] IpChoice Whether the token is IPv4 or IPv6
326 IN PING_ICMPX_TX_INFO
*TxInfo
,
330 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
331 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
332 EFI_IP6_FRAGMENT_DATA
*FragData
;
335 if (TxInfo
== NULL
) {
339 if (TxInfo
->Token
!= NULL
) {
341 if (TxInfo
->Token
->Event
!= NULL
) {
342 gBS
->CloseEvent (TxInfo
->Token
->Event
);
345 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
346 if (IpChoice
== PING_IP_CHOICE_IP6
) {
347 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
349 if (Ip6TxData
->OverrideData
!= NULL
) {
350 FreePool (Ip6TxData
->OverrideData
);
353 if (Ip6TxData
->ExtHdrs
!= NULL
) {
354 FreePool (Ip6TxData
->ExtHdrs
);
357 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
358 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
359 if (FragData
!= NULL
) {
364 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
366 if (Ip4TxData
->OverrideData
!= NULL
) {
367 FreePool (Ip4TxData
->OverrideData
);
370 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
371 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
372 if (FragData
!= NULL
) {
379 FreePool (TxInfo
->Token
);
386 Match the request, and reply with SequenceNum/TimeStamp.
388 @param[in] Private The pointer to PING_PRIVATE_DATA.
389 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
391 @retval EFI_SUCCESS The match is successful.
392 @retval EFI_NOT_FOUND The reply can't be matched with any request.
397 Ping6MatchEchoReply (
398 IN PING_PRIVATE_DATA
*Private
,
399 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
402 PING_ICMPX_TX_INFO
*TxInfo
;
404 LIST_ENTRY
*NextEntry
;
406 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
407 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
409 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
411 RemoveEntryList (&TxInfo
->Link
);
412 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
417 return EFI_NOT_FOUND
;
421 The original intention is to send a request.
422 Currently, the application retransmits an icmp6 echo request packet
423 per second in sendnumber times that is specified by the user.
424 Because nothing can be done here, all things move to the timer rountine.
426 @param[in] Event A EFI_EVENT type event.
427 @param[in] Context The pointer to Context.
432 Ping6OnEchoRequestSent (
440 receive reply, match and print reply infomation.
442 @param[in] Event A EFI_EVENT type event.
443 @param[in] Context The pointer to context.
448 Ping6OnEchoReplyReceived (
454 PING_PRIVATE_DATA
*Private
;
455 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
460 Private
= (PING_PRIVATE_DATA
*) Context
;
462 if (Private
== NULL
|| Private
->Status
== EFI_ABORTED
|| Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
466 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
470 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
471 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
472 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
473 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
476 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
477 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
)) {
481 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
485 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
486 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
487 if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
488 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
)) {
492 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
498 if (PayLoad
!= Private
->BufferSize
) {
502 // Check whether the reply matches the sent request before.
504 Status
= Ping6MatchEchoReply (Private
, Reply
);
505 if (EFI_ERROR(Status
)) {
509 // Display statistics on this icmp6 echo reply packet.
511 Rtt
= CalculateTick (Reply
->TimeStamp
, ReadTime ());
518 Private
->RttSum
+= Rtt
;
519 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
520 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
526 STRING_TOKEN (STR_PING_REPLY_INFO
),
527 gShellNetwork1HiiHandle
,
531 Private
->IpChoice
== PING_IP_CHOICE_IP6
?((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
:0,
538 if (Private
->RxCount
< Private
->SendNum
) {
540 // Continue to receive icmp echo reply packets.
542 Private
->RxToken
.Status
= EFI_ABORTED
;
544 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
546 if (EFI_ERROR (Status
)) {
547 Private
->Status
= EFI_ABORTED
;
551 // All reply have already been received from the dest host.
553 Private
->Status
= EFI_SUCCESS
;
556 // Singal to recycle the each rxdata here, not at the end of process.
558 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
);
562 Create a PING_IPX_COMPLETION_TOKEN.
564 @param[in] Private The pointer of PING_PRIVATE_DATA.
565 @param[in] TimeStamp The TimeStamp of request.
566 @param[in] SequenceNum The SequenceNum of request.
568 @return The pointer of PING_IPX_COMPLETION_TOKEN.
571 PING_IPX_COMPLETION_TOKEN
*
574 IN PING_PRIVATE_DATA
*Private
,
576 IN UINT16 SequenceNum
580 PING_IPX_COMPLETION_TOKEN
*Token
;
582 ICMPX_ECHO_REQUEST_REPLY
*Request
;
586 Request
= AllocateZeroPool (Private
->BufferSize
);
587 if (Request
== NULL
) {
590 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
591 if (TxData
== NULL
) {
595 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
603 // Assembly echo request packet.
605 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
607 Request
->SequenceNum
= SequenceNum
;
608 Request
->Identifier
= 0;
609 Request
->Checksum
= 0;
612 // Assembly token for transmit.
614 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
615 Request
->TimeStamp
= TimeStamp
;
616 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
617 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
618 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
619 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
620 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
621 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
622 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
624 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
625 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
626 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
627 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
628 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
629 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
630 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
631 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
632 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
633 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
634 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
636 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
637 Request
->TimeStamp
= TimeStamp
;
638 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
639 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
643 Token
->Status
= EFI_ABORTED
;
644 Token
->Packet
.TxData
= TxData
;
646 Status
= gBS
->CreateEvent (
649 Ping6OnEchoRequestSent
,
654 if (EFI_ERROR (Status
)) {
665 Transmit the PING_IPX_COMPLETION_TOKEN.
667 @param[in] Private The pointer of PING_PRIVATE_DATA.
669 @retval EFI_SUCCESS Transmitted successfully.
670 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
671 @retval others Transmitted unsuccessfully.
676 PingSendEchoRequest (
677 IN PING_PRIVATE_DATA
*Private
681 PING_ICMPX_TX_INFO
*TxInfo
;
683 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
685 if (TxInfo
== NULL
) {
686 return EFI_OUT_OF_RESOURCES
;
689 TxInfo
->TimeStamp
= ReadTime ();
690 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
691 TxInfo
->Token
= PingGenerateToken (
697 if (TxInfo
->Token
== NULL
) {
698 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
699 return EFI_OUT_OF_RESOURCES
;
702 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
703 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
705 if (EFI_ERROR (Status
)) {
706 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
710 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
717 Place a completion token into the receive packet queue to receive the echo reply.
719 @param[in] Private The pointer of PING_PRIVATE_DATA.
721 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
722 @retval others Put the token into the receive packet queue unsuccessfully.
727 Ping6ReceiveEchoReply (
728 IN PING_PRIVATE_DATA
*Private
733 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
735 Status
= gBS
->CreateEvent (
738 Ping6OnEchoReplyReceived
,
740 &Private
->RxToken
.Event
743 if (EFI_ERROR (Status
)) {
747 Private
->RxToken
.Status
= EFI_NOT_READY
;
749 return (Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
));
753 Remove the timeout request from the list.
755 @param[in] Event A EFI_EVENT type event.
756 @param[in] Context The pointer to Context.
761 Ping6OnTimerRoutine (
767 PING_PRIVATE_DATA
*Private
;
768 PING_ICMPX_TX_INFO
*TxInfo
;
770 LIST_ENTRY
*NextEntry
;
773 Private
= (PING_PRIVATE_DATA
*) Context
;
774 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
775 Private
->Status
= EFI_NOT_FOUND
;
780 // Retransmit icmp6 echo request packets per second in sendnumber times.
782 if (Private
->TxCount
< Private
->SendNum
) {
784 Status
= PingSendEchoRequest (Private
);
785 if (Private
->TxCount
!= 0){
786 if (EFI_ERROR (Status
)) {
787 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
792 // Check whether any icmp6 echo request in the list timeout.
794 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
795 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
796 Time
= CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
799 // Remove the timeout echo request from txlist.
801 if (Time
> DEFAULT_TIMEOUT
) {
803 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
804 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
807 // Remove the timeout icmp6 echo request from list.
809 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
811 RemoveEntryList (&TxInfo
->Link
);
812 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
815 Private
->FailedCount
++;
817 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
819 // All the left icmp6 echo request in the list timeout.
821 Private
->Status
= EFI_TIMEOUT
;
828 Determine if a IP4 address is Link Local.
830 169.254.1.0 through 169.254.254.255 is link local.
832 @param[in] Address The address to test.
835 @retval FALSE It is not.
839 PingNetIp4IsLinkLocalAddr (
840 IN CONST EFI_IPv4_ADDRESS
*Address
843 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
847 Determine if a IP4 address is unspecified.
849 @param[in] Address The address to test.
852 @retval FALSE It is not.
856 PingNetIp4IsUnspecifiedAddr (
857 IN CONST EFI_IPv4_ADDRESS
*Address
860 return ((BOOLEAN
)((ReadUnaligned32 ((UINT32
*)&Address
->Addr
[0])) == 0x00000000));
864 Create a valid IP instance.
866 @param[in] Private The pointer of PING_PRIVATE_DATA.
868 @retval EFI_SUCCESS Create a valid IPx instance successfully.
869 @retval EFI_ABORTED Locate handle with ipx service binding protocol unsuccessfully.
870 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link-local address.
871 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
872 @retval EFI_NOT_FOUND The source address is not found.
876 PingCreateIpInstance (
877 IN PING_PRIVATE_DATA
*Private
883 EFI_HANDLE
*HandleBuffer
;
884 BOOLEAN UnspecifiedSrc
;
885 BOOLEAN MediaPresent
;
886 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
888 EFI_IP6_CONFIG_DATA Ip6Config
;
889 EFI_IP4_CONFIG_DATA Ip4Config
;
890 VOID
*IpXInterfaceInfo
;
892 EFI_IPv6_ADDRESS
*Addr
;
896 UnspecifiedSrc
= FALSE
;
899 IpXInterfaceInfo
= NULL
;
903 // Locate all the handles with ip6 service binding protocol.
905 Status
= gBS
->LocateHandleBuffer (
907 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
912 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
916 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
917 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
919 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
921 UnspecifiedSrc
= TRUE
;
925 // Source address is required when pinging a link-local address.
927 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
928 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
929 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
930 Status
= EFI_INVALID_PARAMETER
;
934 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
935 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
936 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
937 Status
= EFI_INVALID_PARAMETER
;
943 // For each ip6 protocol, check interface addresses list.
945 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
947 IpXInterfaceInfo
= NULL
;
950 if (UnspecifiedSrc
) {
954 NetLibDetectMedia (HandleBuffer
[HandleIndex
], &MediaPresent
);
963 Status
= gBS
->HandleProtocol (
964 HandleBuffer
[HandleIndex
],
965 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
968 if (EFI_ERROR (Status
)) {
973 // Ip6config protocol and ip6 service binding protocol are installed
974 // on the same handle.
976 Status
= gBS
->HandleProtocol (
977 HandleBuffer
[HandleIndex
],
978 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4Config2ProtocolGuid
,
982 if (EFI_ERROR (Status
)) {
986 // Get the interface information size.
988 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
989 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
991 Ip6ConfigDataTypeInterfaceInfo
,
996 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
998 Ip4Config2DataTypeInterfaceInfo
,
1005 // Skip the ones not in current use.
1007 if (Status
== EFI_NOT_STARTED
) {
1011 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1012 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1016 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1018 if (IpXInterfaceInfo
== NULL
) {
1019 Status
= EFI_OUT_OF_RESOURCES
;
1023 // Get the interface info.
1025 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1026 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1028 Ip6ConfigDataTypeInterfaceInfo
,
1033 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1035 Ip4Config2DataTypeInterfaceInfo
,
1041 if (EFI_ERROR (Status
)) {
1042 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1046 // Check whether the source address is one of the interface addresses.
1048 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1049 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1050 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1052 if (UnspecifiedSrc
) {
1053 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1055 // Select the interface automatically.
1057 CopyMem(&Private
->SrcAddress
, Addr
, sizeof(Private
->SrcAddress
));
1060 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1062 // Match a certain interface address.
1068 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1070 // Found a nic handle with right interface address.
1075 if (UnspecifiedSrc
) {
1076 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1077 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1079 // Select the interface automatically.
1083 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1085 // Match a certain interface address.
1091 FreePool (IpXInterfaceInfo
);
1092 IpXInterfaceInfo
= NULL
;
1095 // No exact interface address matched.
1098 if (HandleIndex
== HandleNum
) {
1099 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1100 Status
= EFI_NOT_FOUND
;
1104 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1106 ASSERT (EfiSb
!= NULL
);
1107 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1109 if (EFI_ERROR (Status
)) {
1112 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1113 Status
= gBS
->OpenProtocol (
1114 Private
->IpChildHandle
,
1115 &gEfiIp6ProtocolGuid
,
1116 &Private
->IpProtocol
,
1118 Private
->IpChildHandle
,
1119 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1121 if (EFI_ERROR (Status
)) {
1126 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1129 // Configure the ip6 instance for icmp6 packet exchange.
1131 Ip6Config
.DefaultProtocol
= 58;
1132 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1133 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1134 Ip6Config
.AcceptPromiscuous
= FALSE
;
1135 Ip6Config
.TrafficClass
= 0;
1136 Ip6Config
.HopLimit
= 128;
1137 Ip6Config
.FlowLabel
= 0;
1138 Ip6Config
.ReceiveTimeout
= 0;
1139 Ip6Config
.TransmitTimeout
= 0;
1141 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1142 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1144 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1146 if (EFI_ERROR (Status
)) {
1147 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1151 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1152 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1153 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1154 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1156 Status
= gBS
->OpenProtocol (
1157 Private
->IpChildHandle
,
1158 &gEfiIp4ProtocolGuid
,
1159 &Private
->IpProtocol
,
1161 Private
->IpChildHandle
,
1162 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1164 if (EFI_ERROR (Status
)) {
1169 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1172 // Configure the ip4 instance for icmp4 packet exchange.
1174 Ip4Config
.DefaultProtocol
= 1;
1175 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1176 Ip4Config
.AcceptBroadcast
= FALSE
;
1177 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1178 Ip4Config
.AcceptPromiscuous
= FALSE
;
1179 Ip4Config
.DoNotFragment
= FALSE
;
1180 Ip4Config
.RawData
= FALSE
;
1181 Ip4Config
.ReceiveTimeout
= 0;
1182 Ip4Config
.TransmitTimeout
= 0;
1183 Ip4Config
.UseDefaultAddress
= TRUE
;
1184 Ip4Config
.TimeToLive
= 128;
1185 Ip4Config
.TypeOfService
= 0;
1187 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1189 if (EFI_ERROR (Status
)) {
1190 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1194 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1195 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1196 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1197 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1200 if (HandleBuffer
!= NULL
) {
1201 FreePool (HandleBuffer
);
1207 if (HandleBuffer
!= NULL
) {
1208 FreePool (HandleBuffer
);
1211 if (IpXInterfaceInfo
!= NULL
) {
1212 FreePool (IpXInterfaceInfo
);
1215 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1216 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1223 Destroy the IP instance.
1225 @param[in] Private The pointer of PING_PRIVATE_DATA.
1230 Ping6DestroyIp6Instance (
1231 IN PING_PRIVATE_DATA
*Private
1235 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1237 gBS
->CloseProtocol (
1238 Private
->IpChildHandle
,
1239 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1241 Private
->IpChildHandle
1244 Status
= gBS
->HandleProtocol (
1246 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1250 if (!EFI_ERROR(Status
)) {
1251 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1258 @param[in] SendNumber The send request count.
1259 @param[in] BufferSize The send buffer size.
1260 @param[in] SrcAddress The source address.
1261 @param[in] DstAddress The destination address.
1262 @param[in] IpChoice The choice between IPv4 and IPv6.
1264 @retval SHELL_SUCCESS The ping processed successfullly.
1265 @retval others The ping processed unsuccessfully.
1270 IN UINT32 SendNumber
,
1271 IN UINT32 BufferSize
,
1272 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1273 IN EFI_IPv6_ADDRESS
*DstAddress
,
1278 PING_PRIVATE_DATA
*Private
;
1279 PING_ICMPX_TX_INFO
*TxInfo
;
1281 LIST_ENTRY
*NextEntry
;
1282 SHELL_STATUS ShellStatus
;
1284 ShellStatus
= SHELL_SUCCESS
;
1285 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1287 if (Private
== NULL
) {
1288 return (SHELL_OUT_OF_RESOURCES
);
1291 Private
->IpChoice
= IpChoice
;
1292 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1293 Private
->SendNum
= SendNumber
;
1294 Private
->BufferSize
= BufferSize
;
1295 Private
->RttMin
= ~((UINT64
)(0x0));
1296 Private
->Status
= EFI_NOT_READY
;
1298 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1299 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1301 InitializeListHead (&Private
->TxList
);
1304 // Open and configure a ip instance for us.
1306 Status
= PingCreateIpInstance (Private
);
1308 if (EFI_ERROR (Status
)) {
1309 ShellStatus
= SHELL_ACCESS_DENIED
;
1313 // Print the command line itself.
1315 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1317 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1319 Status
= Ping6ReceiveEchoReply (Private
);
1321 if (EFI_ERROR (Status
)) {
1322 ShellStatus
= SHELL_ACCESS_DENIED
;
1326 // Create and start timer to send icmp6 echo request packet per second.
1328 Status
= gBS
->CreateEvent (
1329 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1331 Ping6OnTimerRoutine
,
1336 if (EFI_ERROR (Status
)) {
1337 ShellStatus
= SHELL_ACCESS_DENIED
;
1341 // Create a ipv6 token to send the first icmp6 echo request packet.
1343 Status
= PingSendEchoRequest (Private
);
1345 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1347 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1348 ShellStatus
= SHELL_ACCESS_DENIED
;
1349 if(Status
== EFI_NOT_FOUND
) {
1350 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1351 } else if (Status
== RETURN_NO_MAPPING
) {
1352 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1354 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1360 Status
= gBS
->SetTimer (
1366 if (EFI_ERROR (Status
)) {
1367 ShellStatus
= SHELL_ACCESS_DENIED
;
1371 // Control the ping6 process by two factors:
1373 // 2. Private->Status
1374 // 2.1. success means all icmp6 echo request packets get reply packets.
1375 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1376 // 2.3. noready means ping6 process is on-the-go.
1378 while (Private
->Status
== EFI_NOT_READY
) {
1379 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1380 if (ShellGetExecutionBreakFlag()) {
1381 Private
->Status
= EFI_ABORTED
;
1388 // Display the statistics in all.
1390 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1392 if (Private
->TxCount
!= 0) {
1397 STRING_TOKEN (STR_PING_STAT
),
1398 gShellNetwork1HiiHandle
,
1400 (Private
->RxCount
- Private
->FailedCount
),
1401 (100 - ((100 * (Private
->RxCount
- Private
->FailedCount
)) / Private
->TxCount
)),
1406 if (Private
->RxCount
> Private
->FailedCount
) {
1411 STRING_TOKEN (STR_PING_RTT
),
1412 gShellNetwork1HiiHandle
,
1415 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
)
1421 if (Private
!= NULL
) {
1423 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1424 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1426 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1427 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1430 RemoveEntryList (&TxInfo
->Link
);
1431 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1434 if (Private
->Timer
!= NULL
) {
1435 gBS
->CloseEvent (Private
->Timer
);
1438 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1439 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1442 if (Private
->RxToken
.Event
!= NULL
) {
1443 gBS
->CloseEvent (Private
->RxToken
.Event
);
1446 if (Private
->IpChildHandle
!= NULL
) {
1447 Ping6DestroyIp6Instance (Private
);
1457 Function for 'ping' command.
1459 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1460 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1462 @retval SHELL_SUCCESS The ping processed successfullly.
1463 @retval others The ping processed unsuccessfully.
1468 ShellCommandRunPing (
1469 IN EFI_HANDLE ImageHandle
,
1470 IN EFI_SYSTEM_TABLE
*SystemTable
1474 SHELL_STATUS ShellStatus
;
1475 EFI_IPv6_ADDRESS DstAddress
;
1476 EFI_IPv6_ADDRESS SrcAddress
;
1479 LIST_ENTRY
*ParamPackage
;
1480 CONST CHAR16
*ValueStr
;
1481 UINTN NonOptionCount
;
1483 CHAR16
*ProblemParam
;
1486 // we use IPv6 buffers to hold items...
1487 // make sure this is enough space!
1489 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1490 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1492 IpChoice
= PING_IP_CHOICE_IP4
;
1494 ShellStatus
= SHELL_SUCCESS
;
1495 ProblemParam
= NULL
;
1497 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1498 if (EFI_ERROR(Status
)) {
1499 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1500 ShellStatus
= SHELL_INVALID_PARAMETER
;
1504 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1505 IpChoice
= PING_IP_CHOICE_IP6
;
1509 // Parse the paramter of count number.
1511 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1512 if (ValueStr
!= NULL
) {
1513 SendNumber
= ShellStrToUintn (ValueStr
);
1516 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1518 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1519 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1520 ShellStatus
= SHELL_INVALID_PARAMETER
;
1524 SendNumber
= DEFAULT_SEND_COUNT
;
1527 // Parse the paramter of buffer size.
1529 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1530 if (ValueStr
!= NULL
) {
1531 BufferSize
= ShellStrToUintn (ValueStr
);
1534 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1536 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1537 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1538 ShellStatus
= SHELL_INVALID_PARAMETER
;
1542 BufferSize
= DEFAULT_BUFFER_SIZE
;
1545 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1546 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1549 // Parse the paramter of source ip address.
1551 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1552 if (ValueStr
== NULL
) {
1553 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1556 if (ValueStr
!= NULL
) {
1557 mSrcString
= ValueStr
;
1558 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1559 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1561 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1563 if (EFI_ERROR (Status
)) {
1564 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1565 ShellStatus
= SHELL_INVALID_PARAMETER
;
1570 // Parse the paramter of destination ip address.
1572 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1573 if (NonOptionCount
< 2) {
1574 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1575 ShellStatus
= SHELL_INVALID_PARAMETER
;
1578 if (NonOptionCount
> 2) {
1579 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1580 ShellStatus
= SHELL_INVALID_PARAMETER
;
1583 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1584 if (ValueStr
!= NULL
) {
1585 mDstString
= ValueStr
;
1586 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1587 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1589 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1591 if (EFI_ERROR (Status
)) {
1592 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1593 ShellStatus
= SHELL_INVALID_PARAMETER
;
1598 // Get frequency to calculate the time from ticks.
1600 Status
= GetFrequency ();
1602 if (EFI_ERROR(Status
)) {
1606 // Enter into ping process.
1608 ShellStatus
= ShellPing (
1617 ShellCommandLineFreeVarList (ParamPackage
);