]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
NetworkPkg: Clean up source files
[mirror_edk2.git] / NetworkPkg / Dhcp6Dxe / Dhcp6Io.c
index cca1468683782a58f1c43c55c16ee1dcda551f53..5ad2ac38bf89376bb716d8084d53470c1386b6ed 100644 (file)
@@ -1,7 +1,8 @@
 /** @file\r
   Dhcp6 internal functions implementation.\r
 \r
-  Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+  Copyright (c) 2009 - 2018, 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
@@ -52,7 +53,7 @@ Dhcp6EnqueueRetry (
   }\r
 \r
   //\r
-  // Save tx packet pointer, and it will be destoryed when reply received.\r
+  // Save tx packet pointer, and it will be destroyed when reply received.\r
   //\r
   TxCb->TxPacket = Packet;\r
   TxCb->Xid      = Packet->Dhcp6.Header.TransactionId;\r
@@ -363,6 +364,32 @@ Dhcp6CleanupRetry (
   }\r
 }\r
 \r
+/**\r
+  Check whether the TxCb is still a valid control block in the instance's retry list.\r
+\r
+  @param[in]  Instance       The pointer to DHCP6_INSTANCE.\r
+  @param[in]  TxCb           The control block for a transmitted message.\r
+\r
+  @retval   TRUE      The control block is in Instance's retry list.\r
+  @retval   FALSE     The control block is NOT in Instance's retry list.\r
+\r
+**/\r
+BOOLEAN\r
+Dhcp6IsValidTxCb (\r
+  IN  DHCP6_INSTANCE          *Instance,\r
+  IN  DHCP6_TX_CB             *TxCb\r
+  )\r
+{\r
+  LIST_ENTRY                *Entry;\r
+\r
+  NET_LIST_FOR_EACH (Entry, &Instance->TxList) {\r
+    if (TxCb == NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link)) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
 \r
 /**\r
   Clean up the session of the instance stateful exchange.\r
@@ -518,7 +545,6 @@ Dhcp6UpdateIaInfo (
   )\r
 {\r
   EFI_STATUS                  Status;\r
-  EFI_DHCP6_STATE             State;\r
   UINT8                       *Option;\r
   UINT8                       *IaInnerOpt;\r
   UINT16                      IaInnerLen;\r
@@ -539,7 +565,6 @@ Dhcp6UpdateIaInfo (
   //\r
   // See details in the section-18.1.8 of rfc-3315.\r
   //\r
-  State  = Dhcp6Init;\r
   Option = Dhcp6SeekIaOption (\r
              Packet->Dhcp6.Option,\r
              Packet->Length - sizeof (EFI_DHCP6_HEADER),\r
@@ -593,6 +618,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 +730,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 +982,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 +1021,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 +1171,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 +1210,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 +1325,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 +1348,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 +1462,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 +1587,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 +1660,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
@@ -1626,6 +1678,106 @@ Dhcp6SendRenewRebindMsg (
   return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
 }\r
 \r
+/**\r
+  Start the information request process.\r
+\r
+  @param[in]  Instance          The pointer to the Dhcp6 instance.\r
+  @param[in]  SendClientId      If TRUE, the client identifier option will be included in\r
+                                information request message. Otherwise, the client identifier\r
+                                option will not be included.\r
+  @param[in]  OptionRequest     The pointer to the option request option.\r
+  @param[in]  OptionCount       The number options in the OptionList.\r
+  @param[in]  OptionList        The array pointers to the appended options.\r
+  @param[in]  Retransmission    The pointer to the retransmission control.\r
+  @param[in]  TimeoutEvent      The event of timeout.\r
+  @param[in]  ReplyCallback     The callback function when the reply was received.\r
+  @param[in]  CallbackContext   The pointer to the parameter passed to the callback.\r
+\r
+  @retval EFI_SUCCESS           Start the info-request process successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.\r
+  @retval EFI_NO_MAPPING        No source address is available for use.\r
+  @retval Others                Failed to start the info-request process.\r
+\r
+**/\r
+EFI_STATUS\r
+Dhcp6StartInfoRequest (\r
+  IN DHCP6_INSTANCE            *Instance,\r
+  IN BOOLEAN                   SendClientId,\r
+  IN EFI_DHCP6_PACKET_OPTION   *OptionRequest,\r
+  IN UINT32                    OptionCount,\r
+  IN EFI_DHCP6_PACKET_OPTION   *OptionList[]    OPTIONAL,\r
+  IN EFI_DHCP6_RETRANSMISSION  *Retransmission,\r
+  IN EFI_EVENT                 TimeoutEvent     OPTIONAL,\r
+  IN EFI_DHCP6_INFO_CALLBACK   ReplyCallback,\r
+  IN VOID                      *CallbackContext OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  DHCP6_INF_CB                 *InfCb;\r
+  DHCP6_SERVICE                *Service;\r
+  EFI_TPL                      OldTpl;\r
+\r
+  Service  = Instance->Service;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  Instance->UdpSts = EFI_ALREADY_STARTED;\r
+  //\r
+  // Create and initialize the control block for the info-request.\r
+  //\r
+  InfCb = AllocateZeroPool (sizeof(DHCP6_INF_CB));\r
+\r
+  if (InfCb == NULL) {\r
+    gBS->RestoreTPL (OldTpl);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  InfCb->ReplyCallback   = ReplyCallback;\r
+  InfCb->CallbackContext = CallbackContext;\r
+  InfCb->TimeoutEvent    = TimeoutEvent;\r
+\r
+  InsertTailList (&Instance->InfList, &InfCb->Link);\r
+\r
+  //\r
+  // Send the info-request message to start exchange process.\r
+  //\r
+  Status = Dhcp6SendInfoRequestMsg (\r
+             Instance,\r
+             InfCb,\r
+             SendClientId,\r
+             OptionRequest,\r
+             OptionCount,\r
+             OptionList,\r
+             Retransmission\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Register receive callback for the stateless exchange process.\r
+  //\r
+  Status = UdpIoRecvDatagram(\r
+             Service->UdpIo,\r
+             Dhcp6ReceivePacket,\r
+             Service,\r
+             0\r
+             );\r
+\r
+  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  gBS->RestoreTPL (OldTpl);\r
+  RemoveEntryList (&InfCb->Link);\r
+  FreePool (InfCb);\r
+\r
+  return Status;\r
+}\r
 \r
 /**\r
   Create the information request message and send it.\r
@@ -1745,6 +1897,11 @@ Dhcp6SendInfoRequestMsg (
   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
   //\r
@@ -1841,7 +1998,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
@@ -1878,6 +2036,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
@@ -1920,6 +2082,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
@@ -1956,7 +2120,7 @@ Dhcp6HandleReplyMsg (
                &Instance->Config->IaDescriptor\r
                );\r
     if (Option == NULL) {\r
-      return EFI_DEVICE_ERROR;\r
+      return EFI_SUCCESS;\r
     }\r
   }\r
 \r
@@ -1969,19 +2133,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
@@ -2015,7 +2166,8 @@ Dhcp6HandleReplyMsg (
     //\r
     Instance->StartTime       = 0;\r
 \r
-    return EFI_SUCCESS;\r
+    Status = EFI_SUCCESS;\r
+    goto ON_EXIT;\r
   }\r
 \r
   //\r
@@ -2031,56 +2183,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
@@ -2126,6 +2286,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
@@ -2135,6 +2308,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
@@ -2242,14 +2427,12 @@ Dhcp6HandleAdvertiseMsg (
 {\r
   EFI_STATUS                  Status;\r
   UINT8                       *Option;\r
-  UINT16                      StsCode;\r
   BOOLEAN                     Timeout;\r
 \r
   ASSERT(Instance->Config);\r
   ASSERT(Instance->IaCb.Ia);\r
 \r
   Timeout = FALSE;\r
-  StsCode = Dhcp6StsSuccess;\r
 \r
   //\r
   // If the client does receives a valid reply message that includes a rapid\r
@@ -2278,17 +2461,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
@@ -2410,7 +2589,7 @@ Dhcp6HandleStateful (
   ClientId = Service->ClientId;\r
   Status   = EFI_SUCCESS;\r
 \r
-  if (Instance->InDestory || Instance->Config == NULL) {\r
+  if (Instance->Config == NULL) {\r
     goto ON_CONTINUE;\r
   }\r
 \r
@@ -2524,10 +2703,6 @@ Dhcp6HandleStateless (
   IsMatched = FALSE;\r
   InfCb     = NULL;\r
 \r
-  if (Instance->InDestory) {\r
-    goto ON_EXIT;\r
-  }\r
-\r
   if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {\r
     goto ON_EXIT;\r
   }\r
@@ -2637,6 +2812,7 @@ Dhcp6ReceivePacket (
   LIST_ENTRY                *Next1;\r
   LIST_ENTRY                *Entry2;\r
   LIST_ENTRY                *Next2;\r
+  EFI_STATUS                Status;\r
 \r
   ASSERT (Udp6Wrap != NULL);\r
   ASSERT (Context != NULL);\r
@@ -2651,6 +2827,10 @@ Dhcp6ReceivePacket (
     return ;\r
   }\r
 \r
+  if (Udp6Wrap->TotalSize < sizeof (EFI_DHCP6_HEADER)) {\r
+    goto ON_CONTINUE;\r
+  }\r
+\r
   //\r
   // Copy the net buffer received from upd6 to a Dhcp6 packet.\r
   //\r
@@ -2716,6 +2896,21 @@ Dhcp6ReceivePacket (
 \r
 ON_CONTINUE:\r
 \r
+  if (!IsDispatched) {\r
+    Status = UdpIoRecvDatagram (\r
+             Service->UdpIo,\r
+             Dhcp6ReceivePacket,\r
+             Service,\r
+             0\r
+             );\r
+    if (EFI_ERROR (Status)) {\r
+      NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) {\r
+        Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link);\r
+        Dhcp6CleanupRetry (Instance, DHCP6_PACKET_ALL);\r
+      }\r
+    }\r
+  }\r
+\r
   NetbufFree (Udp6Wrap);\r
 \r
   if (Packet != NULL) {\r
@@ -2817,7 +3012,7 @@ Dhcp6OnTimerTick (
       //\r
       // Handle the first rt in the transmission of solicit specially.\r
       //\r
-      if (TxCb->RetryCnt == 0 && TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) {\r
+      if ((TxCb->RetryCnt == 0 || TxCb->SolicitRetry) && TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) {\r
         if (Instance->AdSelect == NULL) {\r
           //\r
           // Set adpref as 0xff here to indicate select any advertisement\r
@@ -2829,7 +3024,9 @@ Dhcp6OnTimerTick (
           // Select the advertisement received before.\r
           //\r
           Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);\r
-          if (EFI_ERROR (Status)) {\r
+          if (Status == EFI_ABORTED) {\r
+            goto ON_CLOSE;\r
+          } else if (EFI_ERROR (Status)) {\r
             TxCb->RetryCnt++;\r
           }\r
           return;\r
@@ -2845,6 +3042,7 @@ Dhcp6OnTimerTick (
       // Check whether overflow the max retry count limit for this packet\r
       //\r
       if (TxCb->RetryCtl.Mrc != 0 && TxCb->RetryCtl.Mrc < TxCb->RetryCnt) {\r
+        Status = EFI_NO_RESPONSE;\r
         goto ON_CLOSE;\r
       }\r
 \r
@@ -2852,6 +3050,7 @@ Dhcp6OnTimerTick (
       // Check whether overflow the max retry duration for this packet\r
       //\r
       if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd <= TxCb->RetryLos) {\r
+        Status = EFI_NO_RESPONSE;\r
         goto ON_CLOSE;\r
       }\r
 \r
@@ -2893,6 +3092,10 @@ Dhcp6OnTimerTick (
       // Retransmit the last sent packet again.\r
       //\r
       Dhcp6TransmitPacket (Instance, TxCb->TxPacket, TxCb->Elapsed);\r
+      TxCb->SolicitRetry = FALSE;\r
+      if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) {\r
+        TxCb->SolicitRetry = TRUE;\r
+      }\r
     }\r
   }\r
 \r
@@ -2937,9 +3140,11 @@ Dhcp6OnTimerTick (
 \r
  ON_CLOSE:\r
 \r
-  if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest ||\r
+  if (Dhcp6IsValidTxCb (Instance, TxCb) &&\r
+      TxCb->TxPacket != NULL &&\r
+      (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest ||\r
       TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew       ||\r
-      TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm\r
+      TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm)\r
       ) {\r
     //\r
     // The failure of renew/Confirm will still switch to the bound state.\r
@@ -2964,6 +3169,6 @@ Dhcp6OnTimerTick (
     //\r
     // The failure of the others will terminate current state machine if timeout.\r
     //\r
-    Dhcp6CleanupSession (Instance, EFI_NO_RESPONSE);\r
+    Dhcp6CleanupSession (Instance, Status);\r
   }\r
 }\r