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