mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
dcbd870245
This commit updates the DHCPv6 Prefix Delegation (PD) client to comply with RFC 9915, which obsoletes the Server Unicast option (Option 12) and the UseMulticast status code. Changes: - Removed `mServerAddress` and `ProcessServerUnicastOption()` from `Dhcp6PdClient`. - Modified `Dhcp6PdClient::SendMessage` to always transmit via multicast to `ff02::1:2`. - Removed `UseMulticast` status code handling in `HandleReply()`. - Added `otMessageFree` weak stub in simulation platform's `infra_if.c` to resolve linking errors on simulation radio-only targets when DHCPv6 PD client is enabled. - Updated `test_dhcp6_pd_client.cpp` to expect multicast and removed the obsolete UseMulticast test case.
2622 lines
91 KiB
C++
2622 lines
91 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(void);
|
|
};
|
|
|
|
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(void)
|
|
{
|
|
Message *message;
|
|
|
|
message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
|
|
VerifyOrQuit(message != nullptr);
|
|
PrepareMessage(*message);
|
|
|
|
LogMsg("Sending");
|
|
|
|
otPlatInfraIfDhcp6PdClientHandleReceived(sInstance, message, kInfraIfIndex);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// otPlatInfraIf
|
|
|
|
typedef BorderRouter::Dhcp6PdClient::DelegatedPrefix DelegatedPrefix;
|
|
|
|
static bool sDhcp6ListeningEnabled = false;
|
|
static Array<Dhcp6RxMsg, kMaxDhcp6RxMsgs> sDhcp6RxMsgs;
|
|
|
|
extern "C" {
|
|
|
|
void otPlatInfraIfDhcp6PdClientSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
|
{
|
|
Log("otPlatInfraIfDhcp6PdClientSetListeningEnabled(aEnable:%u)", aEnable);
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aInfraIfIndex == kInfraIfIndex);
|
|
sDhcp6ListeningEnabled = aEnable;
|
|
}
|
|
|
|
void otPlatInfraIfDhcp6PdClientSend(otInstance *aInstance,
|
|
otMessage *aMessage,
|
|
otIp6Address *aDestAddress,
|
|
uint32_t aInfraIfIndex)
|
|
{
|
|
Message *message = AsCoreTypePtr(aMessage);
|
|
Dhcp6RxMsg *rxMsg;
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(message != nullptr);
|
|
VerifyOrQuit(aDestAddress != nullptr);
|
|
|
|
Log("otPlatInfraIfDhcp6PdClientSend(%s)", AsCoreType(aDestAddress).ToString().AsCString());
|
|
|
|
rxMsg = sDhcp6RxMsgs.PushBack();
|
|
VerifyOrQuit(rxMsg != nullptr);
|
|
|
|
rxMsg->ParseFrom(*message);
|
|
rxMsg->LogMsg("Received");
|
|
|
|
rxMsg->mRxTime = sNow;
|
|
rxMsg->mDstAddr = AsCoreType(aDestAddress);
|
|
|
|
message->Free();
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void ProcessTasklets(void)
|
|
{
|
|
do
|
|
{
|
|
otTaskletsProcess(sInstance);
|
|
} while (otTaskletsArePending(sInstance));
|
|
}
|
|
|
|
void AdvanceTime(uint32_t aDuration)
|
|
{
|
|
uint32_t time = sNow + aDuration;
|
|
|
|
Log("AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000);
|
|
|
|
while (TimeMilli(sAlarmTime) <= TimeMilli(time))
|
|
{
|
|
ProcessTasklets();
|
|
sNow = sAlarmTime;
|
|
otPlatAlarmMilliFired(sInstance);
|
|
}
|
|
|
|
ProcessTasklets();
|
|
sNow = time;
|
|
}
|
|
|
|
void AdvanceNowTo(uint32_t aNewNow)
|
|
{
|
|
VerifyOrQuit(aNewNow >= sNow);
|
|
AdvanceTime(aNewNow - sNow);
|
|
}
|
|
|
|
void InitTest(void)
|
|
{
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Initialize OT instance.
|
|
|
|
sNow = 0;
|
|
sAlarmOn = false;
|
|
sInstance = static_cast<Instance *>(testInitInstance());
|
|
|
|
sDhcp6ListeningEnabled = false;
|
|
sDhcp6RxMsgs.Clear();
|
|
|
|
SuccessOrQuit(otBorderRoutingInit(sInstance, kInfraIfIndex, /* aInfraIfIsRunning */ true));
|
|
AdvanceTime(100);
|
|
}
|
|
|
|
void FinalizeTest(void) { testFreeInstance(sInstance); }
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestDhcp6PdPrefixDelegation(bool aShortPrefix)
|
|
{
|
|
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();
|
|
}
|
|
|
|
#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();
|
|
|
|
printf("All tests passed\n");
|
|
#else
|
|
printf("DHCP6_PD_CLIENT_ENABLE feature is not enabled\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|