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