Fix several RFC compliance issues in DHCP6 driver as below.
1. Client must ignore any Advertise message that includes a Status Code option containing the value NoAddrsAvail. 2. The elapsed-time should start from the current DHCP transaction. 3. Client should not change any information about addresses the client has recorded in the IA but not included in the IA from the server. 4. Client need to update to handle the error status code UnspecFail/UseMulticast/NotOnLink/NoBinding in the Reply message from server. 5. When the client receives a Reply message in response to a Renew/ Rebind message, the client examines each IA independently. For each IA in the original Renew/ Rebind message, the client sends a Renew/ Rebind if the IA is not in the Reply message. 6. Client should uses network byte order in IANA T1/T2 option 7. Client should discard any addresses for which the preferred lifetime is greater than the valid lifetime. Signed-off-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com> Reviewed-by: Ouyang Qian <qian.ouyang@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@14039 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@@ -593,6 +593,14 @@ Dhcp6UpdateIaInfo (
|
||||
if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {
|
||||
T1 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 8)));
|
||||
T2 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 12)));
|
||||
//
|
||||
// Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
|
||||
// and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
|
||||
// the remainder of the message as though the server had not included the invalid IA_NA option.
|
||||
//
|
||||
if (T1 > T2 && T2 > 0) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
IaInnerOpt = Option + 16;
|
||||
IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 2))) - 12);
|
||||
} else {
|
||||
@@ -697,7 +705,7 @@ Dhcp6SeekStsOption (
|
||||
&Instance->Config->IaDescriptor
|
||||
);
|
||||
if (*Option == NULL) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -949,7 +957,8 @@ Dhcp6SendSolicitMsg (
|
||||
Cursor,
|
||||
Instance->IaCb.Ia,
|
||||
Instance->IaCb.T1,
|
||||
Instance->IaCb.T2
|
||||
Instance->IaCb.T2,
|
||||
Packet->Dhcp6.Header.MessageType
|
||||
);
|
||||
|
||||
//
|
||||
@@ -987,6 +996,10 @@ Dhcp6SendSolicitMsg (
|
||||
// Dhcp6selecting.
|
||||
//
|
||||
Instance->IaCb.Ia->State = Dhcp6Selecting;
|
||||
//
|
||||
// Clear initial time for current transaction.
|
||||
//
|
||||
Instance->StartTime = 0;
|
||||
|
||||
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
|
||||
|
||||
@@ -1133,7 +1146,8 @@ Dhcp6SendRequestMsg (
|
||||
Cursor,
|
||||
Instance->IaCb.Ia,
|
||||
Instance->IaCb.T1,
|
||||
Instance->IaCb.T2
|
||||
Instance->IaCb.T2,
|
||||
Packet->Dhcp6.Header.MessageType
|
||||
);
|
||||
|
||||
//
|
||||
@@ -1171,6 +1185,10 @@ Dhcp6SendRequestMsg (
|
||||
// Dhcp6requesting.
|
||||
//
|
||||
Instance->IaCb.Ia->State = Dhcp6Requesting;
|
||||
//
|
||||
// Clear initial time for current transaction.
|
||||
//
|
||||
Instance->StartTime = 0;
|
||||
|
||||
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
|
||||
|
||||
@@ -1282,7 +1300,7 @@ Dhcp6SendDeclineMsg (
|
||||
ServerId->Duid
|
||||
);
|
||||
|
||||
Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0);
|
||||
Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType);
|
||||
|
||||
//
|
||||
// Determine the size/length of packet.
|
||||
@@ -1305,6 +1323,10 @@ Dhcp6SendDeclineMsg (
|
||||
// Dhcp6declining.
|
||||
//
|
||||
Instance->IaCb.Ia->State = Dhcp6Declining;
|
||||
//
|
||||
// Clear initial time for current transaction.
|
||||
//
|
||||
Instance->StartTime = 0;
|
||||
|
||||
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
|
||||
|
||||
@@ -1415,7 +1437,7 @@ Dhcp6SendReleaseMsg (
|
||||
&Elapsed
|
||||
);
|
||||
|
||||
Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0);
|
||||
Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType);
|
||||
|
||||
//
|
||||
// Determine the size/length of packet
|
||||
@@ -1540,7 +1562,8 @@ Dhcp6SendRenewRebindMsg (
|
||||
Cursor,
|
||||
Instance->IaCb.Ia,
|
||||
Instance->IaCb.T1,
|
||||
Instance->IaCb.T2
|
||||
Instance->IaCb.T2,
|
||||
Packet->Dhcp6.Header.MessageType
|
||||
);
|
||||
|
||||
if (!RebindRequest) {
|
||||
@@ -1612,6 +1635,10 @@ Dhcp6SendRenewRebindMsg (
|
||||
//
|
||||
Instance->IaCb.Ia->State = State;
|
||||
Instance->IaCb.LeaseTime = (RebindRequest) ? Instance->IaCb.T2 : Instance->IaCb.T1;
|
||||
//
|
||||
// Clear initial time for current transaction.
|
||||
//
|
||||
Instance->StartTime = 0;
|
||||
|
||||
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
|
||||
|
||||
@@ -1844,6 +1871,11 @@ Dhcp6SendInfoRequestMsg (
|
||||
//
|
||||
Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);
|
||||
ASSERT (Packet->Size > Packet->Length + 8);
|
||||
|
||||
//
|
||||
// Clear initial time for current transaction.
|
||||
//
|
||||
Instance->StartTime = 0;
|
||||
|
||||
//
|
||||
// Send info-request packet with no state.
|
||||
@@ -1941,7 +1973,8 @@ Dhcp6SendConfirmMsg (
|
||||
Cursor,
|
||||
Instance->IaCb.Ia,
|
||||
Instance->IaCb.T1,
|
||||
Instance->IaCb.T2
|
||||
Instance->IaCb.T2,
|
||||
Packet->Dhcp6.Header.MessageType
|
||||
);
|
||||
|
||||
//
|
||||
@@ -1978,6 +2011,10 @@ Dhcp6SendConfirmMsg (
|
||||
// Dhcp6Confirming.
|
||||
//
|
||||
Instance->IaCb.Ia->State = Dhcp6Confirming;
|
||||
//
|
||||
// Clear initial time for current transaction.
|
||||
//
|
||||
Instance->StartTime = 0;
|
||||
|
||||
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
|
||||
|
||||
@@ -2020,6 +2057,8 @@ Dhcp6HandleReplyMsg (
|
||||
ASSERT (Instance->IaCb.Ia != NULL);
|
||||
ASSERT (Packet != NULL);
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
@@ -2056,7 +2095,7 @@ Dhcp6HandleReplyMsg (
|
||||
&Instance->Config->IaDescriptor
|
||||
);
|
||||
if (Option == NULL) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2069,19 +2108,6 @@ Dhcp6HandleReplyMsg (
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Dequeue the sent packet from retransmit list since reply received.
|
||||
//
|
||||
Status = Dhcp6DequeueRetry (
|
||||
Instance,
|
||||
Packet->Dhcp6.Header.TransactionId,
|
||||
FALSE
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// When receive a valid reply packet in response to a decline/release packet,
|
||||
// the client considers the decline/release event completed regardless of the
|
||||
@@ -2115,7 +2141,8 @@ Dhcp6HandleReplyMsg (
|
||||
//
|
||||
Instance->StartTime = 0;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
Status = EFI_SUCCESS;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -2131,56 +2158,64 @@ Dhcp6HandleReplyMsg (
|
||||
);
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
//
|
||||
// Reset start time for next exchange.
|
||||
//
|
||||
Instance->StartTime = 0;
|
||||
|
||||
//
|
||||
// No status code or no error status code means succeed to reply.
|
||||
//
|
||||
Status = Dhcp6UpdateIaInfo (Instance, Packet);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
//
|
||||
// Reset start time for next exchange.
|
||||
//
|
||||
Instance->StartTime = 0;
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Set bound state and store the reply packet.
|
||||
//
|
||||
if (Instance->IaCb.Ia->ReplyPacket != NULL) {
|
||||
FreePool (Instance->IaCb.Ia->ReplyPacket);
|
||||
}
|
||||
|
||||
Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);
|
||||
|
||||
if (Instance->IaCb.Ia->ReplyPacket == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);
|
||||
|
||||
Instance->IaCb.Ia->State = Dhcp6Bound;
|
||||
|
||||
//
|
||||
// For sync, set the success flag out of polling in start/renewrebind.
|
||||
//
|
||||
Instance->UdpSts = EFI_SUCCESS;
|
||||
|
||||
//
|
||||
// Maybe this is a new round DHCP process due to some reason, such as NotOnLink
|
||||
// ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that
|
||||
// case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
|
||||
// consumers can be notified to flush old address.
|
||||
//
|
||||
Dhcp6AppendCacheIa (Instance);
|
||||
|
||||
//
|
||||
// For async, signal the Ia event to inform Ia infomation update.
|
||||
//
|
||||
if (Instance->Config->IaInfoEvent != NULL) {
|
||||
gBS->SignalEvent (Instance->Config->IaInfoEvent);
|
||||
//
|
||||
// Set bound state and store the reply packet.
|
||||
//
|
||||
if (Instance->IaCb.Ia->ReplyPacket != NULL) {
|
||||
FreePool (Instance->IaCb.Ia->ReplyPacket);
|
||||
}
|
||||
|
||||
Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);
|
||||
|
||||
if (Instance->IaCb.Ia->ReplyPacket == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);
|
||||
|
||||
Instance->IaCb.Ia->State = Dhcp6Bound;
|
||||
|
||||
//
|
||||
// For sync, set the success flag out of polling in start/renewrebind.
|
||||
//
|
||||
Instance->UdpSts = EFI_SUCCESS;
|
||||
|
||||
//
|
||||
// Maybe this is a new round DHCP process due to some reason, such as NotOnLink
|
||||
// ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that
|
||||
// case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
|
||||
// consumers can be notified to flush old address.
|
||||
//
|
||||
Dhcp6AppendCacheIa (Instance);
|
||||
|
||||
//
|
||||
// For async, signal the Ia event to inform Ia infomation update.
|
||||
//
|
||||
if (Instance->Config->IaInfoEvent != NULL) {
|
||||
gBS->SignalEvent (Instance->Config->IaInfoEvent);
|
||||
}
|
||||
} else if (Status == EFI_NOT_FOUND) {
|
||||
//
|
||||
// Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,
|
||||
// the client sends a Renew or Rebind if the IA is not in the Reply message.
|
||||
// Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.
|
||||
//
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
goto ON_EXIT;
|
||||
|
||||
} else if (Option != NULL) {
|
||||
//
|
||||
// Any error status code option is found.
|
||||
@@ -2226,6 +2261,19 @@ Dhcp6HandleReplyMsg (
|
||||
}
|
||||
break;
|
||||
|
||||
case Dhcp6StsNoBinding:
|
||||
if (Instance->IaCb.Ia->State == Dhcp6Renewing || Instance->IaCb.Ia->State == Dhcp6Rebinding) {
|
||||
//
|
||||
// Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client
|
||||
// sends a Request message if the IA contained a Status Code option with the NoBinding status.
|
||||
//
|
||||
Status = Dhcp6SendRequestMsg(Instance);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//
|
||||
// The other status code, just restart solicitation.
|
||||
@@ -2235,6 +2283,18 @@ Dhcp6HandleReplyMsg (
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
ON_EXIT:
|
||||
|
||||
if (!EFI_ERROR(Status)) {
|
||||
Status = Dhcp6DequeueRetry (
|
||||
Instance,
|
||||
Packet->Dhcp6.Header.TransactionId,
|
||||
FALSE
|
||||
);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
@@ -2378,17 +2438,13 @@ Dhcp6HandleAdvertiseMsg (
|
||||
// display the associated status message to the user.
|
||||
// See the details in the section-17.1.3 of rfc-3315.
|
||||
//
|
||||
Option = Dhcp6SeekOption(
|
||||
Packet->Dhcp6.Option,
|
||||
Packet->Length - 4,
|
||||
Dhcp6OptStatusCode
|
||||
Status = Dhcp6SeekStsOption (
|
||||
Instance,
|
||||
Packet,
|
||||
&Option
|
||||
);
|
||||
|
||||
if (Option != NULL) {
|
||||
StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4)));
|
||||
if (StsCode != Dhcp6StsSuccess) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
|
Reference in New Issue
Block a user