]> 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 493de26f8a95992543350c391ac475fb3eb06798..bec9535a8b436338c91e94290fde58a900e43804 100644 (file)
@@ -1,7 +1,9 @@
 /** @file\r
   The implementation for Ping shell command.\r
 \r
-  Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<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
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -17,6 +19,7 @@
 \r
 #define PING_IP4_COPY_ADDRESS(Dest, Src) (CopyMem ((Dest), (Src), sizeof (EFI_IPv4_ADDRESS)))\r
 \r
+UINT64          mCurrentTick = 0;\r
 \r
 //\r
 // Function templates to match the IPv4 and IPv6 commands that we use.\r
@@ -83,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
@@ -91,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
@@ -106,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
@@ -114,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
@@ -132,31 +140,23 @@ typedef struct _PING_PRIVATE_DATA {
   UINT8                       SrcAddress[MAX(sizeof(EFI_IPv6_ADDRESS)        , sizeof(EFI_IPv4_ADDRESS)          )];\r
   UINT8                       DstAddress[MAX(sizeof(EFI_IPv6_ADDRESS)        , sizeof(EFI_IPv4_ADDRESS)          )];\r
   PING_IPX_COMPLETION_TOKEN   RxToken;\r
+  UINT16                      FailedCount;\r
 } PING_PRIVATE_DATA;\r
 \r
+/**\r
+  Calculate the internet checksum (see RFC 1071).\r
+\r
+  @param[in] Packet  Buffer which contains the data to be checksummed.\r
+  @param[in] Length  Length to be checksummed.\r
+\r
+  @retval Checksum     Returns the 16 bit ones complement of \r
+                       ones complement sum of 16 bit words\r
+**/\r
 UINT16\r
