2 The implementation for Ping6 application.
4 Copyright (c) 2009 - 2011, 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 UINT64 mFrequency
= 0;
63 Get and caculate the frequency in tick/ms.
64 The result is saved in the globle variable mFrequency
66 @retval EFI_SUCCESS Caculated the frequency successfully.
67 @retval Others Failed to caculate the frequency.
76 EFI_CPU_ARCH_PROTOCOL
*Cpu
;
80 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &Cpu
);
82 if (EFI_ERROR (Status
)) {
86 Status
= Cpu
->GetTimerValue (Cpu
, 0, &CurrentTick
, &TimerPeriod
);
88 if (EFI_ERROR (Status
)) {
90 // For NT32 Simulator only. 358049 is a similar value to keep timer granularity.
91 // Set the timer period by ourselves.
93 TimerPeriod
= (UINT64
) NTTIMERPERIOD
;
96 // The timer period is in femtosecond (1 femtosecond is 1e-15 second).
97 // So 1e+12 is divided by timer period to produce the freq in tick/ms.
99 mFrequency
= DivU64x64Remainder (1000000000000ULL, TimerPeriod
, NULL
);
105 Get and caculate the duration in ms.
107 @param[in] Begin The start point of time.
108 @param[in] End The end point of time.
110 @return The duration in ms.
119 ASSERT (End
> Begin
);
120 return DivU64x64Remainder (End
- Begin
, mFrequency
, NULL
);
124 Destroy IPING6_ICMP6_TX_INFO, and recollect the memory.
126 @param[in] TxInfo The pointer to PING6_ICMP6_TX_INFO.
131 IN PING6_ICMP6_TX_INFO
*TxInfo
134 EFI_IP6_TRANSMIT_DATA
*TxData
;
135 EFI_IP6_FRAGMENT_DATA
*FragData
;
138 ASSERT (TxInfo
!= NULL
);
140 if (TxInfo
->Token
!= NULL
) {
142 if (TxInfo
->Token
->Event
!= NULL
) {
143 gBS
->CloseEvent (TxInfo
->Token
->Event
);
146 TxData
= TxInfo
->Token
->Packet
.TxData
;
147 if (TxData
!= NULL
) {
149 if (TxData
->OverrideData
!= NULL
) {
150 FreePool (TxData
->OverrideData
);
153 if (TxData
->ExtHdrs
!= NULL
) {
154 FreePool (TxData
->ExtHdrs
);
157 for (Index
= 0; Index
< TxData
->FragmentCount
; Index
++) {
158 FragData
= TxData
->FragmentTable
[Index
].FragmentBuffer
;
159 if (FragData
!= NULL
) {
165 FreePool (TxInfo
->Token
);
172 Match the request, and reply with SequenceNum/TimeStamp.
174 @param[in] Private The pointer to PING6_PRIVATE_DATA.
175 @param[in] Packet The pointer to ICMP6_ECHO_REQUEST_REPLY.
177 @retval EFI_SUCCESS The match is successful.
178 @retval EFI_NOT_FOUND The reply can't be matched with any request.
182 Ping6MatchEchoReply (
183 IN PING6_PRIVATE_DATA
*Private
,
184 IN ICMP6_ECHO_REQUEST_REPLY
*Packet
187 PING6_ICMP6_TX_INFO
*TxInfo
;
189 LIST_ENTRY
*NextEntry
;
191 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
192 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
194 if ((TxInfo
->SequenceNum
== Packet
->SequenceNum
) && (TxInfo
->TimeStamp
== Packet
->TimeStamp
)) {
196 RemoveEntryList (&TxInfo
->Link
);
197 Ping6DestroyTxInfo (TxInfo
);
202 return EFI_NOT_FOUND
;
206 The original intention is to send a request.
207 Currently, the application retransmits an icmp6 echo request packet
208 per second in sendnumber times that is specified by the user.
209 Because nothing can be done here, all things move to the timer rountine.
211 @param[in] Event A EFI_EVENT type event.
212 @param[in] Context The pointer to Context.
217 Ping6OnEchoRequestSent (
225 receive reply, match and print reply infomation.
227 @param[in] Event A EFI_EVENT type event.
228 @param[in] Context The pointer to context.
233 Ping6OnEchoReplyReceived (
239 PING6_PRIVATE_DATA
*Private
;
240 EFI_IP6_COMPLETION_TOKEN
*RxToken
;
241 EFI_IP6_RECEIVE_DATA
*RxData
;
242 ICMP6_ECHO_REQUEST_REPLY
*Reply
;
247 Private
= (PING6_PRIVATE_DATA
*) Context
;
249 if (Private
->Status
== EFI_ABORTED
) {
253 RxToken
= &Private
->RxToken
;
254 RxData
= RxToken
->Packet
.RxData
;
255 Reply
= RxData
->FragmentTable
[0].FragmentBuffer
;
256 PayLoad
= RxData
->DataLength
;
258 if (RxData
->Header
->NextHeader
!= IP6_ICMP
) {
262 if (!IP6_IS_MULTICAST (&Private
->DstAddress
) &&
263 !EFI_IP6_EQUAL (&RxData
->Header
->SourceAddress
, &Private
->DstAddress
)) {
267 if ((Reply
->Type
!= ICMP_V6_ECHO_REPLY
) || (Reply
->Code
!= 0)) {
271 if (PayLoad
!= Private
->BufferSize
) {
275 // Check whether the reply matches the sent request before.
277 Status
= Ping6MatchEchoReply (Private
, Reply
);
278 if (EFI_ERROR(Status
)) {
282 // Display statistics on this icmp6 echo reply packet.
284 Rtt
= Ping6CalculateTick (Reply
->TimeStamp
, ReadTime ());
291 Private
->RttSum
+= Rtt
;
292 Private
->RttMin
= Private
->RttMin
> Rtt
? Rtt
: Private
->RttMin
;
293 Private
->RttMax
= Private
->RttMax
< Rtt
? Rtt
: Private
->RttMax
;
299 STRING_TOKEN (STR_PING6_REPLY_INFO
),
304 RxData
->Header
->HopLimit
,
311 if (Private
->RxCount
< Private
->SendNum
) {
313 // Continue to receive icmp6 echo reply packets.
315 RxToken
->Status
= EFI_ABORTED
;
317 Status
= Private
->Ip6
->Receive (Private
->Ip6
, RxToken
);
319 if (EFI_ERROR (Status
)) {
320 Private
->Status
= EFI_ABORTED
;
324 // All reply have already been received from the dest host.
326 Private
->Status
= EFI_SUCCESS
;
329 // Singal to recycle the each rxdata here, not at the end of process.
331 gBS
->SignalEvent (RxData
->RecycleSignal
);
335 Initial EFI_IP6_COMPLETION_TOKEN.
337 @param[in] Private The pointer of PING6_PRIVATE_DATA.
338 @param[in] TimeStamp The TimeStamp of request.
339 @param[in] SequenceNum The SequenceNum of request.
341 @return The pointer of EFI_IP6_COMPLETION_TOKEN.
344 EFI_IP6_COMPLETION_TOKEN
*
346 IN PING6_PRIVATE_DATA
*Private
,
348 IN UINT16 SequenceNum
352 EFI_IP6_COMPLETION_TOKEN
*Token
;
353 EFI_IP6_TRANSMIT_DATA
*TxData
;
354 ICMP6_ECHO_REQUEST_REPLY
*Request
;
356 Request
= AllocateZeroPool (Private
->BufferSize
);
358 if (Request
== NULL
) {
362 // Assembly icmp6 echo request packet.
364 Request
->Type
= ICMP_V6_ECHO_REQUEST
;
366 Request
->SequenceNum
= SequenceNum
;
367 Request
->TimeStamp
= TimeStamp
;
368 Request
->Identifier
= 0;
370 // Leave check sum to ip6 layer, since it has no idea of source address
373 Request
->Checksum
= 0;
375 TxData
= AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA
));
377 if (TxData
== NULL
) {
382 // Assembly ipv6 token for transmit.
384 TxData
->OverrideData
= 0;
385 TxData
->ExtHdrsLength
= 0;
386 TxData
->ExtHdrs
= NULL
;
387 TxData
->DataLength
= Private
->BufferSize
;
388 TxData
->FragmentCount
= 1;
389 TxData
->FragmentTable
[0].FragmentBuffer
= (VOID
*) Request
;
390 TxData
->FragmentTable
[0].FragmentLength
= Private
->BufferSize
;
392 Token
= AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN
));
400 Token
->Status
= EFI_ABORTED
;
401 Token
->Packet
.TxData
= TxData
;
403 Status
= gBS
->CreateEvent (
406 Ping6OnEchoRequestSent
,
411 if (EFI_ERROR (Status
)) {
422 Transmit the EFI_IP6_COMPLETION_TOKEN.
424 @param[in] Private The pointer of PING6_PRIVATE_DATA.
426 @retval EFI_SUCCESS Transmitted successfully.
427 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
428 @retval others Transmitted unsuccessfully.
432 Ping6SendEchoRequest (
433 IN PING6_PRIVATE_DATA
*Private
437 PING6_ICMP6_TX_INFO
*TxInfo
;
439 TxInfo
= AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO
));
441 if (TxInfo
== NULL
) {
442 return EFI_OUT_OF_RESOURCES
;
445 TxInfo
->TimeStamp
= ReadTime ();
446 TxInfo
->SequenceNum
= (UINT16
) (Private
->TxCount
+ 1);
448 TxInfo
->Token
= Ping6GenerateToken (
454 if (TxInfo
->Token
== NULL
) {
455 Ping6DestroyTxInfo (TxInfo
);
456 return EFI_OUT_OF_RESOURCES
;
459 Status
= Private
->Ip6
->Transmit (Private
->Ip6
, TxInfo
->Token
);
461 if (EFI_ERROR (Status
)) {
462 Ping6DestroyTxInfo (TxInfo
);
466 InsertTailList (&Private
->TxList
, &TxInfo
->Link
);
473 Place a completion token into the receive packet queue to receive the echo reply.
475 @param[in] Private The pointer of PING6_PRIVATE_DATA.
477 @retval EFI_SUCCESS Put the token into the receive packet queue successfully.
478 @retval others Put the token into the receive packet queue unsuccessfully.
482 Ping6ReceiveEchoReply (
483 IN PING6_PRIVATE_DATA
*Private
488 ZeroMem (&Private
->RxToken
, sizeof (EFI_IP6_COMPLETION_TOKEN
));
490 Status
= gBS
->CreateEvent (
493 Ping6OnEchoReplyReceived
,
495 &Private
->RxToken
.Event
498 if (EFI_ERROR (Status
)) {
502 Private
->RxToken
.Status
= EFI_NOT_READY
;
504 return Private
->Ip6
->Receive (Private
->Ip6
, &Private
->RxToken
);
508 Remove the timeout request from the list.
510 @param[in] Event A EFI_EVENT type event.
511 @param[in] Context The pointer to Context.
516 Ping6OnTimerRoutine (
522 PING6_PRIVATE_DATA
*Private
;
523 PING6_ICMP6_TX_INFO
*TxInfo
;
525 LIST_ENTRY
*NextEntry
;
528 Private
= (PING6_PRIVATE_DATA
*) Context
;
531 // Retransmit icmp6 echo request packets per second in sendnumber times.
533 if (Private
->TxCount
< Private
->SendNum
) {
535 Status
= Ping6SendEchoRequest (Private
);
536 if (Private
->TxCount
!= 0){
537 if (EFI_ERROR (Status
)) {
538 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_SEND_REQUEST
), mHiiHandle
, Private
->TxCount
+ 1);
543 // Check whether any icmp6 echo request in the list timeout.
545 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
546 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
547 Time
= Ping6CalculateTick (TxInfo
->TimeStamp
, ReadTime ());
550 // Remove the timeout echo request from txlist.
552 if (Time
> PING6_DEFAULT_TIMEOUT
) {
554 if (EFI_ERROR (TxInfo
->Token
->Status
)) {
555 Private
->Ip6
->Cancel (Private
->Ip6
, TxInfo
->Token
);
558 // Remove the timeout icmp6 echo request from list.
560 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_TIMEOUT
), mHiiHandle
, TxInfo
->SequenceNum
);
562 RemoveEntryList (&TxInfo
->Link
);
563 Ping6DestroyTxInfo (TxInfo
);
565 if (IsListEmpty (&Private
->TxList
) && (Private
->TxCount
== Private
->SendNum
)) {
567 // All the left icmp6 echo request in the list timeout.
569 Private
->Status
= EFI_TIMEOUT
;
576 Create a valid IP6 instance.
578 @param[in] Private The pointer of PING6_PRIVATE_DATA.
580 @retval EFI_SUCCESS Create a valid IP6 instance successfully.
581 @retval EFI_ABORTED Locate handle with ip6 service binding protocol unsuccessfully.
582 @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link -ocal address.
583 @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.
584 @retval EFI_NOT_FOUND The source address is not found.
587 Ping6CreateIp6Instance (
588 IN PING6_PRIVATE_DATA
*Private
594 EFI_HANDLE
*HandleBuffer
;
595 EFI_SERVICE_BINDING_PROTOCOL
*Ip6Sb
;
596 EFI_IP6_CONFIG_PROTOCOL
*Ip6Cfg
;
597 EFI_IP6_CONFIG_DATA Ip6Config
;
598 EFI_IP6_CONFIG_INTERFACE_INFO
*IfInfo
;
600 EFI_IPv6_ADDRESS
*Addr
;
609 // Locate all the handles with ip6 service binding protocol.
611 Status
= gBS
->LocateHandleBuffer (
613 &gEfiIp6ServiceBindingProtocolGuid
,
618 if (EFI_ERROR (Status
) || (HandleNum
== 0)) {
622 // Source address is required when pinging a link-local address on multi-
625 if (NetIp6IsLinkLocalAddr (&Private
->DstAddress
) &&
626 NetIp6IsUnspecifiedAddr (&Private
->SrcAddress
) &&
628 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_SOURCE
), mHiiHandle
);
629 Status
= EFI_INVALID_PARAMETER
;
633 // For each ip6 protocol, check interface addresses list.
635 for (HandleIndex
= 0; HandleIndex
< HandleNum
; HandleIndex
++) {
641 Status
= gBS
->HandleProtocol (
642 HandleBuffer
[HandleIndex
],
643 &gEfiIp6ServiceBindingProtocolGuid
,
646 if (EFI_ERROR (Status
)) {
650 if (NetIp6IsUnspecifiedAddr (&Private
->SrcAddress
)) {
652 // No need to match interface address.
657 // Ip6config protocol and ip6 service binding protocol are installed
658 // on the same handle.
660 Status
= gBS
->HandleProtocol (
661 HandleBuffer
[HandleIndex
],
662 &gEfiIp6ConfigProtocolGuid
,
666 if (EFI_ERROR (Status
)) {
670 // Get the interface information size.
672 Status
= Ip6Cfg
->GetData (
674 Ip6ConfigDataTypeInterfaceInfo
,
679 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
680 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA
), mHiiHandle
, Status
);
684 IfInfo
= AllocateZeroPool (IfInfoSize
);
686 if (IfInfo
== NULL
) {
687 Status
= EFI_OUT_OF_RESOURCES
;
691 // Get the interface info.
693 Status
= Ip6Cfg
->GetData (
695 Ip6ConfigDataTypeInterfaceInfo
,
700 if (EFI_ERROR (Status
)) {
701 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA
), mHiiHandle
, Status
);
705 // Check whether the source address is one of the interface addresses.
707 for (AddrIndex
= 0; AddrIndex
< IfInfo
->AddressInfoCount
; AddrIndex
++) {
709 Addr
= &(IfInfo
->AddressInfo
[AddrIndex
].Address
);
710 if (EFI_IP6_EQUAL (&Private
->SrcAddress
, Addr
)) {
712 // Match a certain interface address.
718 if (AddrIndex
< IfInfo
->AddressInfoCount
) {
720 // Found a nic handle with right interface address.
730 // No exact interface address matched.
733 if (HandleIndex
== HandleNum
) {
734 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND
), mHiiHandle
, mIp6SrcString
);
735 Status
= EFI_NOT_FOUND
;
739 Private
->NicHandle
= HandleBuffer
[HandleIndex
];
741 ASSERT (Ip6Sb
!= NULL
);
742 Status
= Ip6Sb
->CreateChild (Ip6Sb
, &Private
->Ip6ChildHandle
);
744 if (EFI_ERROR (Status
)) {
748 Status
= gBS
->OpenProtocol (
749 Private
->Ip6ChildHandle
,
750 &gEfiIp6ProtocolGuid
,
751 (VOID
**) &Private
->Ip6
,
752 Private
->ImageHandle
,
753 Private
->Ip6ChildHandle
,
754 EFI_OPEN_PROTOCOL_GET_PROTOCOL
756 if (EFI_ERROR (Status
)) {
760 ZeroMem (&Ip6Config
, sizeof (EFI_IP6_CONFIG_DATA
));
763 // Configure the ip6 instance for icmp6 packet exchange.
765 Ip6Config
.DefaultProtocol
= 58;
766 Ip6Config
.AcceptAnyProtocol
= FALSE
;
767 Ip6Config
.AcceptIcmpErrors
= TRUE
;
768 Ip6Config
.AcceptPromiscuous
= FALSE
;
769 Ip6Config
.TrafficClass
= 0;
770 Ip6Config
.HopLimit
= 128;
771 Ip6Config
.FlowLabel
= 0;
772 Ip6Config
.ReceiveTimeout
= 0;
773 Ip6Config
.TransmitTimeout
= 0;
775 IP6_COPY_ADDRESS (&Ip6Config
.StationAddress
, &Private
->SrcAddress
);
777 IP6_COPY_ADDRESS (&Ip6Config
.DestinationAddress
, &Private
->DstAddress
);
779 Status
= Private
->Ip6
->Configure (Private
->Ip6
, &Ip6Config
);
781 if (EFI_ERROR (Status
)) {
782 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_IP6_CONFIG
), mHiiHandle
, Status
);
789 if (HandleBuffer
!= NULL
) {
790 FreePool (HandleBuffer
);
793 if (IfInfo
!= NULL
) {
797 if ((Ip6Sb
!= NULL
) && (Private
->Ip6ChildHandle
!= NULL
)) {
798 Ip6Sb
->DestroyChild (Ip6Sb
, Private
->Ip6ChildHandle
);
805 Destory the IP6 instance.
807 @param[in] Private The pointer of PING6_PRIVATE_DATA.
811 Ping6DestoryIp6Instance (
812 IN PING6_PRIVATE_DATA
*Private
816 EFI_SERVICE_BINDING_PROTOCOL
*Ip6Sb
;
819 Private
->Ip6ChildHandle
,
820 &gEfiIp6ProtocolGuid
,
821 Private
->ImageHandle
,
822 Private
->Ip6ChildHandle
825 Status
= gBS
->HandleProtocol (
827 &gEfiIp6ServiceBindingProtocolGuid
,
831 if (!EFI_ERROR(Status
)) {
832 Ip6Sb
->DestroyChild (Ip6Sb
, Private
->Ip6ChildHandle
);
839 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
840 @param[in] SendNumber The send request count.
841 @param[in] BufferSize The send buffer size.
842 @param[in] SrcAddress The source IPv6 address.
843 @param[in] DstAddress The destination IPv6 address.
845 @retval EFI_SUCCESS The ping6 processed successfullly.
846 @retval others The ping6 processed unsuccessfully.
851 IN EFI_HANDLE ImageHandle
,
852 IN UINT32 SendNumber
,
853 IN UINT32 BufferSize
,
854 IN EFI_IPv6_ADDRESS
*SrcAddress
,
855 IN EFI_IPv6_ADDRESS
*DstAddress
860 PING6_PRIVATE_DATA
*Private
;
861 PING6_ICMP6_TX_INFO
*TxInfo
;
863 LIST_ENTRY
*NextEntry
;
865 Private
= AllocateZeroPool (sizeof (PING6_PRIVATE_DATA
));
867 ASSERT (Private
!= NULL
);
869 Private
->ImageHandle
= ImageHandle
;
870 Private
->SendNum
= SendNumber
;
871 Private
->BufferSize
= BufferSize
;
872 Private
->RttMin
= ~((UINT64
)(0x0));
873 Private
->Status
= EFI_NOT_READY
;
875 InitializeListHead (&Private
->TxList
);
877 IP6_COPY_ADDRESS (&Private
->SrcAddress
, SrcAddress
);
878 IP6_COPY_ADDRESS (&Private
->DstAddress
, DstAddress
);
881 // Open and configure a ip6 instance for ping6.
883 Status
= Ping6CreateIp6Instance (Private
);
885 if (EFI_ERROR (Status
)) {
889 // Print the command line itself.
891 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_START
), mHiiHandle
, mIp6DstString
, Private
->BufferSize
);
893 // Create a ipv6 token to receive the first icmp6 echo reply packet.
895 Status
= Ping6ReceiveEchoReply (Private
);
897 if (EFI_ERROR (Status
)) {
901 // Create and start timer to send icmp6 echo request packet per second.
903 Status
= gBS
->CreateEvent (
904 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
911 if (EFI_ERROR (Status
)) {
915 // Create a ipv6 token to send the first icmp6 echo request packet.
917 Status
= Ping6SendEchoRequest (Private
);
919 // EFI_NOT_READY for IPsec is enable and IKE is not established.
921 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_READY
)) {
922 if(Status
== EFI_NOT_FOUND
) {
923 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN
), mHiiHandle
, mIp6DstString
);
929 Status
= gBS
->SetTimer (
935 if (EFI_ERROR (Status
)) {
939 // Control the ping6 process by two factors:
941 // 2. Private->Status
942 // 2.1. success means all icmp6 echo request packets get reply packets.
943 // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.
944 // 2.3. noready means ping6 process is on-the-go.
946 while (Private
->Status
== EFI_NOT_READY
) {
947 Private
->Ip6
->Poll (Private
->Ip6
);
950 // Terminate the ping6 process by 'esc' or 'ctl-c'.
952 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
954 if (!EFI_ERROR(Status
)) {
955 if ((Key
.UnicodeChar
== 0x1b) || (Key
.UnicodeChar
== 0x03) ||
956 ((Key
.UnicodeChar
== 0) && (Key
.ScanCode
== SCAN_ESC
))) {
964 // Display the statistics in all.
966 gBS
->SetTimer (Private
->Timer
, TimerCancel
, 0);
968 if (Private
->TxCount
!= 0) {
973 STRING_TOKEN (STR_PING6_STAT
),
977 (100 * (Private
->TxCount
- Private
->RxCount
)) / Private
->TxCount
,
982 if (Private
->RxCount
!= 0) {
987 STRING_TOKEN (STR_PING6_RTT
),
991 DivU64x64Remainder (Private
->RttSum
, Private
->RxCount
, NULL
)
997 if (Private
!= NULL
) {
998 Private
->Status
= EFI_ABORTED
;
1000 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->TxList
) {
1001 TxInfo
= BASE_CR (Entry
, PING6_ICMP6_TX_INFO
, Link
);
1003 Status
= Private
->Ip6
->Cancel (Private
->Ip6
, TxInfo
->Token
);
1005 RemoveEntryList (&TxInfo
->Link
);
1006 Ping6DestroyTxInfo (TxInfo
);
1009 if (Private
->Timer
!= NULL
) {
1010 gBS
->CloseEvent (Private
->Timer
);
1013 if (Private
->Ip6
!= NULL
) {
1014 Status
= Private
->Ip6
->Cancel (Private
->Ip6
, &Private
->RxToken
);
1017 if (Private
->RxToken
.Event
!= NULL
) {
1018 gBS
->CloseEvent (Private
->RxToken
.Event
);
1021 if (Private
->Ip6ChildHandle
!= NULL
) {
1022 Ping6DestoryIp6Instance (Private
);
1032 This is the declaration of an EFI image entry point. This entry point is
1033 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including
1034 both device drivers and bus drivers.
1036 The entry point for the Ping6 application that parses the command line input and calls the Ping6 process.
1038 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
1039 @param[in] SystemTable A pointer to the EFI System Table.
1041 @retval EFI_SUCCESS The operation completed successfully.
1042 @retval EFI_INVALID_PARAMETETR Input parameters combination is invalid.
1043 @retval Others Some errors occur.
1049 IN EFI_HANDLE ImageHandle
,
1050 IN EFI_SYSTEM_TABLE
*SystemTable
1054 EFI_IPv6_ADDRESS DstAddress
;
1055 EFI_IPv6_ADDRESS SrcAddress
;
1058 LIST_ENTRY
*ParamPackage
;
1059 CONST CHAR16
*ValueStr
;
1060 CONST CHAR16
*ValueStrPtr
;
1061 UINTN NonOptionCount
;
1064 // Register our string package with HII and return the handle to it.
1066 mHiiHandle
= HiiAddPackages (&gEfiCallerIdGuid
, ImageHandle
, Ping6Strings
, NULL
);
1067 ASSERT (mHiiHandle
!= NULL
);
1069 Status
= ShellCommandLineParseEx (Ping6ParamList
, &ParamPackage
, NULL
, TRUE
, FALSE
);
1070 if (EFI_ERROR(Status
)) {
1071 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_INPUT
), mHiiHandle
);
1075 if (ShellCommandLineGetFlag (ParamPackage
, L
"-?")) {
1076 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_HELP
), mHiiHandle
);
1084 // Parse the paramter of count number.
1086 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-n");
1087 ValueStrPtr
= ValueStr
;
1088 if (ValueStr
!= NULL
) {
1089 SendNumber
= ShellStrToUintn (ValueStrPtr
);
1092 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1094 if ((SendNumber
== 0) || (SendNumber
> PING6_MAX_SEND_NUMBER
)) {
1095 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER
), mHiiHandle
, ValueStr
);
1096 Status
= EFI_INVALID_PARAMETER
;
1101 // Parse the paramter of buffer size.
1103 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-l");
1104 ValueStrPtr
= ValueStr
;
1105 if (ValueStr
!= NULL
) {
1106 BufferSize
= ShellStrToUintn (ValueStrPtr
);
1109 // ShellStrToUintn will return 0 when input is 0 or an invalid input string.
1111 if ((BufferSize
< 16) || (BufferSize
> PING6_MAX_BUFFER_SIZE
)) {
1112 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE
), mHiiHandle
, ValueStr
);
1113 Status
= EFI_INVALID_PARAMETER
;
1118 ZeroMem (&SrcAddress
, sizeof (EFI_IPv6_ADDRESS
));
1119 ZeroMem (&DstAddress
, sizeof (EFI_IPv6_ADDRESS
));
1122 // Parse the paramter of source ip address.
1124 ValueStr
= ShellCommandLineGetValue (ParamPackage
, L
"-s");
1125 ValueStrPtr
= ValueStr
;
1126 if (ValueStr
!= NULL
) {
1127 mIp6SrcString
= ValueStr
;
1128 Status
= NetLibStrToIp6 (ValueStrPtr
, &SrcAddress
);
1129 if (EFI_ERROR (Status
)) {
1130 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_IP
), mHiiHandle
, ValueStr
);
1131 Status
= EFI_INVALID_PARAMETER
;
1136 // Parse the paramter of destination ip address.
1138 NonOptionCount
= ShellCommandLineGetCount(ParamPackage
);
1139 ValueStr
= ShellCommandLineGetRawValue (ParamPackage
, (UINT32
)(NonOptionCount
-1));
1140 if (NonOptionCount
!= 2) {
1141 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_INPUT
), mHiiHandle
);
1142 Status
= EFI_INVALID_PARAMETER
;
1145 ValueStrPtr
= ValueStr
;
1146 if (ValueStr
!= NULL
) {
1147 mIp6DstString
= ValueStr
;
1148 Status
= NetLibStrToIp6 (ValueStrPtr
, &DstAddress
);
1149 if (EFI_ERROR (Status
)) {
1150 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_PING6_INVALID_IP
), mHiiHandle
, ValueStr
);
1151 Status
= EFI_INVALID_PARAMETER
;
1156 // Get frequency to calculate the time from ticks.
1158 Status
= Ping6GetFrequency ();
1160 if (EFI_ERROR(Status
)) {
1164 // Enter into ping6 process.
1175 ShellCommandLineFreeVarList (ParamPackage
);
1176 HiiRemovePackages (mHiiHandle
);