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;
+}