]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Fix several RFC compliance issues in DHCP6 driver as below.
authorsfu5 <sfu5@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 8 Jan 2013 08:28:11 +0000 (08:28 +0000)
committersfu5 <sfu5@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 8 Jan 2013 08:28:11 +0000 (08:28 +0000)
1. Client must ignore any Advertise message that includes a Status Code option containing the value NoAddrsAvail.
2. The elapsed-time should start from the current DHCP transaction.
3. Client should not change any information about addresses the client has recorded in the IA but not included in the IA from the server.
4. Client need to update to handle the error status code UnspecFail/UseMulticast/NotOnLink/NoBinding in the Reply message from server.
5. When the client receives a Reply message in response to a Renew/ Rebind message, the client examines each IA independently. For each IA in the original Renew/ Rebind message, the client sends a Renew/ Rebind if the IA is not in the Reply message.
6. Client should uses network byte order in IANA T1/T2 option
7. Client should discard any addresses for which the preferred lifetime is greater than the valid lifetime.

Signed-off-by: Fu Siyuan <siyuan.fu@intel.com>
Reviewed-by: Ye Ting <ting.ye@intel.com>
Reviewed-by: Ouyang Qian <qian.ouyang@intel.com>
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@14039 6f19259b-4bc3-4df7-8a09-765794883524

NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c
NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h
NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c
NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h

index 934c03ed859a890ef3fff9841036b11f42ed4ab9..d8c0ad0d24ec7414918264b193462f1e808b8468 100644 (file)
@@ -103,12 +103,6 @@ EfiDhcp6Start (
   OldTpl           = gBS->RaiseTPL (TPL_CALLBACK);\r
   Instance->UdpSts = EFI_ALREADY_STARTED;\r
 \r
-  //\r
-  // Need to clear initial time to make sure that elapsed-time\r
-  // is set to 0 for first Solicit.\r
-  //\r
-  Instance->StartTime = 0;\r
-\r
   //\r
   // Send the solicit message to start S.A.R.R process.\r
   //\r
index 71b16b19199b59ce63bbd12b879fcb79c16f20c4..e3e755316318f747a0399c2ad055f643542920a3 100644 (file)
@@ -249,6 +249,10 @@ struct _DHCP6_INSTANCE {
   volatile EFI_STATUS           UdpSts;\r
   BOOLEAN                       InDestroy;\r
   BOOLEAN                       MediaPresent;\r
+  //\r
+  // StartTime is used to calculate the 'elapsed-time' option. Refer to RFC3315,\r
+  // the elapsed-time is amount of time since the client began its current DHCP transaction. \r
+  //\r
   UINT64                        StartTime;\r
 };\r
 \r
index 0e83d078533cb899b3efda975e4da54f599f70b9..962d9387cab741edac548f3d509723e876a63797 100644 (file)
@@ -593,6 +593,14 @@ Dhcp6UpdateIaInfo (
   if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {\r
     T1 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 8)));\r
     T2 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 12)));\r
+    //\r
+    // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,\r
+    // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes\r
+    // the remainder of the message as though the server had not  included the invalid IA_NA option.\r
+    //\r
+    if (T1 > T2 && T2 > 0) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
     IaInnerOpt = Option + 16;\r
     IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 2))) - 12);\r
   } else {\r
@@ -697,7 +705,7 @@ Dhcp6SeekStsOption (
               &Instance->Config->IaDescriptor\r
               );\r
   if (*Option == NULL) {\r
-    return EFI_DEVICE_ERROR;\r
+    return EFI_SUCCESS;\r
   }\r
 \r
   //\r
@@ -949,7 +957,8 @@ Dhcp6SendSolicitMsg   (
              Cursor,\r
              Instance->IaCb.Ia,\r
              Instance->IaCb.T1,\r
-             Instance->IaCb.T2\r
+             Instance->IaCb.T2,\r
+             Packet->Dhcp6.Header.MessageType\r
              );\r
 \r
   //\r
@@ -987,6 +996,10 @@ Dhcp6SendSolicitMsg   (
   // Dhcp6selecting.\r
   //\r
   Instance->IaCb.Ia->State = Dhcp6Selecting;\r
+  //\r
+  // Clear initial time for current transaction.\r
+  //\r
+  Instance->StartTime = 0;\r
 \r
   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
 \r
@@ -1133,7 +1146,8 @@ Dhcp6SendRequestMsg (
              Cursor,\r
              Instance->IaCb.Ia,\r
              Instance->IaCb.T1,\r
-             Instance->IaCb.T2\r
+             Instance->IaCb.T2,\r
+             Packet->Dhcp6.Header.MessageType\r
              );\r
 \r
   //\r
@@ -1171,6 +1185,10 @@ Dhcp6SendRequestMsg (
   // Dhcp6requesting.\r
   //\r
   Instance->IaCb.Ia->State = Dhcp6Requesting;\r
+  //\r
+  // Clear initial time for current transaction.\r
+  //\r
+  Instance->StartTime = 0;\r
 \r
   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
 \r
@@ -1282,7 +1300,7 @@ Dhcp6SendDeclineMsg (
              ServerId->Duid\r
              );\r
 \r
-  Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0);\r
+  Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType);\r
 \r
   //\r
   // Determine the size/length of packet.\r
@@ -1305,6 +1323,10 @@ Dhcp6SendDeclineMsg (
   // Dhcp6declining.\r
   //\r
   Instance->IaCb.Ia->State = Dhcp6Declining;\r
+  //\r
+  // Clear initial time for current transaction.\r
+  //\r
+  Instance->StartTime = 0;\r
 \r
   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
 \r
@@ -1415,7 +1437,7 @@ Dhcp6SendReleaseMsg (
              &Elapsed\r
              );\r
 \r
-  Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0);\r
+  Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType);\r
 \r
   //\r
   // Determine the size/length of packet\r
