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