mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[dhcp6] introduce Option::Iterator class (#11574)
This commit adds the `Option::Iterator` class for searching for and iterating over DHCPv6 options with a specific code within a message. The iteration can cover the entire message or be constrained to a given `OffsetRange`. The `Option::Iterator` is used to simplify the `Dhcp6::Client` and `Dhcp6.Server` implementations, particularly when iterating over `IaAddressOption`s within an `IaNaOption`.
This commit is contained in:
committed by
GitHub
parent
4b43f6de76
commit
a1de12fd49
@@ -402,9 +402,10 @@ Error Client::ProcessClientIdOption(const Message &aMessage)
|
||||
|
||||
Error Client::ProcessIaNaOption(const Message &aMessage)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
OffsetRange offsetRange;
|
||||
IaNaOption option;
|
||||
Error error = kErrorNone;
|
||||
OffsetRange offsetRange;
|
||||
IaNaOption option;
|
||||
Option::Iterator iterator;
|
||||
|
||||
SuccessOrExit(error = Option::FindOption(aMessage, Option::kIaNa, offsetRange));
|
||||
SuccessOrExit(error = aMessage.Read(offsetRange, option));
|
||||
@@ -416,28 +417,16 @@ Error Client::ProcessIaNaOption(const Message &aMessage)
|
||||
VerifyOrExit(StatusCodeOption::ReadStatusFrom(aMessage, offsetRange) == StatusCodeOption::kSuccess,
|
||||
error = kErrorFailed);
|
||||
|
||||
while (!offsetRange.IsEmpty())
|
||||
for (iterator.Init(aMessage, offsetRange, Option::kIaAddress); !iterator.IsDone(); iterator.Advance())
|
||||
{
|
||||
OffsetRange subOffsetRange;
|
||||
IaAddressOption addressOption;
|
||||
|
||||
error = Option::FindOption(aMessage, offsetRange, Option::kIaAddress, subOffsetRange);
|
||||
|
||||
if (error == kErrorNotFound)
|
||||
{
|
||||
error = kErrorNone;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
SuccessOrExit(error);
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(subOffsetRange, addressOption));
|
||||
SuccessOrExit(error = aMessage.Read(iterator.GetOptionOffsetRange(), addressOption));
|
||||
SuccessOrExit(error = ProcessIaAddressOption(addressOption));
|
||||
|
||||
// Update `offsetRange` to after the parsed `IaAddressOption`
|
||||
offsetRange.InitFromRange(subOffsetRange.GetEndOffset(), offsetRange.GetEndOffset());
|
||||
}
|
||||
|
||||
error = iterator.GetError();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -239,9 +239,10 @@ exit:
|
||||
|
||||
Error Server::ProcessIaNaOption(const Message &aMessage, uint32_t &aIaid)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
OffsetRange offsetRange;
|
||||
IaNaOption iaNaOption;
|
||||
Error error = kErrorNone;
|
||||
OffsetRange offsetRange;
|
||||
IaNaOption iaNaOption;
|
||||
Option::Iterator iterator;
|
||||
|
||||
SuccessOrExit(error = Option::FindOption(aMessage, Option::kIaNa, offsetRange));
|
||||
SuccessOrExit(error = aMessage.Read(offsetRange, iaNaOption));
|
||||
@@ -252,30 +253,18 @@ Error Server::ProcessIaNaOption(const Message &aMessage, uint32_t &aIaid)
|
||||
|
||||
mPrefixAgentsMask = 0;
|
||||
|
||||
// Iterate and parse sub-options within `IaNaOption`.
|
||||
// Iterate and parse `kIaAddress` sub-options within `IaNaOption`.
|
||||
|
||||
while (!offsetRange.IsEmpty())
|
||||
for (iterator.Init(aMessage, offsetRange, Option::kIaAddress); !iterator.IsDone(); iterator.Advance())
|
||||
{
|
||||
OffsetRange subOffsetRange;
|
||||
IaAddressOption addressOption;
|
||||
|
||||
error = Option::FindOption(aMessage, offsetRange, Option::kIaAddress, subOffsetRange);
|
||||
|
||||
if (error == kErrorNotFound)
|
||||
{
|
||||
error = kErrorNone;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
SuccessOrExit(error);
|
||||
|
||||
SuccessOrExit(error = aMessage.Read(subOffsetRange, addressOption));
|
||||
SuccessOrExit(error = aMessage.Read(iterator.GetOptionOffsetRange(), addressOption));
|
||||
ProcessIaAddressOption(addressOption);
|
||||
|
||||
// Update `offsetRange` to after the parsed `IaAddressOption`
|
||||
offsetRange.InitFromRange(subOffsetRange.GetEndOffset(), offsetRange.GetEndOffset());
|
||||
}
|
||||
|
||||
error = iterator.GetError();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -114,6 +114,58 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Option::Iterator
|
||||
|
||||
void Option::Iterator::Init(const Message &aMessage, Code aCode)
|
||||
{
|
||||
OffsetRange msgOffsetRange;
|
||||
|
||||
msgOffsetRange.InitFromMessageOffsetToEnd(aMessage);
|
||||
Init(aMessage, msgOffsetRange, aCode);
|
||||
}
|
||||
|
||||
void Option::Iterator::Init(const Message &aMessage, const OffsetRange &aMsgOffsetRange, Code aCode)
|
||||
{
|
||||
mMessage = &aMessage;
|
||||
mCode = aCode;
|
||||
mMsgOffsetRange = aMsgOffsetRange;
|
||||
mError = kErrorNone;
|
||||
mIsDone = false;
|
||||
Advance();
|
||||
}
|
||||
|
||||
void Option::Iterator::Advance(void)
|
||||
{
|
||||
VerifyOrExit(!mIsDone);
|
||||
|
||||
if (mMessage == nullptr)
|
||||
{
|
||||
mError = kErrorInvalidState;
|
||||
mIsDone = true;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
mError = Option::FindOption(*mMessage, mMsgOffsetRange, mCode, mOptionOffsetRange);
|
||||
|
||||
if (mError == kErrorNone)
|
||||
{
|
||||
// Update `mMsgOffsetRange` to start after the current option,
|
||||
// preparing the iterator for the next call to `Advance()`.
|
||||
|
||||
mMsgOffsetRange.InitFromRange(mOptionOffsetRange.GetEndOffset(), mMsgOffsetRange.GetEndOffset());
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
mOptionOffsetRange.Clear();
|
||||
|
||||
mError = (mError == kErrorNotFound) ? kErrorNone : mError;
|
||||
mIsDone = true;
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Eui64Duid
|
||||
|
||||
|
||||
@@ -178,6 +178,86 @@ public:
|
||||
kClientLastTransactionTime = 46, ///< Client Last Transaction Time Option.
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an iterator for searching for and iterating over DHCPv6 options with a specific code within a message.
|
||||
*/
|
||||
class Iterator : private Clearable<Iterator>
|
||||
{
|
||||
friend class Clearable<Iterator>;
|
||||
|
||||
public:
|
||||
/**
|
||||
* This is an iterator constructor that initializes the iterator to a cleared (invalid) state.
|
||||
*
|
||||
* An iterator in this state must be initialized using one of the `Init()` methods before use.
|
||||
*/
|
||||
Iterator(void) { Clear(); }
|
||||
|
||||
/**
|
||||
* Initializes the iterator and finds the first matching option within an entire message.
|
||||
*
|
||||
* The search is performed from `aMessage.GetOffset()` to the end of the message.
|
||||
*
|
||||
* @param[in] aMessage The message to search in.
|
||||
* @param[in] aCode The option code to search for.
|
||||
*/
|
||||
void Init(const Message &aMessage, Code aCode);
|
||||
|
||||
/**
|
||||
* Initializes the iterator and finds the first matching option within a specific range of a message.
|
||||
*
|
||||
* @param[in] aMessage The message to search in.
|
||||
* @param[in] aMsgOffsetRange The specific range within @p aMessage to search.
|
||||
* @param[in] aCode The option code to search for.
|
||||
*/
|
||||
void Init(const Message &aMessage, const OffsetRange &aMsgOffsetRange, Code aCode);
|
||||
|
||||
/**
|
||||
* Indicates whether the iteration is complete.
|
||||
*
|
||||
* The iteration is considered done when all matching options have been iterated through, or if an error
|
||||
* occurred during iteration. The `GetError()` method can be used to get the error status.
|
||||
*
|
||||
* Particularly, `IsDone() && GetError() == kErrorNone` indicates a successful end of the iteration (i.e., no
|
||||
* more matching options were found).
|
||||
*
|
||||
* @returns `true` if the iteration is complete, `false` otherwise.
|
||||
*/
|
||||
bool IsDone(void) const { return mIsDone; }
|
||||
|
||||
/**
|
||||
* Advances the iterator to the next matching option.
|
||||
*/
|
||||
void Advance(void);
|
||||
|
||||
/**
|
||||
* Gets the offset range of the current option matched by the iterator.
|
||||
*
|
||||
* The returned offset range refers to the matched option in the message when the iterator is not done
|
||||
* (`IsDone()` is `false`). Otherwise, an empty offset range is returned.
|
||||
*
|
||||
* @returns The `OffsetRange` of the current option.
|
||||
*/
|
||||
const OffsetRange &GetOptionOffsetRange(void) const { return mOptionOffsetRange; }
|
||||
|
||||
/**
|
||||
* Gets any error that occurred during the iteration.
|
||||
*
|
||||
* @retval kErrorNone Successfully iterated over options (so far).
|
||||
* @retval kErrorParse The options in the message were malformed and failed to parse.
|
||||
* @retval kErrorInvalidState The iterator was not initialized.
|
||||
*/
|
||||
Error GetError(void) const { return mError; }
|
||||
|
||||
private:
|
||||
const Message *mMessage;
|
||||
OffsetRange mMsgOffsetRange;
|
||||
OffsetRange mOptionOffsetRange;
|
||||
Code mCode;
|
||||
Error mError;
|
||||
bool mIsDone;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the DHCPv6 option code.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user