]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / NetworkPkg / Dhcp6Dxe / Dhcp6Utility.c
index f4e7649e6cba2b4734db308cb52fd6e1de080835..32247c927b0a63a6b89af29be80c24cb0950bd5e 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Dhcp6 support functions implementation.\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
@@ -34,27 +34,18 @@ Dhcp6GenerateClientId (
   EFI_DHCP6_DUID            *Duid;\r
   EFI_TIME                  Time;\r
   UINT32                    Stamp;\r
+  EFI_GUID                  Uuid;\r
+\r
 \r
   //\r
   // Attempt to get client Id from variable to keep it constant.\r
   // See details in section-9 of rfc-3315.\r
   //\r
-  Duid = GetVariable (L"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid);\r
+  GetVariable2 (L"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid, (VOID**)&Duid, NULL);\r
   if (Duid != NULL) {\r
     return Duid;\r
   }\r
 \r
-  //\r
-  // Generate a time stamp of the seconds from 2000/1/1, assume 30day/month.\r
-  //\r
-  gRT->GetTime (&Time, NULL);\r
-  Stamp = (UINT32)\r
-    (\r
-      (((((Time.Year - 2000) * 360 + (Time.Month - 1)) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) *\r
-      60 +\r
-      Time.Second\r
-    );\r
-\r
   //\r
   //  The format of client identifier option:\r
   //\r
@@ -68,42 +59,96 @@ Dhcp6GenerateClientId (
   //    .                                                               .\r
   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
   //\r
-  //\r
-  //  The format of DUID-LLT:\r
-  //\r
-  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
-  //    |          Duid type (1)        |    hardware type (16 bits)    |\r
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
-  //    |                        time (32 bits)                         |\r
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
-  //    .                                                               .\r
-  //    .             link-layer address (variable length)              .\r
-  //    .                                                               .\r
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
-  //\r
 \r
   //\r
-  // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes\r
+  // If System UUID is found from SMBIOS Table, use DUID-UUID type.\r
   //\r
-  Duid = AllocateZeroPool (10 + Mode->HwAddressSize);\r
-  if (Duid == NULL) {\r
-    return NULL;\r
-  }\r
+  if (!EFI_ERROR (NetLibGetSystemGuid (&Uuid))) {\r
+    //\r
+    //\r
+    //  The format of DUID-UUID:\r
+    //   \r
+    //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //   |          DUID-Type (4)        |    UUID (128 bits)            |\r
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |\r
+    //   |                                                               |\r
+    //   |                                                               |\r
+    //   |                                -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //   |                                |\r
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-\r
 \r
-  //\r
-  // sizeof (Duid-type + hardware-type + time) = 8 bytes\r
-  //\r
-  Duid->Length = (UINT16) (Mode->HwAddressSize + 8);\r
+    //\r
+    // sizeof (option-len + Duid-type + UUID-size) = 20 bytes\r
+    //\r
+    Duid = AllocateZeroPool (2 + 2 + sizeof (EFI_GUID));\r
+    if (Duid == NULL) {\r
+      return NULL;\r
+    }\r
 \r
-  //\r
-  // Set the Duid-type, hardware-type, time and copy the hardware address.\r
-  //\r
-  WriteUnaligned16 ((UINT16 *) (Duid->Duid), HTONS (Dhcp6DuidTypeLlt));\r
-  WriteUnaligned16 ((UINT16 *) (Duid->Duid + 2), HTONS (NET_IFTYPE_ETHERNET));\r
-  WriteUnaligned32 ((UINT32 *) (Duid->Duid + 4), HTONL (Stamp));\r
+    //\r
+    // sizeof (Duid-type + UUID-size) = 18 bytes\r
+    //\r
+    Duid->Length = (UINT16) (18);\r
+  \r
+    //\r
+    // Set the Duid-type and copy UUID.\r
+    //\r
+    WriteUnaligned16 ((UINT16 *) (Duid->Duid), HTONS (Dhcp6DuidTypeUuid));\r
+  \r
+    CopyMem (Duid->Duid + 2, &Uuid, sizeof(EFI_GUID));\r
+\r
+  } else {\r
+      \r
+    //\r
+    //\r
+    //  The format of DUID-LLT:\r
+    //\r
+    //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //    |          Duid type (1)        |    hardware type (16 bits)    |\r
+    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //    |                        time (32 bits)                         |\r
+    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //    .                                                               .\r
+    //    .             link-layer address (variable length)              .\r
+    //    .                                                               .\r
+    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //\r
+\r
+    //\r
+    // Generate a time stamp of the seconds from 2000/1/1, assume 30day/month.\r
+    //\r
+    gRT->GetTime (&Time, NULL);\r
+    Stamp = (UINT32)\r
+      (\r
+        (((((Time.Year - 2000) * 360 + (Time.Month - 1)) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) *\r
+        60 +\r
+        Time.Second\r
+      );\r
 \r
-  CopyMem (Duid->Duid + 8, &Mode->CurrentAddress, Mode->HwAddressSize);\r
+    //\r
+    // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes\r
+    //\r
+    Duid = AllocateZeroPool (10 + Mode->HwAddressSize);\r
+    if (Duid == NULL) {\r
+      return NULL;\r
+    }\r
+  \r
+    //\r
+    // sizeof (Duid-type + hardware-type + time) = 8 bytes\r
+    //\r
+    Duid->Length = (UINT16) (Mode->HwAddressSize + 8);\r
+  \r
+    //\r
+    // Set the Duid-type, hardware-type, time and copy the hardware address.\r
+    //\r
+    WriteUnaligned16 ((UINT16 *) (Duid->Duid), HTONS (Dhcp6DuidTypeLlt));\r
+    WriteUnaligned16 ((UINT16 *) (Duid->Duid + 2), HTONS (NET_IFTYPE_ETHERNET));\r
+    WriteUnaligned32 ((UINT32 *) (Duid->Duid + 4), HTONL (Stamp));\r
+  \r
+    CopyMem (Duid->Duid + 8, &Mode->CurrentAddress, Mode->HwAddressSize);\r
+  }\r
 \r
   Status = gRT->SetVariable (\r
                   L"ClientId",\r
@@ -602,6 +647,75 @@ Dhcp6AppendOption (
   return Buf;\r
 }\r
 \r
+/**\r
+  Append the appointed IA Address option to Buf, and move Buf to the end.\r
+\r
+  @param[in, out] Buf           The pointer to the position to append.\r
+  @param[in]      IaAddr        The pointer to the IA Address.\r
+  @param[in]      MessageType   Message type of DHCP6 package.\r
+\r
+  @return         Buf           The position to append the next option.\r
+\r
+**/\r
+UINT8 *\r
+Dhcp6AppendIaAddrOption (\r
+  IN OUT UINT8                  *Buf,\r
+  IN     EFI_DHCP6_IA_ADDRESS   *IaAddr,\r
+  IN     UINT32                 MessageType\r
+)\r
+{\r
+\r
+  //  The format of the IA Address option is:\r
+  //\r
+  //       0                   1                   2                   3\r
+  //       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //      |          OPTION_IAADDR        |          option-len           |\r
+  //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //      |                                                               |\r
+  //      |                         IPv6 address                          |\r
+  //      |                                                               |\r
+  //      |                                                               |\r
+  //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //      |                      preferred-lifetime                       |\r
+  //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //      |                        valid-lifetime                         |\r
+  //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //      .                                                               .\r
+  //      .                        IAaddr-options                         .\r
+  //      .                                                               .\r
+  //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  \r
+  //\r
+  // Fill the value of Ia Address option type\r
+  //\r
+  WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptIaAddr));\r
+  Buf                     += 2;\r
+\r
+  WriteUnaligned16 ((UINT16 *) Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS)));\r
+  Buf                     += 2;\r
+\r
+  CopyMem (Buf, &IaAddr->IpAddress, sizeof(EFI_IPv6_ADDRESS));\r
+  Buf                     += sizeof(EFI_IPv6_ADDRESS);\r
+\r
+  //\r
+  // Fill the value of preferred-lifetime and valid-lifetime.\r
+  // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields\r
+  // should set to 0 when initiate a Confirm message.\r
+  //\r
+  if (MessageType != Dhcp6MsgConfirm) {\r
+    WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->PreferredLifetime));\r
+  }\r
+  Buf                     += 4;\r
+\r
+  if (MessageType != Dhcp6MsgConfirm) {\r
+    WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->ValidLifetime));\r
+  }\r
+  Buf                     += 4;\r
+\r
+  return Buf;\r
+}\r
+\r
 \r
 /**\r
   Append the appointed Ia option to Buf, and move Buf to the end.\r
@@ -610,6 +724,7 @@ Dhcp6AppendOption (
   @param[in]      Ia            The pointer to the Ia.\r
   @param[in]      T1            The time of T1.\r
   @param[in]      T2            The time of T2.\r
+  @param[in]      MessageType   Message type of DHCP6 package.\r
 \r
   @return         Buf           The position to append the next Ia option.\r
 \r
@@ -619,13 +734,13 @@ Dhcp6AppendIaOption (
   IN OUT UINT8                  *Buf,\r
   IN     EFI_DHCP6_IA           *Ia,\r
   IN     UINT32                 T1,\r
-  IN     UINT32                 T2\r
+  IN     UINT32                 T2,\r
+  IN     UINT32                 MessageType\r
   )\r
 {\r
   UINT8                     *AddrOpt;\r
   UINT16                    *Len;\r
   UINTN                     Index;\r
-  UINT16                    Length;\r
 \r
   //\r
   //  The format of IA_NA and IA_TA option:\r
@@ -668,9 +783,9 @@ Dhcp6AppendIaOption (
   // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.\r
   //\r
   if (Ia->Descriptor.Type == Dhcp6OptIana) {\r
-    WriteUnaligned32 ((UINT32 *) Buf, ((T1 != 0) ? T1 : 0xffffffff));\r
+    WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff));\r
     Buf                   += 4;\r
-    WriteUnaligned32 ((UINT32 *) Buf, ((T2 != 0) ? T2 : 0xffffffff));\r
+    WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff));\r
     Buf                   += 4;\r
   }\r
 \r
@@ -678,15 +793,8 @@ Dhcp6AppendIaOption (
   // Fill all the addresses belong to the Ia\r
   //\r
   for (Index = 0; Index < Ia->IaAddressCount; Index++) {\r
-\r
-     AddrOpt = (UINT8 *) Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);\r
-     Length  = HTONS ((UINT16) sizeof (EFI_DHCP6_IA_ADDRESS));\r
-     Buf     = Dhcp6AppendOption (\r
-                 Buf,\r
-                 HTONS (Dhcp6OptIaAddr),\r
-                 Length,\r
-                 AddrOpt\r
-                 );\r
+    AddrOpt = (UINT8 *) Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);\r
+    Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *) AddrOpt, MessageType);\r
   }\r
 \r
   //\r
@@ -782,7 +890,7 @@ SetElapsedTime (
 \r
   //\r
   // Sentinel value of 0 means that this is the first DHCP packet that we are\r
-  // sending and that we need to initialize the value.  First DHCP Solicit\r
+  // sending and that we need to initialize the value.  First DHCP message\r
   // gets 0 elapsed-time.  Otherwise, calculate based on StartTime.\r
   //\r
   if (Instance->StartTime == 0) {\r
@@ -889,10 +997,39 @@ Dhcp6SeekIaOption (
   return Option;\r
 }\r
 \r
+/**\r
+  Check whether the incoming IPv6 address in IaAddr is one of the maintained \r
+  addresses in the IA control blcok.\r
+\r
+  @param[in]  IaAddr            The pointer to the IA Address to be checked.\r
+  @param[in]  CurrentIa         The pointer to the IA in IA control block.\r
+\r
+  @retval     TRUE              Yes, this Address is already in IA control block.\r
+  @retval     FALSE             No, this Address is NOT in IA control block.\r
+\r
+**/\r
+BOOLEAN\r
+Dhcp6AddrIsInCurrentIa (\r
+  IN    EFI_DHCP6_IA_ADDRESS      *IaAddr,\r
+  IN    EFI_DHCP6_IA              *CurrentIa\r
+  )\r
+{\r
+  UINT32    Index;\r
+\r
+  ASSERT (IaAddr != NULL && CurrentIa != NULL);\r
+  \r
+  for (Index = 0; Index < CurrentIa->IaAddressCount; Index++) {\r
+    if (EFI_IP6_EQUAL(&IaAddr->IpAddress, &CurrentIa->IaAddress[Index].IpAddress)) {\r
+      return TRUE;\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
 \r
 /**\r
   Parse the address option and update the address infomation.\r
 \r
+  @param[in]      CurrentIa     The pointer to the Ia Address in control blcok.\r
   @param[in]      IaInnerOpt    The pointer to the buffer.\r
   @param[in]      IaInnerLen    The length to parse.\r
   @param[out]     AddrNum       The number of addresses.\r
@@ -901,6 +1038,7 @@ Dhcp6SeekIaOption (
 **/\r
 VOID\r
 Dhcp6ParseAddrOption (\r
+  IN     EFI_DHCP6_IA            *CurrentIa,\r
   IN     UINT8                   *IaInnerOpt,\r
   IN     UINT16                  IaInnerLen,\r
      OUT UINT32                  *AddrNum,\r
@@ -911,6 +1049,8 @@ Dhcp6ParseAddrOption (
   UINT16                      DataLen;\r
   UINT16                      OpCode;\r
   UINT32                      ValidLt;\r
+  UINT32                      PreferredLt;\r
+  EFI_DHCP6_IA_ADDRESS        *IaAddr;\r
 \r
   //\r
   //  The format of the IA Address option:\r
@@ -947,19 +1087,21 @@ Dhcp6ParseAddrOption (
 \r
   while (Cursor < IaInnerOpt + IaInnerLen) {\r
     //\r
-    // Count the Ia address option with non-0 valid time.\r
+    // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option\r
+    // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time.\r
     //\r
     OpCode  = ReadUnaligned16 ((UINT16 *) Cursor);\r
-    ValidLt = ReadUnaligned32 ((UINT32 *) (Cursor + 24));\r
-    if (OpCode == HTONS (Dhcp6OptIaAddr) && ValidLt != 0) {\r
-\r
+    PreferredLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 20)));\r
+    ValidLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 24)));\r
+    IaAddr = (EFI_DHCP6_IA_ADDRESS *) (Cursor + 4);\r
+    if (OpCode == HTONS (Dhcp6OptIaAddr) && ValidLt >= PreferredLt &&\r
+        (Dhcp6AddrIsInCurrentIa(IaAddr, CurrentIa) || ValidLt !=0)) {\r
       if (AddrBuf != NULL) {\r
-        CopyMem (AddrBuf, Cursor + 4, sizeof (EFI_DHCP6_IA_ADDRESS));\r
-        AddrBuf->PreferredLifetime = NTOHL (AddrBuf->PreferredLifetime);\r
-        AddrBuf->ValidLifetime     = NTOHL (AddrBuf->ValidLifetime);\r
+        CopyMem (AddrBuf, IaAddr, sizeof (EFI_DHCP6_IA_ADDRESS));\r
+        AddrBuf->PreferredLifetime = PreferredLt;\r
+        AddrBuf->ValidLifetime     = ValidLt;\r
         AddrBuf = (EFI_DHCP6_IA_ADDRESS *) ((UINT8 *) AddrBuf + sizeof (EFI_DHCP6_IA_ADDRESS));\r
       }\r
-\r
       (*AddrNum)++;\r
     }\r
     DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));\r
@@ -980,6 +1122,7 @@ Dhcp6ParseAddrOption (
   @retval     EFI_NOT_FOUND         No valid IA option is found.\r
   @retval     EFI_SUCCESS           Create an IA control block successfully.\r
   @retval     EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.\r
+  @retval     EFI_DEVICE_ERROR      An unexpected error.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -996,14 +1139,14 @@ Dhcp6GenerateIaCb (
   EFI_DHCP6_IA                 *Ia;\r
 \r
   if (Instance->IaCb.Ia == NULL) {\r
-    return EFI_NOT_FOUND;\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
   //\r
   // Calculate the number of addresses for this Ia, excluding the addresses with\r
   // the value 0 of valid lifetime.\r
   //\r
-  Dhcp6ParseAddrOption (IaInnerOpt, IaInnerLen, &AddrNum, NULL);\r
+  Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, NULL);\r
 \r
   if (AddrNum == 0) {\r
     return EFI_NOT_FOUND;\r
@@ -1025,7 +1168,7 @@ Dhcp6GenerateIaCb (
   Ia->State          = Instance->IaCb.Ia->State;\r
   Ia->IaAddressCount = AddrNum;\r
   CopyMem (&Ia->Descriptor, &Instance->Config->IaDescriptor, sizeof (EFI_DHCP6_IA_DESCRIPTOR));\r
-  Dhcp6ParseAddrOption (IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress);\r
+  Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress);\r
 \r
   //\r
   // Free original IA resource.\r
@@ -1144,3 +1287,42 @@ Dhcp6AppendCacheIa (
     Instance->IaCb.Ia  = NewIa;\r
   }\r
 }\r
+\r
+/**\r
+  Calculate the Dhcp6 get mapping timeout by adding additinal delay to the IP6 DAD transmits count.\r
+\r
+  @param[in]   Ip6Cfg              The pointer to Ip6 config protocol.\r
+  @param[out]  TimeOut             The time out value in 100ns units.\r
+\r
+  @retval   EFI_INVALID_PARAMETER  Input parameters are invalid.\r
+  @retval   EFI_SUCCESS            Calculate the time out value successfully.\r
+**/\r
+EFI_STATUS\r
+Dhcp6GetMappingTimeOut (\r
+  IN  EFI_IP6_CONFIG_PROTOCOL       *Ip6Cfg,\r
+  OUT UINTN                         *TimeOut\r
+  ) \r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 DataSize;\r
+  EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS    DadXmits;\r
+\r
+  if (Ip6Cfg == NULL || TimeOut == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\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
+    return Status;\r
+  }\r
+  \r
+  *TimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + DHCP6_DAD_ADDITIONAL_DELAY;\r
+  \r
+  return EFI_SUCCESS;\r
+}\r