2 The implementation for Ping6 application.
4 Copyright (c) 2016, 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 "UefiShellNetwork2CommandsLib.h"
18 #define PING6_DEFAULT_TIMEOUT 5000
19 #define PING6_MAX_SEND_NUMBER 10000
20 #define PING6_MAX_BUFFER_SIZE 32768
21 #define PING6_ONE_SECOND 10000000
24 // A similar amount of time that passes in femtoseconds
25 // for each increment of TimerValue. It is for NT32 only.
27 #define NTTIMERPERIOD 358049
31 typedef struct _ICMP6_ECHO_REQUEST_REPLY
{
39 } ICMP6_ECHO_REQUEST_REPLY
;
43 typedef struct _PING6_ICMP6_TX_INFO
{
47 EFI_IP6_COMPLETION_TOKEN
*Token
;
48 } PING6_ICMP6_TX_INFO
;
50 typedef struct _PING6_PRIVATE_DATA
{
51 EFI_HANDLE ImageHandle
;
53 EFI_HANDLE Ip6ChildHandle
;
54 EFI_IP6_PROTOCOL
*Ip6
;
59 EFI_IP6_COMPLETION_TOKEN RxToken
;
67 EFI_IPv6_ADDRESS SrcAddress
;
68 EFI_IPv6_ADDRESS DstAddress
;
74 SHELL_PARAM_ITEM Ping6ParamList
[] = {
98 // Global Variables in Ping6 application.
100 CONST CHAR16
*mIp6DstString
;
101 CONST CHAR16
*mIp6SrcString
;
102 UINT64 mFrequency
= 0;
103 UINT64 mIp6CurrentTick
= 0;
104 EFI_CPU_ARCH_PROTOCOL
*Cpu
= NULL
;
109 Reads and returns the current value of the Time.
111 @return The current tick value.
120 ASSERT (Cpu
!= NULL
);
122 Status
= Cpu
->GetTimerValue (Cpu
, 0, &mIp6CurrentTick
, &TimerPeriod
);
123 if (EFI_ERROR (Status
)) {
125 // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the
126 // TimerPeriod by ourselves.
128 mIp6CurrentTick
+= 1000000;
131 return mIp6CurrentTick
;
135 Get and calculate the frequency in tick/ms.
136 The result is saved in the globle variable mFrequency
138 @retval EFI_SUCCESS Calculated the frequency successfully.
139 @retval Others Failed to calculate the frequency.
151 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &Cpu
);
153 if (EFI_ERROR (Status
)) {
157 Status
= Cpu
->GetTimerValue (Cpu
, 0, &CurrentTick
, &TimerPeriod
);
159 if (EFI_ERROR (Status
)) {
161 // For NT32 Simulator only. 358049 is a similar value to keep timer granularity.
162 // Set the timer period by ourselves.
164 TimerPeriod
= (UINT64
) NTTIMERPERIOD
;
167 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
168 // So 1e+12 is divided by timer period to produce the freq in tick/ms.
170 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
176 Get and calculate the duration in ms.
178 @param[in] Begin The start point of time.
179 @param[in] End The end point of time.
181 @return The duration in ms.
190 ASSERT (End
> Begin
);
191 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
195 Destroy IPING6_ICMP6_TX_INFO, and recollect the memory.
197 @param[in] TxInfo The pointer to PING6_ICMP6_TX_INFO.
202 IN PING6_ICMP6_TX_INFO
*TxInfo
205 EFI_IP6_TRANSMIT_DATA
*TxData
;
206 EFI_IP6_FRAGMENT_DATA
*FragData
;
209 ASSERT (TxInfo
!= NULL
);
211 if (TxInfo
->Token
!= NULL
) {
213 if (TxInfo
->Token
->Event
!= NULL
) {
214 gBS
->CloseEvent (TxInfo
->Token
->Event
);
217 TxData
= TxInfo
->Token
->Packet
.TxData
;
218 if (TxData
!= NULL
) {
220 if (TxData
->OverrideData
!= NULL
) {
221 FreePool (TxData
->OverrideData
);
224 if (TxData
->ExtHdrs
!= NULL
) {
225 FreePool (TxData
->ExtHdrs
);
228 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
229 FragData
= TxData
->FragmentTable
[Index
].FragmentBuffer
;
230 if (FragData
!= NULL
) {
236 FreePool (TxInfo
->Token
);
243 Match the request, and reply with SequenceNum/TimeStamp.
245 @param[in] Private The pointer to PING6_PRIVATE_DATA.
246 @param[in] Packet The pointer to ICMP6_ECHO_REQUEST_REPLY.
248 @retval EFI_SUCCESS The match is successful.
249 @retval EFI_NOT_FOUND The reply can't be matched with any request.
253 Ping6OnMatchEchoReply (
254 IN PING6_PRIVATE_DATA
*Private
,
255 IN ICMP6_ECHO_REQUEST_REPLY
*Packet
258 PING6_ICMP6_TX_INFO
*TxInfo
;
260 LIST_ENTRY
*NextEntry
;
262 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
263 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
265 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
267 RemoveEntryList (&TxInfo
->Link
);
268 Ping6DestroyTxInfo (TxInfo
);
273 return EFI_NOT_FOUND
;
277 The original intention is to send a request.
278 Currently, the application retransmits an icmp6 echo request packet
279 per second in sendnumber times that is specified by the user.
280 Because nothing can be done here, all things move to the timer rountine.
282 @param[in] Event A EFI_EVENT type event.
283 @param[in] Context The pointer to Context.
288 Ping6OnEchoRequestSent6 (
296 receive reply, match and print reply infomation.
298 @param[in] Event A EFI_EVENT type event.
299 @param[in] Context The pointer to context.
304 Ping6OnEchoReplyReceived6 (
310 PING6_PRIVATE_DATA
*Private
;
311 EFI_IP6_COMPLETION_TOKEN
*RxToken
;
312 EFI_IP6_RECEIVE_DATA
*RxData
;
313 ICMP6_ECHO_REQUEST_REPLY
*Reply
;
318 Private
= (PING6_PRIVATE_DATA
*) Context
;
320 if (Private
->Status
== EFI_ABORTED
) {
324 RxToken
= &Private
->RxToken
;
325 RxData
= RxToken
->Packet
.RxData
;
326 Reply
= RxData
->FragmentTable
[0].FragmentBuffer
;
327 PayLoad
= RxData
->DataLength
;
329 if (RxData
->Header
->NextHeader
!= IP6_ICMP
) {
333 if (!IP6_IS_MULTICAST (&Private
->DstAddress
) &&
334 !EFI_IP6_EQUAL (&RxData
->Header
->SourceAddress
, &Private
->DstAddress
)) {
338 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
342 if (PayLoad
!= Private
->BufferSize
) {
346 // Check whether the reply matches the sent request before.
348 Status
= Ping6OnMatchEchoReply (Private
, Reply
);
349 if (EFI_ERROR(Status
)) {
353 // Display statistics on this icmp6 echo reply packet.
355 Rtt
= Ping6CalculateTick (Reply
->TimeStamp
, Ping6ReadTime ());
362 Private
->RttSum
+= Rtt
;
363 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
364 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
370 STRING_TOKEN (STR_PING6_REPLY_INFO
),
371 gShellNetwork2HiiHandle
,
375 RxData
->Header
->HopLimit
,
382 if (Private
->RxCount
< Private
->SendNum
) {
384 // Continue to receive icmp6 echo reply packets.
386 RxToken
->Status
= EFI_ABORTED
;
388 Status
= Private
->Ip6
->Receive (Private
->Ip6
, RxToken
);
390 if (EFI_ERROR (Status
)) {
391 Private
->Status
= EFI_ABORTED
;
395 // All reply have already been received from the dest host.
397 Private
->Status
= EFI_SUCCESS
;
400 // Singal to recycle the each rxdata here, not at the end of process.
402 gBS
->SignalEvent (RxData
->RecycleSignal
);
406 Initial EFI_IP6_COMPLETION_TOKEN.
408 @param[in] Private The pointer of PING6_PRIVATE_DATA.
409 @param[in] TimeStamp The TimeStamp of request.
410 @param[in] SequenceNum The SequenceNum of request.
412 @return The pointer of EFI_IP6_COMPLETION_TOKEN.
415 EFI_IP6_COMPLETION_TOKEN
*
417 IN PING6_PRIVATE_DATA
*Private
,
419 IN UINT16 SequenceNum
423 EFI_IP6_COMPLETION_TOKEN
*Token
;
424 EFI_IP6_TRANSMIT_DATA
*TxData
;
425 ICMP6_ECHO_REQUEST_REPLY
*Request
;
427 Request
= AllocateZeroPool (Private
->BufferSize
);
429 if (Request
== NULL
) {
433 // Assembly icmp6 echo request packet.
435 Request
->Type
= ICMP_V6_ECHO_REQUEST
;
437 Request
->SequenceNum
= SequenceNum
;
438 Request
->TimeStamp
= TimeStamp
;
439 Request
->Identifier
= 0;
441 // Leave check sum to ip6 layer, since it has no idea of source address
444 Request
->Checksum
= 0;
446 TxData
= AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA
));
448 if (TxData
== NULL
) {
453 // Assembly ipv6 token for transmit.
455 TxData
->OverrideData
= 0;
456 TxData
->ExtHdrsLength
= 0;
457 TxData
->ExtHdrs
= NULL
;
458 TxData
->DataLength
= Private
->BufferSize
;
459 TxData
->FragmentCount
= 1;
460 TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
461 TxData
->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
463 Token
= AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN
));
471 Token
->Status
= EFI_ABORTED
;
472 Token
->Packet
.TxData
= TxData
;
474 Status
= gBS
->CreateEvent (
477 Ping6OnEchoRequestSent6
,
482 if (EFI_ERROR (Status
)) {
493 Transmit the EFI_IP6_COMPLETION_TOKEN.
495 @param[in] Private The pointer of PING6_PRIVATE_DATA.
497 @retval EFI_SUCCESS Transmitted successfully.
498 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
499 @retval others Transmitted unsuccessfully.
503 Ping6SendEchoRequest (
504 IN PING6_PRIVATE_DATA
*Private
508 PING6_ICMP6_TX_INFO
*TxInfo
;
510 TxInfo
= AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO
));
512 if (TxInfo
== NULL
) {
513 return EFI_OUT_OF_RESOURCES
;
516 TxInfo
->TimeStamp
= Ping6ReadTime ();
517 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
519 TxInfo
->Token
= Ping6GenerateToken (
525 if (TxInfo
->Token
== NULL
) {
526 Ping6DestroyTxInfo (TxInfo
);
527 return EFI_OUT_OF_RESOURCES
;
530 Status
= Private
->Ip6
->Transmit (Private
->Ip6
, TxInfo
->Token
);
532 if (EFI_ERROR (Status
)) {
533 Ping6DestroyTxInfo (TxInfo
);
537 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
544 Place a completion token into the receive packet queue to receive the echo reply.
546 @param[in] Private The pointer of PING6_PRIVATE_DATA.
548 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
549 @retval others Put the token into the receive packet queue unsuccessfully.
553 Ping6OnReceiveEchoReply (
554 IN PING6_PRIVATE_DATA
*Private
559 ZeroMem (&Private
->RxToken
, sizeof (EFI_IP6_COMPLETION_TOKEN
));
561 Status
= gBS
->CreateEvent (
564 Ping6OnEchoReplyReceived6
,
566 &Private
->RxToken
.Event
569 if (EFI_ERROR (Status
)) {
573 Private
->RxToken
.Status
= EFI_NOT_READY
;
575 return Private
->Ip6
->Receive (Private
->Ip6
, &Private
->RxToken
);
579 Remove the timeout request from the list.
581 @param[in] Event A EFI_EVENT type event.
582 @param[in] Context The pointer to Context.
587 Ping6OnTimerRoutine6 (
593 PING6_PRIVATE_DATA
*Private
;
594 PING6_ICMP6_TX_INFO
*TxInfo
;
596 LIST_ENTRY
*NextEntry
;
599 Private
= (PING6_PRIVATE_DATA
*) Context
;
602 // Retransmit icmp6 echo request packets per second in sendnumber times.
604 if (Private
->TxCount
< Private
->SendNum
) {
606 Status
= Ping6SendEchoRequest (Private
);
607 if (Private
->TxCount
!= 0){
608 if (EFI_ERROR (Status
)) {
609 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_SEND_REQUEST
), gShellNetwork2HiiHandle
, Private
->TxCount
+ 1);
614 // Check whether any icmp6 echo request in the list timeout.
616 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
617 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
618 Time
= Ping6CalculateTick (TxInfo
->TimeStamp
, Ping6ReadTime ());
621 // Remove the timeout echo request from txlist.
623 if (Time
> PING6_DEFAULT_TIMEOUT
) {
625 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
626 Private
->Ip6
->Cancel (Private
->Ip6
, TxInfo
->Token
);
629 // Remove the timeout icmp6 echo request from list.
631 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_TIMEOUT
), gShellNetwork2HiiHandle
, TxInfo
->SequenceNum
);
633 RemoveEntryList (&TxInfo
->Link
);
634 Ping6DestroyTxInfo (TxInfo
);
636 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
638 // All the left icmp6 echo request in the list timeout.
640 Private
->Status
= EFI_TIMEOUT
;
647 Create a valid IP6 instance.
649 @param[in] Private The pointer of PING6_PRIVATE_DATA.
651 @retval EFI_SUCCESS Create a valid IP6 instance successfully.
652 @retval EFI_ABORTED Locate handle with ip6 service binding protocol unsuccessfully.
653 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link -ocal address.
654 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
655 @retval EFI_NOT_FOUND The source address is not found.
658 Ping6CreateIpInstance (
659 IN PING6_PRIVATE_DATA
*Private
665 EFI_HANDLE
*HandleBuffer
;
666 EFI_SERVICE_BINDING_PROTOCOL
*Ip6Sb
;
667 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
668 EFI_IP6_CONFIG_DATA Ip6Config
;
669 EFI_IP6_CONFIG_INTERFACE_INFO
*IfInfo
;
671 EFI_IPv6_ADDRESS
*Addr
;
680 // Locate all the handles with ip6 service binding protocol.
682 Status
= gBS
->LocateHandleBuffer (
684 &gEfiIp6ServiceBindingProtocolGuid
,
689 if (EFI_ERROR (Status
) || (HandleNum
== 0)) {
693 // Source address is required when pinging a link-local address on multi-
696 if (NetIp6IsLinkLocalAddr (&Private
->DstAddress
) &&
697 NetIp6IsUnspecifiedAddr (&Private
->SrcAddress
) &&
699 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_SOURCE
), gShellNetwork2HiiHandle
);
700 Status
= EFI_INVALID_PARAMETER
;
704 // For each ip6 protocol, check interface addresses list.
706 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
712 Status
= gBS
->HandleProtocol (
713 HandleBuffer
[HandleIndex
],
714 &gEfiIp6ServiceBindingProtocolGuid
,
717 if (EFI_ERROR (Status
)) {
721 if (NetIp6IsUnspecifiedAddr (&Private
->SrcAddress
)) {
723 // No need to match interface address.
728 // Ip6config protocol and ip6 service binding protocol are installed
729 // on the same handle.
731 Status
= gBS
->HandleProtocol (
732 HandleBuffer
[HandleIndex
],
733 &gEfiIp6ConfigProtocolGuid
,
737 if (EFI_ERROR (Status
)) {
741 // Get the interface information size.
743 Status
= Ip6Cfg
->GetData (
745 Ip6ConfigDataTypeInterfaceInfo
,
750 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
751 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA
), gShellNetwork2HiiHandle
, Status
);
755 IfInfo
= AllocateZeroPool (IfInfoSize
);
757 if (IfInfo
== NULL
) {
758 Status
= EFI_OUT_OF_RESOURCES
;
762 // Get the interface info.
764 Status
= Ip6Cfg
->GetData (
766 Ip6ConfigDataTypeInterfaceInfo
,
771 if (EFI_ERROR (Status
)) {
772 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA
), gShellNetwork2HiiHandle
, Status
);
776 // Check whether the source address is one of the interface addresses.
778 for (AddrIndex
= 0; AddrIndex
< IfInfo
->AddressInfoCount
; AddrIndex
++) {
780 Addr
= &(IfInfo
->AddressInfo
[AddrIndex
].Address
);
781 if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
783 // Match a certain interface address.
789 if (AddrIndex
< IfInfo
->AddressInfoCount
) {
791 // Found a nic handle with right interface address.
801 // No exact interface address matched.
804 if (HandleIndex
== HandleNum
) {
805 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND
), gShellNetwork2HiiHandle
, mIp6SrcString
);
806 Status
= EFI_NOT_FOUND
;
810 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
812 ASSERT (Ip6Sb
!= NULL
);
813 Status
= Ip6Sb
->CreateChild (Ip6Sb
, &Private
->Ip6ChildHandle
);
815 if (EFI_ERROR (Status
)) {
819 Status
= gBS
->OpenProtocol (
820 Private
->Ip6ChildHandle
,
821 &gEfiIp6ProtocolGuid
,
822 (VOID
**) &Private
->Ip6
,
823 Private
->ImageHandle
,
824 Private
->Ip6ChildHandle
,
825 EFI_OPEN_PROTOCOL_GET_PROTOCOL
827 if (EFI_ERROR (Status
)) {
831 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
834 // Configure the ip6 instance for icmp6 packet exchange.
836 Ip6Config
.DefaultProtocol
= 58;
837 Ip6Config
.AcceptAnyProtocol
= FALSE
;
838 Ip6Config
.AcceptIcmpErrors
= TRUE
;
839 Ip6Config
.AcceptPromiscuous
= FALSE
;
840 Ip6Config
.TrafficClass
= 0;
841 Ip6Config
.HopLimit
= 128;
842 Ip6Config
.FlowLabel
= 0;
843 Ip6Config
.ReceiveTimeout
= 0;
844 Ip6Config
.TransmitTimeout
= 0;
846 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
848 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
850 Status
= Private
->Ip6
->Configure (Private
->Ip6
, &Ip6Config
);
852 if (EFI_ERROR (Status
)) {
853 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6_CONFIG
), gShellNetwork2HiiHandle
, Status
);
860 if (HandleBuffer
!= NULL
) {
861 FreePool (HandleBuffer
);
864 if (IfInfo
!= NULL
) {
868 if ((Ip6Sb
!= NULL
) && (Private
->Ip6ChildHandle
!= NULL
)) {
869 Ip6Sb
->DestroyChild (Ip6Sb
, Private
->Ip6ChildHandle
);
876 Destroy the IP6 instance.
878 @param[in] Private The pointer of PING6_PRIVATE_DATA.
882 Ping6DestroyIpInstance (
883 IN PING6_PRIVATE_DATA
*Private
887 EFI_SERVICE_BINDING_PROTOCOL
*Ip6Sb
;
890 Private
->Ip6ChildHandle
,
891 &gEfiIp6ProtocolGuid
,
892 Private
->ImageHandle
,
893 Private
->Ip6ChildHandle
896 Status
= gBS
->HandleProtocol (
898 &gEfiIp6ServiceBindingProtocolGuid
,
902 if (!EFI_ERROR(Status
)) {
903 Ip6Sb
->DestroyChild (Ip6Sb
, Private
->Ip6ChildHandle
);
910 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
911 @param[in] SendNumber The send request count.
912 @param[in] BufferSize The send buffer size.
913 @param[in] SrcAddress The source IPv6 address.
914 @param[in] DstAddress The destination IPv6 address.
916 @retval SHELL_SUCCESS The ping6 processed successfullly.
917 @retval others The ping6 processed unsuccessfully.
922 IN EFI_HANDLE ImageHandle
,
923 IN UINT32 SendNumber
,
924 IN UINT32 BufferSize
,
925 IN EFI_IPv6_ADDRESS
*SrcAddress
,
926 IN EFI_IPv6_ADDRESS
*DstAddress
931 PING6_PRIVATE_DATA
*Private
;
932 PING6_ICMP6_TX_INFO
*TxInfo
;
934 LIST_ENTRY
*NextEntry
;
935 SHELL_STATUS ShellStatus
;
937 ShellStatus
= SHELL_SUCCESS
;
938 Private
= AllocateZeroPool (sizeof (PING6_PRIVATE_DATA
));
940 ASSERT (Private
!= NULL
);
942 Private
->ImageHandle
= ImageHandle
;
943 Private
->SendNum
= SendNumber
;
944 Private
->BufferSize
= BufferSize
;
945 Private
->RttMin
= ~((UINT64
)(0x0));
946 Private
->Status
= EFI_NOT_READY
;
948 InitializeListHead (&Private
->TxList
);
950 IP6_COPY_ADDRESS (&Private
->SrcAddress
, SrcAddress
);
951 IP6_COPY_ADDRESS (&Private
->DstAddress
, DstAddress
);
954 // Open and configure a ip6 instance for ping6.
956 Status
= Ping6CreateIpInstance (Private
);
958 if (EFI_ERROR (Status
)) {
959 ShellStatus
= SHELL_ACCESS_DENIED
;
963 // Print the command line itself.
965 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_START
), gShellNetwork2HiiHandle
, mIp6DstString
, Private
->BufferSize
);
967 // Create a ipv6 token to receive the first icmp6 echo reply packet.
969 Status
= Ping6OnReceiveEchoReply (Private
);
971 if (EFI_ERROR (Status
)) {
972 ShellStatus
= SHELL_ACCESS_DENIED
;
976 // Create and start timer to send icmp6 echo request packet per second.
978 Status
= gBS
->CreateEvent (
979 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
981 Ping6OnTimerRoutine6
,
986 if (EFI_ERROR (Status
)) {
987 ShellStatus
= SHELL_ACCESS_DENIED
;
991 // Create a ipv6 token to send the first icmp6 echo request packet.
993 Status
= Ping6SendEchoRequest (Private
);
995 // EFI_NOT_READY for IPsec is enable and IKE is not established.
997 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
998 ShellStatus
= SHELL_ACCESS_DENIED
;
999 if(Status
== EFI_NOT_FOUND
) {
1000 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN
), gShellNetwork2HiiHandle
, mIp6DstString
);
1006 Status
= gBS
->SetTimer (
1012 if (EFI_ERROR (Status
)) {
1013 ShellStatus
= SHELL_ACCESS_DENIED
;
1017 // Control the ping6 process by two factors:
1019 // 2. Private->Status
1020 // 2.1. success means all icmp6 echo request packets get reply packets.
1021 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
1022 // 2.3. noready means ping6 process is on-the-go.
1024 while (Private
->Status
== EFI_NOT_READY
) {
1025 Private
->Ip6
->Poll (Private
->Ip6
);
1028 // Terminate the ping6 process by 'esc' or 'ctl-c'.
1030 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
1032 if (!EFI_ERROR(Status
)) {
1033 if ((Key
.UnicodeChar
== 0x1b) || (Key
.UnicodeChar
== 0x03) ||
1034 ((Key
.UnicodeChar
== 0) && (Key
.ScanCode
== SCAN_ESC
))) {
1042 // Display the statistics in all.
1044 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
1046 if (Private
->TxCount
!= 0) {
1051 STRING_TOKEN (STR_PING6_STAT
),
1052 gShellNetwork2HiiHandle
,
1055 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
1060 if (Private
->RxCount
!= 0) {
1065 STRING_TOKEN (STR_PING6_RTT
),
1066 gShellNetwork2HiiHandle
,
1069 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
1075 if (Private
!= NULL
) {
1076 Private
->Status
= EFI_ABORTED
;
1078 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1079 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
1081 Status
= Private
->Ip6
->Cancel (Private
->Ip6
, TxInfo
->Token
);
1083 RemoveEntryList (&TxInfo
->Link
);
1084 Ping6DestroyTxInfo (TxInfo
);
1087 if (Private
->Timer
!= NULL
) {
1088 gBS
->CloseEvent (Private
->Timer
);
1091 if (Private
->Ip6
!= NULL
) {
1092 Status
= Private
->Ip6
->Cancel (Private
->Ip6
, &Private
->RxToken
);
1095 if (Private
->RxToken
.Event
!= NULL
) {
1096 gBS
->CloseEvent (Private
->RxToken
.Event
);
1099 if (Private
->Ip6ChildHandle
!= NULL
) {
1100 Ping6DestroyIpInstance (Private
);
1110 Function for 'ping6' command.
1112 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1113 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1115 @retval SHELL_SUCCESS The ping6 processed successfullly.
1116 @retval others The ping6 processed unsuccessfully.
1121 ShellCommandRunPing6 (
1122 IN EFI_HANDLE ImageHandle
,
1123 IN EFI_SYSTEM_TABLE
*SystemTable
1127 SHELL_STATUS ShellStatus
;
1128 EFI_IPv6_ADDRESS DstAddress
;
1129 EFI_IPv6_ADDRESS SrcAddress
;
1132 LIST_ENTRY
*ParamPackage
;
1133 CONST CHAR16
*ValueStr
;
1134 CONST CHAR16
*ValueStrPtr
;
1135 UINTN NonOptionCount
;
1136 CHAR16
*ProblemParam
;
1138 ProblemParam
= NULL
;
1139 ShellStatus
= SHELL_SUCCESS
;
1141 Status
= ShellCommandLineParseEx (Ping6ParamList
, &ParamPackage
, &ProblemParam
, TRUE
, FALSE
);
1142 if (EFI_ERROR(Status
)) {
1143 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_INPUT
), gShellNetwork2HiiHandle
);
1144 ShellStatus
= SHELL_INVALID_PARAMETER
;
1152 // Parse the paramter of count number.
1154 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1155 ValueStrPtr
= ValueStr
;
1156 if (ValueStr
!= NULL
) {
1157 SendNumber
= ShellStrToUintn (ValueStrPtr
);
1160 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1162 if ((SendNumber
== 0) || (SendNumber
> PING6_MAX_SEND_NUMBER
)) {
1163 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER
), gShellNetwork2HiiHandle
, ValueStr
);
1164 ShellStatus
= SHELL_INVALID_PARAMETER
;
1169 // Parse the paramter of buffer size.
1171 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1172 ValueStrPtr
= ValueStr
;
1173 if (ValueStr
!= NULL
) {
1174 BufferSize
= ShellStrToUintn (ValueStrPtr
);
1177 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1179 if ((BufferSize
< 16) || (BufferSize
> PING6_MAX_BUFFER_SIZE
)) {
1180 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE
), gShellNetwork2HiiHandle
, ValueStr
);
1181 ShellStatus
= SHELL_INVALID_PARAMETER
;
1186 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1187 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1190 // Parse the paramter of source ip address.
1192 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1193 ValueStrPtr
= ValueStr
;
1194 if (ValueStr
!= NULL
) {
1195 mIp6SrcString
= ValueStr
;
1196 Status
= NetLibStrToIp6 (ValueStrPtr
, &SrcAddress
);
1197 if (EFI_ERROR (Status
)) {
1198 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_IP
), gShellNetwork2HiiHandle
, ValueStr
);
1199 ShellStatus
= SHELL_INVALID_PARAMETER
;
1204 // Parse the paramter of destination ip address.
1206 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1207 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, (UINT32
)(NonOptionCount
-1));
1208 if (NonOptionCount
!= 2) {
1209 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_INPUT
), gShellNetwork2HiiHandle
);
1210 ShellStatus
= SHELL_INVALID_PARAMETER
;
1213 ValueStrPtr
= ValueStr
;
1214 if (ValueStr
!= NULL
) {
1215 mIp6DstString
= ValueStr
;
1216 Status
= NetLibStrToIp6 (ValueStrPtr
, &DstAddress
);
1217 if (EFI_ERROR (Status
)) {
1218 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_IP
), gShellNetwork2HiiHandle
, ValueStr
);
1219 ShellStatus
= SHELL_INVALID_PARAMETER
;
1224 // Get frequency to calculate the time from ticks.
1226 Status
= Ping6GetFrequency ();
1228 if (EFI_ERROR(Status
)) {
1229 ShellStatus
= SHELL_ACCESS_DENIED
;
1233 // Enter into ping6 process.
1235 ShellStatus
= ShellPing6 (
1244 ShellCommandLineFreeVarList (ParamPackage
);