]> 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 af7d08f3ec516bfd3932d0715fcaafe86850fee0..2cdf484c06151635ca9733a0025e82443d38e823 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The implementation for Ping6 application.\r
 \r
 /** @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
 \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
 #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
 \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
   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
   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
 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
   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
   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
   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
 //\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
 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
 \r
+  RttTimerTick = (UINT32*) Context;\r
+  (*RttTimerTick)++;\r
+}\r
 \r
 /**\r
 \r
 /**\r
-  Reads and returns the current value of the Time.\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
 \r
-  @return The current tick value.\r
+  @return     System timer period in MS, or 0 if operation failed.\r
 \r
 **/\r
 \r
 **/\r
-UINT64\r
-Ping6ReadTime ()\r
+UINT32\r
+Ping6GetTimerPeriod(\r
+  VOID\r
+  )\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
 \r
-  ASSERT (Cpu != NULL);\r
+  RttTimerTick = 0;\r
+  StallCounter   = 0;\r
 \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
   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
+  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
   }\r
 \r
-  return mIp6CurrentTick;\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
+\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
 \r
-  @retval EFI_SUCCESS    Calculated the frequency successfully.\r
-  @retval Others         Failed to calculate the frequency.\r
+  @param[in]    Private    The pointer to PING6_PRIVATE_DATA.\r
+\r
+  @retval EFI_SUCCESS      RTT timer is started.\r
+  @retval Others           Failed to start the RTT timer.\r
 \r
 **/\r
 EFI_STATUS\r
 \r
 **/\r
 EFI_STATUS\r