-EFIAPI\r
 NetChecksum (\r
   IN UINT8   *Buffer,\r
   IN UINT32  Length\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Calculate the internet checksum (see RFC 1071)\r
-\r
-Arguments:\r
-\r
-  Packet             - Buffer which contains the data to be checksummed\r
-  Length             - Length to be checksummed\r
-\r
-Returns:\r
-\r
-  Checksum           - Returns the 16 bit ones complement of \r
-                       ones complement sum of 16 bit words\r
-\r
---*/\r
 {\r
   UINT32  Sum;\r
   UINT8   Odd;\r
@@ -167,11 +167,11 @@ Returns:
   Sum     = 0;\r
   Odd     = (UINT8) (Length & 1);\r
   Length >>= 1;\r
-  while (Length--) {\r
+  while ((Length--) != 0) {\r
     Sum += *Packet++;\r
   }\r
 \r
-  if (Odd) {\r
+  if (Odd != 0) {\r
     Sum += *(UINT8 *) Packet;\r
   }\r
 \r
@@ -193,11 +193,6 @@ Returns:
   @return The current value of the register.\r
 \r
 **/\r
-UINT64\r
-EFIAPI\r
-ReadTime (\r
-  VOID\r
-  );\r
 \r
 STATIC CONST SHELL_PARAM_ITEM    PingParamList[] = {\r
   {\r
@@ -208,6 +203,10 @@ STATIC CONST SHELL_PARAM_ITEM    PingParamList[] = {
     L"-n",\r
     TypeValue\r
   },\r
+  {\r
+    L"-s",\r
+    TypeValue\r
+  },\r
   {\r
     L"-_s",\r
     TypeValue\r
@@ -227,68 +226,185 @@ STATIC CONST SHELL_PARAM_ITEM    PingParamList[] = {
 //\r
 STATIC CONST CHAR16      *mDstString;\r
 STATIC CONST CHAR16      *mSrcString;\r
-STATIC UINT64            mFrequency = 0;\r
 \r
 /**\r
-  Get and caculate the frequency in tick/ms.\r
-  The result is saved in the globle variable mFrequency\r
+  RTT timer tick routine.\r
 \r
-  @retval EFI_SUCCESS    Caculated the frequency successfully.\r
-  @retval Others         Failed to caculate the frequency.\r
+  @param[in]    Event    A EFI_EVENT type event.\r
+  @param[in]    Context  The pointer to Context.\r
 \r
 **/\r
-EFI_STATUS\r
+VOID\r
 EFIAPI\r
-GetFrequency (\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
-  EFI_STATUS               Status;\r
-  EFI_CPU_ARCH_PROTOCOL    *Cpu;\r
-  UINT64                   CurrentTick;\r
-  UINT64                   TimerPeriod;\r
+  EFI_STATUS                 Status;\r
+  UINT32                     RttTimerTick;\r
+  EFI_EVENT                  TimerEvent;\r
+  UINT32                     StallCounter;\r
+  EFI_TPL                    OldTpl;\r
 \r
-  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu);\r
+  RttTimerTick = 0;\r
+  StallCounter   = 0;\r
 \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
-    return Status;\r
+    return 0;\r
   }\r
 \r
-  Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod);\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
+  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      RTT timer is started.\r
+  @retval Others           Failed to start the RTT timer.\r
+\r
+**/\r
+EFI_STATUS\r
+PingInitRttTimer (\r
+  PING_PRIVATE_DATA      *Private\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
 \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
-    TimerPeriod = DEFAULT_TIMER_PERIOD;\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
+  Status = gBS->SetTimer (\r
+                  Private->RttTimer,\r
+                  TimerPeriodic,\r
+                  TICKS_PER_MS\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->CloseEvent (Private->RttTimer);\r
+    return Status;\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Caculate a duration in ms.\r
+  Free RTT timer event resource.\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
+\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]    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
-EFIAPI\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
@@ -298,7 +414,6 @@ CalculateTick (
   @param[in]    IpChoice  Whether the token is IPv4 or IPv6\r
 **/\r
 VOID\r
-EFIAPI\r
 PingDestroyTxInfo (\r
   IN PING_ICMPX_TX_INFO    *TxInfo,\r
   IN UINT32                IpChoice\r
@@ -370,7 +485,6 @@ PingDestroyTxInfo (
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 Ping6MatchEchoReply (\r
   IN PING_PRIVATE_DATA           *Private,\r
   IN ICMPX_ECHO_REQUEST_REPLY    *Packet\r
@@ -431,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
@@ -485,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
@@ -506,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
@@ -521,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
@@ -546,10 +655,9 @@ ON_EXIT:
 \r
 **/\r
 PING_IPX_COMPLETION_TOKEN *\r
-EFIAPI\r
 PingGenerateToken (\r
   IN PING_PRIVATE_DATA    *Private,\r
-  IN UINT64                TimeStamp,\r
+  IN UINT32                TimeStamp,\r
   IN UINT16                SequenceNum\r
   )\r
 {\r
@@ -581,7 +689,7 @@ PingGenerateToken (
   //\r
   Request->Type        = (UINT8)(Private->IpChoice==PING_IP_CHOICE_IP6?ICMP_V6_ECHO_REQUEST:ICMP_V4_ECHO_REQUEST);\r
   Request->Code        = 0;\r
-  Request->SequenceNum = SequenceNum;\r
+  Request->SequenceNum = SequenceNum; \r
   Request->Identifier  = 0;\r
   Request->Checksum    = 0;\r
 \r
@@ -589,6 +697,7 @@ PingGenerateToken (
   // Assembly token for transmit.\r
   //\r
   if (Private->IpChoice==PING_IP_CHOICE_IP6) {\r
+    Request->TimeStamp   = TimeStamp;\r
     ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrsLength                   = 0;\r
     ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrs                         = NULL;\r
     ((EFI_IP6_TRANSMIT_DATA*)TxData)->OverrideData                    = 0;\r
@@ -648,7 +757,6 @@ PingGenerateToken (
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 PingSendEchoRequest (\r
   IN PING_PRIVATE_DATA    *Private\r
   )\r
@@ -662,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
@@ -699,7 +807,6 @@ PingSendEchoRequest (
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 Ping6ReceiveEchoReply (\r
   IN PING_PRIVATE_DATA    *Private\r
   )\r
@@ -722,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
@@ -769,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
@@ -787,10 +898,8 @@ Ping6OnTimerRoutine (
       RemoveEntryList (&TxInfo->Link);\r
       PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
 \r
-      //\r
-      // We dont need to wait for this some other time...\r
-      //\r
       Private->RxCount++;\r
+      Private->FailedCount++;\r
 \r
       if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
         //\r
@@ -813,7 +922,6 @@ Ping6OnTimerRoutine (
   @retval FALSE     It is not.\r
 **/\r
 BOOLEAN\r
-EFIAPI\r
 PingNetIp4IsLinkLocalAddr (\r
   IN CONST EFI_IPv4_ADDRESS *Address\r
   )\r
@@ -830,7 +938,6 @@ PingNetIp4IsLinkLocalAddr (
   @retval FALSE     It is not.\r
 **/\r
 BOOLEAN\r
-EFIAPI\r
 PingNetIp4IsUnspecifiedAddr (\r
   IN CONST EFI_IPv4_ADDRESS *Address\r
   )\r
@@ -850,7 +957,6 @@ PingNetIp4IsUnspecifiedAddr (
   @retval EFI_NOT_FOUND            The source address is not found.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 PingCreateIpInstance (\r
   IN  PING_PRIVATE_DATA    *Private\r
   )\r
@@ -859,6 +965,8 @@ PingCreateIpInstance (
   UINTN                            HandleIndex;\r
   UINTN                            HandleNum;\r
   EFI_HANDLE                       *HandleBuffer;\r
+  BOOLEAN                          UnspecifiedSrc;\r
+  EFI_STATUS                       MediaStatus;\r
   EFI_SERVICE_BINDING_PROTOCOL     *EfiSb;\r
   VOID                             *IpXCfg;\r
   EFI_IP6_CONFIG_DATA              Ip6Config;\r
@@ -869,6 +977,8 @@ PingCreateIpInstance (
   UINTN                            AddrIndex;\r
 \r
   HandleBuffer      = NULL;\r
+  UnspecifiedSrc    = FALSE;\r
+  MediaStatus       = EFI_SUCCESS;\r
   EfiSb             = NULL;\r
   IpXInterfaceInfo  = NULL;\r
   IfInfoSize        = 0;\r
@@ -883,40 +993,57 @@ PingCreateIpInstance (
                   &HandleNum,\r
                   &HandleBuffer\r
                   );\r
-  if (EFI_ERROR (Status) || (HandleNum == 0)) {\r
+  if (EFI_ERROR (Status) || (HandleNum == 0) || (HandleBuffer == NULL)) {\r
     return EFI_ABORTED;\r
   }\r
+\r
+  if (Private->IpChoice == PING_IP_CHOICE_IP6 ? NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress) : \\r
+      PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&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
-  // 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
   if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
-    if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS*)&Private->DstAddress) &&\r
-        NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress) &&\r
-        (HandleNum > 1)) {\r
-      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, mSrcString);\r
+    if (NetIp6IsLinkLocalAddr ((EFI_IPv6_ADDRESS*)&Private->DstAddress) && UnspecifiedSrc) {\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle);\r
       Status = EFI_INVALID_PARAMETER;\r
       goto ON_ERROR;\r
     }\r
   } else {\r
     ASSERT(Private->IpChoice == PING_IP_CHOICE_IP4);\r
-    if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS*)&Private->DstAddress) &&\r
-        PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&Private->SrcAddress) &&\r
-        (HandleNum > 1)) {\r
-      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, mSrcString);\r
+    if (PingNetIp4IsLinkLocalAddr ((EFI_IPv4_ADDRESS*)&Private->DstAddress) && UnspecifiedSrc) {\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_INVALID_SOURCE), gShellNetwork1HiiHandle); \r
       Status = EFI_INVALID_PARAMETER;\r
       goto ON_ERROR;\r
     }\r
   }\r
+  \r
   //\r
   // For each ip6 protocol, check interface addresses list.\r
   //\r
   for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {\r
-\r
     EfiSb             = NULL;\r
     IpXInterfaceInfo  = 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
                     Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
@@ -926,114 +1053,122 @@ PingCreateIpInstance (
       goto ON_ERROR;\r
     }\r
 \r
-    if (Private->IpChoice == PING_IP_CHOICE_IP6?NetIp6IsUnspecifiedAddr ((EFI_IPv6_ADDRESS*)&Private->SrcAddress):PingNetIp4IsUnspecifiedAddr ((EFI_IPv4_ADDRESS*)&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
-                      Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ConfigProtocolGuid:&gEfiIp4ConfigProtocolGuid,\r
-                      (VOID **) &IpXCfg\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
+                    Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ConfigProtocolGuid:&gEfiIp4Config2ProtocolGuid,\r
+                    (VOID **) &IpXCfg\r
+                    );\r
 \r
-      if (EFI_ERROR (Status)) {\r
-        goto ON_ERROR;\r
-      }\r
-      //\r
-      // Get the interface information size.\r
-      //\r
-      if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
-        Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
-                           IpXCfg,\r
-                           Ip6ConfigDataTypeInterfaceInfo,\r
-                           &IfInfoSize,\r
-                           NULL\r
-                           );\r
-      } else {\r
-        Status = ((EFI_IP4_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
-                           IpXCfg,\r
-                           &IfInfoSize,\r
-                           NULL\r
-                           );\r
-      }\r
-      \r
-      //\r
-      // Skip the ones not in current use.\r
-      //\r
-      if (Status == EFI_NOT_STARTED) {\r
-        continue;\r
-      }\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+    //\r
+    // Get the interface information size.\r
+    //\r
+    if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
+      Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
+                         IpXCfg,\r
+                         Ip6ConfigDataTypeInterfaceInfo,\r
+                         &IfInfoSize,\r
+                         NULL\r
+                         );\r
+    } else {\r
+      Status = ((EFI_IP4_CONFIG2_PROTOCOL*)IpXCfg)->GetData (\r
+                         IpXCfg,\r
+                         Ip4Config2DataTypeInterfaceInfo,\r
+                         &IfInfoSize,\r
+                         NULL\r
+                         );\r
+    }\r
+    \r
+    //\r
+    // Skip the ones not in current use.\r
+    //\r
+    if (Status == EFI_NOT_STARTED) {\r
+      continue;\r
+    }\r
 \r
-      if (Status != EFI_BUFFER_TOO_SMALL) {\r
-        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
-        goto ON_ERROR;\r
-      }\r
+    if (Status != EFI_BUFFER_TOO_SMALL) {\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
+      goto ON_ERROR;\r
+    }\r
 \r
-      IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);\r
+    IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);\r
 \r
-      if (IpXInterfaceInfo == NULL) {\r
-        Status = EFI_OUT_OF_RESOURCES;\r
-        goto ON_ERROR;\r
-      }\r
-      //\r
-      // Get the interface info.\r
-      //\r
-      if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
-        Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
-                           IpXCfg,\r
-                           Ip6ConfigDataTypeInterfaceInfo,\r
-                           &IfInfoSize,\r
-                           IpXInterfaceInfo\r
-                           );\r
-      } else {\r
-        Status = ((EFI_IP4_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
-                           IpXCfg,\r
-                           &IfInfoSize,\r
-                           IpXInterfaceInfo\r
-                           );\r
-      }\r
+    if (IpXInterfaceInfo == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_ERROR;\r
+    }\r
+    //\r
+    // Get the interface info.\r
+    //\r
+    if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
+      Status = ((EFI_IP6_CONFIG_PROTOCOL*)IpXCfg)->GetData (\r
+                         IpXCfg,\r
+                         Ip6ConfigDataTypeInterfaceInfo,\r
+                         &IfInfoSize,\r
+                         IpXInterfaceInfo\r
+                         );\r
+    } else {\r
+      Status = ((EFI_IP4_CONFIG2_PROTOCOL*)IpXCfg)->GetData (\r
+                         IpXCfg,\r
+                         Ip4Config2DataTypeInterfaceInfo,\r
+                         &IfInfoSize,\r
+                         IpXInterfaceInfo\r
+                         );\r
+    }\r
 \r
-      if (EFI_ERROR (Status)) {\r
-        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
-        goto ON_ERROR;\r
-      }\r
-      //\r
-      // Check whether the source address is one of the interface addresses.\r
-      //\r
-      if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
-        for (AddrIndex = 0; AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount; AddrIndex++) {\r
+    if (EFI_ERROR (Status)) {\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_GETDATA), gShellNetwork1HiiHandle, Status);\r
+      goto ON_ERROR;\r
+    }\r
+    //\r
+    // Check whether the source address is one of the interface addresses.\r
+    //\r
+    if (Private->IpChoice == PING_IP_CHOICE_IP6) {\r
+      for (AddrIndex = 0; AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount; AddrIndex++) {\r
+        Addr = &(((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfo[AddrIndex].Address);\r
 \r
-          Addr = &(((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfo[AddrIndex].Address);\r
-          if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
+        if (UnspecifiedSrc) {\r
+          if (!NetIp6IsUnspecifiedAddr (Addr) && !NetIp6IsLinkLocalAddr (Addr)) {\r
             //\r
-            // Match a certain interface address.\r
+            // Select the interface automatically.\r
             //\r
+            CopyMem(&Private->SrcAddress, Addr, sizeof(Private->SrcAddress));\r
             break;\r
           }\r
-        }\r
-\r
-        if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount) {\r
+        } else if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) {\r
           //\r
-          // Found a nic handle with right interface address.\r
+          // Match a certain interface address.\r
           //\r
           break;\r
         }\r
-      } else {\r
+      }\r
+\r
+      if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount) {\r
         //\r
-        // IP4 address check\r
+        // Found a nic handle with right interface address.\r
         //\r
-        if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_IPCONFIG_DATA*)IpXInterfaceInfo)->StationAddress)) {\r
+        break;\r
+      }\r
+    } else {\r
+      if (UnspecifiedSrc) {\r
+        if (!PingNetIp4IsUnspecifiedAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress) && \r
+            !PingNetIp4IsLinkLocalAddr (&((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress)) {\r
           //\r
-          // Match a certain interface address.\r
+          // Select the interface automatically.\r
           //\r
           break;\r
         }\r
+      } else if (EFI_IP4_EQUAL (&Private->SrcAddress, &((EFI_IP4_CONFIG2_INTERFACE_INFO*)IpXInterfaceInfo)->StationAddress)) {\r
+        //\r
+        // Match a certain interface address.\r
+        //\r
+        break;\r
       }\r
     }\r
 \r
@@ -1045,7 +1180,7 @@ PingCreateIpInstance (
   //\r
 \r
   if (HandleIndex == HandleNum) {\r
-    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, mSrcString);\r
+    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_CONFIGD_NIC_NF), gShellNetwork1HiiHandle, L"ping");  \r
     Status = EFI_NOT_FOUND;\r
     goto ON_ERROR;\r
   }\r
@@ -1120,11 +1255,6 @@ PingCreateIpInstance (
     //\r
     // Configure the ip4 instance for icmp4 packet exchange.\r
     //\r
-//    PING_IP4_COPY_ADDRESS (&Ip4Config.StationAddress,     &Private->SrcAddress);\r
-//    Ip4Config.SubnetMask.Addr[0] = 0xFF;\r
-//    Ip4Config.SubnetMask.Addr[1] = 0xFF;\r
-//    Ip4Config.SubnetMask.Addr[2] = 0xFF;\r
-//    Ip4Config.SubnetMask.Addr[3] = 0x00;\r
     Ip4Config.DefaultProtocol   = 1;\r
     Ip4Config.AcceptAnyProtocol = FALSE;\r
     Ip4Config.AcceptBroadcast   = FALSE;\r
@@ -1174,14 +1304,13 @@ ON_ERROR:
 }\r
 \r
 /**\r
-  Destory the IP instance.\r
+  Destroy the IP instance.\r
 \r
   @param[in]    Private    The pointer of PING_PRIVATE_DATA.\r
 \r
 **/\r
 VOID\r
-EFIAPI\r
-Ping6DestoryIp6Instance (\r
+Ping6DestroyIp6Instance (\r
   IN PING_PRIVATE_DATA    *Private\r
   )\r
 {\r
@@ -1206,6 +1335,7 @@ Ping6DestoryIp6Instance (
   }\r
 }\r
 \r
+\r
 /**\r
   The Ping Process.\r
 \r
@@ -1219,7 +1349,6 @@ Ping6DestoryIp6Instance (
   @retval others         The ping processed unsuccessfully.\r
 **/\r
 SHELL_STATUS\r
-EFIAPI\r
 ShellPing (\r
   IN UINT32              SendNumber,\r
   IN UINT32              BufferSize,\r
@@ -1291,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
@@ -1305,7 +1444,7 @@ ShellPing (
     } else if (Status == RETURN_NO_MAPPING) {\r
       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NOROUTE_FOUND), gShellNetwork1HiiHandle, mDstString, mSrcString);\r
     } else {\r
-      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, Status);\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING_NETWORK_ERROR), gShellNetwork1HiiHandle, L"ping", Status);  \r
     }\r
 \r
     goto ON_EXIT;\r
