]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/DxeNetLib/DxeNetLib.c
For network dynamic media support:
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / DxeNetLib.c
index d89ac6483dbbbda60c7d3590ddfb1bb3cf8818e5..5037243b37407a5cab8171824187b7e49ff65394 100644 (file)
@@ -2145,6 +2145,213 @@ NetLibGetMacString (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Detect media status for specified network device.\r
+\r
+  The underlying UNDI driver may or may not support reporting media status from\r
+  GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine\r
+  will try to invoke Snp->GetStatus() to get the media status: if media already\r
+  present, it return directly; if media not present, it will stop SNP and then\r
+  restart SNP to get the latest media status, this give chance to get the correct\r
+  media status for old UNDI driver which doesn't support reporting media status\r
+  from GET_STATUS command.\r
+  Note: there will be two limitations for current algorithm:\r
+  1) for UNDI with this capability, in case of cable is not attached, there will\r
+     be an redundant Stop/Start() process;\r
+  2) for UNDI without this capability, in case cable is attached in UNDI\r
+     initialize while unattached latter, NetLibDetectMedia() will report\r
+     MediaPresent as TRUE, this cause upper layer apps wait for timeout time.\r
+\r
+  @param[in]   ServiceHandle    The handle where network service binding protocols are\r
+                                installed on.\r
+  @param[out]  MediaPresent     The pointer to store the media status.\r
+\r
+  @retval EFI_SUCCESS           Media detection success.\r
+  @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.\r
+  @retval EFI_UNSUPPORTED       Network device does not support media detection.\r
+  @retval EFI_DEVICE_ERROR      SNP is in unknown state.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NetLibDetectMedia (\r
+  IN  EFI_HANDLE            ServiceHandle,\r
+  OUT BOOLEAN               *MediaPresent\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_HANDLE                   SnpHandle;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;\r
+  UINT32                       InterruptStatus;\r
+  UINT32                       OldState;\r
+  EFI_MAC_ADDRESS              *MCastFilter;\r
+  UINT32                       MCastFilterCount;\r
+  UINT32                       EnableFilterBits;\r
+  UINT32                       DisableFilterBits;\r
+  BOOLEAN                      ResetMCastFilters;\r
+\r
+  ASSERT (MediaPresent != NULL);\r
+\r
+  //\r
+  // Get SNP handle\r
+  //\r
+  Snp = NULL;\r
+  SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);\r
+  if (SnpHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether SNP support media detection\r
+  //\r
+  if (!Snp->Mode->MediaPresentSupported) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data\r
+  //\r
+  Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Snp->Mode->MediaPresent) {\r
+    //\r
+    // Media is present, return directly\r
+    //\r
+    *MediaPresent = TRUE;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Till now, GetStatus() report no media; while, in case UNDI not support\r
+  // reporting media status from GetStatus(), this media status may be incorrect.\r
+  // So, we will stop SNP and then restart it to get the correct media status.\r
+  //\r
+  OldState = Snp->Mode->State;\r
+  if (OldState >= EfiSimpleNetworkMaxState) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  MCastFilter = NULL;\r
+\r
+  if (OldState == EfiSimpleNetworkInitialized) {\r
+    //\r
+    // SNP is already in use, need Shutdown/Stop and then Start/Initialize\r
+    //\r
+\r
+    //\r
+    // Backup current SNP receive filter settings\r
+    //\r
+    EnableFilterBits  = Snp->Mode->ReceiveFilterSetting;\r
+    DisableFilterBits = Snp->Mode->ReceiveFilterMask ^ EnableFilterBits;\r
+\r
+    ResetMCastFilters = TRUE;\r
+    MCastFilterCount  = Snp->Mode->MCastFilterCount;\r
+    if (MCastFilterCount != 0) {\r
+      MCastFilter = AllocateCopyPool (\r
+                      MCastFilterCount * sizeof (EFI_MAC_ADDRESS),\r
+                      Snp->Mode->MCastFilter\r
+                      );\r
+      ASSERT (MCastFilter != NULL);\r
+\r
+      ResetMCastFilters = FALSE;\r
+    }\r
+\r
+    //\r
+    // Shutdown/Stop the simple network\r
+    //\r
+    Status = Snp->Shutdown (Snp);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = Snp->Stop (Snp);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // Start/Initialize the simple network\r
+    //\r
+    Status = Snp->Start (Snp);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = Snp->Initialize (Snp, 0, 0);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // Here we get the correct media status\r
+    //\r
+    *MediaPresent = Snp->Mode->MediaPresent;\r
+\r
+    //\r
+    // Restore SNP receive filter settings\r
+    //\r
+    Status = Snp->ReceiveFilters (\r
+                    Snp,\r
+                    EnableFilterBits,\r
+                    DisableFilterBits,\r
+                    ResetMCastFilters,\r
+                    MCastFilterCount,\r
+                    MCastFilter\r
+                    );\r
+\r
+    if (MCastFilter != NULL) {\r
+      FreePool (MCastFilter);\r
+    }\r
+\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted\r
+  //\r
+  if (OldState == EfiSimpleNetworkStopped) {\r
+    //\r
+    // SNP not start yet, start it\r
+    //\r
+    Status = Snp->Start (Snp);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Initialize the simple network\r
+  //\r
+  Status = Snp->Initialize (Snp, 0, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Here we get the correct media status\r
+  //\r
+  *MediaPresent = Snp->Mode->MediaPresent;\r
+\r
+  //\r
+  // Shut down the simple network\r
+  //\r
+  Snp->Shutdown (Snp);\r
+\r
+Exit:\r
+  if (OldState == EfiSimpleNetworkStopped) {\r
+    //\r
+    // Original SNP sate is Stopped, restore to original state\r
+    //\r
+    Snp->Stop (Snp);\r
+  }\r
+\r
+  if (MCastFilter != NULL) {\r
+    FreePool (MCastFilter);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Check the default address used by the IPv4 driver is static or dynamic (acquired\r
   from DHCP).\r
@@ -2417,7 +2624,7 @@ NetLibGetNicHandle (
   @param[in]      String         The pointer to the Ascii string.\r
   @param[out]     Ip4Address     The pointer to the converted IPv4 address.\r
 \r
-  @retval EFI_SUCCESS            Convert to IPv4 address successfully.  \r
+  @retval EFI_SUCCESS            Convert to IPv4 address successfully.\r
   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip4Address is NULL.\r
 \r
 **/\r
@@ -2460,7 +2667,7 @@ NetLibAsciiStrToIp4 (
 \r
     //\r
     // Convert the string to IPv4 address. AsciiStrDecimalToUintn stops at the\r
-    // first character that is not a valid decimal character, '.' or '\0' here. \r
+    // first character that is not a valid decimal character, '.' or '\0' here.\r
     //\r
     NodeVal = AsciiStrDecimalToUintn (TempStr);\r
     if (NodeVal > 0xFF) {\r
@@ -2483,7 +2690,7 @@ NetLibAsciiStrToIp4 (
   @param[in]      String         The pointer to the Ascii string.\r
   @param[out]     Ip6Address     The pointer to the converted IPv6 address.\r
 \r
-  @retval EFI_SUCCESS            Convert to IPv6 address successfully.  \r
+  @retval EFI_SUCCESS            Convert to IPv6 address successfully.\r
   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.\r
 \r
 **/\r
@@ -2519,7 +2726,7 @@ NetLibAsciiStrToIp6 (
       return EFI_INVALID_PARAMETER;\r
     } else {\r
       AllowedCnt = 7;\r
-    }    \r
+    }\r
   }\r
 \r
   ZeroMem (Ip6Address, sizeof (EFI_IPv6_ADDRESS));\r
@@ -2547,7 +2754,7 @@ NetLibAsciiStrToIp6 (
           // ::0 looks strange. report error to user.\r
           //\r
           return EFI_INVALID_PARAMETER;\r
-        }           \r
+        }\r
 \r
         //\r
         // Skip the abbreviation part of IPv6 address.\r
@@ -2561,7 +2768,7 @@ NetLibAsciiStrToIp6 (
               //\r
               return EFI_INVALID_PARAMETER;\r
             }\r
-            \r
+\r
             TailNodeCnt++;\r
             if (TailNodeCnt >= (AllowedCnt - NodeCnt)) {\r
               //\r
@@ -2572,7 +2779,7 @@ NetLibAsciiStrToIp6 (
           }\r
 \r
           TempStr2++;\r
-        }       \r
+        }\r
 \r
         Short  = TRUE;\r
         Update = TRUE;\r
@@ -2587,12 +2794,12 @@ NetLibAsciiStrToIp6 (
           //\r
           return EFI_INVALID_PARAMETER;\r
         }\r
-      }      \r
-    }    \r
+      }\r
+    }\r
 \r
     //\r
     // Convert the string to IPv6 address. AsciiStrHexToUintn stops at the first\r
-    // character that is not a valid hexadecimal character, ':' or '\0' here. \r
+    // character that is not a valid hexadecimal character, ':' or '\0' here.\r
     //\r
     NodeVal = AsciiStrHexToUintn (TempStr);\r
     if ((NodeVal > 0xFFFF) || (Index > 14)) {\r
@@ -2625,7 +2832,7 @@ NetLibAsciiStrToIp6 (
   @param[in]      String         The pointer to the Ascii string.\r
   @param[out]     Ip4Address     The pointer to the converted IPv4 address.\r
 \r
-  @retval EFI_SUCCESS            Convert to IPv4 address successfully.  \r
+  @retval EFI_SUCCESS            Convert to IPv4 address successfully.\r
   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip4Address is NULL.\r
   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.\r
 \r
@@ -2638,7 +2845,7 @@ NetLibStrToIp4 (
 {\r
   CHAR8                          *Ip4Str;\r
   EFI_STATUS                     Status;\r
-  \r
+\r
   if ((String == NULL) || (Ip4Address == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -2665,7 +2872,7 @@ NetLibStrToIp4 (
   @param[in]      String         The pointer to the Ascii string.\r
   @param[out]     Ip6Address     The pointer to the converted IPv6 address.\r
 \r
-  @retval EFI_SUCCESS            Convert to IPv6 address successfully.  \r
+  @retval EFI_SUCCESS            Convert to IPv6 address successfully.\r
   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.\r
   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.\r
 \r
@@ -2674,11 +2881,11 @@ EFI_STATUS
 NetLibStrToIp6 (\r
   IN CONST CHAR16                *String,\r
   OUT      EFI_IPv6_ADDRESS      *Ip6Address\r
-  ) \r
+  )\r
 {\r
   CHAR8                          *Ip6Str;\r
   EFI_STATUS                     Status;\r
-  \r
+\r
   if ((String == NULL) || (Ip6Address == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -2706,7 +2913,7 @@ NetLibStrToIp6 (
   @param[out]     Ip6Address     The pointer to the converted IPv6 address.\r
   @param[out]     PrefixLength   The pointer to the converted prefix length.\r
 \r
-  @retval EFI_SUCCESS            Convert to IPv6 address successfully.  \r
+  @retval EFI_SUCCESS            Convert to IPv6 address successfully.\r
   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.\r
   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.\r
 \r
@@ -2716,14 +2923,14 @@ NetLibStrToIp6andPrefix (
   IN CONST CHAR16                *String,\r
   OUT      EFI_IPv6_ADDRESS      *Ip6Address,\r
   OUT      UINT8                 *PrefixLength\r
-  ) \r
+  )\r
 {\r
-  CHAR8                          *Ip6Str;  \r
+  CHAR8                          *Ip6Str;\r
   CHAR8                          *PrefixStr;\r
   CHAR8                          *TempStr;\r
   EFI_STATUS                     Status;\r
   UINT8                          Length;\r
-  \r
+\r
   if ((String == NULL) || (Ip6Address == NULL) || (PrefixLength == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -2759,14 +2966,18 @@ NetLibStrToIp6andPrefix (
     goto Exit;\r
   }\r
 \r
+  //\r
+  // If input string doesn't indicate the prefix length, return 0xff.\r
+  //\r
+  Length = 0xFF;\r
+  \r
   //\r
   // Convert the string to prefix length\r
   //\r
-  Length = 0;\r
   if (PrefixStr != NULL) {\r
 \r
     Status = EFI_INVALID_PARAMETER;\r
-\r
+    Length = 0;\r
     while (*PrefixStr != '\0') {\r
       if (NET_IS_DIGIT (*PrefixStr)) {\r
         Length = (UINT8) (Length * 10 + (*PrefixStr - '0'));\r