+++ /dev/null
-/** @file\r
- The implementation for Ping6 application.\r
-\r
- Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
-\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php.\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include <Library/ShellLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/UefiHiiServicesLib.h>\r
-#include <Library/HiiLib.h>\r
-#include <Library/NetLib.h>\r
-\r
-#include <Protocol/Cpu.h>\r
-#include <Protocol/ServiceBinding.h>\r
-#include <Protocol/Ip6.h>\r
-#include <Protocol/Ip6Config.h>\r
-\r
-#include "Ping6.h"\r
-\r
-//\r
-// String token ID of Ping6 command help message text.\r
-//\r
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStringPing6HelpToken = STRING_TOKEN (STR_PING6_HELP);\r
-\r
-SHELL_PARAM_ITEM Ping6ParamList[] = {\r
- {\r
- L"-l",\r
- TypeValue\r
- },\r
- {\r
- L"-n",\r
- TypeValue\r
- },\r
- {\r
- L"-s",\r
- TypeValue\r
- },\r
- {\r
- NULL,\r
- TypeMax\r
- },\r
-};\r
-\r
-//\r
-// Global Variables in Ping6 application.\r
-//\r
-EFI_HII_HANDLE mHiiHandle;\r
-CONST CHAR16 *mIp6DstString;\r
-CONST CHAR16 *mIp6SrcString;\r
-UINT64 mFrequency = 0;\r
-/**\r
- Get and calculate the frequency in tick/ms.\r
- The result is saved in the globle variable mFrequency\r
-\r
- @retval EFI_SUCCESS Calculated the frequency successfully.\r
- @retval Others Failed to calculate the frequency.\r
-\r
-**/\r
-EFI_STATUS\r
-Ping6GetFrequency (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_CPU_ARCH_PROTOCOL *Cpu;\r
- UINT64 CurrentTick;\r
- UINT64 TimerPeriod;\r
-\r
- Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu);\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod);\r
-\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // For NT32 Simulator only. 358049 is a similar value to keep timer granularity.\r
- // Set the timer period by ourselves.\r
- //\r
- TimerPeriod = (UINT64) NTTIMERPERIOD;\r
- }\r
- //\r
- // The timer period is in femtosecond (1 femtosecond is 1e-15 second).\r
- // So 1e+12 is divided by timer period to produce the freq in tick/ms.\r
- //\r
- mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Get and calculate the duration in ms.\r
-\r
- @param[in] Begin The start point of time.\r
- @param[in] End The end point of time.\r
-\r
- @return The duration in ms.\r
-\r
-**/\r
-UINT64\r
-Ping6CalculateTick (\r
- IN UINT64 Begin,\r
- IN UINT64 End\r
- )\r
-{\r
- ASSERT (End > Begin);\r
- return DivU64x64Remainder (End - Begin, mFrequency, NULL);\r
-}\r
-\r
-/**\r
- Destroy IPING6_ICMP6_TX_INFO, and recollect the memory.\r
-\r
- @param[in] TxInfo The pointer to PING6_ICMP6_TX_INFO.\r
-\r
-**/\r
-VOID\r
-Ping6DestroyTxInfo (\r
- IN PING6_ICMP6_TX_INFO *TxInfo\r
- )\r
-{\r
- EFI_IP6_TRANSMIT_DATA *TxData;\r
- EFI_IP6_FRAGMENT_DATA *FragData;\r
- UINTN Index;\r
-\r
- ASSERT (TxInfo != NULL);\r
-\r
- if (TxInfo->Token != NULL) {\r
-\r
- if (TxInfo->Token->Event != NULL) {\r
- gBS->CloseEvent (TxInfo->Token->Event);\r
- }\r
-\r
- TxData = TxInfo->Token->Packet.TxData;\r
- if (TxData != NULL) {\r
-\r
- if (TxData->OverrideData != NULL) {\r
- FreePool (TxData->OverrideData);\r
- }\r
-\r
- if (TxData->ExtHdrs != NULL) {\r
- FreePool (TxData->ExtHdrs);\r
- }\r
-\r
- for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
- FragData = TxData->FragmentTable[Index].FragmentBuffer;\r
- if (FragData != NULL) {\r
- FreePool (FragData);\r
- }\r
- }\r
- }\r
-\r
- FreePool (TxInfo->Token);\r
- }\r
-\r
- FreePool (TxInfo);\r
-}\r
-\r
-/**\r
- Match the request, and reply with SequenceNum/TimeStamp.\r
-\r
- @param[in] Private The pointer to PING6_PRIVATE_DATA.\r
- @param[in] Packet The pointer to ICMP6_ECHO_REQUEST_REPLY.\r
-\r
- @retval EFI_SUCCESS The match is successful.\r
- @retval EFI_NOT_FOUND The reply can't be matched with any request.\r
-\r
-**/\r
-EFI_STATUS\r
-Ping6MatchEchoReply (\r
- IN PING6_PRIVATE_DATA *Private,\r
- IN ICMP6_ECHO_REQUEST_REPLY *Packet\r
- )\r
-{\r
- PING6_ICMP6_TX_INFO *TxInfo;\r
- LIST_ENTRY *Entry;\r
- LIST_ENTRY *NextEntry;\r
-\r
- NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
- TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
-\r
- if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) {\r
- Private->RxCount++;\r
- RemoveEntryList (&TxInfo->Link);\r
- Ping6DestroyTxInfo (TxInfo);\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- The original intention is to send a request.\r
- Currently, the application retransmits an icmp6 echo request packet\r
- per second in sendnumber times that is specified by the user.\r
- Because nothing can be done here, all things move to the timer rountine.\r
-\r
- @param[in] Event A EFI_EVENT type event.\r
- @param[in] Context The pointer to Context.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-Ping6OnEchoRequestSent (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
-}\r
-\r
-/**\r
- receive reply, match and print reply infomation.\r
-\r
- @param[in] Event A EFI_EVENT type event.\r
- @param[in] Context The pointer to context.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-Ping6OnEchoReplyReceived (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_STATUS Status;\r
- PING6_PRIVATE_DATA *Private;\r
- EFI_IP6_COMPLETION_TOKEN *RxToken;\r
- EFI_IP6_RECEIVE_DATA *RxData;\r
- ICMP6_ECHO_REQUEST_REPLY *Reply;\r
- UINT32 PayLoad;\r
- UINT64 Rtt;\r
- CHAR8 Near;\r
-\r
- Private = (PING6_PRIVATE_DATA *) Context;\r
-\r
- if (Private->Status == EFI_ABORTED) {\r
- return;\r
- }\r
-\r
- RxToken = &Private->RxToken;\r
- RxData = RxToken->Packet.RxData;\r
- Reply = RxData->FragmentTable[0].FragmentBuffer;\r
- PayLoad = RxData->DataLength;\r
-\r
- if (RxData->Header->NextHeader != IP6_ICMP) {\r
- goto ON_EXIT;\r
- }\r
-\r
- if (!IP6_IS_MULTICAST (&Private->DstAddress) && \r
- !EFI_IP6_EQUAL (&RxData->Header->SourceAddress, &Private->DstAddress)) {\r
- goto ON_EXIT;\r
- }\r
-\r
- if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) {\r
- goto ON_EXIT;\r
- }\r
-\r
- if (PayLoad != Private->BufferSize) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Check whether the reply matches the sent request before.\r
- //\r
- Status = Ping6MatchEchoReply (Private, Reply);\r
- if (EFI_ERROR(Status)) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Display statistics on this icmp6 echo reply packet.\r
- //\r
- Rtt = Ping6CalculateTick (Reply->TimeStamp, ReadTime ());\r
- if (Rtt != 0) {\r
- Near = (CHAR8) '=';\r
- } else {\r
- Near = (CHAR8) '<';\r
- }\r
-\r
- Private->RttSum += Rtt;\r
- Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin;\r
- Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax;\r
-\r
- ShellPrintHiiEx (\r
- -1,\r
- -1,\r
- NULL,\r
- STRING_TOKEN (STR_PING6_REPLY_INFO),\r
- mHiiHandle,\r
- PayLoad,\r
- mIp6DstString,\r
- Reply->SequenceNum,\r
- RxData->Header->HopLimit,\r
- Near,\r
- Rtt\r
- );\r
-\r
-ON_EXIT:\r
-\r
- if (Private->RxCount < Private->SendNum) {\r
- //\r
- // Continue to receive icmp6 echo reply packets.\r
- //\r
- RxToken->Status = EFI_ABORTED;\r
-\r
- Status = Private->Ip6->Receive (Private->Ip6, RxToken);\r
-\r
- if (EFI_ERROR (Status)) {\r
- Private->Status = EFI_ABORTED;\r
- }\r
- } else {\r
- //\r
- // All reply have already been received from the dest host.\r
- //\r
- Private->Status = EFI_SUCCESS;\r
- }\r
- //\r
- // Singal to recycle the each rxdata here, not at the end of process.\r
- //\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
-}\r
-\r
-/**\r
- Initial EFI_IP6_COMPLETION_TOKEN.\r
-\r
- @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
- @param[in] TimeStamp The TimeStamp of request.\r
- @param[in] SequenceNum The SequenceNum of request.\r
-\r
- @return The pointer of EFI_IP6_COMPLETION_TOKEN.\r
-\r
-**/\r
-EFI_IP6_COMPLETION_TOKEN *\r
-Ping6GenerateToken (\r
- IN PING6_PRIVATE_DATA *Private,\r
- IN UINT64 TimeStamp,\r
- IN UINT16 SequenceNum\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_IP6_COMPLETION_TOKEN *Token;\r
- EFI_IP6_TRANSMIT_DATA *TxData;\r
- ICMP6_ECHO_REQUEST_REPLY *Request;\r
-\r
- Request = AllocateZeroPool (Private->BufferSize);\r
-\r
- if (Request == NULL) {\r
- return NULL;\r
- }\r
- //\r
- // Assembly icmp6 echo request packet.\r
- //\r
- Request->Type = ICMP_V6_ECHO_REQUEST;\r
- Request->Code = 0;\r
- Request->SequenceNum = SequenceNum;\r
- Request->TimeStamp = TimeStamp;\r
- Request->Identifier = 0;\r
- //\r
- // Leave check sum to ip6 layer, since it has no idea of source address\r
- // selection.\r
- //\r
- Request->Checksum = 0;\r
-\r
- TxData = AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA));\r
-\r
- if (TxData == NULL) {\r
- FreePool (Request);\r
- return NULL;\r
- }\r
- //\r
- // Assembly ipv6 token for transmit.\r
- //\r
- TxData->OverrideData = 0;\r
- TxData->ExtHdrsLength = 0;\r
- TxData->ExtHdrs = NULL;\r
- TxData->DataLength = Private->BufferSize;\r
- TxData->FragmentCount = 1;\r
- TxData->FragmentTable[0].FragmentBuffer = (VOID *) Request;\r
- TxData->FragmentTable[0].FragmentLength = Private->BufferSize;\r
-\r
- Token = AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN));\r
-\r
- if (Token == NULL) {\r
- FreePool (Request);\r
- FreePool (TxData);\r
- return NULL;\r
- }\r
-\r
- Token->Status = EFI_ABORTED;\r
- Token->Packet.TxData = TxData;\r
-\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- Ping6OnEchoRequestSent,\r
- Private,\r
- &Token->Event\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- FreePool (Request);\r
- FreePool (TxData);\r
- FreePool (Token);\r
- return NULL;\r
- }\r
-\r
- return Token;\r
-}\r
-\r
-/**\r
- Transmit the EFI_IP6_COMPLETION_TOKEN.\r
-\r
- @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
-\r
- @retval EFI_SUCCESS Transmitted successfully.\r
- @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
- @retval others Transmitted unsuccessfully.\r
-\r
-**/\r
-EFI_STATUS\r
-Ping6SendEchoRequest (\r
- IN PING6_PRIVATE_DATA *Private\r
- )\r
-{\r
- EFI_STATUS Status;\r
- PING6_ICMP6_TX_INFO *TxInfo;\r
-\r
- TxInfo = AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO));\r
-\r
- if (TxInfo == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- TxInfo->TimeStamp = ReadTime ();\r
- TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);\r
-\r
- TxInfo->Token = Ping6GenerateToken (\r
- Private,\r
- TxInfo->TimeStamp,\r
- TxInfo->SequenceNum\r
- );\r
-\r
- if (TxInfo->Token == NULL) {\r
- Ping6DestroyTxInfo (TxInfo);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Status = Private->Ip6->Transmit (Private->Ip6, TxInfo->Token);\r
-\r
- if (EFI_ERROR (Status)) {\r
- Ping6DestroyTxInfo (TxInfo);\r
- return Status;\r
- }\r
-\r
- InsertTailList (&Private->TxList, &TxInfo->Link);\r
- Private->TxCount++;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Place a completion token into the receive packet queue to receive the echo reply.\r
-\r
- @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
-\r
- @retval EFI_SUCCESS Put the token into the receive packet queue successfully.\r
- @retval others Put the token into the receive packet queue unsuccessfully.\r
-\r
-**/\r
-EFI_STATUS\r
-Ping6ReceiveEchoReply (\r
- IN PING6_PRIVATE_DATA *Private\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- ZeroMem (&Private->RxToken, sizeof (EFI_IP6_COMPLETION_TOKEN));\r
-\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- Ping6OnEchoReplyReceived,\r
- Private,\r
- &Private->RxToken.Event\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Private->RxToken.Status = EFI_NOT_READY;\r
-\r
- return Private->Ip6->Receive (Private->Ip6, &Private->RxToken);\r
-}\r
-\r
-/**\r
- Remove the timeout request from the list.\r
-\r
- @param[in] Event A EFI_EVENT type event.\r
- @param[in] Context The pointer to Context.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-Ping6OnTimerRoutine (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_STATUS Status;\r
- PING6_PRIVATE_DATA *Private;\r
- PING6_ICMP6_TX_INFO *TxInfo;\r
- LIST_ENTRY *Entry;\r
- LIST_ENTRY *NextEntry;\r
- UINT64 Time;\r
-\r
- Private = (PING6_PRIVATE_DATA *) Context;\r
-\r
- //\r
- // Retransmit icmp6 echo request packets per second in sendnumber times.\r
- //\r
- if (Private->TxCount < Private->SendNum) {\r
-\r
- Status = Ping6SendEchoRequest (Private);\r
- if (Private->TxCount != 0){\r
- if (EFI_ERROR (Status)) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SEND_REQUEST), mHiiHandle, Private->TxCount + 1);\r
- }\r
- }\r
- }\r
- //\r
- // Check whether any icmp6 echo request in the list timeout.\r
- //\r
- NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
- TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
- Time = Ping6CalculateTick (TxInfo->TimeStamp, ReadTime ());\r
-\r
- //\r
- // Remove the timeout echo request from txlist.\r
- //\r
- if (Time > PING6_DEFAULT_TIMEOUT) {\r
-\r
- if (EFI_ERROR (TxInfo->Token->Status)) {\r
- Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);\r
- }\r
- //\r
- // Remove the timeout icmp6 echo request from list.\r
- //\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_TIMEOUT), mHiiHandle, TxInfo->SequenceNum);\r
-\r
- RemoveEntryList (&TxInfo->Link);\r
- Ping6DestroyTxInfo (TxInfo);\r
-\r
- if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
- //\r
- // All the left icmp6 echo request in the list timeout.\r
- //\r
- Private->Status = EFI_TIMEOUT;\r
- }\r
- }\r
- }\r
-}\r
-\r
-/**\r
- Create a valid IP6 instance.\r
-\r
- @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
-\r
- @retval EFI_SUCCESS Create a valid IP6 instance successfully.\r
- @retval EFI_ABORTED Locate handle with ip6 service binding protocol unsuccessfully.\r
- @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link -ocal address.\r
- @retval EFI_OUT_OF_RESOURCES No memory is available on the platform.\r
- @retval EFI_NOT_FOUND The source address is not found.\r
-**/\r
-EFI_STATUS\r
-Ping6CreateIp6Instance (\r
- IN PING6_PRIVATE_DATA *Private\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN HandleIndex;\r
- UINTN HandleNum;\r
- EFI_HANDLE *HandleBuffer;\r
- EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb;\r
- EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;\r
- EFI_IP6_CONFIG_DATA Ip6Config;\r
- EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo;\r
- UINTN IfInfoSize;\r
- EFI_IPv6_ADDRESS *Addr;\r
- UINTN AddrIndex;\r
-\r
- HandleBuffer = NULL;\r
- Ip6Sb = NULL;\r
- IfInfo = NULL;\r
- IfInfoSize = 0;\r
-\r
- //\r
- // Locate all the handles with ip6 service binding protocol.\r
- //\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiIp6ServiceBindingProtocolGuid,\r
- NULL,\r
- &HandleNum,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR (Status) || (HandleNum == 0)) {\r
- return EFI_ABORTED;\r
- }\r
- //\r
- // Source address is required when pinging a link-local address on multi-\r
- // interfaces host.\r
- //\r
- if (NetIp6IsLinkLocalAddr (&Private->DstAddress) &&\r
- NetIp6IsUnspecifiedAddr (&Private->SrcAddress) &&\r
- (HandleNum > 1)) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SOURCE), mHiiHandle);\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_ERROR;\r
- }\r
- //\r
- // For each ip6 protocol, check interface addresses list.\r
- //\r
- for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {\r
-\r
- Ip6Sb = NULL;\r
- IfInfo = NULL;\r
- IfInfoSize = 0;\r
-\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[HandleIndex],\r
- &gEfiIp6ServiceBindingProtocolGuid,\r
- (VOID **) &Ip6Sb\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ON_ERROR;\r
- }\r
-\r
- if (NetIp6IsUnspecifiedAddr (&Private->SrcAddress)) {\r
- //\r
- // No need to match interface address.\r
- //\r
- break;\r
- } else {\r
- //\r
- // Ip6config protocol and ip6 service binding protocol are installed\r
- // on the same handle.\r
- //\r
- Status = gBS->HandleProtocol (\r
- HandleBuffer[HandleIndex],\r
- &gEfiIp6ConfigProtocolGuid,\r
- (VOID **) &Ip6Cfg\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_ERROR;\r
- }\r
- //\r
- // Get the interface information size.\r
- //\r
- Status = Ip6Cfg->GetData (\r
- Ip6Cfg,\r
- Ip6ConfigDataTypeInterfaceInfo,\r
- &IfInfoSize,\r
- NULL\r
- );\r
-\r
- if (Status != EFI_BUFFER_TOO_SMALL) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), mHiiHandle, Status);\r
- goto ON_ERROR;\r
- }\r
-\r
- IfInfo = AllocateZeroPool (IfInfoSize);\r
-\r
- if (IfInfo == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_ERROR;\r
- }\r
- //\r
- // Get the interface info.\r
- //\r
- Status = Ip6Cfg->GetData (\r
- Ip6Cfg,\r
- Ip6ConfigDataTypeInterfaceInfo,\r
- &IfInfoSize,\r
- IfInfo\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), mHiiHandle, Status);\r
- goto ON_ERROR;\r
- }\r
- //\r
- // Check whether the source address is one of the interface addresses.\r
- //\r
- for (AddrIndex = 0; AddrIndex < IfInfo->AddressInfoCount; AddrIndex++) {\r
-\r
- Addr = &(IfInfo->AddressInfo[AddrIndex].Address);\r
- if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
- //\r
- // Match a certain interface address.\r
- //\r
- break;\r
- }\r
- }\r
-\r
- if (AddrIndex < IfInfo->AddressInfoCount) {\r
- //\r
- // Found a nic handle with right interface address.\r
- //\r
- break;\r
- }\r
- }\r
-\r
- FreePool (IfInfo);\r
- IfInfo = NULL;\r
- }\r
- //\r
- // No exact interface address matched.\r
- //\r
-\r
- if (HandleIndex == HandleNum) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND), mHiiHandle, mIp6SrcString);\r
- Status = EFI_NOT_FOUND;\r
- goto ON_ERROR;\r
- }\r
-\r
- Private->NicHandle = HandleBuffer[HandleIndex];\r
-\r
- ASSERT (Ip6Sb != NULL);\r
- Status = Ip6Sb->CreateChild (Ip6Sb, &Private->Ip6ChildHandle);\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_ERROR;\r
- }\r
-\r
- Status = gBS->OpenProtocol (\r
- Private->Ip6ChildHandle,\r
- &gEfiIp6ProtocolGuid,\r
- (VOID **) &Private->Ip6,\r
- Private->ImageHandle,\r
- Private->Ip6ChildHandle,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ON_ERROR;\r
- }\r
-\r
- ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA));\r
-\r
- //\r
- // Configure the ip6 instance for icmp6 packet exchange.\r
- //\r
- Ip6Config.DefaultProtocol = 58;\r
- Ip6Config.AcceptAnyProtocol = FALSE;\r
- Ip6Config.AcceptIcmpErrors = TRUE;\r
- Ip6Config.AcceptPromiscuous = FALSE;\r
- Ip6Config.TrafficClass = 0;\r
- Ip6Config.HopLimit = 128;\r
- Ip6Config.FlowLabel = 0;\r
- Ip6Config.ReceiveTimeout = 0;\r
- Ip6Config.TransmitTimeout = 0;\r
-\r
- IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress);\r
-\r
- IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress);\r
-\r
- Status = Private->Ip6->Configure (Private->Ip6, &Ip6Config);\r
-\r
- if (EFI_ERROR (Status)) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_CONFIG), mHiiHandle, Status);\r
- goto ON_ERROR;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-\r
-ON_ERROR:\r
- if (HandleBuffer != NULL) {\r
- FreePool (HandleBuffer);\r
- }\r
-\r
- if (IfInfo != NULL) {\r
- FreePool (IfInfo);\r
- }\r
-\r
- if ((Ip6Sb != NULL) && (Private->Ip6ChildHandle != NULL)) {\r
- Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Destroy the IP6 instance.\r
-\r
- @param[in] Private The pointer of PING6_PRIVATE_DATA.\r
-\r
-**/\r
-VOID\r
-Ping6DestroyIp6Instance (\r
- IN PING6_PRIVATE_DATA *Private\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb;\r
-\r
- gBS->CloseProtocol (\r
- Private->Ip6ChildHandle,\r
- &gEfiIp6ProtocolGuid,\r
- Private->ImageHandle,\r
- Private->Ip6ChildHandle\r
- );\r
-\r
- Status = gBS->HandleProtocol (\r
- Private->NicHandle,\r
- &gEfiIp6ServiceBindingProtocolGuid,\r
- (VOID **) &Ip6Sb\r
- );\r
-\r
- if (!EFI_ERROR(Status)) {\r
- Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle);\r
- }\r
-}\r
-\r
-/**\r
- The Ping6 Process.\r
-\r
- @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
- @param[in] SendNumber The send request count.\r
- @param[in] BufferSize The send buffer size.\r
- @param[in] SrcAddress The source IPv6 address.\r
- @param[in] DstAddress The destination IPv6 address.\r
-\r
- @retval EFI_SUCCESS The ping6 processed successfullly.\r
- @retval others The ping6 processed unsuccessfully.\r
-\r
-**/\r
-EFI_STATUS\r
-Ping6 (\r
- IN EFI_HANDLE ImageHandle,\r
- IN UINT32 SendNumber,\r
- IN UINT32 BufferSize,\r
- IN EFI_IPv6_ADDRESS *SrcAddress,\r
- IN EFI_IPv6_ADDRESS *DstAddress\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_INPUT_KEY Key;\r
- PING6_PRIVATE_DATA *Private;\r
- PING6_ICMP6_TX_INFO *TxInfo;\r
- LIST_ENTRY *Entry;\r
- LIST_ENTRY *NextEntry;\r
-\r
- Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA));\r
-\r
- ASSERT (Private != NULL);\r
-\r
- Private->ImageHandle = ImageHandle;\r
- Private->SendNum = SendNumber;\r
- Private->BufferSize = BufferSize;\r
- Private->RttMin = ~((UINT64 )(0x0));\r
- Private->Status = EFI_NOT_READY;\r
-\r
- InitializeListHead (&Private->TxList);\r
-\r
- IP6_COPY_ADDRESS (&Private->SrcAddress, SrcAddress);\r
- IP6_COPY_ADDRESS (&Private->DstAddress, DstAddress);\r
-\r
- //\r
- // Open and configure a ip6 instance for ping6.\r
- //\r
- Status = Ping6CreateIp6Instance (Private);\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Print the command line itself.\r
- //\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_START), mHiiHandle, mIp6DstString, Private->BufferSize);\r
- //\r
- // Create a ipv6 token to receive the first icmp6 echo reply packet.\r
- //\r
- Status = Ping6ReceiveEchoReply (Private);\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Create and start timer to send icmp6 echo request packet per second.\r
- //\r
- Status = gBS->CreateEvent (\r
- EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- Ping6OnTimerRoutine,\r
- Private,\r
- &Private->Timer\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Create a ipv6 token to send the first icmp6 echo request packet.\r
- //\r
- Status = Ping6SendEchoRequest (Private);\r
- //\r
- // EFI_NOT_READY for IPsec is enable and IKE is not established.\r
- //\r
- if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
- if(Status == EFI_NOT_FOUND) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN), mHiiHandle, mIp6DstString);\r
- }\r
-\r
- goto ON_EXIT;\r
- }\r
-\r
- Status = gBS->SetTimer (\r
- Private->Timer,\r
- TimerPeriodic,\r
- PING6_ONE_SECOND\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Control the ping6 process by two factors:\r
- // 1. Hot key\r
- // 2. Private->Status\r
- // 2.1. success means all icmp6 echo request packets get reply packets.\r
- // 2.2. timeout means the last icmp6 echo reply request timeout to get reply.\r
- // 2.3. noready means ping6 process is on-the-go.\r
- //\r
- while (Private->Status == EFI_NOT_READY) {\r
- Private->Ip6->Poll (Private->Ip6);\r
-\r
- //\r
- // Terminate the ping6 process by 'esc' or 'ctl-c'.\r
- //\r
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-\r
- if (!EFI_ERROR(Status)) {\r
- if ((Key.UnicodeChar == 0x1b) || (Key.UnicodeChar == 0x03) ||\r
- ((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_ESC))) {\r
- goto ON_STAT;\r
- }\r
- }\r
- }\r
-\r
-ON_STAT:\r
- //\r
- // Display the statistics in all.\r
- //\r
- gBS->SetTimer (Private->Timer, TimerCancel, 0);\r
-\r
- if (Private->TxCount != 0) {\r
- ShellPrintHiiEx (\r
- -1,\r
- -1,\r
- NULL,\r
- STRING_TOKEN (STR_PING6_STAT),\r
- mHiiHandle,\r
- Private->TxCount,\r
- Private->RxCount,\r
- (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount,\r
- Private->RttSum\r
- );\r
- }\r
-\r
- if (Private->RxCount != 0) {\r
- ShellPrintHiiEx (\r
- -1,\r
- -1,\r
- NULL,\r
- STRING_TOKEN (STR_PING6_RTT),\r
- mHiiHandle,\r
- Private->RttMin,\r
- Private->RttMax,\r
- DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL)\r
- );\r
- }\r
-\r
-ON_EXIT:\r
-\r
- if (Private != NULL) {\r
- Private->Status = EFI_ABORTED;\r
-\r
- NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
- TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link);\r
-\r
- Status = Private->Ip6->Cancel (Private->Ip6, TxInfo->Token);\r
-\r
- RemoveEntryList (&TxInfo->Link);\r
- Ping6DestroyTxInfo (TxInfo);\r
- }\r
-\r
- if (Private->Timer != NULL) {\r
- gBS->CloseEvent (Private->Timer);\r
- }\r
-\r
- if (Private->Ip6 != NULL) {\r
- Status = Private->Ip6->Cancel (Private->Ip6, &Private->RxToken);\r
- }\r
-\r
- if (Private->RxToken.Event != NULL) {\r
- gBS->CloseEvent (Private->RxToken.Event);\r
- }\r
-\r
- if (Private->Ip6ChildHandle != NULL) {\r
- Ping6DestroyIp6Instance (Private);\r
- }\r
-\r
- FreePool (Private);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This is the declaration of an EFI image entry point. This entry point is\r
- the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including\r
- both device drivers and bus drivers.\r
-\r
- The entry point for the Ping6 application that parses the command line input and calls the Ping6 process.\r
-\r
- @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
- @param[in] SystemTable A pointer to the EFI System Table.\r
-\r
- @retval EFI_SUCCESS The operation completed successfully.\r
- @retval EFI_INVALID_PARAMETETR Input parameters combination is invalid.\r
- @retval Others Some errors occur.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InitializePing6 (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_IPv6_ADDRESS DstAddress;\r
- EFI_IPv6_ADDRESS SrcAddress;\r
- UINT64 BufferSize;\r
- UINTN SendNumber;\r
- LIST_ENTRY *ParamPackage;\r
- CONST CHAR16 *ValueStr;\r
- CONST CHAR16 *ValueStrPtr;\r
- UINTN NonOptionCount;\r
- EFI_HII_PACKAGE_LIST_HEADER *PackageList;\r
-\r
- //\r
- // Retrieve HII package list from ImageHandle\r
- //\r
- Status = gBS->OpenProtocol (\r
- ImageHandle,\r
- &gEfiHiiPackageListProtocolGuid,\r
- (VOID **) &PackageList,\r
- ImageHandle,\r
- NULL,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Publish HII package list to HII Database.\r
- //\r
- Status = gHiiDatabase->NewPackageList (\r
- gHiiDatabase,\r
- PackageList,\r
- NULL,\r
- &mHiiHandle\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- \r
- ASSERT (mHiiHandle != NULL);\r
-\r
- Status = ShellCommandLineParseEx (Ping6ParamList, &ParamPackage, NULL, TRUE, FALSE);\r
- if (EFI_ERROR(Status)) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), mHiiHandle);\r
- goto ON_EXIT;\r
- }\r
-\r
- SendNumber = 10;\r
- BufferSize = 16;\r
-\r
- //\r
- // Parse the parameter of count number.\r
- //\r
- ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
- ValueStrPtr = ValueStr;\r
- if (ValueStr != NULL) {\r
- SendNumber = ShellStrToUintn (ValueStrPtr);\r
-\r
- //\r
- // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
- //\r
- if ((SendNumber == 0) || (SendNumber > PING6_MAX_SEND_NUMBER)) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER), mHiiHandle, ValueStr);\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_EXIT;\r
- }\r
- }\r
- //\r
- // Parse the parameter of buffer size.\r
- //\r
- ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
- ValueStrPtr = ValueStr;\r
- if (ValueStr != NULL) {\r
- BufferSize = ShellStrToUintn (ValueStrPtr);\r
-\r
- //\r
- // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
- //\r
- if ((BufferSize < 16) || (BufferSize > PING6_MAX_BUFFER_SIZE)) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE), mHiiHandle, ValueStr);\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_EXIT;\r
- }\r
- }\r
-\r
- ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS));\r
- ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
-\r
- //\r
- // Parse the parameter of source ip address.\r
- //\r
- ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
- ValueStrPtr = ValueStr;\r
- if (ValueStr != NULL) {\r
- mIp6SrcString = ValueStr;\r
- Status = NetLibStrToIp6 (ValueStrPtr, &SrcAddress);\r
- if (EFI_ERROR (Status)) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), mHiiHandle, ValueStr);\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_EXIT;\r
- }\r
- }\r
- //\r
- // Parse the parameter of destination ip address.\r
- //\r
- NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
- ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1));\r
- if (NonOptionCount != 2) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), mHiiHandle);\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_EXIT;\r
- }\r
- ValueStrPtr = ValueStr;\r
- if (ValueStr != NULL) {\r
- mIp6DstString = ValueStr;\r
- Status = NetLibStrToIp6 (ValueStrPtr, &DstAddress);\r
- if (EFI_ERROR (Status)) {\r
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), mHiiHandle, ValueStr);\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_EXIT;\r
- }\r
- }\r
- //\r
- // Get frequency to calculate the time from ticks.\r
- //\r
- Status = Ping6GetFrequency ();\r
-\r
- if (EFI_ERROR(Status)) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Enter into ping6 process.\r
- //\r
- Status = Ping6 (\r
- ImageHandle,\r
- (UINT32)SendNumber,\r
- (UINT32)BufferSize,\r
- &SrcAddress,\r
- &DstAddress\r
- );\r
-\r
-ON_EXIT:\r
- ShellCommandLineFreeVarList (ParamPackage);\r
- HiiRemovePackages (mHiiHandle);\r
- return Status;\r
-}\r