-Ping6GetFrequency (\r
-  VOID\r
+Ping6InitRttTimer (\r
+  IN  PING6_PRIVATE_DATA      *Private\r
   )\r
 {\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
 \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
   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
   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
-  //\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
   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
 }\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
   @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
 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
   )\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
 }\r
 \r
 /**\r
@@ -312,8 +404,7 @@ Ping6OnEchoReplyReceived6 (
   EFI_IP6_RECEIVE_DATA        *RxData;\r
   ICMP6_ECHO_REQUEST_REPLY    *Reply;\r
   UINT32                      PayLoad;\r
   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
 \r
   Private = (PING6_PRIVATE_DATA *) Context;\r
 \r
@@ -352,12 +443,7 @@ Ping6OnEchoReplyReceived6 (
   //\r
   // Display statistics on this icmp6 echo reply packet.\r
   //\r
   //\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
 \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
     mIp6DstString,\r
     Reply->SequenceNum,\r
     RxData->Header->HopLimit,\r
-    Near,\r
-    Rtt\r
+    Rtt,\r
+    Rtt + Private->TimerPeriod\r
     );\r
 \r
 ON_EXIT:\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
     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
       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
 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
   IN UINT16                SequenceNum\r
   )\r
 {\r
@@ -513,7 +600,7 @@ Ping6SendEchoRequest (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
     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
   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
 \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
 }\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
   //\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
 \r
     //\r
     // Remove the timeout echo request from txlist.\r
@@ -663,6 +754,8 @@ Ping6CreateIpInstance (
   UINTN                            HandleIndex;\r
   UINTN                            HandleNum;\r
   EFI_HANDLE                       *HandleBuffer;\r
   UINTN                            HandleIndex;\r
   UINTN                            HandleNum;\r
   EFI_HANDLE                       *HandleBuffer;\r
+  BOOLEAN                          UnspecifiedSrc;\r
+  EFI_STATUS                       MediaStatus;\r
   EFI_SERVICE_BINDING_PROTOCOL     *Ip6Sb;\r
   EFI_IP6_CONFIG_PROTOCOL          *Ip6Cfg;\r
   EFI_IP6_CONFIG_DATA              Ip6Config;\r
   EFI_SERVICE_BINDING_PROTOCOL     *Ip6Sb;\r
   EFI_IP6_CONFIG_PROTOCOL          *Ip6Cfg;\r
   EFI_IP6_CONFIG_DATA              Ip6Config;\r
@@ -671,10 +764,12 @@ Ping6CreateIpInstance (
   EFI_IPv6_ADDRESS                 *Addr;\r
   UINTN                            AddrIndex;\r
 \r
   EFI_IPv6_ADDRESS                 *Addr;\r
   UINTN                            AddrIndex;\r
 \r
-  HandleBuffer = NULL;\r
-  Ip6Sb        = NULL;\r
-  IfInfo       = NULL;\r
-  IfInfoSize   = 0;\r
+  HandleBuffer      = NULL;\r
+  UnspecifiedSrc    = FALSE;\r
+  MediaStatus       = EFI_SUCCESS;\r
+  Ip6Sb             = NULL;\r
+  IfInfo            = NULL;\r
+  IfInfoSize        = 0;\r
 \r
   //\r
   // Locate all the handles with ip6 service binding protocol.\r
 \r
   //\r
   // Locate all the handles with ip6 service binding protocol.\r
@@ -689,17 +784,23 @@ Ping6CreateIpInstance (
   if (EFI_ERROR (Status) || (HandleNum == 0)) {\r
     return EFI_ABORTED;\r
   }\r
   if (EFI_ERROR (Status) || (HandleNum == 0)) {\r
     return EFI_ABORTED;\r
   }\r
+\r
+  if (NetIp6IsUnspecifiedAddr (&Private->SrcAddress)) {\r
+    //\r
+    // SrcAddress is unspecified. So, both connected and configured interface will be automatic selected. \r
+    //\r
+    UnspecifiedSrc = TRUE;\r
+  }\r
+  \r
   //\r
   //\r
-  // Source address is required when pinging a link-local address on multi-\r
-  // interfaces host.\r
+  // Source address is required when pinging a link-local address.\r
   //\r
   //\r
-  if (NetIp6IsLinkLocalAddr (&Private->DstAddress) &&\r
-      NetIp6IsUnspecifiedAddr (&Private->SrcAddress) &&\r
-      (HandleNum > 1)) {\r
+  if (NetIp6IsLinkLocalAddr (&Private->DstAddress) && UnspecifiedSrc) {\r
     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SOURCE), gShellNetwork2HiiHandle);\r
     Status = EFI_INVALID_PARAMETER;\r
     goto ON_ERROR;\r
   }\r
     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SOURCE), gShellNetwork2HiiHandle);\r
     Status = EFI_INVALID_PARAMETER;\r
     goto ON_ERROR;\r
   }\r
+  \r
   //\r
   // For each ip6 protocol, check interface addresses list.\r
   //\r
   //\r
   // For each ip6 protocol, check interface addresses list.\r
   //\r
@@ -709,6 +810,19 @@ Ping6CreateIpInstance (
     IfInfo     = NULL;\r
     IfInfoSize = 0;\r
 \r
     IfInfo     = NULL;\r
     IfInfoSize = 0;\r
 \r
+    if (UnspecifiedSrc) {\r
+      //\r
+      // Check media.\r
+      //\r
+      NetLibDetectMediaWaitTimeout (HandleBuffer[HandleIndex], 0, &MediaStatus);\r
+      if (MediaStatus != EFI_SUCCESS) {\r
+        //\r
+        // Skip this one.\r
+        //\r
+        continue;\r
+      }\r
+    }\r
+\r
     Status = gBS->HandleProtocol (\r
                     HandleBuffer[HandleIndex],\r
                     &gEfiIp6ServiceBindingProtocolGuid,\r
     Status = gBS->HandleProtocol (\r
                     HandleBuffer[HandleIndex],\r
                     &gEfiIp6ServiceBindingProtocolGuid,\r
@@ -718,80 +832,81 @@ Ping6CreateIpInstance (
       goto ON_ERROR;\r
     }\r
 \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
+    // 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
 \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), gShellNetwork2HiiHandle, Status);\r
-        goto ON_ERROR;\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), gShellNetwork2HiiHandle, Status);\r
+      goto ON_ERROR;\r
+    }\r
 \r
 \r
-      IfInfo = AllocateZeroPool (IfInfoSize);\r
+    IfInfo = AllocateZeroPool (IfInfoSize);\r
 \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
+    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
 \r
-      if (EFI_ERROR (Status)) {\r
-        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, 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
+    if (EFI_ERROR (Status)) {\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, 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
+      Addr = &(IfInfo->AddressInfo[AddrIndex].Address);\r
 \r
 \r
-        Addr = &(IfInfo->AddressInfo[AddrIndex].Address);\r
-        if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
+      if (UnspecifiedSrc) {\r
+        if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {\r
           //\r
           //\r
-          // Match a certain interface address.\r
+          // Select the interface automatically.\r
           //\r
           //\r
+          CopyMem(&Private->SrcAddress, Addr, sizeof(Private->SrcAddress));\r
           break;\r
         }\r
           break;\r
         }\r
-      }\r
-\r
-      if (AddrIndex < IfInfo->AddressInfoCount) {\r
+      } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
         //\r
         //\r
-        // Found a nic handle with right interface address.\r
+        // Match a certain interface address.\r
         //\r
         break;\r
         //\r
         break;\r
-      }\r
+      } \r
+    }\r
+\r
+    if (AddrIndex < IfInfo->AddressInfoCount) {\r
+      //\r
+      // Found a nic handle with right interface address.\r
+      //\r
+      break;\r
     }\r
 \r
     FreePool (IfInfo);\r
     }\r
 \r
     FreePool (IfInfo);\r
@@ -802,7 +917,7 @@ Ping6CreateIpInstance (
   //\r
 \r
   if (HandleIndex == HandleNum) {\r
   //\r
 \r
   if (HandleIndex == HandleNum) {\r
-    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND), gShellNetwork2HiiHandle, mIp6SrcString);\r
+    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_CONFIGD_NIC_NF), gShellNetwork2HiiHandle);\r
     Status = EFI_NOT_FOUND;\r
     goto ON_ERROR;\r
   }\r
     Status = EFI_NOT_FOUND;\r
     goto ON_ERROR;\r
   }\r
@@ -937,7 +1052,11 @@ ShellPing6 (
   ShellStatus = SHELL_SUCCESS;\r
   Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA));\r
 \r
   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
 \r
   Private->ImageHandle = ImageHandle;\r
   Private->SendNum     = SendNumber;\r
@@ -987,6 +1106,16 @@ ShellPing6 (
     ShellStatus = SHELL_ACCESS_DENIED;\r
     goto ON_EXIT;\r
   }\r
     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
   //\r
   // Create a ipv6 token to send the first icmp6 echo request packet.\r
   //\r
@@ -1065,8 +1194,11 @@ ON_STAT:
       STRING_TOKEN (STR_PING6_RTT),\r
       gShellNetwork2HiiHandle,\r
       Private->RttMin,\r
       STRING_TOKEN (STR_PING6_RTT),\r
       gShellNetwork2HiiHandle,\r
       Private->RttMin,\r
+      Private->RttMin + Private->TimerPeriod,\r
       Private->RttMax,\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
       );\r
   }\r
 \r
@@ -1084,6 +1216,8 @@ ON_EXIT:
       Ping6DestroyTxInfo (TxInfo);\r
     }\r
 \r
       Ping6DestroyTxInfo (TxInfo);\r
     }\r
 \r
+    Ping6FreeRttTimer (Private);\r
+\r
     if (Private->Timer != NULL) {\r
       gBS->CloseEvent (Private->Timer);\r
     }\r
     if (Private->Timer != NULL) {\r
       gBS->CloseEvent (Private->Timer);\r
     }\r
@@ -1149,7 +1283,7 @@ ShellCommandRunPing6 (
   BufferSize = 16;\r
 \r
   //\r
   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
   //\r
   ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n");\r
   ValueStrPtr = ValueStr;\r
@@ -1166,7 +1300,7 @@ ShellCommandRunPing6 (
     }\r
   }\r
   //\r
     }\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
   //\r
   ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");\r
   ValueStrPtr = ValueStr;\r
@@ -1187,7 +1321,7 @@ ShellCommandRunPing6 (
   ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS));\r
 \r
   //\r
   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
   //\r
   ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
   ValueStrPtr = ValueStr;\r
@@ -1201,7 +1335,7 @@ ShellCommandRunPing6 (
     }\r
   }\r
   //\r
     }\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
   //\r
   NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
   ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1));\r
@@ -1220,15 +1354,7 @@ ShellCommandRunPing6 (
       goto ON_EXIT;\r
     }\r
   }\r
       goto ON_EXIT;\r
     }\r
   }\r
-  //\r
-  // Get frequency to calculate the time from ticks.\r
-  //\r
-  Status = Ping6GetFrequency ();\r
 \r
 \r
-  if (EFI_ERROR(Status)) {\r
-    ShellStatus = SHELL_ACCESS_DENIED;\r
-    goto ON_EXIT;\r
-  }\r
   //\r
   // Enter into ping6 process.\r
   //\r
   //\r
   // Enter into ping6 process.\r
   //\r