]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c
Remove ASSERT when failed to Get/Set “AttemptOrder” and “ClientId” variable.
[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 *) (Duid->Duid), HTONS (Dhcp6DuidTypeLlt));
147 WriteUnaligned16 ((UINT16 *) (Duid->Duid + 2), HTONS (NET_IFTYPE_ETHERNET));
148 WriteUnaligned32 ((UINT32 *) (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 EFI_DHCP6_IA_ADDRESS *IaAddr;
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 IaAddr = IaCb->Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);
405 MinLt = MIN (MinLt, IaAddr->ValidLifetime);
406 MaxLt = MAX (MinLt, IaAddr->ValidLifetime);
407 }
408
409 //
410 // Take 50% minlt as t1, and 80% maxlt as t2 if Dhcp6 server doesn't offer
411 // such information.
412 //
413 IaCb->T1 = (IaCb->T1 != 0) ? IaCb->T1 : (UINT32)(MinLt * 5 / 10);
414 IaCb->T2 = (IaCb->T2 != 0) ? IaCb->T2 : (UINT32)(MinLt * 8 / 10);
415 IaCb->AllExpireTime = MaxLt;
416 IaCb->LeaseTime = 0;
417 }
418
419
420 /**
421 Check whether the addresses are all included by the configured Ia.
422
423 @param[in] Ia The pointer to the Ia.
424 @param[in] AddressCount The number of addresses.
425 @param[in] Addresses The pointer to the addresses buffer.
426
427 @retval EFI_SUCCESS The addresses are all included by the configured IA.
428 @retval EFI_NOT_FOUND The addresses are not included by the configured IA.
429
430 **/
431 EFI_STATUS
432 Dhcp6CheckAddress (
433 IN EFI_DHCP6_IA *Ia,
434 IN UINT32 AddressCount,
435 IN EFI_IPv6_ADDRESS *Addresses
436 )
437 {
438 UINTN Index1;
439 UINTN Index2;
440 BOOLEAN Found;
441
442 //
443 // Check whether the addresses are all included by the configured IA. And it
444 // will return success if address count is zero, which means all addresses.
445 //
446 for (Index1 = 0; Index1 < AddressCount; Index1++) {
447
448 Found = FALSE;
449
450 for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {
451
452 if (CompareMem (
453 &Addresses[Index1],
454 &Ia->IaAddress[Index2],
455 sizeof (EFI_IPv6_ADDRESS)
456 ) == 0) {
457
458 Found = TRUE;
459 break;
460 }
461 }
462
463 if (!Found) {
464 return EFI_NOT_FOUND;
465 }
466 }
467
468 return EFI_SUCCESS;
469 }
470
471
472 /**
473 Deprive the addresses from current Ia, and generate another eliminated Ia.
474
475 @param[in] Ia The pointer to the Ia.
476 @param[in] AddressCount The number of addresses.
477 @param[in] Addresses The pointer to the addresses buffer.
478
479 @retval NULL If it failed to generate the deprived Ia.
480 @retval others The pointer to the deprived Ia.
481
482 **/
483 EFI_DHCP6_IA *
484 Dhcp6DepriveAddress (
485 IN EFI_DHCP6_IA *Ia,
486 IN UINT32 AddressCount,
487 IN EFI_IPv6_ADDRESS *Addresses
488 )
489 {
490 EFI_DHCP6_IA *IaCopy;
491 UINTN IaCopySize;
492 UINTN Index1;
493 UINTN Index2;
494 BOOLEAN Found;
495
496 if (AddressCount == 0) {
497 //
498 // It means release all Ia addresses if address count is zero.
499 //
500 AddressCount = Ia->IaAddressCount;
501 }
502
503 ASSERT (AddressCount != 0);
504
505 IaCopySize = sizeof (EFI_DHCP6_IA) + (AddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
506 IaCopy = AllocateZeroPool (IaCopySize);
507
508 if (IaCopy == NULL) {
509 return NULL;
510 }
511
512 if (AddressCount == Ia->IaAddressCount) {
513 //
514 // If release all Ia addresses, just copy the configured Ia and then set
515 // its address count as zero.
516 // We may decline/release part of addresses at the begining. So it's a
517 // forwarding step to update address infor for decline/release, while the
518 // other infor such as Ia state will be updated when receiving reply.
519 //
520 CopyMem (IaCopy, Ia, IaCopySize);
521 Ia->IaAddressCount = 0;
522 return IaCopy;
523 }
524
525 CopyMem (IaCopy, Ia, sizeof (EFI_DHCP6_IA));
526
527 //
528 // Move the addresses from the Ia of instance to the deprived Ia.
529 //
530 for (Index1 = 0; Index1 < AddressCount; Index1++) {
531
532 Found = FALSE;
533
534 for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {
535
536 if (CompareMem (
537 &Addresses[Index1],
538 &Ia->IaAddress[Index2],
539 sizeof (EFI_IPv6_ADDRESS)
540 ) == 0) {
541 //
542 // Copy the deprived address to the copy of Ia
543 //
544 CopyMem (
545 &IaCopy->IaAddress[Index1],
546 &Ia->IaAddress[Index2],
547 sizeof (EFI_DHCP6_IA_ADDRESS)
548 );
549 //
550 // Delete the deprived address from the instance Ia
551 //
552 if (Index2 + 1 < Ia->IaAddressCount) {
553 CopyMem (
554 &Ia->IaAddress[Index2],
555 &Ia->IaAddress[Index2 + 1],
556 (Ia->IaAddressCount - Index2 - 1) * sizeof (EFI_DHCP6_IA_ADDRESS)
557 );
558 }
559 Found = TRUE;
560 break;
561 }
562 }
563 ASSERT (Found == TRUE);
564 }
565
566 Ia->IaAddressCount -= AddressCount;
567 IaCopy->IaAddressCount = AddressCount;
568
569 return IaCopy;
570 }
571
572
573 /**
574 The dummy ext buffer free callback routine.
575
576 @param[in] Arg The pointer to the parameter.
577
578 **/
579 VOID
580 EFIAPI
581 Dhcp6DummyExtFree (
582 IN VOID *Arg
583 )
584 {
585 }
586
587
588 /**
589 The callback routine once message transmitted.
590
591 @param[in] Wrap The pointer to the received net buffer.
592 @param[in] EndPoint The pointer to the udp end point.
593 @param[in] IoStatus The return status from udp io.
594 @param[in] Context The opaque parameter to the function.
595
596 **/
597 VOID
598 EFIAPI
599 Dhcp6OnTransmitted (
600 IN NET_BUF *Wrap,
601 IN UDP_END_POINT *EndPoint,
602 IN EFI_STATUS IoStatus,
603 IN VOID *Context
604 )
605 {
606 NetbufFree (Wrap);
607 }
608
609
610 /**
611 Append the option to Buf, and move Buf to the end.
612
613 @param[in, out] Buf The pointer to the buffer.
614 @param[in] OptType The option type.
615 @param[in] OptLen The length of option contents.
616 @param[in] Data The pointer to the option content.
617
618 @return Buf The position to append the next option.
619
620 **/
621 UINT8 *
622 Dhcp6AppendOption (
623 IN OUT UINT8 *Buf,
624 IN UINT16 OptType,
625 IN UINT16 OptLen,
626 IN UINT8 *Data
627 )
628 {
629 //
630 // The format of Dhcp6 option:
631 //
632 // 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
633 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
634 // | option-code | option-len (option data) |
635 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
636 // | option-data |
637 // | (option-len octets) |
638 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
639 //
640
641 ASSERT (OptLen != 0);
642
643 WriteUnaligned16 ((UINT16 *) Buf, OptType);
644 Buf += 2;
645 WriteUnaligned16 ((UINT16 *) Buf, OptLen);
646 Buf += 2;
647 CopyMem (Buf, Data, NTOHS (OptLen));
648 Buf += NTOHS (OptLen);
649
650 return Buf;
651 }
652
653 /**
654 Append the appointed IA Address option to Buf, and move Buf to the end.
655
656 @param[in, out] Buf The pointer to the position to append.
657 @param[in] IaAddr The pointer to the IA Address.
658 @param[in] MessageType Message type of DHCP6 package.
659
660 @return Buf The position to append the next option.
661
662 **/
663 UINT8 *
664 Dhcp6AppendIaAddrOption (
665 IN OUT UINT8 *Buf,
666 IN EFI_DHCP6_IA_ADDRESS *IaAddr,
667 IN UINT32 MessageType
668 )
669 {
670
671 // The format of the IA Address option is:
672 //
673 // 0 1 2 3
674 // 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
675 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
676 // | OPTION_IAADDR | option-len |
677 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
678 // | |
679 // | IPv6 address |
680 // | |
681 // | |
682 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
683 // | preferred-lifetime |
684 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
685 // | valid-lifetime |
686 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
687 // . .
688 // . IAaddr-options .
689 // . .
690 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
691
692 //
693 // Fill the value of Ia Address option type
694 //
695 WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptIaAddr));
696 Buf += 2;
697
698 WriteUnaligned16 ((UINT16 *) Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS)));
699 Buf += 2;
700
701 CopyMem (Buf, &IaAddr->IpAddress, sizeof(EFI_IPv6_ADDRESS));
702 Buf += sizeof(EFI_IPv6_ADDRESS);
703
704 //
705 // Fill the value of preferred-lifetime and valid-lifetime.
706 // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields
707 // should set to 0 when initiate a Confirm message.
708 //
709 if (MessageType != Dhcp6MsgConfirm) {
710 WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->PreferredLifetime));
711 }
712 Buf += 4;
713
714 if (MessageType != Dhcp6MsgConfirm) {
715 WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->ValidLifetime));
716 }
717 Buf += 4;
718
719 return Buf;
720 }
721
722
723 /**
724 Append the appointed Ia option to Buf, and move Buf to the end.
725
726 @param[in, out] Buf The pointer to the position to append.
727 @param[in] Ia The pointer to the Ia.
728 @param[in] T1 The time of T1.
729 @param[in] T2 The time of T2.
730 @param[in] MessageType Message type of DHCP6 package.
731
732 @return Buf The position to append the next Ia option.
733
734 **/
735 UINT8 *
736 Dhcp6AppendIaOption (
737 IN OUT UINT8 *Buf,
738 IN EFI_DHCP6_IA *Ia,
739 IN UINT32 T1,
740 IN UINT32 T2,
741 IN UINT32 MessageType
742 )
743 {
744 UINT8 *AddrOpt;
745 UINT16 *Len;
746 UINTN Index;
747
748 //
749 // The format of IA_NA and IA_TA option:
750 //
751 // 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
752 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
753 // | OPTION_IA_NA | option-len |
754 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
755 // | IAID (4 octets) |
756 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
757 // | T1 (only for IA_NA) |
758 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
759 // | T2 (only for IA_NA) |
760 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
761 // | |
762 // . IA_NA-options/IA_TA-options .
763 // . .
764 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
765 //
766
767 //
768 // Fill the value of Ia option type
769 //
770 WriteUnaligned16 ((UINT16 *) Buf, HTONS (Ia->Descriptor.Type));
771 Buf += 2;
772
773 //
774 // Fill the len of Ia option later, keep the pointer first
775 //
776 Len = (UINT16 *) Buf;
777 Buf += 2;
778
779 //
780 // Fill the value of iaid
781 //
782 WriteUnaligned32 ((UINT32 *) Buf, HTONL (Ia->Descriptor.IaId));
783 Buf += 4;
784
785 //
786 // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.
787 //
788 if (Ia->Descriptor.Type == Dhcp6OptIana) {
789 WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff));
790 Buf += 4;
791 WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff));
792 Buf += 4;
793 }
794
795 //
796 // Fill all the addresses belong to the Ia
797 //
798 for (Index = 0; Index < Ia->IaAddressCount; Index++) {
799 AddrOpt = (UINT8 *) Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);
800 Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *) AddrOpt, MessageType);
801 }
802
803 //
804 // Fill the value of Ia option length
805 //
806 *Len = HTONS ((UINT16) (Buf - (UINT8 *) Len - 2));
807
808 return Buf;
809 }
810
811 /**
812 Append the appointed Elapsed time option to Buf, and move Buf to the end.
813
814 @param[in, out] Buf The pointer to the position to append.
815 @param[in] Instance The pointer to the Dhcp6 instance.
816 @param[out] Elapsed The pointer to the elapsed time value in
817 the generated packet.
818
819 @return Buf The position to append the next Ia option.
820
821 **/
822 UINT8 *
823 Dhcp6AppendETOption (
824 IN OUT UINT8 *Buf,
825 IN DHCP6_INSTANCE *Instance,
826 OUT UINT16 **Elapsed
827 )
828 {
829 //
830 // The format of elapsed time option:
831 //
832 // 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
833 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
834 // | OPTION_ELAPSED_TIME | option-len |
835 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
836 // | elapsed-time |
837 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
838 //
839
840 //
841 // Fill the value of elapsed-time option type.
842 //
843 WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptElapsedTime));
844 Buf += 2;
845
846 //
847 // Fill the len of elapsed-time option, which is fixed.
848 //
849 WriteUnaligned16 ((UINT16 *) Buf, HTONS(2));
850 Buf += 2;
851
852 //
853 // Fill in elapsed time value with 0 value for now. The actual value is
854 // filled in later just before the packet is transmitted.
855 //
856 WriteUnaligned16 ((UINT16 *) Buf, HTONS(0));
857 *Elapsed = (UINT16 *) Buf;
858 Buf += 2;
859
860 return Buf;
861 }
862
863 /**
864 Set the elapsed time based on the given instance and the pointer to the
865 elapsed time option.
866
867 @param[in] Elapsed The pointer to the position to append.
868 @param[in] Instance The pointer to the Dhcp6 instance.
869
870 **/
871 VOID
872 SetElapsedTime (
873 IN UINT16 *Elapsed,
874 IN DHCP6_INSTANCE *Instance
875 )
876 {
877 EFI_TIME Time;
878 UINT64 CurrentStamp;
879 UINT64 ElapsedTimeValue;
880
881 //
882 // Generate a time stamp of the centiseconds from 2000/1/1, assume 30day/month.
883 //
884 gRT->GetTime (&Time, NULL);
885 CurrentStamp = (UINT64)
886 (
887 ((((((Time.Year - 2000) * 360 +
888 (Time.Month - 1)) * 30 +
889 (Time.Day - 1)) * 24 + Time.Hour) * 60 +
890 Time.Minute) * 60 + Time.Second) * 100
891 + DivU64x32(Time.Nanosecond, 10000000)
892 );
893
894 //
895 // Sentinel value of 0 means that this is the first DHCP packet that we are
896 // sending and that we need to initialize the value. First DHCP message
897 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.
898 //
899 if (Instance->StartTime == 0) {
900 ElapsedTimeValue = 0;
901 Instance->StartTime = CurrentStamp;
902 } else {
903 ElapsedTimeValue = CurrentStamp - Instance->StartTime;
904
905 //
906 // If elapsed time cannot fit in two bytes, set it to 0xffff.
907 //
908 if (ElapsedTimeValue > 0xffff) {
909 ElapsedTimeValue = 0xffff;
910 }
911 }
912 WriteUnaligned16 (Elapsed, HTONS((UINT16) ElapsedTimeValue));
913 }
914
915
916 /**
917 Seek the address of the first byte of the option header.
918
919 @param[in] Buf The pointer to the buffer.
920 @param[in] SeekLen The length to seek.
921 @param[in] OptType The option type.
922
923 @retval NULL If it failed to seek the option.
924 @retval others The position to the option.
925
926 **/
927 UINT8 *
928 Dhcp6SeekOption (
929 IN UINT8 *Buf,
930 IN UINT32 SeekLen,
931 IN UINT16 OptType
932 )
933 {
934 UINT8 *Cursor;
935 UINT8 *Option;
936 UINT16 DataLen;
937 UINT16 OpCode;
938
939 Option = NULL;
940 Cursor = Buf;
941
942 //
943 // The format of Dhcp6 option refers to Dhcp6AppendOption().
944 //
945 while (Cursor < Buf + SeekLen) {
946 OpCode = ReadUnaligned16 ((UINT16 *) Cursor);
947 if (OpCode == HTONS (OptType)) {
948 Option = Cursor;
949 break;
950 }
951 DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));
952 Cursor += (DataLen + 4);
953 }
954
955 return Option;
956 }
957
958
959 /**
960 Seek the address of the first byte of the Ia option header.
961
962 @param[in] Buf The pointer to the buffer.
963 @param[in] SeekLen The length to seek.
964 @param[in] IaDesc The pointer to the Ia descriptor.
965
966 @retval NULL If it failed to seek the Ia option.
967 @retval others The position to the Ia option.
968
969 **/
970 UINT8 *
971 Dhcp6SeekIaOption (
972 IN UINT8 *Buf,
973 IN UINT32 SeekLen,
974 IN EFI_DHCP6_IA_DESCRIPTOR *IaDesc
975 )
976 {
977 UINT8 *Cursor;
978 UINT8 *Option;
979 UINT16 DataLen;
980 UINT16 OpCode;
981 UINT32 IaId;
982
983 //
984 // The format of IA_NA and IA_TA option refers to Dhcp6AppendIaOption().
985 //
986 Option = NULL;
987 Cursor = Buf;
988
989 while (Cursor < Buf + SeekLen) {
990 OpCode = ReadUnaligned16 ((UINT16 *) Cursor);
991 IaId = ReadUnaligned32 ((UINT32 *) (Cursor + 4));
992 if (OpCode == HTONS (IaDesc->Type) && IaId == HTONL (IaDesc->IaId)) {
993 Option = Cursor;
994 break;
995 }
996 DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));
997 Cursor += (DataLen + 4);
998 }
999
1000 return Option;
1001 }
1002
1003 /**
1004 Check whether the incoming IPv6 address in IaAddr is one of the maintained
1005 addresses in the IA control blcok.
1006
1007 @param[in] IaAddr The pointer to the IA Address to be checked.
1008 @param[in] CurrentIa The pointer to the IA in IA control block.
1009
1010 @retval TRUE Yes, this Address is already in IA control block.
1011 @retval FALSE No, this Address is NOT in IA control block.
1012
1013 **/
1014 BOOLEAN
1015 Dhcp6AddrIsInCurrentIa (
1016 IN EFI_DHCP6_IA_ADDRESS *IaAddr,
1017 IN EFI_DHCP6_IA *CurrentIa
1018 )
1019 {
1020 UINT32 Index;
1021
1022 ASSERT (IaAddr != NULL && CurrentIa != NULL);
1023
1024 for (Index = 0; Index < CurrentIa->IaAddressCount; Index++) {
1025 if (EFI_IP6_EQUAL(&IaAddr->IpAddress, &CurrentIa->IaAddress[Index].IpAddress)) {
1026 return TRUE;
1027 }
1028 }
1029 return FALSE;
1030 }
1031
1032 /**
1033 Parse the address option and update the address infomation.
1034
1035 @param[in] CurrentIa The pointer to the Ia Address in control blcok.
1036 @param[in] IaInnerOpt The pointer to the buffer.
1037 @param[in] IaInnerLen The length to parse.
1038 @param[out] AddrNum The number of addresses.
1039 @param[in, out] AddrBuf The pointer to the address buffer.
1040
1041 **/
1042 VOID
1043 Dhcp6ParseAddrOption (
1044 IN EFI_DHCP6_IA *CurrentIa,
1045 IN UINT8 *IaInnerOpt,
1046 IN UINT16 IaInnerLen,
1047 OUT UINT32 *AddrNum,
1048 IN OUT EFI_DHCP6_IA_ADDRESS *AddrBuf
1049 )
1050 {
1051 UINT8 *Cursor;
1052 UINT16 DataLen;
1053 UINT16 OpCode;
1054 UINT32 ValidLt;
1055 UINT32 PreferredLt;
1056 EFI_DHCP6_IA_ADDRESS *IaAddr;
1057
1058 //
1059 // The format of the IA Address option:
1060 //
1061 // 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
1062 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1063 // | OPTION_IAADDR | option-len |
1064 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1065 // | |
1066 // | IPv6 address |
1067 // | |
1068 // | |
1069 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1070 // | preferred-lifetime |
1071 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1072 // | valid-lifetime |
1073 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1074 // . .
1075 // . IAaddr-options .
1076 // . .
1077 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1078 //
1079
1080 //
1081 // Two usage model:
1082 //
1083 // 1. Pass addrbuf == null, to get the addrnum over the Ia inner options.
1084 // 2. Pass addrbuf != null, to resolve the addresses over the Ia inner
1085 // options to the addrbuf.
1086 //
1087
1088 Cursor = IaInnerOpt;
1089 *AddrNum = 0;
1090
1091 while (Cursor < IaInnerOpt + IaInnerLen) {
1092 //
1093 // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option
1094 // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time.
1095 //
1096 OpCode = ReadUnaligned16 ((UINT16 *) Cursor);
1097 PreferredLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 20)));
1098 ValidLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 24)));
1099 IaAddr = (EFI_DHCP6_IA_ADDRESS *) (Cursor + 4);
1100 if (OpCode == HTONS (Dhcp6OptIaAddr) && ValidLt >= PreferredLt &&
1101 (Dhcp6AddrIsInCurrentIa(IaAddr, CurrentIa) || ValidLt !=0)) {
1102 if (AddrBuf != NULL) {
1103 CopyMem (AddrBuf, IaAddr, sizeof (EFI_DHCP6_IA_ADDRESS));
1104 AddrBuf->PreferredLifetime = PreferredLt;
1105 AddrBuf->ValidLifetime = ValidLt;
1106 AddrBuf = (EFI_DHCP6_IA_ADDRESS *) ((UINT8 *) AddrBuf + sizeof (EFI_DHCP6_IA_ADDRESS));
1107 }
1108 (*AddrNum)++;
1109 }
1110 DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));
1111 Cursor += (DataLen + 4);
1112 }
1113 }
1114
1115
1116 /**
1117 Create a control blcok for the Ia according to the corresponding options.
1118
1119 @param[in] Instance The pointer to DHCP6 Instance.
1120 @param[in] IaInnerOpt The pointer to the inner options in the Ia option.
1121 @param[in] IaInnerLen The length of all the inner options in the Ia option.
1122 @param[in] T1 T1 time in the Ia option.
1123 @param[in] T2 T2 time in the Ia option.
1124
1125 @retval EFI_NOT_FOUND No valid IA option is found.
1126 @retval EFI_SUCCESS Create an IA control block successfully.
1127 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1128 @retval EFI_DEVICE_ERROR An unexpected error.
1129
1130 **/
1131 EFI_STATUS
1132 Dhcp6GenerateIaCb (
1133 IN DHCP6_INSTANCE *Instance,
1134 IN UINT8 *IaInnerOpt,
1135 IN UINT16 IaInnerLen,
1136 IN UINT32 T1,
1137 IN UINT32 T2
1138 )
1139 {
1140 UINT32 AddrNum;
1141 UINT32 IaSize;
1142 EFI_DHCP6_IA *Ia;
1143
1144 if (Instance->IaCb.Ia == NULL) {
1145 return EFI_DEVICE_ERROR;
1146 }
1147
1148 //
1149 // Calculate the number of addresses for this Ia, excluding the addresses with
1150 // the value 0 of valid lifetime.
1151 //
1152 Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, NULL);
1153
1154 if (AddrNum == 0) {
1155 return EFI_NOT_FOUND;
1156 }
1157
1158 //
1159 // Allocate for new IA.
1160 //
1161 IaSize = sizeof (EFI_DHCP6_IA) + (AddrNum - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
1162 Ia = AllocateZeroPool (IaSize);
1163
1164 if (Ia == NULL) {
1165 return EFI_OUT_OF_RESOURCES;
1166 }
1167
1168 //
1169 // Fill up this new IA fields.
1170 //
1171 Ia->State = Instance->IaCb.Ia->State;
1172 Ia->IaAddressCount = AddrNum;
1173 CopyMem (&Ia->Descriptor, &Instance->Config->IaDescriptor, sizeof (EFI_DHCP6_IA_DESCRIPTOR));
1174 Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress);
1175
1176 //
1177 // Free original IA resource.
1178 //
1179 if (Instance->IaCb.Ia->ReplyPacket != NULL) {
1180 FreePool (Instance->IaCb.Ia->ReplyPacket);
1181 }
1182 FreePool (Instance->IaCb.Ia);
1183
1184
1185 ZeroMem (&Instance->IaCb, sizeof (DHCP6_IA_CB));
1186
1187 //
1188 // Update IaCb to use new IA.
1189 //
1190 Instance->IaCb.Ia = Ia;
1191
1192 //
1193
1194 // Fill in IaCb fields. Such as T1, T2, AllExpireTime and LeaseTime.
1195 //
1196 Instance->IaCb.T1 = T1;
1197 Instance->IaCb.T2 = T2;
1198 Dhcp6CalculateLeaseTime (&Instance->IaCb);
1199
1200 return EFI_SUCCESS;
1201 }
1202
1203
1204 /**
1205 Cache the current IA configuration information.
1206
1207 @param[in] Instance The pointer to DHCP6 Instance.
1208
1209 @retval EFI_SUCCESS Cache the current IA successfully.
1210 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
1211
1212 **/
1213 EFI_STATUS
1214 Dhcp6CacheIa (
1215 IN DHCP6_INSTANCE *Instance
1216 )
1217 {
1218 UINTN IaSize;
1219 EFI_DHCP6_IA *Ia;
1220
1221 Ia = Instance->IaCb.Ia;
1222
1223 if ((Instance->CacheIa == NULL) && (Ia != NULL)) {
1224 //
1225 // Cache the current IA.
1226 //
1227 IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
1228
1229 Instance->CacheIa = AllocateZeroPool (IaSize);
1230 if (Instance->CacheIa == NULL) {
1231 return EFI_OUT_OF_RESOURCES;
1232 }
1233 CopyMem (Instance->CacheIa, Ia, IaSize);
1234 }
1235 return EFI_SUCCESS;
1236 }
1237
1238 /**
1239 Append CacheIa to the currrent IA. Meanwhile, clear CacheIa.ValidLifetime to 0.
1240
1241 @param[in] Instance The pointer to DHCP6 instance.
1242
1243 **/
1244 VOID
1245 Dhcp6AppendCacheIa (
1246 IN DHCP6_INSTANCE *Instance
1247 )
1248 {
1249 UINT8 *Ptr;
1250 UINTN Index;
1251 UINTN IaSize;
1252 UINTN NewIaSize;
1253 EFI_DHCP6_IA *Ia;
1254 EFI_DHCP6_IA *NewIa;
1255 EFI_DHCP6_IA *CacheIa;
1256
1257 Ia = Instance->IaCb.Ia;
1258 CacheIa = Instance->CacheIa;
1259
1260 if ((CacheIa != NULL) && (CacheIa->IaAddressCount != 0)) {
1261 //
1262 // There are old addresses existing. Merge with current addresses.
1263 //
1264 NewIaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount + CacheIa->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
1265 NewIa = AllocateZeroPool (NewIaSize);
1266 if (NewIa == NULL) {
1267 return;
1268 }
1269
1270 IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);
1271 CopyMem (NewIa, Ia, IaSize);
1272
1273 //
1274 // Clear old address.ValidLifetime
1275 //
1276 for (Index = 0; Index < CacheIa->IaAddressCount; Index++) {
1277 CacheIa->IaAddress[Index].ValidLifetime = 0;
1278 }
1279
1280 NewIa->IaAddressCount += CacheIa->IaAddressCount;
1281 Ptr = (UINT8*)&NewIa->IaAddress[Ia->IaAddressCount];
1282 CopyMem (Ptr, CacheIa->IaAddress, CacheIa->IaAddressCount * sizeof (EFI_DHCP6_IA_ADDRESS));
1283
1284 //
1285 // Migrate to the NewIa and free previous.
1286 //
1287 FreePool (Instance->CacheIa);
1288 FreePool (Instance->IaCb.Ia);
1289 Instance->CacheIa = NULL;
1290 Instance->IaCb.Ia = NewIa;
1291 }
1292 }
1293
1294 /**
1295 Calculate the Dhcp6 get mapping timeout by adding additinal delay to the IP6 DAD transmits count.
1296
1297 @param[in] Ip6Cfg The pointer to Ip6 config protocol.
1298 @param[out] TimeOut The time out value in 100ns units.
1299
1300 @retval EFI_INVALID_PARAMETER Input parameters are invalid.
1301 @retval EFI_SUCCESS Calculate the time out value successfully.
1302 **/
1303 EFI_STATUS
1304 Dhcp6GetMappingTimeOut (
1305 IN EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg,
1306 OUT UINTN *TimeOut
1307 )
1308 {
1309 EFI_STATUS Status;
1310 UINTN DataSize;
1311 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;
1312
1313 if (Ip6Cfg == NULL || TimeOut == NULL) {
1314 return EFI_INVALID_PARAMETER;
1315 }
1316
1317 DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
1318 Status = Ip6Cfg->GetData (
1319 Ip6Cfg,
1320 Ip6ConfigDataTypeDupAddrDetectTransmits,
1321 &DataSize,
1322 &DadXmits
1323 );
1324 if (EFI_ERROR (Status)) {
1325 return Status;
1326 }
1327
1328 *TimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + DHCP6_DAD_ADDITIONAL_DELAY;
1329
1330 return EFI_SUCCESS;
1331 }