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