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**/
29EFI_DHCP6_DUID *
30Dhcp6GenerateClientId (
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**/
180EFI_STATUS
181Dhcp6CopyConfigData (
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**/
255VOID
256Dhcp6CleanupConfigData (
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**/
290VOID
291Dhcp6CleanupModeData (
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**/
326UINT32
327Dhcp6CalculateExpireTime (
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**/
385VOID
386Dhcp6CalculateLeaseTime (
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**/
430EFI_STATUS
431Dhcp6CheckAddress (
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**/
482EFI_DHCP6_IA *
483Dhcp6DepriveAddress (
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**/
578VOID
579EFIAPI
580Dhcp6DummyExtFree (
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**/
596VOID
597EFIAPI
598Dhcp6OnTransmitted (
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**/
620UINT8 *
621Dhcp6AppendOption (
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**/
662UINT8 *
663Dhcp6AppendIaAddrOption (
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**/
734UINT8 *
735Dhcp6AppendIaOption (
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**/
821UINT8 *
822Dhcp6AppendETOption (
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**/
870VOID
871SetElapsedTime (
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**/
926UINT8 *
927Dhcp6SeekOption (
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**/
969UINT8 *
970Dhcp6SeekIaOption (
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**/
1013BOOLEAN
1014Dhcp6AddrIsInCurrentIa (
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**/
1041VOID
1042Dhcp6ParseAddrOption (
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**/
1130EFI_STATUS
1131Dhcp6GenerateIaCb (
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**/
1212EFI_STATUS
1213Dhcp6CacheIa (
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**/
1243VOID
1244Dhcp6AppendCacheIa (
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**/
1302EFI_STATUS
1303Dhcp6GetMappingTimeOut (
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