]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Universal / Network / UefiPxeBcDxe / PxeBcImpl.c
index 2150e0403f66b4e530146e97b266c12367257acf..3fa3be99c1786e34d96dc5ce289d622ca82c4e29 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   Interface routines for PxeBc.\r
 \r
-Copyright (c) 2007 - 2010, Intel Corporation.<BR>\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
 http://opensource.org/licenses/bsd-license.php\r
@@ -166,17 +166,21 @@ IcmpErrorListenHandlerDpc (
     return;\r
   }\r
 \r
-  if (EFI_ERROR (Status) || (RxData == NULL)) {\r
+  if (RxData == NULL) {\r
+    goto Resume;\r
+  }\r
+\r
+  if (Status != EFI_ICMP_ERROR) {\r
     //\r
-    // Only process the normal packets and the icmp error packets, if RxData is NULL\r
-    // with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although\r
-    // this should be a bug of the low layer (IP).\r
+    // The return status should be recognized as EFI_ICMP_ERROR.\r
     //\r
-    goto Resume;\r
+    goto CleanUp;\r
   }\r
 \r
   if (EFI_IP4 (RxData->Header->SourceAddress) != 0 &&\r
-      !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {\r
+      (NTOHL (Mode->SubnetMask.Addr[0]) != 0) &&\r
+      IP4_NET_EQUAL (NTOHL(Mode->StationIp.Addr[0]), EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0])) &&\r
+      !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0]))) {\r
     //\r
     // The source address is not zero and it's not a unicast IP address, discard it.\r
     //\r
@@ -214,8 +218,6 @@ IcmpErrorListenHandlerDpc (
     CopiedPointer += CopiedLen;\r
   }\r
 \r
-  goto Resume;\r
-\r
 CleanUp:\r
   gBS->SignalEvent (RxData->RecycleSignal);\r
 \r
@@ -336,6 +338,8 @@ EfiPxeBcStart (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
+  AsciiPrint ("\n>>Start PXE over IPv4");\r
+\r
   //\r
   // Configure the udp4 instance to let it receive data\r
   //\r
@@ -347,11 +351,19 @@ EfiPxeBcStart (
     return Status;\r
   }\r
 \r
+\r
   //\r
   // Configure block size for TFTP as a default value to handle all link layers.\r
-  // \r
-  Private->BlockSize   = (UINTN) (MIN (Private->Ip4MaxPacketSize, PXEBC_DEFAULT_PACKET_SIZE) - \r
-                           PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE);\r
+  //\r
+  Private->BlockSize   = MIN (Private->Ip4MaxPacketSize, PXEBC_DEFAULT_PACKET_SIZE) -\r
+                           PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE;\r
+  //\r
+  // If PcdTftpBlockSize is set to non-zero, override the default value.\r
+  //\r
+  if (PcdGet64 (PcdTftpBlockSize) != 0) {\r
+    Private->BlockSize   = (UINTN) PcdGet64 (PcdTftpBlockSize);\r
+  }\r
+\r
   Private->AddressIsOk = FALSE;\r
 \r
   ZeroMem (Mode, sizeof (EFI_PXE_BASE_CODE_MODE));\r
@@ -402,6 +414,18 @@ EfiPxeBcStart (
     goto ON_EXIT;\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_EXIT;\r
+  }\r
+\r
   Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4ConfigData);\r
   if (EFI_ERROR (Status)) {\r
     goto ON_EXIT;\r
@@ -553,15 +577,16 @@ EfiPxeBcDhcp (
   IN BOOLEAN                          SortOffers\r
   )\r
 {\r
-  PXEBC_PRIVATE_DATA      *Private;\r
-  EFI_PXE_BASE_CODE_MODE  *Mode;\r
-  EFI_DHCP4_PROTOCOL      *Dhcp4;\r
-  EFI_DHCP4_CONFIG_DATA   Dhcp4CfgData;\r
-  EFI_DHCP4_MODE_DATA     Dhcp4Mode;\r
-  EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];\r
-  UINT32                  OptCount;\r
-  EFI_STATUS              Status;\r
-  EFI_ARP_CONFIG_DATA     ArpConfigData;\r
+  PXEBC_PRIVATE_DATA           *Private;\r
+  EFI_PXE_BASE_CODE_MODE       *Mode;\r
+  EFI_DHCP4_PROTOCOL           *Dhcp4;\r
+  EFI_DHCP4_CONFIG_DATA        Dhcp4CfgData;\r
+  EFI_DHCP4_MODE_DATA          Dhcp4Mode;\r
+  EFI_DHCP4_PACKET_OPTION      *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];\r
+  UINT32                       OptCount;\r
+  EFI_STATUS                   Status;\r
+  EFI_ARP_CONFIG_DATA          ArpConfigData;\r
+  EFI_PXE_BASE_CODE_IP_FILTER  IpFilter;\r
 \r
   if (This == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -580,6 +605,11 @@ EfiPxeBcDhcp (
 \r
   Mode->IcmpErrorReceived = FALSE;\r
 \r
+  //\r
+  // Stop Udp4Read instance\r
+  //\r
+  Private->Udp4Read->Configure (Private->Udp4Read, NULL);\r
+\r
   //\r
   // Initialize the DHCP options and build the option list\r
   //\r
@@ -612,7 +642,7 @@ EfiPxeBcDhcp (
   ZeroMem (Private->ProxyIndex, sizeof (Private->ProxyIndex));\r
 \r
   Status = Dhcp4->Start (Dhcp4, NULL);\r
-  if (EFI_ERROR (Status)) {\r
+  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
     if (Status == EFI_ICMP_ERROR) {\r
       Mode->IcmpErrorReceived = TRUE;\r
     }\r
@@ -638,9 +668,11 @@ EfiPxeBcDhcp (
   // finished, set the various Mode members.\r
   //\r
   Status = PxeBcCheckSelectedOffer (Private);\r
-  if (!EFI_ERROR (Status)) {\r
-    goto ON_EXIT;\r
-  }\r
+\r
+  AsciiPrint ("\n  Station IP address is ");\r
+\r
+  PxeBcShowIp4Addr (&Private->StationIp.v4);\r
+  AsciiPrint ("\n");\r
 \r
 ON_EXIT:\r
   if (EFI_ERROR (Status)) {\r
@@ -663,7 +695,7 @@ ON_EXIT:
       ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));\r
 \r
       ArpConfigData.SwAddressType   = 0x0800;\r
-      ArpConfigData.SwAddressLength = sizeof (EFI_IPv4_ADDRESS);\r
+      ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS);\r
       ArpConfigData.StationAddress  = &Private->StationIp.v4;\r
 \r
       Private->Arp->Configure (Private->Arp, NULL);\r
@@ -686,9 +718,43 @@ ON_EXIT:
         Mode->RouteTable[1].SubnetMask.Addr[0] = 0;\r
         Mode->RouteTable[1].GwAddr.Addr[0]     = Private->GatewayIp.Addr[0];\r
       }\r
+\r
+      //\r
+      // Flush new station IP address into Udp4CfgData and Ip4ConfigData\r
+      //\r
+      CopyMem (&Private->Udp4CfgData.StationAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
+      CopyMem (&Private->Udp4CfgData.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+      CopyMem (&Private->Ip4ConfigData.StationAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
+      CopyMem (&Private->Ip4ConfigData.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+      //\r
+      // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.\r
+      //\r
+      Private->Ip4->Cancel (Private->Ip4, &Private->IcmpErrorRcvToken);\r
+      Private->Ip4->Configure (Private->Ip4, NULL);\r
+\r
+      Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4ConfigData);\r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpErrorRcvToken);\r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_EXIT;\r
+      }\r
     }\r
   }\r
 \r
+  Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);\r
+\r
+  //\r
+  // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP\r
+  // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.\r
+  //\r
+  ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));\r
+  IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
+  This->SetIpFilter (This, &IpFilter);\r
+\r
   return Status;\r
 }\r
 \r
