mirror of
https://github.com/espressif/openthread.git
synced 2026-08-24 19:29:52 +00:00
This commit fixes a message leak in `InfraIf::HandleDhcp6Received()` when incoming DHCPv6 messages are rejected. `otPlatInfraIfDhcp6PdClientHandleReceived()` transfers ownership of the received `aMessage` to OpenThread. Previously, early validation guards in `InfraIf::HandleDhcp6Received()` (when the interface is not running or when the interface index does not match) jumped to `exit:` without freeing `aMessage`. Because DHCPv6 listening remains enabled while a lease is held, bringing down the infrastructure interface caused any subsequent incoming DHCPv6 packets delivered by the socket to be dropped without being freed, resulting in leaked message buffers. This change ensures `aMessage.Free()` is called whenever an error occurs in `InfraIf::HandleDhcp6Received()`. It also updates unit tests to verify that message buffers are not leaked when packets are received while the infra interface is down or has a mismatched interface index.
2730 lines
95 KiB
C++
2730 lines
95 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
|
|
#if OPENTHREAD_CONFIG_LOG_INSTANCE_AWARE_API_ENABLE
|
|
void otPlatLogOutput(otInstance *, otLogLevel, const char *aLogLine) { printf(" %s\n", aLogLine); }
|
|
#else
|
|
void otPlatLog(otLogLevel, otLogRegion, const char *aFormat, ...)
|
|
{
|
|
va_list args;
|
|
|
|
printf(" ");
|
|
va_start(args, aFormat);
|
|
vprintf(aFormat, args);
|
|
va_end(args);
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
#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 mHasSolMaxRt : 1;
|
|
uint16_t mStatusCode;
|
|
uint16_t mElapsedTime;
|
|
Duid mClientDuid;
|
|
Duid mServerDuid;
|
|
ReqOptionArray mRequestedOptions;
|
|
uint8_t mPreference;
|
|
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 (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::SolMaxRtOption solMaxRtOption;
|
|
Dhcp6::IaPdOption iaPdOption;
|
|
Dhcp6::IaPrefixOption iaPrefixOption;
|
|
};
|
|
|
|
Clear();
|
|
offsetRange.InitFromMessageFullLength(aMessage);
|
|
|
|
SuccessOrQuit(aMessage.ReadAndAdvance(offsetRange, header));
|
|
mMsgType = header.GetMsgType();
|
|
mTransactionId = header.GetTransactionId();
|
|
|
|
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::kSolMaxRt:
|
|
VerifyOrQuit(!mHasSolMaxRt);
|
|
mHasSolMaxRt = true;
|
|
SuccessOrQuit(aMessage.Read(optionOffsetRange, solMaxRtOption));
|
|
mSolMaxRt = solMaxRtOption.GetSolMaxRt();
|
|
break;
|
|
|
|
case Dhcp6::Option::kIaPd:
|
|
SuccessOrQuit(aMessage.ReadAndAdvance(optionOffsetRange, 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::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 (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;
|
|
|
|
void ValidateAsRenew(const Ip6::Prefix &aPrefix, const Mac::ExtAddress &aServerMacAddr) const;
|
|
|
|
void ValidateAsRebind(const Ip6::Prefix &aPrefix) const;
|
|
|
|
void ValidateAsRelease(const Ip6::Prefix &aPrefix, const Mac::ExtAddress &aServerMacAddr) const;
|
|
|
|
uint32_t mRxTime;
|
|
Ip6::Address mDstAddr;
|
|
|
|
private:
|
|
void Validate(Dhcp6::MsgType aMsgType,
|
|
const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress *aServerMacAddr = 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
|
|
{
|
|
Validate(Dhcp6::kMsgTypeRequest, aPrefix, &aServerMacAddr);
|
|
}
|
|
|
|
void Dhcp6RxMsg::ValidateAsRenew(const Ip6::Prefix &aPrefix, const Mac::ExtAddress &aServerMacAddr) const
|
|
{
|
|
Validate(Dhcp6::kMsgTypeRenew, aPrefix, &aServerMacAddr);
|
|
}
|
|
|
|
void Dhcp6RxMsg::ValidateAsRebind(const Ip6::Prefix &aPrefix) const { Validate(Dhcp6::kMsgTypeRebind, aPrefix); }
|
|
|
|
void Dhcp6RxMsg::ValidateAsRelease(const Ip6::Prefix &aPrefix, const Mac::ExtAddress &aServerMacAddr) const
|
|
{
|
|
Validate(Dhcp6::kMsgTypeRelease, aPrefix, &aServerMacAddr);
|
|
}
|
|
|
|
void Dhcp6RxMsg::Validate(Dhcp6::MsgType aMsgType,
|
|
const Ip6::Prefix &aPrefix,
|
|
const Mac::ExtAddress *aServerMacAddr) const
|
|
{
|
|
VerifyOrQuit(mMsgType == aMsgType);
|
|
|
|
VerifyOrQuit(mDstAddr == AddressFromString("ff02::1:2"));
|
|
|
|
VerifyOrQuit(!mHasStatus);
|
|
VerifyOrQuit(!mHasPreference);
|
|
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);
|
|
void PrepareReply(const Dhcp6RxMsg &aClientMsg, const Mac::ExtAddress &aServerMacAddr);
|
|
void AddIaPrefix(const PrefixInfo &aInfo);
|
|
void Send(uint32_t aInfraIfIndex = kInfraIfIndex);
|
|
};
|
|
|
|
void Dhcp6TxMsg::PrepareAdvertise(const Dhcp6RxMsg &aClientMsg, const Mac::ExtAddress &aServerMacAddr)
|
|
{
|
|
Clear();
|
|
mMsgType = Dhcp6::kMsgTypeAdvertise;
|
|
mTransactionId = aClientMsg.mTransactionId;
|
|
mHasClientId = true;
|
|
mHasServerId = true;
|
|
mClientDuid = aClientMsg.mClientDuid;
|
|
mServerDuid.mShared.mEui64.Init(aServerMacAddr);
|
|
mServerDuid.mLength = sizeof(Dhcp6::Eui64Duid);
|
|
}
|
|
|
|
void Dhcp6TxMsg::PrepareReply(const Dhcp6RxMsg &aClientMsg, const Mac::ExtAddress &aServerMacAddr)
|
|
{
|
|
Clear();
|
|
mMsgType = Dhcp6::kMsgTypeReply;
|
|
mTransactionId = aClientMsg.mTransactionId;
|
|
mHasClientId = true;
|
|
mHasServerId = true;
|
|
mClientDuid = aClientMsg.mClientDuid;
|
|
mServerDuid.mShared.mEui64.Init(aServerMacAddr);
|
|
mServerDuid.mLength = sizeof(Dhcp6::Eui64Duid);
|
|
}
|
|
|
|
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(uint32_t aInfraIfIndex)
|
|
{
|
|
Message *message;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
PrepareMessage(*message);
|
|
|
|
LogMsg("Sending");
|
|
|
|
otPlatInfraIfDhcp6PdClientHandleReceived(sInstance, message, aInfraIfIndex);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// 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)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Ip6::Prefix adjustedPrefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
const DelegatedPrefix *delegatedPrefix;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdPrefixDelegation(aShortPrefix:%u)", aShortPrefix);
|
|
|
|
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;
|
|
}
|
|
|
|
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();
|
|
|
|
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);
|
|
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRequest(prefix, serverMacAddr);
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
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);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Reply to Release message and check that no more messages is received");
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdPrefixDelegation(aShortPrefix:%u)", aShortPrefix);
|
|
|
|
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 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();
|
|
}
|
|
|
|
void TestDhcp6PdReceiveWhenInfraIfDownOrWrongIndex(void)
|
|
{
|
|
uint16_t heapAllocations;
|
|
Dhcp6TxMsg txMsg;
|
|
Dhcp6TxMsg::PrefixInfo prefixInfo;
|
|
Ip6::Prefix prefix;
|
|
Mac::ExtAddress serverMacAddr;
|
|
const DelegatedPrefix *delegatedPrefix;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdReceiveWhenInfraIfDownOrWrongIndex()");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
serverMacAddr.GenerateRandom();
|
|
|
|
prefix = PrefixFromString("2001:2222::", 64);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Start the client and get a delegated prefix");
|
|
|
|
VerifyOrQuit(!sDhcp6ListeningEnabled);
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Start();
|
|
|
|
AdvanceTime(2200);
|
|
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 2);
|
|
sDhcp6RxMsgs[0].ValidateAsSolicit();
|
|
sDhcp6RxMsgs[1].ValidateAsSolicit();
|
|
|
|
txMsg.PrepareAdvertise(sDhcp6RxMsgs[0], serverMacAddr);
|
|
prefixInfo.mIaid = 0;
|
|
prefixInfo.mT1 = 0;
|
|
prefixInfo.mT2 = 0;
|
|
prefixInfo.mPreferredLifetime = 1800;
|
|
prefixInfo.mValidLifetime = 1800;
|
|
prefixInfo.mPrefix = prefix;
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 3);
|
|
sDhcp6RxMsgs[2].ValidateAsRequest(prefix, serverMacAddr);
|
|
|
|
AdvanceTime(1);
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[2], serverMacAddr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
txMsg.Send();
|
|
|
|
delegatedPrefix = sInstance->Get<BorderRouter::Dhcp6PdClient>().GetDelegatedPrefix();
|
|
VerifyOrQuit(delegatedPrefix != nullptr);
|
|
VerifyOrQuit(delegatedPrefix->mPrefix == prefix);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Signal infra interface is down while lease is held (listening stays enabled)");
|
|
|
|
SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, /* aIsRunning */ false));
|
|
VerifyOrQuit(sDhcp6ListeningEnabled);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send DHCPv6 message while infra if is down - should be rejected and freed");
|
|
|
|
txMsg.Send();
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Signal infra interface is up again");
|
|
|
|
SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, /* aIsRunning */ true));
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send DHCPv6 message with wrong interface index - should be rejected and freed");
|
|
|
|
txMsg.Send(kInfraIfIndex + 1);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Stop the client, and validate that Release message is received");
|
|
|
|
sDhcp6RxMsgs.Clear();
|
|
sInstance->Get<BorderRouter::Dhcp6PdClient>().Stop();
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.GetLength() == 1);
|
|
sDhcp6RxMsgs[0].ValidateAsRelease(prefix, serverMacAddr);
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
Log("Send Reply to Release message and check that no more messages is received");
|
|
|
|
txMsg.PrepareReply(sDhcp6RxMsgs[0], serverMacAddr);
|
|
txMsg.AddIaPrefix(prefixInfo);
|
|
sDhcp6RxMsgs.Clear();
|
|
txMsg.Send();
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sDhcp6RxMsgs.IsEmpty());
|
|
|
|
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDhcp6PdReceiveWhenInfraIfDownOrWrongIndex()");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
#endif // OT_CONFIG_DHCP6_PD_CLIENT_ENABLE
|
|
|
|
} // namespace ot
|
|
|
|
int main(void)
|
|
{
|
|
#if OT_CONFIG_DHCP6_PD_CLIENT_ENABLE
|
|
ot::TestDhcp6PdPrefixDelegation(/* aShortPrefix */ false);
|
|
ot::TestDhcp6PdPrefixDelegation(/* aShortPrefix */ true);
|
|
ot::TestDhcp6PdSolicitRetries();
|
|
ot::TestDhcp6PdRequestRetries();
|
|
ot::TestDhcp6PdSelectBetweenMultipleServers();
|
|
ot::TestDhcp6PdServerWithMaxPreferrence();
|
|
ot::TestDhcp6PdServerOfferingMultiplePrefixes();
|
|
ot::TestDhcp6PdInvalidOrUnusablePrefix();
|
|
ot::TestDhcp6PdLifetimeT1AndT2Adjustments();
|
|
ot::TestDhcp6PdServerVoidingLeaseDuringRenew();
|
|
ot::TestDhcp6PdServerNotExtendingLeaseDuringRenew();
|
|
ot::TestDhcp6PdServerReplacingPrefix();
|
|
ot::TestDhcp6PdServerReplyWithNoBindingToRelease();
|
|
ot::TestDhcp6PdReceiveWhenInfraIfDownOrWrongIndex();
|
|
|
|
printf("All tests passed\n");
|
|
#else
|
|
printf("DHCP6_PD_CLIENT_ENABLE feature is not enabled\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|