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