+ //\r
+ // Try to get SNP handle\r
+ //\r
+ Snp = NULL;\r
+ SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);\r
+ if (SnpHandle != NULL) {\r
+ //\r
+ // SNP found, use it directly\r
+ //\r
+ SnpMode = Snp->Mode;\r
+ } else {\r
+ //\r
+ // Failed to get SNP handle, try to get MAC address from MNP\r
+ //\r
+ MnpChildHandle = NULL;\r
+ Status = gBS->HandleProtocol (\r
+ ServiceHandle,\r
+ &gEfiManagedNetworkServiceBindingProtocolGuid,\r
+ (VOID **) &MnpSb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create a MNP child\r
+ //\r
+ Status = MnpSb->CreateChild (MnpSb, &MnpChildHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Open MNP protocol\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ MnpChildHandle,\r
+ &gEfiManagedNetworkProtocolGuid,\r
+ (VOID **) &Mnp\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ MnpSb->DestroyChild (MnpSb, MnpChildHandle);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Try to get SNP mode from MNP\r
+ //\r
+ Status = Mnp->GetModeData (Mnp, NULL, &SnpModeData);\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {\r
+ MnpSb->DestroyChild (MnpSb, MnpChildHandle);\r
+ return Status;\r
+ }\r
+ SnpMode = &SnpModeData;\r
+\r
+ //\r
+ // Destroy the MNP child\r
+ //\r
+ MnpSb->DestroyChild (MnpSb, MnpChildHandle);\r
+ }\r
+\r
+ *AddressSize = SnpMode->HwAddressSize;\r
+ CopyMem (MacAddress->Addr, SnpMode->CurrentAddress.Addr, SnpMode->HwAddressSize);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Convert MAC address of the NIC associated with specified Service Binding Handle\r
+ to a unicode string. Callers are responsible for freeing the string storage.\r
+\r
+ If MacString is NULL, then ASSERT().\r
+\r
+ Locate simple network protocol associated with the Service Binding Handle and\r
+ get the mac address from SNP. Then convert the mac address into a unicode\r
+ string. It takes 2 unicode characters to represent a 1 byte binary buffer.\r
+ Plus one unicode character for the null-terminator.\r
+\r
+ @param[in] ServiceHandle The handle where network service binding protocol is\r
+ installed on.\r
+ @param[in] ImageHandle The image handle used to act as the agent handle to\r
+ get the simple network protocol. This parameter is\r
+ optional and may be NULL.\r
+ @param[out] MacString The pointer to store the address of the string\r
+ representation of the mac address.\r
+\r
+ @retval EFI_SUCCESS Convert the mac address a unicode string successfully.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.\r
+ @retval Others Failed to open the simple network protocol.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NetLibGetMacString (\r
+ IN EFI_HANDLE ServiceHandle,\r
+ IN EFI_HANDLE ImageHandle, OPTIONAL\r
+ OUT CHAR16 **MacString\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_MAC_ADDRESS MacAddress;\r
+ UINT8 *HwAddress;\r
+ UINTN HwAddressSize;\r
+ UINT16 VlanId;\r
+ CHAR16 *String;\r
+ UINTN Index;\r
+ UINTN BufferSize;\r
+\r
+ ASSERT (MacString != NULL);\r
+\r
+ //\r
+ // Get MAC address of the network device\r
+ //\r
+ Status = NetLibGetMacAddress (ServiceHandle, &MacAddress, &HwAddressSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // It takes 2 unicode characters to represent a 1 byte binary buffer.\r
+ // If VLAN is configured, it will need extra 5 characters like "\0005".\r
+ // Plus one unicode character for the null-terminator.\r
+ //\r
+ BufferSize = (2 * HwAddressSize + 5 + 1) * sizeof (CHAR16);\r
+ String = AllocateZeroPool (BufferSize);\r
+ if (String == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ *MacString = String;\r
+\r
+ //\r
+ // Convert the MAC address into a unicode string.\r
+ //\r
+ HwAddress = &MacAddress.Addr[0];\r
+ for (Index = 0; Index < HwAddressSize; Index++) {\r
+ UnicodeValueToStringS (\r
+ String,\r
+ BufferSize - ((UINTN)String - (UINTN)*MacString),\r
+ PREFIX_ZERO | RADIX_HEX,\r
+ *(HwAddress++),\r
+ 2\r
+ );\r
+ String += StrnLenS (String, (BufferSize - ((UINTN)String - (UINTN)*MacString)) / sizeof (CHAR16));\r
+ }\r
+\r
+ //\r
+ // Append VLAN ID if any\r
+ //\r
+ VlanId = NetLibGetVlanId (ServiceHandle);\r
+ if (VlanId != 0) {\r
+ *String++ = L'\\';\r
+ UnicodeValueToStringS (\r
+ String,\r
+ BufferSize - ((UINTN)String - (UINTN)*MacString),\r
+ PREFIX_ZERO | RADIX_HEX,\r
+ VlanId,\r
+ 4\r
+ );\r
+ String += StrnLenS (String, (BufferSize - ((UINTN)String - (UINTN)*MacString)) / sizeof (CHAR16));\r
+ }\r
+\r
+ //\r
+ // Null terminate the Unicode string\r
+ //\r
+ *String = L'\0';\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Detect media status for specified network device.\r
+\r
+ If MediaPresent is NULL, then ASSERT().\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 that network cable is attached when\r
+ Snp->Initialize() is invoked while network cable is unattached later,\r
+ NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer\r
+ apps to 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
+ if (MCastFilter == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\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
+\r
+ Detect media state for a network device. This routine will wait for a period of time at\r
+ a specified checking interval when a certain network is under connecting until connection\r
+ process finishs or timeout. If Aip protocol is supported by low layer drivers, three kinds\r
+ of media states can be detected: EFI_SUCCESS, EFI_NOT_READY and EFI_NO_MEDIA, represents\r
+ connected state, connecting state and no media state respectively. When function detects\r
+ the current state is EFI_NOT_READY, it will loop to wait for next time's check until state\r
+ turns to be EFI_SUCCESS or EFI_NO_MEDIA. If Aip protocol is not supported, function will\r
+ call NetLibDetectMedia() and return state directly.\r
+\r
+ @param[in] ServiceHandle The handle where network service binding protocols are\r
+ installed on.\r
+ @param[in] Timeout The maximum number of 100ns units to wait when network\r
+ is connecting. Zero value means detect once and return\r
+ immediately.\r
+ @param[out] MediaState The pointer to the detected media state.\r
+\r
+ @retval EFI_SUCCESS Media detection success.\r
+ @retval EFI_INVALID_PARAMETER ServiceHandle is not a valid network device handle or\r
+ MediaState pointer is NULL.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_TIMEOUT Network is connecting but timeout.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NetLibDetectMediaWaitTimeout (\r
+ IN EFI_HANDLE ServiceHandle,\r
+ IN UINT64 Timeout,\r
+ OUT EFI_STATUS *MediaState\r
+ )\r
+{\r
+ 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
+ Node->Header.Type = MESSAGING_DEVICE_PATH;\r
+ Node->Header.SubType = MSG_IPv4_DP;\r
+ SetDevicePathNodeLength (&Node->Header, sizeof (IPv4_DEVICE_PATH));\r
+\r
+ CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+ Node->LocalPort = LocalPort;\r
+ Node->RemotePort = RemotePort;\r
+\r
+ Node->Protocol = Protocol;\r
+\r
+ if (!UseDefaultAddress) {\r
+ Node->StaticIpAddress = TRUE;\r