]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c
ShellPkg/Dp: Add null pointer check
[mirror_edk2.git] / ShellPkg / Library / UefiShellNetwork2CommandsLib / Ping6.c
index 4496802eac6dbce77657fbaaf31b552fadf9a353..2cdf484c06151635ca9733a0025e82443d38e823 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The implementation for Ping6 application.\r
 \r
-  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2016 - 2017, 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
 #define PING6_MAX_SEND_NUMBER      10000\r
 #define PING6_MAX_BUFFER_SIZE      32768\r
 #define PING6_ONE_SECOND           10000000\r
-\r
-//\r
-// A similar amount of time that passes in femtoseconds\r
-// for each increment of TimerValue. It is for NT32 only.\r
-//\r
-#define NTTIMERPERIOD    358049\r
+#define STALL_1_MILLI_SECOND  1000\r
 \r
 #pragma pack(1)\r
 \r
@@ -34,7 +29,7 @@ typedef struct _ICMP6_ECHO_REQUEST_REPLY {
   UINT16                      Checksum;\r
   UINT16                      Identifier;\r
   UINT16                      SequenceNum;\r
-  UINT64                      TimeStamp;\r
+  UINT32                      TimeStamp;\r
   UINT8                       Data[1];\r
 } ICMP6_ECHO_REQUEST_REPLY;\r
 \r