@@ -749,6 +815,7 @@ EfiPxeBcDiscover (
   PXEBC_PRIVATE_DATA              *Private;\r
   EFI_PXE_BASE_CODE_MODE          *Mode;\r
   EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;\r
+  EFI_PXE_BASE_CODE_DISCOVER_INFO *CreatedInfo;\r
   EFI_PXE_BASE_CODE_SRVLIST       *SrvList;\r
   EFI_PXE_BASE_CODE_SRVLIST       DefaultSrvList;\r
   PXEBC_CACHED_DHCP4_PACKET       *Packet;\r
@@ -756,6 +823,7 @@ EfiPxeBcDiscover (
   UINT16                          Index;\r
   EFI_STATUS                      Status;\r
   PXEBC_BOOT_SVR_ENTRY            *BootSvrEntry;\r
+  EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;\r
 \r
   if (This == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -765,6 +833,7 @@ EfiPxeBcDiscover (
   Mode              = Private->PxeBc.Mode;\r
   BootSvrEntry      = NULL;\r
   SrvList           = NULL;\r
+  CreatedInfo       = NULL;\r
   Status            = EFI_DEVICE_ERROR;\r
   Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;\r
 \r
@@ -776,6 +845,11 @@ EfiPxeBcDiscover (
     return EFI_NOT_STARTED;\r
   }\r
 \r
+  //\r
+  // Stop Udp4Read instance\r
+  //\r
+  Private->Udp4Read->Configure (Private->Udp4Read, NULL);\r
+\r
   Mode->IcmpErrorReceived = FALSE;\r
 \r
   //\r
@@ -784,11 +858,13 @@ EfiPxeBcDiscover (
   // If info isn't offered,\r
   //   use the cached DhcpAck and ProxyOffer packets.\r
   //\r
+  ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));\r
   if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {\r
 \r
     if (!Mode->PxeDiscoverValid || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {\r
 \r
-      return EFI_INVALID_PARAMETER;\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto ON_EXIT;\r
     }\r
 \r
     DefaultInfo.IpCnt                 = 1;\r
@@ -811,7 +887,8 @@ EfiPxeBcDiscover (
       //\r
       // Address is not acquired or no discovery options.\r
       //\r
-      return EFI_INVALID_PARAMETER;\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto ON_EXIT;\r
     }\r
 \r
     DefaultInfo.UseMCast    = (BOOLEAN)!IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);\r
@@ -831,6 +908,8 @@ EfiPxeBcDiscover (
     }\r
 \r
     DefaultInfo.IpCnt = 0;\r
+    Info    = &DefaultInfo;\r
+    SrvList = Info->SrvList;\r
 \r
     if (DefaultInfo.MustUseList) {\r
       BootSvrEntry  = VendorOpt->BootSvr;\r
@@ -847,13 +926,31 @@ EfiPxeBcDiscover (
       }\r
 \r
       if (EFI_ERROR (Status)) {\r
-        return Status;\r
+        goto ON_EXIT;\r
       }\r
 \r
       DefaultInfo.IpCnt = BootSvrEntry->IpCnt;\r
+\r
+      if (DefaultInfo.IpCnt >= 1) {\r
+        CreatedInfo = AllocatePool (sizeof (DefaultInfo) + (DefaultInfo.IpCnt - 1) * sizeof (*SrvList));\r
+        if (CreatedInfo == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          goto ON_EXIT;\r
+\r
+        }\r
+\r
+        CopyMem (CreatedInfo, &DefaultInfo, sizeof (DefaultInfo));\r
+        Info    = CreatedInfo;\r
+        SrvList = Info->SrvList;\r
+      }\r
+\r
+      for (Index = 0; Index < DefaultInfo.IpCnt; Index++) {\r
+        CopyMem (&SrvList[Index].IpAddr, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));\r
+        SrvList[Index].AcceptAnyResponse   = FALSE;\r
+        SrvList[Index].Type                = BootSvrEntry->Type;\r
+      }\r
     }\r
 \r
-    Info = &DefaultInfo;\r
   } else {\r
 \r
     SrvList = Info->SrvList;\r
@@ -867,14 +964,16 @@ EfiPxeBcDiscover (
       }\r
 \r
       if (Index != Info->IpCnt) {\r
-        return EFI_INVALID_PARAMETER;\r
+        Status = EFI_INVALID_PARAMETER;\r
+        goto ON_EXIT;\r
       }\r
     }\r
   }\r
 \r
   if ((!Info->UseUCast && !Info->UseBCast && !Info->UseMCast) || (Info->MustUseList && Info->IpCnt == 0)) {\r
 \r
-    return EFI_INVALID_PARAMETER;\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
   }\r
   //\r
   // Execute discover by UniCast/BroadCast/MultiCast\r
@@ -904,6 +1003,9 @@ EfiPxeBcDiscover (
                 TRUE,\r
                 &Private->PxeReply.Packet.Ack\r
                 );\r
+      if (!EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
     }\r
 \r
   } else if (Info->UseMCast) {\r
@@ -941,6 +1043,7 @@ EfiPxeBcDiscover (
     } else {\r
       Status = EFI_DEVICE_ERROR;\r
     }\r
+    goto ON_EXIT;\r
   } else {\r
     PxeBcParseCachedDhcpPacket (&Private->PxeReply);\r
   }\r
