]> 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 dbee764b64eb1230b7c6eb80e54f4bc6be727321..e2dc76570ac9dff957e887e036cb9d5a3f5b80b8 100644 (file)
@@ -2,7 +2,8 @@
   The implementation for Ping shell command.\r
 \r
   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
-  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<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
@@ -134,6 +135,7 @@ 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
@@ -197,6 +199,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
@@ -805,6 +811,9 @@ Ping6OnTimerRoutine (
       RemoveEntryList (&TxInfo->Link);\r
       PingDestroyTxInfo (TxInfo, Private->IpChoice);\r
 \r
+      Private->RxCount++;\r
+      Private->FailedCount++;\r
+\r
       if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) {\r
         //\r
         // All the left icmp6 echo request in the list timeout.\r
@@ -872,6 +881,8 @@ PingCreateIpInstance (
   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
@@ -882,6 +893,8 @@ PingCreateIpInstance (
   UINTN                            AddrIndex;\r
 \r
   HandleBuffer      = NULL;\r
+  UnspecifiedSrc    = FALSE;\r
+  MediaPresent      = TRUE;\r
   EfiSb             = NULL;\r
   IpXInterfaceInfo  = NULL;\r
   IfInfoSize        = 0;\r
@@ -899,37 +912,54 @@ PingCreateIpInstance (
   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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", 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_PARAM_INV), gShellNetwork1HiiHandle, L"ping", 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
+      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
@@ -939,116 +969,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:&gEfiIp4Config2ProtocolGuid,\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_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
+    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_CONFIG2_PROTOCOL*)IpXCfg)->GetData (\r
-                           IpXCfg,\r
-                           Ip4Config2DataTypeInterfaceInfo,\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_CONFIG2_INTERFACE_INFO*)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
@@ -1361,13 +1397,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
@@ -1376,7 +1412,7 @@ ON_STAT:
       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
@@ -1512,7 +1548,11 @@ ShellCommandRunPing (
   //\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