]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c
Remove ASSERT when failed to Get/Set “AttemptOrder” and “ClientId” variable.
[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
146 WriteUnaligned16 ((UINT16 *) (Duid->Duid), HTONS (Dhcp6DuidTypeLlt));\r
147 WriteUnaligned16 ((UINT16 *) (Duid->Duid + 2), HTONS (NET_IFTYPE_ETHERNET));\r
148 WriteUnaligned32 ((UINT32 *) (Duid->Duid + 4), HTONL (Stamp));\r
149 \r
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
389 EFI_DHCP6_IA_ADDRESS *IaAddr;\r
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
404 IaAddr = IaCb->Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);\r
405 MinLt = MIN (MinLt, IaAddr->ValidLifetime);\r
406 MaxLt = MAX (MinLt, IaAddr->ValidLifetime);\r
407 }\r
408\r
409 //\r
410 // Take 50% minlt as t1, and 80% maxlt as t2 if Dhcp6 server doesn't offer\r
411 // such information.\r
412 //\r
413 IaCb->T1 = (IaCb->T1 != 0) ? IaCb->T1 : (UINT32)(MinLt * 5 / 10);\r
414 IaCb->T2 = (IaCb->T2 != 0) ? IaCb->T2 : (UINT32)(MinLt * 8 / 10);\r
415 IaCb->AllExpireTime = MaxLt;\r
416 IaCb->LeaseTime = 0;\r
417}\r
418\r
419\r
420/**\r
421 Check whether the addresses are all included by the configured Ia.\r
422\r
423 @param[in] Ia The pointer to the Ia.\r
424 @param[in] AddressCount The number of addresses.\r
425 @param[in] Addresses The pointer to the addresses buffer.\r
426\r
427 @retval EFI_SUCCESS The addresses are all included by the configured IA.\r
428 @retval EFI_NOT_FOUND The addresses are not included by the configured IA.\r
429\r
430**/\r
431EFI_STATUS\r
432Dhcp6CheckAddress (\r
433 IN EFI_DHCP6_IA *Ia,\r
434 IN UINT32 AddressCount,\r
435 IN EFI_IPv6_ADDRESS *Addresses\r
436 )\r
437{\r
438 UINTN Index1;\r
439 UINTN Index2;\r
440 BOOLEAN Found;\r
441\r
442 //\r
443 // Check whether the addresses are all included by the configured IA. And it\r
444 // will return success if address count is zero, which means all addresses.\r
445 //\r
446 for (Index1 = 0; Index1 < AddressCount; Index1++) {\r
447\r
448 Found = FALSE;\r
449\r
450 for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {\r
451\r
452 if (CompareMem (\r
453 &Addresses[Index1],\r
454 &Ia->IaAddress[Index2],\r
455 sizeof (EFI_IPv6_ADDRESS)\r
456 ) == 0) {\r
457\r
458 Found = TRUE;\r
459 break;\r
460 }\r
461 }\r
462\r
463 if (!Found) {\r
464 return EFI_NOT_FOUND;\r
465 }\r
466 }\r
467\r
468 return EFI_SUCCESS;\r
469}\r
470\r
471\r
472/**\r
473 Deprive the addresses from current Ia, and generate another eliminated Ia.\r
474\r
475 @param[in] Ia The pointer to the Ia.\r
476 @param[in] AddressCount The number of addresses.\r
477 @param[in] Addresses The pointer to the addresses buffer.\r
478\r
479 @retval NULL If it failed to generate the deprived Ia.\r
480 @retval others The pointer to the deprived Ia.\r
481\r
482**/\r
483EFI_DHCP6_IA *\r
484Dhcp6DepriveAddress (\r
485 IN EFI_DHCP6_IA *Ia,\r
486 IN UINT32 AddressCount,\r
487 IN EFI_IPv6_ADDRESS *Addresses\r
488 )\r
489{\r
490 EFI_DHCP6_IA *IaCopy;\r
491 UINTN IaCopySize;\r
492 UINTN Index1;\r
493 UINTN Index2;\r
494 BOOLEAN Found;\r
495\r
496 if (AddressCount == 0) {\r
497 //\r
498 // It means release all Ia addresses if address count is zero.\r
499 //\r
500 AddressCount = Ia->IaAddressCount;\r
501 }\r
502\r
503 ASSERT (AddressCount != 0);\r
504\r
505 IaCopySize = sizeof (EFI_DHCP6_IA) + (AddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r
506 IaCopy = AllocateZeroPool (IaCopySize);\r
507\r
508 if (IaCopy == NULL) {\r
509 return NULL;\r
510 }\r
511\r
512 if (AddressCount == Ia->IaAddressCount) {\r
513 //\r
514 // If release all Ia addresses, just copy the configured Ia and then set\r
515 // its address count as zero.\r
516 // We may decline/release part of addresses at the begining. So it's a\r
517 // forwarding step to update address infor for decline/release, while the\r
518 // other infor such as Ia state will be updated when receiving reply.\r
519 //\r
520 CopyMem (IaCopy, Ia, IaCopySize);\r
521 Ia->IaAddressCount = 0;\r
522 return IaCopy;\r
523 }\r
524\r
525 CopyMem (IaCopy, Ia, sizeof (EFI_DHCP6_IA));\r
526\r
527 //\r
528 // Move the addresses from the Ia of instance to the deprived Ia.\r
529 //\r
530 for (Index1 = 0; Index1 < AddressCount; Index1++) {\r
531\r
532 Found = FALSE;\r
533\r
534 for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {\r
535\r
536 if (CompareMem (\r
537 &Addresses[Index1],\r
538 &Ia->IaAddress[Index2],\r
539 sizeof (EFI_IPv6_ADDRESS)\r
540 ) == 0) {\r
541 //\r
542 // Copy the deprived address to the copy of Ia\r
543 //\r
544 CopyMem (\r
545 &IaCopy->IaAddress[Index1],\r
546 &Ia->IaAddress[Index2],\r
547 sizeof (EFI_DHCP6_IA_ADDRESS)\r
548 );\r
549 //\r
550 // Delete the deprived address from the instance Ia\r
551 //\r
552 if (Index2 + 1 < Ia->IaAddressCount) {\r
553 CopyMem (\r
554 &Ia->IaAddress[Index2],\r
555 &Ia->IaAddress[Index2 + 1],\r
556 (Ia->IaAddressCount - Index2 - 1) * sizeof (EFI_DHCP6_IA_ADDRESS)\r
557 );\r
558 }\r
559 Found = TRUE;\r
560 break;\r
561 }\r
562 }\r
563 ASSERT (Found == TRUE);\r
564 }\r
565\r
566 Ia->IaAddressCount -= AddressCount;\r
567 IaCopy->IaAddressCount = AddressCount;\r
568\r
569 return IaCopy;\r
570}\r
571\r
572\r
573/**\r
574 The dummy ext buffer free callback routine.\r
575\r
576 @param[in] Arg The pointer to the parameter.\r
577\r
578**/\r
579VOID\r
580EFIAPI\r
581Dhcp6DummyExtFree (\r
582 IN VOID *Arg\r
583 )\r
584{\r
585}\r
586\r
587\r
588/**\r
589 The callback routine once message transmitted.\r
590\r
76389e18 591 @param[in] Wrap The pointer to the received net buffer.\r
a3bcde70
HT
592 @param[in] EndPoint The pointer to the udp end point.\r
593 @param[in] IoStatus The return status from udp io.\r
594 @param[in] Context The opaque parameter to the function.\r
595\r
596**/\r
597VOID\r
598EFIAPI\r
599Dhcp6OnTransmitted (\r
600 IN NET_BUF *Wrap,\r
601 IN UDP_END_POINT *EndPoint,\r
602 IN EFI_STATUS IoStatus,\r
603 IN VOID *Context\r
604 )\r
605{\r
606 NetbufFree (Wrap);\r
607}\r
608\r
609\r
610/**\r
611 Append the option to Buf, and move Buf to the end.\r
612\r
613 @param[in, out] Buf The pointer to the buffer.\r
614 @param[in] OptType The option type.\r
615 @param[in] OptLen The length of option contents.\r
616 @param[in] Data The pointer to the option content.\r
617\r
618 @return Buf The position to append the next option.\r
619\r
620**/\r
621UINT8 *\r
622Dhcp6AppendOption (\r
623 IN OUT UINT8 *Buf,\r
624 IN UINT16 OptType,\r
625 IN UINT16 OptLen,\r
626 IN UINT8 *Data\r
627 )\r
628{\r
629 //\r
630 // The format of Dhcp6 option:\r
631 //\r
632 // 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
633 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
634 // | option-code | option-len (option data) |\r
635 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
636 // | option-data |\r
637 // | (option-len octets) |\r
638 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
639 //\r
640\r
641 ASSERT (OptLen != 0);\r
642\r
643 WriteUnaligned16 ((UINT16 *) Buf, OptType);\r
644 Buf += 2;\r
645 WriteUnaligned16 ((UINT16 *) Buf, OptLen);\r
646 Buf += 2;\r
647 CopyMem (Buf, Data, NTOHS (OptLen));\r
648 Buf += NTOHS (OptLen);\r
649\r
650 return Buf;\r
651}\r
652\r
685e44a5 653/**\r
654 Append the appointed IA Address option to Buf, and move Buf to the end.\r
655\r
656 @param[in, out] Buf The pointer to the position to append.\r
657 @param[in] IaAddr The pointer to the IA Address.\r
658 @param[in] MessageType Message type of DHCP6 package.\r
659\r
660 @return Buf The position to append the next option.\r
661\r
662**/\r
663UINT8 *\r
664Dhcp6AppendIaAddrOption (\r
665 IN OUT UINT8 *Buf,\r
666 IN EFI_DHCP6_IA_ADDRESS *IaAddr,\r
667 IN UINT32 MessageType\r
668)\r
669{\r
670\r
671 // The format of the IA Address option is:\r
672 //\r
673 // 0 1 2 3\r
674 // 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
675 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
676 // | OPTION_IAADDR | option-len |\r
677 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
678 // | |\r
679 // | IPv6 address |\r
680 // | |\r
681 // | |\r
682 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
683 // | preferred-lifetime |\r
684 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
685 // | valid-lifetime |\r
686 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
687 // . .\r
688 // . IAaddr-options .\r
689 // . .\r
690 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
691 \r
692 //\r
693 // Fill the value of Ia Address option type\r
694 //\r
695 WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptIaAddr));\r
696 Buf += 2;\r
697\r
698 WriteUnaligned16 ((UINT16 *) Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS)));\r
699 Buf += 2;\r
700\r
701 CopyMem (Buf, &IaAddr->IpAddress, sizeof(EFI_IPv6_ADDRESS));\r
702 Buf += sizeof(EFI_IPv6_ADDRESS);\r
703\r
704 //\r
705 // Fill the value of preferred-lifetime and valid-lifetime.\r
706 // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields\r
707 // should set to 0 when initiate a Confirm message.\r
708 //\r
709 if (MessageType != Dhcp6MsgConfirm) {\r
710 WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->PreferredLifetime));\r
711 }\r
712 Buf += 4;\r
713\r
714 if (MessageType != Dhcp6MsgConfirm) {\r
715 WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->ValidLifetime));\r
716 }\r
717 Buf += 4;\r
718\r
719 return Buf;\r
720}\r
721\r
a3bcde70
HT
722\r
723/**\r
724 Append the appointed Ia option to Buf, and move Buf to the end.\r
725\r
726 @param[in, out] Buf The pointer to the position to append.\r
727 @param[in] Ia The pointer to the Ia.\r
728 @param[in] T1 The time of T1.\r
729 @param[in] T2 The time of T2.\r
685e44a5 730 @param[in] MessageType Message type of DHCP6 package.\r
a3bcde70
HT
731\r
732 @return Buf The position to append the next Ia option.\r
733\r
734**/\r
735UINT8 *\r
736Dhcp6AppendIaOption (\r
737 IN OUT UINT8 *Buf,\r
738 IN EFI_DHCP6_IA *Ia,\r
739 IN UINT32 T1,\r
685e44a5 740 IN UINT32 T2,\r
741 IN UINT32 MessageType\r
a3bcde70
HT
742 )\r
743{\r
744 UINT8 *AddrOpt;\r
745 UINT16 *Len;\r
746 UINTN Index;\r
a3bcde70
HT
747\r
748 //\r
749 // The format of IA_NA and IA_TA option:\r
750 //\r
751 // 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
752 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
753 // | OPTION_IA_NA | option-len |\r
754 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
755 // | IAID (4 octets) |\r
756 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
757 // | T1 (only for IA_NA) |\r
758 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
759 // | T2 (only for IA_NA) |\r
760 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
761 // | |\r
762 // . IA_NA-options/IA_TA-options .\r
763 // . .\r
764 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
765 //\r
766\r
767 //\r
768 // Fill the value of Ia option type\r
769 //\r
770 WriteUnaligned16 ((UINT16 *) Buf, HTONS (Ia->Descriptor.Type));\r
771 Buf += 2;\r
772\r
773 //\r
774 // Fill the len of Ia option later, keep the pointer first\r
775 //\r
776 Len = (UINT16 *) Buf;\r
777 Buf += 2;\r
778\r
779 //\r
780 // Fill the value of iaid\r
781 //\r
782 WriteUnaligned32 ((UINT32 *) Buf, HTONL (Ia->Descriptor.IaId));\r
783 Buf += 4;\r
784\r
785 //\r
786 // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.\r
787 //\r
788 if (Ia->Descriptor.Type == Dhcp6OptIana) {\r
685e44a5 789 WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff));\r
a3bcde70 790 Buf += 4;\r
685e44a5 791 WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff));\r
a3bcde70
HT
792 Buf += 4;\r
793 }\r
794\r
795 //\r
796 // Fill all the addresses belong to the Ia\r
797 //\r
798 for (Index = 0; Index < Ia->IaAddressCount; Index++) {\r
685e44a5 799 AddrOpt = (UINT8 *) Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);\r
800 Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *) AddrOpt, MessageType);\r
a3bcde70
HT
801 }\r
802\r
803 //\r
804 // Fill the value of Ia option length\r
805 //\r
806 *Len = HTONS ((UINT16) (Buf - (UINT8 *) Len - 2));\r
807\r
808 return Buf;\r
809}\r
810\r
811/**\r
812 Append the appointed Elapsed time option to Buf, and move Buf to the end.\r
813\r
814 @param[in, out] Buf The pointer to the position to append.\r
815 @param[in] Instance The pointer to the Dhcp6 instance.\r
816 @param[out] Elapsed The pointer to the elapsed time value in\r
817 the generated packet.\r
818\r
819 @return Buf The position to append the next Ia option.\r
820\r
821**/\r
822UINT8 *\r
823Dhcp6AppendETOption (\r
824 IN OUT UINT8 *Buf,\r
825 IN DHCP6_INSTANCE *Instance,\r
826 OUT UINT16 **Elapsed\r
827 )\r
828{\r
829 //\r
830 // The format of elapsed time option:\r
831 //\r
832 // 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
833 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
834 // | OPTION_ELAPSED_TIME | option-len |\r
835 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
836 // | elapsed-time |\r
837 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
838 //\r
839\r
840 //\r
841 // Fill the value of elapsed-time option type.\r
842 //\r
843 WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptElapsedTime));\r
844 Buf += 2;\r
845\r
846 //\r
847 // Fill the len of elapsed-time option, which is fixed.\r
848 //\r
849 WriteUnaligned16 ((UINT16 *) Buf, HTONS(2));\r
850 Buf += 2;\r
851\r
852 //\r
853 // Fill in elapsed time value with 0 value for now. The actual value is\r
854 // filled in later just before the packet is transmitted.\r
855 //\r
856 WriteUnaligned16 ((UINT16 *) Buf, HTONS(0));\r
857 *Elapsed = (UINT16 *) Buf;\r
858 Buf += 2;\r
859\r
860 return Buf;\r
861}\r
862\r
863/**\r
864 Set the elapsed time based on the given instance and the pointer to the\r
865 elapsed time option.\r
866\r
867 @param[in] Elapsed The pointer to the position to append.\r
868 @param[in] Instance The pointer to the Dhcp6 instance.\r
869\r
870**/\r
871VOID\r
872SetElapsedTime (\r
873 IN UINT16 *Elapsed,\r
874 IN DHCP6_INSTANCE *Instance\r
875 )\r
876{\r
877 EFI_TIME Time;\r
878 UINT64 CurrentStamp;\r
879 UINT64 ElapsedTimeValue;\r
880\r
881 //\r
882 // Generate a time stamp of the centiseconds from 2000/1/1, assume 30day/month.\r
883 //\r
884 gRT->GetTime (&Time, NULL);\r
885 CurrentStamp = (UINT64)\r
886 (\r
887 ((((((Time.Year - 2000) * 360 +\r
888 (Time.Month - 1)) * 30 +\r
889 (Time.Day - 1)) * 24 + Time.Hour) * 60 +\r
890 Time.Minute) * 60 + Time.Second) * 100\r
891 + DivU64x32(Time.Nanosecond, 10000000)\r
892 );\r
893\r
894 //\r
895 // Sentinel value of 0 means that this is the first DHCP packet that we are\r
685e44a5 896 // sending and that we need to initialize the value. First DHCP message\r
a3bcde70
HT
897 // gets 0 elapsed-time. Otherwise, calculate based on StartTime.\r
898 //\r
899 if (Instance->StartTime == 0) {\r
900 ElapsedTimeValue = 0;\r
901 Instance->StartTime = CurrentStamp;\r
902 } else {\r
903 ElapsedTimeValue = CurrentStamp - Instance->StartTime;\r
904\r
905 //\r
906 // If elapsed time cannot fit in two bytes, set it to 0xffff.\r
907 //\r
908 if (ElapsedTimeValue > 0xffff) {\r
909 ElapsedTimeValue = 0xffff;\r
910 }\r
911 }\r
912 WriteUnaligned16 (Elapsed, HTONS((UINT16) ElapsedTimeValue));\r
913}\r
914\r
915\r
916/**\r
917 Seek the address of the first byte of the option header.\r
918\r
919 @param[in] Buf The pointer to the buffer.\r
920 @param[in] SeekLen The length to seek.\r
921 @param[in] OptType The option type.\r
922\r
923 @retval NULL If it failed to seek the option.\r
924 @retval others The position to the option.\r
925\r
926**/\r
927UINT8 *\r
928Dhcp6SeekOption (\r
929 IN UINT8 *Buf,\r
930 IN UINT32 SeekLen,\r
931 IN UINT16 OptType\r
932 )\r
933{\r
934 UINT8 *Cursor;\r
935 UINT8 *Option;\r
936 UINT16 DataLen;\r
937 UINT16 OpCode;\r
938\r
939 Option = NULL;\r
940 Cursor = Buf;\r
941\r
942 //\r
943 // The format of Dhcp6 option refers to Dhcp6AppendOption().\r
944 //\r
945 while (Cursor < Buf + SeekLen) {\r
946 OpCode = ReadUnaligned16 ((UINT16 *) Cursor);\r
947 if (OpCode == HTONS (OptType)) {\r
948 Option = Cursor;\r
949 break;\r
950 }\r
951 DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));\r
952 Cursor += (DataLen + 4);\r
953 }\r
954\r
955 return Option;\r
956}\r
957\r
958\r
959/**\r
960 Seek the address of the first byte of the Ia option header.\r
961\r
962 @param[in] Buf The pointer to the buffer.\r
963 @param[in] SeekLen The length to seek.\r
964 @param[in] IaDesc The pointer to the Ia descriptor.\r
965\r
966 @retval NULL If it failed to seek the Ia option.\r
967 @retval others The position to the Ia option.\r
968\r
969**/\r
970UINT8 *\r
971Dhcp6SeekIaOption (\r
972 IN UINT8 *Buf,\r
973 IN UINT32 SeekLen,\r
974 IN EFI_DHCP6_IA_DESCRIPTOR *IaDesc\r
975 )\r
976{\r
977 UINT8 *Cursor;\r
978 UINT8 *Option;\r
979 UINT16 DataLen;\r
980 UINT16 OpCode;\r
981 UINT32 IaId;\r
982\r
983 //\r
984 // The format of IA_NA and IA_TA option refers to Dhcp6AppendIaOption().\r
985 //\r
986 Option = NULL;\r
987 Cursor = Buf;\r
988\r
989 while (Cursor < Buf + SeekLen) {\r
990 OpCode = ReadUnaligned16 ((UINT16 *) Cursor);\r
991 IaId = ReadUnaligned32 ((UINT32 *) (Cursor + 4));\r
992 if (OpCode == HTONS (IaDesc->Type) && IaId == HTONL (IaDesc->IaId)) {\r
993 Option = Cursor;\r
994 break;\r
995 }\r
996 DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));\r
997 Cursor += (DataLen + 4);\r
998 }\r
999\r
1000 return Option;\r
1001}\r
1002\r
685e44a5 1003/**\r
1004 Check whether the incoming IPv6 address in IaAddr is one of the maintained \r
1005 addresses in the IA control blcok.\r
1006\r
1007 @param[in] IaAddr The pointer to the IA Address to be checked.\r
1008 @param[in] CurrentIa The pointer to the IA in IA control block.\r
1009\r
1010 @retval TRUE Yes, this Address is already in IA control block.\r
1011 @retval FALSE No, this Address is NOT in IA control block.\r
1012\r
1013**/\r
1014BOOLEAN\r
1015Dhcp6AddrIsInCurrentIa (\r
1016 IN EFI_DHCP6_IA_ADDRESS *IaAddr,\r
1017 IN EFI_DHCP6_IA *CurrentIa\r
1018 )\r
1019{\r
1020 UINT32 Index;\r
1021\r
1022 ASSERT (IaAddr != NULL && CurrentIa != NULL);\r
1023 \r
1024 for (Index = 0; Index < CurrentIa->IaAddressCount; Index++) {\r
1025 if (EFI_IP6_EQUAL(&IaAddr->IpAddress, &CurrentIa->IaAddress[Index].IpAddress)) {\r
1026 return TRUE;\r
1027 }\r
1028 }\r
1029 return FALSE;\r
1030}\r
a3bcde70
HT
1031\r
1032/**\r
1033 Parse the address option and update the address infomation.\r
1034\r
685e44a5 1035 @param[in] CurrentIa The pointer to the Ia Address in control blcok.\r
a3bcde70
HT
1036 @param[in] IaInnerOpt The pointer to the buffer.\r
1037 @param[in] IaInnerLen The length to parse.\r
1038 @param[out] AddrNum The number of addresses.\r
1039 @param[in, out] AddrBuf The pointer to the address buffer.\r
1040\r
1041**/\r
1042VOID\r
1043Dhcp6ParseAddrOption (\r
685e44a5 1044 IN EFI_DHCP6_IA *CurrentIa,\r
a3bcde70
HT
1045 IN UINT8 *IaInnerOpt,\r
1046 IN UINT16 IaInnerLen,\r
1047 OUT UINT32 *AddrNum,\r
1048 IN OUT EFI_DHCP6_IA_ADDRESS *AddrBuf\r
1049 )\r
1050{\r
1051 UINT8 *Cursor;\r
1052 UINT16 DataLen;\r
1053 UINT16 OpCode;\r
1054 UINT32 ValidLt;\r
685e44a5 1055 UINT32 PreferredLt;\r
1056 EFI_DHCP6_IA_ADDRESS *IaAddr;\r
a3bcde70
HT
1057\r
1058 //\r
1059 // The format of the IA Address option:\r
1060 //\r
1061 // 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
1062 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
1063 // | OPTION_IAADDR | option-len |\r
1064 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
1065 // | |\r
1066 // | IPv6 address |\r
1067 // | |\r
1068 // | |\r
1069 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
1070 // | preferred-lifetime |\r
1071 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
1072 // | valid-lifetime |\r
1073 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
1074 // . .\r
1075 // . IAaddr-options .\r
1076 // . .\r
1077 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
1078 //\r
1079\r
1080 //\r
1081 // Two usage model:\r
1082 //\r
1083 // 1. Pass addrbuf == null, to get the addrnum over the Ia inner options.\r
1084 // 2. Pass addrbuf != null, to resolve the addresses over the Ia inner\r
1085 // options to the addrbuf.\r
1086 //\r
1087\r
1088 Cursor = IaInnerOpt;\r
1089 *AddrNum = 0;\r
1090\r
1091 while (Cursor < IaInnerOpt + IaInnerLen) {\r
1092 //\r
685e44a5 1093 // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option\r
1094 // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time.\r
a3bcde70
HT
1095 //\r
1096 OpCode = ReadUnaligned16 ((UINT16 *) Cursor);\r
685e44a5 1097 PreferredLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 20)));\r
1098 ValidLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 24)));\r
1099 IaAddr = (EFI_DHCP6_IA_ADDRESS *) (Cursor + 4);\r
1100 if (OpCode == HTONS (Dhcp6OptIaAddr) && ValidLt >= PreferredLt &&\r
1101 (Dhcp6AddrIsInCurrentIa(IaAddr, CurrentIa) || ValidLt !=0)) {\r
a3bcde70 1102 if (AddrBuf != NULL) {\r
685e44a5 1103 CopyMem (AddrBuf, IaAddr, sizeof (EFI_DHCP6_IA_ADDRESS));\r
1104 AddrBuf->PreferredLifetime = PreferredLt;\r
1105 AddrBuf->ValidLifetime = ValidLt;\r
a3bcde70
HT
1106 AddrBuf = (EFI_DHCP6_IA_ADDRESS *) ((UINT8 *) AddrBuf + sizeof (EFI_DHCP6_IA_ADDRESS));\r
1107 }\r
a3bcde70
HT
1108 (*AddrNum)++;\r
1109 }\r
1110 DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));\r
1111 Cursor += (DataLen + 4);\r
1112 }\r
1113}\r
1114\r
1115\r
1116/**\r
1117 Create a control blcok for the Ia according to the corresponding options.\r
1118\r
1119 @param[in] Instance The pointer to DHCP6 Instance.\r
1120 @param[in] IaInnerOpt The pointer to the inner options in the Ia option.\r
1121 @param[in] IaInnerLen The length of all the inner options in the Ia option.\r
1122 @param[in] T1 T1 time in the Ia option.\r
1123 @param[in] T2 T2 time in the Ia option.\r
1124\r
1125 @retval EFI_NOT_FOUND No valid IA option is found.\r
1126 @retval EFI_SUCCESS Create an IA control block successfully.\r
1127 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
685e44a5 1128 @retval EFI_DEVICE_ERROR An unexpected error.\r
a3bcde70
HT
1129\r
1130**/\r
1131EFI_STATUS\r
1132Dhcp6GenerateIaCb (\r
1133 IN DHCP6_INSTANCE *Instance,\r
1134 IN UINT8 *IaInnerOpt,\r
1135 IN UINT16 IaInnerLen,\r
1136 IN UINT32 T1,\r
1137 IN UINT32 T2\r
1138 )\r
1139{\r
1140 UINT32 AddrNum;\r
1141 UINT32 IaSize;\r
1142 EFI_DHCP6_IA *Ia;\r
1143\r
1144 if (Instance->IaCb.Ia == NULL) {\r
685e44a5 1145 return EFI_DEVICE_ERROR;\r
a3bcde70
HT
1146 }\r
1147\r
1148 //\r
1149 // Calculate the number of addresses for this Ia, excluding the addresses with\r
1150 // the value 0 of valid lifetime.\r
1151 //\r
685e44a5 1152 Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, NULL);\r
a3bcde70
HT
1153\r
1154 if (AddrNum == 0) {\r
1155 return EFI_NOT_FOUND;\r
1156 }\r
1157\r
1158 //\r
1159 // Allocate for new IA.\r
1160 //\r
1161 IaSize = sizeof (EFI_DHCP6_IA) + (AddrNum - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r
1162 Ia = AllocateZeroPool (IaSize);\r
1163\r
1164 if (Ia == NULL) {\r
1165 return EFI_OUT_OF_RESOURCES;\r
1166 }\r
1167\r
1168 //\r
1169 // Fill up this new IA fields.\r
1170 //\r
1171 Ia->State = Instance->IaCb.Ia->State;\r
1172 Ia->IaAddressCount = AddrNum;\r
1173 CopyMem (&Ia->Descriptor, &Instance->Config->IaDescriptor, sizeof (EFI_DHCP6_IA_DESCRIPTOR));\r
685e44a5 1174 Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress);\r
a3bcde70
HT
1175\r
1176 //\r
1177 // Free original IA resource.\r
1178 //\r
1179 if (Instance->IaCb.Ia->ReplyPacket != NULL) {\r
1180 FreePool (Instance->IaCb.Ia->ReplyPacket);\r
1181 }\r
1182 FreePool (Instance->IaCb.Ia);\r
1183\r
1184\r
1185 ZeroMem (&Instance->IaCb, sizeof (DHCP6_IA_CB));\r
1186\r
1187 //\r
1188 // Update IaCb to use new IA.\r
1189 //\r
1190 Instance->IaCb.Ia = Ia;\r
1191\r
1192 //\r
1193\r
1194 // Fill in IaCb fields. Such as T1, T2, AllExpireTime and LeaseTime.\r
1195 //\r
1196 Instance->IaCb.T1 = T1;\r
1197 Instance->IaCb.T2 = T2;\r
1198 Dhcp6CalculateLeaseTime (&Instance->IaCb);\r
1199\r
1200 return EFI_SUCCESS;\r
1201}\r
1202\r
1203\r
1204/**\r
1205 Cache the current IA configuration information.\r
1206\r
1207 @param[in] Instance The pointer to DHCP6 Instance.\r
1208\r
1209 @retval EFI_SUCCESS Cache the current IA successfully.\r
1210 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1211\r
1212**/\r
1213EFI_STATUS\r
1214Dhcp6CacheIa (\r
1215 IN DHCP6_INSTANCE *Instance\r
1216 )\r
1217{\r
1218 UINTN IaSize;\r
1219 EFI_DHCP6_IA *Ia;\r
1220\r
1221 Ia = Instance->IaCb.Ia;\r
1222\r
1223 if ((Instance->CacheIa == NULL) && (Ia != NULL)) {\r
1224 //\r
1225 // Cache the current IA.\r
1226 //\r
1227 IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r
1228\r
1229 Instance->CacheIa = AllocateZeroPool (IaSize);\r
1230 if (Instance->CacheIa == NULL) {\r
1231 return EFI_OUT_OF_RESOURCES;\r
1232 }\r
1233 CopyMem (Instance->CacheIa, Ia, IaSize);\r
1234 }\r
1235 return EFI_SUCCESS;\r
1236}\r
1237\r
1238/**\r
1239 Append CacheIa to the currrent IA. Meanwhile, clear CacheIa.ValidLifetime to 0.\r
1240\r
1241 @param[in] Instance The pointer to DHCP6 instance.\r
1242\r
1243**/\r
1244VOID\r
1245Dhcp6AppendCacheIa (\r
1246 IN DHCP6_INSTANCE *Instance\r
1247 )\r
1248{\r
1249 UINT8 *Ptr;\r
1250 UINTN Index;\r
1251 UINTN IaSize;\r
1252 UINTN NewIaSize;\r
1253 EFI_DHCP6_IA *Ia;\r
1254 EFI_DHCP6_IA *NewIa;\r
1255 EFI_DHCP6_IA *CacheIa;\r
1256\r
1257 Ia = Instance->IaCb.Ia;\r
1258 CacheIa = Instance->CacheIa;\r
1259\r
1260 if ((CacheIa != NULL) && (CacheIa->IaAddressCount != 0)) {\r
1261 //\r
1262 // There are old addresses existing. Merge with current addresses.\r
1263 //\r
1264 NewIaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount + CacheIa->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r
1265 NewIa = AllocateZeroPool (NewIaSize);\r
1266 if (NewIa == NULL) {\r
1267 return;\r
1268 }\r
1269\r
1270 IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS);\r
1271 CopyMem (NewIa, Ia, IaSize);\r
1272\r
1273 //\r
1274 // Clear old address.ValidLifetime\r
1275 //\r
1276 for (Index = 0; Index < CacheIa->IaAddressCount; Index++) {\r
1277 CacheIa->IaAddress[Index].ValidLifetime = 0;\r
1278 }\r
1279\r
1280 NewIa->IaAddressCount += CacheIa->IaAddressCount;\r
1281 Ptr = (UINT8*)&NewIa->IaAddress[Ia->IaAddressCount];\r
1282 CopyMem (Ptr, CacheIa->IaAddress, CacheIa->IaAddressCount * sizeof (EFI_DHCP6_IA_ADDRESS));\r
1283\r
1284 //\r
1285 // Migrate to the NewIa and free previous.\r
1286 //\r
1287 FreePool (Instance->CacheIa);\r
1288 FreePool (Instance->IaCb.Ia);\r
1289 Instance->CacheIa = NULL;\r
1290 Instance->IaCb.Ia = NewIa;\r
1291 }\r
1292}\r
cc658224 1293\r
1294/**\r
1295 Calculate the Dhcp6 get mapping timeout by adding additinal delay to the IP6 DAD transmits count.\r
1296\r
1297 @param[in] Ip6Cfg The pointer to Ip6 config protocol.\r
1298 @param[out] TimeOut The time out value in 100ns units.\r
1299\r
1300 @retval EFI_INVALID_PARAMETER Input parameters are invalid.\r
1301 @retval EFI_SUCCESS Calculate the time out value successfully.\r
1302**/\r
1303EFI_STATUS\r
1304Dhcp6GetMappingTimeOut (\r
1305 IN EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg,\r
1306 OUT UINTN *TimeOut\r
1307 ) \r
1308{\r
1309 EFI_STATUS Status;\r
1310 UINTN DataSize;\r
1311 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;\r
1312\r
1313 if (Ip6Cfg == NULL || TimeOut == NULL) {\r
1314 return EFI_INVALID_PARAMETER;\r
1315 }\r
1316\r
1317 DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);\r
1318 Status = Ip6Cfg->GetData (\r
1319 Ip6Cfg,\r
1320 Ip6ConfigDataTypeDupAddrDetectTransmits,\r
1321 &DataSize,\r
1322 &DadXmits\r
1323 );\r
1324 if (EFI_ERROR (Status)) {\r
1325 return Status;\r
1326 }\r
1327 \r
1328 *TimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + DHCP6_DAD_ADDITIONAL_DELAY;\r
1329 \r
1330 return EFI_SUCCESS;\r
1331}\r