X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ShellPkg%2FLibrary%2FUefiShellNetwork2CommandsLib%2FPing6.c;h=2cdf484c06151635ca9733a0025e82443d38e823;hp=af7d08f3ec516bfd3932d0715fcaafe86850fee0;hb=2d70c90d2e8bf4405c5c16c0c7ea5b2446d1517a;hpb=43ca17532bd7292eee5ad979e26b19ddd0d3e55a diff --git a/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c b/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c index af7d08f3ec..2cdf484c06 100644 --- a/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c +++ b/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c @@ -1,7 +1,7 @@ /** @file The implementation for Ping6 application. - Copyright (c) 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -19,12 +19,7 @@ #define PING6_MAX_SEND_NUMBER 10000 #define PING6_MAX_BUFFER_SIZE 32768 #define PING6_ONE_SECOND 10000000 - -// -// A similar amount of time that passes in femtoseconds -// for each increment of TimerValue. It is for NT32 only. -// -#define NTTIMERPERIOD 358049 +#define STALL_1_MILLI_SECOND 1000 #pragma pack(1) @@ -34,7 +29,7 @@ typedef struct _ICMP6_ECHO_REQUEST_REPLY { UINT16 Checksum; UINT16 Identifier; UINT16 SequenceNum; - UINT64 TimeStamp; + UINT32 TimeStamp; UINT8 Data[1]; } ICMP6_ECHO_REQUEST_REPLY; @@ -43,7 +38,7 @@ typedef struct _ICMP6_ECHO_REQUEST_REPLY { typedef struct _PING6_ICMP6_TX_INFO { LIST_ENTRY Link; UINT16 SequenceNum; - UINT64 TimeStamp; + UINT32 TimeStamp; EFI_IP6_COMPLETION_TOKEN *Token; } PING6_ICMP6_TX_INFO; @@ -54,6 +49,10 @@ typedef struct _PING6_PRIVATE_DATA { EFI_IP6_PROTOCOL *Ip6; EFI_EVENT Timer; + UINT32 TimerPeriod; + UINT32 RttTimerTick; + EFI_EVENT RttTimer; + EFI_STATUS Status; LIST_ENTRY TxList; EFI_IP6_COMPLETION_TOKEN RxToken; @@ -99,96 +98,189 @@ SHELL_PARAM_ITEM Ping6ParamList[] = { // CONST CHAR16 *mIp6DstString; CONST CHAR16 *mIp6SrcString; -UINT64 mFrequency = 0; -UINT64 mIp6CurrentTick = 0; EFI_CPU_ARCH_PROTOCOL *Cpu = NULL; +/** + RTT timer tick routine. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6RttTimerTickRoutine ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINT32 *RttTimerTick; + RttTimerTick = (UINT32*) Context; + (*RttTimerTick)++; +} /** - Reads and returns the current value of the Time. + Get the timer period of the system. + + This function tries to get the system timer period by creating + an 1ms period timer. - @return The current tick value. + @return System timer period in MS, or 0 if operation failed. **/ -UINT64 -Ping6ReadTime () +UINT32 +Ping6GetTimerPeriod( + VOID + ) { - UINT64 TimerPeriod; - EFI_STATUS Status; + EFI_STATUS Status; + UINT32 RttTimerTick; + EFI_EVENT TimerEvent; + UINT32 StallCounter; + EFI_TPL OldTpl; - ASSERT (Cpu != NULL); + RttTimerTick = 0; + StallCounter = 0; - Status = Cpu->GetTimerValue (Cpu, 0, &mIp6CurrentTick, &TimerPeriod); + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + Ping6RttTimerTickRoutine, + &RttTimerTick, + &TimerEvent + ); if (EFI_ERROR (Status)) { - // - // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the - // TimerPeriod by ourselves. - // - mIp6CurrentTick += 1000000; + return 0; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + Status = gBS->SetTimer ( + TimerEvent, + TimerPeriodic, + TICKS_PER_MS + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (TimerEvent); + return 0; } - return mIp6CurrentTick; + while (RttTimerTick < 10) { + gBS->Stall (STALL_1_MILLI_SECOND); + ++StallCounter; + } + + gBS->RestoreTPL (OldTpl); + + gBS->SetTimer (TimerEvent, TimerCancel, 0); + gBS->CloseEvent (TimerEvent); + + return StallCounter / RttTimerTick; } + /** - Get and calculate the frequency in tick/ms. - The result is saved in the globle variable mFrequency + Initialize the timer event for RTT (round trip time). - @retval EFI_SUCCESS Calculated the frequency successfully. - @retval Others Failed to calculate the frequency. + @param[in] Private The pointer to PING6_PRIVATE_DATA. + + @retval EFI_SUCCESS RTT timer is started. + @retval Others Failed to start the RTT timer. **/ EFI_STATUS -Ping6GetFrequency ( - VOID +Ping6InitRttTimer ( + IN PING6_PRIVATE_DATA *Private ) { - EFI_STATUS Status; - UINT64 CurrentTick; - UINT64 TimerPeriod; - - Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu); + EFI_STATUS Status; + Private->TimerPeriod = Ping6GetTimerPeriod (); + if (Private->TimerPeriod == 0) { + return EFI_ABORTED; + } + + Private->RttTimerTick = 0; + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + Ping6RttTimerTickRoutine, + &Private->RttTimerTick, + &Private->RttTimer + ); if (EFI_ERROR (Status)) { return Status; } - Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod); - + Status = gBS->SetTimer ( + Private->RttTimer, + TimerPeriodic, + TICKS_PER_MS + ); if (EFI_ERROR (Status)) { - // - // For NT32 Simulator only. 358049 is a similar value to keep timer granularity. - // Set the timer period by ourselves. - // - TimerPeriod = (UINT64) NTTIMERPERIOD; + gBS->CloseEvent (Private->RttTimer); + return Status; } - // - // The timer period is in femtosecond (1 femtosecond is 1e-15 second). - // So 1e+12 is divided by timer period to produce the freq in tick/ms. - // - mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL); return EFI_SUCCESS; + +} + +/** + Free RTT timer event resource. + + @param[in] Private The pointer to PING6_PRIVATE_DATA. + +**/ +VOID +Ping6FreeRttTimer ( + IN PING6_PRIVATE_DATA *Private + ) +{ + if (Private->RttTimer != NULL) { + gBS->SetTimer (Private->RttTimer, TimerCancel, 0); + gBS->CloseEvent (Private->RttTimer); + } +} + +/** + Read the current time. + + @param[in] Private The pointer to PING6_PRIVATE_DATA. + + @retval the current tick value. +**/ +UINT32 +Ping6ReadTime ( + IN PING6_PRIVATE_DATA *Private + ) +{ + return Private->RttTimerTick; } /** Get and calculate the duration in ms. + @param[in] Private The pointer to PING6_PRIVATE_DATA. @param[in] Begin The start point of time. @param[in] End The end point of time. @return The duration in ms. **/ -UINT64 +UINT32 Ping6CalculateTick ( - IN UINT64 Begin, - IN UINT64 End + IN PING6_PRIVATE_DATA *Private, + IN UINT32 Begin, + IN UINT32 End ) { - ASSERT (End > Begin); - return DivU64x64Remainder (End - Begin, mFrequency, NULL); + if (End < Begin) { + return (0); + } + + return (End - Begin) * Private->TimerPeriod; + } /** @@ -312,8 +404,7 @@ Ping6OnEchoReplyReceived6 ( EFI_IP6_RECEIVE_DATA *RxData; ICMP6_ECHO_REQUEST_REPLY *Reply; UINT32 PayLoad; - UINT64 Rtt; - CHAR8 Near; + UINT32 Rtt; Private = (PING6_PRIVATE_DATA *) Context; @@ -352,12 +443,7 @@ Ping6OnEchoReplyReceived6 ( // // Display statistics on this icmp6 echo reply packet. // - Rtt = Ping6CalculateTick (Reply->TimeStamp, Ping6ReadTime ()); - if (Rtt != 0) { - Near = (CHAR8) '='; - } else { - Near = (CHAR8) '<'; - } + Rtt = Ping6CalculateTick (Private, Reply->TimeStamp, Ping6ReadTime (Private)); Private->RttSum += Rtt; Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin; @@ -373,8 +459,8 @@ Ping6OnEchoReplyReceived6 ( mIp6DstString, Reply->SequenceNum, RxData->Header->HopLimit, - Near, - Rtt + Rtt, + Rtt + Private->TimerPeriod ); ON_EXIT: @@ -388,6 +474,7 @@ ON_EXIT: Status = Private->Ip6->Receive (Private->Ip6, RxToken); if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_RECEIVE), gShellNetwork2HiiHandle, Status); Private->Status = EFI_ABORTED; } } else { @@ -415,7 +502,7 @@ ON_EXIT: EFI_IP6_COMPLETION_TOKEN * Ping6GenerateToken ( IN PING6_PRIVATE_DATA *Private, - IN UINT64 TimeStamp, + IN UINT32 TimeStamp, IN UINT16 SequenceNum ) { @@ -513,7 +600,7 @@ Ping6SendEchoRequest ( return EFI_OUT_OF_RESOURCES; } - TxInfo->TimeStamp = Ping6ReadTime (); + TxInfo->TimeStamp = Ping6ReadTime (Private); TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1); TxInfo->Token = Ping6GenerateToken ( @@ -572,7 +659,11 @@ Ping6OnReceiveEchoReply ( Private->RxToken.Status = EFI_NOT_READY; - return Private->Ip6->Receive (Private->Ip6, &Private->RxToken); + Status = Private->Ip6->Receive (Private->Ip6, &Private->RxToken); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_RECEIVE), gShellNetwork2HiiHandle, Status); + } + return Status; } /** @@ -615,7 +706,7 @@ Ping6OnTimerRoutine6 ( // NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link); - Time = Ping6CalculateTick (TxInfo->TimeStamp, Ping6ReadTime ()); + Time = Ping6CalculateTick (Private, TxInfo->TimeStamp, Ping6ReadTime (Private)); // // Remove the timeout echo request from txlist. @@ -663,6 +754,8 @@ Ping6CreateIpInstance ( UINTN HandleIndex; UINTN HandleNum; EFI_HANDLE *HandleBuffer; + BOOLEAN UnspecifiedSrc; + EFI_STATUS MediaStatus; EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb; EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; EFI_IP6_CONFIG_DATA Ip6Config; @@ -671,10 +764,12 @@ Ping6CreateIpInstance ( EFI_IPv6_ADDRESS *Addr; UINTN AddrIndex; - HandleBuffer = NULL; - Ip6Sb = NULL; - IfInfo = NULL; - IfInfoSize = 0; + HandleBuffer = NULL; + UnspecifiedSrc = FALSE; + MediaStatus = EFI_SUCCESS; + Ip6Sb = NULL; + IfInfo = NULL; + IfInfoSize = 0; // // Locate all the handles with ip6 service binding protocol. @@ -689,17 +784,23 @@ Ping6CreateIpInstance ( if (EFI_ERROR (Status) || (HandleNum == 0)) { return EFI_ABORTED; } + + if (NetIp6IsUnspecifiedAddr (&Private->SrcAddress)) { + // + // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected. + // + UnspecifiedSrc = TRUE; + } + // - // Source address is required when pinging a link-local address on multi- - // interfaces host. + // Source address is required when pinging a link-local address. // - if (NetIp6IsLinkLocalAddr (&Private->DstAddress) && - NetIp6IsUnspecifiedAddr (&Private->SrcAddress) && - (HandleNum > 1)) { + if (NetIp6IsLinkLocalAddr (&Private->DstAddress) && UnspecifiedSrc) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SOURCE), gShellNetwork2HiiHandle); Status = EFI_INVALID_PARAMETER; goto ON_ERROR; } + // // For each ip6 protocol, check interface addresses list. // @@ -709,6 +810,19 @@ Ping6CreateIpInstance ( IfInfo = NULL; IfInfoSize = 0; + if (UnspecifiedSrc) { + // + // Check media. + // + NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus); + if (MediaStatus != EFI_SUCCESS) { + // + // Skip this one. + // + continue; + } + } + Status = gBS->HandleProtocol ( HandleBuffer[HandleIndex], &gEfiIp6ServiceBindingProtocolGuid, @@ -718,80 +832,81 @@ Ping6CreateIpInstance ( goto ON_ERROR; } - if (NetIp6IsUnspecifiedAddr (&Private->SrcAddress)) { - // - // No need to match interface address. - // - break; - } else { - // - // Ip6config protocol and ip6 service binding protocol are installed - // on the same handle. - // - Status = gBS->HandleProtocol ( - HandleBuffer[HandleIndex], - &gEfiIp6ConfigProtocolGuid, - (VOID **) &Ip6Cfg - ); + // + // Ip6config protocol and ip6 service binding protocol are installed + // on the same handle. + // + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + &gEfiIp6ConfigProtocolGuid, + (VOID **) &Ip6Cfg + ); - if (EFI_ERROR (Status)) { - goto ON_ERROR; - } - // - // Get the interface information size. - // - Status = Ip6Cfg->GetData ( - Ip6Cfg, - Ip6ConfigDataTypeInterfaceInfo, - &IfInfoSize, - NULL - ); - - if (Status != EFI_BUFFER_TOO_SMALL) { - ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); - goto ON_ERROR; - } + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + // + // Get the interface information size. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + NULL + ); + + if (Status != EFI_BUFFER_TOO_SMALL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } - IfInfo = AllocateZeroPool (IfInfoSize); + IfInfo = AllocateZeroPool (IfInfoSize); - if (IfInfo == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_ERROR; - } - // - // Get the interface info. - // - Status = Ip6Cfg->GetData ( - Ip6Cfg, - Ip6ConfigDataTypeInterfaceInfo, - &IfInfoSize, - IfInfo - ); + if (IfInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // + // Get the interface info. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + IfInfo + ); - if (EFI_ERROR (Status)) { - ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); - goto ON_ERROR; - } - // - // Check whether the source address is one of the interface addresses. - // - for (AddrIndex = 0; AddrIndex < IfInfo->AddressInfoCount; AddrIndex++) { + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + // + // Check whether the source address is one of the interface addresses. + // + for (AddrIndex = 0; AddrIndex < IfInfo->AddressInfoCount; AddrIndex++) { + Addr = &(IfInfo->AddressInfo[AddrIndex].Address); - Addr = &(IfInfo->AddressInfo[AddrIndex].Address); - if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) { + if (UnspecifiedSrc) { + if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) { // - // Match a certain interface address. + // Select the interface automatically. // + CopyMem(&Private->SrcAddress, Addr, sizeof(Private->SrcAddress)); break; } - } - - if (AddrIndex < IfInfo->AddressInfoCount) { + } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) { // - // Found a nic handle with right interface address. + // Match a certain interface address. // break; - } + } + } + + if (AddrIndex < IfInfo->AddressInfoCount) { + // + // Found a nic handle with right interface address. + // + break; } FreePool (IfInfo); @@ -802,7 +917,7 @@ Ping6CreateIpInstance ( // if (HandleIndex == HandleNum) { - ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND), gShellNetwork2HiiHandle, mIp6SrcString); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_CONFIGD_NIC_NF), gShellNetwork2HiiHandle); Status = EFI_NOT_FOUND; goto ON_ERROR; } @@ -937,7 +1052,11 @@ ShellPing6 ( ShellStatus = SHELL_SUCCESS; Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA)); - ASSERT (Private != NULL); + if (Private == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"Ping6"); + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } Private->ImageHandle = ImageHandle; Private->SendNum = SendNumber; @@ -987,6 +1106,16 @@ ShellPing6 ( ShellStatus = SHELL_ACCESS_DENIED; goto ON_EXIT; } + + // + // Start a timer to calculate the RTT. + // + Status = Ping6InitRttTimer (Private); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // // Create a ipv6 token to send the first icmp6 echo request packet. // @@ -1065,8 +1194,11 @@ ON_STAT: STRING_TOKEN (STR_PING6_RTT), gShellNetwork2HiiHandle, Private->RttMin, + Private->RttMin + Private->TimerPeriod, Private->RttMax, - DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL) + Private->RttMax + Private->TimerPeriod, + DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL), + DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL) + Private->TimerPeriod ); } @@ -1084,6 +1216,8 @@ ON_EXIT: Ping6DestroyTxInfo (TxInfo); } + Ping6FreeRttTimer (Private); + if (Private->Timer != NULL) { gBS->CloseEvent (Private->Timer); } @@ -1149,7 +1283,7 @@ ShellCommandRunPing6 ( BufferSize = 16; // - // Parse the paramter of count number. + // Parse the parameter of count number. // ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n"); ValueStrPtr = ValueStr; @@ -1166,7 +1300,7 @@ ShellCommandRunPing6 ( } } // - // Parse the paramter of buffer size. + // Parse the parameter of buffer size. // ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l"); ValueStrPtr = ValueStr; @@ -1187,7 +1321,7 @@ ShellCommandRunPing6 ( ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS)); // - // Parse the paramter of source ip address. + // Parse the parameter of source ip address. // ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s"); ValueStrPtr = ValueStr; @@ -1201,7 +1335,7 @@ ShellCommandRunPing6 ( } } // - // Parse the paramter of destination ip address. + // Parse the parameter of destination ip address. // NonOptionCount = ShellCommandLineGetCount(ParamPackage); ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1)); @@ -1220,15 +1354,7 @@ ShellCommandRunPing6 ( goto ON_EXIT; } } - // - // Get frequency to calculate the time from ticks. - // - Status = Ping6GetFrequency (); - if (EFI_ERROR(Status)) { - ShellStatus = SHELL_ACCESS_DENIED; - goto ON_EXIT; - } // // Enter into ping6 process. //