]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
Update PXE driver to support PXE forced mode.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp6.c
index c3ae23ec82f52d9059704456e62402c62b719b5d..1eb64a6a0f54d4043f59bee2fef3b90fea952df0 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Functions implementation related with DHCPv6 for UefiPxeBc Driver.\r
 \r
-  Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2012, 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
 #include "PxeBcImpl.h"\r
 \r
+//\r
+// Well-known multi-cast address defined in section-24.1 of rfc-3315\r
+//\r
+//   ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2\r
+//\r
+EFI_IPv6_ADDRESS   mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};\r
 \r
 /**\r
   Parse out a DHCPv6 option by OptTag, and find the position in buffer.\r
@@ -232,8 +238,8 @@ PxeBcExtractBootFileUrl (
   )\r
 {\r
   UINT16                     PrefixLen;\r
-  UINT8                      *BootFileNamePtr;\r
-  UINT8                      *BootFileName;\r
+  CHAR8                      *BootFileNamePtr;\r
+  CHAR8                      *BootFileName;\r
   UINT16                     BootFileNameLen;\r
   CHAR8                      *TmpStr;\r
   CHAR8                      TmpChar;\r
@@ -314,7 +320,7 @@ PxeBcExtractBootFileUrl (
   //\r
   // Get the part of BOOTFILE_NAME string.\r
   //\r
-  BootFileNamePtr = (UINT8*)((UINTN)ServerAddress + 1);\r
+  BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1);\r
   if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {\r
     FreePool (TmpStr);\r
     return EFI_INVALID_PARAMETER;\r
@@ -337,12 +343,12 @@ PxeBcExtractBootFileUrl (
     //\r
     // Extract boot file name from URL.\r
     //\r
-    BootFileName = (UINT8 *) AllocateZeroPool (BootFileNameLen);\r
+    BootFileName = (CHAR8 *) AllocateZeroPool (BootFileNameLen);\r
     if (BootFileName == NULL) {\r
       FreePool (TmpStr);\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
-    *FileName = BootFileName;\r
+    *FileName = (UINT8*) BootFileName;\r
 \r
     //\r
     // Decode percent-encoding in boot file name.\r
@@ -788,7 +794,7 @@ PxeBcRequestBootService (
     \r
   Status = PxeBc->UdpRead (\r
                     PxeBc,\r
-                    OpFlags,\r
+                    EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP,\r
                     &Private->StationIp,\r
                     &SrcPort,\r
                     &Private->ServerIp,\r
@@ -844,19 +850,29 @@ PxeBcRetryDhcp6Binl (
   Mode                  = Private->PxeBc.Mode;\r
   Private->IsDoDiscover = FALSE;\r
   Offer                 = &Private->OfferBuffer[Index].Dhcp6;\r
-\r
-  ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\r
-  //\r
-  // Parse out the next server address from the last offer, and store it\r
-  //\r
-  Status = PxeBcExtractBootFileUrl (\r
-             &Private->BootFileName,\r
-             &Private->ServerIp.v6,\r
-             (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
-             NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
+  if (Offer->OfferType == PxeOfferTypeDhcpBinl) {\r
+    //\r
+    // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.\r
+    //\r
+    CopyMem (\r
+      &Private->ServerIp.v6,\r
+      &mAllDhcpRelayAndServersAddress,\r
+      sizeof (EFI_IPv6_ADDRESS)\r
+      );\r
+  } else {\r
+    ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\r
+    //\r
+    // Parse out the next server address from the last offer, and store it\r
+    //\r
+    Status = PxeBcExtractBootFileUrl (\r
+               &Private->BootFileName,\r
+               &Private->ServerIp.v6,\r
+               (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
+               NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
   //\r
@@ -1244,6 +1260,8 @@ PxeBcRegisterIp6Address (
   EFI_EVENT                        TimeOutEvt;\r
   EFI_EVENT                        MappedEvt;\r
   EFI_STATUS                       Status;\r
+  UINT64                           DadTriggerTime;\r
+  EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS    DadXmits;\r
 \r
   Status     = EFI_SUCCESS;\r
   TimeOutEvt = NULL;\r
@@ -1287,6 +1305,20 @@ PxeBcRegisterIp6Address (
     goto ON_EXIT;\r
   }\r
 \r
+  //\r
+  // Get Duplicate Address Detection Transmits count.\r
+  //\r
+  DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);\r
+  Status = Ip6Cfg->GetData (\r
+                     Ip6Cfg,\r
+                     Ip6ConfigDataTypeDupAddrDetectTransmits,\r
+                     &DataSize,\r
+                     &DadXmits\r
+                     );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
   //\r
   // Create a timer as setting address timeout event since DAD in IP6 driver.\r
   //\r
@@ -1338,7 +1370,8 @@ PxeBcRegisterIp6Address (
   // Start the 5 secondes timer to wait for setting address.\r
   //\r
   Status = EFI_NO_MAPPING;\r
-  gBS->SetTimer (TimeOutEvt, TimerRelative, PXEBC_DHCP6_MAPPING_TIMEOUT);\r
+  DadTriggerTime = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY;\r
+  gBS->SetTimer (TimeOutEvt, TimerRelative, DadTriggerTime);\r
 \r
   while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {\r
     Ip6->Poll (Ip6);\r
@@ -1626,6 +1659,14 @@ PxeBcDhcp6Discover (
   }\r
   ReadSize = (UINTN) Reply->Size;\r
 \r
+  //\r
+  // Start Udp6Read instance\r
+  //\r
+  Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
   Status = PxeBc->UdpRead (\r
                     PxeBc,\r
                     OpFlags,\r
@@ -1638,6 +1679,10 @@ PxeBcDhcp6Discover (
                     &ReadSize,\r
                     (VOID *) &Reply->Dhcp6\r
                     );\r
+  //\r
+  // Stop Udp6Read instance\r
+  //\r
+  Private->Udp6Read->Configure (Private->Udp6Read, NULL);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -1670,9 +1715,17 @@ PxeBcDhcp6Sarr (
   UINT8                            Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE];\r
   UINT32                           OptCount;\r
   EFI_STATUS                       Status;\r
+  EFI_IP6_CONFIG_PROTOCOL          *Ip6Cfg;\r
+  EFI_STATUS                       TimerStatus;\r
+  EFI_EVENT                        Timer;\r
+  UINT64                           GetMappingTimeOut;\r
+  UINTN                            DataSize;\r
+  EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS    DadXmits;\r
 \r
   Status     = EFI_SUCCESS;\r
   PxeMode    = Private->PxeBc.Mode;\r
+  Ip6Cfg     = Private->Ip6Cfg;\r
+  Timer      = NULL;\r
 \r
   //\r
   // Build option list for the request packet.\r
@@ -1695,7 +1748,7 @@ PxeBcDhcp6Sarr (
   Config.IaInfoEvent           = NULL;\r
   Config.RapidCommit           = FALSE;\r
   Config.ReconfigureAccept     = FALSE;\r
-  Config.IaDescriptor.IaId     = 1;\r
+  Config.IaDescriptor.IaId     = Private->IaId;\r
   Config.IaDescriptor.Type     = EFI_DHCP6_IA_TYPE_NA;\r
   Config.SolicitRetransmission = Retransmit;\r
   Retransmit->Irt              = 4;\r
@@ -1707,8 +1760,8 @@ PxeBcDhcp6Sarr (
   // Configure the DHCPv6 instance for PXE boot.\r
   //\r
   Status = Dhcp6->Configure (Dhcp6, &Config);\r
+  FreePool (Retransmit);\r
   if (EFI_ERROR (Status)) {\r
-    FreePool (Retransmit);\r
     return Status;\r
   }\r
 \r
@@ -1726,6 +1779,52 @@ PxeBcDhcp6Sarr (
   // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.\r
   //\r
   Status = Dhcp6->Start (Dhcp6);\r
+  if (Status == EFI_NO_MAPPING) {\r
+    //\r
+    // IP6 Linklocal address is not available for use, so stop current Dhcp process\r
+    // and wait for duplicate address detection to finish.\r
+    //\r
+    Dhcp6->Stop (Dhcp6);\r
+\r
+    //\r
+    // Get Duplicate Address Detection Transmits count.\r
+    //\r
+    DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);\r
+    Status = Ip6Cfg->GetData (\r
+                       Ip6Cfg,\r
+                       Ip6ConfigDataTypeDupAddrDetectTransmits,\r
+                       &DataSize,\r
+                       &DadXmits\r
+                       );\r
+    if (EFI_ERROR (Status)) {\r
+      Dhcp6->Configure (Dhcp6, NULL);\r
+      return Status;\r
+    }\r
+\r
+    Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);\r
+    if (EFI_ERROR (Status)) {\r
+      Dhcp6->Configure (Dhcp6, NULL);\r
+      return Status;\r
+    }\r
+\r
+    GetMappingTimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY;\r
+    Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut);\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->CloseEvent (Timer);\r
+      Dhcp6->Configure (Dhcp6, NULL);\r
+      return Status;\r
+    }\r
+\r
+    do {\r
+      \r
+      TimerStatus = gBS->CheckEvent (Timer);\r
+      if (!EFI_ERROR (TimerStatus)) {\r
+        Status = Dhcp6->Start (Dhcp6);\r
+      }\r
+    } while (TimerStatus == EFI_NOT_READY);\r
+    \r
+    gBS->CloseEvent (Timer);\r
+  }\r
   if (EFI_ERROR (Status)) {\r
     if (Status == EFI_ICMP_ERROR) {\r
       PxeMode->IcmpErrorReceived = TRUE;\r