@@ -1351,13 +1490,13 @@ ON_STAT:
       STRING_TOKEN (STR_PING_STAT),\r
       gShellNetwork1HiiHandle,\r
       Private->TxCount,\r
-      Private->RxCount,\r
-      (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount,\r
+      (Private->RxCount - Private->FailedCount),\r
+      (100 - ((100 * (Private->RxCount - Private->FailedCount)) / Private->TxCount)),\r
       Private->RttSum\r
       );\r
   }\r
 \r
-  if (Private->RxCount != 0) {\r
+  if (Private->RxCount > Private->FailedCount) {\r
     ShellPrintHiiEx (\r
       -1,\r
       -1,\r
@@ -1365,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, 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
@@ -1385,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
@@ -1398,7 +1542,7 @@ ON_EXIT:
     }\r
 \r
     if (Private->IpChildHandle != NULL) {\r
-      Ping6DestoryIp6Instance (Private);\r
+      Ping6DestroyIp6Instance (Private);\r
     }\r
 \r
     FreePool (Private);\r
@@ -1412,6 +1556,10 @@ ON_EXIT:
 \r
   @param[in] ImageHandle  Handle to the Image (NULL if Internal).\r
   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).\r
+\r
+  @retval SHELL_SUCCESS  The ping processed successfullly.\r
+  @retval others         The ping processed unsuccessfully.\r
+  \r
 **/\r
 SHELL_STATUS\r
 EFIAPI\r
@@ -1430,6 +1578,7 @@ ShellCommandRunPing (
   CONST CHAR16        *ValueStr;\r
   UINTN               NonOptionCount;\r
   UINT32              IpChoice;\r
+  CHAR16              *ProblemParam;\r
 \r
   //\r
   // we use IPv6 buffers to hold items... \r
@@ -1441,10 +1590,11 @@ ShellCommandRunPing (
   IpChoice = PING_IP_CHOICE_IP4;\r
 \r
   ShellStatus = SHELL_SUCCESS;\r
+  ProblemParam = NULL;\r
 \r
-  Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, NULL, TRUE, FALSE);\r
+  Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);\r
   if (EFI_ERROR(Status)) {\r
-    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle);\r
+    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ProblemParam);\r
     ShellStatus = SHELL_INVALID_PARAMETER;\r
     goto ON_EXIT;\r
   }\r
