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