Home | History | Annotate | Download | only in Dhcp6Dxe
      1 /** @file
      2   Dhcp6 internal functions implementation.
      3 
      4   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
      6 
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php.
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "Dhcp6Impl.h"
     18 
     19 
     20 /**
     21   Enqueue the packet into the retry list in case of timeout.
     22 
     23   @param[in]  Instance        The pointer to the Dhcp6 instance.
     24   @param[in]  Packet          The pointer to the Dhcp6 packet to retry.
     25   @param[in]  Elapsed         The pointer to the elapsed time value in the packet.
     26   @param[in]  RetryCtl        The pointer to the transmission control of the packet.
     27                               This parameter is optional and may be NULL.
     28 
     29   @retval EFI_SUCCESS           Successfully enqueued the packet into the retry list according
     30                                 to its message type.
     31   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
     32   @retval EFI_DEVICE_ERROR      An unexpected message type.
     33 
     34 **/
     35 EFI_STATUS
     36 Dhcp6EnqueueRetry (
     37   IN DHCP6_INSTANCE            *Instance,
     38   IN EFI_DHCP6_PACKET          *Packet,
     39   IN UINT16                    *Elapsed,
     40   IN EFI_DHCP6_RETRANSMISSION  *RetryCtl     OPTIONAL
     41   )
     42 {
     43   DHCP6_TX_CB                  *TxCb;
     44   DHCP6_IA_CB                  *IaCb;
     45 
     46   ASSERT (Packet != NULL);
     47 
     48   IaCb = &Instance->IaCb;
     49   TxCb = AllocateZeroPool (sizeof (DHCP6_TX_CB));
     50 
     51   if (TxCb == NULL) {
     52     return EFI_OUT_OF_RESOURCES;
     53   }
     54 
     55   //
     56   // Save tx packet pointer, and it will be destroyed when reply received.
     57   //
     58   TxCb->TxPacket = Packet;
     59   TxCb->Xid      = Packet->Dhcp6.Header.TransactionId;
     60 
     61   //
     62   // Save pointer to elapsed-time value so we can update it on retransmits.
     63   //
     64   TxCb->Elapsed  = Elapsed;
     65 
     66   //
     67   // Calculate the retransmission according to the the message type.
     68   //
     69   switch (Packet->Dhcp6.Header.MessageType) {
     70   case Dhcp6MsgSolicit:
     71     //
     72     // Calculate the retransmission threshold value for solicit packet.
     73     // Use the default value by rfc-3315 if user doesn't configure.
     74     //
     75     if (RetryCtl == NULL) {
     76       TxCb->RetryCtl.Irt = DHCP6_SOL_IRT;
     77       TxCb->RetryCtl.Mrc = DHCP6_SOL_MRC;
     78       TxCb->RetryCtl.Mrt = DHCP6_SOL_MRT;
     79       TxCb->RetryCtl.Mrd = DHCP6_SOL_MRD;
     80     } else {
     81       TxCb->RetryCtl.Irt = (RetryCtl->Irt != 0) ? RetryCtl->Irt : DHCP6_SOL_IRT;
     82       TxCb->RetryCtl.Mrc = (RetryCtl->Mrc != 0) ? RetryCtl->Mrc : DHCP6_SOL_MRC;
     83       TxCb->RetryCtl.Mrt = (RetryCtl->Mrt != 0) ? RetryCtl->Mrt : DHCP6_SOL_MRT;
     84       TxCb->RetryCtl.Mrd = (RetryCtl->Mrd != 0) ? RetryCtl->Mrd : DHCP6_SOL_MRD;
     85     }
     86 
     87     TxCb->RetryExp       = Dhcp6CalculateExpireTime (
     88                              TxCb->RetryCtl.Irt,
     89                              TRUE,
     90                              FALSE
     91                              );
     92     break;
     93 
     94   case Dhcp6MsgRequest:
     95     //
     96     // Calculate the retransmission threshold value for request packet.
     97     //
     98     TxCb->RetryCtl.Irt = DHCP6_REQ_IRT;
     99     TxCb->RetryCtl.Mrc = DHCP6_REQ_MRC;
    100     TxCb->RetryCtl.Mrt = DHCP6_REQ_MRT;
    101     TxCb->RetryCtl.Mrd = DHCP6_REQ_MRD;
    102     TxCb->RetryExp     = Dhcp6CalculateExpireTime (
    103                            TxCb->RetryCtl.Irt,
    104                            TRUE,
    105                            TRUE
    106                            );
    107     break;
    108 
    109   case Dhcp6MsgConfirm:
    110     //
    111     // Calculate the retransmission threshold value for confirm packet.
    112     //
    113     TxCb->RetryCtl.Irt = DHCP6_CNF_IRT;
    114     TxCb->RetryCtl.Mrc = DHCP6_CNF_MRC;
    115     TxCb->RetryCtl.Mrt = DHCP6_CNF_MRT;
    116     TxCb->RetryCtl.Mrd = DHCP6_CNF_MRD;
    117     TxCb->RetryExp     = Dhcp6CalculateExpireTime (
    118                            TxCb->RetryCtl.Irt,
    119                            TRUE,
    120                            TRUE
    121                            );
    122     break;
    123 
    124   case Dhcp6MsgRenew:
    125     //
    126     // Calculate the retransmission threshold value for renew packet.
    127     //
    128     TxCb->RetryCtl.Irt = DHCP6_REB_IRT;
    129     TxCb->RetryCtl.Mrc = DHCP6_REB_MRC;
    130     TxCb->RetryCtl.Mrt = DHCP6_REB_MRT;
    131     TxCb->RetryCtl.Mrd = IaCb->T2 - IaCb->T1;
    132     TxCb->RetryExp     = Dhcp6CalculateExpireTime (
    133                            TxCb->RetryCtl.Irt,
    134                            TRUE,
    135                            TRUE
    136                            );
    137     break;
    138 
    139   case Dhcp6MsgRebind:
    140     //
    141     // Calculate the retransmission threshold value for rebind packet.
    142     //
    143     TxCb->RetryCtl.Irt = DHCP6_REN_IRT;
    144     TxCb->RetryCtl.Mrc = DHCP6_REN_MRC;
    145     TxCb->RetryCtl.Mrt = DHCP6_REN_MRT;
    146     TxCb->RetryCtl.Mrd = IaCb->AllExpireTime - IaCb->T2;
    147     TxCb->RetryExp     = Dhcp6CalculateExpireTime (
    148                            TxCb->RetryCtl.Irt,
    149                            TRUE,
    150                            TRUE
    151                            );
    152     break;
    153 
    154   case Dhcp6MsgDecline:
    155     //
    156     // Calculate the retransmission threshold value for decline packet.
    157     //
    158     TxCb->RetryCtl.Irt = DHCP6_DEC_IRT;
    159     TxCb->RetryCtl.Mrc = DHCP6_DEC_MRC;
    160     TxCb->RetryCtl.Mrt = DHCP6_DEC_MRT;
    161     TxCb->RetryCtl.Mrd = DHCP6_DEC_MRD;
    162     TxCb->RetryExp     = Dhcp6CalculateExpireTime (
    163                            TxCb->RetryCtl.Irt,
    164                            TRUE,
    165                            TRUE
    166                            );
    167     break;
    168 
    169   case Dhcp6MsgRelease:
    170     //
    171     // Calculate the retransmission threshold value for release packet.
    172     //
    173     TxCb->RetryCtl.Irt = DHCP6_REL_IRT;
    174     TxCb->RetryCtl.Mrc = DHCP6_REL_MRC;
    175     TxCb->RetryCtl.Mrt = DHCP6_REL_MRT;
    176     TxCb->RetryCtl.Mrd = DHCP6_REL_MRD;
    177     TxCb->RetryExp     = Dhcp6CalculateExpireTime (
    178                            TxCb->RetryCtl.Irt,
    179                            TRUE,
    180                            TRUE
    181                            );
    182     break;
    183 
    184   case Dhcp6MsgInfoRequest:
    185     //
    186     // Calculate the retransmission threshold value for info-request packet.
    187     // Use the default value by rfc-3315 if user doesn't configure.
    188     //
    189     if (RetryCtl == NULL) {
    190       TxCb->RetryCtl.Irt = DHCP6_INF_IRT;
    191       TxCb->RetryCtl.Mrc = DHCP6_INF_MRC;
    192       TxCb->RetryCtl.Mrt = DHCP6_INF_MRT;
    193       TxCb->RetryCtl.Mrd = DHCP6_INF_MRD;
    194     } else {
    195       TxCb->RetryCtl.Irt = (RetryCtl->Irt != 0) ? RetryCtl->Irt : DHCP6_INF_IRT;
    196       TxCb->RetryCtl.Mrc = (RetryCtl->Mrc != 0) ? RetryCtl->Mrc : DHCP6_INF_MRC;
    197       TxCb->RetryCtl.Mrt = (RetryCtl->Mrt != 0) ? RetryCtl->Mrt : DHCP6_INF_MRT;
    198       TxCb->RetryCtl.Mrd = (RetryCtl->Mrd != 0) ? RetryCtl->Mrd : DHCP6_INF_MRD;
    199     }
    200 
    201     TxCb->RetryExp       = Dhcp6CalculateExpireTime (
    202                              TxCb->RetryCtl.Irt,
    203                              TRUE,
    204                              TRUE
    205                              );
    206     break;
    207 
    208   default:
    209     //
    210     // Unexpected message type.
    211     //
    212     return EFI_DEVICE_ERROR;
    213   }
    214 
    215   //
    216   // Insert into the retransmit list of the instance.
    217   //
    218   InsertTailList (&Instance->TxList, &TxCb->Link);
    219 
    220   return EFI_SUCCESS;
    221 }
    222 
    223 
    224 /**
    225   Dequeue the packet from retry list if reply received or timeout at last.
    226 
    227   @param[in]  Instance        The pointer to the Dhcp6 instance.
    228   @param[in]  PacketXid       The packet transaction id to match.
    229   @param[in]  NeedSignal      If TRUE, then an timeout event need be signaled when it is existed.
    230                               Otherwise, this parameter is ignored.
    231 
    232   @retval EFI_SUCCESS         Successfully dequeued the packet into retry list .
    233   @retval EFI_NOT_FOUND       There is no xid matched in retry list.
    234 
    235 **/
    236 EFI_STATUS
    237 Dhcp6DequeueRetry (
    238   IN DHCP6_INSTANCE         *Instance,
    239   IN UINT32                 PacketXid,
    240   IN BOOLEAN                NeedSignal
    241   )
    242 {
    243   LIST_ENTRY                *Entry;
    244   LIST_ENTRY                *NextEntry;
    245   DHCP6_TX_CB               *TxCb;
    246   DHCP6_INF_CB              *InfCb;
    247 
    248   //
    249   // Seek the retransmit node in the retransmit list by packet xid.
    250   //
    251   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {
    252 
    253     TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);
    254     ASSERT(TxCb->TxPacket);
    255 
    256     if (TxCb->Xid == PacketXid) {
    257 
    258       if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
    259 
    260         //
    261         // Seek the info-request node in the info-request list by packet xid.
    262         //
    263         NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->InfList) {
    264 
    265           InfCb = NET_LIST_USER_STRUCT (Entry, DHCP6_INF_CB, Link);
    266 
    267           if (InfCb->Xid == PacketXid) {
    268             //
    269             // Remove the info-request node, and signal the event if timeout.
    270             //
    271             if (InfCb->TimeoutEvent != NULL && NeedSignal) {
    272               gBS->SignalEvent (InfCb->TimeoutEvent);
    273             }
    274 
    275             RemoveEntryList (&InfCb->Link);
    276             FreePool (InfCb);
    277           }
    278         }
    279       }
    280       //
    281       // Remove the retransmit node.
    282       //
    283       RemoveEntryList (&TxCb->Link);
    284       ASSERT(TxCb->TxPacket);
    285       FreePool (TxCb->TxPacket);
    286       FreePool (TxCb);
    287       return EFI_SUCCESS;
    288     }
    289   }
    290 
    291   return EFI_NOT_FOUND;
    292 }
    293 
    294 
    295 /**
    296   Clean up the specific nodes in the retry list.
    297 
    298   @param[in]  Instance        The pointer to the Dhcp6 instance.
    299   @param[in]  Scope           The scope of cleanup nodes.
    300 
    301 **/
    302 VOID
    303 Dhcp6CleanupRetry (
    304   IN DHCP6_INSTANCE         *Instance,
    305   IN UINT32                 Scope
    306   )
    307 {
    308   LIST_ENTRY                *Entry;
    309   LIST_ENTRY                *NextEntry;
    310   DHCP6_TX_CB               *TxCb;
    311   DHCP6_INF_CB              *InfCb;
    312 
    313   //
    314   // Clean up all the stateful messages from the retransmit list.
    315   //
    316   if (Scope == DHCP6_PACKET_STATEFUL || Scope == DHCP6_PACKET_ALL) {
    317 
    318     NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {
    319 
    320       TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);
    321       ASSERT(TxCb->TxPacket);
    322 
    323       if (TxCb->TxPacket->Dhcp6.Header.MessageType != Dhcp6MsgInfoRequest) {
    324         RemoveEntryList (&TxCb->Link);
    325         FreePool (TxCb->TxPacket);
    326         FreePool (TxCb);
    327       }
    328     }
    329   }
    330 
    331   //
    332   // Clean up all the stateless messages from the retransmit list.
    333   //
    334   if (Scope == DHCP6_PACKET_STATELESS || Scope == DHCP6_PACKET_ALL) {
    335 
    336     //
    337     // Clean up all the retransmit list for stateless messages.
    338     //
    339     NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {
    340 
    341       TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);
    342       ASSERT(TxCb->TxPacket);
    343 
    344       if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
    345         RemoveEntryList (&TxCb->Link);
    346         FreePool (TxCb->TxPacket);
    347         FreePool (TxCb);
    348       }
    349     }
    350 
    351     //
    352     // Clean up all the info-request messages list.
    353     //
    354     NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->InfList) {
    355 
    356       InfCb = NET_LIST_USER_STRUCT (Entry, DHCP6_INF_CB, Link);
    357 
    358       if (InfCb->TimeoutEvent != NULL) {
    359         gBS->SignalEvent (InfCb->TimeoutEvent);
    360       }
    361       RemoveEntryList (&InfCb->Link);
    362       FreePool (InfCb);
    363     }
    364   }
    365 }
    366 
    367 /**
    368   Check whether the TxCb is still a valid control block in the instance's retry list.
    369 
    370   @param[in]  Instance       The pointer to DHCP6_INSTANCE.
    371   @param[in]  TxCb           The control block for a transmitted message.
    372 
    373   @retval   TRUE      The control block is in Instance's retry list.
    374   @retval   FALSE     The control block is NOT in Instance's retry list.
    375 
    376 **/
    377 BOOLEAN
    378 Dhcp6IsValidTxCb (
    379   IN  DHCP6_INSTANCE          *Instance,
    380   IN  DHCP6_TX_CB             *TxCb
    381   )
    382 {
    383   LIST_ENTRY                *Entry;
    384 
    385   NET_LIST_FOR_EACH (Entry, &Instance->TxList) {
    386     if (TxCb == NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link)) {
    387       return TRUE;
    388     }
    389   }
    390 
    391   return FALSE;
    392 }
    393 
    394 /**
    395   Clean up the session of the instance stateful exchange.
    396 
    397   @param[in, out]  Instance        The pointer to the Dhcp6 instance.
    398   @param[in]       Status          The return status from udp.
    399 
    400 **/
    401 VOID
    402 Dhcp6CleanupSession (
    403   IN OUT DHCP6_INSTANCE          *Instance,
    404   IN     EFI_STATUS              Status
    405   )
    406 {
    407   UINTN                          Index;
    408   EFI_DHCP6_IA                   *Ia;
    409 
    410   ASSERT(Instance->Config);
    411   ASSERT(Instance->IaCb.Ia);
    412 
    413   //
    414   // Clean up the retransmit list for stateful messages.
    415   //
    416   Dhcp6CleanupRetry (Instance, DHCP6_PACKET_STATEFUL);
    417 
    418   if (Instance->Unicast != NULL) {
    419     FreePool (Instance->Unicast);
    420   }
    421 
    422   if (Instance->AdSelect != NULL) {
    423     FreePool (Instance->AdSelect);
    424   }
    425 
    426   if (Instance->IaCb.Ia->ReplyPacket != NULL) {
    427     FreePool (Instance->IaCb.Ia->ReplyPacket);
    428   }
    429 
    430   //
    431   // Reinitialize the Ia fields of the instance.
    432   //
    433   Instance->UdpSts                  = Status;
    434   Instance->AdSelect                = NULL;
    435   Instance->AdPref                  = 0;
    436   Instance->Unicast                 = NULL;
    437   Instance->IaCb.T1                 = 0;
    438   Instance->IaCb.T2                 = 0;
    439   Instance->IaCb.AllExpireTime      = 0;
    440   Instance->IaCb.LeaseTime          = 0;
    441 
    442   //
    443   // Clear start time
    444   //
    445   Instance->StartTime               = 0;
    446 
    447   Ia                                = Instance->IaCb.Ia;
    448   Ia->State                         = Dhcp6Init;
    449   Ia->ReplyPacket                   = NULL;
    450 
    451   //
    452   // Set the addresses as zero lifetime, and then the notify
    453   // function in Ip6Config will remove these timeout address.
    454   //
    455   for (Index = 0; Index < Ia->IaAddressCount; Index++) {
    456     Ia->IaAddress[Index].PreferredLifetime = 0;
    457     Ia->IaAddress[Index].ValidLifetime     = 0;
    458   }
    459 
    460   //
    461   //
    462   // Signal the Ia information updated event to informal user.
    463   //
    464   if (Instance->Config->IaInfoEvent != NULL) {
    465     gBS->SignalEvent (Instance->Config->IaInfoEvent);
    466   }
    467 }
    468 
    469 
    470 /**
    471   Callback to user when Dhcp6 transmit/receive occurs.
    472 
    473   @param[in]      Instance        The pointer to the Dhcp6 instance.
    474   @param[in]      Event           The current Dhcp6 event.
    475   @param[in, out] Packet          The pointer to the packet sending or received.
    476 
    477   @retval EFI_SUCCESS           The user function returns success.
    478   @retval EFI_NOT_READY         Direct the caller to continue collecting the offer.
    479   @retval EFI_ABORTED           The user function ask it to abort.
    480 
    481 **/
    482 EFI_STATUS
    483 EFIAPI
    484 Dhcp6CallbackUser (
    485   IN     DHCP6_INSTANCE       *Instance,
    486   IN     EFI_DHCP6_EVENT      Event,
    487   IN OUT EFI_DHCP6_PACKET     **Packet
    488   )
    489 {
    490   EFI_STATUS                  Status;
    491   EFI_DHCP6_PACKET            *NewPacket;
    492   EFI_DHCP6_CALLBACK          Callback;
    493   VOID                        *Context;
    494 
    495   ASSERT (Packet != NULL);
    496   ASSERT (Instance->Config != NULL);
    497   ASSERT (Instance->IaCb.Ia != NULL);
    498 
    499   NewPacket = NULL;
    500   Status    = EFI_SUCCESS;
    501   Callback  = Instance->Config->Dhcp6Callback;
    502   Context   = Instance->Config->CallbackContext;
    503 
    504   //
    505   // Callback to user with the new message if has.
    506   //
    507   if (Callback != NULL) {
    508 
    509     Status = Callback (
    510                &Instance->Dhcp6,
    511                Context,
    512                Instance->IaCb.Ia->State,
    513                Event,
    514                *Packet,
    515                &NewPacket
    516                );
    517     //
    518     // Updated the new packet from user to replace the original one.
    519     //
    520     if (NewPacket != NULL) {
    521       ASSERT (*Packet != NULL);
    522       FreePool (*Packet);
    523       *Packet = NewPacket;
    524     }
    525   }
    526 
    527   return Status;
    528 }
    529 
    530 
    531 /**
    532   Update Ia according to the new reply message.
    533 
    534   @param[in, out]  Instance        The pointer to the Dhcp6 instance.
    535   @param[in]       Packet          The pointer to reply messages.
    536 
    537   @retval EFI_SUCCESS         Updated the Ia information successfully.
    538   @retval EFI_DEVICE_ERROR    An unexpected error.
    539 
    540 **/
    541 EFI_STATUS
    542 Dhcp6UpdateIaInfo (
    543   IN OUT DHCP6_INSTANCE           *Instance,
    544   IN     EFI_DHCP6_PACKET         *Packet
    545   )
    546 {
    547   EFI_STATUS                  Status;
    548   UINT8                       *Option;
    549   UINT8                       *IaInnerOpt;
    550   UINT16                      IaInnerLen;
    551   UINT16                      StsCode;
    552   UINT32                      T1;
    553   UINT32                      T2;
    554 
    555   ASSERT (Instance->Config != NULL);
    556   //
    557   // If the reply was received in reponse to a solicit with rapid commit option,
    558   // request, renew or rebind message, the client updates the information it has
    559   // recorded about IAs from the IA options contained in the reply message:
    560   //   1. record the T1 and T2 times
    561   //   2. add any new addresses in the IA
    562   //   3. discard any addresses from the IA, that have a valid lifetime of 0
    563   //   4. update lifetimes for any addresses that alread recorded
    564   //   5. leave unchanged any information about addresses
    565   //
    566   // See details in the section-18.1.8 of rfc-3315.
    567   //
    568   Option = Dhcp6SeekIaOption (
    569              Packet->Dhcp6.Option,
    570              Packet->Length - sizeof (EFI_DHCP6_HEADER),
    571              &Instance->Config->IaDescriptor
    572              );
    573   if (Option == NULL) {
    574     return EFI_DEVICE_ERROR;
    575   }
    576 
    577   //
    578   // The format of the IA_NA option is:
    579   //
    580   //     0                   1                   2                   3
    581   //     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
    582   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    583   //    |          OPTION_IA_NA         |          option-len           |
    584   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    585   //    |                        IAID (4 octets)                        |
    586   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    587   //    |                              T1                               |
    588   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    589   //    |                              T2                               |
    590   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    591   //    |                                                               |
    592   //    .                         IA_NA-options                         .
    593   //    .                                                               .
    594   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    595   //
    596   // The format of the IA_TA option is:
    597   //
    598   //     0                   1                   2                   3
    599   //     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
    600   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    601   //    |         OPTION_IA_TA          |          option-len           |
    602   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    603   //    |                        IAID (4 octets)                        |
    604   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    605   //    |                                                               |
    606   //    .                         IA_TA-options                         .
    607   //    .                                                               .
    608   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    609   //
    610 
    611   //
    612   // sizeof (option-code + option-len + IaId)           = 8
    613   // sizeof (option-code + option-len + IaId + T1)      = 12
    614   // sizeof (option-code + option-len + IaId + T1 + T2) = 16
    615   //
    616   // The inner options still start with 2 bytes option-code and 2 bytes option-len.
    617   //
    618   if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {
    619     T1 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 8)));
    620     T2 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 12)));
    621     //
    622     // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
    623     // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
    624     // the remainder of the message as though the server had not  included the invalid IA_NA option.
    625     //
    626     if (T1 > T2 && T2 > 0) {
    627       return EFI_DEVICE_ERROR;
    628     }
    629     IaInnerOpt = Option + 16;
    630     IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 2))) - 12);
    631   } else {
    632     T1 = 0;
    633     T2 = 0;
    634     IaInnerOpt = Option + 8;
    635     IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 2))) - 4);
    636   }
    637 
    638   //
    639   // The format of the Status Code option is:
    640   //
    641   //   0                   1                   2                   3
    642   //   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
    643   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    644   //  |       OPTION_STATUS_CODE      |         option-len            |
    645   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    646   //  |          status-code          |                               |
    647   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
    648   //  .                                                               .
    649   //  .                        status-message                         .
    650   //  .                                                               .
    651   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    652   //
    653 
    654   //
    655   // sizeof (option-code + option-len) = 4
    656   //
    657   StsCode = Dhcp6StsSuccess;
    658   Option  = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);
    659 
    660   if (Option != NULL) {
    661     StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4)));
    662     if (StsCode != Dhcp6StsSuccess) {
    663       return EFI_DEVICE_ERROR;
    664     }
    665   }
    666 
    667   //
    668   // Generate control block for the Ia.
    669   //
    670   Status = Dhcp6GenerateIaCb (
    671              Instance,
    672              IaInnerOpt,
    673              IaInnerLen,
    674              T1,
    675              T2
    676              );
    677 
    678   return Status;
    679 }
    680 
    681 
    682 
    683 /**
    684   Seek StatusCode Option in package. A Status Code option may appear in the
    685   options field of a DHCP message and/or in the options field of another option.
    686   See details in section 22.13, RFC3315.
    687 
    688   @param[in]       Instance        The pointer to the Dhcp6 instance.
    689   @param[in]       Packet          The pointer to reply messages.
    690   @param[out]      Option          The pointer to status code option.
    691 
    692   @retval EFI_SUCCESS              Seek status code option successfully.
    693   @retval EFI_DEVICE_ERROR         An unexpected error.
    694 
    695 **/
    696 EFI_STATUS
    697 Dhcp6SeekStsOption (
    698   IN     DHCP6_INSTANCE           *Instance,
    699   IN     EFI_DHCP6_PACKET         *Packet,
    700   OUT    UINT8                    **Option
    701   )
    702 {
    703   UINT8                       *IaInnerOpt;
    704   UINT16                      IaInnerLen;
    705   UINT16                      StsCode;
    706 
    707   //
    708   // Seek StatusCode option directly in DHCP message body. That is, search in
    709   // non-encapsulated option fields.
    710   //
    711   *Option = Dhcp6SeekOption (
    712               Packet->Dhcp6.Option,
    713               Packet->Length - 4,
    714               Dhcp6OptStatusCode
    715               );
    716 
    717   if (*Option != NULL) {
    718     StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 4)));
    719     if (StsCode != Dhcp6StsSuccess) {
    720       return EFI_DEVICE_ERROR;
    721     }
    722   }
    723 
    724   //
    725   // Seek in encapsulated options, IA_NA and IA_TA.
    726   //
    727   *Option = Dhcp6SeekIaOption (
    728               Packet->Dhcp6.Option,
    729               Packet->Length - sizeof (EFI_DHCP6_HEADER),
    730               &Instance->Config->IaDescriptor
    731               );
    732   if (*Option == NULL) {
    733     return EFI_SUCCESS;
    734   }
    735 
    736   //
    737   // The format of the IA_NA option is:
    738   //
    739   //     0                   1                   2                   3
    740   //     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
    741   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    742   //    |          OPTION_IA_NA         |          option-len           |
    743   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    744   //    |                        IAID (4 octets)                        |
    745   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    746   //    |                              T1                               |
    747   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    748   //    |                              T2                               |
    749   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    750   //    |                                                               |
    751   //    .                         IA_NA-options                         .
    752   //    .                                                               .
    753   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    754   //
    755   // The format of the IA_TA option is:
    756   //
    757   //     0                   1                   2                   3
    758   //     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
    759   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    760   //    |         OPTION_IA_TA          |          option-len           |
    761   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    762   //    |                        IAID (4 octets)                        |
    763   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    764   //    |                                                               |
    765   //    .                         IA_TA-options                         .
    766   //    .                                                               .
    767   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    768   //
    769 
    770   //
    771   // sizeof (option-code + option-len + IaId)           = 8
    772   // sizeof (option-code + option-len + IaId + T1)      = 12
    773   // sizeof (option-code + option-len + IaId + T1 + T2) = 16
    774   //
    775   // The inner options still start with 2 bytes option-code and 2 bytes option-len.
    776   //
    777   if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {
    778     IaInnerOpt = *Option + 16;
    779     IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 2))) - 12);
    780   } else {
    781     IaInnerOpt = *Option + 8;
    782     IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 2))) - 4);
    783   }
    784 
    785   //
    786   // The format of the Status Code option is:
    787   //
    788   //   0                   1                   2                   3
    789   //   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
    790   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    791   //  |       OPTION_STATUS_CODE      |         option-len            |
    792   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    793   //  |          status-code          |                               |
    794   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
    795   //  .                                                               .
    796   //  .                        status-message                         .
    797   //  .                                                               .
    798   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    799   //
    800 
    801   //
    802   // sizeof (option-code + option-len) = 4
    803   //
    804   *Option  = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);
    805   if (*Option != NULL) {
    806     StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 4)));
    807     if (StsCode != Dhcp6StsSuccess) {
    808       return EFI_DEVICE_ERROR;
    809     }
    810   }
    811 
    812   return EFI_SUCCESS;
    813 }
    814 
    815 
    816 /**
    817   Transmit Dhcp6 message by udpio.
    818 
    819   @param[in]  Instance        The pointer to the Dhcp6 instance.
    820   @param[in]  Packet          The pointer to transmit message.
    821   @param[in]  Elapsed         The pointer to the elapsed time value to fill in.
    822 
    823   @retval EFI_SUCCESS           Successfully transmitted the packet.
    824   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
    825   @retval Others                Failed to transmit the packet.
    826 
    827 **/
    828 EFI_STATUS
    829 Dhcp6TransmitPacket (
    830   IN DHCP6_INSTANCE         *Instance,
    831   IN EFI_DHCP6_PACKET       *Packet,
    832   IN UINT16                 *Elapsed
    833   )
    834 {
    835   EFI_STATUS                Status;
    836   NET_BUF                   *Wrap;
    837   NET_FRAGMENT              Frag;
    838   UDP_END_POINT             EndPt;
    839   DHCP6_SERVICE             *Service;
    840 
    841   Service = Instance->Service;
    842 
    843   //
    844   // Wrap it into a netbuf then send it.
    845   //
    846   Frag.Bulk = (UINT8 *) &Packet->Dhcp6.Header;
    847   Frag.Len  = Packet->Length;
    848 
    849   //
    850   // Do not register free packet here, which will be handled in retry list.
    851   //
    852   Wrap = NetbufFromExt (&Frag, 1, 0, 0, Dhcp6DummyExtFree, NULL);
    853 
    854   if (Wrap == NULL) {
    855     return EFI_OUT_OF_RESOURCES;
    856   }
    857 
    858   //
    859   // Multicast the Dhcp6 message, unless get the unicast server address by option.
    860   //
    861   ZeroMem (&EndPt, sizeof (UDP_END_POINT));
    862 
    863   if (Instance->Unicast != NULL) {
    864     CopyMem (
    865       &EndPt.RemoteAddr,
    866       Instance->Unicast,
    867       sizeof (EFI_IPv6_ADDRESS)
    868       );
    869   } else {
    870     CopyMem (
    871       &EndPt.RemoteAddr,
    872       &mAllDhcpRelayAndServersAddress,
    873       sizeof (EFI_IPv6_ADDRESS)
    874       );
    875   }
    876 
    877   EndPt.RemotePort = DHCP6_PORT_SERVER;
    878   EndPt.LocalPort  = DHCP6_PORT_CLIENT;
    879 
    880   //
    881   // Update the elapsed time value.
    882   //
    883   if (Elapsed != NULL) {
    884     SetElapsedTime (Elapsed, Instance);
    885   }
    886 
    887   //
    888   // Send out the message by the configured Udp6Io.
    889   //
    890   Status = UdpIoSendDatagram (
    891              Service->UdpIo,
    892              Wrap,
    893              &EndPt,
    894              NULL,
    895              Dhcp6OnTransmitted,
    896              NULL
    897              );
    898 
    899   if (EFI_ERROR (Status)) {
    900     NetbufFree (Wrap);
    901     return Status;
    902   }
    903 
    904   return EFI_SUCCESS;
    905 }
    906 
    907 
    908 /**
    909   Create the solicit message and send it.
    910 
    911   @param[in]  Instance        The pointer to the Dhcp6 instance.
    912 
    913   @retval EFI_SUCCESS           Created and sent the solicit message successfully.
    914   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
    915   @retval Others                Failed to send the solicit message.
    916 
    917 **/
    918 EFI_STATUS
    919 Dhcp6SendSolicitMsg   (
    920   IN DHCP6_INSTANCE            *Instance
    921   )
    922 {
    923   EFI_STATUS                   Status;
    924   EFI_DHCP6_PACKET             *Packet;
    925   EFI_DHCP6_PACKET_OPTION      *UserOpt;
    926   EFI_DHCP6_DUID               *ClientId;
    927   DHCP6_SERVICE                *Service;
    928   UINT8                        *Cursor;
    929   UINT16                       *Elapsed;
    930   UINT32                       UserLen;
    931   UINTN                        Index;
    932   UINT16                       Length;
    933 
    934   Service  = Instance->Service;
    935   ClientId = Service->ClientId;
    936   UserLen  = 0;
    937 
    938   ASSERT (Service->ClientId != NULL);
    939   ASSERT (Instance->Config != NULL);
    940   ASSERT (Instance->IaCb.Ia != NULL);
    941 
    942   //
    943   // Calculate the added length of customized option list.
    944   //
    945   for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
    946     UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
    947   }
    948 
    949   //
    950   // Create the Dhcp6 packet and initialize commone fields.
    951   //
    952   Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
    953   if (Packet == NULL) {
    954     return EFI_OUT_OF_RESOURCES;
    955   }
    956 
    957   Packet->Size                       = DHCP6_BASE_PACKET_SIZE + UserLen;
    958   Packet->Length                     = sizeof (EFI_DHCP6_HEADER);
    959   Packet->Dhcp6.Header.MessageType   = Dhcp6MsgSolicit;
    960   Packet->Dhcp6.Header.TransactionId = Service->Xid++;
    961 
    962   //
    963   // Assembly Dhcp6 options for solicit message.
    964   //
    965   Cursor = Packet->Dhcp6.Option;
    966 
    967   Length = HTONS (ClientId->Length);
    968   Cursor = Dhcp6AppendOption (
    969              Cursor,
    970              HTONS (Dhcp6OptClientId),
    971              Length,
    972              ClientId->Duid
    973              );
    974 
    975   Cursor = Dhcp6AppendETOption (
    976              Cursor,
    977              Instance,
    978              &Elapsed
    979              );
    980 
    981   Cursor = Dhcp6AppendIaOption (
    982              Cursor,
    983              Instance->IaCb.Ia,
    984              Instance->IaCb.T1,
    985              Instance->IaCb.T2,
    986              Packet->Dhcp6.Header.MessageType
    987              );
    988 
    989   //
    990   // Append user-defined when configurate Dhcp6 service.
    991   //
    992   for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
    993 
    994     UserOpt = Instance->Config->OptionList[Index];
    995     Cursor  = Dhcp6AppendOption(
    996                 Cursor,
    997                 UserOpt->OpCode,
    998                 UserOpt->OpLen,
    999                 UserOpt->Data
   1000                 );
   1001   }
   1002 
   1003   //
   1004   // Determine the size/length of packet.
   1005   //
   1006   Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
   1007   ASSERT (Packet->Size > Packet->Length + 8);
   1008 
   1009   //
   1010   // Callback to user with the packet to be sent and check the user's feedback.
   1011   //
   1012   Status = Dhcp6CallbackUser (Instance, Dhcp6SendSolicit, &Packet);
   1013 
   1014   if (EFI_ERROR (Status)) {
   1015     FreePool (Packet);
   1016     return Status;
   1017   }
   1018 
   1019   //
   1020   // Send solicit packet with the state transition from Dhcp6init to
   1021   // Dhcp6selecting.
   1022   //
   1023   Instance->IaCb.Ia->State = Dhcp6Selecting;
   1024   //
   1025   // Clear initial time for current transaction.
   1026   //
   1027   Instance->StartTime = 0;
   1028 
   1029   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
   1030 
   1031   if (EFI_ERROR (Status)) {
   1032     FreePool (Packet);
   1033     return Status;
   1034   }
   1035 
   1036   //
   1037   // Enqueue the sent packet for the retransmission in case reply timeout.
   1038   //
   1039   return Dhcp6EnqueueRetry (
   1040            Instance,
   1041            Packet,
   1042            Elapsed,
   1043            Instance->Config->SolicitRetransmission
   1044            );
   1045 }
   1046 
   1047 /**
   1048   Configure some parameter to initiate SolicitMsg.
   1049 
   1050   @param[in]  Instance          The pointer to the Dhcp6 instance.
   1051 
   1052   @retval EFI_SUCCESS           Created and sent the solicit message successfully.
   1053   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1054   @retval Others                Failed to send the solicit message.
   1055 
   1056 **/
   1057 EFI_STATUS
   1058 Dhcp6InitSolicitMsg   (
   1059   IN DHCP6_INSTANCE            *Instance
   1060   )
   1061 {
   1062   Instance->IaCb.T1 = 0;
   1063   Instance->IaCb.T2 = 0;
   1064   Instance->IaCb.Ia->IaAddressCount = 0;
   1065 
   1066   return Dhcp6SendSolicitMsg (Instance);
   1067 }
   1068 
   1069 
   1070 /**
   1071   Create the request message and send it.
   1072 
   1073   @param[in]  Instance        The pointer to the Dhcp6 instance.
   1074 
   1075   @retval EFI_SUCCESS           Created and sent the request message successfully.
   1076   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1077   @retval EFI_DEVICE_ERROR      An unexpected error.
   1078   @retval Others                Failed to send the request message.
   1079 
   1080 **/
   1081 EFI_STATUS
   1082 Dhcp6SendRequestMsg (
   1083   IN DHCP6_INSTANCE            *Instance
   1084   )
   1085 {
   1086   EFI_STATUS                   Status;
   1087   EFI_DHCP6_PACKET             *Packet;
   1088   EFI_DHCP6_PACKET_OPTION      *UserOpt;
   1089   EFI_DHCP6_DUID               *ClientId;
   1090   EFI_DHCP6_DUID               *ServerId;
   1091   DHCP6_SERVICE                *Service;
   1092   UINT8                        *Option;
   1093   UINT8                        *Cursor;
   1094   UINT16                       *Elapsed;
   1095   UINT32                       UserLen;
   1096   UINTN                        Index;
   1097   UINT16                       Length;
   1098 
   1099   ASSERT(Instance->AdSelect != NULL);
   1100   ASSERT(Instance->Config != NULL);
   1101   ASSERT(Instance->IaCb.Ia != NULL);
   1102   ASSERT(Instance->Service != NULL);
   1103 
   1104   Service  = Instance->Service;
   1105   ClientId = Service->ClientId;
   1106 
   1107   ASSERT(ClientId != NULL);
   1108 
   1109   //
   1110   // Get the server Id from the selected advertisement message.
   1111   //
   1112   Option = Dhcp6SeekOption (
   1113              Instance->AdSelect->Dhcp6.Option,
   1114              Instance->AdSelect->Length - 4,
   1115              Dhcp6OptServerId
   1116              );
   1117   if (Option == NULL) {
   1118     return EFI_DEVICE_ERROR;
   1119   }
   1120 
   1121   ServerId = (EFI_DHCP6_DUID *) (Option + 2);
   1122 
   1123   //
   1124   // Calculate the added length of customized option list.
   1125   //
   1126   UserLen = 0;
   1127   for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
   1128     UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
   1129   }
   1130 
   1131   //
   1132   // Create the Dhcp6 packet and initialize commone fields.
   1133   //
   1134   Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
   1135   if (Packet == NULL) {
   1136     return EFI_OUT_OF_RESOURCES;
   1137   }
   1138 
   1139   Packet->Size                       = DHCP6_BASE_PACKET_SIZE + UserLen;
   1140   Packet->Length                     = sizeof (EFI_DHCP6_HEADER);
   1141   Packet->Dhcp6.Header.MessageType   = Dhcp6MsgRequest;
   1142   Packet->Dhcp6.Header.TransactionId = Service->Xid++;
   1143 
   1144   //
   1145   // Assembly Dhcp6 options for request message.
   1146   //
   1147   Cursor = Packet->Dhcp6.Option;
   1148 
   1149   Length = HTONS (ClientId->Length);
   1150   Cursor = Dhcp6AppendOption (
   1151              Cursor,
   1152              HTONS (Dhcp6OptClientId),
   1153              Length,
   1154              ClientId->Duid
   1155              );
   1156 
   1157   Cursor = Dhcp6AppendETOption (
   1158              Cursor,
   1159              Instance,
   1160              &Elapsed
   1161              );
   1162 
   1163   Cursor = Dhcp6AppendOption (
   1164              Cursor,
   1165              HTONS (Dhcp6OptServerId),
   1166              ServerId->Length,
   1167              ServerId->Duid
   1168              );
   1169 
   1170   Cursor = Dhcp6AppendIaOption (
   1171              Cursor,
   1172              Instance->IaCb.Ia,
   1173              Instance->IaCb.T1,
   1174              Instance->IaCb.T2,
   1175              Packet->Dhcp6.Header.MessageType
   1176              );
   1177 
   1178   //
   1179   // Append user-defined when configurate Dhcp6 service.
   1180   //
   1181   for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
   1182 
   1183     UserOpt = Instance->Config->OptionList[Index];
   1184     Cursor  = Dhcp6AppendOption(
   1185                 Cursor,
   1186                 UserOpt->OpCode,
   1187                 UserOpt->OpLen,
   1188                 UserOpt->Data
   1189                 );
   1190   }
   1191 
   1192   //
   1193   // Determine the size/length of packet.
   1194   //
   1195   Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
   1196   ASSERT (Packet->Size > Packet->Length + 8);
   1197 
   1198   //
   1199   // Callback to user with the packet to be sent and check the user's feedback.
   1200   //
   1201   Status = Dhcp6CallbackUser (Instance, Dhcp6SendRequest, &Packet);
   1202 
   1203   if (EFI_ERROR (Status)) {
   1204     FreePool (Packet);
   1205     return Status;
   1206   }
   1207 
   1208   //
   1209   // Send request packet with the state transition from Dhcp6selecting to
   1210   // Dhcp6requesting.
   1211   //
   1212   Instance->IaCb.Ia->State = Dhcp6Requesting;
   1213   //
   1214   // Clear initial time for current transaction.
   1215   //
   1216   Instance->StartTime = 0;
   1217 
   1218   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
   1219 
   1220   if (EFI_ERROR (Status)) {
   1221     FreePool (Packet);
   1222     return Status;
   1223   }
   1224 
   1225   //
   1226   // Enqueue the sent packet for the retransmission in case reply timeout.
   1227   //
   1228   return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
   1229 }
   1230 
   1231 
   1232 /**
   1233   Create the decline message and send it.
   1234 
   1235   @param[in]  Instance        The pointer to the Dhcp6 instance.
   1236   @param[in]  DecIa           The pointer to the decline Ia.
   1237 
   1238   @retval EFI_SUCCESS           Created and sent the decline message successfully.
   1239   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1240   @retval EFI_DEVICE_ERROR      An unexpected error.
   1241   @retval Others                Failed to send the decline message.
   1242 
   1243 **/
   1244 EFI_STATUS
   1245 Dhcp6SendDeclineMsg (
   1246   IN DHCP6_INSTANCE            *Instance,
   1247   IN EFI_DHCP6_IA              *DecIa
   1248   )
   1249 {
   1250   EFI_STATUS                   Status;
   1251   EFI_DHCP6_PACKET             *Packet;
   1252   EFI_DHCP6_PACKET             *LastReply;
   1253   EFI_DHCP6_DUID               *ClientId;
   1254   EFI_DHCP6_DUID               *ServerId;
   1255   DHCP6_SERVICE                *Service;
   1256   UINT8                        *Option;
   1257   UINT8                        *Cursor;
   1258   UINT16                       *Elapsed;
   1259   UINT16                       Length;
   1260 
   1261   ASSERT (Instance->Config != NULL);
   1262   ASSERT (Instance->IaCb.Ia != NULL);
   1263   ASSERT (Instance->Service != NULL);
   1264 
   1265   Service   = Instance->Service;
   1266   ClientId  = Service->ClientId;
   1267   LastReply = Instance->IaCb.Ia->ReplyPacket;
   1268 
   1269   ASSERT (ClientId != NULL);
   1270   ASSERT (LastReply != NULL);
   1271 
   1272   //
   1273   // Get the server Id from the last reply message.
   1274   //
   1275   Option = Dhcp6SeekOption (
   1276              LastReply->Dhcp6.Option,
   1277              LastReply->Length - 4,
   1278              Dhcp6OptServerId
   1279              );
   1280   if (Option == NULL) {
   1281     return EFI_DEVICE_ERROR;
   1282   }
   1283 
   1284   //
   1285   // EFI_DHCP6_DUID contains a length field of 2 bytes.
   1286   //
   1287   ServerId = (EFI_DHCP6_DUID *) (Option + 2);
   1288 
   1289   //
   1290   // Create the Dhcp6 packet and initialize commone fields.
   1291   //
   1292   Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE);
   1293   if (Packet == NULL) {
   1294     return EFI_OUT_OF_RESOURCES;
   1295   }
   1296 
   1297   Packet->Size                       = DHCP6_BASE_PACKET_SIZE;
   1298   Packet->Length                     = sizeof (EFI_DHCP6_HEADER);
   1299   Packet->Dhcp6.Header.MessageType   = Dhcp6MsgDecline;
   1300   Packet->Dhcp6.Header.TransactionId = Service->Xid++;
   1301 
   1302   //
   1303   // Assembly Dhcp6 options for rebind/renew message.
   1304   //
   1305   Cursor = Packet->Dhcp6.Option;
   1306 
   1307   Length = HTONS (ClientId->Length);
   1308   Cursor = Dhcp6AppendOption (
   1309              Cursor,
   1310              HTONS (Dhcp6OptClientId),
   1311              Length,
   1312              ClientId->Duid
   1313              );
   1314 
   1315   Cursor = Dhcp6AppendETOption (
   1316              Cursor,
   1317              Instance,
   1318              &Elapsed
   1319              );
   1320 
   1321   Cursor = Dhcp6AppendOption (
   1322              Cursor,
   1323              HTONS (Dhcp6OptServerId),
   1324              ServerId->Length,
   1325              ServerId->Duid
   1326              );
   1327 
   1328   Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType);
   1329 
   1330   //
   1331   // Determine the size/length of packet.
   1332   //
   1333   Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
   1334   ASSERT (Packet->Size > Packet->Length + 8);
   1335 
   1336   //
   1337   // Callback to user with the packet to be sent and check the user's feedback.
   1338   //
   1339   Status = Dhcp6CallbackUser (Instance, Dhcp6SendDecline, &Packet);
   1340 
   1341   if (EFI_ERROR (Status)) {
   1342     FreePool (Packet);
   1343     return Status;
   1344   }
   1345 
   1346   //
   1347   // Send decline packet with the state transition from Dhcp6bound to
   1348   // Dhcp6declining.
   1349   //
   1350   Instance->IaCb.Ia->State = Dhcp6Declining;
   1351   //
   1352   // Clear initial time for current transaction.
   1353   //
   1354   Instance->StartTime = 0;
   1355 
   1356   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
   1357 
   1358   if (EFI_ERROR (Status)) {
   1359     FreePool (Packet);
   1360     return Status;
   1361   }
   1362 
   1363   //
   1364   // Enqueue the sent packet for the retransmission in case reply timeout.
   1365   //
   1366   return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
   1367 }
   1368 
   1369 
   1370 /**
   1371   Create the release message and send it.
   1372 
   1373   @param[in]  Instance        The pointer to the Dhcp6 instance.
   1374   @param[in]  RelIa           The pointer to the release Ia.
   1375 
   1376   @retval EFI_SUCCESS           Created and sent the release message successfully.
   1377   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1378   @retval EFI_DEVICE_ERROR      An unexpected error.
   1379   @retval Others                Failed to send the release message.
   1380 
   1381 **/
   1382 EFI_STATUS
   1383 Dhcp6SendReleaseMsg (
   1384   IN DHCP6_INSTANCE            *Instance,
   1385   IN EFI_DHCP6_IA              *RelIa
   1386   )
   1387 {
   1388   EFI_STATUS                   Status;
   1389   EFI_DHCP6_PACKET             *Packet;
   1390   EFI_DHCP6_PACKET             *LastReply;
   1391   EFI_DHCP6_DUID               *ClientId;
   1392   EFI_DHCP6_DUID               *ServerId;
   1393   DHCP6_SERVICE                *Service;
   1394   UINT8                        *Option;
   1395   UINT8                        *Cursor;
   1396   UINT16                       *Elapsed;
   1397   UINT16                       Length;
   1398 
   1399   ASSERT(Instance->Config);
   1400   ASSERT(Instance->IaCb.Ia);
   1401 
   1402   Service   = Instance->Service;
   1403   ClientId  = Service->ClientId;
   1404   LastReply = Instance->IaCb.Ia->ReplyPacket;
   1405 
   1406   ASSERT(ClientId);
   1407   ASSERT(LastReply);
   1408 
   1409   //
   1410   // Get the server Id from the last reply message.
   1411   //
   1412   Option = Dhcp6SeekOption (
   1413              LastReply->Dhcp6.Option,
   1414              LastReply->Length - 4,
   1415              Dhcp6OptServerId
   1416              );
   1417   if (Option == NULL) {
   1418     return EFI_DEVICE_ERROR;
   1419   }
   1420 
   1421   ServerId = (EFI_DHCP6_DUID *) (Option + 2);
   1422 
   1423   //
   1424   // Create the Dhcp6 packet and initialize commone fields.
   1425   //
   1426   Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE);
   1427   if (Packet == NULL) {
   1428     return EFI_OUT_OF_RESOURCES;
   1429   }
   1430 
   1431   Packet->Size                       = DHCP6_BASE_PACKET_SIZE;
   1432   Packet->Length                     = sizeof (EFI_DHCP6_HEADER);
   1433   Packet->Dhcp6.Header.MessageType   = Dhcp6MsgRelease;
   1434   Packet->Dhcp6.Header.TransactionId = Service->Xid++;
   1435 
   1436   //
   1437   // Assembly Dhcp6 options for rebind/renew message
   1438   //
   1439   Cursor = Packet->Dhcp6.Option;
   1440 
   1441   Length = HTONS (ClientId->Length);
   1442   Cursor = Dhcp6AppendOption (
   1443              Cursor,
   1444              HTONS (Dhcp6OptClientId),
   1445              Length,
   1446              ClientId->Duid
   1447              );
   1448 
   1449   //
   1450   // ServerId is extracted from packet, it's network order.
   1451   //
   1452   Cursor = Dhcp6AppendOption (
   1453              Cursor,
   1454              HTONS (Dhcp6OptServerId),
   1455              ServerId->Length,
   1456              ServerId->Duid
   1457              );
   1458 
   1459   Cursor = Dhcp6AppendETOption (
   1460              Cursor,
   1461              Instance,
   1462              &Elapsed
   1463              );
   1464 
   1465   Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType);
   1466 
   1467   //
   1468   // Determine the size/length of packet
   1469   //
   1470   Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
   1471   ASSERT (Packet->Size > Packet->Length + 8);
   1472 
   1473   //
   1474   // Callback to user with the packet to be sent and check the user's feedback.
   1475   //
   1476   Status = Dhcp6CallbackUser (Instance, Dhcp6SendRelease, &Packet);
   1477 
   1478   if (EFI_ERROR (Status)) {
   1479     FreePool (Packet);
   1480     return Status;
   1481   }
   1482 
   1483   //
   1484   // Send release packet with the state transition from Dhcp6bound to
   1485   // Dhcp6releasing.
   1486   //
   1487   Instance->IaCb.Ia->State = Dhcp6Releasing;
   1488 
   1489   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
   1490 
   1491   if (EFI_ERROR (Status)) {
   1492     FreePool (Packet);
   1493     return Status;
   1494   }
   1495 
   1496   //
   1497   // Enqueue the sent packet for the retransmission in case reply timeout.
   1498   //
   1499   return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
   1500 }
   1501 
   1502 
   1503 /**
   1504   Create the renew/rebind message and send it.
   1505 
   1506   @param[in]  Instance        The pointer to the Dhcp6 instance.
   1507   @param[in]  RebindRequest   If TRUE, it is a Rebind type message.
   1508                               Otherwise, it is a Renew type message.
   1509 
   1510   @retval EFI_SUCCESS           Created and sent the renew/rebind message successfully.
   1511   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1512   @retval EFI_DEVICE_ERROR      An unexpected error.
   1513   @retval Others                Failed to send the renew/rebind message.
   1514 
   1515 **/
   1516 EFI_STATUS
   1517 Dhcp6SendRenewRebindMsg (
   1518   IN DHCP6_INSTANCE         *Instance,
   1519   IN BOOLEAN                RebindRequest
   1520   )
   1521 {
   1522   EFI_STATUS                Status;
   1523   EFI_DHCP6_PACKET          *Packet;
   1524   EFI_DHCP6_PACKET          *LastReply;
   1525   EFI_DHCP6_PACKET_OPTION   *UserOpt;
   1526   EFI_DHCP6_DUID            *ClientId;
   1527   EFI_DHCP6_DUID            *ServerId;
   1528   EFI_DHCP6_STATE           State;
   1529   EFI_DHCP6_EVENT           Event;
   1530   DHCP6_SERVICE             *Service;
   1531   UINT8                     *Option;
   1532   UINT8                     *Cursor;
   1533   UINT16                    *Elapsed;
   1534   UINT32                    UserLen;
   1535   UINTN                     Index;
   1536   UINT16                    Length;
   1537 
   1538   ASSERT(Instance->Config);
   1539   ASSERT(Instance->IaCb.Ia);
   1540 
   1541   Service   = Instance->Service;
   1542   ClientId  = Service->ClientId;
   1543 
   1544   ASSERT(ClientId);
   1545 
   1546   //
   1547   // Calculate the added length of customized option list.
   1548   //
   1549   UserLen = 0;
   1550   for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
   1551     UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
   1552   }
   1553 
   1554   //
   1555   // Create the Dhcp6 packet and initialize commone fields.
   1556   //
   1557   Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
   1558   if (Packet == NULL) {
   1559     return EFI_OUT_OF_RESOURCES;
   1560   }
   1561 
   1562   Packet->Size                       = DHCP6_BASE_PACKET_SIZE + UserLen;
   1563   Packet->Length                     = sizeof (EFI_DHCP6_HEADER);
   1564   Packet->Dhcp6.Header.MessageType   = RebindRequest ? Dhcp6MsgRebind : Dhcp6MsgRenew;
   1565   Packet->Dhcp6.Header.TransactionId = Service->Xid++;
   1566 
   1567   //
   1568   // Assembly Dhcp6 options for rebind/renew message.
   1569   //
   1570   Cursor = Packet->Dhcp6.Option;
   1571 
   1572   Length = HTONS (ClientId->Length);
   1573   Cursor = Dhcp6AppendOption (
   1574              Cursor,
   1575              HTONS (Dhcp6OptClientId),
   1576              Length,
   1577              ClientId->Duid
   1578              );
   1579 
   1580   Cursor = Dhcp6AppendETOption (
   1581              Cursor,
   1582              Instance,
   1583              &Elapsed
   1584              );
   1585 
   1586   Cursor = Dhcp6AppendIaOption (
   1587              Cursor,
   1588              Instance->IaCb.Ia,
   1589              Instance->IaCb.T1,
   1590              Instance->IaCb.T2,
   1591              Packet->Dhcp6.Header.MessageType
   1592              );
   1593 
   1594   if (!RebindRequest) {
   1595     //
   1596     // Get the server Id from the last reply message and
   1597     // insert it for rebind request.
   1598     //
   1599     LastReply = Instance->IaCb.Ia->ReplyPacket;
   1600     ASSERT (LastReply);
   1601 
   1602     Option = Dhcp6SeekOption (
   1603                LastReply->Dhcp6.Option,
   1604                LastReply->Length - 4,
   1605                Dhcp6OptServerId
   1606                );
   1607     if (Option == NULL) {
   1608       FreePool (Packet);
   1609       return EFI_DEVICE_ERROR;
   1610     }
   1611 
   1612     ServerId = (EFI_DHCP6_DUID *) (Option + 2);
   1613 
   1614     Cursor = Dhcp6AppendOption (
   1615                Cursor,
   1616                HTONS (Dhcp6OptServerId),
   1617                ServerId->Length,
   1618                ServerId->Duid
   1619                );
   1620   }
   1621 
   1622   //
   1623   // Append user-defined when configurate Dhcp6 service.
   1624   //
   1625   for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
   1626 
   1627     UserOpt = Instance->Config->OptionList[Index];
   1628     Cursor  = Dhcp6AppendOption(
   1629                 Cursor,
   1630                 UserOpt->OpCode,
   1631                 UserOpt->OpLen,
   1632                 UserOpt->Data
   1633                 );
   1634   }
   1635 
   1636   //
   1637   // Determine the size/length of packet.
   1638   //
   1639   Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
   1640   ASSERT (Packet->Size > Packet->Length + 8);
   1641 
   1642   //
   1643   // Callback to user with the packet to be sent and check the user's feedback.
   1644   //
   1645   State  = (RebindRequest) ? Dhcp6Rebinding : Dhcp6Renewing;
   1646   Event  = (RebindRequest) ? Dhcp6EnterRebinding : Dhcp6EnterRenewing;
   1647 
   1648   Status = Dhcp6CallbackUser (Instance, Event, &Packet);
   1649 
   1650   if (EFI_ERROR (Status)) {
   1651     FreePool (Packet);
   1652     return Status;
   1653   }
   1654 
   1655   //
   1656   // Send renew/rebind packet with the state transition from Dhcp6bound to
   1657   // Dhcp6renew/rebind.
   1658   // And sync the lease time when send renew/rebind, in case that user send
   1659   // renew/rebind actively.
   1660   //
   1661   Instance->IaCb.Ia->State = State;
   1662   Instance->IaCb.LeaseTime = (RebindRequest) ? Instance->IaCb.T2 : Instance->IaCb.T1;
   1663   //
   1664   // Clear initial time for current transaction.
   1665   //
   1666   Instance->StartTime = 0;
   1667 
   1668   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
   1669 
   1670   if (EFI_ERROR (Status)) {
   1671     FreePool (Packet);
   1672     return Status;
   1673   }
   1674 
   1675   //
   1676   // Enqueue the sent packet for the retransmission in case reply timeout.
   1677   //
   1678   return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
   1679 }
   1680 
   1681 /**
   1682   Start the information request process.
   1683 
   1684   @param[in]  Instance          The pointer to the Dhcp6 instance.
   1685   @param[in]  SendClientId      If TRUE, the client identifier option will be included in
   1686                                 information request message. Otherwise, the client identifier
   1687                                 option will not be included.
   1688   @param[in]  OptionRequest     The pointer to the option request option.
   1689   @param[in]  OptionCount       The number options in the OptionList.
   1690   @param[in]  OptionList        The array pointers to the appended options.
   1691   @param[in]  Retransmission    The pointer to the retransmission control.
   1692   @param[in]  TimeoutEvent      The event of timeout.
   1693   @param[in]  ReplyCallback     The callback function when the reply was received.
   1694   @param[in]  CallbackContext   The pointer to the parameter passed to the callback.
   1695 
   1696   @retval EFI_SUCCESS           Start the info-request process successfully.
   1697   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1698   @retval EFI_NO_MAPPING        No source address is available for use.
   1699   @retval Others                Failed to start the info-request process.
   1700 
   1701 **/
   1702 EFI_STATUS
   1703 Dhcp6StartInfoRequest (
   1704   IN DHCP6_INSTANCE            *Instance,
   1705   IN BOOLEAN                   SendClientId,
   1706   IN EFI_DHCP6_PACKET_OPTION   *OptionRequest,
   1707   IN UINT32                    OptionCount,
   1708   IN EFI_DHCP6_PACKET_OPTION   *OptionList[]    OPTIONAL,
   1709   IN EFI_DHCP6_RETRANSMISSION  *Retransmission,
   1710   IN EFI_EVENT                 TimeoutEvent     OPTIONAL,
   1711   IN EFI_DHCP6_INFO_CALLBACK   ReplyCallback,
   1712   IN VOID                      *CallbackContext OPTIONAL
   1713   )
   1714 {
   1715   EFI_STATUS                   Status;
   1716   DHCP6_INF_CB                 *InfCb;
   1717   DHCP6_SERVICE                *Service;
   1718   EFI_TPL                      OldTpl;
   1719 
   1720   Service  = Instance->Service;
   1721 
   1722   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1723   Instance->UdpSts = EFI_ALREADY_STARTED;
   1724   //
   1725   // Create and initialize the control block for the info-request.
   1726   //
   1727   InfCb = AllocateZeroPool (sizeof(DHCP6_INF_CB));
   1728 
   1729   if (InfCb == NULL) {
   1730     gBS->RestoreTPL (OldTpl);
   1731     return EFI_OUT_OF_RESOURCES;
   1732   }
   1733 
   1734   InfCb->ReplyCallback   = ReplyCallback;
   1735   InfCb->CallbackContext = CallbackContext;
   1736   InfCb->TimeoutEvent    = TimeoutEvent;
   1737 
   1738   InsertTailList (&Instance->InfList, &InfCb->Link);
   1739 
   1740   //
   1741   // Send the info-request message to start exchange process.
   1742   //
   1743   Status = Dhcp6SendInfoRequestMsg (
   1744              Instance,
   1745              InfCb,
   1746              SendClientId,
   1747              OptionRequest,
   1748              OptionCount,
   1749              OptionList,
   1750              Retransmission
   1751              );
   1752 
   1753   if (EFI_ERROR (Status)) {
   1754     goto ON_ERROR;
   1755   }
   1756 
   1757   //
   1758   // Register receive callback for the stateless exchange process.
   1759   //
   1760   Status = UdpIoRecvDatagram(
   1761              Service->UdpIo,
   1762              Dhcp6ReceivePacket,
   1763              Service,
   1764              0
   1765              );
   1766 
   1767   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
   1768     goto ON_ERROR;
   1769   }
   1770 
   1771   gBS->RestoreTPL (OldTpl);
   1772   return EFI_SUCCESS;
   1773 
   1774 ON_ERROR:
   1775   gBS->RestoreTPL (OldTpl);
   1776   RemoveEntryList (&InfCb->Link);
   1777   FreePool (InfCb);
   1778 
   1779   return Status;
   1780 }
   1781 
   1782 /**
   1783   Create the information request message and send it.
   1784 
   1785   @param[in]  Instance        The pointer to the Dhcp6 instance.
   1786   @param[in]  InfCb           The pointer to the information request control block.
   1787   @param[in]  SendClientId    If TRUE, the client identifier option will be included in
   1788                               information request message. Otherwise, the client identifier
   1789                               option will not be included.
   1790   @param[in]  OptionRequest   The pointer to the option request option.
   1791   @param[in]  OptionCount     The number options in the OptionList.
   1792   @param[in]  OptionList      The array pointers to the appended options.
   1793   @param[in]  Retransmission  The pointer to the retransmission control.
   1794 
   1795   @retval EFI_SUCCESS           Created and sent the info-request message successfully.
   1796   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1797   @retval Others                Failed to send the info-request message.
   1798 
   1799 **/
   1800 EFI_STATUS
   1801 Dhcp6SendInfoRequestMsg (
   1802   IN DHCP6_INSTANCE            *Instance,
   1803   IN DHCP6_INF_CB              *InfCb,
   1804   IN BOOLEAN                   SendClientId,
   1805   IN EFI_DHCP6_PACKET_OPTION   *OptionRequest,
   1806   IN UINT32                    OptionCount,
   1807   IN EFI_DHCP6_PACKET_OPTION   *OptionList[],
   1808   IN EFI_DHCP6_RETRANSMISSION  *Retransmission
   1809   )
   1810 {
   1811   EFI_STATUS                   Status;
   1812   EFI_DHCP6_PACKET             *Packet;
   1813   EFI_DHCP6_PACKET_OPTION      *UserOpt;
   1814   EFI_DHCP6_DUID               *ClientId;
   1815   DHCP6_SERVICE                *Service;
   1816   UINT8                        *Cursor;
   1817   UINT16                       *Elapsed;
   1818   UINT32                       UserLen;
   1819   UINTN                        Index;
   1820   UINT16                       Length;
   1821 
   1822   ASSERT(OptionRequest);
   1823 
   1824   Service  = Instance->Service;
   1825   ClientId = Service->ClientId;
   1826   UserLen  = NTOHS (OptionRequest->OpLen) + 4;
   1827 
   1828   ASSERT(ClientId);
   1829 
   1830   //
   1831   // Calculate the added length of customized option list.
   1832   //
   1833   for (Index = 0; Index < OptionCount; Index++) {
   1834     UserLen += (NTOHS (OptionList[Index]->OpLen) + 4);
   1835   }
   1836 
   1837   //
   1838   // Create the Dhcp6 packet and initialize commone fields.
   1839   //
   1840   Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
   1841   if (Packet == NULL) {
   1842     return EFI_OUT_OF_RESOURCES;
   1843   }
   1844 
   1845   Packet->Size                       = DHCP6_BASE_PACKET_SIZE + UserLen;
   1846   Packet->Length                     = sizeof (EFI_DHCP6_HEADER);
   1847   Packet->Dhcp6.Header.MessageType   = Dhcp6MsgInfoRequest;
   1848   Packet->Dhcp6.Header.TransactionId = Service->Xid++;
   1849 
   1850   InfCb->Xid                         = Packet->Dhcp6.Header.TransactionId;
   1851 
   1852   //
   1853   // Assembly Dhcp6 options for info-request message.
   1854   //
   1855   Cursor = Packet->Dhcp6.Option;
   1856 
   1857   if (SendClientId) {
   1858     Length = HTONS (ClientId->Length);
   1859     Cursor = Dhcp6AppendOption (
   1860                Cursor,
   1861                HTONS (Dhcp6OptClientId),
   1862                Length,
   1863                ClientId->Duid
   1864                );
   1865   }
   1866 
   1867   Cursor = Dhcp6AppendETOption (
   1868              Cursor,
   1869              Instance,
   1870              &Elapsed
   1871              );
   1872 
   1873   Cursor = Dhcp6AppendOption (
   1874              Cursor,
   1875              OptionRequest->OpCode,
   1876              OptionRequest->OpLen,
   1877              OptionRequest->Data
   1878              );
   1879 
   1880   //
   1881   // Append user-defined when configurate Dhcp6 service.
   1882   //
   1883   for (Index = 0; Index < OptionCount; Index++) {
   1884 
   1885     UserOpt = OptionList[Index];
   1886     Cursor  = Dhcp6AppendOption(
   1887                 Cursor,
   1888                 UserOpt->OpCode,
   1889                 UserOpt->OpLen,
   1890                 UserOpt->Data
   1891                 );
   1892   }
   1893 
   1894   //
   1895   // Determine the size/length of packet.
   1896   //
   1897   Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
   1898   ASSERT (Packet->Size > Packet->Length + 8);
   1899 
   1900   //
   1901   // Clear initial time for current transaction.
   1902   //
   1903   Instance->StartTime = 0;
   1904 
   1905   //
   1906   // Send info-request packet with no state.
   1907   //
   1908   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
   1909 
   1910   if (EFI_ERROR (Status)) {
   1911     FreePool (Packet);
   1912     return Status;
   1913   }
   1914 
   1915   //
   1916   // Enqueue the sent packet for the retransmission in case reply timeout.
   1917   //
   1918   return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, Retransmission);
   1919 }
   1920 
   1921 
   1922 /**
   1923   Create the Confirm message and send it.
   1924 
   1925   @param[in]  Instance          The pointer to the Dhcp6 instance.
   1926 
   1927   @retval EFI_SUCCESS           Created and sent the confirm message successfully.
   1928   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1929   @retval EFI_DEVICE_ERROR      An unexpected error.
   1930   @retval Others                Failed to send the confirm message.
   1931 
   1932 **/
   1933 EFI_STATUS
   1934 Dhcp6SendConfirmMsg (
   1935   IN DHCP6_INSTANCE            *Instance
   1936   )
   1937 {
   1938   UINT8                        *Cursor;
   1939   UINTN                        Index;
   1940   UINT16                       Length;
   1941   UINT32                       UserLen;
   1942   EFI_STATUS                   Status;
   1943   DHCP6_SERVICE                *Service;
   1944   EFI_DHCP6_DUID               *ClientId;
   1945   EFI_DHCP6_PACKET             *Packet;
   1946   EFI_DHCP6_PACKET_OPTION      *UserOpt;
   1947   UINT16                       *Elapsed;
   1948 
   1949   ASSERT (Instance->Config != NULL);
   1950   ASSERT (Instance->IaCb.Ia != NULL);
   1951   ASSERT (Instance->Service != NULL);
   1952 
   1953   Service  = Instance->Service;
   1954   ClientId = Service->ClientId;
   1955   ASSERT (ClientId != NULL);
   1956 
   1957   //
   1958   // Calculate the added length of customized option list.
   1959   //
   1960   UserLen = 0;
   1961   for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
   1962     UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
   1963   }
   1964 
   1965   //
   1966   // Create the Dhcp6 packet and initialize common fields.
   1967   //
   1968   Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
   1969   if (Packet == NULL) {
   1970     return EFI_OUT_OF_RESOURCES;
   1971   }
   1972 
   1973   Packet->Size                       = DHCP6_BASE_PACKET_SIZE + UserLen;
   1974   Packet->Length                     = sizeof (EFI_DHCP6_HEADER);
   1975   Packet->Dhcp6.Header.MessageType   = Dhcp6MsgConfirm;
   1976   Packet->Dhcp6.Header.TransactionId = Service->Xid++;
   1977 
   1978   //
   1979   // Assembly Dhcp6 options for solicit message.
   1980   //
   1981   Cursor = Packet->Dhcp6.Option;
   1982 
   1983   Length = HTONS (ClientId->Length);
   1984   Cursor = Dhcp6AppendOption (
   1985              Cursor,
   1986              HTONS (Dhcp6OptClientId),
   1987              Length,
   1988              ClientId->Duid
   1989              );
   1990 
   1991   Cursor = Dhcp6AppendETOption (
   1992              Cursor,
   1993              Instance,
   1994              &Elapsed
   1995              );
   1996 
   1997   Cursor = Dhcp6AppendIaOption (
   1998              Cursor,
   1999              Instance->IaCb.Ia,
   2000              Instance->IaCb.T1,
   2001              Instance->IaCb.T2,
   2002              Packet->Dhcp6.Header.MessageType
   2003              );
   2004 
   2005   //
   2006   // Append user-defined when configurate Dhcp6 service.
   2007   //
   2008   for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
   2009     UserOpt = Instance->Config->OptionList[Index];
   2010     Cursor  = Dhcp6AppendOption (
   2011                 Cursor,
   2012                 UserOpt->OpCode,
   2013                 UserOpt->OpLen,
   2014                 UserOpt->Data
   2015                 );
   2016   }
   2017 
   2018   //
   2019   // Determine the size/length of packet.
   2020   //
   2021   Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
   2022   ASSERT (Packet->Size > Packet->Length + 8);
   2023 
   2024   //
   2025   // Callback to user with the packet to be sent and check the user's feedback.
   2026   //
   2027   Status = Dhcp6CallbackUser (Instance, Dhcp6SendConfirm, &Packet);
   2028 
   2029   if (EFI_ERROR (Status)) {
   2030     FreePool (Packet);
   2031     return Status;
   2032   }
   2033 
   2034   //
   2035   // Send confirm packet with the state transition from Dhcp6Bound to
   2036   // Dhcp6Confirming.
   2037   //
   2038   Instance->IaCb.Ia->State = Dhcp6Confirming;
   2039   //
   2040   // Clear initial time for current transaction.
   2041   //
   2042   Instance->StartTime = 0;
   2043 
   2044   Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
   2045 
   2046   if (EFI_ERROR (Status)) {
   2047     FreePool (Packet);
   2048     return Status;
   2049   }
   2050 
   2051   //
   2052   // Enqueue the sent packet for the retransmission in case reply timeout.
   2053   //
   2054   return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
   2055 }
   2056 
   2057 
   2058 
   2059 /**
   2060   Handle with the Dhcp6 reply message.
   2061 
   2062   @param[in]  Instance        The pointer to Dhcp6 instance.
   2063   @param[in]  Packet          The pointer to the Dhcp6 reply message.
   2064 
   2065   @retval EFI_SUCCESS           Processed the reply message successfully.
   2066   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   2067   @retval EFI_DEVICE_ERROR      An unexpected error.
   2068   @retval Others                Failed to process the reply message.
   2069 
   2070 **/
   2071 EFI_STATUS
   2072 Dhcp6HandleReplyMsg (
   2073   IN DHCP6_INSTANCE           *Instance,
   2074   IN EFI_DHCP6_PACKET         *Packet
   2075   )
   2076 {
   2077   EFI_STATUS                  Status;
   2078   UINT8                       *Option;
   2079   UINT16                      StsCode;
   2080 
   2081   ASSERT (Instance->Config != NULL);
   2082   ASSERT (Instance->IaCb.Ia != NULL);
   2083   ASSERT (Packet != NULL);
   2084 
   2085   Status = EFI_SUCCESS;
   2086 
   2087   if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {
   2088     return EFI_DEVICE_ERROR;
   2089   }
   2090 
   2091   //
   2092   // If the client subsequently receives a valid reply message that includes a
   2093   // rapid commit option since send a solicit with rapid commit option before,
   2094   // preocess the reply message and discard any reply messages received in
   2095   // response to the request message.
   2096   // See details in the section-17.1.4 of rfc-3315.
   2097   //
   2098   Option = Dhcp6SeekOption (
   2099              Packet->Dhcp6.Option,
   2100              Packet->Length - 4,
   2101              Dhcp6OptRapidCommit
   2102              );
   2103 
   2104   if ((Option != NULL && !Instance->Config->RapidCommit) || (Option == NULL && Instance->Config->RapidCommit)) {
   2105     return EFI_DEVICE_ERROR;
   2106   }
   2107 
   2108   //
   2109   // As to a valid reply packet in response to a request/renew/rebind packet,
   2110   // ignore the packet if not contains the Ia option
   2111   //
   2112   if (Instance->IaCb.Ia->State == Dhcp6Requesting ||
   2113       Instance->IaCb.Ia->State == Dhcp6Renewing ||
   2114       Instance->IaCb.Ia->State == Dhcp6Rebinding
   2115       ) {
   2116 
   2117     Option = Dhcp6SeekIaOption (
   2118                Packet->Dhcp6.Option,
   2119                Packet->Length,
   2120                &Instance->Config->IaDescriptor
   2121                );
   2122     if (Option == NULL) {
   2123       return EFI_SUCCESS;
   2124     }
   2125   }
   2126 
   2127   //
   2128   // Callback to user with the received packet and check the user's feedback.
   2129   //
   2130   Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdReply, &Packet);
   2131 
   2132   if (EFI_ERROR (Status)) {
   2133     return Status;
   2134   }
   2135 
   2136   //
   2137   // When receive a valid reply packet in response to a decline/release packet,
   2138   // the client considers the decline/release event completed regardless of the
   2139   // status code.
   2140   //
   2141   if (Instance->IaCb.Ia->State == Dhcp6Declining || Instance->IaCb.Ia->State == Dhcp6Releasing) {
   2142 
   2143     if (Instance->IaCb.Ia->IaAddressCount != 0) {
   2144       Instance->IaCb.Ia->State       = Dhcp6Bound;
   2145     } else {
   2146       ASSERT (Instance->IaCb.Ia->ReplyPacket);
   2147       FreePool (Instance->IaCb.Ia->ReplyPacket);
   2148       Instance->IaCb.Ia->ReplyPacket = NULL;
   2149       Instance->IaCb.Ia->State       = Dhcp6Init;
   2150     }
   2151 
   2152     //
   2153     // For sync, set the success flag out of polling in decline/release.
   2154     //
   2155     Instance->UdpSts = EFI_SUCCESS;
   2156 
   2157     //
   2158     // For async, signal the Ia event to inform Ia infomation update.
   2159     //
   2160     if (Instance->Config->IaInfoEvent != NULL) {
   2161       gBS->SignalEvent (Instance->Config->IaInfoEvent);
   2162     }
   2163 
   2164     //
   2165     // Reset start time for next exchange.
   2166     //
   2167     Instance->StartTime       = 0;
   2168 
   2169     Status = EFI_SUCCESS;
   2170     goto ON_EXIT;
   2171   }
   2172 
   2173   //
   2174   // Upon the receipt of a valid reply packet in response to a solicit, request,
   2175   // confirm, renew and rebind, the behavior depends on the status code option.
   2176   // See the details in the section-18.1.8 of rfc-3315.
   2177   //
   2178   Option = NULL;
   2179   Status = Dhcp6SeekStsOption (
   2180              Instance,
   2181              Packet,
   2182              &Option
   2183              );
   2184 
   2185   if (!EFI_ERROR (Status)) {
   2186     //
   2187     // No status code or no error status code means succeed to reply.
   2188     //
   2189     Status = Dhcp6UpdateIaInfo (Instance, Packet);
   2190     if (!EFI_ERROR (Status)) {
   2191       //
   2192       // Reset start time for next exchange.
   2193       //
   2194       Instance->StartTime       = 0;
   2195 
   2196       //
   2197       // Set bound state and store the reply packet.
   2198       //
   2199       if (Instance->IaCb.Ia->ReplyPacket != NULL) {
   2200         FreePool (Instance->IaCb.Ia->ReplyPacket);
   2201       }
   2202 
   2203       Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);
   2204 
   2205       if (Instance->IaCb.Ia->ReplyPacket == NULL) {
   2206         Status = EFI_OUT_OF_RESOURCES;
   2207         goto ON_EXIT;
   2208       }
   2209 
   2210       CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);
   2211 
   2212       Instance->IaCb.Ia->State = Dhcp6Bound;
   2213 
   2214       //
   2215       // For sync, set the success flag out of polling in start/renewrebind.
   2216       //
   2217       Instance->UdpSts         = EFI_SUCCESS;
   2218 
   2219       //
   2220       // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
   2221       // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that
   2222       // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
   2223       // consumers can be notified to flush old address.
   2224       //
   2225       Dhcp6AppendCacheIa (Instance);
   2226 
   2227       //
   2228       // For async, signal the Ia event to inform Ia infomation update.
   2229       //
   2230       if (Instance->Config->IaInfoEvent != NULL) {
   2231         gBS->SignalEvent (Instance->Config->IaInfoEvent);
   2232       }
   2233     } else if (Status == EFI_NOT_FOUND) {
   2234       //
   2235       // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,
   2236       // the client sends a Renew or Rebind if the IA is not in the Reply message.
   2237       // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.
   2238       //
   2239       return EFI_SUCCESS;
   2240     }
   2241 
   2242     goto ON_EXIT;
   2243 
   2244   } else if (Option != NULL) {
   2245     //
   2246     // Any error status code option is found.
   2247     //
   2248     StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4)));
   2249     switch (StsCode) {
   2250     case Dhcp6StsUnspecFail:
   2251       //
   2252       // It indicates the server is unable to process the message due to an
   2253       // unspecified failure condition, so just retry if possible.
   2254       //
   2255       break;
   2256 
   2257     case Dhcp6StsUseMulticast:
   2258       //
   2259       // It indicates the server receives a message via unicast from a client
   2260       // to which the server has not sent a unicast option, so retry it by
   2261       // multi-cast address.
   2262       //
   2263       if (Instance->Unicast != NULL) {
   2264         FreePool (Instance->Unicast);
   2265         Instance->Unicast = NULL;
   2266       }
   2267       break;
   2268 
   2269     case Dhcp6StsNotOnLink:
   2270       if (Instance->IaCb.Ia->State == Dhcp6Confirming) {
   2271         //
   2272         // Before initiate new round DHCP, cache the current IA.
   2273         //
   2274         Status = Dhcp6CacheIa (Instance);
   2275         if (EFI_ERROR (Status)) {
   2276           return  Status;
   2277         }
   2278 
   2279         //
   2280         // Restart S.A.R.R process to acquire new address.
   2281         //
   2282         Status = Dhcp6InitSolicitMsg (Instance);
   2283         if (EFI_ERROR (Status)) {
   2284           return Status;
   2285         }
   2286       }
   2287       break;
   2288 
   2289     case Dhcp6StsNoBinding:
   2290       if (Instance->IaCb.Ia->State == Dhcp6Renewing || Instance->IaCb.Ia->State == Dhcp6Rebinding) {
   2291         //
   2292         // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client
   2293         // sends a Request message if the IA contained a Status Code option with the NoBinding status.
   2294         //
   2295         Status = Dhcp6SendRequestMsg(Instance);
   2296         if (EFI_ERROR (Status)) {
   2297           return Status;
   2298         }
   2299       }
   2300       break;
   2301 
   2302     default:
   2303       //
   2304       // The other status code, just restart solicitation.
   2305       //
   2306       break;
   2307     }
   2308   }
   2309 
   2310   return EFI_SUCCESS;
   2311 
   2312 ON_EXIT:
   2313 
   2314   if (!EFI_ERROR(Status)) {
   2315     Status = Dhcp6DequeueRetry (
   2316                Instance,
   2317                Packet->Dhcp6.Header.TransactionId,
   2318                FALSE
   2319                );
   2320   }
   2321 
   2322   return Status;
   2323 }
   2324 
   2325 
   2326 /**
   2327   Select the appointed Dhcp6 advertisement message.
   2328 
   2329   @param[in]  Instance        The pointer to the Dhcp6 instance.
   2330   @param[in]  AdSelect        The pointer to the selected Dhcp6 advertisement message.
   2331 
   2332   @retval EFI_SUCCESS           Selected the right advertisement message successfully.
   2333   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   2334   @retval Others                Failed to select the advertise message.
   2335 
   2336 **/
   2337 EFI_STATUS
   2338 Dhcp6SelectAdvertiseMsg (
   2339   IN DHCP6_INSTANCE           *Instance,
   2340   IN EFI_DHCP6_PACKET         *AdSelect
   2341   )
   2342 {
   2343   EFI_STATUS                  Status;
   2344   UINT8                       *Option;
   2345 
   2346   ASSERT (AdSelect != NULL);
   2347 
   2348   //
   2349   // Callback to user with the selected advertisement packet, and the user
   2350   // might overwrite it.
   2351   //
   2352   Status = Dhcp6CallbackUser (Instance, Dhcp6SelectAdvertise, &AdSelect);
   2353 
   2354   if (EFI_ERROR (Status)) {
   2355     return Status;
   2356   }
   2357 
   2358   Instance->AdSelect = AdSelect;
   2359 
   2360   //
   2361   // Dequeue the sent packet for the retransmission since advertisement selected.
   2362   //
   2363   Status = Dhcp6DequeueRetry (
   2364              Instance,
   2365              AdSelect->Dhcp6.Header.TransactionId,
   2366              FALSE
   2367              );
   2368 
   2369   if (EFI_ERROR(Status)) {
   2370     return Status;
   2371   }
   2372 
   2373   //
   2374   // Check whether there is server unicast option in the selected advertise
   2375   // packet, and update it.
   2376   //
   2377   Option = Dhcp6SeekOption(
   2378              AdSelect->Dhcp6.Option,
   2379              AdSelect->Length - 4,
   2380              Dhcp6OptServerUnicast
   2381              );
   2382 
   2383   if (Option != NULL) {
   2384 
   2385     Instance->Unicast = AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS));
   2386 
   2387     if (Instance->Unicast == NULL) {
   2388       return EFI_OUT_OF_RESOURCES;
   2389     }
   2390 
   2391     CopyMem (Instance->Unicast, Option + 4, sizeof(EFI_IPv6_ADDRESS));
   2392   }
   2393 
   2394   //
   2395   // Update the information of the Ia by the selected advertisement message.
   2396   //
   2397   Status = Dhcp6UpdateIaInfo (Instance, AdSelect);
   2398 
   2399   if (EFI_ERROR (Status)) {
   2400     return Status;
   2401   }
   2402 
   2403   //
   2404   // Send the request message to continue the S.A.R.R. process.
   2405   //
   2406   return Dhcp6SendRequestMsg (Instance);
   2407 }
   2408 
   2409 
   2410 /**
   2411   Handle with the Dhcp6 advertisement message.
   2412 
   2413   @param[in]  Instance        The pointer to the Dhcp6 instance.
   2414   @param[in]  Packet          The pointer to the Dhcp6 advertisement message.
   2415 
   2416   @retval EFI_SUCCESS           Processed the advertisement message successfully.
   2417   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   2418   @retval EFI_DEVICE_ERROR      An unexpected error.
   2419   @retval Others                Failed to process the advertise message.
   2420 
   2421 **/
   2422 EFI_STATUS
   2423 Dhcp6HandleAdvertiseMsg (
   2424   IN DHCP6_INSTANCE           *Instance,
   2425   IN EFI_DHCP6_PACKET         *Packet
   2426   )
   2427 {
   2428   EFI_STATUS                  Status;
   2429   UINT8                       *Option;
   2430   BOOLEAN                     Timeout;
   2431 
   2432   ASSERT(Instance->Config);
   2433   ASSERT(Instance->IaCb.Ia);
   2434 
   2435   Timeout = FALSE;
   2436 
   2437   //
   2438   // If the client does receives a valid reply message that includes a rapid
   2439   // commit option since a solicit with rapid commit optioin sent before, select
   2440   // this reply message. Or else, process the advertise messages as normal.
   2441   // See details in the section-17.1.4 of rfc-3315.
   2442   //
   2443   Option = Dhcp6SeekOption(
   2444              Packet->Dhcp6.Option,
   2445              Packet->Length - 4,
   2446              Dhcp6OptRapidCommit
   2447              );
   2448 
   2449   if (Option != NULL && Instance->Config->RapidCommit && Packet->Dhcp6.Header.MessageType == Dhcp6MsgReply) {
   2450 
   2451     return Dhcp6HandleReplyMsg (Instance, Packet);
   2452   }
   2453 
   2454   if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise) {
   2455     return EFI_DEVICE_ERROR;
   2456   }
   2457 
   2458   //
   2459   // Client must ignore any advertise message that includes a status code option
   2460   // containing the value noaddrsavail, with the exception that the client may
   2461   // display the associated status message to the user.
   2462   // See the details in the section-17.1.3 of rfc-3315.
   2463   //
   2464   Status = Dhcp6SeekStsOption (
   2465              Instance,
   2466              Packet,
   2467              &Option
   2468              );
   2469   if (EFI_ERROR (Status)) {
   2470     return EFI_DEVICE_ERROR;
   2471   }
   2472 
   2473   //
   2474   // Callback to user with the received packet and check the user's feedback.
   2475   //
   2476   Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdAdvertise, &Packet);
   2477 
   2478   if (!EFI_ERROR (Status)) {
   2479     //
   2480     // Success means user choose the current advertisement packet.
   2481     //
   2482     if (Instance->AdSelect != NULL) {
   2483       FreePool (Instance->AdSelect);
   2484     }
   2485 
   2486     //
   2487     // Store the selected advertisement packet and set a flag.
   2488     //
   2489     Instance->AdSelect = AllocateZeroPool (Packet->Size);
   2490 
   2491     if (Instance->AdSelect == NULL) {
   2492       return EFI_OUT_OF_RESOURCES;
   2493     }
   2494 
   2495     CopyMem (Instance->AdSelect, Packet, Packet->Size);
   2496 
   2497     Instance->AdPref = 0xff;
   2498 
   2499   } else if (Status == EFI_NOT_READY) {
   2500     //
   2501     // Not_ready means user wants to continue to receive more advertise packets.
   2502     //
   2503     if (Instance->AdPref == 0xff && Instance->AdSelect == NULL) {
   2504       //
   2505       // It's a tricky point. The timer routine set adpref as 0xff if the first
   2506       // rt timeout and no advertisement received, which means any advertisement
   2507       // received will be selected after the first rt.
   2508       //
   2509       Timeout = TRUE;
   2510     }
   2511 
   2512     //
   2513     // Check whether the current packet has a 255 preference option or not.
   2514     // Take non-preference option as 0 value.
   2515     //
   2516     Option = Dhcp6SeekOption(
   2517                Packet->Dhcp6.Option,
   2518                Packet->Length - 4,
   2519                Dhcp6OptPreference
   2520                );
   2521 
   2522     if (Instance->AdSelect == NULL || (Option != NULL && *(Option + 4) > Instance->AdPref)) {
   2523       //
   2524       // No advertisements received before or preference is more than other
   2525       // advertisements received before. Then store the new packet and the
   2526       // preference value.
   2527       //
   2528       if (Instance->AdSelect != NULL) {
   2529         FreePool (Instance->AdSelect);
   2530       }
   2531 
   2532       Instance->AdSelect = AllocateZeroPool (Packet->Size);
   2533 
   2534       if (Instance->AdSelect == NULL) {
   2535         return EFI_OUT_OF_RESOURCES;
   2536       }
   2537 
   2538       CopyMem (Instance->AdSelect, Packet, Packet->Size);
   2539 
   2540       if (Option != NULL) {
   2541         Instance->AdPref = *(Option + 4);
   2542       }
   2543     } else {
   2544       //
   2545       // Non-preference and other advertisements received before or current
   2546       // preference is less than other advertisements received before.
   2547       // Leave the packet alone.
   2548     }
   2549 
   2550   } else {
   2551     //
   2552     // Other error status means termination.
   2553     //
   2554     return Status;
   2555   }
   2556 
   2557   //
   2558   // Client must collect advertise messages as more as possible until the first
   2559   // RT has elapsed, or get a highest preference 255 advertise.
   2560   // See details in the section-17.1.2 of rfc-3315.
   2561   //
   2562   if (Instance->AdPref == 0xff || Timeout) {
   2563     Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);
   2564   }
   2565 
   2566   return Status;
   2567 }
   2568 
   2569 
   2570 /**
   2571   The Dhcp6 stateful exchange process routine.
   2572 
   2573   @param[in]  Instance        The pointer to the Dhcp6 instance.
   2574   @param[in]  Packet          The pointer to the received Dhcp6 message.
   2575 
   2576 **/
   2577 VOID
   2578 Dhcp6HandleStateful (
   2579   IN DHCP6_INSTANCE         *Instance,
   2580   IN EFI_DHCP6_PACKET       *Packet
   2581   )
   2582 {
   2583   EFI_STATUS                Status;
   2584   EFI_DHCP6_DUID            *ClientId;
   2585   DHCP6_SERVICE             *Service;
   2586   UINT8                     *Option;
   2587 
   2588   Service  = Instance->Service;
   2589   ClientId = Service->ClientId;
   2590   Status   = EFI_SUCCESS;
   2591 
   2592   if (Instance->Config == NULL) {
   2593     goto ON_CONTINUE;
   2594   }
   2595 
   2596   ASSERT (ClientId);
   2597   ASSERT (Instance->Config);
   2598   ASSERT (Instance->IaCb.Ia);
   2599 
   2600   //
   2601   // Discard the packet if not advertisement or reply packet.
   2602   //
   2603   if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise && Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {
   2604     goto ON_CONTINUE;
   2605   }
   2606 
   2607   //
   2608   // Check whether include client Id or not.
   2609   //
   2610   Option = Dhcp6SeekOption(
   2611              Packet->Dhcp6.Option,
   2612              Packet->Length - 4,
   2613              Dhcp6OptClientId
   2614              );
   2615 
   2616   if (Option == NULL || CompareMem (Option + 4, ClientId->Duid, ClientId->Length) != 0) {
   2617     goto ON_CONTINUE;
   2618   }
   2619 
   2620   //
   2621   // Check whether include server Id or not.
   2622   //
   2623   Option = Dhcp6SeekOption(
   2624              Packet->Dhcp6.Option,
   2625              Packet->Length - 4,
   2626              Dhcp6OptServerId
   2627              );
   2628 
   2629   if (Option == NULL) {
   2630     goto ON_CONTINUE;
   2631   }
   2632 
   2633   switch (Instance->IaCb.Ia->State) {
   2634   case Dhcp6Selecting:
   2635     //
   2636     // Handle the advertisement message when in the Dhcp6Selecting state.
   2637     // Do not need check return status, if failed, just continue to the next.
   2638     //
   2639     Dhcp6HandleAdvertiseMsg (Instance, Packet);
   2640     break;
   2641 
   2642   case Dhcp6Requesting:
   2643   case Dhcp6Confirming:
   2644   case Dhcp6Renewing:
   2645   case Dhcp6Rebinding:
   2646   case Dhcp6Releasing:
   2647   case Dhcp6Declining:
   2648     //
   2649     // Handle the reply message when in the Dhcp6Requesting,  Dhcp6Renewing
   2650     // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
   2651     // If failed here, it should reset the current session.
   2652     //
   2653     Status = Dhcp6HandleReplyMsg (Instance, Packet);
   2654     if (EFI_ERROR (Status)) {
   2655       goto ON_EXIT;
   2656     }
   2657     break;
   2658   default:
   2659     //
   2660     // Other state has not supported yet.
   2661     //
   2662     break;
   2663   }
   2664 
   2665 ON_CONTINUE:
   2666   //
   2667   // Continue to receive the following Dhcp6 message.
   2668   //
   2669   Status = UdpIoRecvDatagram (
   2670              Service->UdpIo,
   2671              Dhcp6ReceivePacket,
   2672              Service,
   2673              0
   2674              );
   2675 ON_EXIT:
   2676   if (EFI_ERROR (Status)) {
   2677     Dhcp6CleanupSession (Instance, Status);
   2678   }
   2679 }
   2680 
   2681 
   2682 /**
   2683   The Dhcp6 stateless exchange process routine.
   2684 
   2685   @param[in]  Instance        The pointer to the Dhcp6 instance.
   2686   @param[in]  Packet          The pointer to the received Dhcp6 message.
   2687 
   2688 **/
   2689 VOID
   2690 Dhcp6HandleStateless (
   2691   IN DHCP6_INSTANCE         *Instance,
   2692   IN EFI_DHCP6_PACKET       *Packet
   2693   )
   2694 {
   2695   EFI_STATUS                Status;
   2696   DHCP6_SERVICE             *Service;
   2697   DHCP6_INF_CB              *InfCb;
   2698   UINT8                     *Option;
   2699   BOOLEAN                   IsMatched;
   2700 
   2701   Service   = Instance->Service;
   2702   Status    = EFI_SUCCESS;
   2703   IsMatched = FALSE;
   2704   InfCb     = NULL;
   2705 
   2706   if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {
   2707     goto ON_EXIT;
   2708   }
   2709 
   2710   //
   2711   // Check whether it's a desired Info-request message by Xid.
   2712   //
   2713   while (!IsListEmpty (&Instance->InfList)) {
   2714     InfCb = NET_LIST_HEAD (&Instance->InfList, DHCP6_INF_CB, Link);
   2715     if (InfCb->Xid == Packet->Dhcp6.Header.TransactionId) {
   2716       IsMatched = TRUE;
   2717       break;
   2718     }
   2719   }
   2720 
   2721   if (!IsMatched) {
   2722     goto ON_EXIT;
   2723   }
   2724 
   2725   //
   2726   // Check whether include server Id or not.
   2727   //
   2728   Option = Dhcp6SeekOption (
   2729              Packet->Dhcp6.Option,
   2730              Packet->Length - 4,
   2731              Dhcp6OptServerId
   2732              );
   2733 
   2734   if (Option == NULL) {
   2735     goto ON_EXIT;
   2736   }
   2737 
   2738   //
   2739   // Callback to user with the received packet and check the user's feedback.
   2740   //
   2741   Status = InfCb->ReplyCallback (
   2742                     &Instance->Dhcp6,
   2743                     InfCb->CallbackContext,
   2744                     Packet
   2745                     );
   2746 
   2747   if (Status == EFI_NOT_READY) {
   2748     //
   2749     // Success or aborted will both stop this info-request exchange process,
   2750     // but not ready means user wants to continue to receive reply.
   2751     //
   2752     goto ON_EXIT;
   2753   }
   2754 
   2755   //
   2756   // Dequeue the sent packet from the txlist if the xid matched, and ignore
   2757   // if no xid matched.
   2758   //
   2759   Dhcp6DequeueRetry (
   2760     Instance,
   2761     Packet->Dhcp6.Header.TransactionId,
   2762     FALSE
   2763     );
   2764 
   2765   //
   2766   // For sync, set the status out of polling for info-request.
   2767   //
   2768   Instance->UdpSts = Status;
   2769 
   2770 ON_EXIT:
   2771 
   2772   Status = UdpIoRecvDatagram (
   2773              Service->UdpIo,
   2774              Dhcp6ReceivePacket,
   2775              Service,
   2776              0
   2777              );
   2778 
   2779   if (EFI_ERROR (Status)) {
   2780     Dhcp6CleanupRetry (Instance, DHCP6_PACKET_STATELESS);
   2781   }
   2782 }
   2783 
   2784 
   2785 /**
   2786   The receive callback function for Dhcp6 exchange process.
   2787 
   2788   @param[in]  Udp6Wrap        The pointer to the received net buffer.
   2789   @param[in]  EndPoint        The pointer to the udp end point.
   2790   @param[in]  IoStatus        The return status from udp io.
   2791   @param[in]  Context         The opaque parameter to the function.
   2792 
   2793 **/
   2794 VOID
   2795 EFIAPI
   2796 Dhcp6ReceivePacket (
   2797   IN NET_BUF                *Udp6Wrap,
   2798   IN UDP_END_POINT          *EndPoint,
   2799   IN EFI_STATUS             IoStatus,
   2800   IN VOID                   *Context
   2801   )
   2802 {
   2803   EFI_DHCP6_HEADER          *Head;
   2804   EFI_DHCP6_PACKET          *Packet;
   2805   DHCP6_SERVICE             *Service;
   2806   DHCP6_INSTANCE            *Instance;
   2807   DHCP6_TX_CB               *TxCb;
   2808   UINT32                    Size;
   2809   BOOLEAN                   IsDispatched;
   2810   BOOLEAN                   IsStateless;
   2811   LIST_ENTRY                *Entry1;
   2812   LIST_ENTRY                *Next1;
   2813   LIST_ENTRY                *Entry2;
   2814   LIST_ENTRY                *Next2;
   2815   EFI_STATUS                Status;
   2816 
   2817   ASSERT (Udp6Wrap != NULL);
   2818   ASSERT (Context != NULL);
   2819 
   2820   Service      = (DHCP6_SERVICE *) Context;
   2821   Instance     = NULL;
   2822   Packet       = NULL;
   2823   IsDispatched = FALSE;
   2824   IsStateless  = FALSE;
   2825 
   2826   if (EFI_ERROR (IoStatus)) {
   2827     return ;
   2828   }
   2829 
   2830   //
   2831   // Copy the net buffer received from upd6 to a Dhcp6 packet.
   2832   //
   2833   Size   = sizeof (EFI_DHCP6_PACKET) + Udp6Wrap->TotalSize;
   2834   Packet = (EFI_DHCP6_PACKET *) AllocateZeroPool (Size);
   2835 
   2836   if (Packet == NULL) {
   2837     goto ON_CONTINUE;
   2838   }
   2839 
   2840   Packet->Size   = Size;
   2841   Head           = &Packet->Dhcp6.Header;
   2842   Packet->Length = NetbufCopy (Udp6Wrap, 0, Udp6Wrap->TotalSize, (UINT8 *) Head);
   2843 
   2844   if (Packet->Length == 0) {
   2845     goto ON_CONTINUE;
   2846   }
   2847 
   2848   //
   2849   // Dispatch packet to right instance by transaction id.
   2850   //
   2851   NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) {
   2852 
   2853     Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link);
   2854 
   2855     NET_LIST_FOR_EACH_SAFE (Entry2, Next2, &Instance->TxList) {
   2856 
   2857       TxCb = NET_LIST_USER_STRUCT (Entry2, DHCP6_TX_CB, Link);
   2858 
   2859       if (Packet->Dhcp6.Header.TransactionId == TxCb->Xid) {
   2860         //
   2861         // Find the corresponding packet in tx list, and check it whether belongs
   2862         // to stateful exchange process.
   2863         //
   2864         if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
   2865           IsStateless = TRUE;
   2866         }
   2867         IsDispatched  = TRUE;
   2868         break;
   2869       }
   2870     }
   2871 
   2872     if (IsDispatched) {
   2873       break;
   2874     }
   2875   }
   2876 
   2877   //
   2878   // Skip this packet if not dispatched to any instance.
   2879   //
   2880   if (!IsDispatched) {
   2881     goto ON_CONTINUE;
   2882   }
   2883 
   2884   //
   2885   // Dispatch the received packet ot the right instance.
   2886   //
   2887   if (IsStateless) {
   2888     Dhcp6HandleStateless (Instance, Packet);
   2889   } else {
   2890     Dhcp6HandleStateful (Instance, Packet);
   2891   }
   2892 
   2893 ON_CONTINUE:
   2894 
   2895   if (!IsDispatched) {
   2896     Status = UdpIoRecvDatagram (
   2897              Service->UdpIo,
   2898              Dhcp6ReceivePacket,
   2899              Service,
   2900              0
   2901              );
   2902     if (EFI_ERROR (Status)) {
   2903       NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) {
   2904         Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link);
   2905         Dhcp6CleanupRetry (Instance, DHCP6_PACKET_ALL);
   2906       }
   2907     }
   2908   }
   2909 
   2910   NetbufFree (Udp6Wrap);
   2911 
   2912   if (Packet != NULL) {
   2913     FreePool (Packet);
   2914   }
   2915 }
   2916 
   2917 /**
   2918   Detect Link movement for specified network device.
   2919 
   2920   This routine will try to invoke Snp->GetStatus() to get the media status.
   2921   If media present status switches from unpresent to present, a link movement
   2922   is detected. Note that the underlying UNDI driver may not support reporting
   2923   media status from GET_STATUS command. If that, fail to detect link movement.
   2924 
   2925   @param[in]  Instance       The pointer to DHCP6_INSTANCE.
   2926 
   2927   @retval     TRUE           A link movement is detected.
   2928   @retval     FALSE          A link movement is not detected.
   2929 
   2930 **/
   2931 BOOLEAN
   2932 Dhcp6LinkMovDetect (
   2933   IN  DHCP6_INSTANCE            *Instance
   2934   )
   2935 {
   2936   UINT32                       InterruptStatus;
   2937   BOOLEAN                      MediaPresent;
   2938   EFI_STATUS                   Status;
   2939   EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;
   2940 
   2941   ASSERT (Instance != NULL);
   2942   Snp = Instance->Service->Snp;
   2943   MediaPresent = Instance->MediaPresent;
   2944 
   2945   //
   2946   // Check whether SNP support media detection
   2947   //
   2948   if (!Snp->Mode->MediaPresentSupported) {
   2949     return FALSE;
   2950   }
   2951 
   2952   //
   2953   // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
   2954   //
   2955   Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);
   2956   if (EFI_ERROR (Status)) {
   2957     return FALSE;
   2958   }
   2959 
   2960   Instance->MediaPresent = Snp->Mode->MediaPresent;
   2961   //
   2962   // Media transimit Unpresent to Present means new link movement is detected.
   2963   //
   2964   if (!MediaPresent && Instance->MediaPresent) {
   2965     return TRUE;
   2966   }
   2967   return FALSE;
   2968 }
   2969 
   2970 
   2971 /**
   2972   The timer routine of the Dhcp6 instance for each second.
   2973 
   2974   @param[in]  Event           The timer event.
   2975   @param[in]  Context         The opaque parameter to the function.
   2976 
   2977 **/
   2978 VOID
   2979 EFIAPI
   2980 Dhcp6OnTimerTick (
   2981   IN EFI_EVENT              Event,
   2982   IN VOID                   *Context
   2983   )
   2984 {
   2985   LIST_ENTRY                *Entry;
   2986   LIST_ENTRY                *NextEntry;
   2987   DHCP6_INSTANCE            *Instance;
   2988   DHCP6_TX_CB               *TxCb;
   2989   DHCP6_IA_CB               *IaCb;
   2990   UINT32                    LossTime;
   2991   EFI_STATUS                Status;
   2992 
   2993   ASSERT (Context != NULL);
   2994 
   2995   Instance = (DHCP6_INSTANCE *) Context;
   2996 
   2997   //
   2998   // 1. Loop the tx list, count live time of every tx packet to check whether
   2999   //    need re-transmit or not.
   3000   //
   3001   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {
   3002 
   3003     TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);
   3004 
   3005     TxCb->TickTime++;
   3006 
   3007     if (TxCb->TickTime > TxCb->RetryExp) {
   3008       //
   3009       // Handle the first rt in the transmission of solicit specially.
   3010       //
   3011       if ((TxCb->RetryCnt == 0 || TxCb->SolicitRetry) && TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) {
   3012         if (Instance->AdSelect == NULL) {
   3013           //
   3014           // Set adpref as 0xff here to indicate select any advertisement
   3015           // afterwards.
   3016           //
   3017           Instance->AdPref = 0xff;
   3018         } else {
   3019           //
   3020           // Select the advertisement received before.
   3021           //
   3022           Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);
   3023           if (Status == EFI_ABORTED) {
   3024             goto ON_CLOSE;
   3025           } else if (EFI_ERROR (Status)) {
   3026             TxCb->RetryCnt++;
   3027           }
   3028           return;
   3029         }
   3030       }
   3031       //
   3032       // Increase the retry count for the packet and add up the total loss time.
   3033       //
   3034       TxCb->RetryCnt++;
   3035       TxCb->RetryLos += TxCb->RetryExp;
   3036 
   3037       //
   3038       // Check whether overflow the max retry count limit for this packet
   3039       //
   3040       if (TxCb->RetryCtl.Mrc != 0 && TxCb->RetryCtl.Mrc < TxCb->RetryCnt) {
   3041         Status = EFI_NO_RESPONSE;
   3042         goto ON_CLOSE;
   3043       }
   3044 
   3045       //
   3046       // Check whether overflow the max retry duration for this packet
   3047       //
   3048       if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd <= TxCb->RetryLos) {
   3049         Status = EFI_NO_RESPONSE;
   3050         goto ON_CLOSE;
   3051       }
   3052 
   3053       //
   3054       // Re-calculate retry expire timeout for the next time.
   3055       //
   3056       // Firstly, Check the new calculated time whether overflow the max retry
   3057       // expire time.
   3058       //
   3059       TxCb->RetryExp = Dhcp6CalculateExpireTime (
   3060                          TxCb->RetryExp,
   3061                          FALSE,
   3062                          TRUE
   3063                          );
   3064 
   3065       if (TxCb->RetryCtl.Mrt != 0 && TxCb->RetryCtl.Mrt < TxCb->RetryExp) {
   3066         TxCb->RetryExp = Dhcp6CalculateExpireTime (
   3067                            TxCb->RetryCtl.Mrt,
   3068                            TRUE,
   3069                            TRUE
   3070                            );
   3071       }
   3072 
   3073       //
   3074       // Secondly, Check the new calculated time whether overflow the max retry
   3075       // duration time.
   3076       //
   3077       LossTime = TxCb->RetryLos + TxCb->RetryExp;
   3078       if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd < LossTime) {
   3079         TxCb->RetryExp = TxCb->RetryCtl.Mrd - TxCb->RetryLos;
   3080       }
   3081 
   3082       //
   3083       // Reset the tick time for the next retransmission
   3084       //
   3085       TxCb->TickTime = 0;
   3086 
   3087       //
   3088       // Retransmit the last sent packet again.
   3089       //
   3090       Dhcp6TransmitPacket (Instance, TxCb->TxPacket, TxCb->Elapsed);
   3091       TxCb->SolicitRetry = FALSE;
   3092       if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) {
   3093         TxCb->SolicitRetry = TRUE;
   3094       }
   3095     }
   3096   }
   3097 
   3098   //
   3099   // 2. Check the configured Ia, count lease time of every valid Ia to check
   3100   // whether need to renew or rebind this Ia.
   3101   //
   3102   IaCb = &Instance->IaCb;
   3103 
   3104   if (Instance->Config == NULL || IaCb->Ia == NULL) {
   3105     return;
   3106   }
   3107 
   3108   if (IaCb->Ia->State == Dhcp6Bound || IaCb->Ia->State == Dhcp6Renewing || IaCb->Ia->State == Dhcp6Rebinding) {
   3109 
   3110     IaCb->LeaseTime++;
   3111 
   3112     if (IaCb->LeaseTime > IaCb->T2 && IaCb->Ia->State == Dhcp6Bound) {
   3113       //
   3114       // Exceed t2, send rebind packet to extend the Ia lease.
   3115       //
   3116       Dhcp6SendRenewRebindMsg (Instance, TRUE);
   3117 
   3118     } else if (IaCb->LeaseTime > IaCb->T1 && IaCb->Ia->State == Dhcp6Bound) {
   3119 
   3120       //
   3121       // Exceed t1, send renew packet to extend the Ia lease.
   3122       //
   3123       Dhcp6SendRenewRebindMsg (Instance, FALSE);
   3124     }
   3125   }
   3126 
   3127   //
   3128   // 3. In any situation when a client may have moved to a new link, the
   3129   //    client MUST initiate a Confirm/Reply message exchange.
   3130   //
   3131   if (Dhcp6LinkMovDetect (Instance) && (IaCb->Ia->State == Dhcp6Bound)) {
   3132     Dhcp6SendConfirmMsg (Instance);
   3133   }
   3134 
   3135   return;
   3136 
   3137  ON_CLOSE:
   3138 
   3139   if (Dhcp6IsValidTxCb (Instance, TxCb) &&
   3140       TxCb->TxPacket != NULL &&
   3141       (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest ||
   3142       TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew       ||
   3143       TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm)
   3144       ) {
   3145     //
   3146     // The failure of renew/Confirm will still switch to the bound state.
   3147     //
   3148     if ((TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew) ||
   3149         (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm)) {
   3150       ASSERT (Instance->IaCb.Ia);
   3151       Instance->IaCb.Ia->State = Dhcp6Bound;
   3152     }
   3153     //
   3154     // The failure of info-request will return no response.
   3155     //
   3156     if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
   3157       Instance->UdpSts = EFI_NO_RESPONSE;
   3158     }
   3159     Dhcp6DequeueRetry (
   3160       Instance,
   3161       TxCb->Xid,
   3162       TRUE
   3163       );
   3164   } else {
   3165     //
   3166     // The failure of the others will terminate current state machine if timeout.
   3167     //
   3168     Dhcp6CleanupSession (Instance, Status);
   3169   }
   3170 }
   3171