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
160 Packet
= (UINT16
*) Buffer
;
163 Odd
= (UINT8
) (Length
& 1);
165 while ((Length
--) != 0) {
170 Sum
+= *(UINT8
*) Packet
;
173 Sum
= (Sum
& 0xffff) + (Sum
>> 16);
176 // in case above carried
184 Reads and returns the current value of register.
185 In IA64, the register is the Interval Timer Vector (ITV).
186 In X86(IA32/X64), the register is the Time Stamp Counter (TSC)
188 @return The current value of the register.
192 STATIC CONST SHELL_PARAM_ITEM PingParamList
[] = {
220 // Global Variables in Ping command.
222 STATIC CONST CHAR16
*mDstString
;
223 STATIC CONST CHAR16
*mSrcString
;
224 STATIC UINT64 mFrequency
= 0;
225 EFI_CPU_ARCH_PROTOCOL
*gCpu
= NULL
;
228 Read the current time.
230 @retval the current tick value.
240 ASSERT (gCpu
!= NULL
);
242 Status
= gCpu
->GetTimerValue (gCpu
, 0, &mCurrentTick
, &TimerPeriod
);
243 if (EFI_ERROR (Status
)) {
245 // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the
246 // TimerPeriod by ourselves.
248 mCurrentTick
+= 1000000;
256 Get and calculate the frequency in ticks/ms.
257 The result is saved in the global variable mFrequency
259 @retval EFI_SUCCESS Calculated the frequency successfully.
260 @retval Others Failed to calculate the frequency.
272 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &gCpu
);
273 if (EFI_ERROR (Status
)) {
277 Status
= gCpu
->GetTimerValue (gCpu
, 0, &CurrentTick
, &TimerPeriod
);
279 if (EFI_ERROR (Status
)) {
280 TimerPeriod
= DEFAULT_TIMER_PERIOD
;
284 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
285 // So 1e+12 is divided by timer period to produce the freq in ticks/ms.
287 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
293 Calculate a duration in ms.
295 @param[in] Begin The start point of time.
296 @param[in] End The end point of time.
298 @return The duration in ms.
299 @retval 0 The parameters were not valid.
310 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
314 Destroy PING_ICMPX_TX_INFO, and recollect the memory.
316 @param[in] TxInfo The pointer to PING_ICMPX_TX_INFO.
317 @param[in] IpChoice Whether the token is IPv4 or IPv6
321 IN PING_ICMPX_TX_INFO
*TxInfo
,
325 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
326 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
327 EFI_IP6_FRAGMENT_DATA
*FragData
;
330 if (TxInfo
== NULL
) {
334 if (TxInfo
->Token
!= NULL
) {
336 if (TxInfo
->Token
->Event
!= NULL
) {
337 gBS
->CloseEvent (TxInfo
->Token
->Event
);
340 if (TxInfo
->Token
->Packet
.TxData
!= NULL
) {
341 if (IpChoice
== PING_IP_CHOICE_IP6
) {
342 Ip6TxData
= TxInfo
->Token
->Packet
.TxData
;
344 if (Ip6TxData
->OverrideData
!= NULL
) {
345 FreePool (Ip6TxData
->OverrideData
);
348 if (Ip6TxData
->ExtHdrs
!= NULL
) {
349 FreePool (Ip6TxData
->ExtHdrs
);
352 for (Index
= 0; Index
< Ip6TxData
->FragmentCount
; Index
++) {
353 FragData
= Ip6TxData
->FragmentTable
[Index
].FragmentBuffer
;
354 if (FragData
!= NULL
) {
359 Ip4TxData
= TxInfo
->Token
->Packet
.TxData
;
361 if (Ip4TxData
->OverrideData
!= NULL
) {
362 FreePool (Ip4TxData
->OverrideData
);
365 for (Index
= 0; Index
< Ip4TxData
->FragmentCount
; Index
++) {
366 FragData
= Ip4TxData
->FragmentTable
[Index
].FragmentBuffer
;
367 if (FragData
!= NULL
) {
374 FreePool (TxInfo
->Token
);
381 Match the request, and reply with SequenceNum/TimeStamp.
383 @param[in] Private The pointer to PING_PRIVATE_DATA.
384 @param[in] Packet The pointer to ICMPX_ECHO_REQUEST_REPLY.
386 @retval EFI_SUCCESS The match is successful.
387 @retval EFI_NOT_FOUND The reply can't be matched with any request.
391 Ping6MatchEchoReply (
392 IN PING_PRIVATE_DATA
*Private
,
393 IN ICMPX_ECHO_REQUEST_REPLY
*Packet
396 PING_ICMPX_TX_INFO
*TxInfo
;
398 LIST_ENTRY
*NextEntry
;
400 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
401 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
403 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
405 RemoveEntryList (&TxInfo
->Link
);
406 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
411 return EFI_NOT_FOUND
;
415 The original intention is to send a request.
416 Currently, the application retransmits an icmp6 echo request packet
417 per second in sendnumber times that is specified by the user.
418 Because nothing can be done here, all things move to the timer rountine.
420 @param[in] Event A EFI_EVENT type event.
421 @param[in] Context The pointer to Context.
426 Ping6OnEchoRequestSent (
434 receive reply, match and print reply infomation.
436 @param[in] Event A EFI_EVENT type event.
437 @param[in] Context The pointer to context.
442 Ping6OnEchoReplyReceived (
448 PING_PRIVATE_DATA
*Private
;
449 ICMPX_ECHO_REQUEST_REPLY
*Reply
;
454 Private
= (PING_PRIVATE_DATA
*) Context
;
456 if (Private
== NULL
|| Private
->Status
== EFI_ABORTED
|| Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
460 if (Private
->RxToken
.Packet
.RxData
== NULL
) {
464 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
465 Reply
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
466 PayLoad
= ((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
467 if (((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->NextHeader
!= IP6_ICMP
) {
470 if (!IP6_IS_MULTICAST ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) &&
471 !EFI_IP6_EQUAL (&((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv6_ADDRESS
*)&Private
->DstAddress
)) {
475 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
479 Reply
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->FragmentTable
[0].FragmentBuffer
;
480 PayLoad
= ((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->DataLength
;
481 if (!IP4_IS_MULTICAST (EFI_IP4(*(EFI_IPv4_ADDRESS
*)Private
->DstAddress
)) &&
482 !EFI_IP4_EQUAL (&((EFI_IP4_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->SourceAddress
, (EFI_IPv4_ADDRESS
*)&Private
->DstAddress
)) {
486 if ((Reply
->Type
!= ICMP_V4_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
492 if (PayLoad
!= Private
->BufferSize
) {
496 // Check whether the reply matches the sent request before.
498 Status
= Ping6MatchEchoReply (Private
, Reply
);
499 if (EFI_ERROR(Status
)) {
503 // Display statistics on this icmp6 echo reply packet.
505 Rtt
= CalculateTick (Reply
->TimeStamp
, ReadTime ());
512 Private
->RttSum
+= Rtt
;
513 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
514 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
520 STRING_TOKEN (STR_PING_REPLY_INFO
),
521 gShellNetwork1HiiHandle
,
525 Private
->IpChoice
== PING_IP_CHOICE_IP6
?((EFI_IP6_RECEIVE_DATA
*)Private
->RxToken
.Packet
.RxData
)->Header
->HopLimit
:0,
532 if (Private
->RxCount
< Private
->SendNum
) {
534 // Continue to receive icmp echo reply packets.
536 Private
->RxToken
.Status
= EFI_ABORTED
;
538 Status
= Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
);
540 if (EFI_ERROR (Status
)) {
541 Private
->Status
= EFI_ABORTED
;
545 // All reply have already been received from the dest host.
547 Private
->Status
= EFI_SUCCESS
;
550 // Singal to recycle the each rxdata here, not at the end of process.
552 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
);
556 Create a PING_IPX_COMPLETION_TOKEN.
558 @param[in] Private The pointer of PING_PRIVATE_DATA.
559 @param[in] TimeStamp The TimeStamp of request.
560 @param[in] SequenceNum The SequenceNum of request.
562 @return The pointer of PING_IPX_COMPLETION_TOKEN.
565 PING_IPX_COMPLETION_TOKEN
*
567 IN PING_PRIVATE_DATA
*Private
,
569 IN UINT16 SequenceNum
573 PING_IPX_COMPLETION_TOKEN
*Token
;
575 ICMPX_ECHO_REQUEST_REPLY
*Request
;
579 Request
= AllocateZeroPool (Private
->BufferSize
);
580 if (Request
== NULL
) {
583 TxData
= AllocateZeroPool (Private
->IpChoice
==PING_IP_CHOICE_IP6
?sizeof (EFI_IP6_TRANSMIT_DATA
):sizeof (EFI_IP4_TRANSMIT_DATA
));
584 if (TxData
== NULL
) {
588 Token
= AllocateZeroPool (sizeof (PING_IPX_COMPLETION_TOKEN
));
596 // Assembly echo request packet.
598 Request
->Type
= (UINT8
)(Private
->IpChoice
==PING_IP_CHOICE_IP6
?ICMP_V6_ECHO_REQUEST
:ICMP_V4_ECHO_REQUEST
);
600 Request
->SequenceNum
= SequenceNum
;
601 Request
->Identifier
= 0;
602 Request
->Checksum
= 0;
605 // Assembly token for transmit.
607 if (Private
->IpChoice
==PING_IP_CHOICE_IP6
) {
608 Request
->TimeStamp
= TimeStamp
;
609 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrsLength
= 0;
610 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->ExtHdrs
= NULL
;
611 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
612 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->DataLength
= Private
->BufferSize
;
613 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
614 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
615 ((EFI_IP6_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
617 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsLength
= 0;
618 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OptionsBuffer
= NULL
;
619 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->OverrideData
= 0;
620 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->TotalDataLength
= Private
->BufferSize
;
621 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentCount
= 1;
622 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
623 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
624 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[0] = Private
->DstAddress
[0];
625 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[1] = Private
->DstAddress
[1];
626 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[2] = Private
->DstAddress
[2];
627 ((EFI_IP4_TRANSMIT_DATA
*)TxData
)->DestinationAddress
.Addr
[3] = Private
->DstAddress
[3];
629 HeadSum
= NetChecksum ((UINT8
*) Request
, Private
->BufferSize
);
630 Request
->TimeStamp
= TimeStamp
;
631 TempChecksum
= NetChecksum ((UINT8
*) &Request
->TimeStamp
, sizeof (UINT64
));
632 Request
->Checksum
= (UINT16
)(~NetAddChecksum (HeadSum
, TempChecksum
));
636 Token
->Status
= EFI_ABORTED
;
637 Token
->Packet
.TxData
= TxData
;
639 Status
= gBS
->CreateEvent (
642 Ping6OnEchoRequestSent
,
647 if (EFI_ERROR (Status
)) {
658 Transmit the PING_IPX_COMPLETION_TOKEN.
660 @param[in] Private The pointer of PING_PRIVATE_DATA.
662 @retval EFI_SUCCESS Transmitted successfully.
663 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
664 @retval others Transmitted unsuccessfully.
668 PingSendEchoRequest (
669 IN PING_PRIVATE_DATA
*Private
673 PING_ICMPX_TX_INFO
*TxInfo
;
675 TxInfo
= AllocateZeroPool (sizeof (PING_ICMPX_TX_INFO
));
677 if (TxInfo
== NULL
) {
678 return EFI_OUT_OF_RESOURCES
;
681 TxInfo
->TimeStamp
= ReadTime ();
682 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
683 TxInfo
->Token
= PingGenerateToken (
689 if (TxInfo
->Token
== NULL
) {
690 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
691 return EFI_OUT_OF_RESOURCES
;
694 ASSERT(Private
->ProtocolPointers
.Transmit
!= NULL
);
695 Status
= Private
->ProtocolPointers
.Transmit (Private
->IpProtocol
, TxInfo
->Token
);
697 if (EFI_ERROR (Status
)) {
698 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
702 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
709 Place a completion token into the receive packet queue to receive the echo reply.
711 @param[in] Private The pointer of PING_PRIVATE_DATA.
713 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
714 @retval others Put the token into the receive packet queue unsuccessfully.
718 Ping6ReceiveEchoReply (
719 IN PING_PRIVATE_DATA
*Private
724 ZeroMem (&Private
->RxToken
, sizeof (PING_IPX_COMPLETION_TOKEN
));
726 Status
= gBS
->CreateEvent (
729 Ping6OnEchoReplyReceived
,
731 &Private
->RxToken
.Event
734 if (EFI_ERROR (Status
)) {
738 Private
->RxToken
.Status
= EFI_NOT_READY
;
740 return (Private
->ProtocolPointers
.Receive (Private
->IpProtocol
, &Private
->RxToken
));
744 Remove the timeout request from the list.
746 @param[in] Event A EFI_EVENT type event.
747 @param[in] Context The pointer to Context.
752 Ping6OnTimerRoutine (
758 PING_PRIVATE_DATA
*Private
;
759 PING_ICMPX_TX_INFO
*TxInfo
;
761 LIST_ENTRY
*NextEntry
;
764 Private
= (PING_PRIVATE_DATA
*) Context
;
765 if (Private
->Signature
!= PING_PRIVATE_DATA_SIGNATURE
) {
766 Private
->Status
= EFI_NOT_FOUND
;
771 // Retransmit icmp6 echo request packets per second in sendnumber times.
773 if (Private
->TxCount
< Private
->SendNum
) {
775 Status
= PingSendEchoRequest (Private
);
776 if (Private
->TxCount
!= 0){
777 if (EFI_ERROR (Status
)) {
778 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_SEND_REQUEST
), gShellNetwork1HiiHandle
, Private
->TxCount
+ 1);
783 // Check whether any icmp6 echo request in the list timeout.
785 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
786 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
787 Time
= CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
790 // Remove the timeout echo request from txlist.
792 if (Time
> DEFAULT_TIMEOUT
) {
794 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
795 Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
798 // Remove the timeout icmp6 echo request from list.
800 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_TIMEOUT
), gShellNetwork1HiiHandle
, TxInfo
->SequenceNum
);
802 RemoveEntryList (&TxInfo
->Link
);
803 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
806 Private
->FailedCount
++;
808 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
810 // All the left icmp6 echo request in the list timeout.
812 Private
->Status
= EFI_TIMEOUT
;
819 Determine if a IP4 address is Link Local.
821 169.254.1.0 through 169.254.254.255 is link local.
823 @param[in] Address The address to test.
826 @retval FALSE It is not.
829 PingNetIp4IsLinkLocalAddr (
830 IN CONST EFI_IPv4_ADDRESS
*Address
833 return ((BOOLEAN
)(Address
->Addr
[0] == 169 && Address
->Addr
[1] == 254 && Address
->Addr
[2] >= 1 && Address
->Addr
[2] <= 254));
837 Determine if a IP4 address is unspecified.
839 @param[in] Address The address to test.
842 @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.
864 PingCreateIpInstance (
865 IN PING_PRIVATE_DATA
*Private
871 EFI_HANDLE
*HandleBuffer
;
872 BOOLEAN UnspecifiedSrc
;
873 BOOLEAN MediaPresent
;
874 EFI_SERVICE_BINDING_PROTOCOL
*EfiSb
;
876 EFI_IP6_CONFIG_DATA Ip6Config
;
877 EFI_IP4_CONFIG_DATA Ip4Config
;
878 VOID
*IpXInterfaceInfo
;
880 EFI_IPv6_ADDRESS
*Addr
;
884 UnspecifiedSrc
= FALSE
;
887 IpXInterfaceInfo
= NULL
;
891 // Locate all the handles with ip6 service binding protocol.
893 Status
= gBS
->LocateHandleBuffer (
895 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
900 if (EFI_ERROR (Status
) || (HandleNum
== 0) || (HandleBuffer
== NULL
)) {
904 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS
*)&Private
->SrcAddress
) : \
905 PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS
*)&Private
->SrcAddress
)) {
907 // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected.
909 UnspecifiedSrc
= TRUE
;
913 // Source address is required when pinging a link-local address.
915 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
916 if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
917 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
918 Status
= EFI_INVALID_PARAMETER
;
922 ASSERT(Private
->IpChoice
== PING_IP_CHOICE_IP4
);
923 if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS
*)&Private
->DstAddress
) && UnspecifiedSrc
) {
924 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_INVALID_SOURCE
), gShellNetwork1HiiHandle
);
925 Status
= EFI_INVALID_PARAMETER
;
931 // For each ip6 protocol, check interface addresses list.
933 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
935 IpXInterfaceInfo
= NULL
;
938 if (UnspecifiedSrc
) {
942 NetLibDetectMedia (HandleBuffer
[HandleIndex
], &MediaPresent
);
951 Status
= gBS
->HandleProtocol (
952 HandleBuffer
[HandleIndex
],
953 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
956 if (EFI_ERROR (Status
)) {
961 // Ip6config protocol and ip6 service binding protocol are installed
962 // on the same handle.
964 Status
= gBS
->HandleProtocol (
965 HandleBuffer
[HandleIndex
],
966 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ConfigProtocolGuid
:&gEfiIp4Config2ProtocolGuid
,
970 if (EFI_ERROR (Status
)) {
974 // Get the interface information size.
976 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
977 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
979 Ip6ConfigDataTypeInterfaceInfo
,
984 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
986 Ip4Config2DataTypeInterfaceInfo
,
993 // Skip the ones not in current use.
995 if (Status
== EFI_NOT_STARTED
) {
999 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1000 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1004 IpXInterfaceInfo
= AllocateZeroPool (IfInfoSize
);
1006 if (IpXInterfaceInfo
== NULL
) {
1007 Status
= EFI_OUT_OF_RESOURCES
;
1011 // Get the interface info.
1013 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1014 Status
= ((EFI_IP6_CONFIG_PROTOCOL
*)IpXCfg
)->GetData (
1016 Ip6ConfigDataTypeInterfaceInfo
,
1021 Status
= ((EFI_IP4_CONFIG2_PROTOCOL
*)IpXCfg
)->GetData (
1023 Ip4Config2DataTypeInterfaceInfo
,
1029 if (EFI_ERROR (Status
)) {
1030 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_GETDATA
), gShellNetwork1HiiHandle
, Status
);
1034 // Check whether the source address is one of the interface addresses.
1036 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1037 for (AddrIndex
= 0; AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
; AddrIndex
++) {
1038 Addr
= &(((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfo
[AddrIndex
].Address
);
1040 if (UnspecifiedSrc
) {
1041 if (!NetIp6IsUnspecifiedAddr (Addr
) && !NetIp6IsLinkLocalAddr (Addr
)) {
1043 // Select the interface automatically.
1045 CopyMem(&Private
->SrcAddress
, Addr
, sizeof(Private
->SrcAddress
));
1048 } else if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
1050 // Match a certain interface address.
1056 if (AddrIndex
< ((EFI_IP6_CONFIG_INTERFACE_INFO
*)IpXInterfaceInfo
)->AddressInfoCount
) {
1058 // Found a nic handle with right interface address.
1063 if (UnspecifiedSrc
) {
1064 if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
) &&
1065 !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1067 // Select the interface automatically.
1071 } else if (EFI_IP4_EQUAL (&Private
->SrcAddress
, &((EFI_IP4_CONFIG2_INTERFACE_INFO
*)IpXInterfaceInfo
)->StationAddress
)) {
1073 // Match a certain interface address.
1079 FreePool (IpXInterfaceInfo
);
1080 IpXInterfaceInfo
= NULL
;
1083 // No exact interface address matched.
1086 if (HandleIndex
== HandleNum
) {
1087 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF
), gShellNetwork1HiiHandle
, L
"ping");
1088 Status
= EFI_NOT_FOUND
;
1092 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
1094 ASSERT (EfiSb
!= NULL
);
1095 Status
= EfiSb
->CreateChild (EfiSb
, &Private
->IpChildHandle
);
1097 if (EFI_ERROR (Status
)) {
1100 if (Private
->IpChoice
== PING_IP_CHOICE_IP6
) {
1101 Status
= gBS
->OpenProtocol (
1102 Private
->IpChildHandle
,
1103 &gEfiIp6ProtocolGuid
,
1104 &Private
->IpProtocol
,
1106 Private
->IpChildHandle
,
1107 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1109 if (EFI_ERROR (Status
)) {
1114 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
1117 // Configure the ip6 instance for icmp6 packet exchange.
1119 Ip6Config
.DefaultProtocol
= 58;
1120 Ip6Config
.AcceptAnyProtocol
= FALSE
;
1121 Ip6Config
.AcceptIcmpErrors
= TRUE
;
1122 Ip6Config
.AcceptPromiscuous
= FALSE
;
1123 Ip6Config
.TrafficClass
= 0;
1124 Ip6Config
.HopLimit
= 128;
1125 Ip6Config
.FlowLabel
= 0;
1126 Ip6Config
.ReceiveTimeout
= 0;
1127 Ip6Config
.TransmitTimeout
= 0;
1129 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
1130 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
1132 Status
= ((EFI_IP6_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip6Config
);
1134 if (EFI_ERROR (Status
)) {
1135 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1139 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1140 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1141 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1142 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP6_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1144 Status
= gBS
->OpenProtocol (
1145 Private
->IpChildHandle
,
1146 &gEfiIp4ProtocolGuid
,
1147 &Private
->IpProtocol
,
1149 Private
->IpChildHandle
,
1150 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1152 if (EFI_ERROR (Status
)) {
1157 ZeroMem (&Ip4Config
, sizeof (EFI_IP4_CONFIG_DATA
));
1160 // Configure the ip4 instance for icmp4 packet exchange.
1162 Ip4Config
.DefaultProtocol
= 1;
1163 Ip4Config
.AcceptAnyProtocol
= FALSE
;
1164 Ip4Config
.AcceptBroadcast
= FALSE
;
1165 Ip4Config
.AcceptIcmpErrors
= TRUE
;
1166 Ip4Config
.AcceptPromiscuous
= FALSE
;
1167 Ip4Config
.DoNotFragment
= FALSE
;
1168 Ip4Config
.RawData
= FALSE
;
1169 Ip4Config
.ReceiveTimeout
= 0;
1170 Ip4Config
.TransmitTimeout
= 0;
1171 Ip4Config
.UseDefaultAddress
= TRUE
;
1172 Ip4Config
.TimeToLive
= 128;
1173 Ip4Config
.TypeOfService
= 0;
1175 Status
= ((EFI_IP4_PROTOCOL
*)(Private
->IpProtocol
))->Configure (Private
->IpProtocol
, &Ip4Config
);
1177 if (EFI_ERROR (Status
)) {
1178 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_CONFIG
), gShellNetwork1HiiHandle
, Status
);
1182 Private
->ProtocolPointers
.Transmit
= (PING_IPX_TRANSMIT
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Transmit
;
1183 Private
->ProtocolPointers
.Receive
= (PING_IPX_RECEIVE
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Receive
;
1184 Private
->ProtocolPointers
.Cancel
= (PING_IPX_CANCEL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Cancel
;
1185 Private
->ProtocolPointers
.Poll
= (PING_IPX_POLL
)((EFI_IP4_PROTOCOL
*)Private
->IpProtocol
)->Poll
;
1188 if (HandleBuffer
!= NULL
) {
1189 FreePool (HandleBuffer
);
1195 if (HandleBuffer
!= NULL
) {
1196 FreePool (HandleBuffer
);
1199 if (IpXInterfaceInfo
!= NULL
) {
1200 FreePool (IpXInterfaceInfo
);
1203 if ((EfiSb
!= NULL
) && (Private
->IpChildHandle
!= NULL
)) {
1204 EfiSb
->DestroyChild (EfiSb
, Private
->IpChildHandle
);
1211 Destroy the IP instance.
1213 @param[in] Private The pointer of PING_PRIVATE_DATA.
1217 Ping6DestroyIp6Instance (
1218 IN PING_PRIVATE_DATA
*Private
1222 EFI_SERVICE_BINDING_PROTOCOL
*IpSb
;
1224 gBS
->CloseProtocol (
1225 Private
->IpChildHandle
,
1226 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ProtocolGuid
:&gEfiIp4ProtocolGuid
,
1228 Private
->IpChildHandle
1231 Status
= gBS
->HandleProtocol (
1233 Private
->IpChoice
== PING_IP_CHOICE_IP6
?&gEfiIp6ServiceBindingProtocolGuid
:&gEfiIp4ServiceBindingProtocolGuid
,
1237 if (!EFI_ERROR(Status
)) {
1238 IpSb
->DestroyChild (IpSb
, Private
->IpChildHandle
);
1245 @param[in] SendNumber The send request count.
1246 @param[in] BufferSize The send buffer size.
1247 @param[in] SrcAddress The source address.
1248 @param[in] DstAddress The destination address.
1249 @param[in] IpChoice The choice between IPv4 and IPv6.
1251 @retval SHELL_SUCCESS The ping processed successfullly.
1252 @retval others The ping processed unsuccessfully.
1256 IN UINT32 SendNumber
,
1257 IN UINT32 BufferSize
,
1258 IN EFI_IPv6_ADDRESS
*SrcAddress
,
1259 IN EFI_IPv6_ADDRESS
*DstAddress
,
1264 PING_PRIVATE_DATA
*Private
;
1265 PING_ICMPX_TX_INFO
*TxInfo
;
1267 LIST_ENTRY
*NextEntry
;
1268 SHELL_STATUS ShellStatus
;
1270 ShellStatus
= SHELL_SUCCESS
;
1271 Private
= AllocateZeroPool (sizeof (PING_PRIVATE_DATA
));
1273 if (Private
== NULL
) {
1274 return (SHELL_OUT_OF_RESOURCES
);
1277 Private
->IpChoice
= IpChoice
;
1278 Private
->Signature
= PING_PRIVATE_DATA_SIGNATURE
;
1279 Private
->SendNum
= SendNumber
;
1280 Private
->BufferSize
= BufferSize
;
1281 Private
->RttMin
= ~((UINT64
)(0x0));
1282 Private
->Status
= EFI_NOT_READY
;
1284 CopyMem(&Private
->SrcAddress
, SrcAddress
, sizeof(Private
->SrcAddress
));
1285 CopyMem(&Private
->DstAddress
, DstAddress
, sizeof(Private
->DstAddress
));
1287 InitializeListHead (&Private
->TxList
);
1290 // Open and configure a ip instance for us.
1292 Status
= PingCreateIpInstance (Private
);
1294 if (EFI_ERROR (Status
)) {
1295 ShellStatus
= SHELL_ACCESS_DENIED
;
1299 // Print the command line itself.
1301 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_START
), gShellNetwork1HiiHandle
, mDstString
, Private
->BufferSize
);
1303 // Create a ipv6 token to receive the first icmp6 echo reply packet.
1305 Status
= Ping6ReceiveEchoReply (Private
);
1307 if (EFI_ERROR (Status
)) {
1308 ShellStatus
= SHELL_ACCESS_DENIED
;
1312 // Create and start timer to send icmp6 echo request packet per second.
1314 Status
= gBS
->CreateEvent (
1315 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1317 Ping6OnTimerRoutine
,
1322 if (EFI_ERROR (Status
)) {
1323 ShellStatus
= SHELL_ACCESS_DENIED
;
1327 // Create a ipv6 token to send the first icmp6 echo request packet.
1329 Status
= PingSendEchoRequest (Private
);
1331 // EFI_NOT_READY for IPsec is enable and IKE is not established.
1333 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
1334 ShellStatus
= SHELL_ACCESS_DENIED
;
1335 if(Status
== EFI_NOT_FOUND
) {
1336 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOSOURCE_INDO
), gShellNetwork1HiiHandle
, mDstString
);
1337 } else if (Status
== RETURN_NO_MAPPING
) {
1338 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NOROUTE_FOUND
), gShellNetwork1HiiHandle
, mDstString
, mSrcString
);
1340 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING_NETWORK_ERROR
), gShellNetwork1HiiHandle
, L
"ping", Status
);
1346 Status
= gBS
->SetTimer (
1352 if (EFI_ERROR (Status
)) {
1353 ShellStatus
= SHELL_ACCESS_DENIED
;
1357 // Control the ping6 process by two factors:
1359 // 2. Private->Status
1360 // 2.1. success means all icmp6 echo request packets get reply packets.
1361 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1362 // 2.3. noready means ping6 process is on-the-go.
1364 while (Private
->Status
== EFI_NOT_READY
) {
1365 Status
= Private
->ProtocolPointers
.Poll (Private
->IpProtocol
);
1366 if (ShellGetExecutionBreakFlag()) {
1367 Private
->Status
= EFI_ABORTED
;
1374 // Display the statistics in all.
1376 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1378 if (Private
->TxCount
!= 0) {
1383 STRING_TOKEN (STR_PING_STAT
),
1384 gShellNetwork1HiiHandle
,
1386 (Private
->RxCount
- Private
->FailedCount
),
1387 (100 - ((100 * (Private
->RxCount
- Private
->FailedCount
)) / Private
->TxCount
)),
1392 if (Private
->RxCount
> Private
->FailedCount
) {
1397 STRING_TOKEN (STR_PING_RTT
),
1398 gShellNetwork1HiiHandle
,
1401 DivU64x64Remainder (Private
->RttSum
, (Private
->RxCount
- Private
->FailedCount
), NULL
)
1407 if (Private
!= NULL
) {
1409 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1410 TxInfo
= BASE_CR (Entry
, PING_ICMPX_TX_INFO
, Link
);
1412 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1413 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, TxInfo
->Token
);
1416 RemoveEntryList (&TxInfo
->Link
);
1417 PingDestroyTxInfo (TxInfo
, Private
->IpChoice
);
1420 if (Private
->Timer
!= NULL
) {
1421 gBS
->CloseEvent (Private
->Timer
);
1424 if (Private
->IpProtocol
!= NULL
&& Private
->ProtocolPointers
.Cancel
!= NULL
) {
1425 Status
= Private
->ProtocolPointers
.Cancel (Private
->IpProtocol
, &Private
->RxToken
);
1428 if (Private
->RxToken
.Event
!= NULL
) {
1429 gBS
->CloseEvent (Private
->RxToken
.Event
);
1432 if (Private
->IpChildHandle
!= NULL
) {
1433 Ping6DestroyIp6Instance (Private
);
1443 Function for 'ping' command.
1445 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1446 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1448 @retval SHELL_SUCCESS The ping processed successfullly.
1449 @retval others The ping processed unsuccessfully.
1454 ShellCommandRunPing (
1455 IN EFI_HANDLE ImageHandle
,
1456 IN EFI_SYSTEM_TABLE
*SystemTable
1460 SHELL_STATUS ShellStatus
;
1461 EFI_IPv6_ADDRESS DstAddress
;
1462 EFI_IPv6_ADDRESS SrcAddress
;
1465 LIST_ENTRY
*ParamPackage
;
1466 CONST CHAR16
*ValueStr
;
1467 UINTN NonOptionCount
;
1469 CHAR16
*ProblemParam
;
1472 // we use IPv6 buffers to hold items...
1473 // make sure this is enough space!
1475 ASSERT(sizeof(EFI_IPv4_ADDRESS
) <= sizeof(EFI_IPv6_ADDRESS
));
1476 ASSERT(sizeof(EFI_IP4_COMPLETION_TOKEN
) <= sizeof(EFI_IP6_COMPLETION_TOKEN
));
1478 IpChoice
= PING_IP_CHOICE_IP4
;
1480 ShellStatus
= SHELL_SUCCESS
;
1481 ProblemParam
= NULL
;
1483 Status
= ShellCommandLineParseEx (PingParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1484 if (EFI_ERROR(Status
)) {
1485 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ProblemParam
);
1486 ShellStatus
= SHELL_INVALID_PARAMETER
;
1490 if (ShellCommandLineGetFlag (ParamPackage
, L
"-_ip6")) {
1491 IpChoice
= PING_IP_CHOICE_IP6
;
1495 // Parse the paramter of count number.
1497 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1498 if (ValueStr
!= NULL
) {
1499 SendNumber
= ShellStrToUintn (ValueStr
);
1502 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1504 if ((SendNumber
== 0) || (SendNumber
> MAX_SEND_NUMBER
)) {
1505 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1506 ShellStatus
= SHELL_INVALID_PARAMETER
;
1510 SendNumber
= DEFAULT_SEND_COUNT
;
1513 // Parse the paramter of buffer size.
1515 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1516 if (ValueStr
!= NULL
) {
1517 BufferSize
= ShellStrToUintn (ValueStr
);
1520 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1522 if ((BufferSize
< 16) || (BufferSize
> MAX_BUFFER_SIZE
)) {
1523 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1524 ShellStatus
= SHELL_INVALID_PARAMETER
;
1528 BufferSize
= DEFAULT_BUFFER_SIZE
;
1531 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1532 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1535 // Parse the paramter of source ip address.
1537 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1538 if (ValueStr
== NULL
) {
1539 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-_s");
1542 if (ValueStr
!= NULL
) {
1543 mSrcString
= ValueStr
;
1544 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1545 Status
= NetLibStrToIp6 (ValueStr
, &SrcAddress
);
1547 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&SrcAddress
);
1549 if (EFI_ERROR (Status
)) {
1550 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1551 ShellStatus
= SHELL_INVALID_PARAMETER
;
1556 // Parse the paramter of destination ip address.
1558 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1559 if (NonOptionCount
< 2) {
1560 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellNetwork1HiiHandle
, L
"ping");
1561 ShellStatus
= SHELL_INVALID_PARAMETER
;
1564 if (NonOptionCount
> 2) {
1565 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellNetwork1HiiHandle
, L
"ping");
1566 ShellStatus
= SHELL_INVALID_PARAMETER
;
1569 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, 1);
1570 if (ValueStr
!= NULL
) {
1571 mDstString
= ValueStr
;
1572 if (IpChoice
== PING_IP_CHOICE_IP6
) {
1573 Status
= NetLibStrToIp6 (ValueStr
, &DstAddress
);
1575 Status
= NetLibStrToIp4 (ValueStr
, (EFI_IPv4_ADDRESS
*)&DstAddress
);
1577 if (EFI_ERROR (Status
)) {
1578 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellNetwork1HiiHandle
, L
"ping", ValueStr
);
1579 ShellStatus
= SHELL_INVALID_PARAMETER
;
1584 // Get frequency to calculate the time from ticks.
1586 Status
= GetFrequency ();
1588 if (EFI_ERROR(Status
)) {
1592 // Enter into ping process.
1594 ShellStatus
= ShellPing (
1603 ShellCommandLineFreeVarList (ParamPackage
);