Home | History | Annotate | Download | only in Dhcp6Dxe
      1 /** @file
      2   Dhcp6 support functions implementation.
      3 
      4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2014, 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   Generate client Duid in the format of Duid-llt.
     22 
     23   @param[in]  Mode          The pointer to the mode of SNP.
     24 
     25   @retval     NULL          If it failed to generate a client Id.
     26   @retval     others        The pointer to the new client id.
     27 
     28 **/
     29 EFI_DHCP6_DUID *
     30 Dhcp6GenerateClientId (
     31   IN EFI_SIMPLE_NETWORK_MODE   *Mode
     32   )
     33 {
     34   EFI_STATUS                Status;
     35   EFI_DHCP6_DUID            *Duid;
     36   EFI_TIME                  Time;
     37   UINT32                    Stamp;
     38   EFI_GUID                  Uuid;
     39 
     40 
     41   //
     42   // Attempt to get client Id from variable to keep it constant.
     43   // See details in section-9 of rfc-3315.
     44   //
     45   GetVariable2 (L"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid, (VOID**)&Duid, NULL);
     46   if (Duid != NULL) {
     47     return Duid;
     48   }
     49 
     50   //
     51   //  The format of client identifier option:
     52   //
     53   //     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
     54   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     55   //    |        OPTION_CLIENTID        |          option-len           |
     56   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     57   //    .                                                               .
     58   //    .                              DUID                             .
     59   //    .                        (variable length)                      .
     60   //    .                                                               .
     61   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     62   //
     63 
     64   //
     65   // If System UUID is found from SMBIOS Table, use DUID-UUID type.
     66   //
     67   if ((PcdGet8 (PcdDhcp6UidType) == Dhcp6DuidTypeUuid) && !EFI_ERROR (NetLibGetSystemGuid (&Uuid))) {
     68     //
     69     //
     70     //  The format of DUID-UUID:
     71     //
     72     //    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
     73     //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     74     //   |          DUID-Type (4)        |    UUID (128 bits)            |
     75     //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
     76     //   |                                                               |
     77     //   |                                                               |
     78     //   |                                -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     79     //   |                                |
     80     //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
     81 
     82     //
     83     // sizeof (option-len + Duid-type + UUID-size) = 20 bytes
     84     //
     85     Duid = AllocateZeroPool (2 + 2 + sizeof (EFI_GUID));
     86     if (Duid == NULL) {
     87       return NULL;
     88     }
     89 
     90     //
     91     // sizeof (Duid-type + UUID-size) = 18 bytes
     92     //
     93     Duid->Length = (UINT16) (18);
     94 
     95     //
     96     // Set the Duid-type and copy UUID.
     97     //
     98     WriteUnaligned16 ((UINT16 *) (Duid->Duid), HTONS (Dhcp6DuidTypeUuid));
     99 
    100     CopyMem (Duid->Duid + 2, &Uuid, sizeof(EFI_GUID));
    101 
    102   } else {
    103 
    104     //
    105     //
    106     //  The format of DUID-LLT:
    107     //
    108     //     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
    109     //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    110     //    |          Duid type (1)        |    hardware type (16 bits)    |
    111     //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    112     //    |                        time (32 bits)                         |
    113     //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    114     //    .                                                               .
    115     //    .             link-layer address (variable length)              .
    116     //    .                                                               .
    117     //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    118     //
    119 
    120     //
    121     // Generate a time stamp of the seconds from 2000/1/1, assume 30day/month.
    122     //
    123     gRT->GetTime (&Time, NULL);
    124     Stamp = (UINT32)
    125       (
    126         (((((Time.Year - 2000) * 360 + (Time.Month - 1)) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) *
    127         60 +
    128         Time.Second
    129       );
    130 
    131     //
    132     // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes
    133     //
    134     Duid = AllocateZeroPool (10 + Mode->HwAddressSize);
    135     if (Duid == NULL) {
    136       return NULL;
    137     }
    138 
    139     //
    140     // sizeof (Duid-type + hardware-type + time) = 8 bytes
    141     //
    142     Duid->Length = (UINT16) (Mode->HwAddressSize + 8);
    143 
    144     //
    145     // Set the Duid-type, hardware-type, time and copy the hardware address.
    146     //
    147     WriteUnaligned16 ((UINT16 *) ((UINT8 *) Duid + OFFSET_OF (EFI_DHCP6_DUID, Duid)), HTONS (Dhcp6DuidTypeLlt));
    148     WriteUnaligned16 ((UINT16 *) ((UINT8 *) Duid + OFFSET_OF (EFI_DHCP6_DUID, Duid) + 2), HTONS (NET_IFTYPE_ETHERNET));
    149     WriteUnaligned32 ((UINT32 *) ((UINT8 *) Duid + OFFSET_OF (EFI_DHCP6_DUID, Duid) + 4), HTONL (Stamp));
    150 
    151     CopyMem (Duid->Duid + 8, &Mode->CurrentAddress, Mode->HwAddressSize);
    152   }
    153 
    154   Status = gRT->SetVariable (
    155                   L"ClientId",
    156                   &gEfiDhcp6ServiceBindingProtocolGuid,
    157                   (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS),
    158                   Duid->Length + 2,
    159                   (VOID *) Duid
    160                   );
    161   if (EFI_ERROR (Status)) {
    162     FreePool (Duid);
    163     return NULL;
    164   }
    165 
    166   return Duid;
    167 }
    168 
    169 
    170 /**
    171   Copy the Dhcp6 configure data.
    172 
    173   @param[in]  DstCfg        The pointer to the destination configure data.
    174   @param[in]  SorCfg        The pointer to the source configure data.
    175 
    176   @retval EFI_SUCCESS           Copy the content from SorCfg from DstCfg successfully.
    177   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
    178 
    179 **/
    180 EFI_STATUS
    181 Dhcp6CopyConfigData (
    182   IN EFI_DHCP6_CONFIG_DATA      *DstCfg,
    183   IN EFI_DHCP6_CONFIG_DATA      *SorCfg
    184   )
    185 {
    186   UINTN                     Index;
    187   UINTN                     OptionListSize;
    188   UINTN                     OptionSize;
    189 
    190   CopyMem (DstCfg, SorCfg, sizeof (EFI_DHCP6_CONFIG_DATA));
    191 
    192   //
    193   // Allocate another buffer for solicitretransmission, and copy it.
    194   //
    195   if (SorCfg->SolicitRetransmission != NULL) {
    196 
    197     DstCfg->SolicitRetransmission = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));
    198 
    199     if (DstCfg->SolicitRetransmission == NULL) {
    200       //
    201       // Error will be handled out of this function.
    202       //
    203       return EFI_OUT_OF_RESOURCES;
    204     }
    205 
    206     CopyMem (
    207       DstCfg->SolicitRetransmission,
    208       SorCfg->SolicitRetransmission,
    209       sizeof (EFI_DHCP6_RETRANSMISSION)
    210       );
    211   }
    212 
    213   if (SorCfg->OptionList != NULL && SorCfg->OptionCount != 0) {
    214 
    215     OptionListSize     = SorCfg->OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *);
    216     DstCfg->OptionList = AllocateZeroPool (OptionListSize);
    217 
    218     if (DstCfg->OptionList == NULL) {
    219       //
    220       // Error will be handled out of this function.
    221       //
    222       return EFI_OUT_OF_RESOURCES;
    223     }
    224 
    225     for (Index = 0; Index < SorCfg->OptionCount; Index++) {
    226 
    227       OptionSize                = NTOHS (SorCfg->OptionList[Index]->OpLen) + 4;
    228       DstCfg->OptionList[Index] = AllocateZeroPool (OptionSize);
    229 
    230       if (DstCfg->OptionList[Index] == NULL) {
    231         //
    232         // Error will be handled out of this function.
    233         //
    234         return EFI_OUT_OF_RESOURCES;
    235       }
    236 
    237       CopyMem (
    238         DstCfg->OptionList[Index],
    239         SorCfg->OptionList[Index],
    240         OptionSize
    241         );
    242     }
    243   }
    244 
    245   return EFI_SUCCESS;
    246 }
    247 
    248 
    249 /**
    250   Clean up the configure data.
    251 
    252   @param[in, out]  CfgData       The pointer to the configure data.
    253 
    254 **/
    255 VOID
    256 Dhcp6CleanupConfigData (
    257   IN OUT EFI_DHCP6_CONFIG_DATA       *CfgData
    258   )
    259 {
    260   UINTN                          Index;
    261 
    262   ASSERT (CfgData != NULL);
    263   //
    264   // Clean up all fields in config data including the reference buffers, but do
    265   // not free the config data buffer itself.
    266   //
    267   if (CfgData->OptionList != NULL) {
    268     for (Index = 0; Index < CfgData->OptionCount; Index++) {
    269       if (CfgData->OptionList[Index] != NULL) {
    270         FreePool (CfgData->OptionList[Index]);
    271       }
    272     }
    273     FreePool (CfgData->OptionList);
    274   }
    275 
    276   if (CfgData->SolicitRetransmission != NULL) {
    277     FreePool (CfgData->SolicitRetransmission);
    278   }
    279 
    280   ZeroMem (CfgData, sizeof (EFI_DHCP6_CONFIG_DATA));
    281 }
    282 
    283 
    284 /**
    285   Clean up the mode data.
    286 
    287   @param[in, out]  ModeData      The pointer to the mode data.
    288 
    289 **/
    290 VOID
    291 Dhcp6CleanupModeData (
    292   IN OUT EFI_DHCP6_MODE_DATA        *ModeData
    293   )
    294 {
    295   ASSERT (ModeData != NULL);
    296   //
    297   // Clean up all fields in mode data including the reference buffers, but do
    298   // not free the mode data buffer itself.
    299   //
    300   if (ModeData->ClientId != NULL) {
    301     FreePool (ModeData->ClientId);
    302   }
    303 
    304   if (ModeData->Ia != NULL) {
    305 
    306     if (ModeData->Ia->ReplyPacket != NULL) {
    307       FreePool (ModeData->Ia->ReplyPacket);
    308     }
    309     FreePool (ModeData->Ia);
    310   }
    311 
    312   ZeroMem (ModeData, sizeof (EFI_DHCP6_MODE_DATA));
    313 }
    314 
    315 
    316 /**
    317   Calculate the expire time by the algorithm defined in rfc.
    318 
    319   @param[in]  Base          The base value of the time.
    320   @param[in]  IsFirstRt     If TRUE, it is the first time to calculate expire time.
    321   @param[in]  NeedSigned    If TRUE, the the signed factor is needed.
    322 
    323   @return     Expire        The calculated result for the new expire time.
    324 
    325 **/
    326 UINT32
    327 Dhcp6CalculateExpireTime (
    328   IN UINT32                 Base,
    329   IN BOOLEAN                IsFirstRt,
    330   IN BOOLEAN                NeedSigned
    331   )
    332 {
    333   EFI_TIME                  Time;
    334   BOOLEAN                   Signed;
    335   UINT32                    Seed;
    336   UINT32                    Expire;
    337 
    338   //
    339   // Take the 10bits of microsecond in system time as a uniform distribution.
    340   // Take the 10th bit as a flag to determine it's signed or not.
    341   //
    342   gRT->GetTime (&Time, NULL);
    343   Seed   = ((Time.Nanosecond >> 10) & DHCP6_10_BIT_MASK);
    344   Signed = (BOOLEAN) ((((Time.Nanosecond >> 9) & 0x01) != 0) ? TRUE : FALSE);
    345   Signed = (BOOLEAN) (NeedSigned ? Signed : FALSE);
    346 
    347   //
    348   // Calculate expire by the following algo:
    349   //   1. base + base * (-0.1 ~ 0) for the first solicit
    350   //   2. base + base * (-0.1 ~ 0.1) for the first other messages
    351   //   3. 2 * base + base * (-0.1 ~ 0.1) for the subsequent all messages
    352   //   4. base + base * (-0.1 ~ 0) for the more than mrt timeout
    353   //
    354   // The (Seed / 0x3ff / 10) is used to a random range (0, 0.1).
    355   //
    356   if (IsFirstRt && Signed) {
    357 
    358     Expire = Base - (UINT32) (Base * Seed / DHCP6_10_BIT_MASK / 10);
    359 
    360   } else if (IsFirstRt && !Signed) {
    361 
    362     Expire = Base + (UINT32) (Base * Seed / DHCP6_10_BIT_MASK / 10);
    363 
    364   } else if (!IsFirstRt && Signed) {
    365 
    366     Expire = 2 * Base - (UINT32) (Base * Seed / DHCP6_10_BIT_MASK / 10);
    367 
    368   } else {
    369 
    370     Expire = 2 * Base + (UINT32) (Base * Seed / DHCP6_10_BIT_MASK / 10);
    371   }
    372 
    373   Expire = (Expire != 0) ? Expire : 1;
    374 
    375   return Expire;
    376 }
    377 
    378 
    379 /**
    380   Calculate the lease time by the algorithm defined in rfc.
    381 
    382   @param[in]  IaCb          The pointer to the Ia control block.
    383 
    384 **/
    385 VOID
    386 Dhcp6CalculateLeaseTime (
    387   IN DHCP6_IA_CB              *IaCb
    388   )
    389 {
    390   UINT32                      MinLt;
    391   UINT32                      MaxLt;
    392   UINTN                       Index;
    393 
    394   ASSERT (IaCb->Ia->IaAddressCount > 0);
    395 
    396   MinLt    = (UINT32) (-1);
    397   MaxLt    = 0;
    398 
    399   //
    400   // Calculate minlt as min of all valid life time, and maxlt as max of all
    401   // valid life time.
    402   //
    403   for (Index = 0; Index < IaCb->Ia->IaAddressCount; Index++) {
    404     MinLt  = MIN (MinLt, IaCb->Ia->IaAddress[Index].ValidLifetime);
    405     MaxLt  = MAX (MinLt, IaCb->Ia->IaAddress[Index].ValidLifetime);
    406   }
    407 
    408   //
    409   // Take 50% minlt as t1, and 80% maxlt as t2 if Dhcp6 server doesn't offer
    410   // such information.
    411   //
    412   IaCb->T1            = (IaCb->T1 != 0) ? IaCb->T1 : (UINT32)(MinLt * 5 / 10);
    413   IaCb->T2            = (IaCb->T2 != 0) ? IaCb->T2 : (UINT32)(MinLt * 8 / 10);
    414   IaCb->AllExpireTime = MaxLt;
    415   IaCb->LeaseTime     = 0;
    416 }
    417 
    418 
    419 /**
    420   Check whether the addresses are all included by the configured Ia.
    421 
    422   @param[in]  Ia            The pointer to the Ia.
    423   @param[in]  AddressCount  The number of addresses.
    424   @param[in]  Addresses     The pointer to the addresses buffer.
    425 
    426   @retval EFI_SUCCESS         The addresses are all included by the configured IA.
    427   @retval EFI_NOT_FOUND       The addresses are not included by the configured IA.
    428 
    429 **/
    430 EFI_STATUS
    431 Dhcp6CheckAddress (
    432   IN EFI_DHCP6_IA             *Ia,
    433   IN UINT32                   AddressCount,
    434   IN EFI_IPv6_ADDRESS         *Addresses
    435   )
    436 {
    437   UINTN                       Index1;
    438   UINTN                       Index2;
    439   BOOLEAN                     Found;
    440 
    441   //
    442   // Check whether the addresses are all included by the configured IA. And it
    443   // will return success if address count is zero, which means all addresses.
    444   //
    445   for (Index1 = 0; Index1 < AddressCount; Index1++) {
    446 
    447     Found = FALSE;
    448 
    449     for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {
    450 
    451       if (CompareMem (
    452             &Addresses[Index1],
    453             &Ia->IaAddress[Index2],
    454             sizeof (EFI_IPv6_ADDRESS)
    455             ) == 0) {
    456 
    457         Found = TRUE;
    458         break;
    459       }
    460     }
    461 
    462     if (!Found) {
    463       return EFI_NOT_FOUND;
    464     }
    465   }
    466 
    467   return EFI_SUCCESS;
    468 }
    469 
    470 
    471 /**
    472   Deprive the addresses from current Ia, and generate another eliminated Ia.
    473 
    474   @param[in]  Ia            The pointer to the Ia.
    475   @param[in]  AddressCount  The number of addresses.
    476   @param[in]  Addresses     The pointer to the addresses buffer.
    477 
    478   @retval     NULL          If it failed to generate the deprived Ia.
    479   @retval     others        The pointer to the deprived Ia.
    480 
    481 **/
    482 EFI_DHCP6_IA *
    483 Dhcp6DepriveAddress (
    484   IN EFI_DHCP6_IA             *Ia,
    485   IN UINT32                   AddressCount,
    486   IN EFI_IPv6_ADDRESS         *Addresses
    487   )
    488 {
    489   EFI_DHCP6_IA                *IaCopy;
    490   UINTN                       IaCopySize;
    491   UINTN                       Index1;
    492   UINTN                       Index2;
    493   BOOLEAN                     Found;
    494 
    495   if (AddressCount == 0) {
    496     //
    497     // It means release all Ia addresses if address count is zero.
    498     //
    499     AddressCount = Ia->IaAddressCount;
    500   }
    501 
    502   ASSERT (AddressCount != 0);
    503 
    504   IaCopySize = sizeof (EFI_DHCP6_IA) + (AddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
    505   IaCopy     = AllocateZeroPool (IaCopySize);
    506 
    507   if (IaCopy == NULL) {
    508     return NULL;
    509   }
    510 
    511   if (AddressCount == Ia->IaAddressCount) {
    512     //
    513     // If release all Ia addresses, just copy the configured Ia and then set
    514     // its address count as zero.
    515     // We may decline/release part of addresses at the begining. So it's a
    516     // forwarding step to update address infor for decline/release, while the
    517     // other infor such as Ia state will be updated when receiving reply.
    518     //
    519     CopyMem (IaCopy, Ia, IaCopySize);
    520     Ia->IaAddressCount = 0;
    521     return IaCopy;
    522   }
    523 
    524   CopyMem (IaCopy, Ia, sizeof (EFI_DHCP6_IA));
    525 
    526   //
    527   // Move the addresses from the Ia of instance to the deprived Ia.
    528   //
    529   for (Index1 = 0; Index1 < AddressCount; Index1++) {
    530 
    531     Found = FALSE;
    532 
    533     for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {
    534 
    535       if (CompareMem (
    536             &Addresses[Index1],
    537             &Ia->IaAddress[Index2],
    538             sizeof (EFI_IPv6_ADDRESS)
    539             ) == 0) {
    540         //
    541         // Copy the deprived address to the copy of Ia
    542         //
    543         CopyMem (
    544           &IaCopy->IaAddress[Index1],
    545           &Ia->IaAddress[Index2],
    546           sizeof (EFI_DHCP6_IA_ADDRESS)
    547           );
    548         //
    549         // Delete the deprived address from the instance Ia
    550         //
    551         if (Index2 + 1 < Ia->IaAddressCount) {
    552           CopyMem (
    553             &Ia->IaAddress[Index2],
    554             &Ia->IaAddress[Index2 + 1],
    555             (Ia->IaAddressCount - Index2 - 1) * sizeof (EFI_DHCP6_IA_ADDRESS)
    556             );
    557         }
    558         Found = TRUE;
    559         break;
    560       }
    561     }
    562     ASSERT (Found == TRUE);
    563   }
    564 
    565   Ia->IaAddressCount    -= AddressCount;
    566   IaCopy->IaAddressCount = AddressCount;
    567 
    568   return IaCopy;
    569 }
    570 
    571 
    572 /**
    573   The dummy ext buffer free callback routine.
    574 
    575   @param[in]  Arg           The pointer to the parameter.
    576 
    577 **/
    578 VOID
    579 EFIAPI
    580 Dhcp6DummyExtFree (
    581   IN VOID                      *Arg
    582   )
    583 {
    584 }
    585 
    586 
    587 /**
    588   The callback routine once message transmitted.
    589 
    590   @param[in]  Wrap          The pointer to the received net buffer.
    591   @param[in]  EndPoint      The pointer to the udp end point.
    592   @param[in]  IoStatus      The return status from udp io.
    593   @param[in]  Context       The opaque parameter to the function.
    594 
    595 **/
    596 VOID
    597 EFIAPI
    598 Dhcp6OnTransmitted (
    599   IN NET_BUF                   *Wrap,
    600   IN UDP_END_POINT             *EndPoint,
    601   IN EFI_STATUS                IoStatus,
    602   IN VOID                      *Context
    603   )
    604 {
    605   NetbufFree (Wrap);
    606 }
    607 
    608 
    609 /**
    610   Append the option to Buf, and move Buf to the end.
    611 
    612   @param[in, out] Buf           The pointer to the buffer.
    613   @param[in]      OptType       The option type.
    614   @param[in]      OptLen        The length of option contents.
    615   @param[in]      Data          The pointer to the option content.
    616 
    617   @return         Buf           The position to append the next option.
    618 
    619 **/
    620 UINT8 *
    621 Dhcp6AppendOption (
    622   IN OUT UINT8               *Buf,
    623   IN     UINT16              OptType,
    624   IN     UINT16              OptLen,
    625   IN     UINT8               *Data
    626   )
    627 {
    628   //
    629   //  The format of Dhcp6 option:
    630   //
    631   //     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
    632   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    633   //    |          option-code          |   option-len (option data)    |
    634   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    635   //    |                          option-data                          |
    636   //    |                      (option-len octets)                      |
    637   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    638   //
    639 
    640   ASSERT (OptLen != 0);
    641 
    642   WriteUnaligned16 ((UINT16 *) Buf, OptType);
    643   Buf            += 2;
    644   WriteUnaligned16 ((UINT16 *) Buf, OptLen);
    645   Buf            += 2;
    646   CopyMem (Buf, Data, NTOHS (OptLen));
    647   Buf            += NTOHS (OptLen);
    648 
    649   return Buf;
    650 }
    651 
    652 /**
    653   Append the appointed IA Address option to Buf, and move Buf to the end.
    654 
    655   @param[in, out] Buf           The pointer to the position to append.
    656   @param[in]      IaAddr        The pointer to the IA Address.
    657   @param[in]      MessageType   Message type of DHCP6 package.
    658 
    659   @return         Buf           The position to append the next option.
    660 
    661 **/
    662 UINT8 *
    663 Dhcp6AppendIaAddrOption (
    664   IN OUT UINT8                  *Buf,
    665   IN     EFI_DHCP6_IA_ADDRESS   *IaAddr,
    666   IN     UINT32                 MessageType
    667 )
    668 {
    669 
    670   //  The format of the IA Address option is:
    671   //
    672   //       0                   1                   2                   3
    673   //       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
    674   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    675   //      |          OPTION_IAADDR        |          option-len           |
    676   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    677   //      |                                                               |
    678   //      |                         IPv6 address                          |
    679   //      |                                                               |
    680   //      |                                                               |
    681   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    682   //      |                      preferred-lifetime                       |
    683   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    684   //      |                        valid-lifetime                         |
    685   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    686   //      .                                                               .
    687   //      .                        IAaddr-options                         .
    688   //      .                                                               .
    689   //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    690 
    691   //
    692   // Fill the value of Ia Address option type
    693   //
    694   WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptIaAddr));
    695   Buf                     += 2;
    696 
    697   WriteUnaligned16 ((UINT16 *) Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS)));
    698   Buf                     += 2;
    699 
    700   CopyMem (Buf, &IaAddr->IpAddress, sizeof(EFI_IPv6_ADDRESS));
    701   Buf                     += sizeof(EFI_IPv6_ADDRESS);
    702 
    703   //
    704   // Fill the value of preferred-lifetime and valid-lifetime.
    705   // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields
    706   // should set to 0 when initiate a Confirm message.
    707   //
    708   if (MessageType != Dhcp6MsgConfirm) {
    709     WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->PreferredLifetime));
    710   }
    711   Buf                     += 4;
    712 
    713   if (MessageType != Dhcp6MsgConfirm) {
    714     WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->ValidLifetime));
    715   }
    716   Buf                     += 4;
    717 
    718   return Buf;
    719 }
    720 
    721 
    722 /**
    723   Append the appointed Ia option to Buf, and move Buf to the end.
    724 
    725   @param[in, out] Buf           The pointer to the position to append.
    726   @param[in]      Ia            The pointer to the Ia.
    727   @param[in]      T1            The time of T1.
    728   @param[in]      T2            The time of T2.
    729   @param[in]      MessageType   Message type of DHCP6 package.
    730 
    731   @return         Buf           The position to append the next Ia option.
    732 
    733 **/
    734 UINT8 *
    735 Dhcp6AppendIaOption (
    736   IN OUT UINT8                  *Buf,
    737   IN     EFI_DHCP6_IA           *Ia,
    738   IN     UINT32                 T1,
    739   IN     UINT32                 T2,
    740   IN     UINT32                 MessageType
    741   )
    742 {
    743   UINT8                     *AddrOpt;
    744   UINT16                    *Len;
    745   UINTN                     Index;
    746 
    747   //
    748   //  The format of IA_NA and IA_TA option:
    749   //
    750   //     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
    751   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    752   //    |          OPTION_IA_NA         |          option-len           |
    753   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    754   //    |                        IAID (4 octets)                        |
    755   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    756   //    |                        T1 (only for IA_NA)                    |
    757   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    758   //    |                        T2 (only for IA_NA)                    |
    759   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    760   //    |                                                               |
    761   //    .                  IA_NA-options/IA_TA-options                  .
    762   //    .                                                               .
    763   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    764   //
    765 
    766   //
    767   // Fill the value of Ia option type
    768   //
    769   WriteUnaligned16 ((UINT16 *) Buf, HTONS (Ia->Descriptor.Type));
    770   Buf                     += 2;
    771 
    772   //
    773   // Fill the len of Ia option later, keep the pointer first
    774   //
    775   Len                      = (UINT16 *) Buf;
    776   Buf                     += 2;
    777 
    778   //
    779   // Fill the value of iaid
    780   //
    781   WriteUnaligned32 ((UINT32 *) Buf, HTONL (Ia->Descriptor.IaId));
    782   Buf                     += 4;
    783 
    784   //
    785   // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.
    786   //
    787   if (Ia->Descriptor.Type == Dhcp6OptIana) {
    788     WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff));
    789     Buf                   += 4;
    790     WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff));
    791     Buf                   += 4;
    792   }
    793 
    794   //
    795   // Fill all the addresses belong to the Ia
    796   //
    797   for (Index = 0; Index < Ia->IaAddressCount; Index++) {
    798     AddrOpt = (UINT8 *) Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);
    799     Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *) AddrOpt, MessageType);
    800   }
    801 
    802   //
    803   // Fill the value of Ia option length
    804   //
    805   *Len = HTONS ((UINT16) (Buf - (UINT8 *) Len - 2));
    806 
    807   return Buf;
    808 }
    809 
    810 /**
    811   Append the appointed Elapsed time option to Buf, and move Buf to the end.
    812 
    813   @param[in, out] Buf           The pointer to the position to append.
    814   @param[in]      Instance      The pointer to the Dhcp6 instance.
    815   @param[out]     Elapsed       The pointer to the elapsed time value in
    816                                   the generated packet.
    817 
    818   @return         Buf           The position to append the next Ia option.
    819 
    820 **/
    821 UINT8 *
    822 Dhcp6AppendETOption (
    823   IN OUT UINT8                  *Buf,
    824   IN     DHCP6_INSTANCE         *Instance,
    825   OUT    UINT16                 **Elapsed
    826   )
    827 {
    828   //
    829   //  The format of elapsed time option:
    830   //
    831   //   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
    832   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    833   //  |      OPTION_ELAPSED_TIME      |           option-len          |
    834   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    835   //  |          elapsed-time         |
    836   //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    837   //
    838 
    839   //
    840   // Fill the value of elapsed-time option type.
    841   //
    842   WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptElapsedTime));
    843   Buf                     += 2;
    844 
    845   //
    846   // Fill the len of elapsed-time option, which is fixed.
    847   //
    848   WriteUnaligned16 ((UINT16 *) Buf, HTONS(2));
    849   Buf                     += 2;
    850 
    851   //
    852   // Fill in elapsed time value with 0 value for now.  The actual value is
    853   // filled in later just before the packet is transmitted.
    854   //
    855   WriteUnaligned16 ((UINT16 *) Buf, HTONS(0));
    856   *Elapsed                  = (UINT16 *) Buf;
    857   Buf                     += 2;
    858 
    859   return Buf;
    860 }
    861 
    862 /**
    863   Set the elapsed time based on the given instance and the pointer to the
    864   elapsed time option.
    865 
    866   @param[in]      Elapsed       The pointer to the position to append.
    867   @param[in]      Instance      The pointer to the Dhcp6 instance.
    868 
    869 **/
    870 VOID
    871 SetElapsedTime (
    872   IN     UINT16                 *Elapsed,
    873   IN     DHCP6_INSTANCE         *Instance
    874   )
    875 {
    876   EFI_TIME          Time;
    877   UINT64            CurrentStamp;
    878   UINT64            ElapsedTimeValue;
    879 
    880   //
    881   // Generate a time stamp of the centiseconds from 2000/1/1, assume 30day/month.
    882   //
    883   gRT->GetTime (&Time, NULL);
    884   CurrentStamp = (UINT64)
    885     (
    886       ((((((Time.Year - 2000) * 360 +
    887        (Time.Month - 1)) * 30 +
    888        (Time.Day - 1)) * 24 + Time.Hour) * 60 +
    889        Time.Minute) * 60 + Time.Second) * 100
    890        + DivU64x32(Time.Nanosecond, 10000000)
    891     );
    892 
    893   //
    894   // Sentinel value of 0 means that this is the first DHCP packet that we are
    895   // sending and that we need to initialize the value.  First DHCP message
    896   // gets 0 elapsed-time.  Otherwise, calculate based on StartTime.
    897   //
    898   if (Instance->StartTime == 0) {
    899     ElapsedTimeValue = 0;
    900     Instance->StartTime = CurrentStamp;
    901   } else {
    902     ElapsedTimeValue = CurrentStamp - Instance->StartTime;
    903 
    904     //
    905     // If elapsed time cannot fit in two bytes, set it to 0xffff.
    906     //
    907     if (ElapsedTimeValue > 0xffff) {
    908       ElapsedTimeValue = 0xffff;
    909     }
    910   }
    911   WriteUnaligned16 (Elapsed, HTONS((UINT16) ElapsedTimeValue));
    912 }
    913 
    914 
    915 /**
    916   Seek the address of the first byte of the option header.
    917 
    918   @param[in]  Buf           The pointer to the buffer.
    919   @param[in]  SeekLen       The length to seek.
    920   @param[in]  OptType       The option type.
    921 
    922   @retval     NULL          If it failed to seek the option.
    923   @retval     others        The position to the option.
    924 
    925 **/
    926 UINT8 *
    927 Dhcp6SeekOption (
    928   IN UINT8           *Buf,
    929   IN UINT32          SeekLen,
    930   IN UINT16          OptType
    931   )
    932 {
    933   UINT8              *Cursor;
    934   UINT8              *Option;
    935   UINT16             DataLen;
    936   UINT16             OpCode;
    937 
    938   Option = NULL;
    939   Cursor = Buf;
    940 
    941   //
    942   // The format of Dhcp6 option refers to Dhcp6AppendOption().
    943   //
    944   while (Cursor < Buf + SeekLen) {
    945     OpCode = ReadUnaligned16 ((UINT16 *) Cursor);
    946     if (OpCode == HTONS (OptType)) {
    947       Option = Cursor;
    948       break;
    949     }
    950     DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));
    951     Cursor += (DataLen + 4);
    952   }
    953 
    954   return Option;
    955 }
    956 
    957 
    958 /**
    959   Seek the address of the first byte of the Ia option header.
    960 
    961   @param[in]  Buf           The pointer to the buffer.
    962   @param[in]  SeekLen       The length to seek.
    963   @param[in]  IaDesc        The pointer to the Ia descriptor.
    964 
    965   @retval     NULL          If it failed to seek the Ia option.
    966   @retval     others        The position to the Ia option.
    967 
    968 **/
    969 UINT8 *
    970 Dhcp6SeekIaOption (
    971   IN UINT8                    *Buf,
    972   IN UINT32                   SeekLen,
    973   IN EFI_DHCP6_IA_DESCRIPTOR  *IaDesc
    974   )
    975 {
    976   UINT8              *Cursor;
    977   UINT8              *Option;
    978   UINT16             DataLen;
    979   UINT16             OpCode;
    980   UINT32             IaId;
    981 
    982   //
    983   // The format of IA_NA and IA_TA option refers to Dhcp6AppendIaOption().
    984   //
    985   Option = NULL;
    986   Cursor = Buf;
    987 
    988   while (Cursor < Buf + SeekLen) {
    989     OpCode = ReadUnaligned16 ((UINT16 *) Cursor);
    990     IaId   = ReadUnaligned32 ((UINT32 *) (Cursor + 4));
    991     if (OpCode == HTONS (IaDesc->Type) && IaId == HTONL (IaDesc->IaId)) {
    992       Option = Cursor;
    993       break;
    994     }
    995     DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));
    996     Cursor += (DataLen + 4);
    997   }
    998 
    999   return Option;
   1000 }
   1001 
   1002 /**
   1003   Check whether the incoming IPv6 address in IaAddr is one of the maintained
   1004   addresses in the IA control blcok.
   1005 
   1006   @param[in]  IaAddr            The pointer to the IA Address to be checked.
   1007   @param[in]  CurrentIa         The pointer to the IA in IA control block.
   1008 
   1009   @retval     TRUE              Yes, this Address is already in IA control block.
   1010   @retval     FALSE             No, this Address is NOT in IA control block.
   1011 
   1012 **/
   1013 BOOLEAN
   1014 Dhcp6AddrIsInCurrentIa (
   1015   IN    EFI_DHCP6_IA_ADDRESS      *IaAddr,
   1016   IN    EFI_DHCP6_IA              *CurrentIa
   1017   )
   1018 {
   1019   UINT32    Index;
   1020 
   1021   ASSERT (IaAddr != NULL && CurrentIa != NULL);
   1022 
   1023   for (Index = 0; Index < CurrentIa->IaAddressCount; Index++) {
   1024     if (EFI_IP6_EQUAL(&IaAddr->IpAddress, &CurrentIa->IaAddress[Index].IpAddress)) {
   1025       return TRUE;
   1026     }
   1027   }
   1028   return FALSE;
   1029 }
   1030 
   1031 /**
   1032   Parse the address option and update the address infomation.
   1033 
   1034   @param[in]      CurrentIa     The pointer to the Ia Address in control blcok.
   1035   @param[in]      IaInnerOpt    The pointer to the buffer.
   1036   @param[in]      IaInnerLen    The length to parse.
   1037   @param[out]     AddrNum       The number of addresses.
   1038   @param[in, out] AddrBuf       The pointer to the address buffer.
   1039 
   1040 **/
   1041 VOID
   1042 Dhcp6ParseAddrOption (
   1043   IN     EFI_DHCP6_IA            *CurrentIa,
   1044   IN     UINT8                   *IaInnerOpt,
   1045   IN     UINT16                  IaInnerLen,
   1046      OUT UINT32                  *AddrNum,
   1047   IN OUT EFI_DHCP6_IA_ADDRESS    *AddrBuf
   1048   )
   1049 {
   1050   UINT8                       *Cursor;
   1051   UINT16                      DataLen;
   1052   UINT16                      OpCode;
   1053   UINT32                      ValidLt;
   1054   UINT32                      PreferredLt;
   1055   EFI_DHCP6_IA_ADDRESS        *IaAddr;
   1056 
   1057   //
   1058   //  The format of the IA Address option:
   1059   //
   1060   //     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
   1061   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   1062   //    |          OPTION_IAADDR        |          option-len           |
   1063   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   1064   //    |                                                               |
   1065   //    |                         IPv6 address                          |
   1066   //    |                                                               |
   1067   //    |                                                               |
   1068   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   1069   //    |                      preferred-lifetime                       |
   1070   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   1071   //    |                        valid-lifetime                         |
   1072   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   1073   //    .                                                               .
   1074   //    .                        IAaddr-options                         .
   1075   //    .                                                               .
   1076   //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   1077   //
   1078 
   1079   //
   1080   //  Two usage model:
   1081   //
   1082   //    1. Pass addrbuf == null, to get the addrnum over the Ia inner options.
   1083   //    2. Pass addrbuf != null, to resolve the addresses over the Ia inner
   1084   //       options to the addrbuf.
   1085   //
   1086 
   1087   Cursor   = IaInnerOpt;
   1088   *AddrNum = 0;
   1089 
   1090   while (Cursor < IaInnerOpt + IaInnerLen) {
   1091     //
   1092     // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option
   1093     // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time.
   1094     //
   1095     OpCode  = ReadUnaligned16 ((UINT16 *) Cursor);
   1096     PreferredLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 20)));
   1097     ValidLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 24)));
   1098     IaAddr = (EFI_DHCP6_IA_ADDRESS *) (Cursor + 4);
   1099     if (OpCode == HTONS (Dhcp6OptIaAddr) && ValidLt >= PreferredLt &&
   1100         (Dhcp6AddrIsInCurrentIa(IaAddr, CurrentIa) || ValidLt !=0)) {
   1101       if (AddrBuf != NULL) {
   1102         CopyMem (AddrBuf, IaAddr, sizeof (EFI_DHCP6_IA_ADDRESS));
   1103         AddrBuf->PreferredLifetime = PreferredLt;
   1104         AddrBuf->ValidLifetime     = ValidLt;
   1105         AddrBuf = (EFI_DHCP6_IA_ADDRESS *) ((UINT8 *) AddrBuf + sizeof (EFI_DHCP6_IA_ADDRESS));
   1106       }
   1107       (*AddrNum)++;
   1108     }
   1109     DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));
   1110     Cursor += (DataLen + 4);
   1111   }
   1112 }
   1113 
   1114 
   1115 /**
   1116   Create a control blcok for the Ia according to the corresponding options.
   1117 
   1118   @param[in]  Instance              The pointer to DHCP6 Instance.
   1119   @param[in]  IaInnerOpt            The pointer to the inner options in the Ia option.
   1120   @param[in]  IaInnerLen            The length of all the inner options in the Ia option.
   1121   @param[in]  T1                    T1 time in the Ia option.
   1122   @param[in]  T2                    T2 time in the Ia option.
   1123 
   1124   @retval     EFI_NOT_FOUND         No valid IA option is found.
   1125   @retval     EFI_SUCCESS           Create an IA control block successfully.
   1126   @retval     EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1127   @retval     EFI_DEVICE_ERROR      An unexpected error.
   1128 
   1129 **/
   1130 EFI_STATUS
   1131 Dhcp6GenerateIaCb (
   1132   IN  DHCP6_INSTANCE           *Instance,
   1133   IN  UINT8                    *IaInnerOpt,
   1134   IN  UINT16                   IaInnerLen,
   1135   IN  UINT32                   T1,
   1136   IN  UINT32                   T2
   1137   )
   1138 {
   1139   UINT32                       AddrNum;
   1140   UINT32                       IaSize;
   1141   EFI_DHCP6_IA                 *Ia;
   1142 
   1143   if (Instance->IaCb.Ia == NULL) {
   1144     return EFI_DEVICE_ERROR;
   1145   }
   1146 
   1147   //
   1148   // Calculate the number of addresses for this Ia, excluding the addresses with
   1149   // the value 0 of valid lifetime.
   1150   //
   1151   Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, NULL);
   1152 
   1153   if (AddrNum == 0) {
   1154     return EFI_NOT_FOUND;
   1155   }
   1156 
   1157   //
   1158   // Allocate for new IA.
   1159   //
   1160   IaSize = sizeof (EFI_DHCP6_IA) + (AddrNum - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
   1161   Ia = AllocateZeroPool (IaSize);
   1162 
   1163   if (Ia == NULL) {
   1164     return EFI_OUT_OF_RESOURCES;
   1165   }
   1166 
   1167   //
   1168   // Fill up this new IA fields.
   1169   //
   1170   Ia->State          = Instance->IaCb.Ia->State;
   1171   Ia->IaAddressCount = AddrNum;
   1172   CopyMem (&Ia->Descriptor, &Instance->Config->IaDescriptor, sizeof (EFI_DHCP6_IA_DESCRIPTOR));
   1173   Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress);
   1174 
   1175   //
   1176   // Free original IA resource.
   1177   //
   1178   if (Instance->IaCb.Ia->ReplyPacket != NULL) {
   1179     FreePool (Instance->IaCb.Ia->ReplyPacket);
   1180   }
   1181   FreePool (Instance->IaCb.Ia);
   1182 
   1183 
   1184   ZeroMem (&Instance->IaCb, sizeof (DHCP6_IA_CB));
   1185 
   1186   //
   1187   // Update IaCb to use new IA.
   1188   //
   1189   Instance->IaCb.Ia   = Ia;
   1190 
   1191   //
   1192 
   1193  // Fill in IaCb fields. Such as T1, T2, AllExpireTime and LeaseTime.
   1194   //
   1195   Instance->IaCb.T1 = T1;
   1196   Instance->IaCb.T2 = T2;
   1197   Dhcp6CalculateLeaseTime (&Instance->IaCb);
   1198 
   1199   return EFI_SUCCESS;
   1200 }
   1201 
   1202 
   1203 /**
   1204   Cache the current IA configuration information.
   1205 
   1206   @param[in] Instance           The pointer to DHCP6 Instance.
   1207 
   1208   @retval EFI_SUCCESS           Cache the current IA successfully.
   1209   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1210 
   1211 **/
   1212 EFI_STATUS
   1213 Dhcp6CacheIa (
   1214   IN DHCP6_INSTANCE           *Instance
   1215   )
   1216 {
   1217   UINTN                        IaSize;
   1218   EFI_DHCP6_IA                 *Ia;
   1219 
   1220   Ia = Instance->IaCb.Ia;
   1221 
   1222   if ((Instance->CacheIa == NULL) && (Ia != NULL)) {
   1223     //
   1224     // Cache the current IA.
   1225     //
   1226     IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
   1227 
   1228     Instance->CacheIa = AllocateZeroPool (IaSize);
   1229     if (Instance->CacheIa == NULL) {
   1230       return EFI_OUT_OF_RESOURCES;
   1231     }
   1232     CopyMem (Instance->CacheIa, Ia, IaSize);
   1233   }
   1234   return EFI_SUCCESS;
   1235 }
   1236 
   1237 /**
   1238   Append CacheIa to the currrent IA. Meanwhile, clear CacheIa.ValidLifetime to 0.
   1239 
   1240   @param[in]  Instance            The pointer to DHCP6 instance.
   1241 
   1242 **/
   1243 VOID
   1244 Dhcp6AppendCacheIa (
   1245   IN DHCP6_INSTANCE           *Instance
   1246   )
   1247 {
   1248   UINT8                        *Ptr;
   1249   UINTN                        Index;
   1250   UINTN                        IaSize;
   1251   UINTN                        NewIaSize;
   1252   EFI_DHCP6_IA                 *Ia;
   1253   EFI_DHCP6_IA                 *NewIa;
   1254   EFI_DHCP6_IA                 *CacheIa;
   1255 
   1256   Ia      = Instance->IaCb.Ia;
   1257   CacheIa = Instance->CacheIa;
   1258 
   1259   if ((CacheIa != NULL) && (CacheIa->IaAddressCount != 0)) {
   1260     //
   1261     // There are old addresses existing. Merge with current addresses.
   1262     //
   1263     NewIaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount + CacheIa->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
   1264     NewIa     = AllocateZeroPool (NewIaSize);
   1265     if (NewIa == NULL) {
   1266       return;
   1267     }
   1268 
   1269     IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
   1270     CopyMem (NewIa, Ia, IaSize);
   1271 
   1272     //
   1273     // Clear old address.ValidLifetime
   1274     //
   1275     for (Index = 0; Index < CacheIa->IaAddressCount; Index++) {
   1276       CacheIa->IaAddress[Index].ValidLifetime  = 0;
   1277     }
   1278 
   1279     NewIa->IaAddressCount += CacheIa->IaAddressCount;
   1280     Ptr   = (UINT8*)&NewIa->IaAddress[Ia->IaAddressCount];
   1281     CopyMem (Ptr, CacheIa->IaAddress, CacheIa->IaAddressCount * sizeof (EFI_DHCP6_IA_ADDRESS));
   1282 
   1283     //
   1284     // Migrate to the NewIa and free previous.
   1285     //
   1286     FreePool (Instance->CacheIa);
   1287     FreePool (Instance->IaCb.Ia);
   1288     Instance->CacheIa  = NULL;
   1289     Instance->IaCb.Ia  = NewIa;
   1290   }
   1291 }
   1292 
   1293 /**
   1294   Calculate the Dhcp6 get mapping timeout by adding additinal delay to the IP6 DAD transmits count.
   1295 
   1296   @param[in]   Ip6Cfg              The pointer to Ip6 config protocol.
   1297   @param[out]  TimeOut             The time out value in 100ns units.
   1298 
   1299   @retval   EFI_INVALID_PARAMETER  Input parameters are invalid.
   1300   @retval   EFI_SUCCESS            Calculate the time out value successfully.
   1301 **/
   1302 EFI_STATUS
   1303 Dhcp6GetMappingTimeOut (
   1304   IN  EFI_IP6_CONFIG_PROTOCOL       *Ip6Cfg,
   1305   OUT UINTN                         *TimeOut
   1306   )
   1307 {
   1308   EFI_STATUS            Status;
   1309   UINTN                 DataSize;
   1310   EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS    DadXmits;
   1311 
   1312   if (Ip6Cfg == NULL || TimeOut == NULL) {
   1313     return EFI_INVALID_PARAMETER;
   1314   }
   1315 
   1316   DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
   1317   Status = Ip6Cfg->GetData (
   1318                      Ip6Cfg,
   1319                      Ip6ConfigDataTypeDupAddrDetectTransmits,
   1320                      &DataSize,
   1321                      &DadXmits
   1322                      );
   1323   if (EFI_ERROR (Status)) {
   1324     return Status;
   1325   }
   1326 
   1327   *TimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + DHCP6_DAD_ADDITIONAL_DELAY;
   1328 
   1329   return EFI_SUCCESS;
   1330 }
   1331