2 The implementation for Ping6 application.
4 Copyright (c) 2009 - 2010, 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/HiiLib.h>
23 #include <Library/NetLib.h>
25 #include <Protocol/Cpu.h>
26 #include <Protocol/ServiceBinding.h>
27 #include <Protocol/Ip6.h>
28 #include <Protocol/Ip6Config.h>
32 SHELL_PARAM_ITEM Ping6ParamList
[] = {
56 // Global Variables in Ping6 application.
58 EFI_HII_HANDLE mHiiHandle
;
59 CONST CHAR16
*mIp6DstString
;
60 CONST CHAR16
*mIp6SrcString
;
61 EFI_GUID mEfiPing6Guid
= EFI_PING6_GUID
;
62 UINT64 mFrequency
= 0;
64 Get and caculate the frequency in tick/ms.
65 The result is saved in the globle variable mFrequency
67 @retval EFI_SUCCESS Caculated the frequency successfully.
68 @retval Others Failed to caculate the frequency.
77 EFI_CPU_ARCH_PROTOCOL
*Cpu
;
81 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &Cpu
);
83 if (EFI_ERROR (Status
)) {
87 Status
= Cpu
->GetTimerValue (Cpu
, 0, &CurrentTick
, &TimerPeriod
);
89 if (EFI_ERROR (Status
)) {
91 // For NT32 Simulator only. 358049 is a similar value to keep timer granularity.
92 // Set the timer period by ourselves.
94 TimerPeriod
= (UINT64
) NTTIMERPERIOD
;
97 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
98 // So 1e+12 is divided by timer period to produce the freq in tick/ms.
100 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
106 Get and caculate the duration in ms.
108 @param[in] Begin The start point of time.
109 @param[in] End The end point of time.
111 @return The duration in ms.
120 ASSERT (End
> Begin
);
121 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
125 Destroy IPING6_ICMP6_TX_INFO, and recollect the memory.
127 @param[in] TxInfo The pointer to PING6_ICMP6_TX_INFO.
132 IN PING6_ICMP6_TX_INFO
*TxInfo
135 EFI_IP6_TRANSMIT_DATA
*TxData
;
136 EFI_IP6_FRAGMENT_DATA
*FragData
;
139 ASSERT (TxInfo
!= NULL
);
141 if (TxInfo
->Token
!= NULL
) {
143 if (TxInfo
->Token
->Event
!= NULL
) {
144 gBS
->CloseEvent (TxInfo
->Token
->Event
);
147 TxData
= TxInfo
->Token
->Packet
.TxData
;
148 if (TxData
!= NULL
) {
150 if (TxData
->OverrideData
!= NULL
) {
151 FreePool (TxData
->OverrideData
);
154 if (TxData
->ExtHdrs
!= NULL
) {
155 FreePool (TxData
->ExtHdrs
);
158 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
159 FragData
= TxData
->FragmentTable
[Index
].FragmentBuffer
;
160 if (FragData
!= NULL
) {
166 FreePool (TxInfo
->Token
);
173 Match the request, and reply with SequenceNum/TimeStamp.
175 @param[in] Private The pointer to PING6_PRIVATE_DATA.
176 @param[in] Packet The pointer to ICMP6_ECHO_REQUEST_REPLY.
178 @retval EFI_SUCCESS The match is successful.
179 @retval EFI_NOT_FOUND The reply can't be matched with any request.
183 Ping6MatchEchoReply (
184 IN PING6_PRIVATE_DATA
*Private
,
185 IN ICMP6_ECHO_REQUEST_REPLY
*Packet
188 PING6_ICMP6_TX_INFO
*TxInfo
;
190 LIST_ENTRY
*NextEntry
;
192 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
193 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
195 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
197 RemoveEntryList (&TxInfo
->Link
);
198 Ping6DestroyTxInfo (TxInfo
);
203 return EFI_NOT_FOUND
;
207 The original intention is to send a request.
208 Currently, the application retransmits an icmp6 echo request packet
209 per second in sendnumber times that is specified by the user.
210 Because nothing can be done here, all things move to the timer rountine.
212 @param[in] Event A EFI_EVENT type event.
213 @param[in] Context The pointer to Context.
218 Ping6OnEchoRequestSent (
226 receive reply, match and print reply infomation.
228 @param[in] Event A EFI_EVENT type event.
229 @param[in] Context The pointer to context.
234 Ping6OnEchoReplyReceived (
240 PING6_PRIVATE_DATA
*Private
;
241 EFI_IP6_COMPLETION_TOKEN
*RxToken
;
242 EFI_IP6_RECEIVE_DATA
*RxData
;
243 ICMP6_ECHO_REQUEST_REPLY
*Reply
;
248 Private
= (PING6_PRIVATE_DATA
*) Context
;
250 if (Private
->Status
== EFI_ABORTED
) {
254 RxToken
= &Private
->RxToken
;
255 RxData
= RxToken
->Packet
.RxData
;
256 Reply
= RxData
->FragmentTable
[0].FragmentBuffer
;
257 PayLoad
= RxData
->DataLength
;
259 if (RxData
->Header
->NextHeader
!= IP6_ICMP
) {
263 if (!IP6_IS_MULTICAST (&Private
->DstAddress
) &&
264 !EFI_IP6_EQUAL (&RxData
->Header
->SourceAddress
, &Private
->DstAddress
)) {
268 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
272 if (PayLoad
!= Private
->BufferSize
) {
276 // Check whether the reply matches the sent request before.
278 Status
= Ping6MatchEchoReply (Private
, Reply
);
279 if (EFI_ERROR(Status
)) {
283 // Display statistics on this icmp6 echo reply packet.
285 Rtt
= Ping6CalculateTick (Reply
->TimeStamp
, ReadTime ());
292 Private
->RttSum
+= Rtt
;
293 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
294 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
300 STRING_TOKEN (STR_PING6_REPLY_INFO
),
305 RxData
->Header
->HopLimit
,
312 if (Private
->RxCount
< Private
->SendNum
) {
314 // Continue to receive icmp6 echo reply packets.
316 RxToken
->Status
= EFI_ABORTED
;
318 Status
= Private
->Ip6
->Receive (Private
->Ip6
, RxToken
);
320 if (EFI_ERROR (Status
)) {
321 Private
->Status
= EFI_ABORTED
;
325 // All reply have already been received from the dest host.
327 Private
->Status
= EFI_SUCCESS
;
330 // Singal to recycle the each rxdata here, not at the end of process.
332 gBS
->SignalEvent (RxData
->RecycleSignal
);
336 Initial EFI_IP6_COMPLETION_TOKEN.
338 @param[in] Private The pointer of PING6_PRIVATE_DATA.
339 @param[in] TimeStamp The TimeStamp of request.
340 @param[in] SequenceNum The SequenceNum of request.
342 @return The pointer of EFI_IP6_COMPLETION_TOKEN.
345 EFI_IP6_COMPLETION_TOKEN
*
347 IN PING6_PRIVATE_DATA
*Private
,
349 IN UINT16 SequenceNum
353 EFI_IP6_COMPLETION_TOKEN
*Token
;
354 EFI_IP6_TRANSMIT_DATA
*TxData
;
355 ICMP6_ECHO_REQUEST_REPLY
*Request
;
357 Request
= AllocateZeroPool (Private
->BufferSize
);
359 if (Request
== NULL
) {
363 // Assembly icmp6 echo request packet.
365 Request
->Type
= ICMP_V6_ECHO_REQUEST
;
367 Request
->SequenceNum
= SequenceNum
;
368 Request
->TimeStamp
= TimeStamp
;
369 Request
->Identifier
= 0;
371 // Leave check sum to ip6 layer, since it has no idea of source address
374 Request
->Checksum
= 0;
376 TxData
= AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA
));
378 if (TxData
== NULL
) {
383 // Assembly ipv6 token for transmit.
385 TxData
->OverrideData
= 0;
386 TxData
->ExtHdrsLength
= 0;
387 TxData
->ExtHdrs
= NULL
;
388 TxData
->DataLength
= Private
->BufferSize
;
389 TxData
->FragmentCount
= 1;
390 TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
391 TxData
->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
393 Token
= AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN
));
401 Token
->Status
= EFI_ABORTED
;
402 Token
->Packet
.TxData
= TxData
;
404 Status
= gBS
->CreateEvent (
407 Ping6OnEchoRequestSent
,
412 if (EFI_ERROR (Status
)) {
423 Transmit the EFI_IP6_COMPLETION_TOKEN.
425 @param[in] Private The pointer of PING6_PRIVATE_DATA.
427 @retval EFI_SUCCESS Transmitted successfully.
428 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
429 @retval others Transmitted unsuccessfully.
433 Ping6SendEchoRequest (
434 IN PING6_PRIVATE_DATA
*Private
438 PING6_ICMP6_TX_INFO
*TxInfo
;
440 TxInfo
= AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO
));
442 if (TxInfo
== NULL
) {
443 return EFI_OUT_OF_RESOURCES
;
446 TxInfo
->TimeStamp
= ReadTime ();
447 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
449 TxInfo
->Token
= Ping6GenerateToken (
455 if (TxInfo
->Token
== NULL
) {
456 Ping6DestroyTxInfo (TxInfo
);
457 return EFI_OUT_OF_RESOURCES
;
460 Status
= Private
->Ip6
->Transmit (Private
->Ip6
, TxInfo
->Token
);
462 if (EFI_ERROR (Status
)) {
463 Ping6DestroyTxInfo (TxInfo
);
467 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
474 Place a completion token into the receive packet queue to receive the echo reply.
476 @param[in] Private The pointer of PING6_PRIVATE_DATA.
478 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
479 @retval others Put the token into the receive packet queue unsuccessfully.
483 Ping6ReceiveEchoReply (
484 IN PING6_PRIVATE_DATA
*Private
489 ZeroMem (&Private
->RxToken
, sizeof (EFI_IP6_COMPLETION_TOKEN
));
491 Status
= gBS
->CreateEvent (
494 Ping6OnEchoReplyReceived
,
496 &Private
->RxToken
.Event
499 if (EFI_ERROR (Status
)) {
503 Private
->RxToken
.Status
= EFI_NOT_READY
;
505 return Private
->Ip6
->Receive (Private
->Ip6
, &Private
->RxToken
);
509 Remove the timeout request from the list.
511 @param[in] Event A EFI_EVENT type event.
512 @param[in] Context The pointer to Context.
517 Ping6OnTimerRoutine (
523 PING6_PRIVATE_DATA
*Private
;
524 PING6_ICMP6_TX_INFO
*TxInfo
;
526 LIST_ENTRY
*NextEntry
;
529 Private
= (PING6_PRIVATE_DATA
*) Context
;
532 // Retransmit icmp6 echo request packets per second in sendnumber times.
534 if (Private
->TxCount
< Private
->SendNum
) {
536 Status
= Ping6SendEchoRequest (Private
);
537 if (Private
->TxCount
!= 0){
538 if (EFI_ERROR (Status
)) {
539 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_SEND_REQUEST
), mHiiHandle
, Private
->TxCount
+ 1);
544 // Check whether any icmp6 echo request in the list timeout.
546 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
547 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
548 Time
= Ping6CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
551 // Remove the timeout echo request from txlist.
553 if (Time
> PING6_DEFAULT_TIMEOUT
) {
555 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
556 Private
->Ip6
->Cancel (Private
->Ip6
, TxInfo
->Token
);
559 // Remove the timeout icmp6 echo request from list.
561 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_TIMEOUT
), mHiiHandle
, TxInfo
->SequenceNum
);
563 RemoveEntryList (&TxInfo
->Link
);
564 Ping6DestroyTxInfo (TxInfo
);
566 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
568 // All the left icmp6 echo request in the list timeout.
570 Private
->Status
= EFI_TIMEOUT
;
577 Create a valid IP6 instance.
579 @param[in] Private The pointer of PING6_PRIVATE_DATA.
581 @retval EFI_SUCCESS Create a valid IP6 instance successfully.
582 @retval EFI_ABORTED Locate handle with ip6 service binding protocol unsuccessfully.
583 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link -ocal address.
584 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
585 @retval EFI_NOT_FOUND The source address is not found.
588 Ping6CreateIp6Instance (
589 IN PING6_PRIVATE_DATA
*Private
595 EFI_HANDLE
*HandleBuffer
;
596 EFI_SERVICE_BINDING_PROTOCOL
*Ip6Sb
;
597 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
598 EFI_IP6_CONFIG_DATA Ip6Config
;
599 EFI_IP6_CONFIG_INTERFACE_INFO
*IfInfo
;
601 EFI_IPv6_ADDRESS
*Addr
;
610 // Locate all the handles with ip6 service binding protocol.
612 Status
= gBS
->LocateHandleBuffer (
614 &gEfiIp6ServiceBindingProtocolGuid
,
619 if (EFI_ERROR (Status
) || (HandleNum
== 0)) {
623 // Source address is required when pinging a link-local address on multi-
626 if (NetIp6IsLinkLocalAddr (&Private
->DstAddress
) &&
627 NetIp6IsUnspecifiedAddr (&Private
->SrcAddress
) &&
629 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_SOURCE
), mHiiHandle
);
630 Status
= EFI_INVALID_PARAMETER
;
634 // For each ip6 protocol, check interface addresses list.
636 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
642 Status
= gBS
->HandleProtocol (
643 HandleBuffer
[HandleIndex
],
644 &gEfiIp6ServiceBindingProtocolGuid
,
647 if (EFI_ERROR (Status
)) {
651 if (NetIp6IsUnspecifiedAddr (&Private
->SrcAddress
)) {
653 // No need to match interface address.
658 // Ip6config protocol and ip6 service binding protocol are installed
659 // on the same handle.
661 Status
= gBS
->HandleProtocol (
662 HandleBuffer
[HandleIndex
],
663 &gEfiIp6ConfigProtocolGuid
,
667 if (EFI_ERROR (Status
)) {
671 // Get the interface information size.
673 Status
= Ip6Cfg
->GetData (
675 Ip6ConfigDataTypeInterfaceInfo
,
680 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
681 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA
), mHiiHandle
, Status
);
685 IfInfo
= AllocateZeroPool (IfInfoSize
);
687 if (IfInfo
== NULL
) {
688 Status
= EFI_OUT_OF_RESOURCES
;
692 // Get the interface info.
694 Status
= Ip6Cfg
->GetData (
696 Ip6ConfigDataTypeInterfaceInfo
,
701 if (EFI_ERROR (Status
)) {
702 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA
), mHiiHandle
, Status
);
706 // Check whether the source address is one of the interface addresses.
708 for (AddrIndex
= 0; AddrIndex
< IfInfo
->AddressInfoCount
; AddrIndex
++) {
710 Addr
= &(IfInfo
->AddressInfo
[AddrIndex
].Address
);
711 if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
713 // Match a certain interface address.
719 if (AddrIndex
< IfInfo
->AddressInfoCount
) {
721 // Found a nic handle with right interface address.
731 // No exact interface address matched.
734 if (HandleIndex
== HandleNum
) {
735 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND
), mHiiHandle
, mIp6SrcString
);
736 Status
= EFI_NOT_FOUND
;
740 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
742 ASSERT (Ip6Sb
!= NULL
);
743 Status
= Ip6Sb
->CreateChild (Ip6Sb
, &Private
->Ip6ChildHandle
);
745 if (EFI_ERROR (Status
)) {
749 Status
= gBS
->OpenProtocol (
750 Private
->Ip6ChildHandle
,
751 &gEfiIp6ProtocolGuid
,
752 (VOID
**) &Private
->Ip6
,
753 Private
->ImageHandle
,
754 Private
->Ip6ChildHandle
,
755 EFI_OPEN_PROTOCOL_GET_PROTOCOL
757 if (EFI_ERROR (Status
)) {
761 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
764 // Configure the ip6 instance for icmp6 packet exchange.
766 Ip6Config
.DefaultProtocol
= 58;
767 Ip6Config
.AcceptAnyProtocol
= FALSE
;
768 Ip6Config
.AcceptIcmpErrors
= TRUE
;
769 Ip6Config
.AcceptPromiscuous
= FALSE
;
770 Ip6Config
.TrafficClass
= 0;
771 Ip6Config
.HopLimit
= 128;
772 Ip6Config
.FlowLabel
= 0;
773 Ip6Config
.ReceiveTimeout
= 0;
774 Ip6Config
.TransmitTimeout
= 0;
776 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
778 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
780 Status
= Private
->Ip6
->Configure (Private
->Ip6
, &Ip6Config
);
782 if (EFI_ERROR (Status
)) {
783 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6_CONFIG
), mHiiHandle
, Status
);
790 if (HandleBuffer
!= NULL
) {
791 FreePool (HandleBuffer
);
794 if (IfInfo
!= NULL
) {
798 if ((Ip6Sb
!= NULL
) && (Private
->Ip6ChildHandle
!= NULL
)) {
799 Ip6Sb
->DestroyChild (Ip6Sb
, Private
->Ip6ChildHandle
);
806 Destory the IP6 instance.
808 @param[in] Private The pointer of PING6_PRIVATE_DATA.
812 Ping6DestoryIp6Instance (
813 IN PING6_PRIVATE_DATA
*Private
817 EFI_SERVICE_BINDING_PROTOCOL
*Ip6Sb
;
820 Private
->Ip6ChildHandle
,
821 &gEfiIp6ProtocolGuid
,
822 Private
->ImageHandle
,
823 Private
->Ip6ChildHandle
826 Status
= gBS
->HandleProtocol (
828 &gEfiIp6ServiceBindingProtocolGuid
,
832 if (!EFI_ERROR(Status
)) {
833 Ip6Sb
->DestroyChild (Ip6Sb
, Private
->Ip6ChildHandle
);
840 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
841 @param[in] SendNumber The send request count.
842 @param[in] BufferSize The send buffer size.
843 @param[in] SrcAddress The source IPv6 address.
844 @param[in] DstAddress The destination IPv6 address.
846 @retval EFI_SUCCESS The ping6 processed successfullly.
847 @retval others The ping6 processed unsuccessfully.
852 IN EFI_HANDLE ImageHandle
,
853 IN UINT32 SendNumber
,
854 IN UINT32 BufferSize
,
855 IN EFI_IPv6_ADDRESS
*SrcAddress
,
856 IN EFI_IPv6_ADDRESS
*DstAddress
861 PING6_PRIVATE_DATA
*Private
;
862 PING6_ICMP6_TX_INFO
*TxInfo
;
864 LIST_ENTRY
*NextEntry
;
866 Private
= AllocateZeroPool (sizeof (PING6_PRIVATE_DATA
));
868 ASSERT (Private
!= NULL
);
870 Private
->ImageHandle
= ImageHandle
;
871 Private
->SendNum
= SendNumber
;
872 Private
->BufferSize
= BufferSize
;
873 Private
->RttMin
= ~((UINT64
)(0x0));
874 Private
->Status
= EFI_NOT_READY
;
876 InitializeListHead (&Private
->TxList
);
878 IP6_COPY_ADDRESS (&Private
->SrcAddress
, SrcAddress
);
879 IP6_COPY_ADDRESS (&Private
->DstAddress
, DstAddress
);
882 // Open and configure a ip6 instance for ping6.
884 Status
= Ping6CreateIp6Instance (Private
);
886 if (EFI_ERROR (Status
)) {
890 // Print the command line itself.
892 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_START
), mHiiHandle
, mIp6DstString
, Private
->BufferSize
);
894 // Create a ipv6 token to receive the first icmp6 echo reply packet.
896 Status
= Ping6ReceiveEchoReply (Private
);
898 if (EFI_ERROR (Status
)) {
902 // Create and start timer to send icmp6 echo request packet per second.
904 Status
= gBS
->CreateEvent (
905 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
912 if (EFI_ERROR (Status
)) {
916 // Create a ipv6 token to send the first icmp6 echo request packet.
918 Status
= Ping6SendEchoRequest (Private
);
920 // EFI_NOT_READY for IPsec is enable and IKE is not established.
922 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
923 if(Status
== EFI_NOT_FOUND
) {
924 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN
), mHiiHandle
, mIp6DstString
);
930 Status
= gBS
->SetTimer (
936 if (EFI_ERROR (Status
)) {
940 // Control the ping6 process by two factors:
942 // 2. Private->Status
943 // 2.1. success means all icmp6 echo request packets get reply packets.
944 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
945 // 2.3. noready means ping6 process is on-the-go.
947 while (Private
->Status
== EFI_NOT_READY
) {
948 Private
->Ip6
->Poll (Private
->Ip6
);
951 // Terminate the ping6 process by 'esc' or 'ctl-c'.
953 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
955 if (!EFI_ERROR(Status
)) {
956 if ((Key
.UnicodeChar
== 0x1b) || (Key
.UnicodeChar
== 0x03) ||
957 ((Key
.UnicodeChar
== 0) && (Key
.ScanCode
== SCAN_ESC
))) {
965 // Display the statistics in all.
967 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
969 if (Private
->TxCount
!= 0) {
974 STRING_TOKEN (STR_PING6_STAT
),
978 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
983 if (Private
->RxCount
!= 0) {
988 STRING_TOKEN (STR_PING6_RTT
),
992 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
998 if (Private
!= NULL
) {
999 Private
->Status
= EFI_ABORTED
;
1001 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1002 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
1004 Status
= Private
->Ip6
->Cancel (Private
->Ip6
, TxInfo
->Token
);
1006 RemoveEntryList (&TxInfo
->Link
);
1007 Ping6DestroyTxInfo (TxInfo
);
1010 if (Private
->Timer
!= NULL
) {
1011 gBS
->CloseEvent (Private
->Timer
);
1014 if (Private
->Ip6
!= NULL
) {
1015 Status
= Private
->Ip6
->Cancel (Private
->Ip6
, &Private
->RxToken
);
1018 if (Private
->RxToken
.Event
!= NULL
) {
1019 gBS
->CloseEvent (Private
->RxToken
.Event
);
1022 if (Private
->Ip6ChildHandle
!= NULL
) {
1023 Ping6DestoryIp6Instance (Private
);
1033 This is the declaration of an EFI image entry point. This entry point is
1034 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including
1035 both device drivers and bus drivers.
1037 The entry point for the Ping6 application that parses the command line input and calls the Ping6 process.
1039 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
1040 @param[in] SystemTable A pointer to the EFI System Table.
1042 @retval EFI_SUCCESS The operation completed successfully.
1043 @retval EFI_INVALID_PARAMETETR Input parameters combination is invalid.
1044 @retval Others Some errors occur.
1050 IN EFI_HANDLE ImageHandle
,
1051 IN EFI_SYSTEM_TABLE
*SystemTable
1055 EFI_IPv6_ADDRESS DstAddress
;
1056 EFI_IPv6_ADDRESS SrcAddress
;
1059 LIST_ENTRY
*ParamPackage
;
1060 CONST CHAR16
*ValueStr
;
1061 CONST CHAR16
*ValueStrPtr
;
1062 UINTN NonOptionCount
;
1065 // Register our string package with HII and return the handle to it.
1067 mHiiHandle
= HiiAddPackages (&gEfiCallerIdGuid
, ImageHandle
, Ping6Strings
, NULL
);
1068 ASSERT (mHiiHandle
!= NULL
);
1070 Status
= ShellCommandLineParseEx (Ping6ParamList
, &ParamPackage
, NULL
, TRUE
, FALSE
);
1071 if (EFI_ERROR(Status
)) {
1072 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_INPUT
), mHiiHandle
);
1076 if (ShellCommandLineGetFlag (ParamPackage
, L
"-?")) {
1077 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_HELP
), mHiiHandle
);
1085 // Parse the paramter of count number.
1087 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1088 ValueStrPtr
= ValueStr
;
1089 if (ValueStr
!= NULL
) {
1090 SendNumber
= ShellStrToUintn (ValueStrPtr
);
1093 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1095 if ((SendNumber
== 0) || (SendNumber
> PING6_MAX_SEND_NUMBER
)) {
1096 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER
), mHiiHandle
, ValueStr
);
1097 Status
= EFI_INVALID_PARAMETER
;
1102 // Parse the paramter of buffer size.
1104 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1105 ValueStrPtr
= ValueStr
;
1106 if (ValueStr
!= NULL
) {
1107 BufferSize
= ShellStrToUintn (ValueStrPtr
);
1110 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1112 if ((BufferSize
< 16) || (BufferSize
> PING6_MAX_BUFFER_SIZE
)) {
1113 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE
), mHiiHandle
, ValueStr
);
1114 Status
= EFI_INVALID_PARAMETER
;
1119 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1120 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1123 // Parse the paramter of source ip address.
1125 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1126 ValueStrPtr
= ValueStr
;
1127 if (ValueStr
!= NULL
) {
1128 mIp6SrcString
= ValueStr
;
1129 Status
= NetLibStrToIp6 (ValueStrPtr
, &SrcAddress
);
1130 if (EFI_ERROR (Status
)) {
1131 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_IP
), mHiiHandle
, ValueStr
);
1132 Status
= EFI_INVALID_PARAMETER
;
1137 // Parse the paramter of destination ip address.
1139 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1140 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, (UINT32
)(NonOptionCount
-1));
1141 if (NonOptionCount
!= 2) {
1142 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_INPUT
), mHiiHandle
);
1143 Status
= EFI_INVALID_PARAMETER
;
1146 ValueStrPtr
= ValueStr
;
1147 if (ValueStr
!= NULL
) {
1148 mIp6DstString
= ValueStr
;
1149 Status
= NetLibStrToIp6 (ValueStrPtr
, &DstAddress
);
1150 if (EFI_ERROR (Status
)) {
1151 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_IP
), mHiiHandle
, ValueStr
);
1152 Status
= EFI_INVALID_PARAMETER
;
1157 // Get frequency to calculate the time from ticks.
1159 Status
= Ping6GetFrequency ();
1161 if (EFI_ERROR(Status
)) {
1165 // Enter into ping6 process.
1176 ShellCommandLineFreeVarList (ParamPackage
);
1177 HiiRemovePackages (mHiiHandle
);