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