mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[border-admitter] enhance forwarding of joiner relay to enrollers (#12829)
This commit enhances the `Admitter` logic for forwarding `RelayRx` messages to connected enrollers. If an enroller has explicitly accepted a specific joiner IID, the `Admitter` will now always forward that joiner's relay traffic to the owning enroller, regardless of its current `kForwardJoinerRelayRx` flag in its registered enroller mode. The flag now strictly controls whether the enroller receives general "multicast" forwarding for joiners that have not yet been accepted by any enroller. This enhancement adds a new capability to the interactions between the `Admitter` and enrollers. Previously, if an enroller accepted a joiner but also cleared its `kForwardJoinerRelayRx` flag, it could be considered a misbehavior by the enroller, as it would effectively block that joiner's traffic from reaching any other enrollers without receiving the traffic itself. This scenario is no longer possible, and this configuration now supports a new behavior: allowing an enroller to accept certain joiners and receive relay traffic only from those it has explicitly accepted. The `test_border_admitter` is updated to validate this behavior in detail.
This commit is contained in:
committed by
GitHub
parent
9f28df1e30
commit
5889e428ce
@@ -341,7 +341,7 @@ private:
|
||||
void SendEnrollerResponse(Uri aUri, StateTlv::State aResponseState, const Coap::Message &aRequest);
|
||||
void SendEnrollerReportState(uint8_t aAdmitterState);
|
||||
Error AppendAdmitterTlvs(Coap::Message &aMessage, uint8_t aAdmitterState);
|
||||
void ForwardUdpRelayToEnroller(const Coap::Message &aMessage);
|
||||
void ForwardUdpRelayToEnroller(const Coap::Message &aMessage, bool aCheckEnrollerMode);
|
||||
void ForwardUdpProxyToEnroller(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
static Error ReadSteeringDataTlv(const Message &aMessage, SteeringData &aSteeringData);
|
||||
|
||||
@@ -236,14 +236,16 @@ void Admitter::ForwardJoinerRelayToEnrollers(const Coap::Msg &aMsg)
|
||||
if (joiner != nullptr)
|
||||
{
|
||||
joiner->UpdateExpirationTime();
|
||||
iter.GetSessionAs<Manager::CoapDtlsSession>()->ForwardUdpRelayToEnroller(aMsg.mMessage);
|
||||
iter.GetSessionAs<Manager::CoapDtlsSession>()->ForwardUdpRelayToEnroller(aMsg.mMessage,
|
||||
/* aCheckEnrollerMode */ false);
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
for (EnrollerIterator iter(GetInstance()); !iter.IsDone(); iter.Advance())
|
||||
{
|
||||
iter.GetSessionAs<Manager::CoapDtlsSession>()->ForwardUdpRelayToEnroller(aMsg.mMessage);
|
||||
iter.GetSessionAs<Manager::CoapDtlsSession>()->ForwardUdpRelayToEnroller(aMsg.mMessage,
|
||||
/* aCheckEnrollerMode */ true);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -1425,12 +1427,16 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Manager::CoapDtlsSession::ForwardUdpRelayToEnroller(const Coap::Message &aMessage)
|
||||
void Manager::CoapDtlsSession::ForwardUdpRelayToEnroller(const Coap::Message &aMessage, bool aCheckEnrollerMode)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(IsEnroller());
|
||||
VerifyOrExit(mEnroller->ShouldForwardJoinerRelay());
|
||||
|
||||
if (aCheckEnrollerMode)
|
||||
{
|
||||
VerifyOrExit(mEnroller->ShouldForwardJoinerRelay());
|
||||
}
|
||||
|
||||
SuccessOrExit(error = ForwardUdpRelay(aMessage));
|
||||
LogInfo("Forward %s to enroller - session %u", UriToString<kUriRelayRx>(), mIndex);
|
||||
|
||||
@@ -1326,8 +1326,10 @@ template <uint8_t kNumEnrollers> bool DidFindAllEnrollers(const BitSet<kNumEnrol
|
||||
|
||||
void LogEnroller(const Admitter::EnrollerInfo &aInfo)
|
||||
{
|
||||
Log(" Enroller - id:%s steeringData:%s mode:0x%02x", aInfo.mId,
|
||||
AsCoreType(&aInfo.mSteeringData).ToString().AsCString(), aInfo.mMode);
|
||||
Log(" Enroller - id:%s steeringData:%s mode:0x%02x[%c%c]", aInfo.mId,
|
||||
AsCoreType(&aInfo.mSteeringData).ToString().AsCString(), aInfo.mMode,
|
||||
aInfo.mMode & MeshCoP::EnrollerModeTlv::kForwardJoinerRelayRx ? 'J' : '-',
|
||||
aInfo.mMode & MeshCoP::EnrollerModeTlv::kForwardUdpProxyRx ? 'U' : '-');
|
||||
}
|
||||
|
||||
void LogJoiner(const Admitter::JoinerInfo &aInfo)
|
||||
@@ -2040,6 +2042,219 @@ void TestBorderAdmitterJoinerEnrollerInteraction(void)
|
||||
|
||||
joiners[1]->Get<Joiner>().Stop();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Send `EnrollerKeepAlive` message from `enrollers[0]` change its mode to disallow `kForwardJoinerRelayRx`");
|
||||
|
||||
modes[0] = MeshCoP::EnrollerModeTlv::kForwardUdpProxyRx;
|
||||
|
||||
message =
|
||||
enrollers[0]->Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriEnrollerKeepAlive);
|
||||
VerifyOrQuit(message != nullptr);
|
||||
|
||||
SuccessOrQuit(Tlv::Append<MeshCoP::StateTlv>(*message, MeshCoP::StateTlv::kAccept));
|
||||
SuccessOrQuit(Tlv::Append<MeshCoP::EnrollerModeTlv>(*message, modes[0]));
|
||||
|
||||
responseContexts[0].Clear();
|
||||
SuccessOrQuit(enrollers[0]->Get<Tmf::SecureAgent>().SendMessage(*message, HandleResponse, &responseContexts[0]));
|
||||
|
||||
nexus.AdvanceTime(Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(responseContexts[0].mReceived);
|
||||
VerifyOrQuit(responseContexts[0].mResponseState == MeshCoP::StateTlv::kAccept);
|
||||
VerifyOrQuit(responseContexts[0].mHasAdmitterState);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Validate that the `enrollers[0]` mode got changed on `admitter`");
|
||||
|
||||
foundEnrollers.Clear();
|
||||
iter.Init(admitter.GetInstance());
|
||||
|
||||
while (iter.GetNextEnrollerInfo(enrollerInfo) == kErrorNone)
|
||||
{
|
||||
uint8_t matchedIndex;
|
||||
|
||||
LogEnroller(enrollerInfo);
|
||||
|
||||
matchedIndex = FindMatchingEnroller<kNumEnrollers>(enrollerInfo, kEnrollerIds, foundEnrollers);
|
||||
|
||||
VerifyOrQuit(AsCoreType(&enrollerInfo.mSteeringData) == steeringData);
|
||||
VerifyOrQuit(enrollerInfo.mMode == modes[matchedIndex]);
|
||||
|
||||
if (matchedIndex == 0)
|
||||
{
|
||||
SuccessOrQuit(iter.GetNextJoinerInfo(joinerInfo));
|
||||
VerifyOrQuit(AsCoreType(&joinerInfo.mIid) == joinerIids[0]);
|
||||
LogJoiner(joinerInfo);
|
||||
}
|
||||
|
||||
VerifyOrQuit(iter.GetNextJoinerInfo(joinerInfo) == kErrorNotFound);
|
||||
}
|
||||
|
||||
VerifyOrQuit(DidFindAllEnrollers<kNumEnrollers>(foundEnrollers));
|
||||
|
||||
nexus.AdvanceTime(Time::kOneSecondInMsec);
|
||||
|
||||
for (uint8_t i = 0; i < kNumEnrollers; i++)
|
||||
{
|
||||
recvContext[i].Clear();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Start `joiners[0]` again and validate that its `RelayRx` is still only forwarded to `enrollers[0]`");
|
||||
|
||||
joiners[0]->Get<ThreadNetif>().Up();
|
||||
SuccessOrQuit(joiners[0]->Get<Joiner>().Start(kPskd,
|
||||
/* aProvisioningUrl */ nullptr,
|
||||
/* aVendorName */ nullptr,
|
||||
/* aVendorModel */ nullptr,
|
||||
/* aVendorSwVersion */ nullptr,
|
||||
/* aVendorData */ nullptr,
|
||||
/* aCallback */ nullptr,
|
||||
/* aContext */ nullptr));
|
||||
|
||||
nexus.AdvanceTime(8 * Time::kOneSecondInMsec);
|
||||
|
||||
for (uint8_t i = 0; i < kNumEnrollers; i++)
|
||||
{
|
||||
Ip6::InterfaceIdentifier readIid;
|
||||
uint16_t joinerRouterRloc;
|
||||
|
||||
message = AsCoapMessagePtr(recvContext[i].mRelayRxMsgs.GetHead());
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
VerifyOrQuit(message == nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
VerifyOrQuit(message != nullptr);
|
||||
|
||||
VerifyOrQuit(message->ReadType() == Coap::kTypeNonConfirmable);
|
||||
VerifyOrQuit(message->ReadCode() == Coap::kCodePost);
|
||||
SuccessOrQuit(Tlv::Find<MeshCoP::JoinerIidTlv>(*message, readIid));
|
||||
SuccessOrQuit(Tlv::Find<MeshCoP::JoinerRouterLocatorTlv>(*message, joinerRouterRloc));
|
||||
|
||||
VerifyOrQuit(readIid == joinerIids[0]);
|
||||
VerifyOrQuit(joinerRouterRloc == admitter.Get<Mle::Mle>().GetRloc16());
|
||||
}
|
||||
|
||||
joiners[0]->Get<Joiner>().Stop();
|
||||
|
||||
for (uint8_t i = 0; i < kNumEnrollers; i++)
|
||||
{
|
||||
recvContext[i].Clear();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Start `joiners[1]` and validate that its `RelayRx` is not longer forwarded to `enrollers[0]`");
|
||||
|
||||
joiners[1]->Get<ThreadNetif>().Up();
|
||||
SuccessOrQuit(joiners[1]->Get<Joiner>().Start(kPskd,
|
||||
/* aProvisioningUrl */ nullptr,
|
||||
/* aVendorName */ nullptr,
|
||||
/* aVendorModel */ nullptr,
|
||||
/* aVendorSwVersion */ nullptr,
|
||||
/* aVendorData */ nullptr,
|
||||
/* aCallback */ nullptr,
|
||||
/* aContext */ nullptr));
|
||||
|
||||
joinerIids[1].SetFromExtAddress(joiners[1]->Get<Joiner>().GetId());
|
||||
|
||||
nexus.AdvanceTime(8 * Time::kOneSecondInMsec);
|
||||
|
||||
for (uint8_t i = 0; i < kNumEnrollers; i++)
|
||||
{
|
||||
Ip6::InterfaceIdentifier readIid;
|
||||
uint16_t joinerRouterRloc;
|
||||
|
||||
message = AsCoapMessagePtr(recvContext[i].mRelayRxMsgs.GetHead());
|
||||
|
||||
if ((modes[i] & MeshCoP::EnrollerModeTlv::kForwardJoinerRelayRx) == 0)
|
||||
{
|
||||
VerifyOrQuit(message == nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
VerifyOrQuit(message != nullptr);
|
||||
|
||||
VerifyOrQuit(message->ReadType() == Coap::kTypeNonConfirmable);
|
||||
VerifyOrQuit(message->ReadCode() == Coap::kCodePost);
|
||||
SuccessOrQuit(Tlv::Find<MeshCoP::JoinerIidTlv>(*message, readIid));
|
||||
SuccessOrQuit(Tlv::Find<MeshCoP::JoinerRouterLocatorTlv>(*message, joinerRouterRloc));
|
||||
|
||||
VerifyOrQuit(readIid == joinerIids[1]);
|
||||
VerifyOrQuit(joinerRouterRloc == admitter.Get<Mle::Mle>().GetRloc16());
|
||||
}
|
||||
|
||||
joiners[1]->Get<Joiner>().Stop();
|
||||
|
||||
for (uint8_t i = 0; i < kNumEnrollers; i++)
|
||||
{
|
||||
recvContext[i].Clear();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Send `EnrollerKeepAlive` message from `enrollers[0]` to revert its mode back to allowing both Joiner and UDP");
|
||||
|
||||
modes[0] = MeshCoP::EnrollerModeTlv::kForwardJoinerRelayRx | MeshCoP::EnrollerModeTlv::kForwardUdpProxyRx;
|
||||
|
||||
message =
|
||||
enrollers[0]->Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriEnrollerKeepAlive);
|
||||
VerifyOrQuit(message != nullptr);
|
||||
|
||||
SuccessOrQuit(Tlv::Append<MeshCoP::StateTlv>(*message, MeshCoP::StateTlv::kAccept));
|
||||
SuccessOrQuit(Tlv::Append<MeshCoP::EnrollerModeTlv>(*message, modes[0]));
|
||||
|
||||
responseContexts[0].Clear();
|
||||
SuccessOrQuit(enrollers[0]->Get<Tmf::SecureAgent>().SendMessage(*message, HandleResponse, &responseContexts[0]));
|
||||
|
||||
nexus.AdvanceTime(Time::kOneSecondInMsec);
|
||||
|
||||
VerifyOrQuit(responseContexts[0].mReceived);
|
||||
VerifyOrQuit(responseContexts[0].mResponseState == MeshCoP::StateTlv::kAccept);
|
||||
VerifyOrQuit(responseContexts[0].mHasAdmitterState);
|
||||
|
||||
for (uint8_t i = 0; i < kNumEnrollers; i++)
|
||||
{
|
||||
recvContext[i].Clear();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Validate that the `enrollers[0]` mode got changed on `admitter`");
|
||||
|
||||
foundEnrollers.Clear();
|
||||
iter.Init(admitter.GetInstance());
|
||||
|
||||
while (iter.GetNextEnrollerInfo(enrollerInfo) == kErrorNone)
|
||||
{
|
||||
uint8_t matchedIndex;
|
||||
|
||||
LogEnroller(enrollerInfo);
|
||||
|
||||
matchedIndex = FindMatchingEnroller<kNumEnrollers>(enrollerInfo, kEnrollerIds, foundEnrollers);
|
||||
|
||||
VerifyOrQuit(AsCoreType(&enrollerInfo.mSteeringData) == steeringData);
|
||||
VerifyOrQuit(enrollerInfo.mMode == modes[matchedIndex]);
|
||||
|
||||
if (matchedIndex == 0)
|
||||
{
|
||||
SuccessOrQuit(iter.GetNextJoinerInfo(joinerInfo));
|
||||
VerifyOrQuit(AsCoreType(&joinerInfo.mIid) == joinerIids[0]);
|
||||
LogJoiner(joinerInfo);
|
||||
}
|
||||
|
||||
VerifyOrQuit(iter.GetNextJoinerInfo(joinerInfo) == kErrorNotFound);
|
||||
}
|
||||
|
||||
VerifyOrQuit(DidFindAllEnrollers<kNumEnrollers>(foundEnrollers));
|
||||
|
||||
nexus.AdvanceTime(Time::kOneSecondInMsec);
|
||||
|
||||
for (uint8_t i = 0; i < kNumEnrollers; i++)
|
||||
{
|
||||
recvContext[i].Clear();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Send `EnrollerKeepAlive` message from all `enrollers` to maintain the connection");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user