]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
ShellPkg/Dp: Add null pointer check
[mirror_edk2.git] / ShellPkg / Library / UefiShellNetwork1CommandsLib / Ping.c
index 38625fef93e62c2025e3b890e851ad47cef74c1d..bec9535a8b436338c91e94290fde58a900e43804 100644 (file)
@@ -2,7 +2,7 @@
   The implementation for Ping shell command.\r
 \r
   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
-  Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
   (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
 \r
   This program and the accompanying materials\r
@@ -86,7 +86,7 @@ typedef struct _ICMPX_ECHO_REQUEST_REPLY {
   UINT16                      Checksum;\r
   UINT16                      Identifier;\r
   UINT16                      SequenceNum;\r
-  UINT64                      TimeStamp;\r
+  UINT32                      TimeStamp;\r
   UINT8                       Data[1];\r
 } ICMPX_ECHO_REQUEST_REPLY;\r
 #pragma pack()\r
@@ -94,7 +94,7 @@ typedef struct _ICMPX_ECHO_REQUEST_REPLY {
 typedef struct _PING_ICMP_TX_INFO {\r
   LIST_ENTRY                Link;\r
   UINT16                    SequenceNum;\r
-  UINT64                    TimeStamp;\r
+  UINT32                    TimeStamp;\r
   PING_IPX_COMPLETION_TOKEN *Token;\r
 } PING_ICMPX_TX_INFO;\r
 \r
@@ -109,6 +109,7 @@ typedef struct _PING_ICMP_TX_INFO {
 #define DEFAULT_BUFFER_SIZE   16\r
 #define ICMP_V4_ECHO_REQUEST  0x8\r
 #define ICMP_V4_ECHO_REPLY    0x0\r
+#define STALL_1_MILLI_SECOND  1000\r
 \r
 #define PING_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('P', 'i', 'n', 'g')\r
 typedef struct _PING_PRIVATE_DATA {\r
@@ -117,6 +118,10 @@ typedef struct _PING_PRIVATE_DATA {
   EFI_HANDLE                  IpChildHandle;\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
   UINT16                      RxCount;\r
@@ -221,93 +226,185 @@ STATIC CONST SHELL_PARAM_ITEM    PingParamList[] = {
 //\r
 STATIC CONST CHAR16      *mDstString;\r
 STATIC CONST CHAR16      *mSrcString;\r
-STATIC UINT64            mFrequency = 0;\r
-EFI_CPU_ARCH_PROTOCOL    *gCpu = NULL;\r
 \r
 /**\r
-  Read the current time.\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
-  @retval the current tick value.\r
 **/\r
-UINT64\r
-ReadTime (\r
+VOID\r
+EFIAPI\r
+RttTimerTickRoutine (\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
+  Get the timer period of the system.\r
+\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
+UINT32\r
+GetTimerPeriod(\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 (gCpu != NULL);\r
+  RttTimerTick = 0;\r
+  StallCounter   = 0;\r
 \r
-  Status = gCpu->GetTimerValue (gCpu, 0, &mCurrentTick, &TimerPeriod);\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  RttTimerTickRoutine,\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
-    mCurrentTick += 1000000;\r
+    return 0;\r
   }\r
-  \r
-  return mCurrentTick;\r
-}\r
 \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
-  Get and calculate the frequency in ticks/ms.\r
-  The result is saved in the global variable mFrequency\r
+  Initialize the timer event for RTT (round trip time).\r
+\r
+  @param[in]    Private    The pointer to PING_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
-GetFrequency (\r
-  VOID\r
+PingInitRttTimer (\r
+  PING_PRIVATE_DATA      *Private\r
   )\r
 {\r
-  EFI_STATUS               Status;\r
-  UINT64                   CurrentTick;\r
-  UINT64                   TimerPeriod;\r
+  EFI_STATUS                 Status;\r
 \r
-  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &gCpu);\r
+  Private->TimerPeriod = GetTimerPeriod ();\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
+                  RttTimerTickRoutine,\r
+                  &Private->RttTimerTick,\r
+                  &Private->RttTimer\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Status = gCpu->GetTimerValue (gCpu, 0, &CurrentTick, &TimerPeriod);\r
-\r
+  Status = gBS->SetTimer (\r
+                  Private->RttTimer,\r
+                  TimerPeriodic,\r
+                  TICKS_PER_MS\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
-    TimerPeriod = DEFAULT_TIMER_PERIOD;\r
+    gBS->CloseEvent (Private->RttTimer);\r
+    return Status;\r
   }\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 ticks/ms.\r
-  //\r
-  mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL);\r
-\r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Free RTT timer event resource.\r
+\r
+  @param[in]    Private    The pointer to PING_PRIVATE_DATA.\r
+\r
+**/\r
+VOID\r
+PingFreeRttTimer (\r
+  PING_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 PING_PRIVATE_DATA.\r
+\r
+  @retval the current tick value.\r
+**/\r
+UINT32\r
+ReadTime (\r
+  PING_PRIVATE_DATA      *Private\r
+  )\r
+{\r
+  return Private->RttTimerTick;\r
+}\r
+\r
 /**\r
   Calculate a duration in ms.\r
 \r
-  @param[in]  Begin     The start point of time.\r
-  @param[in]  End       The end point of time.\r
+  @param[in]    Private   The pointer to PING_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
   @retval 0             The parameters were not valid.\r
 **/\r
-UINT64\r
+UINT32\r
 CalculateTick (\r
-  IN UINT64    Begin,\r
-  IN UINT64    End\r
+  PING_PRIVATE_DATA      *Private,\r
+  IN UINT32              Begin,\r
+  IN UINT32              End\r
   )\r
 {\r
-  if (End <= Begin) {\r
+  if (End < Begin) {\r
     return (0);\r
   }\r
-  return DivU64x64Remainder (End - Begin, mFrequency, NULL);\r
+\r
+  return (End - Begin) * Private->TimerPeriod;\r
 }\r
 \r
 /**\r
@@ -448,8 +545,7 @@ Ping6OnEchoReplyReceived (
   PING_PRIVATE_DATA           *Private;\r
   ICMPX_ECHO_REQUEST_REPLY    *Reply;\r
   UINT32                      PayLoad;\r
-  UINT64                      Rtt;\r
-  CHAR8                       Near;\r
+  UINT32                      Rtt;\r
 \r
   Private = (PING_PRIVATE_DATA *) Context;\r
 \r
@@ -502,12 +598,7 @@ Ping6OnEchoReplyReceived (
   //\r
   // Display statistics on this icmp6 echo reply packet.\r
   //\r
-  Rtt  = CalculateTick (Reply->TimeStamp, ReadTime ());\r
-  if (Rtt != 0) {\r
-    Near = (CHAR8) '=';\r
-  } else {\r
-    Near = (CHAR8) '<';\r
-  }\r
+  Rtt  = CalculateTick (Private, Reply->TimeStamp, ReadTime (Private));\r
 \r
   Private->RttSum += Rtt;\r
   Private->RttMin  = Private->RttMin > Rtt ? Rtt : Private->RttMin;\r
@@ -523,8 +614,8 @@ Ping6OnEchoReplyReceived (
     mDstString,\r
     Reply->SequenceNum,\r
     Private->IpChoice == PING_IP_CHOICE_IP6?((EFI_IP6_RECEIVE_DATA*)Private->RxToken.Packet.RxData)->Header->HopLimit:0,\r
-    Near,\r
-    Rtt\r
+    Rtt,\r
+    Rtt + Private->TimerPeriod\r
     );\r
 \r
 ON_EXIT:\r
@@ -538,6 +629,7 @@ ON_EXIT:
     Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);\r
 \r
     if (EFI_ERROR (Status)) {\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);\r
       Private->Status = EFI_ABORTED;\r
     }\r
   } else {\r
@@ -565,7 +657,7 @@ ON_EXIT:
 PING_IPX_COMPLETION_TOKEN *\r
 PingGenerateToken (\r
   IN PING_PRIVATE_DATA    *Private,\r
-  IN UINT64                TimeStamp,\r
+  IN UINT32                TimeStamp,\r
   IN UINT16                SequenceNum\r
   )\r
 {\r
@@ -678,7 +770,7 @@ PingSendEchoRequest (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  TxInfo->TimeStamp   = ReadTime ();\r
+  TxInfo->TimeStamp   = ReadTime (Private);\r
   TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1);\r
   TxInfo->Token       = PingGenerateToken (\r
                           Private,\r
@@ -737,7 +829,11 @@ Ping6ReceiveEchoReply (
 \r
   Private->RxToken.Status = EFI_NOT_READY;\r
 \r
-  return (Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken));\r
+  Status = Private->ProtocolPointers.Receive (Private->IpProtocol, &Private->RxToken);\r
+  if (EFI_ERROR (Status)) {\r
+    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_RECEIVE), gShellNetwork1HiiHandle, Status);\r
+  }\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -784,7 +880,7 @@ Ping6OnTimerRoutine (
   //\r
   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) {\r
     TxInfo = BASE_CR (Entry, PING_ICMPX_TX_INFO, Link);\r
-    Time   = CalculateTick (TxInfo->TimeStamp, ReadTime ());\r
+    Time   = CalculateTick (Private, TxInfo->TimeStamp, ReadTime (Private));\r
 \r
     //\r
     // Remove the timeout echo request from txlist.\r
@@ -870,7 +966,7 @@ PingCreateIpInstance (
   UINTN                            HandleNum;\r
   EFI_HANDLE                       *HandleBuffer;\r
   BOOLEAN                          UnspecifiedSrc;\r
-  BOOLEAN                          MediaPresent;\r
+  EFI_STATUS                       MediaStatus;\r
   EFI_SERVICE_BINDING_PROTOCOL     *EfiSb;\r
   VOID                             *IpXCfg;\r
   EFI_IP6_CONFIG_DATA              Ip6Config;\r
@@ -882,7 +978,7 @@ PingCreateIpInstance (
 \r
   HandleBuffer      = NULL;\r
   UnspecifiedSrc    = FALSE;\r
-  MediaPresent      = TRUE;\r
+  MediaStatus       = EFI_SUCCESS;\r
   EfiSb             = NULL;\r
   IpXInterfaceInfo  = NULL;\r
   IfInfoSize        = 0;\r
@@ -939,8 +1035,8 @@ PingCreateIpInstance (
       //\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
@@ -1239,6 +1335,7 @@ Ping6DestroyIp6Instance (
   }\r
 }\r
 \r
+\r
 /**\r
   The Ping Process.\r
 \r
@@ -1323,6 +1420,16 @@ ShellPing (
     ShellStatus = SHELL_ACCESS_DENIED;\r
     goto ON_EXIT;\r
   }\r
+\r
+  //\r
+  // Start a timer to calculate the RTT.\r
+  //\r
+  Status = PingInitRttTimer (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
@@ -1397,8 +1504,11 @@ ON_STAT:
       STRING_TOKEN (STR_PING_RTT),\r
       gShellNetwork1HiiHandle,\r
       Private->RttMin,\r
+      Private->RttMin + Private->TimerPeriod,\r
       Private->RttMax,\r
-      DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL)\r
+      Private->RttMax + Private->TimerPeriod,\r
+      DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL),\r
+      DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL) + Private->TimerPeriod\r
       );\r
   }\r
 \r
@@ -1417,6 +1527,8 @@ ON_EXIT:
       PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
     }\r
 \r
+    PingFreeRttTimer (Private);\r
+\r
     if (Private->Timer != NULL) {\r
       gBS->CloseEvent (Private->Timer);\r
     }\r
@@ -1492,7 +1604,7 @@ ShellCommandRunPing (
   }\r
 \r
   //\r
-  // Parse the paramter of count number.\r
+  // Parse the parameter of count number.\r
   //\r
   ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
   if (ValueStr != NULL) {\r
@@ -1510,7 +1622,7 @@ ShellCommandRunPing (
     SendNumber = DEFAULT_SEND_COUNT;\r
   }\r
   //\r
-  // Parse the paramter of buffer size.\r
+  // Parse the parameter of buffer size.\r
   //\r
   ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
   if (ValueStr != NULL) {\r
@@ -1532,7 +1644,7 @@ ShellCommandRunPing (
   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
   if (ValueStr == NULL) {\r
@@ -1553,7 +1665,7 @@ ShellCommandRunPing (
     }\r
   }\r
   //\r
-  // Parse the paramter of destination ip address.\r
+  // Parse the parameter of destination ip address.\r
   //\r
   NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
   if (NonOptionCount < 2) {\r
@@ -1580,14 +1692,7 @@ ShellCommandRunPing (
       goto ON_EXIT;\r
     }\r
   }\r
-  //\r
-  // Get frequency to calculate the time from ticks.\r
-  //\r
-  Status = GetFrequency ();\r
 \r
-  if (EFI_ERROR(Status)) {\r
-    goto ON_EXIT;\r
-  }\r
   //\r
   // Enter into ping process.\r
   //\r