| /** @file | |
| Dhcp6 support functions implementation. | |
| (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR> | |
| Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php. | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "Dhcp6Impl.h" | |
| /** | |
| Generate client Duid in the format of Duid-llt. | |
| @param[in] Mode The pointer to the mode of SNP. | |
| @retval NULL If it failed to generate a client Id. | |
| @retval others The pointer to the new client id. | |
| **/ | |
| EFI_DHCP6_DUID * | |
| Dhcp6GenerateClientId ( | |
| IN EFI_SIMPLE_NETWORK_MODE *Mode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_DHCP6_DUID *Duid; | |
| EFI_TIME Time; | |
| UINT32 Stamp; | |
| EFI_GUID Uuid; | |
| // | |
| // Attempt to get client Id from variable to keep it constant. | |
| // See details in section-9 of rfc-3315. | |
| // | |
| GetVariable2 (L"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid, (VOID**)&Duid, NULL); | |
| if (Duid != NULL) { | |
| return Duid; | |
| } | |
| // | |
| // The format of client identifier option: | |
| // | |
| // 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 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | OPTION_CLIENTID | option-len | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // . . | |
| // . DUID . | |
| // . (variable length) . | |
| // . . | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | |
| // | |
| // If System UUID is found from SMBIOS Table, use DUID-UUID type. | |
| // | |
| if ((PcdGet8 (PcdDhcp6UidType) == Dhcp6DuidTypeUuid) && !EFI_ERROR (NetLibGetSystemGuid (&Uuid))) { | |
| // | |
| // | |
| // The format of DUID-UUID: | |
| // | |
| // 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 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | DUID-Type (4) | UUID (128 bits) | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | |
| // | | | |
| // | | | |
| // | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- | |
| // | |
| // sizeof (option-len + Duid-type + UUID-size) = 20 bytes | |
| // | |
| Duid = AllocateZeroPool (2 + 2 + sizeof (EFI_GUID)); | |
| if (Duid == NULL) { | |
| return NULL; | |
| } | |
| // | |
| // sizeof (Duid-type + UUID-size) = 18 bytes | |
| // | |
| Duid->Length = (UINT16) (18); | |
| // | |
| // Set the Duid-type and copy UUID. | |
| // | |
| WriteUnaligned16 ((UINT16 *) (Duid->Duid), HTONS (Dhcp6DuidTypeUuid)); | |
| CopyMem (Duid->Duid + 2, &Uuid, sizeof(EFI_GUID)); | |
| } else { | |
| // | |
| // | |
| // The format of DUID-LLT: | |
| // | |
| // 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 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | Duid type (1) | hardware type (16 bits) | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | time (32 bits) | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // . . | |
| // . link-layer address (variable length) . | |
| // . . | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | |
| // | |
| // Generate a time stamp of the seconds from 2000/1/1, assume 30day/month. | |
| // | |
| gRT->GetTime (&Time, NULL); | |
| Stamp = (UINT32) | |
| ( | |
| (((((Time.Year - 2000) * 360 + (Time.Month - 1)) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) * | |
| 60 + | |
| Time.Second | |
| ); | |
| // | |
| // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes | |
| // | |
| Duid = AllocateZeroPool (10 + Mode->HwAddressSize); | |
| if (Duid == NULL) { | |
| return NULL; | |
| } | |
| // | |
| // sizeof (Duid-type + hardware-type + time) = 8 bytes | |
| // | |
| Duid->Length = (UINT16) (Mode->HwAddressSize + 8); | |
| // | |
| // Set the Duid-type, hardware-type, time and copy the hardware address. | |
| // | |
| WriteUnaligned16 ((UINT16 *) ((UINT8 *) Duid + OFFSET_OF (EFI_DHCP6_DUID, Duid)), HTONS (Dhcp6DuidTypeLlt)); | |
| WriteUnaligned16 ((UINT16 *) ((UINT8 *) Duid + OFFSET_OF (EFI_DHCP6_DUID, Duid) + 2), HTONS (NET_IFTYPE_ETHERNET)); | |
| WriteUnaligned32 ((UINT32 *) ((UINT8 *) Duid + OFFSET_OF (EFI_DHCP6_DUID, Duid) + 4), HTONL (Stamp)); | |
| CopyMem (Duid->Duid + 8, &Mode->CurrentAddress, Mode->HwAddressSize); | |
| } | |
| Status = gRT->SetVariable ( | |
| L"ClientId", | |
| &gEfiDhcp6ServiceBindingProtocolGuid, | |
| (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS), | |
| Duid->Length + 2, | |
| (VOID *) Duid | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| FreePool (Duid); | |
| return NULL; | |
| } | |
| return Duid; | |
| } | |
| /** | |
| Copy the Dhcp6 configure data. | |
| @param[in] DstCfg The pointer to the destination configure data. | |
| @param[in] SorCfg The pointer to the source configure data. | |
| @retval EFI_SUCCESS Copy the content from SorCfg from DstCfg successfully. | |
| @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. | |
| **/ | |
| EFI_STATUS | |
| Dhcp6CopyConfigData ( | |
| IN EFI_DHCP6_CONFIG_DATA *DstCfg, | |
| IN EFI_DHCP6_CONFIG_DATA *SorCfg | |
| ) | |
| { | |
| UINTN Index; | |
| UINTN OptionListSize; | |
| UINTN OptionSize; | |
| CopyMem (DstCfg, SorCfg, sizeof (EFI_DHCP6_CONFIG_DATA)); | |
| // | |
| // Allocate another buffer for solicitretransmission, and copy it. | |
| // | |
| if (SorCfg->SolicitRetransmission != NULL) { | |
| DstCfg->SolicitRetransmission = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION)); | |
| if (DstCfg->SolicitRetransmission == NULL) { | |
| // | |
| // Error will be handled out of this function. | |
| // | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| CopyMem ( | |
| DstCfg->SolicitRetransmission, | |
| SorCfg->SolicitRetransmission, | |
| sizeof (EFI_DHCP6_RETRANSMISSION) | |
| ); | |
| } | |
| if (SorCfg->OptionList != NULL && SorCfg->OptionCount != 0) { | |
| OptionListSize = SorCfg->OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *); | |
| DstCfg->OptionList = AllocateZeroPool (OptionListSize); | |
| if (DstCfg->OptionList == NULL) { | |
| // | |
| // Error will be handled out of this function. | |
| // | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| for (Index = 0; Index < SorCfg->OptionCount; Index++) { | |
| OptionSize = NTOHS (SorCfg->OptionList[Index]->OpLen) + 4; | |
| DstCfg->OptionList[Index] = AllocateZeroPool (OptionSize); | |
| if (DstCfg->OptionList[Index] == NULL) { | |
| // | |
| // Error will be handled out of this function. | |
| // | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| CopyMem ( | |
| DstCfg->OptionList[Index], | |
| SorCfg->OptionList[Index], | |
| OptionSize | |
| ); | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Clean up the configure data. | |
| @param[in, out] CfgData The pointer to the configure data. | |
| **/ | |
| VOID | |
| Dhcp6CleanupConfigData ( | |
| IN OUT EFI_DHCP6_CONFIG_DATA *CfgData | |
| ) | |
| { | |
| UINTN Index; | |
| ASSERT (CfgData != NULL); | |
| // | |
| // Clean up all fields in config data including the reference buffers, but do | |
| // not free the config data buffer itself. | |
| // | |
| if (CfgData->OptionList != NULL) { | |
| for (Index = 0; Index < CfgData->OptionCount; Index++) { | |
| if (CfgData->OptionList[Index] != NULL) { | |
| FreePool (CfgData->OptionList[Index]); | |
| } | |
| } | |
| FreePool (CfgData->OptionList); | |
| } | |
| if (CfgData->SolicitRetransmission != NULL) { | |
| FreePool (CfgData->SolicitRetransmission); | |
| } | |
| ZeroMem (CfgData, sizeof (EFI_DHCP6_CONFIG_DATA)); | |
| } | |
| /** | |
| Clean up the mode data. | |
| @param[in, out] ModeData The pointer to the mode data. | |
| **/ | |
| VOID | |
| Dhcp6CleanupModeData ( | |
| IN OUT EFI_DHCP6_MODE_DATA *ModeData | |
| ) | |
| { | |
| ASSERT (ModeData != NULL); | |
| // | |
| // Clean up all fields in mode data including the reference buffers, but do | |
| // not free the mode data buffer itself. | |
| // | |
| if (ModeData->ClientId != NULL) { | |
| FreePool (ModeData->ClientId); | |
| } | |
| if (ModeData->Ia != NULL) { | |
| if (ModeData->Ia->ReplyPacket != NULL) { | |
| FreePool (ModeData->Ia->ReplyPacket); | |
| } | |
| FreePool (ModeData->Ia); | |
| } | |
| ZeroMem (ModeData, sizeof (EFI_DHCP6_MODE_DATA)); | |
| } | |
| /** | |
| Calculate the expire time by the algorithm defined in rfc. | |
| @param[in] Base The base value of the time. | |
| @param[in] IsFirstRt If TRUE, it is the first time to calculate expire time. | |
| @param[in] NeedSigned If TRUE, the the signed factor is needed. | |
| @return Expire The calculated result for the new expire time. | |
| **/ | |
| UINT32 | |
| Dhcp6CalculateExpireTime ( | |
| IN UINT32 Base, | |
| IN BOOLEAN IsFirstRt, | |
| IN BOOLEAN NeedSigned | |
| ) | |
| { | |
| EFI_TIME Time; | |
| BOOLEAN Signed; | |
| UINT32 Seed; | |
| UINT32 Expire; | |
| // | |
| // Take the 10bits of microsecond in system time as a uniform distribution. | |
| // Take the 10th bit as a flag to determine it's signed or not. | |
| // | |
| gRT->GetTime (&Time, NULL); | |
| Seed = ((Time.Nanosecond >> 10) & DHCP6_10_BIT_MASK); | |
| Signed = (BOOLEAN) ((((Time.Nanosecond >> 9) & 0x01) != 0) ? TRUE : FALSE); | |
| Signed = (BOOLEAN) (NeedSigned ? Signed : FALSE); | |
| // | |
| // Calculate expire by the following algo: | |
| // 1. base + base * (-0.1 ~ 0) for the first solicit | |
| // 2. base + base * (-0.1 ~ 0.1) for the first other messages | |
| // 3. 2 * base + base * (-0.1 ~ 0.1) for the subsequent all messages | |
| // 4. base + base * (-0.1 ~ 0) for the more than mrt timeout | |
| // | |
| // The (Seed / 0x3ff / 10) is used to a random range (0, 0.1). | |
| // | |
| if (IsFirstRt && Signed) { | |
| Expire = Base - (UINT32) (Base * Seed / DHCP6_10_BIT_MASK / 10); | |
| } else if (IsFirstRt && !Signed) { | |
| Expire = Base + (UINT32) (Base * Seed / DHCP6_10_BIT_MASK / 10); | |
| } else if (!IsFirstRt && Signed) { | |
| Expire = 2 * Base - (UINT32) (Base * Seed / DHCP6_10_BIT_MASK / 10); | |
| } else { | |
| Expire = 2 * Base + (UINT32) (Base * Seed / DHCP6_10_BIT_MASK / 10); | |
| } | |
| Expire = (Expire != 0) ? Expire : 1; | |
| return Expire; | |
| } | |
| /** | |
| Calculate the lease time by the algorithm defined in rfc. | |
| @param[in] IaCb The pointer to the Ia control block. | |
| **/ | |
| VOID | |
| Dhcp6CalculateLeaseTime ( | |
| IN DHCP6_IA_CB *IaCb | |
| ) | |
| { | |
| UINT32 MinLt; | |
| UINT32 MaxLt; | |
| UINTN Index; | |
| ASSERT (IaCb->Ia->IaAddressCount > 0); | |
| MinLt = (UINT32) (-1); | |
| MaxLt = 0; | |
| // | |
| // Calculate minlt as min of all valid life time, and maxlt as max of all | |
| // valid life time. | |
| // | |
| for (Index = 0; Index < IaCb->Ia->IaAddressCount; Index++) { | |
| MinLt = MIN (MinLt, IaCb->Ia->IaAddress[Index].ValidLifetime); | |
| MaxLt = MAX (MinLt, IaCb->Ia->IaAddress[Index].ValidLifetime); | |
| } | |
| // | |
| // Take 50% minlt as t1, and 80% maxlt as t2 if Dhcp6 server doesn't offer | |
| // such information. | |
| // | |
| IaCb->T1 = (IaCb->T1 != 0) ? IaCb->T1 : (UINT32)(MinLt * 5 / 10); | |
| IaCb->T2 = (IaCb->T2 != 0) ? IaCb->T2 : (UINT32)(MinLt * 8 / 10); | |
| IaCb->AllExpireTime = MaxLt; | |
| IaCb->LeaseTime = 0; | |
| } | |
| /** | |
| Check whether the addresses are all included by the configured Ia. | |
| @param[in] Ia The pointer to the Ia. | |
| @param[in] AddressCount The number of addresses. | |
| @param[in] Addresses The pointer to the addresses buffer. | |
| @retval EFI_SUCCESS The addresses are all included by the configured IA. | |
| @retval EFI_NOT_FOUND The addresses are not included by the configured IA. | |
| **/ | |
| EFI_STATUS | |
| Dhcp6CheckAddress ( | |
| IN EFI_DHCP6_IA *Ia, | |
| IN UINT32 AddressCount, | |
| IN EFI_IPv6_ADDRESS *Addresses | |
| ) | |
| { | |
| UINTN Index1; | |
| UINTN Index2; | |
| BOOLEAN Found; | |
| // | |
| // Check whether the addresses are all included by the configured IA. And it | |
| // will return success if address count is zero, which means all addresses. | |
| // | |
| for (Index1 = 0; Index1 < AddressCount; Index1++) { | |
| Found = FALSE; | |
| for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) { | |
| if (CompareMem ( | |
| &Addresses[Index1], | |
| &Ia->IaAddress[Index2], | |
| sizeof (EFI_IPv6_ADDRESS) | |
| ) == 0) { | |
| Found = TRUE; | |
| break; | |
| } | |
| } | |
| if (!Found) { | |
| return EFI_NOT_FOUND; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Deprive the addresses from current Ia, and generate another eliminated Ia. | |
| @param[in] Ia The pointer to the Ia. | |
| @param[in] AddressCount The number of addresses. | |
| @param[in] Addresses The pointer to the addresses buffer. | |
| @retval NULL If it failed to generate the deprived Ia. | |
| @retval others The pointer to the deprived Ia. | |
| **/ | |
| EFI_DHCP6_IA * | |
| Dhcp6DepriveAddress ( | |
| IN EFI_DHCP6_IA *Ia, | |
| IN UINT32 AddressCount, | |
| IN EFI_IPv6_ADDRESS *Addresses | |
| ) | |
| { | |
| EFI_DHCP6_IA *IaCopy; | |
| UINTN IaCopySize; | |
| UINTN Index1; | |
| UINTN Index2; | |
| BOOLEAN Found; | |
| if (AddressCount == 0) { | |
| // | |
| // It means release all Ia addresses if address count is zero. | |
| // | |
| AddressCount = Ia->IaAddressCount; | |
| } | |
| ASSERT (AddressCount != 0); | |
| IaCopySize = sizeof (EFI_DHCP6_IA) + (AddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS); | |
| IaCopy = AllocateZeroPool (IaCopySize); | |
| if (IaCopy == NULL) { | |
| return NULL; | |
| } | |
| if (AddressCount == Ia->IaAddressCount) { | |
| // | |
| // If release all Ia addresses, just copy the configured Ia and then set | |
| // its address count as zero. | |
| // We may decline/release part of addresses at the begining. So it's a | |
| // forwarding step to update address infor for decline/release, while the | |
| // other infor such as Ia state will be updated when receiving reply. | |
| // | |
| CopyMem (IaCopy, Ia, IaCopySize); | |
| Ia->IaAddressCount = 0; | |
| return IaCopy; | |
| } | |
| CopyMem (IaCopy, Ia, sizeof (EFI_DHCP6_IA)); | |
| // | |
| // Move the addresses from the Ia of instance to the deprived Ia. | |
| // | |
| for (Index1 = 0; Index1 < AddressCount; Index1++) { | |
| Found = FALSE; | |
| for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) { | |
| if (CompareMem ( | |
| &Addresses[Index1], | |
| &Ia->IaAddress[Index2], | |
| sizeof (EFI_IPv6_ADDRESS) | |
| ) == 0) { | |
| // | |
| // Copy the deprived address to the copy of Ia | |
| // | |
| CopyMem ( | |
| &IaCopy->IaAddress[Index1], | |
| &Ia->IaAddress[Index2], | |
| sizeof (EFI_DHCP6_IA_ADDRESS) | |
| ); | |
| // | |
| // Delete the deprived address from the instance Ia | |
| // | |
| if (Index2 + 1 < Ia->IaAddressCount) { | |
| CopyMem ( | |
| &Ia->IaAddress[Index2], | |
| &Ia->IaAddress[Index2 + 1], | |
| (Ia->IaAddressCount - Index2 - 1) * sizeof (EFI_DHCP6_IA_ADDRESS) | |
| ); | |
| } | |
| Found = TRUE; | |
| break; | |
| } | |
| } | |
| ASSERT (Found == TRUE); | |
| } | |
| Ia->IaAddressCount -= AddressCount; | |
| IaCopy->IaAddressCount = AddressCount; | |
| return IaCopy; | |
| } | |
| /** | |
| The dummy ext buffer free callback routine. | |
| @param[in] Arg The pointer to the parameter. | |
| **/ | |
| VOID | |
| EFIAPI | |
| Dhcp6DummyExtFree ( | |
| IN VOID *Arg | |
| ) | |
| { | |
| } | |
| /** | |
| The callback routine once message transmitted. | |
| @param[in] Wrap The pointer to the received net buffer. | |
| @param[in] EndPoint The pointer to the udp end point. | |
| @param[in] IoStatus The return status from udp io. | |
| @param[in] Context The opaque parameter to the function. | |
| **/ | |
| VOID | |
| EFIAPI | |
| Dhcp6OnTransmitted ( | |
| IN NET_BUF *Wrap, | |
| IN UDP_END_POINT *EndPoint, | |
| IN EFI_STATUS IoStatus, | |
| IN VOID *Context | |
| ) | |
| { | |
| NetbufFree (Wrap); | |
| } | |
| /** | |
| Append the option to Buf, and move Buf to the end. | |
| @param[in, out] Buf The pointer to the buffer. | |
| @param[in] OptType The option type. | |
| @param[in] OptLen The length of option contents. | |
| @param[in] Data The pointer to the option content. | |
| @return Buf The position to append the next option. | |
| **/ | |
| UINT8 * | |
| Dhcp6AppendOption ( | |
| IN OUT UINT8 *Buf, | |
| IN UINT16 OptType, | |
| IN UINT16 OptLen, | |
| IN UINT8 *Data | |
| ) | |
| { | |
| // | |
| // The format of Dhcp6 option: | |
| // | |
| // 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 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | option-code | option-len (option data) | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | option-data | | |
| // | (option-len octets) | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | |
| ASSERT (OptLen != 0); | |
| WriteUnaligned16 ((UINT16 *) Buf, OptType); | |
| Buf += 2; | |
| WriteUnaligned16 ((UINT16 *) Buf, OptLen); | |
| Buf += 2; | |
| CopyMem (Buf, Data, NTOHS (OptLen)); | |
| Buf += NTOHS (OptLen); | |
| return Buf; | |
| } | |
| /** | |
| Append the appointed IA Address option to Buf, and move Buf to the end. | |
| @param[in, out] Buf The pointer to the position to append. | |
| @param[in] IaAddr The pointer to the IA Address. | |
| @param[in] MessageType Message type of DHCP6 package. | |
| @return Buf The position to append the next option. | |
| **/ | |
| UINT8 * | |
| Dhcp6AppendIaAddrOption ( | |
| IN OUT UINT8 *Buf, | |
| IN EFI_DHCP6_IA_ADDRESS *IaAddr, | |
| IN UINT32 MessageType | |
| ) | |
| { | |
| // The format of the IA Address option is: | |
| // | |
| // 0 1 2 3 | |
| // 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 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | OPTION_IAADDR | option-len | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | | | |
| // | IPv6 address | | |
| // | | | |
| // | | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | preferred-lifetime | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | valid-lifetime | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // . . | |
| // . IAaddr-options . | |
| // . . | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | |
| // Fill the value of Ia Address option type | |
| // | |
| WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptIaAddr)); | |
| Buf += 2; | |
| WriteUnaligned16 ((UINT16 *) Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS))); | |
| Buf += 2; | |
| CopyMem (Buf, &IaAddr->IpAddress, sizeof(EFI_IPv6_ADDRESS)); | |
| Buf += sizeof(EFI_IPv6_ADDRESS); | |
| // | |
| // Fill the value of preferred-lifetime and valid-lifetime. | |
| // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields | |
| // should set to 0 when initiate a Confirm message. | |
| // | |
| if (MessageType != Dhcp6MsgConfirm) { | |
| WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->PreferredLifetime)); | |
| } | |
| Buf += 4; | |
| if (MessageType != Dhcp6MsgConfirm) { | |
| WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->ValidLifetime)); | |
| } | |
| Buf += 4; | |
| return Buf; | |
| } | |
| /** | |
| Append the appointed Ia option to Buf, and move Buf to the end. | |
| @param[in, out] Buf The pointer to the position to append. | |
| @param[in] Ia The pointer to the Ia. | |
| @param[in] T1 The time of T1. | |
| @param[in] T2 The time of T2. | |
| @param[in] MessageType Message type of DHCP6 package. | |
| @return Buf The position to append the next Ia option. | |
| **/ | |
| UINT8 * | |
| Dhcp6AppendIaOption ( | |
| IN OUT UINT8 *Buf, | |
| IN EFI_DHCP6_IA *Ia, | |
| IN UINT32 T1, | |
| IN UINT32 T2, | |
| IN UINT32 MessageType | |
| ) | |
| { | |
| UINT8 *AddrOpt; | |
| UINT16 *Len; | |
| UINTN Index; | |
| // | |
| // The format of IA_NA and IA_TA option: | |
| // | |
| // 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 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | OPTION_IA_NA | option-len | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | IAID (4 octets) | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | T1 (only for IA_NA) | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | T2 (only for IA_NA) | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | | | |
| // . IA_NA-options/IA_TA-options . | |
| // . . | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | |
| // | |
| // Fill the value of Ia option type | |
| // | |
| WriteUnaligned16 ((UINT16 *) Buf, HTONS (Ia->Descriptor.Type)); | |
| Buf += 2; | |
| // | |
| // Fill the len of Ia option later, keep the pointer first | |
| // | |
| Len = (UINT16 *) Buf; | |
| Buf += 2; | |
| // | |
| // Fill the value of iaid | |
| // | |
| WriteUnaligned32 ((UINT32 *) Buf, HTONL (Ia->Descriptor.IaId)); | |
| Buf += 4; | |
| // | |
| // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified. | |
| // | |
| if (Ia->Descriptor.Type == Dhcp6OptIana) { | |
| WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff)); | |
| Buf += 4; | |
| WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff)); | |
| Buf += 4; | |
| } | |
| // | |
| // Fill all the addresses belong to the Ia | |
| // | |
| for (Index = 0; Index < Ia->IaAddressCount; Index++) { | |
| AddrOpt = (UINT8 *) Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS); | |
| Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *) AddrOpt, MessageType); | |
| } | |
| // | |
| // Fill the value of Ia option length | |
| // | |
| *Len = HTONS ((UINT16) (Buf - (UINT8 *) Len - 2)); | |
| return Buf; | |
| } | |
| /** | |
| Append the appointed Elapsed time option to Buf, and move Buf to the end. | |
| @param[in, out] Buf The pointer to the position to append. | |
| @param[in] Instance The pointer to the Dhcp6 instance. | |
| @param[out] Elapsed The pointer to the elapsed time value in | |
| the generated packet. | |
| @return Buf The position to append the next Ia option. | |
| **/ | |
| UINT8 * | |
| Dhcp6AppendETOption ( | |
| IN OUT UINT8 *Buf, | |
| IN DHCP6_INSTANCE *Instance, | |
| OUT UINT16 **Elapsed | |
| ) | |
| { | |
| // | |
| // The format of elapsed time option: | |
| // | |
| // 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 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | OPTION_ELAPSED_TIME | option-len | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | elapsed-time | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | |
| // | |
| // Fill the value of elapsed-time option type. | |
| // | |
| WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptElapsedTime)); | |
| Buf += 2; | |
| // | |
| // Fill the len of elapsed-time option, which is fixed. | |
| // | |
| WriteUnaligned16 ((UINT16 *) Buf, HTONS(2)); | |
| Buf += 2; | |
| // | |
| // Fill in elapsed time value with 0 value for now. The actual value is | |
| // filled in later just before the packet is transmitted. | |
| // | |
| WriteUnaligned16 ((UINT16 *) Buf, HTONS(0)); | |
| *Elapsed = (UINT16 *) Buf; | |
| Buf += 2; | |
| return Buf; | |
| } | |
| /** | |
| Set the elapsed time based on the given instance and the pointer to the | |
| elapsed time option. | |
| @param[in] Elapsed The pointer to the position to append. | |
| @param[in] Instance The pointer to the Dhcp6 instance. | |
| **/ | |
| VOID | |
| SetElapsedTime ( | |
| IN UINT16 *Elapsed, | |
| IN DHCP6_INSTANCE *Instance | |
| ) | |
| { | |
| EFI_TIME Time; | |
| UINT64 CurrentStamp; | |
| UINT64 ElapsedTimeValue; | |
| // | |
| // Generate a time stamp of the centiseconds from 2000/1/1, assume 30day/month. | |
| // | |
| gRT->GetTime (&Time, NULL); | |
| CurrentStamp = (UINT64) | |
| ( | |
| ((((((Time.Year - 2000) * 360 + | |
| (Time.Month - 1)) * 30 + | |
| (Time.Day - 1)) * 24 + Time.Hour) * 60 + | |
| Time.Minute) * 60 + Time.Second) * 100 | |
| + DivU64x32(Time.Nanosecond, 10000000) | |
| ); | |
| // | |
| // Sentinel value of 0 means that this is the first DHCP packet that we are | |
| // sending and that we need to initialize the value. First DHCP message | |
| // gets 0 elapsed-time. Otherwise, calculate based on StartTime. | |
| // | |
| if (Instance->StartTime == 0) { | |
| ElapsedTimeValue = 0; | |
| Instance->StartTime = CurrentStamp; | |
| } else { | |
| ElapsedTimeValue = CurrentStamp - Instance->StartTime; | |
| // | |
| // If elapsed time cannot fit in two bytes, set it to 0xffff. | |
| // | |
| if (ElapsedTimeValue > 0xffff) { | |
| ElapsedTimeValue = 0xffff; | |
| } | |
| } | |
| WriteUnaligned16 (Elapsed, HTONS((UINT16) ElapsedTimeValue)); | |
| } | |
| /** | |
| Seek the address of the first byte of the option header. | |
| @param[in] Buf The pointer to the buffer. | |
| @param[in] SeekLen The length to seek. | |
| @param[in] OptType The option type. | |
| @retval NULL If it failed to seek the option. | |
| @retval others The position to the option. | |
| **/ | |
| UINT8 * | |
| Dhcp6SeekOption ( | |
| IN UINT8 *Buf, | |
| IN UINT32 SeekLen, | |
| IN UINT16 OptType | |
| ) | |
| { | |
| UINT8 *Cursor; | |
| UINT8 *Option; | |
| UINT16 DataLen; | |
| UINT16 OpCode; | |
| Option = NULL; | |
| Cursor = Buf; | |
| // | |
| // The format of Dhcp6 option refers to Dhcp6AppendOption(). | |
| // | |
| while (Cursor < Buf + SeekLen) { | |
| OpCode = ReadUnaligned16 ((UINT16 *) Cursor); | |
| if (OpCode == HTONS (OptType)) { | |
| Option = Cursor; | |
| break; | |
| } | |
| DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2))); | |
| Cursor += (DataLen + 4); | |
| } | |
| return Option; | |
| } | |
| /** | |
| Seek the address of the first byte of the Ia option header. | |
| @param[in] Buf The pointer to the buffer. | |
| @param[in] SeekLen The length to seek. | |
| @param[in] IaDesc The pointer to the Ia descriptor. | |
| @retval NULL If it failed to seek the Ia option. | |
| @retval others The position to the Ia option. | |
| **/ | |
| UINT8 * | |
| Dhcp6SeekIaOption ( | |
| IN UINT8 *Buf, | |
| IN UINT32 SeekLen, | |
| IN EFI_DHCP6_IA_DESCRIPTOR *IaDesc | |
| ) | |
| { | |
| UINT8 *Cursor; | |
| UINT8 *Option; | |
| UINT16 DataLen; | |
| UINT16 OpCode; | |
| UINT32 IaId; | |
| // | |
| // The format of IA_NA and IA_TA option refers to Dhcp6AppendIaOption(). | |
| // | |
| Option = NULL; | |
| Cursor = Buf; | |
| while (Cursor < Buf + SeekLen) { | |
| OpCode = ReadUnaligned16 ((UINT16 *) Cursor); | |
| IaId = ReadUnaligned32 ((UINT32 *) (Cursor + 4)); | |
| if (OpCode == HTONS (IaDesc->Type) && IaId == HTONL (IaDesc->IaId)) { | |
| Option = Cursor; | |
| break; | |
| } | |
| DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2))); | |
| Cursor += (DataLen + 4); | |
| } | |
| return Option; | |
| } | |
| /** | |
| Check whether the incoming IPv6 address in IaAddr is one of the maintained | |
| addresses in the IA control blcok. | |
| @param[in] IaAddr The pointer to the IA Address to be checked. | |
| @param[in] CurrentIa The pointer to the IA in IA control block. | |
| @retval TRUE Yes, this Address is already in IA control block. | |
| @retval FALSE No, this Address is NOT in IA control block. | |
| **/ | |
| BOOLEAN | |
| Dhcp6AddrIsInCurrentIa ( | |
| IN EFI_DHCP6_IA_ADDRESS *IaAddr, | |
| IN EFI_DHCP6_IA *CurrentIa | |
| ) | |
| { | |
| UINT32 Index; | |
| ASSERT (IaAddr != NULL && CurrentIa != NULL); | |
| for (Index = 0; Index < CurrentIa->IaAddressCount; Index++) { | |
| if (EFI_IP6_EQUAL(&IaAddr->IpAddress, &CurrentIa->IaAddress[Index].IpAddress)) { | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Parse the address option and update the address infomation. | |
| @param[in] CurrentIa The pointer to the Ia Address in control blcok. | |
| @param[in] IaInnerOpt The pointer to the buffer. | |
| @param[in] IaInnerLen The length to parse. | |
| @param[out] AddrNum The number of addresses. | |
| @param[in, out] AddrBuf The pointer to the address buffer. | |
| **/ | |
| VOID | |
| Dhcp6ParseAddrOption ( | |
| IN EFI_DHCP6_IA *CurrentIa, | |
| IN UINT8 *IaInnerOpt, | |
| IN UINT16 IaInnerLen, | |
| OUT UINT32 *AddrNum, | |
| IN OUT EFI_DHCP6_IA_ADDRESS *AddrBuf | |
| ) | |
| { | |
| UINT8 *Cursor; | |
| UINT16 DataLen; | |
| UINT16 OpCode; | |
| UINT32 ValidLt; | |
| UINT32 PreferredLt; | |
| EFI_DHCP6_IA_ADDRESS *IaAddr; | |
| // | |
| // The format of the IA Address option: | |
| // | |
| // 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 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | OPTION_IAADDR | option-len | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | | | |
| // | IPv6 address | | |
| // | | | |
| // | | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | preferred-lifetime | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | valid-lifetime | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // . . | |
| // . IAaddr-options . | |
| // . . | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | |
| // | |
| // Two usage model: | |
| // | |
| // 1. Pass addrbuf == null, to get the addrnum over the Ia inner options. | |
| // 2. Pass addrbuf != null, to resolve the addresses over the Ia inner | |
| // options to the addrbuf. | |
| // | |
| Cursor = IaInnerOpt; | |
| *AddrNum = 0; | |
| while (Cursor < IaInnerOpt + IaInnerLen) { | |
| // | |
| // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option | |
| // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time. | |
| // | |
| OpCode = ReadUnaligned16 ((UINT16 *) Cursor); | |
| PreferredLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 20))); | |
| ValidLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 24))); | |
| IaAddr = (EFI_DHCP6_IA_ADDRESS *) (Cursor + 4); | |
| if (OpCode == HTONS (Dhcp6OptIaAddr) && ValidLt >= PreferredLt && | |
| (Dhcp6AddrIsInCurrentIa(IaAddr, CurrentIa) || ValidLt !=0)) { | |
| if (AddrBuf != NULL) { | |
| CopyMem (AddrBuf, IaAddr, sizeof (EFI_DHCP6_IA_ADDRESS)); | |
| AddrBuf->PreferredLifetime = PreferredLt; | |
| AddrBuf->ValidLifetime = ValidLt; | |
| AddrBuf = (EFI_DHCP6_IA_ADDRESS *) ((UINT8 *) AddrBuf + sizeof (EFI_DHCP6_IA_ADDRESS)); | |
| } | |
| (*AddrNum)++; | |
| } | |
| DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2))); | |
| Cursor += (DataLen + 4); | |
| } | |
| } | |
| /** | |
| Create a control blcok for the Ia according to the corresponding options. | |
| @param[in] Instance The pointer to DHCP6 Instance. | |
| @param[in] IaInnerOpt The pointer to the inner options in the Ia option. | |
| @param[in] IaInnerLen The length of all the inner options in the Ia option. | |
| @param[in] T1 T1 time in the Ia option. | |
| @param[in] T2 T2 time in the Ia option. | |
| @retval EFI_NOT_FOUND No valid IA option is found. | |
| @retval EFI_SUCCESS Create an IA control block successfully. | |
| @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. | |
| @retval EFI_DEVICE_ERROR An unexpected error. | |
| **/ | |
| EFI_STATUS | |
| Dhcp6GenerateIaCb ( | |
| IN DHCP6_INSTANCE *Instance, | |
| IN UINT8 *IaInnerOpt, | |
| IN UINT16 IaInnerLen, | |
| IN UINT32 T1, | |
| IN UINT32 T2 | |
| ) | |
| { | |
| UINT32 AddrNum; | |
| UINT32 IaSize; | |
| EFI_DHCP6_IA *Ia; | |
| if (Instance->IaCb.Ia == NULL) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| // | |
| // Calculate the number of addresses for this Ia, excluding the addresses with | |
| // the value 0 of valid lifetime. | |
| // | |
| Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, NULL); | |
| if (AddrNum == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Allocate for new IA. | |
| // | |
| IaSize = sizeof (EFI_DHCP6_IA) + (AddrNum - 1) * sizeof (EFI_DHCP6_IA_ADDRESS); | |
| Ia = AllocateZeroPool (IaSize); | |
| if (Ia == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Fill up this new IA fields. | |
| // | |
| Ia->State = Instance->IaCb.Ia->State; | |
| Ia->IaAddressCount = AddrNum; | |
| CopyMem (&Ia->Descriptor, &Instance->Config->IaDescriptor, sizeof (EFI_DHCP6_IA_DESCRIPTOR)); | |
| Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress); | |
| // | |
| // Free original IA resource. | |
| // | |
| if (Instance->IaCb.Ia->ReplyPacket != NULL) { | |
| FreePool (Instance->IaCb.Ia->ReplyPacket); | |
| } | |
| FreePool (Instance->IaCb.Ia); | |
| ZeroMem (&Instance->IaCb, sizeof (DHCP6_IA_CB)); | |
| // | |
| // Update IaCb to use new IA. | |
| // | |
| Instance->IaCb.Ia = Ia; | |
| // | |
| // Fill in IaCb fields. Such as T1, T2, AllExpireTime and LeaseTime. | |
| // | |
| Instance->IaCb.T1 = T1; | |
| Instance->IaCb.T2 = T2; | |
| Dhcp6CalculateLeaseTime (&Instance->IaCb); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Cache the current IA configuration information. | |
| @param[in] Instance The pointer to DHCP6 Instance. | |
| @retval EFI_SUCCESS Cache the current IA successfully. | |
| @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. | |
| **/ | |
| EFI_STATUS | |
| Dhcp6CacheIa ( | |
| IN DHCP6_INSTANCE *Instance | |
| ) | |
| { | |
| UINTN IaSize; | |
| EFI_DHCP6_IA *Ia; | |
| Ia = Instance->IaCb.Ia; | |
| if ((Instance->CacheIa == NULL) && (Ia != NULL)) { | |
| // | |
| // Cache the current IA. | |
| // | |
| IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS); | |
| Instance->CacheIa = AllocateZeroPool (IaSize); | |
| if (Instance->CacheIa == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| CopyMem (Instance->CacheIa, Ia, IaSize); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Append CacheIa to the currrent IA. Meanwhile, clear CacheIa.ValidLifetime to 0. | |
| @param[in] Instance The pointer to DHCP6 instance. | |
| **/ | |
| VOID | |
| Dhcp6AppendCacheIa ( | |
| IN DHCP6_INSTANCE *Instance | |
| ) | |
| { | |
| UINT8 *Ptr; | |
| UINTN Index; | |
| UINTN IaSize; | |
| UINTN NewIaSize; | |
| EFI_DHCP6_IA *Ia; | |
| EFI_DHCP6_IA *NewIa; | |
| EFI_DHCP6_IA *CacheIa; | |
| Ia = Instance->IaCb.Ia; | |
| CacheIa = Instance->CacheIa; | |
| if ((CacheIa != NULL) && (CacheIa->IaAddressCount != 0)) { | |
| // | |
| // There are old addresses existing. Merge with current addresses. | |
| // | |
| NewIaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount + CacheIa->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS); | |
| NewIa = AllocateZeroPool (NewIaSize); | |
| if (NewIa == NULL) { | |
| return; | |
| } | |
| IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount - 1) * sizeof (EFI_DHCP6_IA_ADDRESS); | |
| CopyMem (NewIa, Ia, IaSize); | |
| // | |
| // Clear old address.ValidLifetime | |
| // | |
| for (Index = 0; Index < CacheIa->IaAddressCount; Index++) { | |
| CacheIa->IaAddress[Index].ValidLifetime = 0; | |
| } | |
| NewIa->IaAddressCount += CacheIa->IaAddressCount; | |
| Ptr = (UINT8*)&NewIa->IaAddress[Ia->IaAddressCount]; | |
| CopyMem (Ptr, CacheIa->IaAddress, CacheIa->IaAddressCount * sizeof (EFI_DHCP6_IA_ADDRESS)); | |
| // | |
| // Migrate to the NewIa and free previous. | |
| // | |
| FreePool (Instance->CacheIa); | |
| FreePool (Instance->IaCb.Ia); | |
| Instance->CacheIa = NULL; | |
| Instance->IaCb.Ia = NewIa; | |
| } | |
| } | |
| /** | |
| Calculate the Dhcp6 get mapping timeout by adding additinal delay to the IP6 DAD transmits count. | |
| @param[in] Ip6Cfg The pointer to Ip6 config protocol. | |
| @param[out] TimeOut The time out value in 100ns units. | |
| @retval EFI_INVALID_PARAMETER Input parameters are invalid. | |
| @retval EFI_SUCCESS Calculate the time out value successfully. | |
| **/ | |
| EFI_STATUS | |
| Dhcp6GetMappingTimeOut ( | |
| IN EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg, | |
| OUT UINTN *TimeOut | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN DataSize; | |
| EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits; | |
| if (Ip6Cfg == NULL || TimeOut == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); | |
| Status = Ip6Cfg->GetData ( | |
| Ip6Cfg, | |
| Ip6ConfigDataTypeDupAddrDetectTransmits, | |
| &DataSize, | |
| &DadXmits | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| *TimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + DHCP6_DAD_ADDITIONAL_DELAY; | |
| return EFI_SUCCESS; | |
| } |