@@ -953,6 +1056,22 @@ EfiPxeBcDiscover (
       );\r
   }\r
 \r
+  if (CreatedInfo != NULL) {\r
+    FreePool (CreatedInfo);\r
+  }\r
+\r
+ON_EXIT:\r
+\r
+  Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);\r
+\r
+  //\r
+  // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP\r
+  // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.\r
+  //\r
+  ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));\r
+  IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
+  This->SetIpFilter (This, &IpFilter);\r
+\r
   return Status;\r
 }\r
 \r
@@ -1043,16 +1162,19 @@ EfiPxeBcMtftp (
   IN BOOLEAN                          DontUseBuffer\r
   )\r
 {\r
-  PXEBC_PRIVATE_DATA      *Private;\r
-  EFI_MTFTP4_CONFIG_DATA  Mtftp4Config;\r
-  EFI_STATUS              Status;\r
-  EFI_PXE_BASE_CODE_MODE  *Mode;\r
-  EFI_MAC_ADDRESS         TempMacAddr;\r
+  PXEBC_PRIVATE_DATA           *Private;\r
+  EFI_MTFTP4_CONFIG_DATA       Mtftp4Config;\r
+  EFI_STATUS                   Status;\r
+  EFI_PXE_BASE_CODE_MODE       *Mode;\r
+  EFI_MAC_ADDRESS              TempMacAddr;\r
+  EFI_PXE_BASE_CODE_IP_FILTER  IpFilter;\r
 \r
   if ((This == NULL)                                                          ||\r
       (Filename == NULL)                                                      ||\r
       (BufferSize == NULL)                                                    ||\r
-      ((ServerIp == NULL) || !NetIp4IsUnicast (NTOHL (ServerIp->Addr[0]), 0)) ||\r
+      ((ServerIp == NULL) ||\r
+       (IP4_IS_UNSPECIFIED (NTOHL (ServerIp->Addr[0])) ||\r
+        IP4_IS_LOCAL_BROADCAST (NTOHL (ServerIp->Addr[0]))))                  ||\r
       ((BufferPtr == NULL) && DontUseBuffer)                                  ||\r
       ((BlockSize != NULL) && (*BlockSize < 512))) {\r
 \r
@@ -1073,6 +1195,11 @@ EfiPxeBcMtftp (
     }\r
   }\r
 \r
+  //\r
+  // Stop Udp4Read instance\r
+  //\r
+  Private->Udp4Read->Configure (Private->Udp4Read, NULL);\r
+\r
   Mode->TftpErrorReceived = FALSE;\r
   Mode->IcmpErrorReceived = FALSE;\r
 \r
@@ -1173,6 +1300,20 @@ EfiPxeBcMtftp (
     Mode->IcmpErrorReceived = TRUE;\r
   }\r
 \r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+ON_EXIT:\r
+  Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);\r
+  //\r
+  // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP\r
+  // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.\r
+  //\r
+  ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));\r
+  IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;\r
+  This->SetIpFilter (This, &IpFilter);\r
+\r
   return Status;\r
 }\r
 \r
