mirror of
https://github.com/espressif/openthread.git
synced 2026-07-10 22:30:21 +00:00
f90d50b220
This commit introduces the `Dhcp6PdClient` class, which implements DHCPv6 Prefix Delegation (PD) client functionality. It integrates with `BorderRouter::RoutingManager` and its `PdPrefixManager` sub-component. The CMake `OT_BORDER_ROUTING_DHCP6_PD_CLIENT` mapped to `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE` config enables this feature. Previously, the platform layer was expected to implement client functionality, acquiring and providing the delegated prefix(es) to the OT stack using `otPlatBorderRouter*` callbacks. This approach continues to be supported. The `Dhcp6PdClient` feature adds native support for this functionality in the OpenThread core. The `Dhcp6PdClient` implementation follows RFC 8415, focusing on prefix delegation and all required behaviors. The client follows the standard four-message Solicit/Advertise/Request/Reply exchange to obtain a delegated prefix, followed by a two-message Renew/Reply or Rebind/Reply exchange to extend the lifetime of the delegated prefix. When the prefix is no longer needed, a two-message Release/Reply exchange ends its lease. The current client implementation does not support the optional "Reconfigure Accept" mechanism. A set of `otPlatInfraIfDhcp6PdClient*` platform APIs are also introduced for use by the `Dhcp6PdClient`. These APIs are used to enable or disable listening for DHCPv6 messages and to handle sending and receiving them on the standard client and server UDP ports (546 and 547), effectively acting as a UDP socket. This commit also includes a comprehensive unit test covering various aspects of `Dhcp6PdClient`, including common behaviors and many specific edge cases.
2797 lines
98 KiB
C++
2797 lines
98 KiB
C++
/*
|
|
* Copyright (c) 2025, The OpenThread Authors.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the copyright holder nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <openthread/config.h>
|
|
|
|
#include "test_platform.h"
|
|
#include "test_util.hpp"
|
|
|
|
#include <openthread/dataset_ftd.h>
|
|
#include <openthread/thread.h>
|
|
#include <openthread/platform/border_routing.h>
|
|
#include <openthread/platform/infra_if.h>
|
|
|
|
#include "border_router/dhcp6_pd_client.hpp"
|
|
#include "common/arg_macros.hpp"
|
|
#include "common/array.hpp"
|
|
#include "common/num_utils.hpp"
|
|
#include "instance/instance.hpp"
|
|
|
|
namespace ot {
|
|
|
|
#if OT_CONFIG_DHCP6_PD_CLIENT_ENABLE
|
|
|
|
// Logs a message and adds current time (sNow) as "<hours>:<min>:<secs>.<msec>"
|
|
#define Log(...) \
|
|
printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 3600000), (sNow / 60000) % 60, \
|
|
(sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__))
|
|
|
|
static constexpr uint32_t kInfraIfIndex = 1;
|
|
|
|
static Instance *sInstance;
|
|
|
|
static uint32_t sNow = 0;
|
|
static uint32_t sAlarmTime;
|
|
static bool sAlarmOn = false;
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// Function prototypes
|
|
|
|
void ProcessTasklets(void);
|
|
void AdvanceTime(uint32_t aDuration);
|
|
void AdvanceNowTo(uint32_t aNewNow);
|
|
|
|
extern "C" {
|
|
|
|
#if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
|
|
void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
|
|
{
|
|
OT_UNUSED_VARIABLE(aLogLevel);
|
|
OT_UNUSED_VARIABLE(aLogRegion);
|
|
|
|
va_list args;
|
|
|
|
printf(" ");
|
|
va_start(args, aFormat);
|
|
vprintf(aFormat, args);
|
|
va_end(args);
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// otPlatAlarams
|
|
|
|
void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; }
|
|
|
|
void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
|
|
{
|
|
sAlarmOn = true;
|
|
sAlarmTime = aT0 + aDt;
|
|
}
|
|
|
|
uint32_t otPlatAlarmMilliGetNow(void) { return sNow; }
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// Heap
|
|
|
|
Array<void *, 500> sHeapAllocatedPtrs;
|
|
|
|
#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
|
|
|
|
void *otPlatCAlloc(size_t aNum, size_t aSize)
|
|
{
|
|
void *ptr = calloc(aNum, aSize);
|
|
|
|
SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr));
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void otPlatFree(void *aPtr)
|
|
{
|
|
if (aPtr != nullptr)
|
|
{
|
|
void **entry = sHeapAllocatedPtrs.Find(aPtr);
|
|
|
|
VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice");
|
|
sHeapAllocatedPtrs.Remove(*entry);
|
|
}
|
|
|
|
free(aPtr);
|
|
}
|
|
|
|
#endif
|
|
|
|
} // extern "C"
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
// Dhcp6Msg
|
|
|
|
struct Dhcp6Msg : public Clearable<Dhcp6Msg>
|
|
{
|
|
static constexpr uint16_t kMaxIaPds = 2;
|
|
static constexpr uint16_t kMaxIaPrefixes = 3;
|
|
static constexpr uint16_t kMaxReqOptions = 3;
|
|
static constexpr uint16_t kInfoStringSize = 100;
|
|
|
|
typedef String<kInfoStringSize> InfoString;
|
|
|
|
struct IaPrefix : public Clearable<IaPrefix>
|
|
{
|
|
Ip6::Prefix mPrefix;
|
|
uint32_t mPreferredLifetime;
|
|
uint32_t mValidLifetime;
|
|
};
|
|
|
|
using IaPrefixArray = Array<IaPrefix, kMaxIaPrefixes>;
|
|
|
|
struct IaPd : Clearable<IaPd>
|
|
{
|
|
bool Matches(uint32_t aIaid) const { return mIaid == aIaid; }
|
|
|
|
uint32_t mIaid;
|
|
uint32_t mT1;
|
|
uint32_t mT2;
|
|
bool mHasStatus;
|
|
uint16_t mStatusCode;
|
|
IaPrefixArray mIaPrefixes;
|
|
};
|
|
|
|
using IaPdArray = Array<IaPd, kMaxIaPds>;
|
|
|
|
struct Duid
|
|
{
|
|
InfoString ToString(void) const
|
|
{
|
|
InfoString string;
|
|
|
|
string.AppendHexBytes(mShared.mBytes, mLength);
|
|
return string;
|
|
}
|
|
|
|
union
|
|
{
|
|
uint8_t mBytes[Dhcp6::Duid::kMaxSize];
|
|
Dhcp6::Eui64Duid mEui64;
|
|
} mShared;
|
|
uint16_t mLength;
|
|
};
|
|
|
|
using ReqOptionArray = Array<uint16_t, kMaxReqOptions>;
|
|
|
|
void LogMsg(const char *aAction) const;
|
|
void ParseFrom(const Message &aMessage);
|
|
void PrepareMessage(Message &aMessage);
|
|
|
|
uint8_t mMsgType;
|
|
Dhcp6::TransactionId mTransactionId;
|
|
bool mHasStatus : 1;
|
|
bool mHasElapsedTime : 1;
|
|
bool mHasClientId : 1;
|
|
bool mHasServerId : 1;
|
|
bool mHasOptionRequest : 1;
|
|
bool mHasPreference : 1;
|
|
bool mHasServerUnicast : 1;
|
|
bool mHasSolMaxRt : 1;
|
|
uint16_t mStatusCode;
|
|
uint16_t mElapsedTime;
|
|
Duid mClientDuid;
|
|
Duid mServerDuid;
|
|
ReqOptionArray mRequestedOptions;
|
|
uint8_t mPreference;
|
|
Ip6::Address mServerAddress;
|
|
uint16_t mSolMaxRt;
|
|
IaPdArray mIaPds;
|
|
};
|
|
|
|
static const char *Dhcp6MsgTypeToString(uint8_t aMsgType)
|
|
{
|
|
const char *str = "Unknown";
|
|
|
|
switch (aMsgType)
|
|
{
|
|
case Dhcp6::kMsgTypeSolicit:
|
|
str = "Solicit";
|
|
break;
|
|
case Dhcp6::kMsgTypeAdvertise:
|
|
str = "Advertise";
|
|
break;
|
|
case Dhcp6::kMsgTypeRequest:
|
|
str = "Request";
|
|
break;
|
|
case Dhcp6::kMsgTypeRenew:
|
|
str = "Renew";
|
|
break;
|
|
case Dhcp6::kMsgTypeRebind:
|
|
str = "Rebind";
|
|
break;
|
|
case Dhcp6::kMsgTypeReply:
|
|
str = "Reply";
|
|
break;
|
|
case Dhcp6::kMsgTypeRelease:
|
|
str = "Release";
|
|
break;
|
|
case Dhcp6::kMsgTypeReconfigure:
|
|
str = "Reconfigure";
|
|
break;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
void Dhcp6Msg::LogMsg(const char *aAction) const
|
|
{
|
|
const uint8_t *txnId = reinterpret_cast<const uint8_t *>(&mTransactionId);
|
|
|
|
Log("%s %s message", aAction, Dhcp6MsgTypeToString(mMsgType));
|
|
|
|
Log(" %-13s : %02x%02x%02x", "TransactionId", txnId[0], txnId[1], txnId[2]);
|
|
|
|
if (mHasStatus)
|
|
{
|
|
Log(" %-13s : %u", "StatusCode", mStatusCode);
|
|
}
|
|
|
|
if (mHasElapsedTime)
|
|
{
|
|
Log(" %-13s : %u", "ElapsedTime", mElapsedTime);
|
|
}
|
|
|
|
if (mHasClientId)
|
|
{
|
|
Log(" %-13s : %s", "ClientId", mClientDuid.ToString().AsCString());
|
|
}
|
|
|
|
if (mHasServerId)
|
|
{
|
|
Log(" %-13s : %s", "ServerId", mServerDuid.ToString().AsCString());
|
|
}
|
|
|
|
if (mHasOptionRequest)
|
|
{
|
|
InfoString string;
|
|
|
|
string.Append("[ ");
|
|
for (uint16_t optionCode : mRequestedOptions)
|
|
{
|
|
string.Append("%u ", optionCode);
|
|
}
|
|
string.Append("]");
|
|
Log(" %-13s : %s", "ReqOptions", string.AsCString());
|
|
}
|
|
|
|
if (mHasPreference)
|
|
{
|
|
Log(" %-13s : %u", "Preference", mPreference);
|
|
}
|
|
|
|
if (mHasServerUnicast)
|
|
{
|
|
Log(" %-13s : %s", "ServerAddr", mServerAddress.ToString().AsCString());
|
|
}
|
|
|
|
if (mHasSolMaxRt)
|
|
{
|
|
Log(" %-13s : %lu", "SolMaxRt", ToUlong(mSolMaxRt));
|
|
}
|
|
|
|
for (const IaPd &iaPd : mIaPds)
|
|
{
|
|
Log(" %-13s : Iaid:%lu, T1:%lu, T2:%lu", "IaPd", ToUlong(iaPd.mIaid), ToUlong(iaPd.mT1), ToUlong(iaPd.mT2));
|
|
|
|
if (iaPd.mHasStatus)
|
|
{
|
|
Log(" %-11s : %u", "StatusCode", iaPd.mStatusCode);
|
|
}
|
|
|
|
for (const IaPrefix &iaPrefix : iaPd.mIaPrefixes)
|
|
{
|
|
Log(" %-11s : %s, preferred:%lu, valid:%lu", "Prefix", iaPrefix.mPrefix.ToString().AsCString(),
|
|
ToUlong(iaPrefix.mPreferredLifetime), ToUlong(iaPrefix.mValidLifetime));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Dhcp6Msg::ParseFrom(const Message &aMessage)
|
|
{
|
|
OffsetRange offsetRange;
|
|
OffsetRange optionOffsetRange;
|
|
OffsetRange subOptionOffsetRange;
|
|
Dhcp6::Header header;
|
|
IaPd *iaPd;
|
|
IaPrefix *iaPrefix;
|
|
union
|
|
{
|
|
Dhcp6::Option option;
|
|
Dhcp6::StatusCodeOption statusOption;
|
|
Dhcp6::ElapsedTimeOption elapsedTimeOption;
|
|
Dhcp6::PreferenceOption preferenceOption;
|
|
Dhcp6::ServerUnicastOption serverUnicastOption;
|
|
Dhcp6::SolMaxRtOption solMaxRtOption;
|
|
Dhcp6::IaPdOption iaPdOption;
|
|
Dhcp6::IaPrefixOption iaPrefixOption;
|
|
};
|
|
|
|
Clear();
|
|
offsetRange.InitFromMessageFullLength(aMessage);
|
|
|
|
SuccessOrQuit(aMessage.Read(offsetRange, header));
|
|
mMsgType = header.GetMsgType();
|
|
mTransactionId = header.GetTransactionId();
|
|
offsetRange.AdvanceOffset(sizeof(header));
|
|
|
|
while (!offsetRange.IsEmpty())
|
|
{
|
|
SuccessOrQuit(aMessage.Read(offsetRange, option));
|
|
VerifyOrQuit(offsetRange.Contains(option.GetSize()));
|
|
|
|
optionOffsetRange = offsetRange;
|
|
optionOffsetRange.ShrinkLength(static_cast<uint16_t>(option.GetSize()));
|
|
offsetRange.AdvanceOffset(option.GetSize());
|
|
|
|
switch (option.GetCode())
|
|
{
|
|
case Dhcp6::Option::kStatusCode:
|
|
VerifyOrQuit(!mHasStatus);
|
|
mHasStatus = true;
|
|
SuccessOrQuit(aMessage.Read(optionOffsetRange, statusOption));
|
|
mStatusCode = statusOption.GetStatusCode();
|
|
break;
|
|
|
|
case Dhcp6::Option::kElapsedTime:
|
|
VerifyOrQuit(!mHasElapsedTime);
|
|
mHasElapsedTime = true;
|
|
SuccessOrQuit(aMessage.Read(optionOffsetRange, elapsedTimeOption));
|
|
mElapsedTime = elapsedTimeOption.GetElapsedTime();
|
|
break;
|
|
|
|
case Dhcp6::Option::kClientId:
|
|
VerifyOrQuit(!mHasClientId);
|
|
mHasClientId = true;
|
|
optionOffsetRange.AdvanceOffset(sizeof(Dhcp6::Option));
|
|
VerifyOrQuit(optionOffsetRange.GetLength() >= Dhcp6::Duid::kMinSize);
|
|
VerifyOrQuit(optionOffsetRange.GetLength() <= Dhcp6::Duid::kMaxSize);
|
|
mClientDuid.mLength = optionOffsetRange.GetLength();
|
|
aMessage.ReadBytes(optionOffsetRange, mClientDuid.mShared.mBytes);
|
|
break;
|
|
|
|
case Dhcp6::Option::kServerId:
|
|
VerifyOrQuit(!mHasServerId);
|
|
mHasServerId = true;
|
|
optionOffsetRange.AdvanceOffset(sizeof(Dhcp6::Option));
|
|
VerifyOrQuit(optionOffsetRange.GetLength() >= Dhcp6::Duid::kMinSize);
|
|
VerifyOrQuit(optionOffsetRange.GetLength() <= Dhcp6::Duid::kMaxSize);
|
|
mServerDuid.mLength = optionOffsetRange.GetLength();
|
|
aMessage.ReadBytes(optionOffsetRange, mServerDuid.mShared.mBytes);
|
|
break;
|
|
|
|
case Dhcp6::Option::kOptionRequest:
|
|
VerifyOrQuit(!mHasOptionRequest);
|
|
mHasOptionRequest = true;
|
|
optionOffsetRange.AdvanceOffset(sizeof(Dhcp6::Option));
|
|
VerifyOrQuit(optionOffsetRange.GetLength() > 0);
|
|
|
|
while (!optionOffsetRange.IsEmpty())
|
|
{
|
|
uint16_t reqOption;
|
|
|
|
SuccessOrQuit(aMessage.Read(optionOffsetRange, reqOption));
|
|
reqOption = BigEndian::HostSwap16(reqOption);
|
|
SuccessOrQuit(mRequestedOptions.PushBack(reqOption));
|
|
optionOffsetRange.AdvanceOffset(sizeof(uint16_t));
|
|
}
|
|
|
|
break;
|
|
|
|
case Dhcp6::Option::kPreference:
|
|
VerifyOrQuit(!mHasPreference);
|
|
mHasPreference = true;
|
|
SuccessOrQuit(aMessage.Read(optionOffsetRange, preferenceOption));
|
|
mPreference = preferenceOption.GetPreference();
|
|
break;
|
|
|
|
case Dhcp6::Option::kServerUnicast:
|
|
VerifyOrQuit(!mHasServerUnicast);
|
|
mHasServerUnicast = true;
|
|
SuccessOrQuit(aMessage.Read(optionOffsetRange, serverUnicastOption));
|
|
mServerAddress = serverUnicastOption.GetServerAddress();
|
|
break;
|
|
|
|
case Dhcp6::Option::kSolMaxRt:
|
|
VerifyOrQuit(!mHasSolMaxRt);
|
|
mHasSolMaxRt = true;
|
|
SuccessOrQuit(aMessage.Read(optionOffsetRange, solMaxRtOption));
|
|
mSolMaxRt = solMaxRtOption.GetSolMaxRt();
|
|
break;
|
|
|
|
case Dhcp6::Option::kIaPd:
|
|
SuccessOrQuit(aMessage.Read(optionOffsetRange, iaPdOption));
|
|
optionOffsetRange.AdvanceOffset(sizeof(iaPdOption));
|
|
VerifyOrQuit(!mIaPds.ContainsMatching(iaPdOption.GetIaid()));
|
|
|
|
iaPd = mIaPds.PushBack();
|
|
VerifyOrQuit(iaPd != nullptr);
|
|
iaPd->Clear();
|
|
iaPd->mIaid = iaPdOption.GetIaid();
|
|
iaPd->mT1 = iaPdOption.GetT1();
|
|
iaPd->mT2 = iaPdOption.GetT2();
|
|
|
|
while (!optionOffsetRange.IsEmpty())
|
|
{
|
|
SuccessOrQuit(aMessage.Read(optionOffsetRange, option));
|
|
VerifyOrQuit(optionOffsetRange.Contains(option.GetSize()));
|
|
|
|
subOptionOffsetRange = optionOffsetRange;
|
|
subOptionOffsetRange.ShrinkLength(static_cast<uint16_t>(option.GetSize()));
|
|
|
|
optionOffsetRange.AdvanceOffset(option.GetSize());
|
|
|
|
switch (option.GetCode())
|
|
{
|
|
case Dhcp6::Option::kStatusCode:
|
|
VerifyOrQuit(!iaPd->mHasStatus);
|
|
iaPd->mHasStatus = true;
|
|
SuccessOrQuit(aMessage.Read(subOptionOffsetRange, statusOption));
|
|
iaPd->mStatusCode = statusOption.GetStatusCode();
|
|
break;
|
|
|
|
case Dhcp6::Option::kIaPrefix:
|
|
SuccessOrQuit(aMessage.Read(subOptionOffsetRange, iaPrefixOption));
|
|
iaPrefix = iaPd->mIaPrefixes.PushBack();
|
|
VerifyOrQuit(iaPrefix != nullptr);
|
|
iaPrefix->Clear();
|
|
iaPrefixOption.GetPrefix(iaPrefix->mPrefix);
|
|
iaPrefix->mPreferredLifetime = iaPrefixOption.GetPreferredLifetime();
|
|
iaPrefix->mValidLifetime = iaPrefixOption.GetValidLifetime();
|
|
break;
|
|
|
|
default:
|
|
// Unexpected sub-option
|
|
VerifyOrQuit(false);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// Unexpected option
|
|
VerifyOrQuit(false);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Dhcp6Msg::PrepareMessage(Message &aMessage)
|
|
{
|
|
Dhcp6::Header header;
|
|
union
|
|
{
|
|
Dhcp6::Option option;
|
|
Dhcp6::StatusCodeOption statusOption;
|
|
Dhcp6::ElapsedTimeOption elapsedTimeOption;
|
|
Dhcp6::PreferenceOption preferenceOption;
|
|
Dhcp6::ServerUnicastOption serverUnicastOption;
|
|
Dhcp6::SolMaxRtOption solMaxRtOption;
|
|
Dhcp6::IaPdOption iaPdOption;
|
|
Dhcp6::IaPrefixOption iaPrefixOption;
|
|
};
|
|
|
|
header.SetMsgType(static_cast<Dhcp6::MsgType>(mMsgType));
|
|
header.SetTransactionId(mTransactionId);
|
|
SuccessOrQuit(aMessage.Append(header));
|
|
|
|
if (mHasStatus)
|
|
{
|
|
statusOption.Init();
|
|
statusOption.SetStatusCode(static_cast<Dhcp6::StatusCodeOption::Status>(mStatusCode));
|
|
SuccessOrQuit(aMessage.Append(statusOption));
|
|
}
|
|
|
|
if (mHasElapsedTime)
|
|
{
|
|
elapsedTimeOption.Init();
|
|
elapsedTimeOption.SetElapsedTime(mElapsedTime);
|
|
SuccessOrQuit(aMessage.Append(elapsedTimeOption));
|
|
}
|
|
|
|
if (mHasClientId)
|
|
{
|
|
SuccessOrQuit(Dhcp6::Option::AppendOption(aMessage, Dhcp6::Option::kClientId, mClientDuid.mShared.mBytes,
|
|
mClientDuid.mLength));
|
|
}
|
|
|
|
if (mHasServerId)
|
|
{
|
|
SuccessOrQuit(Dhcp6::Option::AppendOption(aMessage, Dhcp6::Option::kServerId, mServerDuid.mShared.mBytes,
|
|
mServerDuid.mLength));
|
|
}
|
|
|
|
if (mHasOptionRequest)
|
|
{
|
|
option.SetCode(Dhcp6::Option::kOptionRequest);
|
|
option.SetLength(mRequestedOptions.GetLength() * sizeof(uint16_t));
|
|
SuccessOrQuit(aMessage.Append(option));
|
|
|
|
for (uint16_t reqOption : mRequestedOptions)
|
|
{
|
|
uint16_t swapedOption = BigEndian::HostSwap16(reqOption);
|
|
|
|
SuccessOrQuit(aMessage.Append(swapedOption));
|
|
}
|
|
}
|
|
|
|
if (mHasPreference)
|
|
{
|
|
preferenceOption.Init();
|
|
preferenceOption.SetPreference(mPreference);
|
|
SuccessOrQuit(aMessage.Append(preferenceOption));
|
|
}
|
|
|
|
if (mHasServerUnicast)
|
|
{
|
|
serverUnicastOption.Init();
|
|
serverUnicastOption.SetServerAddress(mServerAddress);
|
|
SuccessOrQuit(aMessage.Append(serverUnicastOption));
|
|
}
|
|
|
|
if (mHasSolMaxRt)
|
|
{
|
|
solMaxRtOption.Init();
|
|
solMaxRtOption.SetSolMaxRt(mSolMaxRt);
|
|
SuccessOrQuit(aMessage.Append(solMaxRtOption));
|
|
}
|
|
|
|
for (const IaPd &iaPd : mIaPds)
|
|
{
|
|
uint16_t length;
|
|
|
|
length = sizeof(Dhcp6::IaPdOption) - sizeof(Dhcp6::Option);
|
|
|
|
if (mHasStatus)
|
|
{
|
|
length += sizeof(Dhcp6::StatusCodeOption);
|
|
}
|
|
|
|
length += sizeof(Dhcp6::IaPrefixOption) * iaPd.mIaPrefixes.GetLength();
|
|
|
|
iaPdOption.Init();
|
|
iaPdOption.SetLength(length);
|
|
iaPdOption.SetIaid(iaPd.mIaid);
|
|
iaPdOption.SetT1(iaPd.mT1);
|
|
iaPdOption.SetT2(iaPd.mT2);
|
|
SuccessOrQuit(aMessage.Append(iaPdOption));
|
|
|
|
if (mHasStatus)
|
|
{
|
|
statusOption.Init();
|
|
statusOption.SetStatusCode(static_cast<Dhcp6::StatusCodeOption::Status>(iaPd.mStatusCode));
|
|
SuccessOrQuit(aMessage.Append(statusOption));
|
|
}
|
|
|
|
for (const IaPrefix &iaPrefix : iaPd.mIaPrefixes)
|
|
{
|
|
iaPrefixOption.Init();
|
|
iaPrefixOption.SetPreferredLifetime(iaPrefix.mPreferredLifetime);
|
|
iaPrefixOption.SetValidLifetime(iaPrefix.mValidLifetime);
|
|
iaPrefixOption.SetPrefix(iaPrefix.mPrefix);
|
|
SuccessOrQuit(aMessage.Append(iaPrefixOption));
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// Dhcp6RxMsg
|
|
|
|
static const uint32_t kExpectedIaid = 0;
|
|
static const uint8_t kExpectedPrefixLength = 64;
|
|
|
|
static const uint16_t kMaxDhcp6RxMsgs = 32;
|
|
|
|
class Dhcp6RxMsg : public Dhcp6Msg
|
|
{
|
|
public:
|
|
void ValidateAsSolicit(void) const;
|
|
|
|
void ValidateAsRequest(const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr = nullptr) const;
|
|
|
|
void ValidateAsRenew(const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr = nullptr) const;
|
|
|
|
void ValidateAsRebind(const Ip6::Prefix &aPrefix) const;
|
|
|
|
void ValidateAsRelease(const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr = nullptr) const;
|
|
|
|
uint32_t mRxTime;
|
|
Ip6::Address mDstAddr;
|
|
|
|
private:
|
|
void Validate(Dhcp6::MsgType aMsgType,
|
|
const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress *aServerMacAddr = nullptr,
|
|
const Ip6::Address *aServerIp6Addr = nullptr) const;
|
|
};
|
|
|
|
Ip6::Prefix PrefixFromString(const char *aString, uint8_t aPrefixLength)
|
|
{
|
|
Ip6::Prefix prefix;
|
|
|
|
SuccessOrQuit(AsCoreType(&prefix.mPrefix).FromString(aString));
|
|
prefix.mLength = aPrefixLength;
|
|
|
|
return prefix;
|
|
}
|
|
|
|
Ip6::Address AddressFromString(const char *aString)
|
|
{
|
|
Ip6::Address address;
|
|
|
|
SuccessOrQuit(address.FromString(aString));
|
|
|
|
return address;
|
|
}
|
|
|
|
void Dhcp6RxMsg::ValidateAsSolicit(void) const
|
|
{
|
|
Ip6::Prefix prefix;
|
|
|
|
VerifyOrQuit(mMsgType == Dhcp6::kMsgTypeSolicit);
|
|
VerifyOrQuit(mDstAddr == AddressFromString("ff02::1:2"));
|
|
|
|
prefix.Clear();
|
|
prefix.SetLength(kExpectedPrefixLength);
|
|
|
|
Validate(Dhcp6::kMsgTypeSolicit, prefix);
|
|
}
|
|
|
|
void Dhcp6RxMsg::ValidateAsRequest(const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr) const
|
|
{
|
|
Validate(Dhcp6::kMsgTypeRequest, aPrefix, &aServerMacAddr, aServerIp6Addr);
|
|
}
|
|
|
|
void Dhcp6RxMsg::ValidateAsRenew(const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr) const
|
|
{
|
|
Validate(Dhcp6::kMsgTypeRenew, aPrefix, &aServerMacAddr, aServerIp6Addr);
|
|
}
|
|
|
|
void Dhcp6RxMsg::ValidateAsRebind(const Ip6::Prefix &aPrefix) const { Validate(Dhcp6::kMsgTypeRebind, aPrefix); }
|
|
|
|
void Dhcp6RxMsg::ValidateAsRelease(const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr) const
|
|
{
|
|
Validate(Dhcp6::kMsgTypeRelease, aPrefix, &aServerMacAddr, aServerIp6Addr);
|
|
}
|
|
|
|
void Dhcp6RxMsg::Validate(Dhcp6::MsgType aMsgType,
|
|
const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress *aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr) const
|
|
{
|
|
VerifyOrQuit(mMsgType == aMsgType);
|
|
|
|
if (aServerIp6Addr != nullptr)
|
|
{
|
|
VerifyOrQuit(mDstAddr == *aServerIp6Addr);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(mDstAddr == AddressFromString("ff02::1:2"));
|
|
}
|
|
|
|
VerifyOrQuit(!mHasStatus);
|
|
VerifyOrQuit(!mHasPreference);
|
|
VerifyOrQuit(!mHasServerUnicast);
|
|
VerifyOrQuit(!mHasSolMaxRt);
|
|
|
|
VerifyOrQuit(mHasElapsedTime);
|
|
|
|
VerifyOrQuit(mHasOptionRequest);
|
|
VerifyOrQuit(mRequestedOptions.GetLength() == 1);
|
|
VerifyOrQuit(mRequestedOptions[0] == Dhcp6::Option::kSolMaxRt);
|
|
|
|
VerifyOrQuit(mHasClientId);
|
|
VerifyOrQuit(mClientDuid.mShared.mEui64.IsValid());
|
|
VerifyOrQuit(mClientDuid.mShared.mEui64.GetLinkLayerAddress() == sInstance->Get<Mac::Mac>().GetExtAddress());
|
|
|
|
if (aServerMacAddr != nullptr)
|
|
{
|
|
VerifyOrQuit(mHasServerId);
|
|
VerifyOrQuit(mServerDuid.mShared.mEui64.IsValid());
|
|
VerifyOrQuit(mServerDuid.mShared.mEui64.GetLinkLayerAddress() == *aServerMacAddr);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!mHasServerId);
|
|
}
|
|
|
|
VerifyOrQuit(mIaPds.GetLength() == 1);
|
|
VerifyOrQuit(mIaPds[0].mIaid == kExpectedIaid);
|
|
VerifyOrQuit(mIaPds[0].mT1 == 0);
|
|
VerifyOrQuit(mIaPds[0].mT2 == 0);
|
|
VerifyOrQuit(!mIaPds[0].mHasStatus);
|
|
VerifyOrQuit(mIaPds[0].mIaPrefixes.GetLength() == 1);
|
|
VerifyOrQuit(mIaPds[0].mIaPrefixes[0].mPrefix == aPrefix);
|
|
VerifyOrQuit(mIaPds[0].mIaPrefixes[0].mPreferredLifetime == 0);
|
|
VerifyOrQuit(mIaPds[0].mIaPrefixes[0].mValidLifetime == 0);
|
|
}
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
struct Dhcp6TxMsg : public Dhcp6Msg
|
|
{
|
|
struct PrefixInfo
|
|
{
|
|
uint16_t mIaid;
|
|
uint32_t mT1;
|
|
uint32_t mT2;
|
|
uint32_t mPreferredLifetime;
|
|
uint32_t mValidLifetime;
|
|
Ip6::Prefix mPrefix;
|
|
};
|
|
|
|
void PrepareAdvertise(const Dhcp6RxMsg &aClientMsg,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr = nullptr);
|
|
void PrepareReply(const Dhcp6RxMsg &aClientMsg,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr = nullptr);
|
|
void AddIaPrefix(const PrefixInfo &aInfo);
|
|
void Send(void);
|
|
};
|
|
|
|
void Dhcp6TxMsg::PrepareAdvertise(const Dhcp6RxMsg &aClientMsg,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr)
|
|
{
|
|
Clear();
|
|
mMsgType = Dhcp6::kMsgTypeAdvertise;
|
|
mTransactionId = aClientMsg.mTransactionId;
|
|
mHasClientId = true;
|
|
mHasServerId = true;
|
|
mClientDuid = aClientMsg.mClientDuid;
|
|
mServerDuid.mShared.mEui64.Init(aServerMacAddr);
|
|
mServerDuid.mLength = sizeof(Dhcp6::Eui64Duid);
|
|
|
|
if (aServerIp6Addr != nullptr)
|
|
{
|
|
mHasServerUnicast = true;
|
|
mServerAddress = *aServerIp6Addr;
|
|
}
|
|
}
|
|
|
|
void Dhcp6TxMsg::PrepareReply(const Dhcp6RxMsg &aClientMsg,
|
|
const Mac::ExtAddress &aServerMacAddr,
|
|
const Ip6::Address *aServerIp6Addr)
|
|
{
|
|
Clear();
|
|
mMsgType = Dhcp6::kMsgTypeReply;
|
|
mTransactionId = aClientMsg.mTransactionId;
|
|
mHasClientId = true;
|
|
mHasServerId = true;
|
|
mClientDuid = aClientMsg.mClientDuid;
|
|
mServerDuid.mShared.mEui64.Init(aServerMacAddr);
|
|
mServerDuid.mLength = sizeof(Dhcp6::Eui64Duid);
|
|
|
|
if (aServerIp6Addr != nullptr)
|
|
{
|
|
mHasServerUnicast = true;
|
|
mServerAddress = *aServerIp6Addr;
|
|
}
|
|
}
|
|
|
|
void Dhcp6TxMsg::AddIaPrefix(const PrefixInfo &aInfo)
|
|
{
|
|
IaPd *iaPd = nullptr;
|
|
IaPrefix *iaPrefix;
|
|
|
|
for (IaPd &ia : mIaPds)
|
|
{
|
|
if (ia.mIaid == aInfo.mIaid)
|
|
{
|
|
iaPd = &ia;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (iaPd == nullptr)
|
|
{
|
|
iaPd = mIaPds.PushBack();
|
|
VerifyOrQuit(iaPd != nullptr);
|
|
}
|
|
|
|
iaPd->mIaid = aInfo.mIaid;
|
|
iaPd->mT1 = aInfo.mT1;
|
|
iaPd->mT2 = aInfo.mT2;
|
|
|
|
iaPrefix = iaPd->mIaPrefixes.PushBack();
|
|
VerifyOrQuit(iaPrefix != nullptr);
|
|
iaPrefix->mPrefix = aInfo.mPrefix;
|
|
iaPrefix->mPreferredLifetime = aInfo.mPreferredLifetime;
|
|
iaPrefix->mValidLifetime = aInfo.mValidLifetime;
|
|
}
|
|
|
|
void Dhcp6TxMsg::Send(void)
|
|
{
|
|
Message *message;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
PrepareMessage(*message);
|
|
|
|
LogMsg("Sending");
|
|
|
|
otPlatInfraIfDhcp6PdClientHandleReceived(sInstance, message, kInfraIfIndex);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// otPlatInfraIf
|
|
|
|
typedef BorderRouter::Dhcp6PdClient::DelegatedPrefix DelegatedPrefix;
|
|
|
|
static bool sDhcp6ListeningEnabled = false;
|
|
static Array<Dhcp6RxMsg, kMaxDhcp6RxMsgs> sDhcp6RxMsgs;
|
|
|
|
extern "C" {
|
|
|
|
void otPlatInfraIfDhcp6PdClientSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
|
{
|
|
Log("otPlatInfraIfDhcp6PdClientSetListeningEnabled(aEnable:%u)", aEnable);
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aInfraIfIndex == kInfraIfIndex);
|
|
sDhcp6ListeningEnabled = aEnable;
|
|
}
|
|
|
|
void otPlatInfraIfDhcp6PdClientSend(otInstance *aInstance,
|
|
otMessage *aMessage,
|
|
otIp6Address *aDestAddress,
|
|
uint32_t aInfraIfIndex)
|
|
{
|
|
Message *message = AsCoreTypePtr(aMessage);
|
|
Dhcp6RxMsg *rxMsg;
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(message != nullptr);
|
|
VerifyOrQuit(aDestAddress != nullptr);
|
|
|
|
Log("otPlatInfraIfDhcp6PdClientSend(%s)", AsCoreType(aDestAddress).ToString().AsCString());
|
|
|
|
rxMsg = sDhcp6RxMsgs.PushBack();
|
|
VerifyOrQuit(rxMsg != nullptr);
|
|
|
|
rxMsg->ParseFrom(*message);
|
|
rxMsg->LogMsg("Received");
|
|
|
|
rxMsg->mRxTime = sNow;
|
|
rxMsg->mDstAddr = AsCoreType(aDestAddress);
|
|
|
|
message->Free();
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void ProcessTasklets(void)
|
|
{
|
|
do
|
|
{
|
|
otTaskletsProcess(sInstance);
|
|
} while (otTaskletsArePending(sInstance));
|
|
}
|
|
|
|
void AdvanceTime(uint32_t aDuration)
|
|
{
|
|
uint32_t time = sNow + aDuration;
|
|
|
|
Log("AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000);
|
|
|
|
while (TimeMilli(sAlarmTime) <= TimeMilli(time))
|
|
{
|
|
ProcessTasklets();
|
|
sNow = sAlarmTime;
|
|
otPlatAlarmMilliFired(sInstance);
|
|
}
|
|
|
|
ProcessTasklets();
|
|
sNow = time;
|
|
}
|
|
|
|
void AdvanceNowTo(uint32_t aNewNow)
|
|
{
|
|
VerifyOrQuit(aNewNow >= sNow);
|
|
AdvanceTime(aNewNow - sNow);
|
|
}
|
|
|
|
void InitTest(void)
|
|
{
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Initialize OT instance.
|
|
|
|
sNow = 0;
|
|
sAlarmOn = false;
|
|
sInstance = static_cast<Instance *>(testInitInstance());
|
|
|
|
sDhcp6ListeningEnabled = false;
|
|
sDhcp6RxMsgs.Clear();
|
|
|
|
SuccessOrQuit(otBorderRoutingInit(sInstance, kInfraIfIndex, /* aInfraIfIsRunning */ true));
|
|
AdvanceTime(100);
|
|
}
|
|
|
|
void FinalizeTest(void) { testFreeInstance(sInstance); }
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestDhcp6PdPrefixDelegation(bool aShortPrefix, bool aAddServerUnicastOption)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Ip6::Prefix adjustedPrefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
const DelegatedPrefix *delegatedPrefix;
|
|
Ip6::Address serverAddr;
|
|
const Ip6::Address *serverIp6Addr;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdPrefixDelegation(aShortPrefix:%u, aAddServerUnicastOption:%u)", aShortPrefix,
|
|
aAddServerUnicastOption);
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
if (aShortPrefix)
|
|
{
|
|
prefix = PrefixFromString("2001:1111::", 48);
|
|
adjustedPrefix = PrefixFromString("2001:1111::", 64);
|
|
}
|
|
else
|
|
{
|
|
prefix = PrefixFromString("2001:2222::", 64);
|
|
adjustedPrefix = prefix;
|
|
}
|
|
|
|
// If `aAddServerUnicastOption` is enabled, we add `ServerUnicastOption`
|
|
// to Advertise and Reply messages. This prompts the client to use a
|
|
// specific server unicast address instead of the all-servers multicast
|
|
// address. The client's use of this address is then validated when it
|
|
// sends Request or Renew messages throughout all the test steps.
|
|
|
|
serverAddr = AddressFromString("fe80::1");
|
|
serverIp6Addr = (aAddServerUnicastOption ? &serverAddr : 0);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and wait for the first two Solicit messages");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
AdvanceTime(2200);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mTransactionId == sDhcp6RxMsgs[1].mTransactionId);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr, serverIp6Addr);
|
|
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate Request message is received");
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr, serverIp6Addr);
|
|
|
|
for (uint16_t iter = 0; iter < 3; iter++)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Reply message to %s", iter == 0 ? "Request" : "Renew");
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr, serverIp6Addr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate the delegated prefix on the client");
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == adjustedPrefix);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == prefixInfo.mT1);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == prefixInfo.mT2);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == prefixInfo.mPreferredLifetime);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that no messages is received until renew time T1");
|
|
|
|
AdvanceTime(prefixInfo.mT1 * 1000 - 1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.IsEmpty());
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that at T1 time Renew message is received");
|
|
|
|
AdvanceTime(5);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
|
|
sDhcp6RxMsgs[0].ValidateAsRenew(prefix, serverMacAddr, serverIp6Addr);
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mElapsedTime == 0);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Do not send a Reply to the Renew. Wait till T2 time and check the Renew message retries");
|
|
|
|
AdvanceTime((prefixInfo.mT2 - prefixInfo.mT1) * 1000 - 6);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() > 1);
|
|
|
|
for (uint16_t index = 2; index < sDhcp6RxMsgs.GetLength(); index++)
|
|
{
|
|
sDhcp6RxMsgs[index].ValidateAsRenew(prefix, serverMacAddr, serverIp6Addr);
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mElapsedTime > 0);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that the delegated prefix on the client remains unchanged");
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == adjustedPrefix);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == prefixInfo.mT1);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == prefixInfo.mT2);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == prefixInfo.mPreferredLifetime);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that Rebind message is received at T2 time");
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
AdvanceTime(10);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRebind(prefix);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Reply to Rebind");
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr, serverIp6Addr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that the delegated prefix on the client is renewed");
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == adjustedPrefix);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == prefixInfo.mT1);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == prefixInfo.mT2);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == prefixInfo.mPreferredLifetime);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that no message is received until renew time T1");
|
|
|
|
AdvanceTime(prefixInfo.mT1 * 1000 - 1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.IsEmpty());
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate Renew message is received");
|
|
|
|
AdvanceTime(5);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
|
|
sDhcp6RxMsgs[0].ValidateAsRenew(prefix, serverMacAddr, serverIp6Addr);
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mElapsedTime == 0);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Wait till T2 time and check that Renew message is retried");
|
|
|
|
AdvanceTime((prefixInfo.mT2 - prefixInfo.mT1) * 1000 - 6);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() > 1);
|
|
|
|
for (uint16_t index = 2; index < sDhcp6RxMsgs.GetLength(); index++)
|
|
{
|
|
sDhcp6RxMsgs[index].ValidateAsRenew(prefix, serverMacAddr, serverIp6Addr);
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mElapsedTime > 0);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that Rebind message is received after T2 time");
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
AdvanceTime(5);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRebind(prefix);
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mElapsedTime == 0);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Wait till preferred time and check that Rebind message is now retried");
|
|
|
|
AdvanceTime((prefixInfo.mPreferredLifetime - prefixInfo.mT2) * 1000 - 6);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() > 1);
|
|
|
|
for (uint16_t index = 2; index < sDhcp6RxMsgs.GetLength(); index++)
|
|
{
|
|
sDhcp6RxMsgs[index].ValidateAsRebind(prefix);
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mElapsedTime > 0);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that the delegated prefix is still present on the client right before its expire time");
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == adjustedPrefix);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == prefixInfo.mT1);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == prefixInfo.mT2);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == prefixInfo.mPreferredLifetime);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that the delegated prefix is removed after its expire time");
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
AdvanceTime(5);
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that Solicit messages are sent again");
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() > 1);
|
|
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mElapsedTime == 0);
|
|
|
|
for (uint16_t index = 2; index < sDhcp6RxMsgs.GetLength(); index++)
|
|
{
|
|
sDhcp6RxMsgs[index].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mElapsedTime > 0);
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement, check Request message and respond with Reply");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr, serverIp6Addr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr, serverIp6Addr);
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr, serverIp6Addr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate the delegated prefix on the client");
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == adjustedPrefix);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == prefixInfo.mT1);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == prefixInfo.mT2);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == prefixInfo.mPreferredLifetime);
|
|
|
|
AdvanceTime(5 * 1000);
|
|
VerifyOrQuit(sDhcp6RxMsgs.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client, and validate that Release message is received");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRelease(prefix, serverMacAddr, serverIp6Addr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Reply to Release message and check that no more messages is received");
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr, serverIp6Addr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdPrefixDelegation(aShortPrefix:%u, aAddServerUnicastOption:%u)", aShortPrefix,
|
|
aAddServerUnicastOption);
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestDhcp6PdSolicitRetries(void)
|
|
{
|
|
static uint32_t kMaxTimeout = 3600 * 1000;
|
|
|
|
uint16_t heapAllocations;
|
|
uint32_t firstRxTime;
|
|
uint32_t timeout;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdSolicitRetries");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and check initial delay for first Solicit");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
// Initial random delay of [0, 1000] msec to send first solicit
|
|
AdvanceTime(1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mElapsedTime == 0);
|
|
firstRxTime = sDhcp6RxMsgs[0].mRxTime;
|
|
|
|
VerifyOrQuit(sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Wait for more than 30 minutes and collect all Solicit messages");
|
|
|
|
AdvanceTime(20000 * 1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() >= 14);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate the retx timing of Solicit messages");
|
|
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[1].mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
VerifyOrQuit(sDhcp6RxMsgs[1].mElapsedTime == (sDhcp6RxMsgs[1].mRxTime - firstRxTime) / 10);
|
|
timeout = sDhcp6RxMsgs[1].mRxTime - firstRxTime;
|
|
|
|
// The initial time should be randomly picked from [1, 1.1] sec.
|
|
|
|
VerifyOrQuit(timeout >= 1000);
|
|
VerifyOrQuit(timeout <= 1100);
|
|
|
|
for (uint16_t index = 2; index < sDhcp6RxMsgs.GetLength(); index++)
|
|
{
|
|
uint32_t newTimeout;
|
|
uint32_t minTimeout;
|
|
uint32_t maxTimeout;
|
|
uint32_t elapsedTime;
|
|
|
|
sDhcp6RxMsgs[index].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
|
|
newTimeout = sDhcp6RxMsgs[index].mRxTime - sDhcp6RxMsgs[index - 1].mRxTime;
|
|
|
|
minTimeout = 2 * timeout - timeout / 10;
|
|
maxTimeout = 2 * timeout + timeout / 10;
|
|
|
|
if (maxTimeout > kMaxTimeout)
|
|
{
|
|
minTimeout = Min(minTimeout, kMaxTimeout - kMaxTimeout / 10);
|
|
maxTimeout = kMaxTimeout + kMaxTimeout / 10;
|
|
}
|
|
|
|
Log("Solicit %2u -> timeout:%lu, min:%lu, max:%lu", index, ToUlong(newTimeout), ToUlong(minTimeout),
|
|
ToUlong(maxTimeout));
|
|
|
|
elapsedTime = (sDhcp6RxMsgs[index].mRxTime - firstRxTime) / 10;
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mElapsedTime == ClampToUint16(elapsedTime));
|
|
|
|
VerifyOrQuit(newTimeout >= minTimeout);
|
|
VerifyOrQuit(newTimeout <= maxTimeout);
|
|
|
|
timeout = newTimeout;
|
|
}
|
|
|
|
VerifyOrQuit(sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client and make sure there are no more transmissions");
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
|
|
AdvanceTime(200 * 1000);
|
|
VerifyOrQuit(sDhcp6RxMsgs.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start again and check the Solicit message tx");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
// Initial random delay of [0, 1000] msec to send first solicit
|
|
AdvanceTime(1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mElapsedTime == 0);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
AdvanceTime(15 * 1000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdSolicitRetries");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestDhcp6PdRequestRetries(void)
|
|
{
|
|
static constexpr uint32_t kInitialRequestTimeout = 1000;
|
|
static constexpr uint32_t kMaxRequestTimeout = 30 * 1000;
|
|
static constexpr uint16_t kMaxRequestRetxCount = 10;
|
|
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
uint32_t firstRxTime;
|
|
uint32_t timeout;
|
|
uint32_t newTimeout;
|
|
uint32_t minTimeout;
|
|
uint32_t maxTimeout;
|
|
uint32_t elapsedTime;
|
|
uint16_t index;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdRequestRetries");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix = PrefixFromString("2001:aa::", 64);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and wait for the first two Solicit messages");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
AdvanceTime(2200);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mTransactionId == sDhcp6RxMsgs[1].mTransactionId);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate Request message is received");
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr);
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mElapsedTime == 0);
|
|
firstRxTime = sDhcp6RxMsgs[0].mRxTime;
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Wait for 5 minutes and collect all messages");
|
|
|
|
AdvanceTime(300 * 1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() > kMaxRequestRetxCount);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate the retx timing of Request messages");
|
|
|
|
sDhcp6RxMsgs[1].ValidateAsRequest(prefix, serverMacAddr);
|
|
VerifyOrQuit(sDhcp6RxMsgs[1].mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
VerifyOrQuit(sDhcp6RxMsgs[1].mElapsedTime == (sDhcp6RxMsgs[1].mRxTime - firstRxTime) / 10);
|
|
timeout = sDhcp6RxMsgs[1].mRxTime - firstRxTime;
|
|
|
|
// Validate the initial timeout
|
|
|
|
minTimeout = kInitialRequestTimeout - kInitialRequestTimeout / 10;
|
|
maxTimeout = kInitialRequestTimeout + kInitialRequestTimeout / 10;
|
|
|
|
Log("Request %2u -> timeout:%lu, min:%lu, max:%lu", 1, ToUlong(timeout), ToUlong(minTimeout), ToUlong(maxTimeout));
|
|
|
|
VerifyOrQuit(timeout >= minTimeout);
|
|
VerifyOrQuit(timeout <= maxTimeout);
|
|
|
|
for (index = 2; index <= kMaxRequestRetxCount; index++)
|
|
{
|
|
sDhcp6RxMsgs[index].ValidateAsRequest(prefix, serverMacAddr);
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
|
|
newTimeout = sDhcp6RxMsgs[index].mRxTime - sDhcp6RxMsgs[index - 1].mRxTime;
|
|
|
|
minTimeout = 2 * timeout - timeout / 10;
|
|
maxTimeout = 2 * timeout + timeout / 10;
|
|
|
|
if (maxTimeout > kMaxRequestTimeout)
|
|
{
|
|
minTimeout = Min(minTimeout, kMaxRequestTimeout - kMaxRequestTimeout / 10);
|
|
maxTimeout = kMaxRequestTimeout + kMaxRequestTimeout / 10;
|
|
}
|
|
|
|
Log("Request %2u -> timeout:%lu, min:%lu, max:%lu", index, ToUlong(newTimeout), ToUlong(minTimeout),
|
|
ToUlong(maxTimeout));
|
|
|
|
elapsedTime = (sDhcp6RxMsgs[index].mRxTime - firstRxTime) / 10;
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mElapsedTime == ClampToUint16(elapsedTime));
|
|
|
|
VerifyOrQuit(newTimeout >= minTimeout);
|
|
VerifyOrQuit(newTimeout <= maxTimeout);
|
|
|
|
timeout = newTimeout;
|
|
}
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that after the Request Retries are finished, client restarts sending Solicit");
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() > kMaxRequestRetxCount + 1);
|
|
|
|
index = kMaxRequestRetxCount + 1;
|
|
|
|
sDhcp6RxMsgs[index].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mTransactionId != sDhcp6RxMsgs[0].mTransactionId);
|
|
VerifyOrQuit(sDhcp6RxMsgs[index].mElapsedTime == 0);
|
|
|
|
// Check the timeout of the last Request message
|
|
timeout = sDhcp6RxMsgs[index].mRxTime - sDhcp6RxMsgs[index - 1].mRxTime;
|
|
VerifyOrQuit(timeout >= minTimeout);
|
|
VerifyOrQuit(timeout <= maxTimeout);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
AdvanceTime(15 * 1000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdRequestRetries");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestDhcp6PdSelectBetweenMultipleServers(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix1;
|
|
Ip6::Prefix prefix2;
|
|
Ip6::Prefix prefix3;
|
|
Mac::ExtAddress serverMacAddr1;
|
|
Mac::ExtAddress serverMacAddr2;
|
|
Mac::ExtAddress serverMacAddr3;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdSelectBetweenMultipleServers()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr1.GenerateRandom();
|
|
serverMacAddr2.GenerateRandom();
|
|
serverMacAddr3.GenerateRandom();
|
|
|
|
prefix1 = PrefixFromString("2001:ff::", 64);
|
|
prefix2 = PrefixFromString("2001:0::", 48);
|
|
prefix3 = PrefixFromString("2001:dad0::", 40);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and wait for the first Solicit message");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send multiple Advertisements from different servers providing different prefixes");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr1);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix1;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr2);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix2;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr3);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix3;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that the client does wait for the full timeout (on first Solicit) ");
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
|
|
// First timeout is at least 1000 msec
|
|
AdvanceNowTo(sDhcp6RxMsgs[0].mRxTime + 1000 - 1);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate Request message is received and its for the preferred prefix from server2");
|
|
|
|
AdvanceTime(200);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[1].ValidateAsRequest(prefix2, serverMacAddr2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
|
|
AdvanceTime(5 * 1000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdSelectBetweenMultipleServers()");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestDhcp6PdServerWithMaxPreferrence(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdServerWithMaxPreferrence()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix = PrefixFromString("2001:7::", 64);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and wait for the first Solicit message");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
|
|
// On the first Solicit, the client must wait for the full timeout
|
|
// unless preference is in Advertisement is set to max (255).
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement with Preference Option string preference to max to the first Solicit");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.mHasPreference = true;
|
|
txMsg.mPreference = 255;
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that the client does not wait any longer and sends Request immediately");
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[1].ValidateAsRequest(prefix, serverMacAddr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
|
|
AdvanceTime(5 * 1000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdServerWithMaxPreferrence()");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestDhcp6PdServerOfferingMultiplePrefixes(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix1;
|
|
Ip6::Prefix prefix2;
|
|
Ip6::Prefix prefix3;
|
|
Mac::ExtAddress serverMacAddr;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdServerOfferingMultiplePrefixes()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix1 = PrefixFromString("2001:5:baba:beef::", 64);
|
|
prefix2 = PrefixFromString("2001:4::", 48);
|
|
prefix3 = PrefixFromString("2001:ef::", 40);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and wait for the first Solicit message");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
AdvanceTime(1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisements from server offering three prefixes");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix1;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
prefixInfo.mPrefix = prefix2;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
prefixInfo.mPrefix = prefix3;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that the client does wait for the full timeout (on first Solicit) ");
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
AdvanceNowTo(sDhcp6RxMsgs[0].mRxTime + 1000 - 1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate Request message is received and its for the preferred prefix");
|
|
|
|
AdvanceTime(200);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[1].ValidateAsRequest(prefix2, serverMacAddr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
|
|
AdvanceTime(5 * 1000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdServerOfferingMultiplePrefixes()");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestDhcp6PdInvalidOrUnusablePrefix(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
Dhcp6RxMsg modifiedSolicitRxMsg;
|
|
Mac::ExtAddress modifiedClientMacAddr;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdInvalidOrUnusablePrefix");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix = PrefixFromString("2001:9::", 64);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and wait for the first two Solicit messages");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
AdvanceTime(2200);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mTransactionId == sDhcp6RxMsgs[1].mTransactionId);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement with wrong TransactionId and ensure it is not accepted");
|
|
|
|
modifiedSolicitRxMsg = sDhcp6RxMsgs[0];
|
|
|
|
do
|
|
{
|
|
modifiedSolicitRxMsg.mTransactionId.GenerateRandom();
|
|
} while (modifiedSolicitRxMsg.mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
|
|
txMsg.PrepareAdvertise(modifiedSolicitRxMsg, serverMacAddr);
|
|
prefixInfo.mIaid = modifiedSolicitRxMsg.mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement with wrong Client ID and ensure it is not accepted");
|
|
|
|
modifiedSolicitRxMsg = sDhcp6RxMsgs[0];
|
|
|
|
do
|
|
{
|
|
modifiedClientMacAddr.GenerateRandom();
|
|
} while (modifiedClientMacAddr == sDhcp6RxMsgs[0].mClientDuid.mShared.mEui64.GetLinkLayerAddress());
|
|
|
|
modifiedSolicitRxMsg.mClientDuid.mShared.mEui64.Init(modifiedClientMacAddr);
|
|
|
|
txMsg.PrepareAdvertise(modifiedSolicitRxMsg, serverMacAddr);
|
|
prefixInfo.mIaid = modifiedSolicitRxMsg.mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement with no Client ID and ensure it is not accepted");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.mHasClientId = false;
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement with no Server ID and ensure it is not accepted");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.mHasServerId = false;
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement with a wrong `Iaid` and ensure it is not accepted");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid + 1;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement with a long prefix and ensure it is not accepted");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = PrefixFromString("2001:dead:beef:cafe::", 65);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement T1 longer than T2 and ensure it is not accepted");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 3000;
|
|
prefixInfo.mT2 = 2000;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement preferred lifetime longer than valid lifetime and ensure it is not accepted");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 4000;
|
|
prefixInfo.mValidLifetime = 3600;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement with preferred lifetime below the min required threshold of 30 min");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 900;
|
|
prefixInfo.mT2 = 1000;
|
|
prefixInfo.mPreferredLifetime = 1799;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Finally send Advertisement with everything valid and ensure it is accepted");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 0;
|
|
prefixInfo.mT2 = 0;
|
|
prefixInfo.mPreferredLifetime = 1800;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.Send();
|
|
AdvanceTime(1);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 3);
|
|
|
|
sDhcp6RxMsgs[2].ValidateAsRequest(prefix, serverMacAddr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
AdvanceTime(15 * 1000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdInvalidOrUnusablePrefix");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestDhcp6PdLifetimeT1AndT2Adjustments(void)
|
|
{
|
|
struct TestCase
|
|
{
|
|
uint32_t mT1;
|
|
uint32_t mT2;
|
|
uint32_t mPreferredLifetime;
|
|
uint32_t mExpectedT1;
|
|
uint32_t mExpectedT2;
|
|
uint32_t mExpectedPreferredLifetime;
|
|
};
|
|
|
|
// Validate client will adjust the T1 and T2 and lifetime to reasonable range.
|
|
|
|
static const TestCase kTestCases[] = {
|
|
// T1 and T2 are zero. Client must pick 0.5 and 0.8 times lifetime for T1 and T2.
|
|
{0, 0, 1800, 900, 1440, 1800},
|
|
|
|
// Only T1 is zero.
|
|
{0, 1300, 1800, 900, 1300, 1800},
|
|
|
|
// Only T2 is zero.
|
|
{800, 0, 1800, 800, 1440, 1800},
|
|
|
|
// T1 is zero, but default T1 (half of preferred lifetime) will be larger than given T2.
|
|
{0, 800, 1800, 900, 900, 1800},
|
|
|
|
// T1 and T2 are given but way too short. Client enforces min of 300s (5 min).
|
|
{1, 5, 1800, 300, 300, 1800},
|
|
|
|
// T1 and T2 zero with preferred lifetime of 7200 (2 hours).
|
|
{0, 0, 7200, 3600, 5760, 7200},
|
|
|
|
// T1 and T2 longer than lifetime.
|
|
{2000, 2500, 1800, 900, 1440, 1800},
|
|
|
|
// Given T1 and T2 (shorter than 0.5 and 0.8) with preferred lifetime of 7200 (2 hours).
|
|
{1000, 1200, 7200, 1000, 1200, 7200},
|
|
|
|
// Given T1 and T2 are too close to the preferred lifetime of 7200 (2 hours).
|
|
{7100, 7150, 7200, 6300, 6840, 7200},
|
|
|
|
// Very long preferred lifetime. Client limit it to 4 hours (14400)
|
|
{0, 0, 14500, 7200, 11520, 14400},
|
|
|
|
// Very long preferred lifetime. Client limit it to 4 hours (14400)
|
|
{2000, 2500, 14500, 2000, 2500, 14400},
|
|
|
|
// Infinite lifetime and T1 and T2. Client limit to 4 hours.
|
|
{0xffffffff, 0xffffffff, 0xffffffff, 13500, 14040, 14400}};
|
|
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Ip6::Prefix adjustedPrefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
const DelegatedPrefix *delegatedPrefix;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdLifetimeT1AndT2Adjustments()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix = PrefixFromString("2001:13::", 48);
|
|
adjustedPrefix = PrefixFromString("2001:13::", 64);
|
|
|
|
for (const TestCase &testCase : kTestCases)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Test case: {T1:%lu T2:%lu prf:%lu } --> Expected {T1:%lu T2:%lu prf:%lu}", ToUlong(testCase.mT1),
|
|
ToUlong(testCase.mT2), ToUlong(testCase.mPreferredLifetime), ToUlong(testCase.mExpectedT1),
|
|
ToUlong(testCase.mExpectedT2), ToUlong(testCase.mExpectedPreferredLifetime));
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
|
|
AdvanceTime(2200);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mTransactionId == sDhcp6RxMsgs[1].mTransactionId);
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = testCase.mT1;
|
|
prefixInfo.mT2 = testCase.mT2;
|
|
prefixInfo.mPreferredLifetime = testCase.mPreferredLifetime;
|
|
prefixInfo.mValidLifetime = testCase.mPreferredLifetime;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
Log("Delegated Prefix -> {T1:%lu T2:%lu prf:%lu}", ToUlong(delegatedPrefix->mT1), ToUlong(delegatedPrefix->mT2),
|
|
ToUlong(delegatedPrefix->mPreferredLifetime));
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == adjustedPrefix);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == testCase.mExpectedT1);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == testCase.mExpectedT2);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == testCase.mExpectedPreferredLifetime);
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
AdvanceTime(100);
|
|
}
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdLifetimeT1AndT2Adjustments");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestDhcp6PdServerVoidingLeaseDuringRenew(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Ip6::Prefix adjustedPrefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
const DelegatedPrefix *delegatedPrefix;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdServerVoidingLeaseDuringRenew()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix = PrefixFromString("2001:cafe:5555::", 48);
|
|
adjustedPrefix = PrefixFromString("2001:cafe:5555::", 64);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start client, interact with it to successfully delegate a prefix");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
|
|
AdvanceTime(2200);
|
|
|
|
// Listen for Solicit and send Advertise
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mTransactionId == sDhcp6RxMsgs[1].mTransactionId);
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 0;
|
|
prefixInfo.mT2 = 0;
|
|
prefixInfo.mPreferredLifetime = 1800;
|
|
prefixInfo.mValidLifetime = 1800;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
// Listen for Request and send Reply
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == adjustedPrefix);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == 900);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == 1440);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == 1800);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Wait till T1 time for client to renew");
|
|
|
|
AdvanceTime(900 * 1000 + 10);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRenew(prefix, serverMacAddr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send a Reply invalidating the previously delegated prefix");
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 0;
|
|
prefixInfo.mT2 = 0;
|
|
prefixInfo.mPreferredLifetime = 0;
|
|
prefixInfo.mValidLifetime = 0;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
AdvanceTime(5 * 1000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdServerVoidingLeaseDuringRenew");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestDhcp6PdServerNotExtendingLeaseDuringRenew(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Ip6::Prefix adjustedPrefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
const DelegatedPrefix *delegatedPrefix;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdServerNotExtendingLeaseDuringRenew()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix = PrefixFromString("2001:4567::", 48);
|
|
adjustedPrefix = PrefixFromString("2001:4567::", 64);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start client, interact with it to successfully delegate a prefix");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
|
|
AdvanceTime(2200);
|
|
|
|
// Listen for Solicit and send Advertise
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mTransactionId == sDhcp6RxMsgs[1].mTransactionId);
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 0;
|
|
prefixInfo.mT2 = 0;
|
|
prefixInfo.mPreferredLifetime = 1800;
|
|
prefixInfo.mValidLifetime = 1800;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
// Listen for Request and send Reply
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == adjustedPrefix);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == 900);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == 1440);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == 1800);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Wait till T1 time for client to renew");
|
|
|
|
AdvanceTime(900 * 1000 + 10);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRenew(prefix, serverMacAddr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send a Reply including the previously delegated prefix but with short lifetime");
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 0;
|
|
prefixInfo.mT2 = 0;
|
|
prefixInfo.mPreferredLifetime = 100;
|
|
prefixInfo.mValidLifetime = 100;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == adjustedPrefix);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == 100);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == 100);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == 100);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Wait for the short lifetime to expire and validate that the delegated prefix is removed");
|
|
|
|
AdvanceTime(100 * 1000 + 1);
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix == nullptr);
|
|
|
|
AdvanceTime(5 * 1000);
|
|
|
|
VerifyOrQuit(!sDhcp6RxMsgs.IsEmpty());
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mElapsedTime == 0);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
AdvanceTime(5 * 1000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdServerNotExtendingLeaseDuringRenew");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestDhcp6PdServerReplacingPrefix(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix1;
|
|
Ip6::Prefix prefix2;
|
|
Mac::ExtAddress serverMacAddr;
|
|
const DelegatedPrefix *delegatedPrefix;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdServerReplacingPrefix()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix1 = PrefixFromString("2001:b2d4:1111::", 64);
|
|
prefix1 = PrefixFromString("2001:b2d4:2222::", 64);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start client, interact with it to successfully delegate a prefix");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
|
|
AdvanceTime(2200);
|
|
|
|
// Listen for Solicit and send Advertise
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mTransactionId == sDhcp6RxMsgs[1].mTransactionId);
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 0;
|
|
prefixInfo.mT2 = 0;
|
|
prefixInfo.mPreferredLifetime = 1800;
|
|
prefixInfo.mValidLifetime = 1800;
|
|
prefixInfo.mPrefix = prefix1;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
// Listen for Request and send Reply
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix1, serverMacAddr);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix1);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == prefix1);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == 900);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == 1440);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == 1800);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Wait till T1 time for client to renew");
|
|
|
|
AdvanceTime(900 * 1000 + 10);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRenew(prefix1, serverMacAddr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send a Reply including a new prefix with old one with short lifetime");
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 0;
|
|
prefixInfo.mT2 = 0;
|
|
prefixInfo.mPreferredLifetime = 120;
|
|
prefixInfo.mValidLifetime = 120;
|
|
prefixInfo.mPrefix = prefix1;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
prefixInfo.mPreferredLifetime = 1800;
|
|
prefixInfo.mValidLifetime = 1800;
|
|
prefixInfo.mPrefix = prefix2;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix2);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == prefix2);
|
|
VerifyOrQuit(delegatedPrefix->mT1 == 900);
|
|
VerifyOrQuit(delegatedPrefix->mT2 == 1440);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == 1800);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
AdvanceTime(5 * 1000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdServerReplacingPrefix");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestDhcp6PdServerStatusCodeUseMulticast(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Ip6::Prefix adjustedPrefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
const DelegatedPrefix *delegatedPrefix;
|
|
Ip6::Address serverIp6Addr;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdServerStatusCodeUseMulticast()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix = PrefixFromString("2001:f57c::", 48);
|
|
adjustedPrefix = PrefixFromString("2001:f57c::", 64);
|
|
|
|
serverIp6Addr = AddressFromString("fe80::2");
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and wait for the first two Solicit messages");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
AdvanceTime(2200);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mTransactionId == sDhcp6RxMsgs[1].mTransactionId);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisement");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr, &serverIp6Addr);
|
|
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 2000;
|
|
prefixInfo.mT2 = 3200;
|
|
prefixInfo.mPreferredLifetime = 3600;
|
|
prefixInfo.mValidLifetime = 4000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix() == nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate Request message is received using unicast address of server");
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr, &serverIp6Addr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Reply message with status code UseMulticast");
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.mHasStatus = true;
|
|
txMsg.mStatusCode = Dhcp6::StatusCodeOption::kUseMulticast;
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate Request message is sent again now as a multicast");
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr, nullptr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdServerStatusCodeUseMulticast");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestDhcp6PdServerReplyWithNoBindingToRelease(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
const DelegatedPrefix *delegatedPrefix;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdServerReplyWithNoBindingToRelease()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix = PrefixFromString("2001:8765::", 64);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and wait for the first two Solicit messages");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
AdvanceTime(2200);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mTransactionId == sDhcp6RxMsgs[1].mTransactionId);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Advertisements from server offering three prefixes");
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
prefixInfo.mT1 = 0;
|
|
prefixInfo.mT2 = 0;
|
|
prefixInfo.mPreferredLifetime = 5000;
|
|
prefixInfo.mValidLifetime = 5000;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate Request message is received");
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Reply message");
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mAdjustedPrefix == prefix);
|
|
VerifyOrQuit(delegatedPrefix->mPreferredLifetime == prefixInfo.mPreferredLifetime);
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client to release the prefix");
|
|
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRelease(prefix, serverMacAddr);
|
|
VerifyOrQuit(sDhcp6RxMsgs[0].mElapsedTime == 0);
|
|
|
|
AdvanceTime(1200);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[1].ValidateAsRelease(prefix, serverMacAddr);
|
|
VerifyOrQuit(sDhcp6RxMsgs[1].mTransactionId == sDhcp6RxMsgs[0].mTransactionId);
|
|
VerifyOrQuit(sDhcp6RxMsgs[1].mElapsedTime > 0);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send a Reply to the Release with status code NoBinding, validate that it is accepted");
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = sDhcp6RxMsgs[0].mIaPds[0].mIaid;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
|
|
txMsg.mIaPds[0].mHasStatus = true;
|
|
txMsg.mIaPds[0].mStatusCode = Dhcp6::StatusCodeOption::kNoBinding;
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Validate that the client accepts the Reply and there are no more retries of Release");
|
|
|
|
AdvanceTime(30 * 1000);
|
|
VerifyOrQuit(sDhcp6RxMsgs.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdServerReplyWithNoBindingToRelease()");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
#endif // OT_CONFIG_DHCP6_PD_CLIENT_ENABLE
|
|
|
|
} // namespace ot
|
|
|
|
int main(void)
|
|
{
|
|
#if OT_CONFIG_DHCP6_PD_CLIENT_ENABLE
|
|
ot::TestDhcp6PdPrefixDelegation(/* aShortPrefix */ false, /* aAddServerUnicastOption */ false);
|
|
ot::TestDhcp6PdPrefixDelegation(/* aShortPrefix */ false, /* aAddServerUnicastOption */ true);
|
|
ot::TestDhcp6PdPrefixDelegation(/* aShortPrefix */ true, /* aAddServerUnicastOption */ false);
|
|
ot::TestDhcp6PdPrefixDelegation(/* aShortPrefix */ true, /* aAddServerUnicastOption */ true);
|
|
ot::TestDhcp6PdSolicitRetries();
|
|
ot::TestDhcp6PdRequestRetries();
|
|
ot::TestDhcp6PdSelectBetweenMultipleServers();
|
|
ot::TestDhcp6PdServerWithMaxPreferrence();
|
|
ot::TestDhcp6PdServerOfferingMultiplePrefixes();
|
|
ot::TestDhcp6PdInvalidOrUnusablePrefix();
|
|
ot::TestDhcp6PdLifetimeT1AndT2Adjustments();
|
|
ot::TestDhcp6PdServerVoidingLeaseDuringRenew();
|
|
ot::TestDhcp6PdServerNotExtendingLeaseDuringRenew();
|
|
ot::TestDhcp6PdServerReplacingPrefix();
|
|
ot::TestDhcp6PdServerStatusCodeUseMulticast();
|
|
ot::TestDhcp6PdServerReplyWithNoBindingToRelease();
|
|
|
|
printf("All tests passed\n");
|
|
#else
|
|
printf("DHCP6_PD_CLIENT_ENABLE feature is not enabled\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|