@@ -1540,7 +1562,8 @@ Dhcp6SendRenewRebindMsg (
              Cursor,\r
              Instance->IaCb.Ia,\r
              Instance->IaCb.T1,\r
-             Instance->IaCb.T2\r
+             Instance->IaCb.T2,\r
+             Packet->Dhcp6.Header.MessageType\r
              );\r
 \r
   if (!RebindRequest) {\r
@@ -1612,6 +1635,10 @@ Dhcp6SendRenewRebindMsg (
   //\r
   Instance->IaCb.Ia->State = State;\r
   Instance->IaCb.LeaseTime = (RebindRequest) ? Instance->IaCb.T2 : Instance->IaCb.T1;\r
+  //\r
+  // Clear initial time for current transaction.\r
+  //\r
+  Instance->StartTime = 0;\r
 \r
   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
 \r
@@ -1844,6 +1871,11 @@ Dhcp6SendInfoRequestMsg (
   //\r
   Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);\r
   ASSERT (Packet->Size > Packet->Length + 8);\r
+  \r
+  //\r
+  // Clear initial time for current transaction.\r
+  //\r
+  Instance->StartTime = 0;\r
 \r
   //\r
   // Send info-request packet with no state.\r
@@ -1941,7 +1973,8 @@ Dhcp6SendConfirmMsg (
              Cursor,\r
              Instance->IaCb.Ia,\r
              Instance->IaCb.T1,\r
-             Instance->IaCb.T2\r
+             Instance->IaCb.T2,\r
+             Packet->Dhcp6.Header.MessageType\r
              );\r
 \r
   //\r
@@ -1978,6 +2011,10 @@ Dhcp6SendConfirmMsg (
   // Dhcp6Confirming.\r
   //\r
   Instance->IaCb.Ia->State = Dhcp6Confirming;\r
+  //\r
+  // Clear initial time for current transaction.\r
+  //\r
+  Instance->StartTime = 0;\r
 \r
   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
 \r
@@ -2020,6 +2057,8 @@ Dhcp6HandleReplyMsg (
   ASSERT (Instance->IaCb.Ia != NULL);\r
   ASSERT (Packet != NULL);\r
 \r
+  Status = EFI_SUCCESS;\r
+\r
   if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
@@ -2056,7 +2095,7 @@ Dhcp6HandleReplyMsg (
                &Instance->Config->IaDescriptor\r
                );\r
     if (Option == NULL) {\r
-      return EFI_DEVICE_ERROR;\r
+      return EFI_SUCCESS;\r
     }\r
   }\r
 \r
@@ -2069,19 +2108,6 @@ Dhcp6HandleReplyMsg (
     return Status;\r
   }\r
 \r
-  //\r
-  // Dequeue the sent packet from retransmit list since reply received.\r
-  //\r
-  Status = Dhcp6DequeueRetry (\r
-             Instance,\r
-             Packet->Dhcp6.Header.TransactionId,\r
-             FALSE\r
-             );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
   //\r
   // When receive a valid reply packet in response to a decline/release packet,\r
   // the client considers the decline/release event completed regardless of the\r
@@ -2115,7 +2141,8 @@ Dhcp6HandleReplyMsg (
     //\r
     Instance->StartTime       = 0;\r
 \r
-    return EFI_SUCCESS;\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
   }\r
 \r
   //\r
@@ -2131,56 +2158,64 @@ Dhcp6HandleReplyMsg (
              );\r
 \r
   if (!EFI_ERROR (Status)) {\r
-    //\r
-    // Reset start time for next exchange.\r
-    //\r
-    Instance->StartTime       = 0;\r
-\r
     //\r
     // No status code or no error status code means succeed to reply.\r
     //\r
     Status = Dhcp6UpdateIaInfo (Instance, Packet);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Reset start time for next exchange.\r
+      //\r
+      Instance->StartTime       = 0;\r
 \r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-\r
-    //\r
-    // Set bound state and store the reply packet.\r
-    //\r
-    if (Instance->IaCb.Ia->ReplyPacket != NULL) {\r
-      FreePool (Instance->IaCb.Ia->ReplyPacket);\r
-    }\r
+      //\r
+      // Set bound state and store the reply packet.\r
+      //\r
+      if (Instance->IaCb.Ia->ReplyPacket != NULL) {\r
+        FreePool (Instance->IaCb.Ia->ReplyPacket);\r
+      }\r
 \r
-    Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);\r
+      Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);\r
 \r
-    if (Instance->IaCb.Ia->ReplyPacket == NULL) {\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }\r
+      if (Instance->IaCb.Ia->ReplyPacket == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto ON_EXIT;\r
+      }\r
 \r
-    CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);\r
+      CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);\r
 \r
