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