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