]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c
PXE driver bug fix.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcImpl.c
index 00f1e4d39515f8aaf6206e5a148b91ebe3dc6d14..19c83d3234fde237f4c82b0168462e6bb19e353b 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   This implementation of EFI_PXE_BASE_CODE_PROTOCOL and EFI_LOAD_FILE_PROTOCOL.\r
 \r
-  Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2007 - 2015, 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
@@ -124,6 +124,14 @@ EfiPxeBcStart (
     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
@@ -338,6 +346,7 @@ EfiPxeBcStop (
       gBS->CloseEvent (Private->IcmpToken.Event);\r
       Private->IcmpToken.Event = NULL;\r
     }\r
+    Private->BootFileName = NULL;\r
   }\r
 \r
   gBS->CloseEvent (Private->UdpTimeOutEvent);\r
@@ -345,6 +354,10 @@ EfiPxeBcStop (
   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
@@ -428,15 +441,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
-\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-\r
-    //\r
-    // Configure Udp6Read instance\r
-    //\r
-    Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);    \r
   } else {\r
 \r
     //\r
@@ -448,17 +452,16 @@ EfiPxeBcDhcp (
     // 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
-      return Status;\r
-    }\r
-\r
-    //\r
-    // Configure Udp4Read instance\r
-    //\r
-    Status = Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);\r
   }\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
+    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
@@ -533,6 +536,7 @@ EfiPxeBcDiscover (
   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
@@ -545,6 +549,7 @@ EfiPxeBcDiscover (
   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
@@ -574,6 +579,7 @@ EfiPxeBcDiscover (
   //\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
@@ -598,12 +604,13 @@ EfiPxeBcDiscover (
     //\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
-\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
@@ -619,7 +626,7 @@ EfiPxeBcDiscover (
       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
@@ -638,30 +645,7 @@ EfiPxeBcDiscover (
 \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
@@ -671,8 +655,8 @@ EfiPxeBcDiscover (
                Layer,\r
                UseBis,\r
                &Info->ServerMCastIp,\r
-               0,\r
-               NULL\r
+               Info->IpCnt,\r
+               SrvList\r
                );\r
 \r
   } else if (Info->UseBCast) {\r
@@ -689,11 +673,33 @@ EfiPxeBcDiscover (
                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
-  if (EFI_ERROR (Status)) {\r
-    return Status;    \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
@@ -702,8 +708,8 @@ EfiPxeBcDiscover (
       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
@@ -713,8 +719,8 @@ EfiPxeBcDiscover (
       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
@@ -724,10 +730,14 @@ EfiPxeBcDiscover (
 \r
 ON_EXIT:\r
 \r
+  if (NewCreatedInfo != NULL && NewCreatedInfo != &DefaultInfo) {\r
+    FreePool (NewCreatedInfo);\r
+  }\r
+  \r
   if (Mode->UsingIpv6) {\r
-    Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);    \r
+    Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
   } else {\r
-    Status = Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);    \r
+    Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);\r
   }\r
   \r
   //\r
@@ -961,16 +971,14 @@ EfiPxeBcMtftp (
     Mode->IcmpErrorReceived = TRUE;\r
   }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
+  //\r
+  // Reconfigure the UDP instance with the default configuration.\r
+  //\r
   if (Mode->UsingIpv6) {\r
-    Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);    \r
+    Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
   } else {\r
-    Status = Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);    \r
+    Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);\r
   }\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
@@ -1382,7 +1390,9 @@ EfiPxeBcUdpRead (
       if (Udp6Rx->DataLength - HeaderLen > *BufferSize) {\r
         Status = EFI_BUFFER_TOO_SMALL;\r
       } else {\r
-        *HeaderSize = HeaderLen;\r
+        if (HeaderSize != NULL) {\r
+          *HeaderSize = HeaderLen;\r
+        }\r
         *BufferSize = Udp6Rx->DataLength - HeaderLen;\r
 \r
         HeaderCopiedLen = 0;\r
@@ -1434,7 +1444,9 @@ EfiPxeBcUdpRead (
       if (Udp4Rx->DataLength - HeaderLen > *BufferSize) {\r
         Status = EFI_BUFFER_TOO_SMALL;\r
       } else {\r
-        *HeaderSize = HeaderLen;\r
+        if (HeaderSize != NULL) {\r
+          *HeaderSize = HeaderLen;\r
+        }\r
         *BufferSize = Udp4Rx->DataLength - HeaderLen;\r
 \r
         HeaderCopiedLen = 0;\r
@@ -2022,7 +2034,7 @@ EfiPxeBcSetStationIP (
     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
@@ -2341,6 +2353,15 @@ EfiPxeLoadFile (
   // 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