2 The implementation for Ping6 application.
4 Copyright (c) 2009 - 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 <Library/ShellLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/UefiHiiServicesLib.h>
23 #include <Library/HiiLib.h>
24 #include <Library/NetLib.h>
26 #include <Protocol/Cpu.h>
27 #include <Protocol/ServiceBinding.h>
28 #include <Protocol/Ip6.h>
29 #include <Protocol/Ip6Config.h>
33 SHELL_PARAM_ITEM Ping6ParamList
[] = {
53 // Global Variables in Ping6 application.
55 EFI_HII_HANDLE mHiiHandle
;
56 CONST CHAR16
*mIp6DstString
;
57 CONST CHAR16
*mIp6SrcString
;
58 UINT64 mFrequency
= 0;
60 Get and calculate the frequency in tick/ms.
61 The result is saved in the globle variable mFrequency
63 @retval EFI_SUCCESS Calculated the frequency successfully.
64 @retval Others Failed to calculate the frequency.
73 EFI_CPU_ARCH_PROTOCOL
*Cpu
;
77 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &Cpu
);
79 if (EFI_ERROR (Status
)) {
83 Status
= Cpu
->GetTimerValue (Cpu
, 0, &CurrentTick
, &TimerPeriod
);
85 if (EFI_ERROR (Status
)) {
87 // For NT32 Simulator only. 358049 is a similar value to keep timer granularity.
88 // Set the timer period by ourselves.
90 TimerPeriod
= (UINT64
) NTTIMERPERIOD
;
93 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
94 // So 1e+12 is divided by timer period to produce the freq in tick/ms.
96 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
102 Get and calculate the duration in ms.
104 @param[in] Begin The start point of time.
105 @param[in] End The end point of time.
107 @return The duration in ms.
116 ASSERT (End
> Begin
);
117 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
121 Destroy IPING6_ICMP6_TX_INFO, and recollect the memory.
123 @param[in] TxInfo The pointer to PING6_ICMP6_TX_INFO.
128 IN PING6_ICMP6_TX_INFO
*TxInfo
131 EFI_IP6_TRANSMIT_DATA
*TxData
;
132 EFI_IP6_FRAGMENT_DATA
*FragData
;
135 ASSERT (TxInfo
!= NULL
);
137 if (TxInfo
->Token
!= NULL
) {
139 if (TxInfo
->Token
->Event
!= NULL
) {
140 gBS
->CloseEvent (TxInfo
->Token
->Event
);
143 TxData
= TxInfo
->Token
->Packet
.TxData
;
144 if (TxData
!= NULL
) {
146 if (TxData
->OverrideData
!= NULL
) {
147 FreePool (TxData
->OverrideData
);
150 if (TxData
->ExtHdrs
!= NULL
) {
151 FreePool (TxData
->ExtHdrs
);
154 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
155 FragData
= TxData
->FragmentTable
[Index
].FragmentBuffer
;
156 if (FragData
!= NULL
) {
162 FreePool (TxInfo
->Token
);
169 Match the request, and reply with SequenceNum/TimeStamp.
171 @param[in] Private The pointer to PING6_PRIVATE_DATA.
172 @param[in] Packet The pointer to ICMP6_ECHO_REQUEST_REPLY.
174 @retval EFI_SUCCESS The match is successful.
175 @retval EFI_NOT_FOUND The reply can't be matched with any request.
179 Ping6MatchEchoReply (
180 IN PING6_PRIVATE_DATA
*Private
,
181 IN ICMP6_ECHO_REQUEST_REPLY
*Packet
184 PING6_ICMP6_TX_INFO
*TxInfo
;
186 LIST_ENTRY
*NextEntry
;
188 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
189 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
191 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
193 RemoveEntryList (&TxInfo
->Link
);
194 Ping6DestroyTxInfo (TxInfo
);
199 return EFI_NOT_FOUND
;
203 The original intention is to send a request.
204 Currently, the application retransmits an icmp6 echo request packet
205 per second in sendnumber times that is specified by the user.
206 Because nothing can be done here, all things move to the timer rountine.
208 @param[in] Event A EFI_EVENT type event.
209 @param[in] Context The pointer to Context.
214 Ping6OnEchoRequestSent (
222 receive reply, match and print reply infomation.
224 @param[in] Event A EFI_EVENT type event.
225 @param[in] Context The pointer to context.
230 Ping6OnEchoReplyReceived (
236 PING6_PRIVATE_DATA
*Private
;
237 EFI_IP6_COMPLETION_TOKEN
*RxToken
;
238 EFI_IP6_RECEIVE_DATA
*RxData
;
239 ICMP6_ECHO_REQUEST_REPLY
*Reply
;
244 Private
= (PING6_PRIVATE_DATA
*) Context
;
246 if (Private
->Status
== EFI_ABORTED
) {
250 RxToken
= &Private
->RxToken
;
251 RxData
= RxToken
->Packet
.RxData
;
252 Reply
= RxData
->FragmentTable
[0].FragmentBuffer
;
253 PayLoad
= RxData
->DataLength
;
255 if (RxData
->Header
->NextHeader
!= IP6_ICMP
) {
259 if (!IP6_IS_MULTICAST (&Private
->DstAddress
) &&
260 !EFI_IP6_EQUAL (&RxData
->Header
->SourceAddress
, &Private
->DstAddress
)) {
264 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
268 if (PayLoad
!= Private
->BufferSize
) {
272 // Check whether the reply matches the sent request before.
274 Status
= Ping6MatchEchoReply (Private
, Reply
);
275 if (EFI_ERROR(Status
)) {
279 // Display statistics on this icmp6 echo reply packet.
281 Rtt
= Ping6CalculateTick (Reply
->TimeStamp
, ReadTime ());
288 Private
->RttSum
+= Rtt
;
289 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
290 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
296 STRING_TOKEN (STR_PING6_REPLY_INFO
),
301 RxData
->Header
->HopLimit
,
308 if (Private
->RxCount
< Private
->SendNum
) {
310 // Continue to receive icmp6 echo reply packets.
312 RxToken
->Status
= EFI_ABORTED
;
314 Status
= Private
->Ip6
->Receive (Private
->Ip6
, RxToken
);
316 if (EFI_ERROR (Status
)) {
317 Private
->Status
= EFI_ABORTED
;
321 // All reply have already been received from the dest host.
323 Private
->Status
= EFI_SUCCESS
;
326 // Singal to recycle the each rxdata here, not at the end of process.
328 gBS
->SignalEvent (RxData
->RecycleSignal
);
332 Initial EFI_IP6_COMPLETION_TOKEN.
334 @param[in] Private The pointer of PING6_PRIVATE_DATA.
335 @param[in] TimeStamp The TimeStamp of request.
336 @param[in] SequenceNum The SequenceNum of request.
338 @return The pointer of EFI_IP6_COMPLETION_TOKEN.
341 EFI_IP6_COMPLETION_TOKEN
*
343 IN PING6_PRIVATE_DATA
*Private
,
345 IN UINT16 SequenceNum
349 EFI_IP6_COMPLETION_TOKEN
*Token
;
350 EFI_IP6_TRANSMIT_DATA
*TxData
;
351 ICMP6_ECHO_REQUEST_REPLY
*Request
;
353 Request
= AllocateZeroPool (Private
->BufferSize
);
355 if (Request
== NULL
) {
359 // Assembly icmp6 echo request packet.
361 Request
->Type
= ICMP_V6_ECHO_REQUEST
;
363 Request
->SequenceNum
= SequenceNum
;
364 Request
->TimeStamp
= TimeStamp
;
365 Request
->Identifier
= 0;
367 // Leave check sum to ip6 layer, since it has no idea of source address
370 Request
->Checksum
= 0;
372 TxData
= AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA
));
374 if (TxData
== NULL
) {
379 // Assembly ipv6 token for transmit.
381 TxData
->OverrideData
= 0;
382 TxData
->ExtHdrsLength
= 0;
383 TxData
->ExtHdrs
= NULL
;
384 TxData
->DataLength
= Private
->BufferSize
;
385 TxData
->FragmentCount
= 1;
386 TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
387 TxData
->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
389 Token
= AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN
));
397 Token
->Status
= EFI_ABORTED
;
398 Token
->Packet
.TxData
= TxData
;
400 Status
= gBS
->CreateEvent (
403 Ping6OnEchoRequestSent
,
408 if (EFI_ERROR (Status
)) {
419 Transmit the EFI_IP6_COMPLETION_TOKEN.
421 @param[in] Private The pointer of PING6_PRIVATE_DATA.
423 @retval EFI_SUCCESS Transmitted successfully.
424 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
425 @retval others Transmitted unsuccessfully.
429 Ping6SendEchoRequest (
430 IN PING6_PRIVATE_DATA
*Private
434 PING6_ICMP6_TX_INFO
*TxInfo
;
436 TxInfo
= AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO
));
438 if (TxInfo
== NULL
) {
439 return EFI_OUT_OF_RESOURCES
;
442 TxInfo
->TimeStamp
= ReadTime ();
443 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
445 TxInfo
->Token
= Ping6GenerateToken (
451 if (TxInfo
->Token
== NULL
) {
452 Ping6DestroyTxInfo (TxInfo
);
453 return EFI_OUT_OF_RESOURCES
;
456 Status
= Private
->Ip6
->Transmit (Private
->Ip6
, TxInfo
->Token
);
458 if (EFI_ERROR (Status
)) {
459 Ping6DestroyTxInfo (TxInfo
);
463 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
470 Place a completion token into the receive packet queue to receive the echo reply.
472 @param[in] Private The pointer of PING6_PRIVATE_DATA.
474 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
475 @retval others Put the token into the receive packet queue unsuccessfully.
479 Ping6ReceiveEchoReply (
480 IN PING6_PRIVATE_DATA
*Private
485 ZeroMem (&Private
->RxToken
, sizeof (EFI_IP6_COMPLETION_TOKEN
));
487 Status
= gBS
->CreateEvent (
490 Ping6OnEchoReplyReceived
,
492 &Private
->RxToken
.Event
495 if (EFI_ERROR (Status
)) {
499 Private
->RxToken
.Status
= EFI_NOT_READY
;
501 return Private
->Ip6
->Receive (Private
->Ip6
, &Private
->RxToken
);
505 Remove the timeout request from the list.
507 @param[in] Event A EFI_EVENT type event.
508 @param[in] Context The pointer to Context.
513 Ping6OnTimerRoutine (
519 PING6_PRIVATE_DATA
*Private
;
520 PING6_ICMP6_TX_INFO
*TxInfo
;
522 LIST_ENTRY
*NextEntry
;
525 Private
= (PING6_PRIVATE_DATA
*) Context
;
528 // Retransmit icmp6 echo request packets per second in sendnumber times.
530 if (Private
->TxCount
< Private
->SendNum
) {
532 Status
= Ping6SendEchoRequest (Private
);
533 if (Private
->TxCount
!= 0){
534 if (EFI_ERROR (Status
)) {
535 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_SEND_REQUEST
), mHiiHandle
, Private
->TxCount
+ 1);
540 // Check whether any icmp6 echo request in the list timeout.
542 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
543 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
544 Time
= Ping6CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
547 // Remove the timeout echo request from txlist.
549 if (Time
> PING6_DEFAULT_TIMEOUT
) {
551 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
552 Private
->Ip6
->Cancel (Private
->Ip6
, TxInfo
->Token
);
555 // Remove the timeout icmp6 echo request from list.
557 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_TIMEOUT
), mHiiHandle
, TxInfo
->SequenceNum
);
559 RemoveEntryList (&TxInfo
->Link
);
560 Ping6DestroyTxInfo (TxInfo
);
562 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
564 // All the left icmp6 echo request in the list timeout.
566 Private
->Status
= EFI_TIMEOUT
;
573 Create a valid IP6 instance.
575 @param[in] Private The pointer of PING6_PRIVATE_DATA.
577 @retval EFI_SUCCESS Create a valid IP6 instance successfully.
578 @retval EFI_ABORTED Locate handle with ip6 service binding protocol unsuccessfully.
579 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link -ocal address.
580 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
581 @retval EFI_NOT_FOUND The source address is not found.
584 Ping6CreateIp6Instance (
585 IN PING6_PRIVATE_DATA
*Private
591 EFI_HANDLE
*HandleBuffer
;
592 EFI_SERVICE_BINDING_PROTOCOL
*Ip6Sb
;
593 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
594 EFI_IP6_CONFIG_DATA Ip6Config
;
595 EFI_IP6_CONFIG_INTERFACE_INFO
*IfInfo
;
597 EFI_IPv6_ADDRESS
*Addr
;
606 // Locate all the handles with ip6 service binding protocol.
608 Status
= gBS
->LocateHandleBuffer (
610 &gEfiIp6ServiceBindingProtocolGuid
,
615 if (EFI_ERROR (Status
) || (HandleNum
== 0)) {
619 // Source address is required when pinging a link-local address on multi-
622 if (NetIp6IsLinkLocalAddr (&Private
->DstAddress
) &&
623 NetIp6IsUnspecifiedAddr (&Private
->SrcAddress
) &&
625 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_SOURCE
), mHiiHandle
);
626 Status
= EFI_INVALID_PARAMETER
;
630 // For each ip6 protocol, check interface addresses list.
632 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
638 Status
= gBS
->HandleProtocol (
639 HandleBuffer
[HandleIndex
],
640 &gEfiIp6ServiceBindingProtocolGuid
,
643 if (EFI_ERROR (Status
)) {
647 if (NetIp6IsUnspecifiedAddr (&Private
->SrcAddress
)) {
649 // No need to match interface address.
654 // Ip6config protocol and ip6 service binding protocol are installed
655 // on the same handle.
657 Status
= gBS
->HandleProtocol (
658 HandleBuffer
[HandleIndex
],
659 &gEfiIp6ConfigProtocolGuid
,
663 if (EFI_ERROR (Status
)) {
667 // Get the interface information size.
669 Status
= Ip6Cfg
->GetData (
671 Ip6ConfigDataTypeInterfaceInfo
,
676 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
677 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA
), mHiiHandle
, Status
);
681 IfInfo
= AllocateZeroPool (IfInfoSize
);
683 if (IfInfo
== NULL
) {
684 Status
= EFI_OUT_OF_RESOURCES
;
688 // Get the interface info.
690 Status
= Ip6Cfg
->GetData (
692 Ip6ConfigDataTypeInterfaceInfo
,
697 if (EFI_ERROR (Status
)) {
698 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA
), mHiiHandle
, Status
);
702 // Check whether the source address is one of the interface addresses.
704 for (AddrIndex
= 0; AddrIndex
< IfInfo
->AddressInfoCount
; AddrIndex
++) {
706 Addr
= &(IfInfo
->AddressInfo
[AddrIndex
].Address
);
707 if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
709 // Match a certain interface address.
715 if (AddrIndex
< IfInfo
->AddressInfoCount
) {
717 // Found a nic handle with right interface address.
727 // No exact interface address matched.
730 if (HandleIndex
== HandleNum
) {
731 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND
), mHiiHandle
, mIp6SrcString
);
732 Status
= EFI_NOT_FOUND
;
736 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
738 ASSERT (Ip6Sb
!= NULL
);
739 Status
= Ip6Sb
->CreateChild (Ip6Sb
, &Private
->Ip6ChildHandle
);
741 if (EFI_ERROR (Status
)) {
745 Status
= gBS
->OpenProtocol (
746 Private
->Ip6ChildHandle
,
747 &gEfiIp6ProtocolGuid
,
748 (VOID
**) &Private
->Ip6
,
749 Private
->ImageHandle
,
750 Private
->Ip6ChildHandle
,
751 EFI_OPEN_PROTOCOL_GET_PROTOCOL
753 if (EFI_ERROR (Status
)) {
757 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
760 // Configure the ip6 instance for icmp6 packet exchange.
762 Ip6Config
.DefaultProtocol
= 58;
763 Ip6Config
.AcceptAnyProtocol
= FALSE
;
764 Ip6Config
.AcceptIcmpErrors
= TRUE
;
765 Ip6Config
.AcceptPromiscuous
= FALSE
;
766 Ip6Config
.TrafficClass
= 0;
767 Ip6Config
.HopLimit
= 128;
768 Ip6Config
.FlowLabel
= 0;
769 Ip6Config
.ReceiveTimeout
= 0;
770 Ip6Config
.TransmitTimeout
= 0;
772 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
774 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
776 Status
= Private
->Ip6
->Configure (Private
->Ip6
, &Ip6Config
);
778 if (EFI_ERROR (Status
)) {
779 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6_CONFIG
), mHiiHandle
, Status
);
786 if (HandleBuffer
!= NULL
) {
787 FreePool (HandleBuffer
);
790 if (IfInfo
!= NULL
) {
794 if ((Ip6Sb
!= NULL
) && (Private
->Ip6ChildHandle
!= NULL
)) {
795 Ip6Sb
->DestroyChild (Ip6Sb
, Private
->Ip6ChildHandle
);
802 Destroy the IP6 instance.
804 @param[in] Private The pointer of PING6_PRIVATE_DATA.
808 Ping6DestroyIp6Instance (
809 IN PING6_PRIVATE_DATA
*Private
813 EFI_SERVICE_BINDING_PROTOCOL
*Ip6Sb
;
816 Private
->Ip6ChildHandle
,
817 &gEfiIp6ProtocolGuid
,
818 Private
->ImageHandle
,
819 Private
->Ip6ChildHandle
822 Status
= gBS
->HandleProtocol (
824 &gEfiIp6ServiceBindingProtocolGuid
,
828 if (!EFI_ERROR(Status
)) {
829 Ip6Sb
->DestroyChild (Ip6Sb
, Private
->Ip6ChildHandle
);
836 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
837 @param[in] SendNumber The send request count.
838 @param[in] BufferSize The send buffer size.
839 @param[in] SrcAddress The source IPv6 address.
840 @param[in] DstAddress The destination IPv6 address.
842 @retval EFI_SUCCESS The ping6 processed successfullly.
843 @retval others The ping6 processed unsuccessfully.
848 IN EFI_HANDLE ImageHandle
,
849 IN UINT32 SendNumber
,
850 IN UINT32 BufferSize
,
851 IN EFI_IPv6_ADDRESS
*SrcAddress
,
852 IN EFI_IPv6_ADDRESS
*DstAddress
857 PING6_PRIVATE_DATA
*Private
;
858 PING6_ICMP6_TX_INFO
*TxInfo
;
860 LIST_ENTRY
*NextEntry
;
862 Private
= AllocateZeroPool (sizeof (PING6_PRIVATE_DATA
));
864 ASSERT (Private
!= NULL
);
866 Private
->ImageHandle
= ImageHandle
;
867 Private
->SendNum
= SendNumber
;
868 Private
->BufferSize
= BufferSize
;
869 Private
->RttMin
= ~((UINT64
)(0x0));
870 Private
->Status
= EFI_NOT_READY
;
872 InitializeListHead (&Private
->TxList
);
874 IP6_COPY_ADDRESS (&Private
->SrcAddress
, SrcAddress
);
875 IP6_COPY_ADDRESS (&Private
->DstAddress
, DstAddress
);
878 // Open and configure a ip6 instance for ping6.
880 Status
= Ping6CreateIp6Instance (Private
);
882 if (EFI_ERROR (Status
)) {
886 // Print the command line itself.
888 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_START
), mHiiHandle
, mIp6DstString
, Private
->BufferSize
);
890 // Create a ipv6 token to receive the first icmp6 echo reply packet.
892 Status
= Ping6ReceiveEchoReply (Private
);
894 if (EFI_ERROR (Status
)) {
898 // Create and start timer to send icmp6 echo request packet per second.
900 Status
= gBS
->CreateEvent (
901 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
908 if (EFI_ERROR (Status
)) {
912 // Create a ipv6 token to send the first icmp6 echo request packet.
914 Status
= Ping6SendEchoRequest (Private
);
916 // EFI_NOT_READY for IPsec is enable and IKE is not established.
918 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
919 if(Status
== EFI_NOT_FOUND
) {
920 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN
), mHiiHandle
, mIp6DstString
);
926 Status
= gBS
->SetTimer (
932 if (EFI_ERROR (Status
)) {
936 // Control the ping6 process by two factors:
938 // 2. Private->Status
939 // 2.1. success means all icmp6 echo request packets get reply packets.
940 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
941 // 2.3. noready means ping6 process is on-the-go.
943 while (Private
->Status
== EFI_NOT_READY
) {
944 Private
->Ip6
->Poll (Private
->Ip6
);
947 // Terminate the ping6 process by 'esc' or 'ctl-c'.
949 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
951 if (!EFI_ERROR(Status
)) {
952 if ((Key
.UnicodeChar
== 0x1b) || (Key
.UnicodeChar
== 0x03) ||
953 ((Key
.UnicodeChar
== 0) && (Key
.ScanCode
== SCAN_ESC
))) {
961 // Display the statistics in all.
963 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
965 if (Private
->TxCount
!= 0) {
970 STRING_TOKEN (STR_PING6_STAT
),
974 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
979 if (Private
->RxCount
!= 0) {
984 STRING_TOKEN (STR_PING6_RTT
),
988 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
994 if (Private
!= NULL
) {
995 Private
->Status
= EFI_ABORTED
;
997 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
998 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
1000 Status
= Private
->Ip6
->Cancel (Private
->Ip6
, TxInfo
->Token
);
1002 RemoveEntryList (&TxInfo
->Link
);
1003 Ping6DestroyTxInfo (TxInfo
);
1006 if (Private
->Timer
!= NULL
) {
1007 gBS
->CloseEvent (Private
->Timer
);
1010 if (Private
->Ip6
!= NULL
) {
1011 Status
= Private
->Ip6
->Cancel (Private
->Ip6
, &Private
->RxToken
);
1014 if (Private
->RxToken
.Event
!= NULL
) {
1015 gBS
->CloseEvent (Private
->RxToken
.Event
);
1018 if (Private
->Ip6ChildHandle
!= NULL
) {
1019 Ping6DestroyIp6Instance (Private
);
1029 This is the declaration of an EFI image entry point. This entry point is
1030 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including
1031 both device drivers and bus drivers.
1033 The entry point for the Ping6 application that parses the command line input and calls the Ping6 process.
1035 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
1036 @param[in] SystemTable A pointer to the EFI System Table.
1038 @retval EFI_SUCCESS The operation completed successfully.
1039 @retval EFI_INVALID_PARAMETETR Input parameters combination is invalid.
1040 @retval Others Some errors occur.
1046 IN EFI_HANDLE ImageHandle
,
1047 IN EFI_SYSTEM_TABLE
*SystemTable
1051 EFI_IPv6_ADDRESS DstAddress
;
1052 EFI_IPv6_ADDRESS SrcAddress
;
1055 LIST_ENTRY
*ParamPackage
;
1056 CONST CHAR16
*ValueStr
;
1057 CONST CHAR16
*ValueStrPtr
;
1058 UINTN NonOptionCount
;
1059 EFI_HII_PACKAGE_LIST_HEADER
*PackageList
;
1062 // Retrieve HII package list from ImageHandle
1064 Status
= gBS
->OpenProtocol (
1066 &gEfiHiiPackageListProtocolGuid
,
1067 (VOID
**) &PackageList
,
1070 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1072 if (EFI_ERROR (Status
)) {
1077 // Publish HII package list to HII Database.
1079 Status
= gHiiDatabase
->NewPackageList (
1085 if (EFI_ERROR (Status
)) {
1089 ASSERT (mHiiHandle
!= NULL
);
1091 Status
= ShellCommandLineParseEx (Ping6ParamList
, &ParamPackage
, NULL
, TRUE
, FALSE
);
1092 if (EFI_ERROR(Status
)) {
1093 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_INPUT
), mHiiHandle
);
1101 // Parse the paramter of count number.
1103 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1104 ValueStrPtr
= ValueStr
;
1105 if (ValueStr
!= NULL
) {
1106 SendNumber
= ShellStrToUintn (ValueStrPtr
);
1109 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1111 if ((SendNumber
== 0) || (SendNumber
> PING6_MAX_SEND_NUMBER
)) {
1112 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER
), mHiiHandle
, ValueStr
);
1113 Status
= EFI_INVALID_PARAMETER
;
1118 // Parse the paramter of buffer size.
1120 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1121 ValueStrPtr
= ValueStr
;
1122 if (ValueStr
!= NULL
) {
1123 BufferSize
= ShellStrToUintn (ValueStrPtr
);
1126 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1128 if ((BufferSize
< 16) || (BufferSize
> PING6_MAX_BUFFER_SIZE
)) {
1129 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE
), mHiiHandle
, ValueStr
);
1130 Status
= EFI_INVALID_PARAMETER
;
1135 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1136 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1139 // Parse the paramter of source ip address.
1141 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1142 ValueStrPtr
= ValueStr
;
1143 if (ValueStr
!= NULL
) {
1144 mIp6SrcString
= ValueStr
;
1145 Status
= NetLibStrToIp6 (ValueStrPtr
, &SrcAddress
);
1146 if (EFI_ERROR (Status
)) {
1147 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_IP
), mHiiHandle
, ValueStr
);
1148 Status
= EFI_INVALID_PARAMETER
;
1153 // Parse the paramter of destination ip address.
1155 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1156 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, (UINT32
)(NonOptionCount
-1));
1157 if (NonOptionCount
!= 2) {
1158 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_INPUT
), mHiiHandle
);
1159 Status
= EFI_INVALID_PARAMETER
;
1162 ValueStrPtr
= ValueStr
;
1163 if (ValueStr
!= NULL
) {
1164 mIp6DstString
= ValueStr
;
1165 Status
= NetLibStrToIp6 (ValueStrPtr
, &DstAddress
);
1166 if (EFI_ERROR (Status
)) {
1167 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_IP
), mHiiHandle
, ValueStr
);
1168 Status
= EFI_INVALID_PARAMETER
;
1173 // Get frequency to calculate the time from ticks.
1175 Status
= Ping6GetFrequency ();
1177 if (EFI_ERROR(Status
)) {
1181 // Enter into ping6 process.
1192 ShellCommandLineFreeVarList (ParamPackage
);
1193 HiiRemovePackages (mHiiHandle
);