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