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