-    Instance->IaCb.Ia->State = Dhcp6Bound;\r
+      Instance->IaCb.Ia->State = Dhcp6Bound;\r
 \r
-    //\r
-    // For sync, set the success flag out of polling in start/renewrebind.\r
-    //\r
-    Instance->UdpSts         = EFI_SUCCESS;\r
+      //\r
+      // For sync, set the success flag out of polling in start/renewrebind.\r
+      //\r
+      Instance->UdpSts         = EFI_SUCCESS;\r
 \r
-    //\r
-    // Maybe this is a new round DHCP process due to some reason, such as NotOnLink\r
-    // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that\r
-    // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP\r
-    // consumers can be notified to flush old address.\r
-    //\r
-    Dhcp6AppendCacheIa (Instance);\r
+      //\r
+      // Maybe this is a new round DHCP process due to some reason, such as NotOnLink\r
+      // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that\r
+      // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP\r
+      // consumers can be notified to flush old address.\r
+      //\r
+      Dhcp6AppendCacheIa (Instance);\r
 \r
-    //\r
-    // For async, signal the Ia event to inform Ia infomation update.\r
-    //\r
-    if (Instance->Config->IaInfoEvent != NULL) {\r
-      gBS->SignalEvent (Instance->Config->IaInfoEvent);\r
+      //\r
+      // For async, signal the Ia event to inform Ia infomation update.\r
+      //\r
+      if (Instance->Config->IaInfoEvent != NULL) {\r
+        gBS->SignalEvent (Instance->Config->IaInfoEvent);\r
+      }\r
+    } else if (Status == EFI_NOT_FOUND) {\r
+      //\r
+      // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, \r
+      // the client sends a Renew or Rebind if the IA is not in the Reply message.\r
+      // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.\r
+      //\r
+      return EFI_SUCCESS;\r
     }\r
+    \r
+    goto ON_EXIT;\r
+    \r
   } else if (Option != NULL) {\r
     //\r
     // Any error status code option is found.\r
@@ -2226,6 +2261,19 @@ Dhcp6HandleReplyMsg (
       }\r
       break;\r
 \r
+    case Dhcp6StsNoBinding:\r
+      if (Instance->IaCb.Ia->State == Dhcp6Renewing || Instance->IaCb.Ia->State == Dhcp6Rebinding) {\r
+        //\r
+        // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client \r
+        // sends a Request message if the IA contained a Status Code option with the NoBinding status.\r
+        //\r
+        Status = Dhcp6SendRequestMsg(Instance);\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+      }\r
+      break;\r
+\r
     default:\r
       //\r
       // The other status code, just restart solicitation.\r
@@ -2235,6 +2283,18 @@ Dhcp6HandleReplyMsg (
   }\r
 \r
   return EFI_SUCCESS;\r
+  \r
+ON_EXIT:\r
+\r
+  if (!EFI_ERROR(Status)) {\r
+    Status = Dhcp6DequeueRetry (\r
+               Instance,\r
+               Packet->Dhcp6.Header.TransactionId,\r
+               FALSE\r
+               );\r
+  }\r
+  \r
+  return Status;\r
 }\r
 \r
 \r
@@ -2378,17 +2438,13 @@ Dhcp6HandleAdvertiseMsg (
   // display the associated status message to the user.\r
   // See the details in the section-17.1.3 of rfc-3315.\r
   //\r
-  Option = Dhcp6SeekOption(\r
-             Packet->Dhcp6.Option,\r
-             Packet->Length - 4,\r
-             Dhcp6OptStatusCode\r
+  Status = Dhcp6SeekStsOption (\r
+             Instance,\r
+             Packet,\r
+             &Option\r
              );\r
-\r
-  if (Option != NULL) {\r
-    StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4)));\r
-    if (StsCode != Dhcp6StsSuccess) {\r
-      return EFI_DEVICE_ERROR;\r
-    }\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
   //\r
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
index 2a44d0068fda1a41d13614b8b8bae664f1987937..8c3151e306c0558adfd1bf0162d7d1a5d3e1180d 100644 (file)
@@ -192,6 +192,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
@@ -201,7 +202,8 @@ 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
 /**\r
@@ -274,6 +276,7 @@ Dhcp6SeekIaOption (
 /**\r
   Parse the address option and update the address info.\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
@@ -282,6 +285,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
@@ -300,6 +304,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