]> 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 4c32028680d078dede26e225b73e24b3dd110425..32247c927b0a63a6b89af29be80c24cb0950bd5e 100644 (file)
@@ -647,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
@@ -655,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
@@ -664,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
@@ -713,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
@@ -723,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
@@ -827,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
@@ -934,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
@@ -946,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
@@ -956,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
@@ -992,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
@@ -1025,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
@@ -1041,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
@@ -1070,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