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