+ EFI_STATUS Status;\r
+ EFI_HANDLE SnpHandle;\r
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+ EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;\r
+ EFI_ADAPTER_INFO_MEDIA_STATE *MediaInfo;\r
+ BOOLEAN MediaPresent;\r
+ UINTN DataSize;\r
+ EFI_STATUS TimerStatus;\r
+ EFI_EVENT Timer;\r
+ UINT64 TimeRemained;\r
+\r
+ if (MediaState == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *MediaState = EFI_SUCCESS;\r
+ MediaInfo = 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
+ Status = gBS->HandleProtocol (\r
+ SnpHandle,\r
+ &gEfiAdapterInformationProtocolGuid,\r
+ (VOID *) &Aip\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ MediaPresent = TRUE;\r
+ Status = NetLibDetectMedia (ServiceHandle, &MediaPresent);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (MediaPresent) {\r
+ *MediaState = EFI_SUCCESS;\r
+ } else {\r
+ *MediaState = EFI_NO_MEDIA;\r
+ }\r
+ }\r
+\r
+ //\r
+ // NetLibDetectMedia doesn't support EFI_NOT_READY status, return now!\r
+ //\r
+ return Status;\r
+ }\r
+\r
+ Status = Aip->GetInformation (\r
+ Aip,\r
+ &gEfiAdapterInfoMediaStateGuid,\r
+ (VOID **) &MediaInfo,\r
+ &DataSize\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ *MediaState = MediaInfo->MediaState;\r
+ FreePool (MediaInfo);\r
+ if (*MediaState != EFI_NOT_READY || Timeout < MEDIA_STATE_DETECT_TIME_INTERVAL) {\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ } else {\r
+\r
+ if (MediaInfo != NULL) {\r
+ FreePool (MediaInfo);\r
+ }\r
+\r
+ if (Status == EFI_UNSUPPORTED) {\r
+\r
+ //\r
+ // If gEfiAdapterInfoMediaStateGuid is not supported, call NetLibDetectMedia to get media state!\r
+ //\r
+ MediaPresent = TRUE;\r
+ Status = NetLibDetectMedia (ServiceHandle, &MediaPresent);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (MediaPresent) {\r
+ *MediaState = EFI_SUCCESS;\r
+ } else {\r
+ *MediaState = EFI_NO_MEDIA;\r
+ }\r
+ }\r
+ return Status;\r
+ }\r
+\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Loop to check media state\r
+ //\r
+\r
+ Timer = NULL;\r
+ TimeRemained = Timeout;\r
+ Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ do {\r
+ Status = gBS->SetTimer (\r
+ Timer,\r
+ TimerRelative,\r
+ MEDIA_STATE_DETECT_TIME_INTERVAL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseEvent(Timer);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ do {\r
+ TimerStatus = gBS->CheckEvent (Timer);\r
+ if (!EFI_ERROR (TimerStatus)) {\r
+\r
+ TimeRemained -= MEDIA_STATE_DETECT_TIME_INTERVAL;\r
+ Status = Aip->GetInformation (\r
+ Aip,\r
+ &gEfiAdapterInfoMediaStateGuid,\r
+ (VOID **) &MediaInfo,\r
+ &DataSize\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ *MediaState = MediaInfo->MediaState;\r
+ FreePool (MediaInfo);\r
+ } else {\r
+\r
+ if (MediaInfo != NULL) {\r
+ FreePool (MediaInfo);\r
+ }\r
+ gBS->CloseEvent(Timer);\r
+ return Status;\r
+ }\r
+ }\r
+ } while (TimerStatus == EFI_NOT_READY);\r
+ } while (*MediaState == EFI_NOT_READY && TimeRemained >= MEDIA_STATE_DETECT_TIME_INTERVAL);\r
+\r
+ gBS->CloseEvent(Timer);\r
+ if (*MediaState == EFI_NOT_READY && TimeRemained < MEDIA_STATE_DETECT_TIME_INTERVAL) {\r
+ return EFI_TIMEOUT;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
+\r
+/**\r
+ Check the default address used by the IPv4 driver is static or dynamic (acquired\r
+ from DHCP).\r
+\r
+ If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the\r
+ default address is static. If failed to get the policy from Ip4 Config2 Protocol,\r
+ the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.\r
+\r
+ @param[in] Controller The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL\r
+ relative with the default address to judge.\r
+\r
+ @retval TRUE If the default address is static.\r
+ @retval FALSE If the default address is acquired from DHCP.\r
+\r
+**/\r
+BOOLEAN\r
+NetLibDefaultAddressIsStatic (\r
+ IN EFI_HANDLE Controller\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
+ UINTN DataSize;\r
+ EFI_IP4_CONFIG2_POLICY Policy;\r
+ BOOLEAN IsStatic;\r
+\r
+ Ip4Config2 = NULL;\r
+\r
+ DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
+\r
+ IsStatic = TRUE;\r
+\r
+ //\r
+ // Get Ip4Config2 policy.\r
+ //\r
+ Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypePolicy, &DataSize, &Policy);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ IsStatic = (BOOLEAN) (Policy == Ip4Config2PolicyStatic);\r
+\r
+ON_EXIT:\r
+\r
+ return IsStatic;\r
+}\r
+\r
+/**\r
+ Create an IPv4 device path node.\r
+\r
+ If Node is NULL, then ASSERT().\r
+\r
+ The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.\r
+ The header subtype of IPv4 device path node is MSG_IPv4_DP.\r
+ Get other info from parameters to make up the whole IPv4 device path node.\r
+\r
+ @param[in, out] Node Pointer to the IPv4 device path node.\r
+ @param[in] Controller The controller handle.\r
+ @param[in] LocalIp The local IPv4 address.\r
+ @param[in] LocalPort The local port.\r
+ @param[in] RemoteIp The remote IPv4 address.\r
+ @param[in] RemotePort The remote port.\r
+ @param[in] Protocol The protocol type in the IP header.\r
+ @param[in] UseDefaultAddress Whether this instance is using default address or not.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+NetLibCreateIPv4DPathNode (\r
+ IN OUT IPv4_DEVICE_PATH *Node,\r
+ IN EFI_HANDLE Controller,\r
+ IN IP4_ADDR LocalIp,\r
+ IN UINT16 LocalPort,\r
+ IN IP4_ADDR RemoteIp,\r
+ IN UINT16 RemotePort,\r
+ IN UINT16 Protocol,\r
+ IN BOOLEAN UseDefaultAddress\r
+ )\r
+{\r
+ ASSERT (Node != NULL);\r
+\r