]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c
NetworkPkg: Add warning message for PXE if failed to read system GUID from SMBIOS.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcImpl.c
index ba7f9485949ef74f36a8c3b77ab93d2a7d570f4d..d3146c3a7e5feb958d6be1e778c600e7d94ced47 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   This implementation of EFI_PXE_BASE_CODE_PROTOCOL and EFI_LOAD_FILE_PROTOCOL.\r
 \r
 /** @file\r
   This implementation of EFI_PXE_BASE_CODE_PROTOCOL and EFI_LOAD_FILE_PROTOCOL.\r
 \r
-  Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<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
@@ -95,19 +95,19 @@ EfiPxeBcStart (
     //\r
     // Configure block size for TFTP as a default value to handle all link layers.\r
     //\r
     //\r
     // Configure block size for TFTP as a default value to handle all link layers.\r
     //\r
-    Private->BlockSize = (UINTN) (Private->Ip6MaxPacketSize -\r
-                           PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE);\r
+    Private->BlockSize = Private->Ip6MaxPacketSize -\r
+                           PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE;\r
 \r
     //\r
     // PXE over IPv6 starts here, initialize the fields and list header.\r
     //\r
     Private->Ip6Policy                          = PXEBC_IP6_POLICY_MAX;\r
 \r
     //\r
     // PXE over IPv6 starts here, initialize the fields and list header.\r
     //\r
     Private->Ip6Policy                          = PXEBC_IP6_POLICY_MAX;\r
-    Private->ProxyOffer.Dhcp6.Packet.Offer.Size = PXEBC_DHCP6_PACKET_MAX_SIZE;\r
-    Private->DhcpAck.Dhcp6.Packet.Ack.Size      = PXEBC_DHCP6_PACKET_MAX_SIZE;\r
-    Private->PxeReply.Dhcp6.Packet.Ack.Size     = PXEBC_DHCP6_PACKET_MAX_SIZE;\r
+    Private->ProxyOffer.Dhcp6.Packet.Offer.Size = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE;\r
+    Private->DhcpAck.Dhcp6.Packet.Ack.Size      = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE;\r
+    Private->PxeReply.Dhcp6.Packet.Ack.Size     = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE;\r
 \r
     for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) {\r
 \r
     for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) {\r
-      Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = PXEBC_DHCP6_PACKET_MAX_SIZE;\r
+      Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE;\r
     }\r
 \r
     //\r
     }\r
 \r
     //\r
@@ -124,6 +124,14 @@ EfiPxeBcStart (
     if (EFI_ERROR (Status)) {\r
       goto ON_ERROR;\r
     }\r
     if (EFI_ERROR (Status)) {\r
       goto ON_ERROR;\r
     }\r
+\r
+    //\r
+    // Set Ip6 policy to Automatic to start the IP6 router discovery.\r
+    //\r
+    Status = PxeBcSetIp6Policy (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
   } else {\r
     AsciiPrint ("\n>>Start PXE over IPv4");\r
     //\r
   } else {\r
     AsciiPrint ("\n>>Start PXE over IPv4");\r
     //\r
@@ -140,18 +148,18 @@ EfiPxeBcStart (
     //\r
     // Configure block size for TFTP as a default value to handle all link layers.\r
     //\r
     //\r
     // Configure block size for TFTP as a default value to handle all link layers.\r
     //\r
-    Private->BlockSize = (UINTN) (Private->Ip4MaxPacketSize -\r
-                           PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE);\r
+    Private->BlockSize = Private->Ip4MaxPacketSize -\r
+                           PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE;\r
 \r
     //\r
     // PXE over IPv4 starts here, initialize the fields.\r
     //\r
 \r
     //\r
     // PXE over IPv4 starts here, initialize the fields.\r
     //\r
-    Private->ProxyOffer.Dhcp4.Packet.Offer.Size = PXEBC_DHCP4_PACKET_MAX_SIZE;\r
-    Private->DhcpAck.Dhcp4.Packet.Ack.Size      = PXEBC_DHCP4_PACKET_MAX_SIZE;\r
-    Private->PxeReply.Dhcp4.Packet.Ack.Size     = PXEBC_DHCP4_PACKET_MAX_SIZE;\r
+    Private->ProxyOffer.Dhcp4.Packet.Offer.Size = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE;\r
+    Private->DhcpAck.Dhcp4.Packet.Ack.Size      = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE;\r
+    Private->PxeReply.Dhcp4.Packet.Ack.Size     = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE;\r
 \r
     for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) {\r
 \r
     for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) {\r
-      Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = PXEBC_DHCP4_PACKET_MAX_SIZE;\r
+      Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE;\r
     }\r
 \r
     PxeBcSeedDhcp4Packet (&Private->SeedPacket, Private->Udp4Read);\r
     }\r
 \r
     PxeBcSeedDhcp4Packet (&Private->SeedPacket, Private->Udp4Read);\r
@@ -196,6 +204,18 @@ EfiPxeBcStart (
     if (EFI_ERROR (Status)) {\r
       goto ON_ERROR;\r
     }\r
     if (EFI_ERROR (Status)) {\r
       goto ON_ERROR;\r
     }\r
+\r
+    //\r
+    //DHCP4 service allows only one of its children to be configured in  \r
+    //the active state, If the DHCP4 D.O.R.A started by IP4 auto  \r
+    //configuration and has not been completed, the Dhcp4 state machine \r
+    //will not be in the right state for the PXE to start a new round D.O.R.A. \r
+    //so we need to switch it's policy to static.\r
+    //\r
+    Status = PxeBcSetIp4Policy (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
   }\r
 \r
   //\r
   }\r
 \r
   //\r
@@ -338,6 +358,7 @@ EfiPxeBcStop (
       gBS->CloseEvent (Private->IcmpToken.Event);\r
       Private->IcmpToken.Event = NULL;\r
     }\r
       gBS->CloseEvent (Private->IcmpToken.Event);\r
       Private->IcmpToken.Event = NULL;\r
     }\r
+    Private->BootFileName = NULL;\r
   }\r
 \r
   gBS->CloseEvent (Private->UdpTimeOutEvent);\r
   }\r
 \r
   gBS->CloseEvent (Private->UdpTimeOutEvent);\r
@@ -345,6 +366,10 @@ EfiPxeBcStop (
   Private->BootFileSize = 0;\r
   Private->SolicitTimes = 0;\r
   Private->ElapsedTime  = 0;\r
   Private->BootFileSize = 0;\r
   Private->SolicitTimes = 0;\r
   Private->ElapsedTime  = 0;\r
+  ZeroMem (&Private->StationIp, sizeof (EFI_IP_ADDRESS));\r
+  ZeroMem (&Private->SubnetMask, sizeof (EFI_IP_ADDRESS));\r
+  ZeroMem (&Private->GatewayIp, sizeof (EFI_IP_ADDRESS));\r
+  ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));\r
 \r
   //\r
   // Reset the mode data.\r
 \r
   //\r
   // Reset the mode data.\r
@@ -428,10 +453,6 @@ EfiPxeBcDhcp (
     // Start S.A.R.R. process to get a IPv6 address and other boot information.\r
     //\r
     Status = PxeBcDhcp6Sarr (Private, Private->Dhcp6);\r
     // Start S.A.R.R. process to get a IPv6 address and other boot information.\r
     //\r
     Status = PxeBcDhcp6Sarr (Private, Private->Dhcp6);\r
-\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\r
-    }\r
   } else {\r
 \r
     //\r
   } else {\r
 \r
     //\r
@@ -443,13 +464,11 @@ EfiPxeBcDhcp (
     // Start D.O.R.A. process to get a IPv4 address and other boot information.\r
     //\r
     Status = PxeBcDhcp4Dora (Private, Private->Dhcp4);\r
     // Start D.O.R.A. process to get a IPv4 address and other boot information.\r
     //\r
     Status = PxeBcDhcp4Dora (Private, Private->Dhcp4);\r
-\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\r
-    }\r
   }\r
   }\r
-  \r
-ON_EXIT:\r
+\r
+  //\r
+  // Reconfigure the UDP instance with the default configuration.\r
+  //\r
   if (Mode->UsingIpv6) {\r
     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
   } else {\r
   if (Mode->UsingIpv6) {\r
     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
   } else {\r
@@ -529,6 +548,7 @@ EfiPxeBcDiscover (
   UINT16                          Index;\r
   EFI_STATUS                      Status;\r
   EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;\r
   UINT16                          Index;\r
   EFI_STATUS                      Status;\r
   EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;\r
+  EFI_PXE_BASE_CODE_DISCOVER_INFO *NewCreatedInfo;\r
 \r
   if (This == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
 \r
   if (This == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -541,6 +561,7 @@ EfiPxeBcDiscover (
   SrvList                 = NULL;\r
   Status                  = EFI_DEVICE_ERROR;\r
   Private->Function       = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;\r
   SrvList                 = NULL;\r
   Status                  = EFI_DEVICE_ERROR;\r
   Private->Function       = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;\r
+  NewCreatedInfo          = NULL;\r
 \r
   if (!Mode->Started) {\r
     return EFI_NOT_STARTED;\r
 \r
   if (!Mode->Started) {\r
     return EFI_NOT_STARTED;\r
@@ -570,6 +591,7 @@ EfiPxeBcDiscover (
   //\r
   // There are 3 methods to get the information for discover.\r
   //\r
   //\r
   // There are 3 methods to get the information for discover.\r
   //\r
+  ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));\r
   if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {\r
     //\r
     // 1. Take the previous setting as the discover info.\r
   if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {\r
     //\r
     // 1. Take the previous setting as the discover info.\r
@@ -594,12 +616,13 @@ EfiPxeBcDiscover (
     //\r
     // 2. Extract the discover information from the cached packets if unspecified.\r
     //\r
     //\r
     // 2. Extract the discover information from the cached packets if unspecified.\r
     //\r
-    Info   = &DefaultInfo;\r
-    Status = PxeBcExtractDiscoverInfo (Private, Type, Info, &BootSvrEntry, &SrvList);\r
+    NewCreatedInfo = &DefaultInfo;\r
+    Status = PxeBcExtractDiscoverInfo (Private, Type, &NewCreatedInfo, &BootSvrEntry, &SrvList);\r
     if (EFI_ERROR (Status)) {\r
       goto ON_EXIT;\r
     }\r
     if (EFI_ERROR (Status)) {\r
       goto ON_EXIT;\r
     }\r
-\r
+    ASSERT (NewCreatedInfo != NULL);\r
+    Info = NewCreatedInfo;\r
   } else {\r
     //\r
     // 3. Take the pass-in information as the discover info, and validate the server list.\r
   } else {\r
     //\r
     // 3. Take the pass-in information as the discover info, and validate the server list.\r
@@ -615,7 +638,7 @@ EfiPxeBcDiscover (
       if (Index != Info->IpCnt) {\r
         //\r
         // It's invalid if the first server doesn't accecpt any response\r
       if (Index != Info->IpCnt) {\r
         //\r
         // It's invalid if the first server doesn't accecpt any response\r
-        // and meanwhile any of the rest servers accept any reponse.\r
+        // but any of the other servers does accept any response.\r
         //\r
         Status = EFI_INVALID_PARAMETER;\r
         goto ON_EXIT;\r
         //\r
         Status = EFI_INVALID_PARAMETER;\r
         goto ON_EXIT;\r
@@ -634,30 +657,7 @@ EfiPxeBcDiscover (
 \r
   Private->IsDoDiscover = TRUE;\r
 \r
 \r
   Private->IsDoDiscover = TRUE;\r
 \r
-  if (Info->UseUCast) {\r
-    //\r
-    // Do discover by unicast.\r
-    //\r
-    for (Index = 0; Index < Info->IpCnt; Index++) {\r
-      if (BootSvrEntry == NULL) {\r
-        CopyMem (&Private->ServerIp, &SrvList[Index].IpAddr, sizeof (EFI_IP_ADDRESS));\r
-      } else {\r
-        ASSERT (!Mode->UsingIpv6);\r
-        ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));\r
-        CopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));\r
-      }\r
-\r
-      Status = PxeBcDiscoverBootServer (\r
-                 Private,\r
-                 Type,\r
-                 Layer,\r
-                 UseBis,\r
-                 &SrvList[Index].IpAddr,\r
-                 0,\r
-                 NULL\r
-                 );\r
-    }\r
-  } else if (Info->UseMCast) {\r
+  if (Info->UseMCast) {\r
     //\r
     // Do discover by multicast.\r
     //\r
     //\r
     // Do discover by multicast.\r
     //\r
@@ -667,8 +667,8 @@ EfiPxeBcDiscover (
                Layer,\r
                UseBis,\r
                &Info->ServerMCastIp,\r
                Layer,\r
                UseBis,\r
                &Info->ServerMCastIp,\r
-               0,\r
-               NULL\r
+               Info->IpCnt,\r
+               SrvList\r
                );\r
 \r
   } else if (Info->UseBCast) {\r
                );\r
 \r
   } else if (Info->UseBCast) {\r
@@ -685,11 +685,33 @@ EfiPxeBcDiscover (
                Info->IpCnt,\r
                SrvList\r
                );\r
                Info->IpCnt,\r
                SrvList\r
                );\r
+\r
+  } else if (Info->UseUCast) {\r
+    //\r
+    // Do discover by unicast.\r
+    //\r
+    for (Index = 0; Index < Info->IpCnt; Index++) {\r
+      if (BootSvrEntry == NULL) {\r
+        CopyMem (&Private->ServerIp, &SrvList[Index].IpAddr, sizeof (EFI_IP_ADDRESS));\r
+      } else {\r
+        ASSERT (!Mode->UsingIpv6);\r
+        ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));\r
+        CopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));\r
+      }\r
+\r
+      Status = PxeBcDiscoverBootServer (\r
+                 Private,\r
+                 Type,\r
+                 Layer,\r
+                 UseBis,\r
+                 &Private->ServerIp,\r
+                 Info->IpCnt,\r
+                 SrvList\r
+                 );\r
+      }\r
   }\r
 \r
   }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_EXIT;\r
-  } else {\r
+  if (!EFI_ERROR (Status)) {\r
     //\r
     // Parse the cached PXE reply packet, and store it into mode data if valid.\r
     //\r
     //\r
     // Parse the cached PXE reply packet, and store it into mode data if valid.\r
     //\r
@@ -698,8 +720,8 @@ EfiPxeBcDiscover (
       if (!EFI_ERROR (Status)) {\r
         CopyMem (\r
           &Mode->PxeReply.Dhcpv6,\r
       if (!EFI_ERROR (Status)) {\r
         CopyMem (\r
           &Mode->PxeReply.Dhcpv6,\r
-          &Private->PxeReply.Dhcp6.Packet.Offer,\r
-          Private->PxeReply.Dhcp6.Packet.Offer.Length\r
+          &Private->PxeReply.Dhcp6.Packet.Ack.Dhcp6,\r
+          Private->PxeReply.Dhcp6.Packet.Ack.Length\r
           );\r
         Mode->PxeReplyReceived = TRUE;\r
         Mode->PxeDiscoverValid = TRUE;\r
           );\r
         Mode->PxeReplyReceived = TRUE;\r
         Mode->PxeDiscoverValid = TRUE;\r
@@ -709,8 +731,8 @@ EfiPxeBcDiscover (
       if (!EFI_ERROR (Status)) {\r
         CopyMem (\r
           &Mode->PxeReply.Dhcpv4,\r
       if (!EFI_ERROR (Status)) {\r
         CopyMem (\r
           &Mode->PxeReply.Dhcpv4,\r
-          &Private->PxeReply.Dhcp4.Packet.Offer,\r
-          Private->PxeReply.Dhcp4.Packet.Offer.Length\r
+          &Private->PxeReply.Dhcp4.Packet.Ack.Dhcp4,\r
+          Private->PxeReply.Dhcp4.Packet.Ack.Length\r
           );\r
         Mode->PxeReplyReceived = TRUE;\r
         Mode->PxeDiscoverValid = TRUE;\r
           );\r
         Mode->PxeReplyReceived = TRUE;\r
         Mode->PxeDiscoverValid = TRUE;\r
@@ -720,6 +742,10 @@ EfiPxeBcDiscover (
 \r
 ON_EXIT:\r
 \r
 \r
 ON_EXIT:\r
 \r
+  if (NewCreatedInfo != NULL && NewCreatedInfo != &DefaultInfo) {\r
+    FreePool (NewCreatedInfo);\r
+  }\r
+  \r
   if (Mode->UsingIpv6) {\r
     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
   } else {\r
   if (Mode->UsingIpv6) {\r
     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
   } else {\r
@@ -829,17 +855,34 @@ EfiPxeBcMtftp (
       (Filename == NULL) ||\r
       (BufferSize == NULL) ||\r
       (ServerIp == NULL) ||\r
       (Filename == NULL) ||\r
       (BufferSize == NULL) ||\r
       (ServerIp == NULL) ||\r
-      ((BufferPtr == NULL) && DontUseBuffer) ||\r
-      ((BlockSize != NULL) && (*BlockSize < PXE_MTFTP_DEFAULT_BLOCK_SIZE)) ||\r
-      (!NetIp4IsUnicast (NTOHL (ServerIp->Addr[0]), 0) && !NetIp6IsValidUnicast (&ServerIp->v6))) {\r
+      ((BlockSize != NULL) && (*BlockSize < PXE_MTFTP_DEFAULT_BLOCK_SIZE))) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if (Operation == EFI_PXE_BASE_CODE_TFTP_READ_FILE ||\r
+      Operation == EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY ||\r
+      Operation == EFI_PXE_BASE_CODE_MTFTP_READ_FILE ||\r
+      Operation == EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY) {\r
+    if (BufferPtr == NULL && !DontUseBuffer) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
   Config    = NULL;\r
   Status    = EFI_DEVICE_ERROR;\r
   Private   = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
   Mode      = Private->PxeBc.Mode;\r
 \r
   Config    = NULL;\r
   Status    = EFI_DEVICE_ERROR;\r
   Private   = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
   Mode      = Private->PxeBc.Mode;\r
 \r
+  if (Mode->UsingIpv6) {\r
+    if (!NetIp6IsValidUnicast (&ServerIp->v6)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    if (IP4_IS_UNSPECIFIED (NTOHL (ServerIp->Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (ServerIp->Addr[0])))   {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
   if (Mode->UsingIpv6) {\r
     //\r
     // Set configuration data for Mtftp6 instance.\r
   if (Mode->UsingIpv6) {\r
     //\r
     // Set configuration data for Mtftp6 instance.\r
@@ -957,11 +1000,9 @@ EfiPxeBcMtftp (
     Mode->IcmpErrorReceived = TRUE;\r
   }\r
 \r
     Mode->IcmpErrorReceived = TRUE;\r
   }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_EXIT;\r
-  }\r
-  \r
-ON_EXIT:\r
+  //\r
+  // Reconfigure the UDP instance with the default configuration.\r
+  //\r
   if (Mode->UsingIpv6) {\r
     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
   } else {\r
   if (Mode->UsingIpv6) {\r
     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
   } else {\r
@@ -1052,7 +1093,8 @@ EfiPxeBcUdpWrite (
     DoNotFragment = TRUE;\r
   }\r
 \r
     DoNotFragment = TRUE;\r
   }\r
 \r
-  if (!Mode->UsingIpv6 && GatewayIp != NULL && !NetIp4IsUnicast (NTOHL (GatewayIp->Addr[0]), 0)) {\r
+  if (!Mode->UsingIpv6 && GatewayIp != NULL && Mode->SubnetMask.Addr[0] != 0 && \r
+      !NetIp4IsUnicast (NTOHL (GatewayIp->Addr[0]), EFI_NTOHL(Mode->SubnetMask))) {\r
     //\r
     // Gateway is provided but it's not a unicast IPv4 address, while it will be ignored for IPv6.\r
     //\r
     //\r
     // Gateway is provided but it's not a unicast IPv4 address, while it will be ignored for IPv6.\r
     //\r
@@ -1101,7 +1143,9 @@ EfiPxeBcUdpWrite (
                &Private->SubnetMask.v4,\r
                &Private->GatewayIp.v4,\r
                &Private->CurSrcPort,\r
                &Private->SubnetMask.v4,\r
                &Private->GatewayIp.v4,\r
                &Private->CurSrcPort,\r
-               DoNotFragment\r
+               DoNotFragment,\r
+               Private->Mode.TTL,\r
+               Private->Mode.ToS\r
                );\r
   }\r
 \r
                );\r
   }\r
 \r
@@ -1253,7 +1297,7 @@ EfiPxeBcUdpRead (
   UINTN                       FragmentIndex;\r
   UINT8                       *FragmentBuffer;\r
 \r
   UINTN                       FragmentIndex;\r
   UINT8                       *FragmentBuffer;\r
 \r
-  if (This == NULL || DestIp == NULL || DestPort == NULL) {\r
+  if (This == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -1264,9 +1308,9 @@ EfiPxeBcUdpRead (
   Udp4Rx    = NULL;\r
   Udp6Rx    = NULL;\r
 \r
   Udp4Rx    = NULL;\r
   Udp6Rx    = NULL;\r
 \r
-  if (((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0 && DestPort == NULL) ||\r
-      ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0 && SrcIp == NULL) ||\r
-      ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0 && SrcPort == NULL)) {\r
+  if (((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) == 0 && DestPort == NULL) ||\r
+      ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) == 0 && SrcIp == NULL) ||\r
+      ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) == 0 && SrcPort == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -1561,13 +1605,16 @@ EfiPxeBcSetIpFilter (
       //\r
       return EFI_INVALID_PARAMETER;\r
     }\r
       //\r
       return EFI_INVALID_PARAMETER;\r
     }\r
-    if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 &&\r
-        (NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), 0) ||\r
-         NetIp6IsValidUnicast (&NewFilter->IpList[Index].v6))) {\r
-      //\r
-      // If EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP is set and IPv4/IPv6 address\r
-      // is in IpList, promiscuous mode is needed.\r
-      //\r
+    if (Mode->UsingIpv6) {\r
+      if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 &&\r
+          NetIp6IsValidUnicast (&NewFilter->IpList[Index].v6)) {\r
+        NeedPromiscuous = TRUE;\r
+      }\r
+    } else if ((EFI_NTOHL(Mode->StationIp) != 0) &&\r
+               (EFI_NTOHL(Mode->SubnetMask) != 0) &&\r
+               IP4_NET_EQUAL(EFI_NTOHL(Mode->StationIp), EFI_NTOHL(NewFilter->IpList[Index].v4), EFI_NTOHL(Mode->SubnetMask.v4)) &&\r
+               NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), EFI_NTOHL(Mode->SubnetMask)) &&\r
+               ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0)) {\r
       NeedPromiscuous = TRUE;\r
     }\r
   }\r
       NeedPromiscuous = TRUE;\r
     }\r
   }\r
@@ -1886,7 +1933,7 @@ EfiPxeBcSetParameters (
       // Update the previous PxeBcCallback protocol.\r
       //\r
       Status = gBS->HandleProtocol (\r
       // Update the previous PxeBcCallback protocol.\r
       //\r
       Status = gBS->HandleProtocol (\r
-                      Private->Controller,\r
+                      Mode->UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller,\r
                       &gEfiPxeBaseCodeCallbackProtocolGuid,\r
                       (VOID **) &Private->PxeBcCallback\r
                       );\r
                       &gEfiPxeBaseCodeCallbackProtocolGuid,\r
                       (VOID **) &Private->PxeBcCallback\r
                       );\r
@@ -1902,6 +1949,7 @@ EfiPxeBcSetParameters (
 \r
   if (NewSendGUID != NULL) {\r
     if (*NewSendGUID && EFI_ERROR (NetLibGetSystemGuid (&SystemGuid))) {\r
 \r
   if (NewSendGUID != NULL) {\r
     if (*NewSendGUID && EFI_ERROR (NetLibGetSystemGuid (&SystemGuid))) {\r
+      DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n"));\r
       return EFI_INVALID_PARAMETER;\r
     }\r
     Mode->SendGUID = *NewSendGUID;\r
       return EFI_INVALID_PARAMETER;\r
     }\r
     Mode->SendGUID = *NewSendGUID;\r
@@ -1961,9 +2009,7 @@ EfiPxeBcSetStationIP (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (NewStationIp != NULL &&\r
-      (!NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), 0) &&\r
-       !NetIp6IsValidUnicast (&NewStationIp->v6))) {\r
+  if (NewStationIp != NULL && !NetIp6IsValidUnicast (&NewStationIp->v6)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -1977,6 +2023,14 @@ EfiPxeBcSetStationIP (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if (!Mode->UsingIpv6 && NewStationIp != NULL) {\r
+    if (IP4_IS_UNSPECIFIED(NTOHL (NewStationIp->Addr[0])) || \r
+        IP4_IS_LOCAL_BROADCAST(NTOHL (NewStationIp->Addr[0])) ||\r
+        (NewSubnetMask != NULL && NewSubnetMask->Addr[0] != 0 && !NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), NTOHL (NewSubnetMask->Addr[0])))) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  \r
   if (!Mode->Started) {\r
     return EFI_NOT_STARTED;\r
   }\r
   if (!Mode->Started) {\r
     return EFI_NOT_STARTED;\r
   }\r
@@ -2022,7 +2076,7 @@ EfiPxeBcSetStationIP (
     CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS));\r
   }\r
 \r
     CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS));\r
   }\r
 \r
-  Status = PxeBcFlushStaionIp (Private, NewStationIp, NewSubnetMask);\r
+  Status = PxeBcFlushStationIp (Private, NewStationIp, NewSubnetMask);\r
 ON_EXIT:\r
   return Status;\r
 }\r
 ON_EXIT:\r
   return Status;\r
 }\r
@@ -2302,31 +2356,31 @@ EfiPxeLoadFile (
   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;\r
   BOOLEAN                     UsingIpv6;\r
   EFI_STATUS                  Status;\r
   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;\r
   BOOLEAN                     UsingIpv6;\r
   EFI_STATUS                  Status;\r
-  BOOLEAN                     MediaPresent;\r
-\r
-  VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This);\r
-  Private    = VirtualNic->Private;\r
-  PxeBc      = &Private->PxeBc;\r
-  UsingIpv6  = FALSE;\r
-  Status     = EFI_DEVICE_ERROR;\r
+  EFI_STATUS                  MediaStatus;\r
 \r
 \r
-  if (This == NULL || BufferSize == NULL) {\r
+  if (This == NULL || BufferSize == NULL || FilePath == NULL || !IsDevicePathEnd (FilePath)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-\r
+  \r
   //\r
   // Only support BootPolicy\r
   //\r
   if (!BootPolicy) {\r
     return EFI_UNSUPPORTED;\r
   }\r
   //\r
   // Only support BootPolicy\r
   //\r
   if (!BootPolicy) {\r
     return EFI_UNSUPPORTED;\r
   }\r
+  \r
+  VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This);\r
+  Private    = VirtualNic->Private;\r
+  PxeBc      = &Private->PxeBc;\r
+  UsingIpv6  = FALSE;\r
+  Status     = EFI_DEVICE_ERROR;\r
 \r
   //\r
   // Check media status before PXE start\r
   //\r
 \r
   //\r
   // Check media status before PXE start\r
   //\r
-  MediaPresent = TRUE;\r
-  NetLibDetectMedia (Private->Controller, &MediaPresent);\r
-  if (!MediaPresent) {\r
+  MediaStatus = EFI_SUCCESS;\r
+  NetLibDetectMediaWaitTimeout (Private->Controller, PXEBC_CHECK_MEDIA_WAITING_TIME, &MediaStatus);\r
+  if (MediaStatus != EFI_SUCCESS) {\r
     return EFI_NO_MEDIA;\r
   }\r
 \r
     return EFI_NO_MEDIA;\r
   }\r
 \r
@@ -2341,6 +2395,15 @@ EfiPxeLoadFile (
   // Start Pxe Base Code to initialize PXE boot.\r
   //\r
   Status = PxeBc->Start (PxeBc, UsingIpv6);\r
   // Start Pxe Base Code to initialize PXE boot.\r
   //\r
   Status = PxeBc->Start (PxeBc, UsingIpv6);\r
+  if (Status == EFI_ALREADY_STARTED && UsingIpv6 != PxeBc->Mode->UsingIpv6) {\r
+    //\r
+    // PxeBc protocol has already been started but not on the required IP version, restart it.\r
+    //\r
+    Status = PxeBc->Stop (PxeBc);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = PxeBc->Start (PxeBc, UsingIpv6);\r
+    }\r
+  }\r
   if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) {\r
     Status = PxeBcLoadBootFile (Private, BufferSize, Buffer);\r
   }\r
   if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) {\r
     Status = PxeBcLoadBootFile (Private, BufferSize, Buffer);\r
   }\r
@@ -2355,6 +2418,16 @@ EfiPxeLoadFile (
     //   3. unsupported.\r
     //\r
     PxeBc->Stop (PxeBc);\r
     //   3. unsupported.\r
     //\r
     PxeBc->Stop (PxeBc);\r
+  } else {\r
+    //\r
+    // The DHCP4 can have only one configured child instance so we need to stop\r
+    // reset the DHCP4 child before we return. Otherwise these programs which \r
+    // also need to use DHCP4 will be impacted.\r
+    //\r
+    if (!PxeBc->Mode->UsingIpv6) {\r
+      Private->Dhcp4->Stop (Private->Dhcp4);\r
+      Private->Dhcp4->Configure (Private->Dhcp4, NULL);\r
+    }\r
   }\r
 \r
   return Status;\r
   }\r
 \r
   return Status;\r