@@ -1454,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
@@ -1464,7 +1614,7 @@ ShellCommandRunPing (
     // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
     //\r
     if ((SendNumber == 0) || (SendNumber > MAX_SEND_NUMBER)) {\r
-      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr);\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);  \r
       ShellStatus = SHELL_INVALID_PARAMETER;\r
       goto ON_EXIT;\r
     }\r
@@ -1472,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
@@ -1482,7 +1632,7 @@ ShellCommandRunPing (
     // ShellStrToUintn will return 0 when input is 0 or an invalid input string.\r
     //\r
     if ((BufferSize < 16) || (BufferSize > MAX_BUFFER_SIZE)) {\r
-      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr);\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);  \r
       ShellStatus = SHELL_INVALID_PARAMETER;\r
       goto ON_EXIT;\r
     }\r
@@ -1494,9 +1644,13 @@ 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
+  ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");\r
+  if (ValueStr == NULL) {\r
+    ValueStr = ShellCommandLineGetValue (ParamPackage, L"-_s");\r
+  }\r
+  \r
   if (ValueStr != NULL) {\r
     mSrcString = ValueStr;\r
     if (IpChoice == PING_IP_CHOICE_IP6) {\r
@@ -1505,22 +1659,22 @@ ShellCommandRunPing (
       Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&SrcAddress);\r
     }\r
     if (EFI_ERROR (Status)) {\r
-      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr);\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);  \r
       ShellStatus = SHELL_INVALID_PARAMETER;\r
       goto ON_EXIT;\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
   if (NonOptionCount < 2) {\r
-    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle);\r
+    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellNetwork1HiiHandle, L"ping");  \r
     ShellStatus = SHELL_INVALID_PARAMETER;\r
     goto ON_EXIT;\r
   }\r
   if (NonOptionCount > 2) {\r
-    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle);\r
+    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellNetwork1HiiHandle, L"ping");  \r
     ShellStatus = SHELL_INVALID_PARAMETER;\r
     goto ON_EXIT;\r
   }\r
@@ -1533,19 +1687,12 @@ ShellCommandRunPing (
       Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&DstAddress);\r
     }\r
     if (EFI_ERROR (Status)) {\r
-      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellNetwork1HiiHandle, ValueStr);\r
+      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ping", ValueStr);  \r
       ShellStatus = SHELL_INVALID_PARAMETER;\r
       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