@@ -1248,7 +1389,7 @@ EfiPxeBcUdpWrite (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if ((GatewayIp != NULL) && !NetIp4IsUnicast (NTOHL (GatewayIp->Addr[0]), 0)) {\r
+  if ((GatewayIp != NULL) && (IP4_IS_UNSPECIFIED (NTOHL (GatewayIp->Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (GatewayIp->Addr[0])))) {\r
     //\r
     // Gateway is provided but it's not a unicast IP address.\r
     //\r
@@ -1298,18 +1439,20 @@ EfiPxeBcUdpWrite (
     if (SrcPort != NULL) {\r
       Private->CurrentUdpSrcPort = *SrcPort;\r
     }\r
+  }\r
 \r
-    Status = PxeBcConfigureUdpWriteInstance (\r
-               Udp4,\r
-               &Private->StationIp.v4,\r
-               &Private->SubnetMask.v4,\r
-               &Private->GatewayIp.v4,\r
-               &Private->CurrentUdpSrcPort\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      Private->CurrentUdpSrcPort = 0;\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
+  Status = PxeBcConfigureUdpWriteInstance (\r
+             Udp4,\r
+             &Private->StationIp.v4,\r
+             &Private->SubnetMask.v4,\r
+             &Private->GatewayIp.v4,\r
+             &Private->CurrentUdpSrcPort,\r
+             Private->Mode.TTL,\r
+             Private->Mode.ToS\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Private->CurrentUdpSrcPort = 0;\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   ZeroMem (&Token, sizeof (EFI_UDP4_COMPLETION_TOKEN));\r
@@ -1383,6 +1526,10 @@ ON_EXIT:
 \r
   FreePool (Udp4TxData);\r
 \r
+  //\r
+  // Reset the instance.\r
+  //\r
+  Udp4->Configure (Udp4, NULL);\r
   return Status;\r
 }\r
 \r
@@ -1508,7 +1655,13 @@ EfiPxeBcUdpRead (
   EFI_STATUS                Status;\r
   BOOLEAN                   IsDone;\r
   BOOLEAN                   Matched;\r
-  UINTN                     CopyLen;\r
+  UINTN                     CopiedLen;\r
+  UINTN                     HeaderLen;\r
+  UINTN                     HeaderCopiedLen;\r
+  UINTN                     BufferCopiedLen;\r
+  UINT32                    FragmentLength;\r
+  UINTN                     FragmentIndex;\r
+  UINT8                     *FragmentBuffer;\r
 \r
   if (This == NULL || DestIp == NULL || DestPort == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1524,7 +1677,7 @@ EfiPxeBcUdpRead (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if ((BufferSize == NULL) || ((BufferPtr == NULL) && (*BufferSize != 0))) {\r
+  if ((BufferSize == NULL) || (BufferPtr == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -1665,26 +1818,51 @@ TRY_AGAIN:
     }\r
 \r
     if (Matched) {\r
+      ASSERT (RxData != NULL);\r
 \r
-      CopyLen = 0;\r
-\r
+      HeaderLen = 0;\r
       if (HeaderSize != NULL) {\r
-        CopyLen = MIN (*HeaderSize, RxData->DataLength);\r
-        CopyMem (HeaderPtr, RxData->FragmentTable[0].FragmentBuffer, CopyLen);\r
-        *HeaderSize = CopyLen;\r
+        HeaderLen = MIN (*HeaderSize, RxData->DataLength);\r
       }\r
 \r
-      if (RxData->DataLength - CopyLen > *BufferSize) {\r
-\r
+      if (RxData->DataLength - HeaderLen > *BufferSize) {\r
         Status = EFI_BUFFER_TOO_SMALL;\r
       } else {\r
-\r
-        *BufferSize = RxData->DataLength - CopyLen;\r
-        CopyMem (\r
-          BufferPtr,\r
-          (UINT8 *) RxData->FragmentTable[0].FragmentBuffer + CopyLen,\r
-          *BufferSize\r
-          );\r
+        *HeaderSize = HeaderLen;\r
+        *BufferSize = RxData->DataLength - HeaderLen;\r
+\r
+        HeaderCopiedLen = 0;\r
+        BufferCopiedLen = 0;\r
+        for (FragmentIndex = 0; FragmentIndex < RxData->FragmentCount; FragmentIndex++) {\r
+          FragmentLength = RxData->FragmentTable[FragmentIndex].FragmentLength;\r
+          FragmentBuffer = RxData->FragmentTable[FragmentIndex].FragmentBuffer;\r
+          if (HeaderCopiedLen + FragmentLength < HeaderLen) {\r
+            //\r
+            // Copy the header part of received data.\r
+            //\r
+            CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, FragmentLength);\r
+            HeaderCopiedLen += FragmentLength;\r
+          } else if (HeaderCopiedLen < HeaderLen) {\r
+            //\r
+            // Copy the header part of received data.\r
+            //\r
+            CopiedLen = HeaderLen - HeaderCopiedLen;\r
+            CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, CopiedLen);\r
+            HeaderCopiedLen += CopiedLen;\r
+\r
+            //\r
+            // Copy the other part of received data.\r
+            //\r
+            CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer + CopiedLen, FragmentLength - CopiedLen);\r
+            BufferCopiedLen += (FragmentLength - CopiedLen);\r
+          } else {\r
+            //\r
+            // Copy the other part of received data.\r
+            //\r
+            CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer, FragmentLength);\r
+            BufferCopiedLen += FragmentLength;\r
+          }\r
+        }\r
       }\r
     } else {\r
 \r
@@ -1753,7 +1931,11 @@ EfiPxeBcSetIpFilter (
   PXEBC_PRIVATE_DATA        *Private;\r
   EFI_PXE_BASE_CODE_MODE    *Mode;\r
   UINTN                     Index;\r
+  EFI_UDP4_CONFIG_DATA      *Udp4Cfg;\r
   BOOLEAN                   PromiscuousNeed;\r
+  BOOLEAN                   AcceptPromiscuous;\r
+  BOOLEAN                   AcceptBroadcast;\r
+  BOOLEAN                   MultiCastUpdate;\r
 \r
   if (This == NULL) {\r
     DEBUG ((EFI_D_ERROR, "This == NULL.\n"));\r
@@ -1778,6 +1960,11 @@ EfiPxeBcSetIpFilter (
     return EFI_NOT_STARTED;\r
   }\r
 \r
+  if (Mode->UsingIpv6) {\r
+    DEBUG ((EFI_D_ERROR, "This driver is PXE for IPv4 Only.\n"));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   PromiscuousNeed = FALSE;\r
 \r
   for (Index = 0; Index < NewFilter->IpCnt; ++Index) {\r
@@ -1788,9 +1975,11 @@ EfiPxeBcSetIpFilter (
       DEBUG ((EFI_D_ERROR, "There is broadcast address in NewFilter.\n"));\r
       return EFI_INVALID_PARAMETER;\r
     }\r
-    if (NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), 0) &&\r
-        ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0)\r
-       ) {\r
+    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)) &&\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
       //\r
       // If EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP is set and IP4 address is in IpList,\r
       // promiscuous mode is needed.\r
@@ -1799,54 +1988,71 @@ EfiPxeBcSetIpFilter (
     }\r
   }\r
 \r
-  //\r
-  // Clear the UDP instance configuration, all joined groups will be left\r
-  // during the operation.\r
-  //\r
-  Private->Udp4Read->Configure (Private->Udp4Read, NULL);\r
-  Private->Udp4CfgData.AcceptPromiscuous  = FALSE;\r
-  Private->Udp4CfgData.AcceptBroadcast    = FALSE;\r
+  AcceptPromiscuous = FALSE;\r
+  AcceptBroadcast   = FALSE;\r
+  MultiCastUpdate   = FALSE;\r
 \r
   if (PromiscuousNeed ||\r
       ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) ||\r
       ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0)\r
      ) {\r
     //\r
-    // Configure the udp4 filter to receive all packages\r
+    // Configure the udp4 filter to receive all packages.\r
     //\r
-    Private->Udp4CfgData.AcceptPromiscuous  = TRUE;\r
-\r
+    AcceptPromiscuous  = TRUE;\r
+  } else if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) {\r
     //\r
-    // Configure the UDP instance with the new configuration.\r
+    // Configure the udp4 filter to receive all broadcast packages.\r
     //\r
-    Status = Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-\r
-  } else {\r
+    AcceptBroadcast   = TRUE;\r
+  }\r
 \r
-    if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) {\r
-      //\r
-      // Configure the udp4 filter to receive all broadcast packages\r
-      //\r
-      Private->Udp4CfgData.AcceptBroadcast    = TRUE;\r
+  //\r
+  // In multicast condition when Promiscuous FALSE and IpCnt no-zero.\r
+  // Here check if there is any update of the multicast ip address. If yes,\r
+  // we need leave the old multicast group (by Config UDP instance to NULL),\r
+  // and join the new multicast group.\r
+  //\r
+  if (!AcceptPromiscuous) {\r
+    if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) {\r
+      if (Mode->IpFilter.IpCnt != NewFilter->IpCnt) {\r
+        MultiCastUpdate = TRUE;\r
+      } else if (CompareMem (Mode->IpFilter.IpList, NewFilter->IpList, NewFilter->IpCnt * sizeof (EFI_IP_ADDRESS)) != 0 ) {\r
+        MultiCastUpdate = TRUE;\r
+      }\r
     }\r
+  }\r
+\r
+  //\r
+  // Check whether we need reconfigure the UDP instance.\r
+  //\r
+  Udp4Cfg = &Private->Udp4CfgData;\r
+  if ((AcceptPromiscuous != Udp4Cfg->AcceptPromiscuous) ||\r
+      (AcceptBroadcast != Udp4Cfg->AcceptBroadcast)     || MultiCastUpdate) {\r
+    //\r
+    // Clear the UDP instance configuration, all joined groups will be left\r
+    // during the operation.\r
+    //\r
+    Private->Udp4Read->Configure (Private->Udp4Read, NULL);\r
 \r
     //\r
     // Configure the UDP instance with the new configuration.\r
     //\r
-    Status = Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);\r
+    Udp4Cfg->AcceptPromiscuous = AcceptPromiscuous;\r
+    Udp4Cfg->AcceptBroadcast   = AcceptBroadcast;\r
+    Status = Private->Udp4Read->Configure (Private->Udp4Read, Udp4Cfg);\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
 \r
-    if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) {\r
-\r
+    //\r
+    // In not Promiscuous mode, need to join the new multicast group.\r
+    //\r
+    if (!AcceptPromiscuous) {\r
       for (Index = 0; Index < NewFilter->IpCnt; ++Index) {\r
         if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) {\r
           //\r
-          // Join the mutilcast group\r
+          // Join the mutilcast group.\r
           //\r
           Status = Private->Udp4Read->Groups (Private->Udp4Read, TRUE, &NewFilter->IpList[Index].v4);\r
           if (EFI_ERROR (Status)) {\r
@@ -2115,12 +2321,16 @@ EfiPxeBcSetStationIP (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (NewStationIp != NULL && !NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), 0)) {\r
+  if (NewSubnetMask != NULL && !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (NewSubnetMask != NULL && !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) {\r
-    return EFI_INVALID_PARAMETER;\r
+  if (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
   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
@@ -2150,7 +2360,7 @@ EfiPxeBcSetStationIP (
     ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));\r
 \r
     ArpConfigData.SwAddressType   = 0x0800;\r
-    ArpConfigData.SwAddressLength = sizeof (EFI_IPv4_ADDRESS);\r
+    ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS);\r
     ArpConfigData.StationAddress  = &Private->StationIp.v4;\r
 \r
     Private->Arp->Configure (Private->Arp, NULL);\r
@@ -2537,6 +2747,14 @@ DiscoverBootFile (
 \r
   Private->FileSize = (UINTN) *BufferSize;\r
 \r
+  //\r
+  // Display all the information: boot server address, boot file name and boot file size.\r
+  //\r
+  AsciiPrint ("\n  Server IP address is ");\r
+  PxeBcShowIp4Addr (&Private->ServerIp.v4);\r
+  AsciiPrint ("\n  NBP filename is %a", Private->BootFileName);\r
+  AsciiPrint ("\n  NBP filesize is %d Bytes", Private->FileSize);\r
+\r
   return Status;\r
 }\r
 \r
@@ -2583,7 +2801,11 @@ EfiPxeLoadFile (
   BOOLEAN                     NewMakeCallback;\r
   EFI_STATUS                  Status;\r
   UINT64                      TmpBufSize;\r
-  BOOLEAN                     MediaPresent;\r
+  EFI_STATUS                  MediaStatus;\r
+\r
+  if (FilePath == NULL || !IsDevicePathEnd (FilePath)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   Private         = PXEBC_PRIVATE_DATA_FROM_LOADFILE (This);\r
   PxeBc           = &Private->PxeBc;\r
@@ -2605,9 +2827,9 @@ EfiPxeLoadFile (
   //\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
@@ -2648,6 +2870,7 @@ EfiPxeLoadFile (
     if (sizeof (UINTN) < sizeof (UINT64) && (TmpBufSize > 0xFFFFFFFF)) {\r
       Status = EFI_DEVICE_ERROR;\r
     } else if (TmpBufSize > 0 && *BufferSize >= (UINTN) TmpBufSize && Buffer != NULL) {\r
+      AsciiPrint ("\n Downloading NBP file...\n");\r
       *BufferSize = (UINTN) TmpBufSize;\r
       Status = PxeBc->Mtftp (\r
                         PxeBc,\r
@@ -2672,6 +2895,7 @@ EfiPxeLoadFile (
     //\r
     // Download the file.\r
     //\r
+    AsciiPrint ("\n Downloading NBP file...\n");\r
     TmpBufSize = (UINT64) (*BufferSize);\r
     Status = PxeBc->Mtftp (\r
                       PxeBc,\r
@@ -2706,17 +2930,25 @@ EfiPxeLoadFile (
   // Check download status\r
   //\r
   if (Status == EFI_SUCCESS) {\r
+    AsciiPrint ("\n  NBP file downloaded successfully.\n");\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 the other programs which\r
+    // also need to use DHCP4 will be impacted.\r
     // The functionality of PXE Base Code protocol will not be stopped,\r
     // when downloading is successfully.\r
     //\r
+    Private->Dhcp4->Stop (Private->Dhcp4);\r
+    Private->Dhcp4->Configure (Private->Dhcp4, NULL);\r
     return EFI_SUCCESS;\r
 \r
   } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
     if (Buffer != NULL) {\r
       AsciiPrint ("PXE-E05: Download buffer is smaller than requested file.\n");\r
     } else {\r
-      PxeBc->Stop (PxeBc);\r
+      //\r
+      // The functionality of PXE Base Code protocol will not be stopped.\r
+      //\r
       return Status;\r
     }\r
 \r