OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
Instance->UdpSts = EFI_ALREADY_STARTED;\r
\r
- //\r
- // Need to clear initial time to make sure that elapsed-time\r
- // is set to 0 for first Solicit.\r
- //\r
- Instance->StartTime = 0;\r
-\r
//\r
// Send the solicit message to start S.A.R.R process.\r
//\r
volatile EFI_STATUS UdpSts;\r
BOOLEAN InDestroy;\r
BOOLEAN MediaPresent;\r
+ //\r
+ // StartTime is used to calculate the 'elapsed-time' option. Refer to RFC3315,\r
+ // the elapsed-time is amount of time since the client began its current DHCP transaction. \r
+ //\r
UINT64 StartTime;\r
};\r
\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
// 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
return Buf;\r
}\r
\r
+/**\r
+ Append the appointed IA Address option to Buf, and move Buf to the end.\r
+\r
+ @param[in, out] Buf The pointer to the position to append.\r
+ @param[in] IaAddr The pointer to the IA Address.\r
+ @param[in] MessageType Message type of DHCP6 package.\r
+\r
+ @return Buf The position to append the next option.\r
+\r
+**/\r
+UINT8 *\r
+Dhcp6AppendIaAddrOption (\r
+ IN OUT UINT8 *Buf,\r
+ IN EFI_DHCP6_IA_ADDRESS *IaAddr,\r
+ IN UINT32 MessageType\r
+)\r
+{\r
+\r
+ // The format of the IA Address option is:\r
+ //\r
+ // 0 1 2 3\r
+ // 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\r
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ // | OPTION_IAADDR | option-len |\r
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ // | |\r
+ // | IPv6 address |\r
+ // | |\r
+ // | |\r
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ // | preferred-lifetime |\r
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ // | valid-lifetime |\r
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ // . .\r
+ // . IAaddr-options .\r
+ // . .\r
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ \r
+ //\r
+ // Fill the value of Ia Address option type\r
+ //\r
+ WriteUnaligned16 ((UINT16 *) Buf, HTONS (Dhcp6OptIaAddr));\r
+ Buf += 2;\r
+\r
+ WriteUnaligned16 ((UINT16 *) Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS)));\r
+ Buf += 2;\r
+\r
+ CopyMem (Buf, &IaAddr->IpAddress, sizeof(EFI_IPv6_ADDRESS));\r
+ Buf += sizeof(EFI_IPv6_ADDRESS);\r
+\r
+ //\r
+ // Fill the value of preferred-lifetime and valid-lifetime.\r
+ // According to RFC3315 Chapter 18.1.2, the preferred-lifetime and valid-lifetime fields\r
+ // should set to 0 when initiate a Confirm message.\r
+ //\r
+ if (MessageType != Dhcp6MsgConfirm) {\r
+ WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->PreferredLifetime));\r
+ }\r
+ Buf += 4;\r
+\r
+ if (MessageType != Dhcp6MsgConfirm) {\r
+ WriteUnaligned32 ((UINT32 *) Buf, HTONL (IaAddr->ValidLifetime));\r
+ }\r
+ Buf += 4;\r
+\r
+ return Buf;\r
+}\r
+\r
\r
/**\r
Append the appointed Ia option to Buf, and move Buf to the end.\r
@param[in] Ia The pointer to the Ia.\r
@param[in] T1 The time of T1.\r
@param[in] T2 The time of T2.\r
+ @param[in] MessageType Message type of DHCP6 package.\r
\r
@return Buf The position to append the next Ia option.\r
\r
IN OUT UINT8 *Buf,\r
IN EFI_DHCP6_IA *Ia,\r
IN UINT32 T1,\r
- IN UINT32 T2\r
+ IN UINT32 T2,\r
+ IN UINT32 MessageType\r
)\r
{\r
UINT8 *AddrOpt;\r
UINT16 *Len;\r
UINTN Index;\r
- UINT16 Length;\r
\r
//\r
// The format of IA_NA and IA_TA option:\r
// Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.\r
//\r
if (Ia->Descriptor.Type == Dhcp6OptIana) {\r
- WriteUnaligned32 ((UINT32 *) Buf, ((T1 != 0) ? T1 : 0xffffffff));\r
+ WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff));\r
Buf += 4;\r
- WriteUnaligned32 ((UINT32 *) Buf, ((T2 != 0) ? T2 : 0xffffffff));\r
+ WriteUnaligned32 ((UINT32 *) Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff));\r
Buf += 4;\r
}\r
\r
// Fill all the addresses belong to the Ia\r
//\r
for (Index = 0; Index < Ia->IaAddressCount; Index++) {\r
-\r
- AddrOpt = (UINT8 *) Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);\r
- Length = HTONS ((UINT16) sizeof (EFI_DHCP6_IA_ADDRESS));\r
- Buf = Dhcp6AppendOption (\r
- Buf,\r
- HTONS (Dhcp6OptIaAddr),\r
- Length,\r
- AddrOpt\r
- );\r
+ AddrOpt = (UINT8 *) Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);\r
+ Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *) AddrOpt, MessageType);\r
}\r
\r
//\r
\r
//\r
// Sentinel value of 0 means that this is the first DHCP packet that we are\r
- // sending and that we need to initialize the value. First DHCP Solicit\r
+ // sending and that we need to initialize the value. First DHCP message\r
// gets 0 elapsed-time. Otherwise, calculate based on StartTime.\r
//\r
if (Instance->StartTime == 0) {\r
return Option;\r
}\r
\r
+/**\r
+ Check whether the incoming IPv6 address in IaAddr is one of the maintained \r
+ addresses in the IA control blcok.\r
+\r
+ @param[in] IaAddr The pointer to the IA Address to be checked.\r
+ @param[in] CurrentIa The pointer to the IA in IA control block.\r
+\r
+ @retval TRUE Yes, this Address is already in IA control block.\r
+ @retval FALSE No, this Address is NOT in IA control block.\r
+\r
+**/\r
+BOOLEAN\r
+Dhcp6AddrIsInCurrentIa (\r
+ IN EFI_DHCP6_IA_ADDRESS *IaAddr,\r
+ IN EFI_DHCP6_IA *CurrentIa\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ ASSERT (IaAddr != NULL && CurrentIa != NULL);\r
+ \r
+ for (Index = 0; Index < CurrentIa->IaAddressCount; Index++) {\r
+ if (EFI_IP6_EQUAL(&IaAddr->IpAddress, &CurrentIa->IaAddress[Index].IpAddress)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r
\r
/**\r
Parse the address option and update the address infomation.\r
\r
+ @param[in] CurrentIa The pointer to the Ia Address in control blcok.\r
@param[in] IaInnerOpt The pointer to the buffer.\r
@param[in] IaInnerLen The length to parse.\r
@param[out] AddrNum The number of addresses.\r
**/\r
VOID\r
Dhcp6ParseAddrOption (\r
+ IN EFI_DHCP6_IA *CurrentIa,\r
IN UINT8 *IaInnerOpt,\r
IN UINT16 IaInnerLen,\r
OUT UINT32 *AddrNum,\r
UINT16 DataLen;\r
UINT16 OpCode;\r
UINT32 ValidLt;\r
+ UINT32 PreferredLt;\r
+ EFI_DHCP6_IA_ADDRESS *IaAddr;\r
\r
//\r
// The format of the IA Address option:\r
\r
while (Cursor < IaInnerOpt + IaInnerLen) {\r
//\r
- // Count the Ia address option with non-0 valid time.\r
+ // Refer to RFC3315 Chapter 18.1.8, we need to update lifetimes for any addresses in the IA option\r
+ // that the client already has recorded in the IA, and discard the Ia address option with 0 valid time.\r
//\r
OpCode = ReadUnaligned16 ((UINT16 *) Cursor);\r
- ValidLt = ReadUnaligned32 ((UINT32 *) (Cursor + 24));\r
- if (OpCode == HTONS (Dhcp6OptIaAddr) && ValidLt != 0) {\r
-\r
+ PreferredLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 20)));\r
+ ValidLt = NTOHL (ReadUnaligned32 ((UINT32 *) (Cursor + 24)));\r
+ IaAddr = (EFI_DHCP6_IA_ADDRESS *) (Cursor + 4);\r
+ if (OpCode == HTONS (Dhcp6OptIaAddr) && ValidLt >= PreferredLt &&\r
+ (Dhcp6AddrIsInCurrentIa(IaAddr, CurrentIa) || ValidLt !=0)) {\r
if (AddrBuf != NULL) {\r
- CopyMem (AddrBuf, Cursor + 4, sizeof (EFI_DHCP6_IA_ADDRESS));\r
- AddrBuf->PreferredLifetime = NTOHL (AddrBuf->PreferredLifetime);\r
- AddrBuf->ValidLifetime = NTOHL (AddrBuf->ValidLifetime);\r
+ CopyMem (AddrBuf, IaAddr, sizeof (EFI_DHCP6_IA_ADDRESS));\r
+ AddrBuf->PreferredLifetime = PreferredLt;\r
+ AddrBuf->ValidLifetime = ValidLt;\r
AddrBuf = (EFI_DHCP6_IA_ADDRESS *) ((UINT8 *) AddrBuf + sizeof (EFI_DHCP6_IA_ADDRESS));\r
}\r
-\r
(*AddrNum)++;\r
}\r
DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));\r
@retval EFI_NOT_FOUND No valid IA option is found.\r
@retval EFI_SUCCESS Create an IA control block successfully.\r
@retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
+ @retval EFI_DEVICE_ERROR An unexpected error.\r
\r
**/\r
EFI_STATUS\r
EFI_DHCP6_IA *Ia;\r
\r
if (Instance->IaCb.Ia == NULL) {\r
- return EFI_NOT_FOUND;\r
+ return EFI_DEVICE_ERROR;\r
}\r
\r
//\r
// Calculate the number of addresses for this Ia, excluding the addresses with\r
// the value 0 of valid lifetime.\r
//\r
- Dhcp6ParseAddrOption (IaInnerOpt, IaInnerLen, &AddrNum, NULL);\r
+ Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, NULL);\r
\r
if (AddrNum == 0) {\r
return EFI_NOT_FOUND;\r
Ia->State = Instance->IaCb.Ia->State;\r
Ia->IaAddressCount = AddrNum;\r
CopyMem (&Ia->Descriptor, &Instance->Config->IaDescriptor, sizeof (EFI_DHCP6_IA_DESCRIPTOR));\r
- Dhcp6ParseAddrOption (IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress);\r
+ Dhcp6ParseAddrOption (Instance->IaCb.Ia, IaInnerOpt, IaInnerLen, &AddrNum, Ia->IaAddress);\r
\r
//\r
// Free original IA resource.\r
@param[in] Ia The pointer to the Ia.\r
@param[in] T1 The time of T1.\r
@param[in] T2 The time of T2.\r
+ @param[in] MessageType Message type of DHCP6 package.\r
\r
@return Buf The position to append the next Ia option.\r
\r
IN OUT UINT8 *Buf,\r
IN EFI_DHCP6_IA *Ia,\r
IN UINT32 T1,\r
- IN UINT32 T2\r
+ IN UINT32 T2,\r
+ IN UINT32 MessageType\r
);\r
\r
/**\r
/**\r
Parse the address option and update the address info.\r
\r
+ @param[in] CurrentIa The pointer to the Ia Address in control blcok.\r
@param[in] IaInnerOpt The pointer to the buffer.\r
@param[in] IaInnerLen The length to parse.\r
@param[out] AddrNum The number of addresses.\r
**/\r
VOID\r
Dhcp6ParseAddrOption (\r
+ IN EFI_DHCP6_IA *CurrentIa,\r
IN UINT8 *IaInnerOpt,\r
IN UINT16 IaInnerLen,\r
OUT UINT32 *AddrNum,\r
@retval EFI_NOT_FOUND No valid IA option is found.\r
@retval EFI_SUCCESS Create an IA control block successfully.\r
@retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
+ @retval EFI_DEVICE_ERROR An unexpected error.\r
\r
**/\r
EFI_STATUS\r