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 *
Dhcp6GenerateClientId(IN EFI_SIMPLE_NETWORK_MODE * Mode)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
Dhcp6CopyConfigData(IN EFI_DHCP6_CONFIG_DATA * DstCfg,IN EFI_DHCP6_CONFIG_DATA * SorCfg)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
Dhcp6CleanupConfigData(IN OUT EFI_DHCP6_CONFIG_DATA * CfgData)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
Dhcp6CleanupModeData(IN OUT EFI_DHCP6_MODE_DATA * ModeData)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
Dhcp6CalculateExpireTime(IN UINT32 Base,IN BOOLEAN IsFirstRt,IN BOOLEAN NeedSigned)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
Dhcp6CalculateLeaseTime(IN DHCP6_IA_CB * IaCb)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
Dhcp6CheckAddress(IN EFI_DHCP6_IA * Ia,IN UINT32 AddressCount,IN EFI_IPv6_ADDRESS * Addresses)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 *
Dhcp6DepriveAddress(IN EFI_DHCP6_IA * Ia,IN UINT32 AddressCount,IN EFI_IPv6_ADDRESS * Addresses)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
Dhcp6DummyExtFree(IN VOID * Arg)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
Dhcp6OnTransmitted(IN NET_BUF * Wrap,IN UDP_END_POINT * EndPoint,IN EFI_STATUS IoStatus,IN VOID * Context)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 *
Dhcp6AppendOption(IN OUT UINT8 * Buf,IN UINT16 OptType,IN UINT16 OptLen,IN UINT8 * Data)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 *
Dhcp6AppendIaAddrOption(IN OUT UINT8 * Buf,IN EFI_DHCP6_IA_ADDRESS * IaAddr,IN UINT32 MessageType)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 *
Dhcp6AppendIaOption(IN OUT UINT8 * Buf,IN EFI_DHCP6_IA * Ia,IN UINT32 T1,IN UINT32 T2,IN UINT32 MessageType)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 *
Dhcp6AppendETOption(IN OUT UINT8 * Buf,IN DHCP6_INSTANCE * Instance,OUT UINT16 ** Elapsed)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
SetElapsedTime(IN UINT16 * Elapsed,IN DHCP6_INSTANCE * Instance)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 *
Dhcp6SeekOption(IN UINT8 * Buf,IN UINT32 SeekLen,IN UINT16 OptType)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 *
Dhcp6SeekIaOption(IN UINT8 * Buf,IN UINT32 SeekLen,IN EFI_DHCP6_IA_DESCRIPTOR * IaDesc)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
Dhcp6AddrIsInCurrentIa(IN EFI_DHCP6_IA_ADDRESS * IaAddr,IN EFI_DHCP6_IA * CurrentIa)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
Dhcp6ParseAddrOption(IN EFI_DHCP6_IA * CurrentIa,IN UINT8 * IaInnerOpt,IN UINT16 IaInnerLen,OUT UINT32 * AddrNum,IN OUT EFI_DHCP6_IA_ADDRESS * AddrBuf)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
Dhcp6GenerateIaCb(IN DHCP6_INSTANCE * Instance,IN UINT8 * IaInnerOpt,IN UINT16 IaInnerLen,IN UINT32 T1,IN UINT32 T2)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
Dhcp6CacheIa(IN DHCP6_INSTANCE * Instance)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
Dhcp6AppendCacheIa(IN DHCP6_INSTANCE * Instance)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
Dhcp6GetMappingTimeOut(IN EFI_IP6_CONFIG_PROTOCOL * Ip6Cfg,OUT UINTN * TimeOut)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