X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=NetworkPkg%2FDhcp6Dxe%2FDhcp6Utility.c;h=8603669903fb5acd6ea0651470eb08f4ec843e3c;hb=393a3169c2a777e3ed899c85f7827258a13f0755;hp=f4e7649e6cba2b4734db308cb52fd6e1de080835;hpb=76389e18c04833a87811550ed6db06f1790aacde;p=mirror_edk2.git diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c index f4e7649e6c..8603669903 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c @@ -1,7 +1,7 @@ /** @file Dhcp6 support functions implementation. - Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -34,27 +34,18 @@ Dhcp6GenerateClientId ( 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. // - Duid = GetVariable (L"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid); + GetVariable2 (L"ClientId", &gEfiDhcp6ServiceBindingProtocolGuid, (VOID**)&Duid, NULL); if (Duid != NULL) { return Duid; } - // - // 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 - ); - // // The format of client identifier option: // @@ -68,42 +59,96 @@ Dhcp6GenerateClientId ( // . . // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // - // - // 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) . - // . . - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // // - // sizeof (option-len + Duid-type + hardware-type + time) = 10 bytes + // If System UUID is found from SMBIOS Table, use DUID-UUID type. // - Duid = AllocateZeroPool (10 + Mode->HwAddressSize); - if (Duid == NULL) { - return NULL; - } + if (!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 (Duid-type + hardware-type + time) = 8 bytes - // - Duid->Length = (UINT16) (Mode->HwAddressSize + 8); + // + // sizeof (option-len + Duid-type + UUID-size) = 20 bytes + // + Duid = AllocateZeroPool (2 + 2 + sizeof (EFI_GUID)); + if (Duid == NULL) { + return NULL; + } - // - // Set the Duid-type, hardware-type, time and copy the hardware address. - // - WriteUnaligned16 ((UINT16 *) (Duid->Duid), HTONS (Dhcp6DuidTypeLlt)); - WriteUnaligned16 ((UINT16 *) (Duid->Duid + 2), HTONS (NET_IFTYPE_ETHERNET)); - WriteUnaligned32 ((UINT32 *) (Duid->Duid + 4), HTONL (Stamp)); + // + // 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) . + // . . + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // - CopyMem (Duid->Duid + 8, &Mode->CurrentAddress, Mode->HwAddressSize); + // + // 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", @@ -112,7 +157,10 @@ Dhcp6GenerateClientId ( Duid->Length + 2, (VOID *) Duid ); - ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + FreePool (Duid); + return NULL; + } return Duid; } @@ -602,6 +650,75 @@ Dhcp6AppendOption ( 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. @@ -610,6 +727,7 @@ Dhcp6AppendOption ( @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. @@ -619,13 +737,13 @@ Dhcp6AppendIaOption ( IN OUT UINT8 *Buf, IN EFI_DHCP6_IA *Ia, IN UINT32 T1, - IN UINT32 T2 + IN UINT32 T2, + IN UINT32 MessageType ) { UINT8 *AddrOpt; UINT16 *Len; UINTN Index; - UINT16 Length; // // The format of IA_NA and IA_TA option: @@ -668,9 +786,9 @@ Dhcp6AppendIaOption ( // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified. // if (Ia->Descriptor.Type == Dhcp6OptIana) { - WriteUnaligned32 ((UINT32 *) Buf, ((T1 != 0) ? T1 : 0xffffffff)); + WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff)); Buf += 4; - WriteUnaligned32 ((UINT32 *) Buf, ((T2 != 0) ? T2 : 0xffffffff)); + WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff)); Buf += 4; } @@ -678,15 +796,8 @@ Dhcp6AppendIaOption ( // 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); - Length = HTONS ((UINT16) sizeof (EFI_DHCP6_IA_ADDRESS)); - Buf = Dhcp6AppendOption ( - Buf, - HTONS (Dhcp6OptIaAddr), - Length, - AddrOpt - ); + AddrOpt = (UINT8 *) Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS); + Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *) AddrOpt, MessageType); } // @@ -782,7 +893,7 @@ SetElapsedTime ( // // 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 Solicit + // 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) { @@ -889,10 +1000,39 @@ Dhcp6SeekIaOption ( 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. @@ -901,6 +1041,7 @@ Dhcp6SeekIaOption ( **/ VOID Dhcp6ParseAddrOption ( + IN EFI_DHCP6_IA *CurrentIa, IN UINT8 *IaInnerOpt, IN UINT16 IaInnerLen, OUT UINT32 *AddrNum, @@ -911,6 +1052,8 @@ Dhcp6ParseAddrOption ( UINT16 DataLen; UINT16 OpCode; UINT32 ValidLt; + UINT32 PreferredLt; + EFI_DHCP6_IA_ADDRESS *IaAddr; // // The format of the IA Address option: @@ -947,19 +1090,21 @@ Dhcp6ParseAddrOption ( while (Cursor < IaInnerOpt + IaInnerLen) { // - // Count the Ia address option with non-0 valid time. + // 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); - ValidLt = ReadUnaligned32 ((UINT32 *) (Cursor + 24)); - if (OpCode == HTONS (Dhcp6OptIaAddr) && ValidLt != 0) { - + 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, Cursor + 4, sizeof (EFI_DHCP6_IA_ADDRESS)); - AddrBuf->PreferredLifetime = NTOHL (AddrBuf->PreferredLifetime); - AddrBuf->ValidLifetime = NTOHL (AddrBuf->ValidLifetime); + 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))); @@ -980,6 +1125,7 @@ Dhcp6ParseAddrOption ( @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 @@ -996,14 +1142,14 @@ Dhcp6GenerateIaCb ( EFI_DHCP6_IA *Ia; if (Instance->IaCb.Ia == NULL) { - return EFI_NOT_FOUND; + return EFI_DEVICE_ERROR; } // // Calculate the number of addresses for this Ia, excluding the addresses with // the value 0 of valid lifetime. // - Dhcp6ParseAddrOption (IaInnerOpt, IaInnerLen, &AddrNum, NULL); + Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, NULL); if (AddrNum == 0) { return EFI_NOT_FOUND; @@ -1025,7 +1171,7 @@ Dhcp6GenerateIaCb ( Ia->State = Instance->IaCb.Ia->State; Ia->IaAddressCount = AddrNum; CopyMem (&Ia->Descriptor, &Instance->Config->IaDescriptor, sizeof (EFI_DHCP6_IA_DESCRIPTOR)); - Dhcp6ParseAddrOption (IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress); + Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress); // // Free original IA resource. @@ -1144,3 +1290,42 @@ Dhcp6AppendCacheIa ( 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; +}