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