@@ -43,7 +38,7 @@ typedef struct _ICMP6_ECHO_REQUEST_REPLY {
 typedef struct _PING6_ICMP6_TX_INFO {\r
   LIST_ENTRY                  Link;\r
   UINT16                      SequenceNum;\r
-  UINT64                      TimeStamp;\r
+  UINT32                      TimeStamp;\r
   EFI_IP6_COMPLETION_TOKEN    *Token;\r
 } PING6_ICMP6_TX_INFO;\r
 \r
@@ -54,6 +49,10 @@ typedef struct _PING6_PRIVATE_DATA {
   EFI_IP6_PROTOCOL            *Ip6;\r
   EFI_EVENT                   Timer;\r
 \r
+  UINT32                      TimerPeriod;\r
+  UINT32                      RttTimerTick;   \r
+  EFI_EVENT                   RttTimer;\r
+\r
   EFI_STATUS                  Status;\r
   LIST_ENTRY                  TxList;\r
   EFI_IP6_COMPLETION_TOKEN    RxToken;\r
@@ -99,96 +98,189 @@ SHELL_PARAM_ITEM    Ping6ParamList[] = {
 //\r
 CONST CHAR16            *mIp6DstString;\r
 CONST CHAR16            *mIp6SrcString;\r
-UINT64                  mFrequency = 0;\r
-UINT64                  mIp6CurrentTick = 0;\r
 EFI_CPU_ARCH_PROTOCOL   *Cpu = NULL;\r
 \r
+/**\r
+  RTT timer tick routine.\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
+Ping6RttTimerTickRoutine (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID         *Context\r
+  )\r
+{\r
+  UINT32     *RttTimerTick;\r
 \r
+  RttTimerTick = (UINT32*) Context;\r
+  (*RttTimerTick)++;\r
+}\r
 \r
 /**\r
-  Reads and returns the current value of the Time.\r
+  Get the timer period of the system.\r
 \r
-  @return The current tick value.\r
+  This function tries to get the system timer period by creating\r
+  an 1ms period timer.\r
+\r
+  @return     System timer period in MS, or 0 if operation failed.\r
 \r
 **/\r
-UINT64\r
-Ping6ReadTime ()\r
+UINT32\r
+Ping6GetTimerPeriod(\r
+  VOID\r
+  )\r
 {\r
-  UINT64                 TimerPeriod;\r
-  EFI_STATUS             Status;\r
+  EFI_STATUS                 Status;\r
+  UINT32                     RttTimerTick;\r
+  EFI_EVENT                  TimerEvent;\r
+  UINT32                     StallCounter;\r
+  EFI_TPL                    OldTpl;\r
 \r
-  ASSERT (Cpu != NULL);\r
+  RttTimerTick = 0;\r
+  StallCounter   = 0;\r
 \r
-  Status = Cpu->GetTimerValue (Cpu, 0, &mIp6CurrentTick, &TimerPeriod);\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  Ping6RttTimerTickRoutine,\r
+                  &RttTimerTick,\r
+                  &TimerEvent\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
-    //\r
-    // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the\r
-    // TimerPeriod by ourselves.\r
-    //\r
-    mIp6CurrentTick += 1000000;\r
+    return 0;\r
   }\r
 \r
-  return mIp6CurrentTick;\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  Status = gBS->SetTimer (\r
+                  TimerEvent,\r
+                  TimerPeriodic,\r
+                  TICKS_PER_MS\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->CloseEvent (TimerEvent);\r
+    return 0;\r
+  }\r
+\r
+  while (RttTimerTick < 10) {\r
+    gBS->Stall (STALL_1_MILLI_SECOND);\r
+    ++StallCounter;\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  gBS->SetTimer (TimerEvent, TimerCancel, 0);\r
+  gBS->CloseEvent (TimerEvent);\r
+\r
+  return StallCounter / RttTimerTick;\r
 }\r
 \r
+\r
 /**\r
-  Get and calculate the frequency in tick/ms.\r
-  The result is saved in the globle variable mFrequency\r
+  Initialize the timer event for RTT (round trip time).\r
+\r
+  @param[in]    Private    The pointer to PING6_PRIVATE_DATA.\r
 \r
-  @retval EFI_SUCCESS    Calculated the frequency successfully.\r
-  @retval Others         Failed to calculate the frequency.\r
+  @retval EFI_SUCCESS      RTT timer is started.\r
+  @retval Others           Failed to start the RTT timer.\r
 \r
 **/\r
 EFI_STATUS\r
-Ping6GetFrequency (\r
-  VOID\r
+Ping6InitRttTimer (\r
+  IN  PING6_PRIVATE_DATA      *Private\r
   )\r
 {\r
-  EFI_STATUS               Status;\r
-  UINT64                   CurrentTick;\r
-  UINT64                   TimerPeriod;\r
-\r
-  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu);\r
+  EFI_STATUS                 Status;\r
 \r
+  Private->TimerPeriod = Ping6GetTimerPeriod ();\r
+  if (Private->TimerPeriod == 0) {\r
+    return EFI_ABORTED;\r
+  }\r
+  \r
+  Private->RttTimerTick = 0;\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  Ping6RttTimerTickRoutine,\r
+                  &Private->RttTimerTick,\r
+                  &Private->RttTimer\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod);\r
-\r
+  Status = gBS->SetTimer (\r
+                  Private->RttTimer,\r
+                  TimerPeriodic,\r
+                  TICKS_PER_MS\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
+    gBS->CloseEvent (Private->RttTimer);\r
+    return Status;\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
+/**\r
+  Free RTT timer event resource.\r
+\r
+  @param[in]    Private    The pointer to PING6_PRIVATE_DATA.\r
+\r
+**/\r
+VOID\r
+Ping6FreeRttTimer (\r
+  IN  PING6_PRIVATE_DATA      *Private\r
+  )\r
+{\r
+  if (Private->RttTimer != NULL) {\r
+    gBS->SetTimer (Private->RttTimer, TimerCancel, 0);\r
+    gBS->CloseEvent (Private->RttTimer);\r
+  }\r
+}\r
+\r
+/**\r
+  Read the current time.\r
+  \r
+  @param[in]    Private    The pointer to PING6_PRIVATE_DATA.\r
+\r
+  @retval the current tick value.\r
+**/\r
+UINT32\r
+Ping6ReadTime (\r
+  IN  PING6_PRIVATE_DATA      *Private\r
+  )\r
+{\r
+  return Private->RttTimerTick;\r
 }\r
 \r
 /**\r
   Get and calculate the duration in ms.\r
 \r
+  @param[in]  Private  The pointer to PING6_PRIVATE_DATA.\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
+UINT32\r
 Ping6CalculateTick (\r
-  IN UINT64    Begin,\r
-  IN UINT64    End\r
+  IN PING6_PRIVATE_DATA      *Private,\r
+  IN UINT32    Begin,\r
+  IN UINT32    End\r
   )\r
 {\r
-  ASSERT (End > Begin);\r
-  return DivU64x64Remainder (End - Begin, mFrequency, NULL);\r
+  if (End < Begin) {\r
+    return (0);\r
+  }\r
+\r
+  return (End - Begin) * Private->TimerPeriod;\r
+\r
 }\r
 \r
 /**\r
@@ -312,8 +404,7 @@ Ping6OnEchoReplyReceived6 (
   EFI_IP6_RECEIVE_DATA        *RxData;\r
   ICMP6_ECHO_REQUEST_REPLY    *Reply;\r
   UINT32                      PayLoad;\r
-  UINT64                      Rtt;\r
-  CHAR8                       Near;\r
+  UINT32                      Rtt;\r
 \r
   Private = (PING6_PRIVATE_DATA *) Context;\r
 \r
@@ -352,12 +443,7 @@ Ping6OnEchoReplyReceived6 (
   //\r
   // Display statistics on this icmp6 echo reply packet.\r
   //\r
-  Rtt  = Ping6CalculateTick (Reply->TimeStamp, Ping6ReadTime ());\r
-  if (Rtt != 0) {\r
-    Near = (CHAR8) '=';\r
-  } else {\r
-    Near = (CHAR8) '<';\r
-  }\r
+  Rtt  = Ping6CalculateTick (Private, Reply->TimeStamp, Ping6ReadTime (Private));\r
 \r
   Private->RttSum += Rtt;\r
   Private->RttMin  = Private->RttMin > Rtt ? Rtt : Private->RttMin;\r
@@ -373,8 +459,8 @@ Ping6OnEchoReplyReceived6 (
     mIp6DstString,\r
     Reply->SequenceNum,\r
     RxData->Header->HopLimit,\r
-    Near,\r
-    Rtt\r
+    Rtt,\r
+    Rtt + Private->TimerPeriod\r
     );\r
 \r
 ON_EXIT:\r
@@ -388,6 +474,7 @@ ON_EXIT:
     Status = Private->Ip6->Receive (Private->Ip6, RxToken);\r
 \r
     if (EFI_ERROR (Status)) {\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_RECEIVE), gShellNetwork2HiiHandle, Status);\r
       Private->Status = EFI_ABORTED;\r
     }\r
   } else {\r
@@ -415,7 +502,7 @@ ON_EXIT:
 EFI_IP6_COMPLETION_TOKEN *\r
 Ping6GenerateToken (\r
   IN PING6_PRIVATE_DATA    *Private,\r
-  IN UINT64                TimeStamp,\r
+  IN UINT32                TimeStamp,\r
   IN UINT16                SequenceNum\r
   )\r
 {\r
@@ -513,7 +600,7 @@ Ping6SendEchoRequest (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  TxInfo->TimeStamp   = Ping6ReadTime ();\r
+  TxInfo->TimeStamp   = Ping6ReadTime (Private);\r
   TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);\r
 \r
   TxInfo->Token       = Ping6GenerateToken (\r
@@ -572,7 +659,11 @@ Ping6OnReceiveEchoReply (
 \r
   Private->RxToken.Status = EFI_NOT_READY;\r
 \r
-  return Private->Ip6->Receive (Private->Ip6, &Private->RxToken);\r
+  Status = Private->Ip6->Receive (Private->Ip6, &Private->RxToken);\r
+  if (EFI_ERROR (Status)) {\r
+    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_RECEIVE), gShellNetwork2HiiHandle, Status);\r
+  }\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -615,7 +706,7 @@ Ping6OnTimerRoutine6 (
   //\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, Ping6ReadTime ());\r
+    Time   = Ping6CalculateTick (Private, TxInfo->TimeStamp, Ping6ReadTime (Private));\r
 \r
     //\r
     // Remove the timeout echo request from txlist.\r
@@ -664,7 +755,7 @@ Ping6CreateIpInstance (
   UINTN                            HandleNum;\r
   EFI_HANDLE                       *HandleBuffer;\r
   BOOLEAN                          UnspecifiedSrc;\r
-  BOOLEAN                          MediaPresent;\r
+  EFI_STATUS                       MediaStatus;\r
   EFI_SERVICE_BINDING_PROTOCOL     *Ip6Sb;\r
   EFI_IP6_CONFIG_PROTOCOL          *Ip6Cfg;\r
   EFI_IP6_CONFIG_DATA              Ip6Config;\r
@@ -675,7 +766,7 @@ Ping6CreateIpInstance (
 \r
   HandleBuffer      = NULL;\r
   UnspecifiedSrc    = FALSE;\r
-  MediaPresent      = TRUE;\r
+  MediaStatus       = EFI_SUCCESS;\r
   Ip6Sb             = NULL;\r
   IfInfo            = NULL;\r
   IfInfoSize        = 0;\r
@@ -723,8 +814,8 @@ Ping6CreateIpInstance (
       //\r
       // Check media.\r
       //\r
-      NetLibDetectMedia (HandleBuffer[HandleIndex], &MediaPresent);\r
-      if (!MediaPresent) {\r
+      NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus);\r
+      if (MediaStatus != EFI_SUCCESS) {\r
         //\r
         // Skip this one.\r
         //\r
@@ -961,7 +1052,11 @@ ShellPing6 (
   ShellStatus = SHELL_SUCCESS;\r
   Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA));\r
 \r
-  ASSERT (Private != NULL);\r
+  if (Private == NULL) {\r
+    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork2HiiHandle, L"Ping6");\r
+    ShellStatus = SHELL_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
 \r
   Private->ImageHandle = ImageHandle;\r
   Private->SendNum     = SendNumber;\r
@@ -1011,6 +1106,16 @@ ShellPing6 (
     ShellStatus = SHELL_ACCESS_DENIED;\r
     goto ON_EXIT;\r
   }\r
+\r
+  //\r
+  // Start a timer to calculate the RTT.\r
+  //\r
+  Status = Ping6InitRttTimer (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    ShellStatus = SHELL_ACCESS_DENIED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
   //\r
   // Create a ipv6 token to send the first icmp6 echo request packet.\r
   //\r
@@ -1089,8 +1194,11 @@ ON_STAT:
       STRING_TOKEN (STR_PING6_RTT),\r
       gShellNetwork2HiiHandle,\r
       Private->RttMin,\r
+      Private->RttMin + Private->TimerPeriod,\r
       Private->RttMax,\r
-      DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL)\r
+      Private->RttMax + Private->TimerPeriod,\r
+      DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL),\r
+      DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL) + Private->TimerPeriod\r
       );\r
   }\r
 \r
@@ -1108,6 +1216,8 @@ ON_EXIT:
       Ping6DestroyTxInfo (TxInfo);\r
     }\r
 \r
+    Ping6FreeRttTimer (Private);\r
+\r
     if (Private->Timer != NULL) {\r
       gBS->CloseEvent (Private->Timer);\r
     }\r
@@ -1173,7 +1283,7 @@ ShellCommandRunPing6 (
   BufferSize = 16;\r
 \r
   //\r
-  // Parse the paramter of count number.\r
+  // Parse the parameter of count number.\r
   //\r
   ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
   ValueStrPtr = ValueStr;\r
@@ -1190,7 +1300,7 @@ ShellCommandRunPing6 (
     }\r
   }\r
   //\r
-  // Parse the paramter of buffer size.\r
+  // Parse the parameter of buffer size.\r
   //\r
   ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
   ValueStrPtr = ValueStr;\r
@@ -1211,7 +1321,7 @@ ShellCommandRunPing6 (
   ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
 \r
   //\r
-  // Parse the paramter of source ip address.\r
+  // Parse the parameter of source ip address.\r
   //\r
   ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
   ValueStrPtr = ValueStr;\r
@@ -1225,7 +1335,7 @@ ShellCommandRunPing6 (
     }\r
   }\r
   //\r
-  // Parse the paramter of destination ip address.\r
+  // Parse the parameter of destination ip address.\r
   //\r
   NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
   ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1));\r
@@ -1244,15 +1354,7 @@ ShellCommandRunPing6 (
       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
-    ShellStatus = SHELL_ACCESS_DENIED;\r
-    goto ON_EXIT;\r
-  }\r
   //\r
   // Enter into ping6 process.\r
   //\r