mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
1e79496c57
This commit adds support for handling mDNS service name conflicts by automatically renaming the service when a collision is detected during registration. The new naming scheme appends a suffix based on the last two bytes of the device's Extended Address (e.g., " #AB1E"). If this name also conflicts, an additional index is appended (e.g., " #AB1E (1)"). Changes: - Added `mServiceRenameIndex` to `Manager` and `EphemeralKeyManager` to track re-naming attempts. - Updated `otBorderAgentSetMeshCoPServiceBaseName()` and CLI documentation to reflect the new naming and conflict resolution logic. - Updated `OT_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME_MAX_LENGTH` to ensure the full name fits within the 63-character DNS label limit. - Added Nexus tests to verify the renaming logic under conflict.
2584 lines
110 KiB
C++
2584 lines
110 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 <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "platform/nexus_core.hpp"
|
|
#include "platform/nexus_node.hpp"
|
|
|
|
namespace ot {
|
|
namespace Nexus {
|
|
|
|
using ActiveDatasetManager = MeshCoP::ActiveDatasetManager;
|
|
using Manager = MeshCoP::BorderAgent::Manager;
|
|
using BaTxtData = MeshCoP::BorderAgent::TxtData;
|
|
using EphemeralKeyManager = MeshCoP::BorderAgent::EphemeralKeyManager;
|
|
using Admitter = MeshCoP::BorderAgent::Admitter;
|
|
using EpskcEvent = HistoryTracker::EpskcEvent;
|
|
using Iterator = HistoryTracker::Iterator;
|
|
using NetworkIdentity = MeshCoP::NetworkIdentity;
|
|
using NameData = MeshCoP::NameData;
|
|
using TxtEntry = Dns::TxtEntry;
|
|
|
|
void TestBorderAgent(void)
|
|
{
|
|
Core nexus;
|
|
Node &node0 = nexus.CreateNode();
|
|
Node &node1 = nexus.CreateNode();
|
|
Node &node2 = nexus.CreateNode();
|
|
Node &node3 = nexus.CreateNode();
|
|
Ip6::SockAddr sockAddr;
|
|
Pskc pskc;
|
|
Coap::Message *message;
|
|
Manager::SessionIterator iter;
|
|
Manager::SessionInfo sessionInfo;
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log("TestBorderAgent");
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
// Form the topology:
|
|
// - node0 leader acting as Border Agent,
|
|
// - node1-3 stay disconnected (acting as candidate)
|
|
|
|
node0.Form();
|
|
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader());
|
|
|
|
SuccessOrQuit(node1.Get<Mac::Mac>().SetPanChannel(node0.Get<Mac::Mac>().GetPanChannel()));
|
|
node1.Get<Mac::Mac>().SetPanId(node0.Get<Mac::Mac>().GetPanId());
|
|
node1.Get<ThreadNetif>().Up();
|
|
|
|
SuccessOrQuit(node2.Get<Mac::Mac>().SetPanChannel(node0.Get<Mac::Mac>().GetPanChannel()));
|
|
node2.Get<Mac::Mac>().SetPanId(node0.Get<Mac::Mac>().GetPanId());
|
|
node2.Get<ThreadNetif>().Up();
|
|
|
|
SuccessOrQuit(node3.Get<Mac::Mac>().SetPanChannel(node0.Get<Mac::Mac>().GetPanChannel()));
|
|
node3.Get<Mac::Mac>().SetPanId(node0.Get<Mac::Mac>().GetPanId());
|
|
node3.Get<ThreadNetif>().Up();
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check Border Agent initial state");
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().IsEnabled());
|
|
VerifyOrQuit(node0.Get<Manager>().IsRunning());
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check disabling and re-enabling of Border Agent");
|
|
|
|
node0.Get<Manager>().SetEnabled(false);
|
|
VerifyOrQuit(!node0.Get<Manager>().IsEnabled());
|
|
VerifyOrQuit(!node0.Get<Manager>().IsRunning());
|
|
|
|
node0.Get<Manager>().SetEnabled(true);
|
|
VerifyOrQuit(node0.Get<Manager>().IsEnabled());
|
|
VerifyOrQuit(node0.Get<Manager>().IsRunning());
|
|
|
|
SuccessOrQuit(node0.Get<Ip6::Filter>().AddUnsecurePort(node0.Get<Manager>().GetUdpPort()));
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Establish a DTLS connection to Border Agent");
|
|
|
|
sockAddr.SetAddress(node0.Get<Mle::Mle>().GetLinkLocalAddress());
|
|
sockAddr.SetPort(node0.Get<Manager>().GetUdpPort());
|
|
|
|
node0.Get<KeyManager>().GetPskc(pskc);
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SetPsk(pskc.m8, Pskc::kSize));
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mPskcSecureSessionSuccesses == 1);
|
|
|
|
iter.Init(node0.GetInstance());
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(!sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node1.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Disconnect from candidate side");
|
|
|
|
node1.Get<Tmf::SecureAgent>().Close();
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<Manager>().IsRunning());
|
|
|
|
iter.Init(node0.GetInstance());
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Establish a secure connection again");
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mPskcSecureSessionSuccesses == 2);
|
|
|
|
iter.Init(node0.GetInstance());
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(!sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node1.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Send `Commissioner Petition` TMF command to become full commissioner");
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerPetition);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mPskcSecureSessionSuccesses == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mPskcCommissionerPetitions == 1);
|
|
|
|
iter.Init(node0.GetInstance());
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node1.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Send `Commissioner Keep Alive` and check timeout behavior");
|
|
|
|
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
iter.Init(node0.GetInstance());
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerKeepAlive);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::StateTlv>(*message, MeshCoP::StateTlv::kAccept));
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
Log(" Wait for 49 seconds (TIMEOUT_LEAD_PET is 50 seconds) and check BA state");
|
|
|
|
nexus.AdvanceTime(49 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
Log(" Wait for additional 5 seconds (ensuring TIMEOUT_LEAD_PET and session disconnect guard time expires)");
|
|
|
|
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().IsRunning());
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
iter.Init(node0.GetInstance());
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Establish a secure session again and petition to become commissioner");
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerPetition);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mPskcSecureSessionSuccesses == 3);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mPskcCommissionerPetitions == 2);
|
|
|
|
iter.Init(node0.GetInstance());
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node1.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Establish two more secure sessions while the first session is still active");
|
|
|
|
SuccessOrQuit(node2.Get<Tmf::SecureAgent>().SetPsk(pskc.m8, Pskc::kSize));
|
|
SuccessOrQuit(node2.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node2.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
SuccessOrQuit(node3.Get<Tmf::SecureAgent>().SetPsk(pskc.m8, Pskc::kSize));
|
|
SuccessOrQuit(node3.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node3.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node2.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node3.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mPskcSecureSessionSuccesses == 5);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mPskcCommissionerPetitions == 2);
|
|
|
|
iter.Init(node0.GetInstance());
|
|
|
|
for (uint8_t numSessions = 0; numSessions < 3; numSessions++)
|
|
{
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
|
|
if (node1.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)))
|
|
{
|
|
VerifyOrQuit(sessionInfo.mIsCommissioner);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(node2.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)) ||
|
|
node3.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
VerifyOrQuit(!sessionInfo.mIsCommissioner);
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Disconnect from candidate side on node 1");
|
|
|
|
node1.Get<Tmf::SecureAgent>().Close();
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<Manager>().IsRunning());
|
|
|
|
VerifyOrQuit(node2.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node3.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
iter.Init(node0.GetInstance());
|
|
|
|
for (uint8_t numSessions = 0; numSessions < 2; numSessions++)
|
|
{
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(!sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node2.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)) ||
|
|
node3.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
}
|
|
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Connect again from node 1 after 25 seconds");
|
|
|
|
nexus.AdvanceTime(25 * Time::kOneSecondInMsec);
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node2.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node3.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
iter.Init(node0.GetInstance());
|
|
|
|
for (uint8_t numSessions = 0; numSessions < 3; numSessions++)
|
|
{
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(!sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node1.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)) ||
|
|
node2.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)) ||
|
|
node3.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
}
|
|
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Wait for the first two sessions to timeout, check that only the recent node1 session is connected");
|
|
|
|
nexus.AdvanceTime(28 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(!node2.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(!node3.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
iter.Init(node0.GetInstance());
|
|
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(!sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node1.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Wait for the node1 session to also timeout, validate that its disconnected");
|
|
|
|
nexus.AdvanceTime(25 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(!node2.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(!node3.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
iter.Init(node0.GetInstance());
|
|
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
static bool sEphemeralKeyCallbackCalled = false;
|
|
|
|
void HandleEphemeralKeyChange(void *aContext)
|
|
{
|
|
Node *node;
|
|
|
|
VerifyOrQuit(aContext != nullptr);
|
|
node = reinterpret_cast<Node *>(aContext);
|
|
|
|
Log(" EphemeralKeyCallback() state:%s",
|
|
EphemeralKeyManager::StateToString(node->Get<EphemeralKeyManager>().GetState()));
|
|
sEphemeralKeyCallbackCalled = true;
|
|
}
|
|
|
|
void TestBorderAgentEphemeralKey(void)
|
|
{
|
|
static const char kEphemeralKey[] = "nexus1234";
|
|
static const char kTooShortEphemeralKey[] = "abcde";
|
|
static const char kTooLongEphemeralKey[] = "012345678901234567890123456789012";
|
|
|
|
static constexpr uint16_t kEphemeralKeySize = sizeof(kEphemeralKey) - 1;
|
|
static constexpr uint16_t kUdpPort = 49155;
|
|
|
|
Core nexus;
|
|
Node &node0 = nexus.CreateNode();
|
|
Node &node1 = nexus.CreateNode();
|
|
Node &node2 = nexus.CreateNode();
|
|
Ip6::SockAddr sockAddr;
|
|
Ip6::SockAddr baSockAddr;
|
|
Pskc pskc;
|
|
Manager::SessionIterator iter;
|
|
Manager::SessionInfo sessionInfo;
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log("TestBorderAgentEphemeralKey");
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
// Form the topology:
|
|
// - node0 leader acting as Border Agent,
|
|
// - node1 and node2 staying disconnected (acting as candidate)
|
|
|
|
node0.Form();
|
|
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader());
|
|
|
|
SuccessOrQuit(node1.Get<Mac::Mac>().SetPanChannel(node0.Get<Mac::Mac>().GetPanChannel()));
|
|
node1.Get<Mac::Mac>().SetPanId(node0.Get<Mac::Mac>().GetPanId());
|
|
node1.Get<ThreadNetif>().Up();
|
|
|
|
SuccessOrQuit(node2.Get<Mac::Mac>().SetPanChannel(node0.Get<Mac::Mac>().GetPanChannel()));
|
|
node2.Get<Mac::Mac>().SetPanId(node0.Get<Mac::Mac>().GetPanId());
|
|
node2.Get<ThreadNetif>().Up();
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check Border Agent ephemeral key counter's initial value");
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 0);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcSecureSessionSuccesses == 0);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationTimeouts == 0);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationDisconnects == 0);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationMaxAttempts == 0);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationClears == 0);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcInvalidArgsErrors == 0);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcInvalidBaStateErrors == 0);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check Border Agent ephemeral key feature enabled");
|
|
|
|
node0.Get<EphemeralKeyManager>().SetEnabled(false);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateDisabled);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort) ==
|
|
kErrorInvalidState);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcInvalidBaStateErrors == 1);
|
|
|
|
node0.Get<EphemeralKeyManager>().SetEnabled(true);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check Border Agent ephemeral key initial state");
|
|
|
|
sEphemeralKeyCallbackCalled = false;
|
|
VerifyOrQuit(!sEphemeralKeyCallbackCalled);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Set and start ephemeral key on Border Agent");
|
|
|
|
node0.Get<EphemeralKeyManager>().SetCallback(HandleEphemeralKeyChange, &node0);
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 1);
|
|
|
|
SuccessOrQuit(node0.Get<Ip6::Filter>().AddUnsecurePort(kUdpPort));
|
|
|
|
nexus.AdvanceTime(0);
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Establish a secure connection with BA using the ephemeral key");
|
|
|
|
sEphemeralKeyCallbackCalled = false;
|
|
sockAddr.SetAddress(node0.Get<Mle::Mle>().GetLinkLocalAddress());
|
|
sockAddr.SetPort(kUdpPort);
|
|
|
|
SuccessOrQuit(
|
|
node1.Get<Tmf::SecureAgent>().SetPsk(reinterpret_cast<const uint8_t *>(kEphemeralKey), kEphemeralKeySize));
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateConnected);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 1);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcSecureSessionSuccesses == 1);
|
|
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Disconnect from candidate side, check that ephemeral key use is stopped");
|
|
|
|
sEphemeralKeyCallbackCalled = false;
|
|
|
|
node1.Get<Tmf::SecureAgent>().Close();
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 1);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcSecureSessionSuccesses == 1);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
|
|
|
nexus.AdvanceTime(10 * Time::kOneSecondInMsec);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Start using ephemeral key again with short timeout (20 seconds) and establish a connection");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, 20 * Time::kOneSecondInMsec, kUdpPort));
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(2 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateConnected);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcSecureSessionSuccesses == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
|
|
|
Log(" Check the ephemeral key timeout behavior");
|
|
|
|
sEphemeralKeyCallbackCalled = false;
|
|
nexus.AdvanceTime(25 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcSecureSessionSuccesses == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationTimeouts == 1);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Start using ephemeral key without any candidate connecting, check timeout");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
|
|
|
Log(" Wait more than 120 seconds (default ephemeral key timeout)");
|
|
sEphemeralKeyCallbackCalled = false;
|
|
nexus.AdvanceTime(122 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 3);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcSecureSessionSuccesses == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationTimeouts == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check that ephemeral key use is stopped after max failed connection attempts");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
|
|
|
SuccessOrQuit(
|
|
node1.Get<Tmf::SecureAgent>().SetPsk(reinterpret_cast<const uint8_t *>(kEphemeralKey), kEphemeralKeySize - 2));
|
|
|
|
for (uint8_t numAttempts = 1; numAttempts < 10; numAttempts++)
|
|
{
|
|
Log(" Attempt %u to connect with the wrong key", numAttempts);
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
}
|
|
|
|
Log(" Attempt 10 (final attempt) to connect with the wrong key, check that ephemeral key use is stopped");
|
|
|
|
sEphemeralKeyCallbackCalled = false;
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 4);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcSecureSessionSuccesses == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationTimeouts == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationMaxAttempts == 1);
|
|
|
|
node1.Get<Tmf::SecureAgent>().Close();
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Validate that disabling ephemeral key will stop and disconnect an active session");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
|
|
|
SuccessOrQuit(
|
|
node1.Get<Tmf::SecureAgent>().SetPsk(reinterpret_cast<const uint8_t *>(kEphemeralKey), kEphemeralKeySize));
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateConnected);
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
sEphemeralKeyCallbackCalled = false;
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateConnected);
|
|
node0.Get<EphemeralKeyManager>().SetEnabled(false);
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateDisabled);
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 5);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcSecureSessionSuccesses == 3);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationTimeouts == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationMaxAttempts == 1);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationClears == 1);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check ephemeral key can be used along with PSKc");
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().IsRunning());
|
|
SuccessOrQuit(node0.Get<Ip6::Filter>().AddUnsecurePort(node0.Get<Manager>().GetUdpPort()));
|
|
|
|
node0.Get<EphemeralKeyManager>().SetEnabled(true);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
|
|
|
Log(" Establish a secure session using PSKc (from node2)");
|
|
|
|
baSockAddr.SetAddress(node0.Get<Mle::Mle>().GetLinkLocalAddress());
|
|
baSockAddr.SetPort(node0.Get<Manager>().GetUdpPort());
|
|
|
|
node0.Get<KeyManager>().GetPskc(pskc);
|
|
SuccessOrQuit(node2.Get<Tmf::SecureAgent>().SetPsk(pskc.m8, Pskc::kSize));
|
|
SuccessOrQuit(node2.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node2.Get<Tmf::SecureAgent>().Connect(baSockAddr));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node2.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
iter.Init(node0.GetInstance());
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(!sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node2.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
Log(" Establish a secure session using ephemeral key (from node1)");
|
|
|
|
node1.Get<Tmf::SecureAgent>().Close();
|
|
SuccessOrQuit(
|
|
node1.Get<Tmf::SecureAgent>().SetPsk(reinterpret_cast<const uint8_t *>(kEphemeralKey), kEphemeralKeySize));
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateConnected);
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
Log(" Stop the secure session using ephemeral key");
|
|
|
|
node0.Get<EphemeralKeyManager>().Stop();
|
|
|
|
sEphemeralKeyCallbackCalled = false;
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
VerifyOrQuit(sEphemeralKeyCallbackCalled);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 6);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcSecureSessionSuccesses == 4);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationTimeouts == 2);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationDisconnects == 1);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationMaxAttempts == 1);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcDeactivationClears == 2);
|
|
|
|
Log(" Check the BA session using PSKc is still connected");
|
|
|
|
VerifyOrQuit(node2.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
iter.Init(node0.GetInstance());
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(!sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node2.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node2.Get<Tmf::SecureAgent>().IsConnected());
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
|
|
iter.Init(node0.GetInstance());
|
|
SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo));
|
|
VerifyOrQuit(sessionInfo.mIsConnected);
|
|
VerifyOrQuit(!sessionInfo.mIsCommissioner);
|
|
VerifyOrQuit(node2.Get<ThreadNetif>().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)));
|
|
VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check proper error is returned with invalid ephemeral key (too short or long)");
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().Start(kTooShortEphemeralKey, /* aTimeout */ 0, kUdpPort) ==
|
|
kErrorInvalidArgs);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 6);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcInvalidArgsErrors == 1);
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().Start(kTooLongEphemeralKey, /* aTimeout */ 0, kUdpPort) ==
|
|
kErrorInvalidArgs);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcActivations == 6);
|
|
VerifyOrQuit(node0.Get<Manager>().GetCounters().mEpskcInvalidArgsErrors == 2);
|
|
}
|
|
|
|
void TestBorderAgentEphemeralKeyTapGeneration(void)
|
|
{
|
|
static constexpr uint16_t kMaxRounds = 20;
|
|
|
|
using Tap = EphemeralKeyManager::Tap;
|
|
|
|
Core nexus;
|
|
Node &node = nexus.CreateNode();
|
|
Tap tap;
|
|
uint8_t index;
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log("TestBorderAgentEphemeralKeyTapGeneration");
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
node.Form();
|
|
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node.Get<Mle::Mle>().IsLeader());
|
|
|
|
for (uint16_t round = 0; round < kMaxRounds; round++)
|
|
{
|
|
SuccessOrQuit(tap.GenerateRandom());
|
|
SuccessOrQuit(tap.Validate());
|
|
Log("Generated random TAP: %s", tap.mTap);
|
|
|
|
// Tamper with one of the digits and ensure checksum fails.
|
|
|
|
index = round % Tap::kLength;
|
|
|
|
tap.mTap[index]++;
|
|
|
|
if (tap.mTap[index] > '9')
|
|
{
|
|
tap.mTap[index] = '0';
|
|
}
|
|
|
|
VerifyOrQuit(tap.Validate() == kErrorFailed);
|
|
}
|
|
|
|
// CHeck valid TAP strings (Thread spec (1.4.1d3) - section 8.4.9.7)
|
|
|
|
SuccessOrQuit(StringCopy(tap.mTap, "903723159"));
|
|
SuccessOrQuit(tap.Validate());
|
|
|
|
SuccessOrQuit(StringCopy(tap.mTap, "746351983"));
|
|
SuccessOrQuit(tap.Validate());
|
|
|
|
// Check invalid TAP strings.
|
|
|
|
SuccessOrQuit(StringCopy(tap.mTap, ""));
|
|
VerifyOrQuit(tap.Validate() == kErrorInvalidArgs);
|
|
|
|
SuccessOrQuit(StringCopy(tap.mTap, "1234"));
|
|
VerifyOrQuit(tap.Validate() == kErrorInvalidArgs);
|
|
|
|
SuccessOrQuit(StringCopy(tap.mTap, "12345678"));
|
|
VerifyOrQuit(tap.Validate() == kErrorInvalidArgs);
|
|
|
|
SuccessOrQuit(StringCopy(tap.mTap, "123456789"));
|
|
VerifyOrQuit(tap.Validate() == kErrorFailed);
|
|
|
|
SuccessOrQuit(StringCopy(tap.mTap, "a23456789"));
|
|
VerifyOrQuit(tap.Validate() == kErrorInvalidArgs);
|
|
|
|
SuccessOrQuit(StringCopy(tap.mTap, "12345678A"));
|
|
VerifyOrQuit(tap.Validate() == kErrorInvalidArgs);
|
|
}
|
|
|
|
EpskcEvent GetNewestEpskcEvent(Node &aNode)
|
|
{
|
|
const EpskcEvent *epskcEvent = nullptr;
|
|
Iterator iter;
|
|
uint32_t age;
|
|
iter.Init();
|
|
|
|
epskcEvent = aNode.Get<HistoryTracker::Local>().IterateEpskcEventHistory(iter, age);
|
|
|
|
VerifyOrQuit(epskcEvent != nullptr);
|
|
return *epskcEvent;
|
|
}
|
|
|
|
void TestHistoryTrackerBorderAgentEpskcEvent(void)
|
|
{
|
|
static const char kEphemeralKey[] = "nexus1234";
|
|
|
|
static constexpr uint16_t kEphemeralKeySize = sizeof(kEphemeralKey) - 1;
|
|
static constexpr uint16_t kUdpPort = 49155;
|
|
|
|
Core nexus;
|
|
Node &node0 = nexus.CreateNode();
|
|
Node &node1 = nexus.CreateNode();
|
|
Ip6::SockAddr sockAddr;
|
|
Coap::Message *message;
|
|
EpskcEvent epskcEvent;
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log("TestHistoryTrackerBorderAgentEpskcEvent");
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
// Form the topology:
|
|
// - node0 leader acting as Border Agent.
|
|
// - node1 acting as candidate
|
|
|
|
node0.Form();
|
|
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader());
|
|
sockAddr.SetAddress(node0.Get<Mle::Mle>().GetLinkLocalAddress());
|
|
sockAddr.SetPort(kUdpPort);
|
|
|
|
SuccessOrQuit(node1.Get<Mac::Mac>().SetPanChannel(node0.Get<Mac::Mac>().GetPanChannel()));
|
|
node1.Get<Mac::Mac>().SetPanId(node0.Get<Mac::Mac>().GetPanId());
|
|
node1.Get<ThreadNetif>().Up();
|
|
|
|
// Enable the Ephemeral Key feature.
|
|
node0.Get<EphemeralKeyManager>().SetEnabled(true);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log(" Check Ephemeral Key Journey 1: Epskc Mode is activated, then deactivated");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_ACTIVATED);
|
|
|
|
node0.Get<EphemeralKeyManager>().Stop();
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_DEACTIVATED_LOCAL_CLOSE);
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log(" Check Ephemeral Key Journey 2: Epskc Mode is activated, then deactivated after max failed connection "
|
|
"attempts");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
SuccessOrQuit(node0.Get<Ip6::Filter>().AddUnsecurePort(kUdpPort));
|
|
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_ACTIVATED);
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Open());
|
|
SuccessOrQuit(
|
|
node1.Get<Tmf::SecureAgent>().SetPsk(reinterpret_cast<const uint8_t *>(kEphemeralKey), kEphemeralKeySize - 2));
|
|
|
|
for (uint8_t numAttempts = 1; numAttempts < 10; numAttempts++)
|
|
{
|
|
Log(" Attempt %u to connect with the wrong key", numAttempts);
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
}
|
|
|
|
Log(" Attempt 10 (final attempt) to connect with the wrong key, check that ephemeral key use is stopped");
|
|
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_DEACTIVATED_MAX_ATTEMPTS);
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log(" Check Ephemeral Key Journey 3: The session is connected successfully, then disconnected by API");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_ACTIVATED);
|
|
|
|
SuccessOrQuit(
|
|
node1.Get<Tmf::SecureAgent>().SetPsk(reinterpret_cast<const uint8_t *>(kEphemeralKey), kEphemeralKeySize));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_CONNECTED);
|
|
|
|
node0.Get<EphemeralKeyManager>().Stop();
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_DEACTIVATED_LOCAL_CLOSE);
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log(" Check Ephemeral Key Journey 4: The session is connected successfully. And the candidate petitioned as an "
|
|
"active commissioner. The session is disconnected by the remote.");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_ACTIVATED);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_CONNECTED);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerPetition);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_PETITIONED);
|
|
|
|
node1.Get<Tmf::SecureAgent>().Disconnect();
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_DEACTIVATED_REMOTE_CLOSE);
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log(" Check Ephemeral Key Journey 5: The session is connected successfully. And the active dataset is fetched. "
|
|
"The session is disconnected by the remote.");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_ACTIVATED);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_CONNECTED);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerPetition);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_PETITIONED);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriActiveGet);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_RETRIEVED_ACTIVE_DATASET);
|
|
|
|
node1.Get<Tmf::SecureAgent>().Disconnect();
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_DEACTIVATED_REMOTE_CLOSE);
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log(" Check Ephemeral Key Journey 6: The session is connected successfully. And the pending dataset is fetched. "
|
|
"The session is disconnected by the remote.");
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_ACTIVATED);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_CONNECTED);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerPetition);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_PETITIONED);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriActiveGet);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_RETRIEVED_ACTIVE_DATASET);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriPendingGet);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_RETRIEVED_PENDING_DATASET);
|
|
|
|
node1.Get<Tmf::SecureAgent>().Disconnect();
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_DEACTIVATED_REMOTE_CLOSE);
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log(" Check Ephemeral Key Journey 7: The session is connected successfully. And the pending dataset is fetched. "
|
|
"The session is due to session timeout.");
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_ACTIVATED);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_CONNECTED);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerPetition);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_PETITIONED);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriActiveGet);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_RETRIEVED_ACTIVE_DATASET);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriPendingGet);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_RETRIEVED_PENDING_DATASET);
|
|
|
|
static constexpr uint32_t kKeepAliveTimeout = 50 * 1000; // Timeout to reject a commissioner (in msec)
|
|
nexus.AdvanceTime(kKeepAliveTimeout); // Wait for the session timeout
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_DEACTIVATED_SESSION_TIMEOUT);
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log(" Check Ephemeral Key Journey 8: The session is connected successfully. The epskc mode is deactivated due to "
|
|
"timeout.");
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_ACTIVATED);
|
|
|
|
VerifyOrQuit(!node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().Connect(sockAddr));
|
|
|
|
nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node1.Get<Tmf::SecureAgent>().IsConnected());
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_CONNECTED);
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerPetition);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_PETITIONED);
|
|
|
|
// Send a KeepAlive message every 30s until ePSKc mode timed out
|
|
for (uint8_t i = 0; i < EphemeralKeyManager::kDefaultTimeout / (30 * Time::kOneSecondInMsec) - 1; i++)
|
|
{
|
|
if (!node1.Get<Tmf::SecureAgent>().IsConnected())
|
|
{
|
|
break;
|
|
}
|
|
message =
|
|
node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerKeepAlive);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::StateTlv>(*message, MeshCoP::StateTlv::kAccept));
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
|
|
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_KEEP_ALIVE);
|
|
}
|
|
|
|
message = node1.Get<Tmf::SecureAgent>().AllocateAndInitPriorityConfirmablePostMessage(kUriCommissionerKeepAlive);
|
|
VerifyOrQuit(message != nullptr);
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::StateTlv>(*message, MeshCoP::StateTlv::kAccept));
|
|
SuccessOrQuit(Tlv::Append<MeshCoP::CommissionerIdTlv>(*message, "node1"));
|
|
SuccessOrQuit(node1.Get<Tmf::SecureAgent>().SendMessage(*message));
|
|
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
epskcEvent = GetNewestEpskcEvent(node0);
|
|
VerifyOrQuit(epskcEvent == OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_DEACTIVATED_EPSKC_TIMEOUT);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
struct TxtData
|
|
{
|
|
void Init(const uint8_t *aData, uint16_t aLength) { mData = aData, mLength = aLength; }
|
|
|
|
void ValidateFormat(void)
|
|
{
|
|
TxtEntry::Iterator iter;
|
|
TxtEntry txtEntry;
|
|
|
|
iter.Init(mData, mLength);
|
|
|
|
while (true)
|
|
{
|
|
Error error = iter.GetNextEntry(txtEntry);
|
|
|
|
if (error == kErrorNotFound)
|
|
{
|
|
break;
|
|
}
|
|
|
|
SuccessOrQuit(error);
|
|
VerifyOrQuit(txtEntry.mKey != nullptr);
|
|
}
|
|
}
|
|
|
|
void LogAllTxtEntries(void)
|
|
{
|
|
static constexpr uint16_t kValueStringSize = 256;
|
|
|
|
char valueString[kValueStringSize];
|
|
TxtEntry::Iterator iter;
|
|
TxtEntry txtEntry;
|
|
|
|
Log("TXT data - length %u", mLength);
|
|
|
|
iter.Init(mData, mLength);
|
|
|
|
while (true)
|
|
{
|
|
Error error = iter.GetNextEntry(txtEntry);
|
|
StringWriter writer(valueString, sizeof(valueString));
|
|
|
|
if (error == kErrorNotFound)
|
|
{
|
|
break;
|
|
}
|
|
|
|
SuccessOrQuit(error);
|
|
VerifyOrQuit(txtEntry.mKey != nullptr);
|
|
|
|
writer.AppendHexBytes(txtEntry.mValue, txtEntry.mValueLength);
|
|
Log(" %s -> [%s] (len:%u)", txtEntry.mKey, valueString, txtEntry.mValueLength);
|
|
}
|
|
}
|
|
|
|
bool ContainsKey(const char *aKey) const
|
|
{
|
|
TxtEntry txtEntry;
|
|
|
|
return FindTxtEntry(aKey, txtEntry);
|
|
}
|
|
|
|
void ValidateKey(const char *aKey, const void *aValue, uint16_t aValueLength) const
|
|
{
|
|
TxtEntry txtEntry;
|
|
|
|
VerifyOrQuit(FindTxtEntry(aKey, txtEntry));
|
|
VerifyOrQuit(txtEntry.mValueLength == aValueLength);
|
|
VerifyOrQuit(memcmp(txtEntry.mValue, aValue, aValueLength) == 0);
|
|
}
|
|
|
|
template <typename ObjectType> void ValidateKey(const char *aKey, const ObjectType &aObject) const
|
|
{
|
|
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
|
|
|
|
ValidateKey(aKey, &aObject, sizeof(aObject));
|
|
}
|
|
|
|
void ValidateKey(const char *aKey, const char *aString) const { ValidateKey(aKey, aString, strlen(aString)); }
|
|
|
|
uint32_t ReadUint32Key(const char *aKey) const
|
|
{
|
|
TxtEntry txtEntry;
|
|
|
|
VerifyOrQuit(FindTxtEntry(aKey, txtEntry));
|
|
VerifyOrQuit(txtEntry.mValueLength == sizeof(uint32_t));
|
|
return BigEndian::ReadUint32(txtEntry.mValue);
|
|
}
|
|
|
|
bool FindTxtEntry(const char *aKey, TxtEntry &aTxtEntry) const
|
|
{
|
|
bool found = false;
|
|
TxtEntry::Iterator iter;
|
|
|
|
iter.Init(mData, mLength);
|
|
|
|
while (iter.GetNextEntry(aTxtEntry) == kErrorNone)
|
|
{
|
|
VerifyOrQuit(aTxtEntry.mKey != nullptr);
|
|
|
|
if (StringMatch(aTxtEntry.mKey, aKey))
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
const uint8_t *mData;
|
|
uint16_t mLength;
|
|
};
|
|
|
|
void ValidateMeshCoPTxtData(TxtData &aTxtData, Node &aNode, bool aExpectVendorInfo, const char *aVendorName = nullptr)
|
|
{
|
|
// State bitmap masks and field values
|
|
static constexpr uint32_t kMaskConnectionMode = 7 << 0;
|
|
static constexpr uint32_t kConnectionModeDisabled = 0 << 0;
|
|
static constexpr uint32_t kConnectionModePskc = 1 << 0;
|
|
static constexpr uint32_t kMaskThreadIfStatus = 3 << 3;
|
|
static constexpr uint32_t kThreadIfStatusNotInitialized = 0 << 3;
|
|
static constexpr uint32_t kThreadIfStatusInitialized = 1 << 3;
|
|
static constexpr uint32_t kThreadIfStatusActive = 2 << 3;
|
|
static constexpr uint32_t kMaskThreadRole = 3 << 9;
|
|
static constexpr uint32_t kThreadRoleDisabledOrDetached = 0 << 9;
|
|
static constexpr uint32_t kThreadRoleChild = 1 << 9;
|
|
static constexpr uint32_t kThreadRoleRouter = 2 << 9;
|
|
static constexpr uint32_t kThreadRoleLeader = 3 << 9;
|
|
static constexpr uint32_t kFlagEpskcSupported = 1 << 11;
|
|
static constexpr uint32_t kFlagAdmitterSupported = 1 << 14;
|
|
|
|
MeshCoP::BorderAgent::Id id;
|
|
BaTxtData::Info info;
|
|
const Mac::ExtAddress &extAddress = aNode.Get<Mac::Mac>().GetExtAddress();
|
|
uint32_t stateBitmap;
|
|
uint32_t threadIfStatus;
|
|
uint32_t threadRole;
|
|
bool baIsRunning;
|
|
|
|
aTxtData.ValidateFormat();
|
|
aTxtData.LogAllTxtEntries();
|
|
|
|
SuccessOrQuit(info.ParseFrom(aTxtData.mData, aTxtData.mLength));
|
|
|
|
aNode.Get<Manager>().GetId(id);
|
|
aTxtData.ValidateKey("id", id);
|
|
VerifyOrQuit(info.mHasAgentId);
|
|
VerifyOrQuit(id == AsCoreType(&info.mAgentId));
|
|
|
|
aTxtData.ValidateKey("rv", "1");
|
|
VerifyOrQuit(info.mHasRecordVersion);
|
|
VerifyOrQuit(StringMatch(info.mRecordVersion, "1"));
|
|
|
|
aTxtData.ValidateKey("tv", kThreadVersionString);
|
|
VerifyOrQuit(info.mHasThreadVersion);
|
|
VerifyOrQuit(StringMatch(info.mThreadVersion, kThreadVersionString));
|
|
|
|
aTxtData.ValidateKey("xa", extAddress);
|
|
VerifyOrQuit(info.mHasExtAddress);
|
|
VerifyOrQuit(AsCoreType(&info.mExtAddress) == extAddress);
|
|
|
|
if (aNode.Get<MeshCoP::ActiveDatasetManager>().IsComplete())
|
|
{
|
|
const char *networkName = aNode.Get<NetworkIdentity>().GetNetworkName().GetAsCString();
|
|
const MeshCoP::ExtendedPanId &extPanId = aNode.Get<NetworkIdentity>().GetExtPanId();
|
|
|
|
aTxtData.ValidateKey("nn", networkName);
|
|
VerifyOrQuit(info.mHasNetworkName);
|
|
VerifyOrQuit(StringMatch(info.mNetworkName.m8, networkName));
|
|
|
|
aTxtData.ValidateKey("xp", extPanId);
|
|
VerifyOrQuit(info.mHasExtendedPanId);
|
|
VerifyOrQuit(AsCoreType(&info.mExtendedPanId) == extPanId);
|
|
}
|
|
|
|
if (aNode.Get<Mle::Mle>().IsAttached())
|
|
{
|
|
uint32_t partitionId = aNode.Get<Mle::Mle>().GetLeaderData().GetPartitionId();
|
|
const MeshCoP::Timestamp ×tamp = aNode.Get<ActiveDatasetManager>().GetTimestamp();
|
|
MeshCoP::Timestamp::Info timestampInfo;
|
|
|
|
aTxtData.ValidateKey("pt", BigEndian::HostSwap32(partitionId));
|
|
VerifyOrQuit(info.mHasPartitionId);
|
|
VerifyOrQuit(info.mPartitionId == partitionId);
|
|
|
|
aTxtData.ValidateKey("at", timestamp);
|
|
timestamp.ConvertTo(timestampInfo);
|
|
VerifyOrQuit(info.mHasActiveTimestamp);
|
|
VerifyOrQuit(info.mActiveTimestamp.mSeconds == timestampInfo.mSeconds);
|
|
VerifyOrQuit(info.mActiveTimestamp.mTicks == timestampInfo.mTicks);
|
|
VerifyOrQuit(info.mActiveTimestamp.mAuthoritative == timestampInfo.mAuthoritative);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!aTxtData.ContainsKey("pt"));
|
|
VerifyOrQuit(!info.mHasPartitionId);
|
|
|
|
VerifyOrQuit(!aTxtData.ContainsKey("at"));
|
|
VerifyOrQuit(!info.mHasActiveTimestamp);
|
|
}
|
|
|
|
stateBitmap = aTxtData.ReadUint32Key("sb");
|
|
VerifyOrQuit(info.mHasStateBitmap);
|
|
|
|
baIsRunning = aNode.Get<Manager>().IsRunning();
|
|
VerifyOrQuit((stateBitmap & kMaskConnectionMode) == (baIsRunning ? kConnectionModePskc : kConnectionModeDisabled));
|
|
VerifyOrQuit(info.mStateBitmap.mConnMode ==
|
|
(baIsRunning ? BaTxtData::kConnModePskc : BaTxtData::kConnModeDisabled));
|
|
|
|
switch (aNode.Get<Mle::Mle>().GetRole())
|
|
{
|
|
case Mle::DeviceRole::kRoleDisabled:
|
|
threadIfStatus = kThreadIfStatusNotInitialized;
|
|
threadRole = kThreadRoleDisabledOrDetached;
|
|
VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfNotInit);
|
|
VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleDisabledDetached);
|
|
break;
|
|
case Mle::DeviceRole::kRoleDetached:
|
|
threadIfStatus = kThreadIfStatusInitialized;
|
|
threadRole = kThreadRoleDisabledOrDetached;
|
|
VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfInit);
|
|
VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleDisabledDetached);
|
|
break;
|
|
case Mle::DeviceRole::kRoleChild:
|
|
threadIfStatus = kThreadIfStatusActive;
|
|
threadRole = kThreadRoleChild;
|
|
VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfActive);
|
|
VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleChild);
|
|
break;
|
|
case Mle::DeviceRole::kRoleRouter:
|
|
threadIfStatus = kThreadIfStatusActive;
|
|
threadRole = kThreadRoleRouter;
|
|
VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfActive);
|
|
VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleRouter);
|
|
break;
|
|
case Mle::DeviceRole::kRoleLeader:
|
|
threadIfStatus = kThreadIfStatusActive;
|
|
threadRole = kThreadRoleLeader;
|
|
VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfActive);
|
|
VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleLeader);
|
|
break;
|
|
}
|
|
|
|
VerifyOrQuit((stateBitmap & kMaskThreadIfStatus) == threadIfStatus);
|
|
VerifyOrQuit((stateBitmap & kMaskThreadRole) == threadRole);
|
|
|
|
if (aNode.Get<EphemeralKeyManager>().GetState() != EphemeralKeyManager::kStateDisabled)
|
|
{
|
|
VerifyOrQuit(stateBitmap & kFlagEpskcSupported);
|
|
VerifyOrQuit(info.mStateBitmap.mEpskcSupported);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!(stateBitmap & kFlagEpskcSupported));
|
|
VerifyOrQuit(!info.mStateBitmap.mEpskcSupported);
|
|
}
|
|
|
|
if (aNode.Get<Admitter>().IsEnabled())
|
|
{
|
|
VerifyOrQuit(stateBitmap & kFlagAdmitterSupported);
|
|
VerifyOrQuit(info.mStateBitmap.mAdmitterSupported);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!(stateBitmap & kFlagAdmitterSupported));
|
|
VerifyOrQuit(!info.mStateBitmap.mAdmitterSupported);
|
|
}
|
|
|
|
if (aExpectVendorInfo)
|
|
{
|
|
const char *expectedVendorName = (aVendorName != nullptr) ? aVendorName : aNode.Get<VendorInfo>().GetName();
|
|
const char *expectedModelName = aNode.Get<VendorInfo>().GetModel();
|
|
|
|
aTxtData.ValidateKey("vn", expectedVendorName);
|
|
VerifyOrQuit(info.mHasVendorName);
|
|
VerifyOrQuit(StringMatch(info.mVendorName, expectedVendorName));
|
|
|
|
aTxtData.ValidateKey("mn", expectedModelName);
|
|
VerifyOrQuit(info.mHasModelName);
|
|
VerifyOrQuit(StringMatch(info.mModelName, expectedModelName));
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!aTxtData.ContainsKey("vn"));
|
|
VerifyOrQuit(!info.mHasVendorName);
|
|
|
|
VerifyOrQuit(!aTxtData.ContainsKey("mn"));
|
|
VerifyOrQuit(!info.mHasModelName);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
void HandleServiceChanged(void *aContext) // Callback used in `TestBorderAgentTxtDataCallback().`
|
|
{
|
|
// `aContext` is a boolean `callbackInvoked`
|
|
VerifyOrQuit(aContext != nullptr);
|
|
*static_cast<bool *>(aContext) = true;
|
|
}
|
|
|
|
void ReadAndValidateMeshCoPTxtData(Node &aNode)
|
|
{
|
|
BaTxtData::ServiceTxtData serviceTxtData;
|
|
TxtData txtData;
|
|
|
|
SuccessOrQuit(aNode.Get<BaTxtData>().Prepare(serviceTxtData));
|
|
txtData.Init(serviceTxtData.mData, serviceTxtData.mLength);
|
|
|
|
ValidateMeshCoPTxtData(txtData, aNode, /* aExpectVendorInfo */ false);
|
|
}
|
|
|
|
void TestBorderAgentTxtDataCallback(void)
|
|
{
|
|
Core nexus;
|
|
Node &node0 = nexus.CreateNode();
|
|
bool callbackInvoked = false;
|
|
MeshCoP::BorderAgent::Id newId;
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log("TestBorderAgentTxtDataCallback");
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Set MeshCoP service change callback. Will get initial values.
|
|
Log("Set MeshCoP service change callback and check initial values");
|
|
node0.Get<BaTxtData>().SetChangedCallback(HandleServiceChanged, &callbackInvoked);
|
|
nexus.AdvanceTime(1);
|
|
|
|
// Check the initial TXT entries
|
|
ReadAndValidateMeshCoPTxtData(node0);
|
|
|
|
// Check the Border Agent state
|
|
VerifyOrQuit(!node0.Get<Manager>().IsRunning());
|
|
VerifyOrQuit(node0.Get<Manager>().GetUdpPort() == 0);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Join Thread network and check updated values and states.
|
|
callbackInvoked = false;
|
|
Log("Join Thread network and check updated Txt data and states");
|
|
node0.Form();
|
|
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(callbackInvoked);
|
|
ReadAndValidateMeshCoPTxtData(node0);
|
|
|
|
VerifyOrQuit(node0.Get<Manager>().IsRunning());
|
|
VerifyOrQuit(node0.Get<Manager>().GetUdpPort() != 0);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Log("Change the Border Agent ID and validate that TXT data changed and callback is invoked");
|
|
|
|
newId.GenerateRandom();
|
|
|
|
callbackInvoked = false;
|
|
node0.Get<Manager>().SetId(newId);
|
|
|
|
nexus.AdvanceTime(1);
|
|
ReadAndValidateMeshCoPTxtData(node0);
|
|
|
|
// Validate that setting the ID to the same value as before is
|
|
// correctly detected and does not trigger the callback.
|
|
|
|
callbackInvoked = false;
|
|
node0.Get<Manager>().SetId(newId);
|
|
nexus.AdvanceTime(1);
|
|
VerifyOrQuit(!callbackInvoked);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Disable EphemeralKeyManager and validate that TXT data state bitmap indicates this");
|
|
|
|
callbackInvoked = false;
|
|
node0.Get<EphemeralKeyManager>().SetEnabled(false);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateDisabled);
|
|
|
|
nexus.AdvanceTime(1);
|
|
VerifyOrQuit(callbackInvoked);
|
|
ReadAndValidateMeshCoPTxtData(node0);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Disable the MLE operation and validate the TXT data state bitmap");
|
|
|
|
callbackInvoked = false;
|
|
SuccessOrQuit(node0.Get<Mle::Mle>().Disable());
|
|
|
|
nexus.AdvanceTime(1);
|
|
VerifyOrQuit(callbackInvoked);
|
|
ReadAndValidateMeshCoPTxtData(node0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
static constexpr uint32_t kInfraIfIndex = 1;
|
|
static constexpr uint16_t kMaxEntries = 5;
|
|
static constexpr uint16_t kMaxTxtDataSize = 400;
|
|
|
|
typedef Dns::Name::Buffer DnsName;
|
|
|
|
struct BrowseOutcome
|
|
{
|
|
DnsName mServiceInstance;
|
|
uint32_t mTtl;
|
|
};
|
|
|
|
struct SrvOutcome
|
|
{
|
|
DnsName mHostName;
|
|
uint16_t mPort;
|
|
uint32_t mTtl;
|
|
};
|
|
|
|
struct TxtOutcome
|
|
{
|
|
uint8_t mTxtData[kMaxTxtDataSize];
|
|
uint16_t mTxtDataLength;
|
|
uint32_t mTtl;
|
|
};
|
|
|
|
static Array<BrowseOutcome, kMaxEntries> sBrowseOutcomes;
|
|
static Array<SrvOutcome, kMaxEntries> sSrvOutcomes;
|
|
static Array<TxtOutcome, kMaxEntries> sTxtOutcomes;
|
|
|
|
void HandleBrowseCallback(otInstance *aInstance, const Dns::Multicast::Core::BrowseResult *aResult)
|
|
{
|
|
BrowseOutcome *outcome;
|
|
|
|
VerifyOrQuit(aInstance != nullptr);
|
|
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
|
|
|
|
outcome = sBrowseOutcomes.PushBack();
|
|
VerifyOrQuit(outcome != nullptr);
|
|
|
|
SuccessOrQuit(StringCopy(outcome->mServiceInstance, aResult->mServiceInstance));
|
|
outcome->mTtl = aResult->mTtl;
|
|
}
|
|
|
|
void HandleSrvCallback(otInstance *aInstance, const Dns::Multicast::Core::SrvResult *aResult)
|
|
{
|
|
SrvOutcome *outcome;
|
|
|
|
VerifyOrQuit(aInstance != nullptr);
|
|
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
|
|
|
|
outcome = sSrvOutcomes.PushBack();
|
|
VerifyOrQuit(outcome != nullptr);
|
|
|
|
SuccessOrQuit(StringCopy(outcome->mHostName, aResult->mHostName));
|
|
outcome->mPort = aResult->mPort;
|
|
outcome->mTtl = aResult->mTtl;
|
|
}
|
|
|
|
void HandleTxtCallback(otInstance *aInstance, const Dns::Multicast::Core::TxtResult *aResult)
|
|
{
|
|
TxtOutcome *outcome;
|
|
|
|
VerifyOrQuit(aInstance != nullptr);
|
|
VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
|
|
|
|
outcome = sTxtOutcomes.PushBack();
|
|
VerifyOrQuit(outcome != nullptr);
|
|
|
|
VerifyOrQuit(aResult->mTxtDataLength < kMaxTxtDataSize);
|
|
memcpy(outcome->mTxtData, aResult->mTxtData, aResult->mTxtDataLength);
|
|
outcome->mTxtDataLength = aResult->mTxtDataLength;
|
|
outcome->mTtl = aResult->mTtl;
|
|
}
|
|
|
|
void ValidateRegisteredServiceData(Dns::Multicast::Core::Service &aService,
|
|
Node &aNode,
|
|
const char *aVendorName = nullptr)
|
|
{
|
|
TxtData txtData;
|
|
|
|
txtData.Init(aService.mTxtData, aService.mTxtDataLength);
|
|
ValidateMeshCoPTxtData(txtData, aNode, /* aExpectVendorInfo */ true, aVendorName);
|
|
}
|
|
|
|
void TestBorderAgentServiceRegistration(void)
|
|
{
|
|
static const char kDefaultServiceBaseName[] = OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME;
|
|
static const char kEphemeralKey[] = "nexus1234";
|
|
static const uint8_t kVendorTxtData[] = {8, 'v', 'n', '=', 'n', 'e', 'x', 'u', 's'};
|
|
|
|
static constexpr uint32_t kUdpPort = 49155;
|
|
|
|
Core nexus;
|
|
Node &node0 = nexus.CreateNode();
|
|
Node &node1 = nexus.CreateNode();
|
|
Dns::Multicast::Core::Iterator *iterator;
|
|
Dns::Multicast::Core::Service service;
|
|
Dns::Multicast::Core::EntryState entryState;
|
|
bool foundService;
|
|
bool foundEpskService;
|
|
Dns::Multicast::Core::Browser browser;
|
|
Dns::Multicast::Core::SrvResolver srvResolver;
|
|
Dns::Multicast::Core::TxtResolver txtResolver;
|
|
TxtData txtData;
|
|
uint16_t txtDataLengthWithNoVendorData;
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log("TestBorderAgentServiceRegistration");
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
node0.Form();
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disable Border Agent function on node1
|
|
node1.Get<MeshCoP::BorderAgent::Manager>().SetEnabled(false);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Enable mDNS
|
|
SuccessOrQuit(node0.Get<Dns::Multicast::Core>().SetEnabled(true, kInfraIfIndex));
|
|
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().IsEnabled());
|
|
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().SetEnabled(true, kInfraIfIndex));
|
|
VerifyOrQuit(node1.Get<Dns::Multicast::Core>().IsEnabled());
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader());
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent::Manager>().IsEnabled());
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Validate the registered mDNS MeshCop service by Border Agent");
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - -");
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, kDefaultServiceBaseName));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
foundService = true;
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Validate that the service can be resolved on other nodes");
|
|
|
|
ClearAllBytes(browser);
|
|
browser.mServiceType = "_meshcop._udp";
|
|
browser.mInfraIfIndex = kInfraIfIndex;
|
|
browser.mCallback = HandleBrowseCallback;
|
|
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StartBrowser(browser));
|
|
|
|
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(sBrowseOutcomes.GetLength() == 1);
|
|
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[0].mServiceInstance, kDefaultServiceBaseName));
|
|
VerifyOrQuit(sBrowseOutcomes[0].mTtl > 0);
|
|
|
|
ClearAllBytes(srvResolver);
|
|
srvResolver.mServiceInstance = sBrowseOutcomes[0].mServiceInstance;
|
|
srvResolver.mServiceType = browser.mServiceType;
|
|
srvResolver.mInfraIfIndex = kInfraIfIndex;
|
|
srvResolver.mCallback = HandleSrvCallback;
|
|
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StartSrvResolver(srvResolver));
|
|
|
|
ClearAllBytes(txtResolver);
|
|
txtResolver.mServiceInstance = sBrowseOutcomes[0].mServiceInstance;
|
|
txtResolver.mServiceType = browser.mServiceType;
|
|
txtResolver.mInfraIfIndex = kInfraIfIndex;
|
|
txtResolver.mCallback = HandleTxtCallback;
|
|
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StartTxtResolver(txtResolver));
|
|
|
|
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(sSrvOutcomes.GetLength() == 1);
|
|
VerifyOrQuit(StringStartsWith(sSrvOutcomes[0].mHostName, "ot"));
|
|
VerifyOrQuit(sSrvOutcomes[0].mTtl > 0);
|
|
VerifyOrQuit(sSrvOutcomes[0].mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
|
|
VerifyOrQuit(sTxtOutcomes.GetLength() == 1);
|
|
VerifyOrQuit(sTxtOutcomes[0].mTtl > 0);
|
|
txtData.Init(sTxtOutcomes[0].mTxtData, sTxtOutcomes[0].mTxtDataLength);
|
|
ValidateMeshCoPTxtData(txtData, node0, /* aExptecVendorInfo */ true);
|
|
|
|
sBrowseOutcomes.Clear();
|
|
sSrvOutcomes.Clear();
|
|
sTxtOutcomes.Clear();
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Enable and start ephemeral key");
|
|
|
|
node0.Get<EphemeralKeyManager>().SetEnabled(true);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
node0.Get<EphemeralKeyManager>().SetCallback(HandleEphemeralKeyChange, &node0);
|
|
|
|
SuccessOrQuit(node0.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
|
|
nexus.AdvanceTime(10 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
VerifyOrQuit(node0.Get<EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check the registered services");
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
foundEpskService = false;
|
|
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log("- - - - - - - - - - - - - - - - -");
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, kDefaultServiceBaseName));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
ValidateRegisteredServiceData(service, node0);
|
|
}
|
|
else if (StringMatch(service.mServiceType, "_meshcop-e._udp"))
|
|
{
|
|
VerifyOrQuit(!foundEpskService);
|
|
foundEpskService = true;
|
|
|
|
Log("- - - - - - - - - - - - - - - - -");
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, kDefaultServiceBaseName));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
VerifyOrQuit(service.mPort == kUdpPort);
|
|
VerifyOrQuit(service.mTxtDataLength == 1);
|
|
VerifyOrQuit(service.mTxtData[0] == 0);
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
VerifyOrQuit(foundEpskService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
VerifyOrQuit(sBrowseOutcomes.GetLength() == 0);
|
|
VerifyOrQuit(sSrvOutcomes.GetLength() == 0);
|
|
VerifyOrQuit(sTxtOutcomes.GetLength() == 0);
|
|
|
|
Log("Wait for the ephemeral key to expire and validate the registered service is removed");
|
|
|
|
nexus.AdvanceTime(5 * Time::kOneMinuteInMsec);
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, kDefaultServiceBaseName));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Change the base service name and validate the new service");
|
|
|
|
SuccessOrQuit(node0.Get<MeshCoP::BorderAgent::Manager>().SetServiceBaseName("OpenThreadAgent"));
|
|
|
|
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
}
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
// Check browser/resolver outcome on node1
|
|
|
|
VerifyOrQuit(sSrvOutcomes.GetLength() == 1);
|
|
VerifyOrQuit(sSrvOutcomes[0].mTtl == 0);
|
|
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StopSrvResolver(srvResolver));
|
|
|
|
VerifyOrQuit(sTxtOutcomes.GetLength() == 1);
|
|
VerifyOrQuit(sTxtOutcomes[0].mTtl == 0);
|
|
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().StopTxtResolver(txtResolver));
|
|
|
|
VerifyOrQuit(sBrowseOutcomes.GetLength() == 2);
|
|
VerifyOrQuit(sBrowseOutcomes[0].mTtl == 0);
|
|
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[0].mServiceInstance, kDefaultServiceBaseName));
|
|
|
|
VerifyOrQuit(sBrowseOutcomes[1].mTtl > 0);
|
|
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[1].mServiceInstance, "OpenThreadAgent"));
|
|
|
|
sBrowseOutcomes.Clear();
|
|
sSrvOutcomes.Clear();
|
|
sTxtOutcomes.Clear();
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Enable Admitter function");
|
|
|
|
node0.Get<Admitter>().SetEnabled(true);
|
|
VerifyOrQuit(node0.Get<Admitter>().IsEnabled());
|
|
|
|
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check the registered service");
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
}
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
nexus.AdvanceTime(10 * Time::kOneSecondInMsec);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Disable Admitter function");
|
|
|
|
node0.Get<Admitter>().SetEnabled(false);
|
|
VerifyOrQuit(!node0.Get<Admitter>().IsEnabled());
|
|
|
|
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check the registered service");
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Disable Border Agent and validate that registered service is removed");
|
|
|
|
node0.Get<MeshCoP::BorderAgent::Manager>().SetEnabled(false);
|
|
VerifyOrQuit(!node0.Get<MeshCoP::BorderAgent::Manager>().IsEnabled());
|
|
|
|
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
VerifyOrQuit(sBrowseOutcomes.GetLength() == 1);
|
|
VerifyOrQuit(sBrowseOutcomes[0].mTtl == 0);
|
|
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[0].mServiceInstance, "OpenThreadAgent"));
|
|
|
|
sBrowseOutcomes.Clear();
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Change the base service name while agent is disabled and validate no service is registered");
|
|
|
|
SuccessOrQuit(node0.Get<MeshCoP::BorderAgent::Manager>().SetServiceBaseName("NewName"));
|
|
|
|
VerifyOrQuit(!node0.Get<MeshCoP::BorderAgent::Manager>().IsEnabled());
|
|
|
|
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
VerifyOrQuit(sBrowseOutcomes.IsEmpty());
|
|
|
|
SuccessOrQuit(node0.Get<MeshCoP::BorderAgent::Manager>().SetServiceBaseName("OpenThreadAgent"));
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Re-enable Border Agent and validate that service is registered again");
|
|
|
|
node0.Get<MeshCoP::BorderAgent::Manager>().SetEnabled(true);
|
|
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent::Manager>().IsEnabled());
|
|
|
|
nexus.AdvanceTime(30 * Time::kOneSecondInMsec);
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
txtDataLengthWithNoVendorData = service.mTxtDataLength;
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
VerifyOrQuit(sBrowseOutcomes.GetLength() == 1);
|
|
VerifyOrQuit(sBrowseOutcomes[0].mTtl > 0);
|
|
VerifyOrQuit(StringStartsWith(sBrowseOutcomes[0].mServiceInstance, "OpenThreadAgent"));
|
|
|
|
sBrowseOutcomes.Clear();
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Set vendor TXT data and validate that it is included in the registered mDNS service");
|
|
|
|
node0.Get<BaTxtData>().SetVendorData(kVendorTxtData, sizeof(kVendorTxtData));
|
|
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0, /* aExpectedVendorName */ "nexus");
|
|
|
|
// Check that vendor TXT data is included at the end of
|
|
// the registered service TXT data.
|
|
VerifyOrQuit(service.mTxtDataLength > sizeof(kVendorTxtData));
|
|
VerifyOrQuit(!memcmp(&service.mTxtData[service.mTxtDataLength - sizeof(kVendorTxtData)], kVendorTxtData,
|
|
sizeof(kVendorTxtData)));
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Clear vendor TXT data and validate that the registered mDNS service is updated accordingly");
|
|
|
|
node0.Get<BaTxtData>().SetVendorData(nullptr, 0);
|
|
nexus.AdvanceTime(5 * Time::kOneSecondInMsec);
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
VerifyOrQuit(service.mTxtDataLength == txtDataLengthWithNoVendorData);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Change vendor name and validate that the registered mDNS service is updated accordingly");
|
|
|
|
SuccessOrQuit(node0.Get<VendorInfo>().SetName("RD:v"));
|
|
nexus.AdvanceTime(Time::kOneSecondInMsec);
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Change vendor model and validate that the registered mDNS service is updated accordingly");
|
|
|
|
SuccessOrQuit(node0.Get<VendorInfo>().SetModel("model"));
|
|
nexus.AdvanceTime(Time::kOneSecondInMsec);
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(!foundService);
|
|
foundService = true;
|
|
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
VerifyOrQuit(StringMatch(service.mServiceType, "_meshcop._udp"));
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, "OpenThreadAgent"));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(!StringMatch(service.mServiceType, "_meshcop-e._udp"));
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
node0.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
}
|
|
|
|
void TestBorderAgentServiceRegistrationRename(void)
|
|
{
|
|
static const char kServiceBaseName[] = "VeryLongServiceBaseNameForTestingPurposeOfLimitsMax";
|
|
static const char kEphemeralKey[] = "nexus1234";
|
|
|
|
static constexpr uint32_t kUdpPort = 49155;
|
|
|
|
Core nexus;
|
|
Node &node0 = nexus.CreateNode();
|
|
Node &node1 = nexus.CreateNode();
|
|
Mac::ExtAddress extAddress;
|
|
Dns::Multicast::Core::Iterator *iterator;
|
|
Dns::Multicast::Core::Service service;
|
|
Dns::Multicast::Core::EntryState entryState;
|
|
String<Dns::Name::kMaxLabelSize> expectedName;
|
|
bool foundService;
|
|
bool foundEpskService;
|
|
|
|
Log("------------------------------------------------------------------------------------------------------");
|
|
Log("TestBorderAgentServiceRegistrationRename");
|
|
|
|
nexus.AdvanceTime(0);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Set the same Ext address on both node0 and node1
|
|
|
|
extAddress.GenerateRandom();
|
|
extAddress.m8[6] = 0xbe;
|
|
extAddress.m8[7] = 0xef;
|
|
|
|
node0.Get<Mac::Mac>().SetExtAddress(extAddress);
|
|
node1.Get<Mac::Mac>().SetExtAddress(extAddress);
|
|
VerifyOrQuit(node1.Get<Mac::Mac>().GetExtAddress() == node0.Get<Mac::Mac>().GetExtAddress());
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Set the Service Base Name on both node0 and node1
|
|
SuccessOrQuit(node0.Get<MeshCoP::BorderAgent::Manager>().SetServiceBaseName(kServiceBaseName));
|
|
SuccessOrQuit(node1.Get<MeshCoP::BorderAgent::Manager>().SetServiceBaseName(kServiceBaseName));
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disable Border Agent function on node1
|
|
node1.Get<MeshCoP::BorderAgent::Manager>().SetEnabled(false);
|
|
|
|
node0.Form();
|
|
node1.Form();
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Construct the expected service instance name label.
|
|
|
|
expectedName.Append("%s #%02X%02X", kServiceBaseName, extAddress.m8[6], extAddress.m8[7]);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Enable mDNS
|
|
SuccessOrQuit(node0.Get<Dns::Multicast::Core>().SetEnabled(true, kInfraIfIndex));
|
|
VerifyOrQuit(node0.Get<Dns::Multicast::Core>().IsEnabled());
|
|
SuccessOrQuit(node1.Get<Dns::Multicast::Core>().SetEnabled(true, kInfraIfIndex));
|
|
VerifyOrQuit(node1.Get<Dns::Multicast::Core>().IsEnabled());
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
|
VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader());
|
|
VerifyOrQuit(node1.Get<Mle::Mle>().IsLeader());
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
VerifyOrQuit(node0.Get<MeshCoP::BorderAgent::Manager>().IsEnabled());
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Validate the registered mDNS MeshCop service by Border Agent");
|
|
|
|
iterator = node0.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
|
|
while (node0.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - -");
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(StringMatch(service.mServiceInstance, expectedName.AsCString()));
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mPort == node0.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node0);
|
|
foundService = true;
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Enable BorderAgent on node1");
|
|
|
|
node1.Get<MeshCoP::BorderAgent::Manager>().SetEnabled(true);
|
|
|
|
nexus.AdvanceTime(2 * Time::kOneSecondInMsec);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Validate the registered mDNS MeshCop service by Border Agent on node1");
|
|
|
|
iterator = node1.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
|
|
while (node1.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - -");
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
Log("Validate that node1 properly renamed the conflicted service name");
|
|
|
|
VerifyOrQuit(StringStartsWith(service.mServiceInstance, expectedName.AsCString()));
|
|
expectedName.Append(" (1)");
|
|
VerifyOrQuit(StringMatch(service.mServiceInstance, expectedName.AsCString()));
|
|
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
ValidateRegisteredServiceData(service, node1);
|
|
foundService = true;
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
|
|
node1.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Enable and start ephemeral key on node 1");
|
|
|
|
node1.Get<EphemeralKeyManager>().SetEnabled(true);
|
|
VerifyOrQuit(node1.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStopped);
|
|
node1.Get<EphemeralKeyManager>().SetCallback(HandleEphemeralKeyChange, &node1);
|
|
|
|
SuccessOrQuit(node1.Get<EphemeralKeyManager>().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort));
|
|
|
|
nexus.AdvanceTime(10 * Time::kOneSecondInMsec);
|
|
|
|
VerifyOrQuit(node1.Get<EphemeralKeyManager>().GetState() == EphemeralKeyManager::kStateStarted);
|
|
VerifyOrQuit(node1.Get<EphemeralKeyManager>().GetUdpPort() == kUdpPort);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check the registered services - validate the same service name is used for `_meshcop-e` service");
|
|
|
|
iterator = node1.Get<Dns::Multicast::Core>().AllocateIterator();
|
|
VerifyOrQuit(iterator != nullptr);
|
|
|
|
foundService = false;
|
|
foundEpskService = false;
|
|
|
|
while (node1.Get<Dns::Multicast::Core>().GetNextService(*iterator, service, entryState) == kErrorNone)
|
|
{
|
|
Log("- - - - - - - - - - - - - - - - -");
|
|
Log(" HostName: %s", service.mHostName);
|
|
Log(" ServiceInstance: %s", service.mServiceInstance);
|
|
Log(" ServiceType: %s", service.mServiceType);
|
|
Log(" Port: %u", service.mPort);
|
|
Log(" TTL: %lu", ToUlong(service.mTtl));
|
|
|
|
if (StringMatch(service.mServiceType, "_meshcop._udp"))
|
|
{
|
|
VerifyOrQuit(StringMatch(service.mServiceInstance, expectedName.AsCString()));
|
|
|
|
VerifyOrQuit(service.mPort == node1.Get<MeshCoP::BorderAgent::Manager>().GetUdpPort());
|
|
ValidateRegisteredServiceData(service, node1);
|
|
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
foundService = true;
|
|
}
|
|
else if (StringMatch(service.mServiceType, "_meshcop-e._udp"))
|
|
{
|
|
VerifyOrQuit(StringMatch(service.mServiceInstance, expectedName.AsCString()));
|
|
|
|
VerifyOrQuit(service.mPort == kUdpPort);
|
|
VerifyOrQuit(service.mTxtDataLength == 1);
|
|
VerifyOrQuit(service.mTxtData[0] == 0);
|
|
|
|
VerifyOrQuit(StringStartsWith(service.mHostName, "ot"));
|
|
VerifyOrQuit(service.mSubTypeLabelsLength == 0);
|
|
VerifyOrQuit(service.mTtl > 0);
|
|
VerifyOrQuit(service.mInfraIfIndex == kInfraIfIndex);
|
|
VerifyOrQuit(entryState == OT_MDNS_ENTRY_STATE_REGISTERED);
|
|
foundEpskService = true;
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(foundService);
|
|
VerifyOrQuit(foundEpskService);
|
|
|
|
node1.Get<Dns::Multicast::Core>().FreeIterator(*iterator);
|
|
}
|
|
|
|
} // namespace Nexus
|
|
} // namespace ot
|
|
|
|
int main(void)
|
|
{
|
|
ot::Nexus::TestBorderAgent();
|
|
ot::Nexus::TestBorderAgentEphemeralKey();
|
|
ot::Nexus::TestBorderAgentEphemeralKeyTapGeneration();
|
|
ot::Nexus::TestHistoryTrackerBorderAgentEpskcEvent();
|
|
ot::Nexus::TestBorderAgentTxtDataCallback();
|
|
ot::Nexus::TestBorderAgentServiceRegistration();
|
|
ot::Nexus::TestBorderAgentServiceRegistrationRename();
|
|
printf("All tests passed\n");
|
|
return 0;
|
|
}
|