]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
Update PXE driver to wait for IPv6 duplicate address detection to finish.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp6.c
index 0a2dd6d13ebc1eb6f20fd9491faa860056edcd6b..6ab2afa088af05fc5113a25d364211044590e3c9 100644 (file)
@@ -1260,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
@@ -1303,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
@@ -1354,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
@@ -1698,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
@@ -1735,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
@@ -1754,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