]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellNetwork1CommandsLib/Ping.c
ShellPkg:Ping: Ping command hangs with intermittent packet losses
[mirror_edk2.git] / ShellPkg / Library / UefiShellNetwork1CommandsLib / Ping.c
index 7982f99c579cb05b22e5c3299f81a0f79515ed47..e2dc76570ac9dff957e887e036cb9d5a3f5b80b8 100644 (file)
@@ -1,7 +1,9 @@
 /** @file\r
   The implementation for Ping shell command.\r
 \r
 /** @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 - 2016, 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
 \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
 \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
 \r
 //\r
 // Function templates to match the IPv4 and IPv6 commands that we use.\r
@@ -132,31 +135,24 @@ 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
   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
 } 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
 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
 {\r
   UINT32  Sum;\r
   UINT8   Odd;\r
@@ -167,11 +163,11 @@ Returns:
   Sum     = 0;\r
   Odd     = (UINT8) (Length & 1);\r
   Length >>= 1;\r
   Sum     = 0;\r
   Odd     = (UINT8) (Length & 1);\r
   Length >>= 1;\r
-  while (Length--) {\r
+  while ((Length--) != 0) {\r
     Sum += *Packet++;\r
   }\r
 \r
     Sum += *Packet++;\r
   }\r
 \r
-  if (Odd) {\r
+  if (Odd != 0) {\r
     Sum += *(UINT8 *) Packet;\r
   }\r
 \r
     Sum += *(UINT8 *) Packet;\r
   }\r
 \r
@@ -193,11 +189,6 @@ Returns:
   @return The current value of the register.\r
 \r
 **/\r
   @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
 \r
 STATIC CONST SHELL_PARAM_ITEM    PingParamList[] = {\r
   {\r
@@ -208,6 +199,10 @@ STATIC CONST SHELL_PARAM_ITEM    PingParamList[] = {
     L"-n",\r
     TypeValue\r
   },\r
     L"-n",\r
     TypeValue\r
   },\r
+  {\r
+    L"-s",\r
+    TypeValue\r
+  },\r
   {\r
     L"-_s",\r
     TypeValue\r
   {\r
     L"-_s",\r
     TypeValue\r
@@ -228,13 +223,43 @@ STATIC CONST SHELL_PARAM_ITEM    PingParamList[] = {
 STATIC CONST CHAR16      *mDstString;\r
 STATIC CONST CHAR16      *mSrcString;\r
 STATIC UINT64            mFrequency = 0;\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
 \r
 /**\r
-  Get and caculate the frequency in tick/ms.\r
-  The result is saved in the globle variable mFrequency\r
+  Read the current time.\r
+\r
+  @retval the current tick value.\r
+**/\r
+UINT64\r
+EFIAPI\r
+ReadTime (\r
+  VOID\r
+  )\r
+{\r
+  UINT64                 TimerPeriod;\r
+  EFI_STATUS             Status;\r
 \r
 \r
-  @retval EFI_SUCCESS    Caculated the frequency successfully.\r
-  @retval Others         Failed to caculate the frequency.\r
+  ASSERT (gCpu != NULL);\r
+\r
+  Status = gCpu->GetTimerValue (gCpu, 0, &mCurrentTick, &TimerPeriod);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the\r
+    // TimerPeriod by ourselves.\r
+    //\r
+    mCurrentTick += 1000000;\r
+  }\r
+  \r
+  return mCurrentTick;\r
+}\r
+\r
+\r
+/**\r
+  Get and calculate the frequency in ticks/ms.\r
+  The result is saved in the global variable mFrequency\r
+\r
+  @retval EFI_SUCCESS    Calculated the frequency successfully.\r
+  @retval Others         Failed to calculate the frequency.\r
 \r
 **/\r
 EFI_STATUS\r
 \r
 **/\r
 EFI_STATUS\r
@@ -244,17 +269,15 @@ GetFrequency (
   )\r
 {\r
   EFI_STATUS               Status;\r
   )\r
 {\r
   EFI_STATUS               Status;\r
-  EFI_CPU_ARCH_PROTOCOL    *Cpu;\r
   UINT64                   CurrentTick;\r
   UINT64                   TimerPeriod;\r
 \r
   UINT64                   CurrentTick;\r
   UINT64                   TimerPeriod;\r
 \r
-  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu);\r
-\r
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &gCpu);\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
+  Status = gCpu->GetTimerValue (gCpu, 0, &CurrentTick, &TimerPeriod);\r
 \r
   if (EFI_ERROR (Status)) {\r
     TimerPeriod = DEFAULT_TIMER_PERIOD;\r
 \r
   if (EFI_ERROR (Status)) {\r
     TimerPeriod = DEFAULT_TIMER_PERIOD;\r
@@ -262,7 +285,7 @@ GetFrequency (
 \r
   //\r
   // The timer period is in femtosecond (1 femtosecond is 1e-15 second).\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
+  // So 1e+12 is divided by timer period to produce the freq in ticks/ms.\r
   //\r
   mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL);\r
 \r
   //\r
   mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL);\r
 \r
@@ -270,7 +293,7 @@ GetFrequency (
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
-  Caculate a duration in ms.\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
 \r
   @param[in]  Begin     The start point of time.\r
   @param[in]  End       The end point of time.\r
@@ -581,7 +604,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
   //\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
   Request->Identifier  = 0;\r
   Request->Checksum    = 0;\r
 \r
@@ -589,6 +612,7 @@ PingGenerateToken (
   // Assembly token for transmit.\r
   //\r
   if (Private->IpChoice==PING_IP_CHOICE_IP6) {\r
   // 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
     ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrsLength                   = 0;\r
     ((EFI_IP6_TRANSMIT_DATA*)TxData)->ExtHdrs                         = NULL;\r
     ((EFI_IP6_TRANSMIT_DATA*)TxData)->OverrideData                    = 0;\r
@@ -787,10 +811,8 @@ Ping6OnTimerRoutine (
       RemoveEntryList (&TxInfo->Link);\r
       PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
 \r
       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->RxCount++;\r
+      Private->FailedCount++;\r
 \r
       if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
         //\r
 \r
       if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
         //\r
@@ -859,6 +881,8 @@ PingCreateIpInstance (
   UINTN                            HandleIndex;\r
   UINTN                            HandleNum;\r
   EFI_HANDLE                       *HandleBuffer;\r
   UINTN                            HandleIndex;\r
   UINTN                            HandleNum;\r
   EFI_HANDLE                       *HandleBuffer;\r
+  BOOLEAN                          UnspecifiedSrc;\r
+  BOOLEAN                          MediaPresent;\r
   EFI_SERVICE_BINDING_PROTOCOL     *EfiSb;\r
   VOID                             *IpXCfg;\r
   EFI_IP6_CONFIG_DATA              Ip6Config;\r
   EFI_SERVICE_BINDING_PROTOCOL     *EfiSb;\r
   VOID                             *IpXCfg;\r
   EFI_IP6_CONFIG_DATA              Ip6Config;\r
@@ -869,6 +893,8 @@ PingCreateIpInstance (
   UINTN                            AddrIndex;\r
 \r
   HandleBuffer      = NULL;\r
   UINTN                            AddrIndex;\r
 \r
   HandleBuffer      = NULL;\r
+  UnspecifiedSrc    = FALSE;\r
+  MediaPresent      = TRUE;\r
   EfiSb             = NULL;\r
   IpXInterfaceInfo  = NULL;\r
   IfInfoSize        = 0;\r
   EfiSb             = NULL;\r
   IpXInterfaceInfo  = NULL;\r
   IfInfoSize        = 0;\r
@@ -886,37 +912,54 @@ PingCreateIpInstance (
   if (EFI_ERROR (Status) || (HandleNum == 0) || (HandleBuffer == NULL)) {\r
     return EFI_ABORTED;\r
   }\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
   //\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
   //\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
       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
       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
   // 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
     EfiSb             = NULL;\r
     IpXInterfaceInfo  = NULL;\r
     IfInfoSize        = 0;\r
 \r
+    if (UnspecifiedSrc) {\r
+      //\r
+      // Check media.\r
+      //\r
+      NetLibDetectMedia (HandleBuffer[HandleIndex], &MediaPresent);\r
+      if (!MediaPresent) {\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
     Status = gBS->HandleProtocol (\r
                     HandleBuffer[HandleIndex],\r
                     Private->IpChoice == PING_IP_CHOICE_IP6?&gEfiIp6ServiceBindingProtocolGuid:&gEfiIp4ServiceBindingProtocolGuid,\r
@@ -926,114 +969,122 @@ PingCreateIpInstance (
       goto ON_ERROR;\r
     }\r
 \r
       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
 \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
 \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
 \r
-      IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);\r
+    IpXInterfaceInfo = AllocateZeroPool (IfInfoSize);\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_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
 \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
 \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
             //\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 < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->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
           //\r
           break;\r
         }\r
-      } else {\r
+      }\r
+\r
+      if (AddrIndex < ((EFI_IP6_CONFIG_INTERFACE_INFO*)IpXInterfaceInfo)->AddressInfoCount) {\r
         //\r
         //\r
-        // IP4 address check\r
+        // Found a nic handle with right interface address.\r
         //\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
           //\r
-          // Match a certain interface address.\r
+          // Select the interface automatically.\r
           //\r
           break;\r
         }\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
       }\r
     }\r
 \r
@@ -1045,7 +1096,7 @@ PingCreateIpInstance (
   //\r
 \r
   if (HandleIndex == HandleNum) {\r
   //\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
     Status = EFI_NOT_FOUND;\r
     goto ON_ERROR;\r
   }\r
@@ -1120,11 +1171,6 @@ PingCreateIpInstance (
     //\r
     // Configure the ip4 instance for icmp4 packet exchange.\r
     //\r
     //\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
     Ip4Config.DefaultProtocol   = 1;\r
     Ip4Config.AcceptAnyProtocol = FALSE;\r
     Ip4Config.AcceptBroadcast   = FALSE;\r
@@ -1174,14 +1220,14 @@ ON_ERROR:
 }\r
 \r
 /**\r
 }\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
 \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
   IN PING_PRIVATE_DATA    *Private\r
   )\r
 {\r
@@ -1305,7 +1351,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
     } 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
     }\r
 \r
     goto ON_EXIT;\r
@@ -1351,13 +1397,13 @@ ON_STAT:
       STRING_TOKEN (STR_PING_STAT),\r
       gShellNetwork1HiiHandle,\r
       Private->TxCount,\r
       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
       Private->RttSum\r
       );\r
   }\r
 \r
-  if (Private->RxCount != 0) {\r
+  if (Private->RxCount > Private->FailedCount) {\r
     ShellPrintHiiEx (\r
       -1,\r
       -1,\r
     ShellPrintHiiEx (\r
       -1,\r
       -1,\r
@@ -1366,7 +1412,7 @@ ON_STAT:
       gShellNetwork1HiiHandle,\r
       Private->RttMin,\r
       Private->RttMax,\r
       gShellNetwork1HiiHandle,\r
       Private->RttMin,\r
       Private->RttMax,\r
-      DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL)\r
+      DivU64x64Remainder (Private->RttSum, (Private->RxCount - Private->FailedCount), NULL)\r
       );\r
   }\r
 \r
       );\r
   }\r
 \r
@@ -1398,7 +1444,7 @@ ON_EXIT:
     }\r
 \r
     if (Private->IpChildHandle != NULL) {\r
     }\r
 \r
     if (Private->IpChildHandle != NULL) {\r
-      Ping6DestoryIp6Instance (Private);\r
+      Ping6DestroyIp6Instance (Private);\r
     }\r
 \r
     FreePool (Private);\r
     }\r
 \r
     FreePool (Private);\r
@@ -1412,6 +1458,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
   @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
 **/\r
 SHELL_STATUS\r
 EFIAPI\r
@@ -1430,6 +1480,7 @@ ShellCommandRunPing (
   CONST CHAR16        *ValueStr;\r
   UINTN               NonOptionCount;\r
   UINT32              IpChoice;\r
   CONST CHAR16        *ValueStr;\r
   UINTN               NonOptionCount;\r
   UINT32              IpChoice;\r
+  CHAR16              *ProblemParam;\r
 \r
   //\r
   // we use IPv6 buffers to hold items... \r
 \r
   //\r
   // we use IPv6 buffers to hold items... \r
@@ -1441,10 +1492,11 @@ ShellCommandRunPing (
   IpChoice = PING_IP_CHOICE_IP4;\r
 \r
   ShellStatus = SHELL_SUCCESS;\r
   IpChoice = PING_IP_CHOICE_IP4;\r
 \r
   ShellStatus = SHELL_SUCCESS;\r
+  ProblemParam = NULL;\r
 \r
 \r
-  Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, NULL, TRUE, FALSE);\r
+  Status = ShellCommandLineParseEx (PingParamList, &ParamPackage, &ProblemParam, TRUE, FALSE);\r
   if (EFI_ERROR(Status)) {\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
     ShellStatus = SHELL_INVALID_PARAMETER;\r
     goto ON_EXIT;\r
   }\r
@@ -1464,7 +1516,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
     // 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
       ShellStatus = SHELL_INVALID_PARAMETER;\r
       goto ON_EXIT;\r
     }\r
@@ -1482,7 +1534,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
     // 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
       ShellStatus = SHELL_INVALID_PARAMETER;\r
       goto ON_EXIT;\r
     }\r
@@ -1496,7 +1548,11 @@ ShellCommandRunPing (
   //\r
   // Parse the paramter of source ip address.\r
   //\r
   //\r
   // Parse the paramter 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
   if (ValueStr != NULL) {\r
     mSrcString = ValueStr;\r
     if (IpChoice == PING_IP_CHOICE_IP6) {\r
@@ -1505,7 +1561,7 @@ ShellCommandRunPing (
       Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&SrcAddress);\r
     }\r
     if (EFI_ERROR (Status)) {\r
       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
       ShellStatus = SHELL_INVALID_PARAMETER;\r
       goto ON_EXIT;\r
     }\r
@@ -1515,12 +1571,12 @@ ShellCommandRunPing (
   //\r
   NonOptionCount = ShellCommandLineGetCount(ParamPackage);\r
   if (NonOptionCount < 2) {\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
     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
     ShellStatus = SHELL_INVALID_PARAMETER;\r
     goto ON_EXIT;\r
   }\r
@@ -1533,7 +1589,7 @@ ShellCommandRunPing (
       Status = NetLibStrToIp4 (ValueStr, (EFI_IPv4_ADDRESS*)&DstAddress);\r
     }\r
     if (EFI_ERROR (Status)) {\r
       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
       ShellStatus = SHELL_INVALID_PARAMETER;\r
       goto ON_EXIT;\r
     }\r