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