]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c
NetworkPkg: reset DHCP child when leaving PXE LoadFile.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcImpl.c
index ba7f9485949ef74f36a8c3b77ab93d2a7d570f4d..12e5566a7913b1804551f69b23c970935758c0c0 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 - 2012, 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
@@ -196,6 +204,18 @@ EfiPxeBcStart (
     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
@@ -338,6 +358,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 +366,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,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
-\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\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
-\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\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
@@ -529,6 +548,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
@@ -541,6 +561,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
@@ -570,6 +591,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
@@ -594,12 +616,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
@@ -615,7 +638,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
@@ -634,30 +657,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
@@ -667,8 +667,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
@@ -685,11 +685,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
-    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
@@ -698,8 +720,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
@@ -709,8 +731,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
@@ -720,6 +742,10 @@ EfiPxeBcDiscover (
 \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
@@ -957,11 +983,9 @@ EfiPxeBcMtftp (
     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
@@ -1253,7 +1277,7 @@ EfiPxeBcUdpRead (
   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
@@ -1264,9 +1288,9 @@ EfiPxeBcUdpRead (
   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
@@ -2022,7 +2046,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
@@ -2304,6 +2328,10 @@ EfiPxeLoadFile (
   EFI_STATUS                  Status;\r
   BOOLEAN                     MediaPresent;\r
 \r
+  if (FilePath == NULL || !IsDevicePathEnd (FilePath)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
   VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This);\r
   Private    = VirtualNic->Private;\r
   PxeBc      = &Private->PxeBc;\r
@@ -2341,6 +2369,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
@@ -2355,6 +2392,16 @@ EfiPxeLoadFile (
     //   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