/** @file\r
Dhcp6 internal functions implementation.\r
\r
- Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+ Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
}\r
}\r
\r
+/**\r
+ Check whether the TxCb is still a valid control block in the instance's retry list.\r
+\r
+ @param[in] Instance The pointer to DHCP6_INSTANCE.\r
+ @param[in] TxCb The control block for a transmitted message.\r
+\r
+ @retval TRUE The control block is in Instance's retry list.\r
+ @retval FALSE The control block is NOT in Instance's retry list.\r
+ \r
+**/\r
+BOOLEAN\r
+Dhcp6IsValidTxCb (\r
+ IN DHCP6_INSTANCE *Instance,\r
+ IN DHCP6_TX_CB *TxCb\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+\r
+ NET_LIST_FOR_EACH (Entry, &Instance->TxList) {\r
+ if (TxCb == NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
\r
/**\r
Clean up the session of the instance stateful exchange.\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_DHCP6_STATE State;\r
UINT8 *Option;\r
UINT8 *IaInnerOpt;\r
UINT16 IaInnerLen;\r
//\r
// See details in the section-18.1.8 of rfc-3315.\r
//\r
- State = Dhcp6Init;\r
Option = Dhcp6SeekIaOption (\r
Packet->Dhcp6.Option,\r
Packet->Length - sizeof (EFI_DHCP6_HEADER),\r
if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {\r
T1 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 8)));\r
T2 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 12)));\r
+ //\r
+ // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,\r
+ // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes\r
+ // the remainder of the message as though the server had not included the invalid IA_NA option.\r
+ //\r
+ if (T1 > T2 && T2 > 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
IaInnerOpt = Option + 16;\r
IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 2))) - 12);\r
} else {\r
&Instance->Config->IaDescriptor\r
);\r
if (*Option == NULL) {\r
- return EFI_DEVICE_ERROR;\r
+ return EFI_SUCCESS;\r
}\r
\r
//\r
Cursor,\r
Instance->IaCb.Ia,\r
Instance->IaCb.T1,\r
- Instance->IaCb.T2\r
+ Instance->IaCb.T2,\r
+ Packet->Dhcp6.Header.MessageType\r
);\r
\r
//\r
// Dhcp6selecting.\r
//\r
Instance->IaCb.Ia->State = Dhcp6Selecting;\r
+ //\r
+ // Clear initial time for current transaction.\r
+ //\r
+ Instance->StartTime = 0;\r
\r
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
\r
Cursor,\r
Instance->IaCb.Ia,\r
Instance->IaCb.T1,\r
- Instance->IaCb.T2\r
+ Instance->IaCb.T2,\r
+ Packet->Dhcp6.Header.MessageType\r
);\r
\r
//\r
// Dhcp6requesting.\r
//\r
Instance->IaCb.Ia->State = Dhcp6Requesting;\r
+ //\r
+ // Clear initial time for current transaction.\r
+ //\r
+ Instance->StartTime = 0;\r
\r
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
\r
ServerId->Duid\r
);\r
\r
- Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0);\r
+ Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType);\r
\r
//\r
// Determine the size/length of packet.\r
// Dhcp6declining.\r
//\r
Instance->IaCb.Ia->State = Dhcp6Declining;\r
+ //\r
+ // Clear initial time for current transaction.\r
+ //\r
+ Instance->StartTime = 0;\r
\r
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
\r
&Elapsed\r
);\r
\r
- Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0);\r
+ Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType);\r
\r
//\r
// Determine the size/length of packet\r
Cursor,\r
Instance->IaCb.Ia,\r
Instance->IaCb.T1,\r
- Instance->IaCb.T2\r
+ Instance->IaCb.T2,\r
+ Packet->Dhcp6.Header.MessageType\r
);\r
\r
if (!RebindRequest) {\r
//\r
Instance->IaCb.Ia->State = State;\r
Instance->IaCb.LeaseTime = (RebindRequest) ? Instance->IaCb.T2 : Instance->IaCb.T1;\r
+ //\r
+ // Clear initial time for current transaction.\r
+ //\r
+ Instance->StartTime = 0;\r
\r
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
\r
//\r
Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);\r
ASSERT (Packet->Size > Packet->Length + 8);\r
+ \r
+ //\r
+ // Clear initial time for current transaction.\r
+ //\r
+ Instance->StartTime = 0;\r
\r
//\r
// Send info-request packet with no state.\r
Cursor,\r
Instance->IaCb.Ia,\r
Instance->IaCb.T1,\r
- Instance->IaCb.T2\r
+ Instance->IaCb.T2,\r
+ Packet->Dhcp6.Header.MessageType\r
);\r
\r
//\r
// Dhcp6Confirming.\r
//\r
Instance->IaCb.Ia->State = Dhcp6Confirming;\r
+ //\r
+ // Clear initial time for current transaction.\r
+ //\r
+ Instance->StartTime = 0;\r
\r
Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
\r
ASSERT (Instance->IaCb.Ia != NULL);\r
ASSERT (Packet != NULL);\r
\r
+ Status = EFI_SUCCESS;\r
+\r
if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {\r
return EFI_DEVICE_ERROR;\r
}\r
&Instance->Config->IaDescriptor\r
);\r
if (Option == NULL) {\r
- return EFI_DEVICE_ERROR;\r
+ return EFI_SUCCESS;\r
}\r
}\r
\r
return Status;\r
}\r
\r
- //\r
- // Dequeue the sent packet from retransmit list since reply received.\r
- //\r
- Status = Dhcp6DequeueRetry (\r
- Instance,\r
- Packet->Dhcp6.Header.TransactionId,\r
- FALSE\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
//\r
// When receive a valid reply packet in response to a decline/release packet,\r
// the client considers the decline/release event completed regardless of the\r
//\r
Instance->StartTime = 0;\r
\r
- return EFI_SUCCESS;\r
+ Status = EFI_SUCCESS;\r
+ goto ON_EXIT;\r
}\r
\r
//\r
);\r
\r
if (!EFI_ERROR (Status)) {\r
- //\r
- // Reset start time for next exchange.\r
- //\r
- Instance->StartTime = 0;\r
-\r
//\r
// No status code or no error status code means succeed to reply.\r
//\r
Status = Dhcp6UpdateIaInfo (Instance, Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Reset start time for next exchange.\r
+ //\r
+ Instance->StartTime = 0;\r
\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Set bound state and store the reply packet.\r
- //\r
- if (Instance->IaCb.Ia->ReplyPacket != NULL) {\r
- FreePool (Instance->IaCb.Ia->ReplyPacket);\r
- }\r
+ //\r
+ // Set bound state and store the reply packet.\r
+ //\r
+ if (Instance->IaCb.Ia->ReplyPacket != NULL) {\r
+ FreePool (Instance->IaCb.Ia->ReplyPacket);\r
+ }\r
\r
- Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);\r
+ Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);\r
\r
- if (Instance->IaCb.Ia->ReplyPacket == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
+ if (Instance->IaCb.Ia->ReplyPacket == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
\r
- CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);\r
+ CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);\r
\r
- Instance->IaCb.Ia->State = Dhcp6Bound;\r
+ Instance->IaCb.Ia->State = Dhcp6Bound;\r
\r
- //\r
- // For sync, set the success flag out of polling in start/renewrebind.\r
- //\r
- Instance->UdpSts = EFI_SUCCESS;\r
+ //\r
+ // For sync, set the success flag out of polling in start/renewrebind.\r
+ //\r
+ Instance->UdpSts = EFI_SUCCESS;\r
\r
- //\r
- // Maybe this is a new round DHCP process due to some reason, such as NotOnLink\r
- // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that\r
- // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP\r
- // consumers can be notified to flush old address.\r
- //\r
- Dhcp6AppendCacheIa (Instance);\r
+ //\r
+ // Maybe this is a new round DHCP process due to some reason, such as NotOnLink\r
+ // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that\r
+ // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP\r
+ // consumers can be notified to flush old address.\r
+ //\r
+ Dhcp6AppendCacheIa (Instance);\r
\r
- //\r
- // For async, signal the Ia event to inform Ia infomation update.\r
- //\r
- if (Instance->Config->IaInfoEvent != NULL) {\r
- gBS->SignalEvent (Instance->Config->IaInfoEvent);\r
+ //\r
+ // For async, signal the Ia event to inform Ia infomation update.\r
+ //\r
+ if (Instance->Config->IaInfoEvent != NULL) {\r
+ gBS->SignalEvent (Instance->Config->IaInfoEvent);\r
+ }\r
+ } else if (Status == EFI_NOT_FOUND) {\r
+ //\r
+ // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, \r
+ // the client sends a Renew or Rebind if the IA is not in the Reply message.\r
+ // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.\r
+ //\r
+ return EFI_SUCCESS;\r
}\r
+ \r
+ goto ON_EXIT;\r
+ \r
} else if (Option != NULL) {\r
//\r
// Any error status code option is found.\r
}\r
break;\r
\r
+ case Dhcp6StsNoBinding:\r
+ if (Instance->IaCb.Ia->State == Dhcp6Renewing || Instance->IaCb.Ia->State == Dhcp6Rebinding) {\r
+ //\r
+ // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client \r
+ // sends a Request message if the IA contained a Status Code option with the NoBinding status.\r
+ //\r
+ Status = Dhcp6SendRequestMsg(Instance);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ break;\r
+\r
default:\r
//\r
// The other status code, just restart solicitation.\r
}\r
\r
return EFI_SUCCESS;\r
+ \r
+ON_EXIT:\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = Dhcp6DequeueRetry (\r
+ Instance,\r
+ Packet->Dhcp6.Header.TransactionId,\r
+ FALSE\r
+ );\r
+ }\r
+ \r
+ return Status;\r
}\r
\r
\r
{\r
EFI_STATUS Status;\r
UINT8 *Option;\r
- UINT16 StsCode;\r
BOOLEAN Timeout;\r
\r
ASSERT(Instance->Config);\r
ASSERT(Instance->IaCb.Ia);\r
\r
Timeout = FALSE;\r
- StsCode = Dhcp6StsSuccess;\r
\r
//\r
// If the client does receives a valid reply message that includes a rapid\r
// display the associated status message to the user.\r
// See the details in the section-17.1.3 of rfc-3315.\r
//\r
- Option = Dhcp6SeekOption(\r
- Packet->Dhcp6.Option,\r
- Packet->Length - 4,\r
- Dhcp6OptStatusCode\r
+ Status = Dhcp6SeekStsOption (\r
+ Instance,\r
+ Packet,\r
+ &Option\r
);\r
-\r
- if (Option != NULL) {\r
- StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4)));\r
- if (StsCode != Dhcp6StsSuccess) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
}\r
\r
//\r
LIST_ENTRY *Next1;\r
LIST_ENTRY *Entry2;\r
LIST_ENTRY *Next2;\r
+ EFI_STATUS Status;\r
\r
ASSERT (Udp6Wrap != NULL);\r
ASSERT (Context != NULL);\r
return ;\r
}\r
\r
+ if (Udp6Wrap->TotalSize < sizeof (EFI_DHCP6_HEADER)) {\r
+ goto ON_CONTINUE;\r
+ }\r
+\r
//\r
// Copy the net buffer received from upd6 to a Dhcp6 packet.\r
//\r
\r
ON_CONTINUE:\r
\r
+ if (!IsDispatched) {\r
+ Status = UdpIoRecvDatagram (\r
+ Service->UdpIo,\r
+ Dhcp6ReceivePacket,\r
+ Service,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) {\r
+ Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link);\r
+ Dhcp6CleanupRetry (Instance, DHCP6_PACKET_ALL);\r
+ }\r
+ }\r
+ }\r
+\r
NetbufFree (Udp6Wrap);\r
\r
if (Packet != NULL) {\r
// Select the advertisement received before.\r
//\r
Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);\r
- if (EFI_ERROR (Status)) {\r
+ if (Status == EFI_ABORTED) {\r
+ goto ON_CLOSE;\r
+ } else if (EFI_ERROR (Status)) {\r
TxCb->RetryCnt++;\r
}\r
return;\r
// Check whether overflow the max retry count limit for this packet\r
//\r
if (TxCb->RetryCtl.Mrc != 0 && TxCb->RetryCtl.Mrc < TxCb->RetryCnt) {\r
+ Status = EFI_NO_RESPONSE;\r
goto ON_CLOSE;\r
}\r
\r
// Check whether overflow the max retry duration for this packet\r
//\r
if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd <= TxCb->RetryLos) {\r
+ Status = EFI_NO_RESPONSE;\r
goto ON_CLOSE;\r
}\r
\r
\r
ON_CLOSE:\r
\r
- if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest ||\r
+ if (Dhcp6IsValidTxCb (Instance, TxCb) &&\r
+ TxCb->TxPacket != NULL &&\r
+ (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest ||\r
TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew ||\r
- TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm\r
+ TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm)\r
) {\r
//\r
// The failure of renew/Confirm will still switch to the bound state.\r
//\r
// The failure of the others will terminate current state machine if timeout.\r
//\r
- Dhcp6CleanupSession (Instance, EFI_NO_RESPONSE);\r
+ Dhcp6CleanupSession (Instance, Status);\r
}\r
}\r