mirror of
https://github.com/espressif/openthread.git
synced 2026-09-21 16:37:37 +00:00
[mdns] support registering local host and its IPv6/IPv4 addresses (#11353)
This commit enhances the native OpenThread mDNS implementation to streamline the registration of the local host and its IPv6/IPv4 addresses. Previously, registering the local host required tracking host addresses and using `otMdnsRegisterHost()`, similar to registering any other host. This commit introduces a simpler alternative that handles both IPv6 and IPv4 addresses. The changes in this PR include: - The local host name can be explicitly set by the caller using new API `otMdnsSetLocalHostName`. However, if not provided, the mDNS module automatically generates a name derived from the device's Extended MAC address. - A new platform API callback, `otPlatMdnsHandleHostAddressEvent`, is introduced to notify the OpenThread mDNS module of host address changes. - The OpenThread mDNS maintains an internal list of host addresses, automatically updating it based on platform callbacks. A short guard time is used to group multiple changes before announcing them. Transient changes (e.g., address removal and re-addition) are handled to prevent unnecessary announcements. - Host IPv4 addresses (A records) are now supported. The `HostEntry` class is updated to optionally include IPv4 addresses, in addition to the required IPv6 addresses. - A detailed test case in `test_mdns` covers all new local host-related behaviors.
This commit is contained in:
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (490)
|
||||
#define OPENTHREAD_API_VERSION (491)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -203,6 +203,29 @@ bool otMdnsIsQuestionUnicastAllowed(otInstance *aInstance);
|
||||
*/
|
||||
void otMdnsSetConflictCallback(otInstance *aInstance, otMdnsConflictCallback aCallback);
|
||||
|
||||
/**
|
||||
* Gets the local host name.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*
|
||||
* @returns The local host name.
|
||||
*/
|
||||
const char *otMdnsGetLocalHostName(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Sets the local host name.
|
||||
*
|
||||
* The local host name can be set only when the mDNS module is disabled. If not set the mDNS module itself will
|
||||
* auto-generate the local host name.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aName The local host name to use, can be to `NULL` to allow the mDNS module to choose the name.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The local host name was successfully set.
|
||||
* @retval OT_ERROR_INVALID_STATE mDNS module is already enabled.
|
||||
*/
|
||||
otError otMdnsSetLocalHostName(otInstance *aInstance, const char *aName);
|
||||
|
||||
/**
|
||||
* Registers or updates a host on mDNS.
|
||||
*
|
||||
|
||||
@@ -75,6 +75,10 @@ typedef struct otPlatMdnsAddressInfo
|
||||
*
|
||||
* While enabled, all received messages MUST be reported back using `otPlatMdnsHandleReceive()` callback.
|
||||
*
|
||||
* When enabled, the platform MUST also monitor and report all IPv4 and IPv6 addresses assigned to the network
|
||||
* interface using the `otPlatMdnsHandleHostAddressEvent()` callback function. Refer to the documentation of this
|
||||
* callback for detailed information on the callback's usage and parameters.
|
||||
*
|
||||
* @param[in] aInstance The OpernThread instance.
|
||||
* @param[in] aEnable Indicate whether to enable or disable.
|
||||
* @param[in] aInfraInfIndex The infrastructure network interface index.
|
||||
@@ -154,6 +158,47 @@ extern void otPlatMdnsHandleReceive(otInstance *aInstance,
|
||||
bool aIsUnicast,
|
||||
const otPlatMdnsAddressInfo *aAddress);
|
||||
|
||||
/**
|
||||
* Callback to notify OpenThread mDNS module of host address changes.
|
||||
*
|
||||
* When `otPlatMdnsSetListeningEnabled()` enables mDNS listening on an @p aInfraIfIndex, the platform MUST monitor and
|
||||
* report ALL IPv4 and IPv6 addresses assigned to this network interface.
|
||||
*
|
||||
* When mDNS is enabled:
|
||||
* - The platform MUST retrieve ALL currently assigned IPv4 and IPv6 addresses on the specified interface.
|
||||
* - For each retrieved address, the platform MUST call `otPlatMdnsHandleHostAddressEvent()`.
|
||||
* - The IPv4 addresses are represented using IPv4-mapped IPv6 format.
|
||||
*
|
||||
* Ongoing monitoring (while enabled):
|
||||
* - The platform MUST continuously monitor the specified interface for address changes.
|
||||
* - If any addresses are added or removed, the platform MUST call this callback for each affected address, indicating
|
||||
* the change (addition or removal using @p aAdded).
|
||||
*
|
||||
* When mDNS is disabled:
|
||||
* - The platform MUST cease monitoring for address changes on the interface.
|
||||
* - The platform does NOT need to explicitly signal the removal of addresses upon disable. The OpenThread stack
|
||||
* automatically clears its internal address list.
|
||||
* - If address monitoring is re-enabled later, the platform MUST repeat the "enable" steps again, retrieving and
|
||||
* reporting ALL current addresses.
|
||||
*
|
||||
* The OpenThread stack maintains an internal list of host addresses. It updates this list automatically upon receiving
|
||||
* calls to `otPlatMdnsHandleHostAddressEvent()`.
|
||||
* - OpenThread's mDNS implementation uses a short guard time (4 msec) before taking action (e.g., announcing new
|
||||
* addresses). This allows multiple changes to be grouped and announced together.
|
||||
* - OpenThread's mDNS implementation also handles transient changes, e.g., an address is removed and then quickly
|
||||
* re-added. It ensures that announcements are only made when there is a change to the list (from what was
|
||||
* announced before). This simplifies the platform's responsibility as it can simply report all observed changes.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aAddress IP Address. IPv4-mapped IPv6 format is used to represent an IPv4 address.
|
||||
* @param[in] aAdded Boolean to indicate whether the address added (`TRUE`) or removed (`FALSE`).
|
||||
* @param[in] aInfraIfIndex The interface index.
|
||||
*/
|
||||
extern void otPlatMdnsHandleHostAddressEvent(otInstance *aInstance,
|
||||
const otIp6Address *aAddress,
|
||||
bool aAdded,
|
||||
uint32_t aInfraIfIndex);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -86,6 +86,11 @@ template <> otError Mdns::Process<Cmd("unicastquestion")>(Arg aArgs[])
|
||||
return ProcessEnableDisable(aArgs, otMdnsIsQuestionUnicastAllowed, otMdnsSetQuestionUnicastAllowed);
|
||||
}
|
||||
|
||||
template <> otError Mdns::Process<Cmd("localhostname")>(Arg aArgs[])
|
||||
{
|
||||
return ProcessGetSet(aArgs, otMdnsGetLocalHostName, otMdnsSetLocalHostName);
|
||||
}
|
||||
|
||||
void Mdns::OutputHost(const otMdnsHost &aHost)
|
||||
{
|
||||
OutputLine("Host %s", aHost.mHostName);
|
||||
@@ -1209,6 +1214,7 @@ otError Mdns::Process(Arg aArgs[])
|
||||
CmdEntry("ip6resolvers"),
|
||||
CmdEntry("keys"),
|
||||
#endif
|
||||
CmdEntry("localhostname"),
|
||||
CmdEntry("recordquerier"),
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
||||
CmdEntry("recordqueriers"),
|
||||
|
||||
@@ -61,6 +61,16 @@ void otMdnsSetConflictCallback(otInstance *aInstance, otMdnsConflictCallback aCa
|
||||
AsCoreType(aInstance).Get<Dns::Multicast::Core>().SetConflictCallback(aCallback);
|
||||
}
|
||||
|
||||
const char *otMdnsGetLocalHostName(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().GetLocalHostName();
|
||||
}
|
||||
|
||||
otError otMdnsSetLocalHostName(otInstance *aInstance, const char *aName)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Dns::Multicast::Core>().SetLocalHostName(aName);
|
||||
}
|
||||
|
||||
otError otMdnsRegisterHost(otInstance *aInstance,
|
||||
const otMdnsHost *aHost,
|
||||
otMdnsRequestId aRequestId,
|
||||
|
||||
@@ -405,6 +405,10 @@ void Instance::AfterInit(void)
|
||||
Get<Trel::Link>().AfterInit();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
Get<Dns::Multicast::Core>().AfterInstanceInit();
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
|
||||
#if OPENTHREAD_ENABLE_VENDOR_EXTENSION
|
||||
|
||||
+440
-62
@@ -55,6 +55,14 @@ extern "C" void otPlatMdnsHandleReceive(otInstance *aInstance,
|
||||
AsCoreType(aInstance).Get<Core>().HandleMessage(AsCoreType(aMessage), aIsUnicast, AsCoreType(aAddress));
|
||||
}
|
||||
|
||||
extern "C" void otPlatMdnsHandleHostAddressEvent(otInstance *aInstance,
|
||||
const otIp6Address *aAddress,
|
||||
bool aAdded,
|
||||
uint32_t aInfraIfIndex)
|
||||
{
|
||||
AsCoreType(aInstance).Get<Core>().HandleHostAddressEvent(AsCoreType(aAddress), aAdded, aInfraIfIndex);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core
|
||||
|
||||
@@ -70,6 +78,7 @@ Core::Core(Instance &aInstance)
|
||||
, mIsQuestionUnicastAllowed(kDefaultQuAllowed)
|
||||
, mMaxMessageSize(kMaxMessageSize)
|
||||
, mInfraIfIndex(0)
|
||||
, mLocalHost(aInstance)
|
||||
, mMultiPacketRxMessages(aInstance)
|
||||
, mNextProbeTxTime(TimerMilli::GetNow() - 1)
|
||||
, mEntryTimer(aInstance)
|
||||
@@ -82,6 +91,19 @@ Core::Core(Instance &aInstance)
|
||||
{
|
||||
}
|
||||
|
||||
void Core::AfterInstanceInit(void)
|
||||
{
|
||||
// This is called immediately after the OpenThread `Instance` is
|
||||
// initialized (i.e., after all constructors are called and saved
|
||||
// information from `Settings` is restored). This call triggers
|
||||
// the generation of the local host name, which is derived from
|
||||
// the device's extended MAC address. This ensures that the MAC
|
||||
// address is restored from the non-volatile settings, and the
|
||||
// generated name remains consistent across device reboots.
|
||||
|
||||
mLocalHost.GenerateName();
|
||||
}
|
||||
|
||||
Error Core::SetEnabled(bool aEnable, uint32_t aInfraIfIndex)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
@@ -99,10 +121,8 @@ Error Core::SetEnabled(bool aEnable, uint32_t aInfraIfIndex)
|
||||
else
|
||||
{
|
||||
LogInfo("Disabling");
|
||||
}
|
||||
|
||||
if (!mIsEnabled)
|
||||
{
|
||||
mLocalHost.ClearAddresses();
|
||||
mHostEntries.Clear();
|
||||
mServiceEntries.Clear();
|
||||
mServiceTypes.Clear();
|
||||
@@ -258,6 +278,12 @@ void Core::InvokeConflictCallback(const char *aName, const char *aServiceType)
|
||||
mConflictCallback(&GetInstance(), aName, aServiceType);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::HandleHostAddressEvent(const Ip6::Address &aAddress, bool aAdded, uint32_t aInfraIfIndex)
|
||||
{
|
||||
mLocalHost.HandleAddressEvent(aAddress, aAdded, aInfraIfIndex);
|
||||
}
|
||||
|
||||
void Core::HandleMessage(Message &aMessage, bool aIsUnicast, const AddressInfo &aSenderAddress)
|
||||
{
|
||||
OwnedPtr<Message> messagePtr(&aMessage);
|
||||
@@ -540,6 +566,11 @@ exit:
|
||||
return matches;
|
||||
}
|
||||
|
||||
bool Core::AddressArray::Matches(const AddressArray &aOther) const
|
||||
{
|
||||
return Matches(aOther.AsCArray(), aOther.GetLength());
|
||||
}
|
||||
|
||||
void Core::AddressArray::SetFrom(const Ip6::Address *aAddresses, uint16_t aNumAddresses)
|
||||
{
|
||||
Free();
|
||||
@@ -1198,7 +1229,7 @@ bool Core::Entry::ShouldAnswerNsec(TimeMilli aNow) const
|
||||
return mMulticastNsecPending && (GetNsecAnswerTime() <= aNow);
|
||||
}
|
||||
|
||||
void Core::Entry::AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength)
|
||||
void Core::Entry::AnswerNonProbe(const AnswerInfo &aInfo, RecordAndTypeArray &aRecordAndTypes)
|
||||
{
|
||||
// Schedule answers for all matching records in `aRecords` array
|
||||
// to a given non-probe question.
|
||||
@@ -1206,9 +1237,9 @@ void Core::Entry::AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecord
|
||||
bool allEmptyOrZeroTtl = true;
|
||||
bool answerNsec = true;
|
||||
|
||||
for (uint16_t index = 0; index < aRecordsLength; index++)
|
||||
for (RecordAndType &recordAndType : aRecordAndTypes)
|
||||
{
|
||||
RecordInfo &record = aRecords[index].mRecord;
|
||||
RecordInfo &record = *recordAndType.mRecord;
|
||||
|
||||
if (!record.CanAnswer())
|
||||
{
|
||||
@@ -1218,7 +1249,7 @@ void Core::Entry::AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecord
|
||||
|
||||
allEmptyOrZeroTtl = false;
|
||||
|
||||
if (QuestionMatches(aInfo.mQuestionRrType, aRecords[index].mType))
|
||||
if (QuestionMatches(aInfo.mQuestionRrType, recordAndType.mType))
|
||||
{
|
||||
answerNsec = false;
|
||||
record.ScheduleAnswer(aInfo);
|
||||
@@ -1235,7 +1266,7 @@ void Core::Entry::AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecord
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Entry::AnswerProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength)
|
||||
void Core::Entry::AnswerProbe(const AnswerInfo &aInfo, RecordAndTypeArray &aRecordAndTypes)
|
||||
{
|
||||
bool allEmptyOrZeroTtl = true;
|
||||
bool shouldDelay = false;
|
||||
@@ -1246,9 +1277,9 @@ void Core::Entry::AnswerProbe(const AnswerInfo &aInfo, RecordAndType *aRecords,
|
||||
|
||||
OT_ASSERT(info.mIsProbe);
|
||||
|
||||
for (uint16_t index = 0; index < aRecordsLength; index++)
|
||||
for (RecordAndType &recordAndType : aRecordAndTypes)
|
||||
{
|
||||
RecordInfo &record = aRecords[index].mRecord;
|
||||
RecordInfo &record = *recordAndType.mRecord;
|
||||
TimeMilli lastMulticastTime;
|
||||
|
||||
if (!record.CanAnswer())
|
||||
@@ -1294,9 +1325,9 @@ void Core::Entry::AnswerProbe(const AnswerInfo &aInfo, RecordAndType *aRecords,
|
||||
info.mAnswerDelay = 0;
|
||||
}
|
||||
|
||||
for (uint16_t index = 0; index < aRecordsLength; index++)
|
||||
for (RecordAndType &recordAndType : aRecordAndTypes)
|
||||
{
|
||||
aRecords[index].mRecord.ScheduleAnswer(info);
|
||||
recordAndType.mRecord->ScheduleAnswer(info);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -1469,6 +1500,180 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core::Entry::RecordAndTypeArray
|
||||
|
||||
void Core::Entry::RecordAndTypeArray::Add(RecordInfo &aRecord, uint16_t aType)
|
||||
{
|
||||
RecordAndType *entry = PushBack();
|
||||
|
||||
OT_ASSERT(entry != nullptr);
|
||||
entry->mRecord = &aRecord;
|
||||
entry->mType = aType;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core::LocalHost
|
||||
|
||||
Core::LocalHost::LocalHost(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mEventTimer(aInstance)
|
||||
{
|
||||
GenerateName();
|
||||
}
|
||||
|
||||
Error Core::LocalHost::SetName(const char *aName)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(!Get<Core>().mIsEnabled, error = kErrorInvalidState);
|
||||
|
||||
if (aName == nullptr)
|
||||
{
|
||||
GenerateName();
|
||||
}
|
||||
else
|
||||
{
|
||||
SuccessOrAssert(mName.Set(aName));
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Core::LocalHost::GenerateName(void)
|
||||
{
|
||||
Name::LabelBuffer name;
|
||||
StringWriter writer(name, sizeof(name));
|
||||
|
||||
writer.Append("ot%s", Get<Mac::Mac>().GetExtAddress().ToString().AsCString());
|
||||
|
||||
SuccessOrAssert(mName.Set(name));
|
||||
}
|
||||
|
||||
void Core::LocalHost::ClearAddresses(void)
|
||||
{
|
||||
mIp4Addresses.Free();
|
||||
mIp6Addresses.Free();
|
||||
mAddrEvents.Clear();
|
||||
mEventTimer.Stop();
|
||||
}
|
||||
|
||||
void Core::LocalHost::HandleAddressEvent(const Ip6::Address &aAddress, bool aAdded, uint32_t aInfraIfIndex)
|
||||
{
|
||||
AddrEvent *addrEvent;
|
||||
|
||||
VerifyOrExit(Get<Core>().mIsEnabled);
|
||||
VerifyOrExit(aInfraIfIndex == Get<Core>().mInfraIfIndex);
|
||||
|
||||
LogInfo("Host address %s event: %s", aAddress.ToString().AsCString(), aAdded ? "added" : "removed");
|
||||
|
||||
addrEvent = AddrEvent::Allocate(aAddress, aAdded);
|
||||
OT_ASSERT(addrEvent != nullptr);
|
||||
|
||||
// Before we add the new event, we remove any previous events in the
|
||||
// list that match the same address. This way we always track the
|
||||
// latest event for each address. This handles the case where
|
||||
// a "removed" address event is quickly followed by an "added" event
|
||||
// for the same address.
|
||||
//
|
||||
// The events are processed after a short guard delay time
|
||||
// `kGuardTimeToProcessAddrEvents`. This ensures multiple changes
|
||||
// to be grouped and announced together.
|
||||
|
||||
mAddrEvents.RemoveAndFreeAllMatching(aAddress);
|
||||
mAddrEvents.Push(*addrEvent);
|
||||
|
||||
if (!mEventTimer.IsRunning())
|
||||
{
|
||||
mEventTimer.Start(kGuardTimeToProcessAddrEvents);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Core::LocalHost::HandleEventTimer(void)
|
||||
{
|
||||
// Process all saved `AddrEvents` and update IPv4 and IPv6
|
||||
// address lists.
|
||||
|
||||
static const AddrType kAddrTypes[] = {kIp4AddrType, kIp6AddrType};
|
||||
|
||||
VerifyOrExit(Get<Core>().mIsEnabled);
|
||||
|
||||
for (AddrType addrType : kAddrTypes)
|
||||
{
|
||||
AddressArray &addresses = (addrType == kIp4AddrType) ? mIp4Addresses : mIp6Addresses;
|
||||
AddressArray oldAddresses;
|
||||
|
||||
oldAddresses.TakeFrom(static_cast<AddressArray &&>(addresses));
|
||||
addresses.Clear();
|
||||
|
||||
// First, add existing addresses (from old list) that did not
|
||||
// change (there is no "removed" event).
|
||||
|
||||
for (const Ip6::Address &address : oldAddresses)
|
||||
{
|
||||
const AddrEvent *addrEvent = mAddrEvents.FindMatching(address);
|
||||
|
||||
if ((addrEvent == nullptr) || addrEvent->mAdded)
|
||||
{
|
||||
SuccessOrAssert(addresses.PushBack(address));
|
||||
}
|
||||
}
|
||||
|
||||
// Next, add any new addresses for which we got an "added"
|
||||
// event.
|
||||
|
||||
for (const AddrEvent &addrEvent : mAddrEvents)
|
||||
{
|
||||
if (!addrEvent.Matches(addrType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addrEvent.mAdded && !addresses.Contains(addrEvent.mAddress))
|
||||
{
|
||||
SuccessOrAssert(addresses.PushBack(addrEvent.mAddress));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IgnoreError(Get<Core>().Register<HostEntry>(*this, /* aRequestId */ 0, /* aCallback */ nullptr));
|
||||
|
||||
exit:
|
||||
mAddrEvents.Clear();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core::LocalHost::AddrEvent
|
||||
|
||||
Core::LocalHost::AddrEvent::AddrEvent(const Ip6::Address &aAddress, bool aAdded)
|
||||
: mNext(nullptr)
|
||||
, mAddress(aAddress)
|
||||
, mAdded(aAdded)
|
||||
{
|
||||
}
|
||||
|
||||
bool Core::LocalHost::AddrEvent::Matches(AddrType aType) const
|
||||
{
|
||||
bool matches = false;
|
||||
bool isIp4 = mAddress.IsIp4Mapped();
|
||||
|
||||
switch (aType)
|
||||
{
|
||||
case kIp4AddrType:
|
||||
matches = isIp4;
|
||||
break;
|
||||
case kIp6AddrType:
|
||||
matches = !isIp4;
|
||||
break;
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core::HostEntry
|
||||
|
||||
@@ -1492,11 +1697,24 @@ bool Core::HostEntry::Matches(const Name &aName) const
|
||||
|
||||
bool Core::HostEntry::Matches(const Host &aHost) const { return NameMatch(mName, aHost.mHostName); }
|
||||
|
||||
bool Core::HostEntry::Matches(const LocalHost &aLocalHost) const { return NameMatch(mName, aLocalHost.GetName()); }
|
||||
|
||||
bool Core::HostEntry::Matches(const Key &aKey) const { return !IsKeyForService(aKey) && NameMatch(mName, aKey.mName); }
|
||||
|
||||
bool Core::HostEntry::Matches(const Heap::String &aName) const { return NameMatch(mName, aName); }
|
||||
|
||||
bool Core::HostEntry::IsEmpty(void) const { return !mAddrRecord.IsPresent() && !mKeyRecord.IsPresent(); }
|
||||
bool Core::HostEntry::IsEmpty(void) const
|
||||
{
|
||||
bool isEmpty = false;
|
||||
|
||||
VerifyOrExit(!mKeyRecord.IsPresent() && !mIp6AddrRecord.IsPresent());
|
||||
VerifyOrExit((mIp4AddrRecord == nullptr) || !mIp4AddrRecord->IsPresent());
|
||||
|
||||
isEmpty = true;
|
||||
|
||||
exit:
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
void Core::HostEntry::Register(const Host &aHost, const Callback &aCallback)
|
||||
{
|
||||
@@ -1525,8 +1743,8 @@ void Core::HostEntry::Register(const Host &aHost, const Callback &aCallback)
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
mAddrRecord.UpdateTtl(DetermineTtl(aHost.mTtl, kDefaultTtl));
|
||||
mAddrRecord.UpdateProperty(mAddresses, AsCoreTypePtr(aHost.mAddresses), aHost.mAddressesLength);
|
||||
mIp6AddrRecord.UpdateTtl(DetermineTtl(aHost.mTtl, kDefaultTtl));
|
||||
mIp6AddrRecord.UpdateAddresses(aHost);
|
||||
|
||||
DetermineNextFireTime();
|
||||
ScheduleTimer();
|
||||
@@ -1535,6 +1753,46 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Core::HostEntry::Register(const LocalHost &aLocalHost, const Callback &aCallback)
|
||||
{
|
||||
SetCallback(aCallback);
|
||||
|
||||
if (aLocalHost.GetIp6Addresses().IsEmpty())
|
||||
{
|
||||
if (mIp6AddrRecord.IsPresent())
|
||||
{
|
||||
mIp6AddrRecord.UpdateTtl(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mIp6AddrRecord.UpdateTtl(kDefaultTtl);
|
||||
mIp6AddrRecord.UpdateAddresses(aLocalHost.GetIp6Addresses());
|
||||
}
|
||||
|
||||
if (aLocalHost.GetIp4Addresses().IsEmpty())
|
||||
{
|
||||
if ((mIp4AddrRecord != nullptr) && mIp4AddrRecord->IsPresent())
|
||||
{
|
||||
mIp4AddrRecord->UpdateTtl(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mIp4AddrRecord == nullptr)
|
||||
{
|
||||
mIp4AddrRecord.Reset(AddrRecord::Allocate());
|
||||
OT_ASSERT(mIp4AddrRecord != nullptr);
|
||||
}
|
||||
|
||||
mIp4AddrRecord->UpdateTtl(kDefaultTtl);
|
||||
mIp4AddrRecord->UpdateAddresses(aLocalHost.GetIp4Addresses());
|
||||
}
|
||||
|
||||
DetermineNextFireTime();
|
||||
ScheduleTimer();
|
||||
}
|
||||
|
||||
void Core::HostEntry::Register(const Key &aKey, const Callback &aCallback)
|
||||
{
|
||||
Entry::Register(aKey, aCallback);
|
||||
@@ -1547,14 +1805,14 @@ void Core::HostEntry::Unregister(const Host &aHost)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aHost);
|
||||
|
||||
VerifyOrExit(mAddrRecord.IsPresent());
|
||||
VerifyOrExit(mIp6AddrRecord.IsPresent());
|
||||
|
||||
ClearCallback();
|
||||
|
||||
switch (GetState())
|
||||
{
|
||||
case kRegistered:
|
||||
mAddrRecord.UpdateTtl(0);
|
||||
mIp6AddrRecord.UpdateTtl(0);
|
||||
DetermineNextFireTime();
|
||||
ScheduleTimer();
|
||||
break;
|
||||
@@ -1585,8 +1843,12 @@ void Core::HostEntry::Unregister(const Key &aKey)
|
||||
|
||||
void Core::HostEntry::ClearHost(void)
|
||||
{
|
||||
mAddrRecord.Clear();
|
||||
mAddresses.Free();
|
||||
mIp6AddrRecord.Clear();
|
||||
|
||||
if (mIp4AddrRecord != nullptr)
|
||||
{
|
||||
mIp4AddrRecord->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Core::HostEntry::ScheduleToRemoveIfEmpty(void)
|
||||
@@ -1612,20 +1874,25 @@ exit:
|
||||
|
||||
void Core::HostEntry::AnswerQuestion(const AnswerInfo &aInfo)
|
||||
{
|
||||
RecordAndType records[] = {
|
||||
{mAddrRecord, ResourceRecord::kTypeAaaa},
|
||||
{mKeyRecord, ResourceRecord::kTypeKey},
|
||||
};
|
||||
RecordAndTypeArray recordAndTypes;
|
||||
|
||||
VerifyOrExit(GetState() == kRegistered);
|
||||
|
||||
recordAndTypes.Add(mIp6AddrRecord, ResourceRecord::kTypeAaaa);
|
||||
recordAndTypes.Add(mKeyRecord, ResourceRecord::kTypeKey);
|
||||
|
||||
if (mIp4AddrRecord != nullptr)
|
||||
{
|
||||
recordAndTypes.Add(*mIp4AddrRecord, ResourceRecord::kTypeA);
|
||||
}
|
||||
|
||||
if (aInfo.mIsProbe)
|
||||
{
|
||||
AnswerProbe(aInfo, records, GetArrayLength(records));
|
||||
AnswerProbe(aInfo, recordAndTypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
AnswerNonProbe(aInfo, records, GetArrayLength(records));
|
||||
AnswerNonProbe(aInfo, recordAndTypes);
|
||||
}
|
||||
|
||||
DetermineNextFireTime();
|
||||
@@ -1644,7 +1911,12 @@ void Core::HostEntry::ClearAppendState(void)
|
||||
|
||||
Entry::ClearAppendState();
|
||||
|
||||
mAddrRecord.MarkAsNotAppended();
|
||||
mIp6AddrRecord.MarkAsNotAppended();
|
||||
|
||||
if (mIp4AddrRecord != nullptr)
|
||||
{
|
||||
mIp4AddrRecord->MarkAsNotAppended();
|
||||
}
|
||||
|
||||
mNameOffset = kUnspecifiedOffset;
|
||||
}
|
||||
@@ -1660,7 +1932,8 @@ void Core::HostEntry::PrepareProbe(TxMessage &aProbe)
|
||||
AppendNameTo(aProbe, kQuestionSection);
|
||||
AppendQuestionTo(aProbe);
|
||||
|
||||
AppendAddressRecordsTo(aProbe, kAuthoritySection);
|
||||
AppendIp6AddressRecordsTo(aProbe, kAuthoritySection);
|
||||
AppendIp4AddressRecordsTo(aProbe, kAuthoritySection);
|
||||
AppendKeyRecordTo(aProbe, kAuthoritySection);
|
||||
|
||||
aProbe.CheckSizeLimitToPrepareAgain(prepareAgain);
|
||||
@@ -1670,7 +1943,13 @@ void Core::HostEntry::PrepareProbe(TxMessage &aProbe)
|
||||
|
||||
void Core::HostEntry::StartAnnouncing(void)
|
||||
{
|
||||
mAddrRecord.StartAnnouncing();
|
||||
mIp6AddrRecord.StartAnnouncing();
|
||||
|
||||
if (mIp4AddrRecord != nullptr)
|
||||
{
|
||||
mIp4AddrRecord->StartAnnouncing();
|
||||
}
|
||||
|
||||
mKeyRecord.StartAnnouncing();
|
||||
}
|
||||
|
||||
@@ -1695,9 +1974,15 @@ void Core::HostEntry::PrepareResponseRecords(EntryContext &aContext)
|
||||
bool appendNsec = false;
|
||||
TxMessage &response = aContext.mResponseMessage;
|
||||
|
||||
if (mAddrRecord.ShouldAppendTo(aContext))
|
||||
if (mIp6AddrRecord.ShouldAppendTo(aContext))
|
||||
{
|
||||
AppendAddressRecordsTo(response, kAnswerSection);
|
||||
AppendIp6AddressRecordsTo(response, kAnswerSection);
|
||||
appendNsec = true;
|
||||
}
|
||||
|
||||
if ((mIp4AddrRecord != nullptr) && mIp4AddrRecord->ShouldAppendTo(aContext))
|
||||
{
|
||||
AppendIp4AddressRecordsTo(response, kAnswerSection);
|
||||
appendNsec = true;
|
||||
}
|
||||
|
||||
@@ -1718,7 +2003,12 @@ void Core::HostEntry::UpdateRecordsState(const TxMessage &aResponse)
|
||||
// Updates state after a response is prepared.
|
||||
|
||||
Entry::UpdateRecordsState(aResponse);
|
||||
mAddrRecord.UpdateStateAfterAnswer(aResponse);
|
||||
mIp6AddrRecord.UpdateStateAfterAnswer(aResponse);
|
||||
|
||||
if (mIp4AddrRecord != nullptr)
|
||||
{
|
||||
mIp4AddrRecord->UpdateStateAfterAnswer(aResponse);
|
||||
}
|
||||
|
||||
if (IsEmpty())
|
||||
{
|
||||
@@ -1731,7 +2021,12 @@ void Core::HostEntry::DetermineNextFireTime(void)
|
||||
VerifyOrExit(GetState() == kRegistered);
|
||||
|
||||
Entry::DetermineNextFireTime();
|
||||
mAddrRecord.UpdateFireTimeOn(*this);
|
||||
mIp6AddrRecord.UpdateFireTimeOn(*this);
|
||||
|
||||
if (mIp4AddrRecord != nullptr)
|
||||
{
|
||||
mIp4AddrRecord->UpdateFireTimeOn(*this);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -1742,33 +2037,72 @@ void Core::HostEntry::DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) con
|
||||
VerifyOrExit(GetState() == kRegistered);
|
||||
|
||||
Entry::DetermineNextAggrTxTime(aNextAggrTxTime);
|
||||
mAddrRecord.DetermineNextAggrTxTime(aNextAggrTxTime);
|
||||
mIp6AddrRecord.DetermineNextAggrTxTime(aNextAggrTxTime);
|
||||
|
||||
if (mIp4AddrRecord != nullptr)
|
||||
{
|
||||
mIp4AddrRecord->DetermineNextAggrTxTime(aNextAggrTxTime);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Core::HostEntry::AppendAddressRecordsTo(TxMessage &aTxMessage, Section aSection)
|
||||
void Core::HostEntry::AppendIp6AddressRecordsTo(TxMessage &aTxMessage, Section aSection)
|
||||
{
|
||||
AppendAddressRecordsTo(aTxMessage, aSection, mIp6AddrRecord, /* aIp6 */ true);
|
||||
}
|
||||
|
||||
void Core::HostEntry::AppendIp4AddressRecordsTo(TxMessage &aTxMessage, Section aSection)
|
||||
{
|
||||
if (mIp4AddrRecord != nullptr)
|
||||
{
|
||||
AppendAddressRecordsTo(aTxMessage, aSection, *mIp4AddrRecord, /* aIp6 */ false);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::HostEntry::AppendAddressRecordsTo(TxMessage &aTxMessage,
|
||||
Section aSection,
|
||||
AddrRecord &aAddrRecord,
|
||||
bool aIp6)
|
||||
{
|
||||
Message *message;
|
||||
bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse);
|
||||
|
||||
VerifyOrExit(mAddrRecord.CanAppend());
|
||||
mAddrRecord.MarkAsAppended(aTxMessage, aSection);
|
||||
VerifyOrExit(aAddrRecord.CanAppend());
|
||||
aAddrRecord.MarkAsAppended(aTxMessage, aSection);
|
||||
|
||||
message = &aTxMessage.SelectMessageFor(aSection);
|
||||
|
||||
for (const Ip6::Address &address : mAddresses)
|
||||
for (const Ip6::Address &address : aAddrRecord.mAddresses)
|
||||
{
|
||||
AaaaRecord aaaaRecord;
|
||||
|
||||
aaaaRecord.Init();
|
||||
aaaaRecord.SetAddress(address);
|
||||
aaaaRecord.SetTtl(mAddrRecord.GetTtl(isLegacyUnicast));
|
||||
UpdateCacheFlushFlagIn(aaaaRecord, aSection, isLegacyUnicast);
|
||||
|
||||
AppendNameTo(aTxMessage, aSection);
|
||||
SuccessOrAssert(message->Append(aaaaRecord));
|
||||
|
||||
if (aIp6)
|
||||
{
|
||||
AaaaRecord aaaaRecord;
|
||||
|
||||
aaaaRecord.Init();
|
||||
aaaaRecord.SetAddress(address);
|
||||
aaaaRecord.SetTtl(aAddrRecord.GetTtl(isLegacyUnicast));
|
||||
UpdateCacheFlushFlagIn(aaaaRecord, aSection, isLegacyUnicast);
|
||||
|
||||
SuccessOrAssert(message->Append(aaaaRecord));
|
||||
}
|
||||
else
|
||||
{
|
||||
Ip4::Address ip4Address;
|
||||
ARecord aRecord;
|
||||
|
||||
SuccessOrAssert(ip4Address.ExtractFromIp4MappedIp6Address(address));
|
||||
|
||||
aRecord.Init();
|
||||
aRecord.SetAddress(ip4Address);
|
||||
aRecord.SetTtl(aAddrRecord.GetTtl(isLegacyUnicast));
|
||||
UpdateCacheFlushFlagIn(aRecord, aSection, isLegacyUnicast);
|
||||
|
||||
SuccessOrAssert(message->Append(aRecord));
|
||||
}
|
||||
|
||||
aTxMessage.IncrementRecordCount(aSection);
|
||||
}
|
||||
@@ -1786,11 +2120,16 @@ void Core::HostEntry::AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection
|
||||
{
|
||||
TypeArray types;
|
||||
|
||||
if (mAddrRecord.IsPresent() && (mAddrRecord.GetTtl() > 0))
|
||||
if (mIp6AddrRecord.IsPresent() && (mIp6AddrRecord.GetTtl() > 0))
|
||||
{
|
||||
types.Add(ResourceRecord::kTypeAaaa);
|
||||
}
|
||||
|
||||
if ((mIp4AddrRecord != nullptr) && mIp4AddrRecord->IsPresent() && (mIp4AddrRecord->GetTtl() > 0))
|
||||
{
|
||||
types.Add(ResourceRecord::kTypeA);
|
||||
}
|
||||
|
||||
if (mKeyRecord.IsPresent() && (mKeyRecord.GetTtl() > 0))
|
||||
{
|
||||
types.Add(ResourceRecord::kTypeKey);
|
||||
@@ -1820,18 +2159,28 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Core::HostEntry::MarkToAppendAddrRecordsInAdditionalData(void)
|
||||
{
|
||||
mIp6AddrRecord.MarkToAppendInAdditionalData();
|
||||
|
||||
if (mIp4AddrRecord != nullptr)
|
||||
{
|
||||
mIp4AddrRecord->MarkToAppendInAdditionalData();
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
||||
|
||||
Error Core::HostEntry::CopyInfoTo(Host &aHost, EntryState &aState) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(mAddrRecord.IsPresent(), error = kErrorNotFound);
|
||||
VerifyOrExit(mIp6AddrRecord.IsPresent(), error = kErrorNotFound);
|
||||
|
||||
aHost.mHostName = mName.AsCString();
|
||||
aHost.mAddresses = mAddresses.AsCArray();
|
||||
aHost.mAddressesLength = mAddresses.GetLength();
|
||||
aHost.mTtl = mAddrRecord.GetTtl();
|
||||
aHost.mAddresses = mIp6AddrRecord.mAddresses.AsCArray();
|
||||
aHost.mAddressesLength = mIp6AddrRecord.mAddresses.GetLength();
|
||||
aHost.mTtl = mIp6AddrRecord.GetTtl();
|
||||
aHost.mInfraIfIndex = Get<Core>().mInfraIfIndex;
|
||||
aState = static_cast<EntryState>(GetState());
|
||||
|
||||
@@ -1854,6 +2203,25 @@ exit:
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core::HostEntry::AddrRecord
|
||||
|
||||
void Core::HostEntry::AddrRecord::Clear(void)
|
||||
{
|
||||
RecordInfo::Clear();
|
||||
mAddresses.Free();
|
||||
}
|
||||
|
||||
void Core::HostEntry::AddrRecord::UpdateAddresses(const Host &aHost)
|
||||
{
|
||||
UpdateProperty(mAddresses, AsCoreTypePtr(aHost.mAddresses), aHost.mAddressesLength);
|
||||
}
|
||||
|
||||
void Core::HostEntry::AddrRecord::UpdateAddresses(const AddressArray &aAddresses)
|
||||
{
|
||||
UpdateProperty(mAddresses, aAddresses.AsCArray(), aAddresses.GetLength());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Core::ServiceEntry
|
||||
|
||||
@@ -2103,21 +2471,21 @@ exit:
|
||||
|
||||
void Core::ServiceEntry::AnswerServiceNameQuestion(const AnswerInfo &aInfo)
|
||||
{
|
||||
RecordAndType records[] = {
|
||||
{mSrvRecord, ResourceRecord::kTypeSrv},
|
||||
{mTxtRecord, ResourceRecord::kTypeTxt},
|
||||
{mKeyRecord, ResourceRecord::kTypeKey},
|
||||
};
|
||||
RecordAndTypeArray recordAndTypes;
|
||||
|
||||
VerifyOrExit(GetState() == kRegistered);
|
||||
|
||||
recordAndTypes.Add(mSrvRecord, ResourceRecord::kTypeSrv);
|
||||
recordAndTypes.Add(mTxtRecord, ResourceRecord::kTypeTxt);
|
||||
recordAndTypes.Add(mKeyRecord, ResourceRecord::kTypeKey);
|
||||
|
||||
if (aInfo.mIsProbe)
|
||||
{
|
||||
AnswerProbe(aInfo, records, GetArrayLength(records));
|
||||
AnswerProbe(aInfo, recordAndTypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
AnswerNonProbe(aInfo, records, GetArrayLength(records));
|
||||
AnswerNonProbe(aInfo, recordAndTypes);
|
||||
}
|
||||
|
||||
DetermineNextFireTime();
|
||||
@@ -2313,7 +2681,7 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext)
|
||||
|
||||
if (hostEntry != nullptr)
|
||||
{
|
||||
hostEntry->mAddrRecord.MarkToAppendInAdditionalData();
|
||||
hostEntry->MarkToAppendAddrRecordsInAdditionalData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2324,7 +2692,7 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext)
|
||||
|
||||
if ((mSrvRecord.GetTtl() > 0) && (hostEntry != nullptr))
|
||||
{
|
||||
hostEntry->mAddrRecord.MarkToAppendInAdditionalData();
|
||||
hostEntry->MarkToAppendAddrRecordsInAdditionalData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2352,9 +2720,17 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext)
|
||||
AppendTxtRecordTo(response, kAdditionalDataSection);
|
||||
}
|
||||
|
||||
if ((hostEntry != nullptr) && (hostEntry->mAddrRecord.ShouldAppendInAdditionalDataSection()))
|
||||
if (hostEntry != nullptr)
|
||||
{
|
||||
hostEntry->AppendAddressRecordsTo(response, kAdditionalDataSection);
|
||||
if (hostEntry->mIp6AddrRecord.ShouldAppendInAdditionalDataSection())
|
||||
{
|
||||
hostEntry->AppendIp6AddressRecordsTo(response, kAdditionalDataSection);
|
||||
}
|
||||
|
||||
if ((hostEntry->mIp4AddrRecord != nullptr) && hostEntry->mIp4AddrRecord->ShouldAppendInAdditionalDataSection())
|
||||
{
|
||||
hostEntry->AppendIp4AddressRecordsTo(response, kAdditionalDataSection);
|
||||
}
|
||||
}
|
||||
|
||||
if (appendNsec || ShouldAnswerNsec(aContext.GetNow()))
|
||||
@@ -2428,6 +2804,8 @@ void Core::ServiceEntry::DiscoverOffsetsAndHost(HostEntry *&aHostEntry)
|
||||
// and name compression offsets from the previously appended
|
||||
// entries.
|
||||
|
||||
// TODO: Need to handle name matching host name
|
||||
|
||||
aHostEntry = Get<Core>().mHostEntries.FindMatching(mHostName);
|
||||
|
||||
if ((aHostEntry != nullptr) && (aHostEntry->GetState() != GetState()))
|
||||
@@ -3709,7 +4087,7 @@ void Core::RxMessage::ProcessQuestion(Question &aQuestion)
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// Check if question name matches a `HostEntry` or a `ServiceEntry`
|
||||
// Check if question name matches a `HostEntry` or a `ServiceEntry`.
|
||||
|
||||
aQuestion.mEntry = Get<Core>().mHostEntries.FindMatching(name);
|
||||
|
||||
|
||||
+113
-9
@@ -77,16 +77,28 @@ extern "C" void otPlatMdnsHandleReceive(otInstance *aInstance,
|
||||
bool aIsUnicast,
|
||||
const otPlatMdnsAddressInfo *aAddress);
|
||||
|
||||
extern "C" void otPlatMdnsHandleHostAddressEvent(otInstance *aInstance,
|
||||
const otIp6Address *aAddress,
|
||||
bool aAdded,
|
||||
uint32_t aInfraIfIndex);
|
||||
|
||||
/**
|
||||
* Implements Multicast DNS (mDNS) core.
|
||||
*/
|
||||
class Core : public InstanceLocator, private NonCopyable
|
||||
{
|
||||
friend class ot::Instance;
|
||||
|
||||
friend void otPlatMdnsHandleReceive(otInstance *aInstance,
|
||||
otMessage *aMessage,
|
||||
bool aIsUnicast,
|
||||
const otPlatMdnsAddressInfo *aAddress);
|
||||
|
||||
friend void otPlatMdnsHandleHostAddressEvent(otInstance *aInstance,
|
||||
const otIp6Address *aAddress,
|
||||
bool aAdded,
|
||||
uint32_t aInfraIfIndex);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initializes a `Core` instance.
|
||||
@@ -165,6 +177,26 @@ public:
|
||||
*/
|
||||
bool IsEnabled(void) const { return mIsEnabled; }
|
||||
|
||||
/**
|
||||
* Gets the local host name.
|
||||
*
|
||||
* @returns The local host name.
|
||||
*/
|
||||
const char *GetLocalHostName(void) { return mLocalHost.GetName(); }
|
||||
|
||||
/**
|
||||
* Sets the local host name.
|
||||
*
|
||||
* The local host name can be set only when the mDNS module is disabled. If not set the mDNS module itself will
|
||||
* generate the local host name.
|
||||
*
|
||||
* @param[in] aName The local host name to use, can be to `nullptr` to allow the mDNS module to choose the name.
|
||||
*
|
||||
* @retval kErrorNone The local host name was successfully set.
|
||||
* @retval kErrorInvalidState mDNS module is already enabled.
|
||||
*/
|
||||
Error SetLocalHostName(const char *aName) { return mLocalHost.SetName(aName); }
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF
|
||||
/**
|
||||
* Notifies `AdvertisingProxy` that `InfraIf` state changed.
|
||||
@@ -817,6 +849,12 @@ private:
|
||||
kAppendedLabels,
|
||||
};
|
||||
|
||||
enum AddrType : uint8_t
|
||||
{
|
||||
kIp4AddrType,
|
||||
kIp6AddrType,
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Forward declarations
|
||||
|
||||
@@ -897,7 +935,9 @@ private:
|
||||
class AddressArray : public Heap::Array<Ip6::Address>
|
||||
{
|
||||
public:
|
||||
bool IsEmpty(void) const { return (GetLength() == 0); }
|
||||
bool Matches(const Ip6::Address *aAddresses, uint16_t aNumAddresses) const;
|
||||
bool Matches(const AddressArray &aOther) const;
|
||||
void SetFrom(const Ip6::Address *aAddresses, uint16_t aNumAddresses);
|
||||
};
|
||||
|
||||
@@ -1031,10 +1071,15 @@ private:
|
||||
|
||||
struct RecordAndType
|
||||
{
|
||||
RecordInfo &mRecord;
|
||||
RecordInfo *mRecord;
|
||||
uint16_t mType;
|
||||
};
|
||||
|
||||
struct RecordAndTypeArray : public Array<RecordAndType, kTypeArraySize>
|
||||
{
|
||||
void Add(RecordInfo &aRecord, uint16_t aType);
|
||||
};
|
||||
|
||||
typedef void (*NameAppender)(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
|
||||
|
||||
Entry(void);
|
||||
@@ -1056,8 +1101,8 @@ private:
|
||||
void DetermineNextFireTime(void);
|
||||
void DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) const;
|
||||
void ScheduleTimer(void);
|
||||
void AnswerProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength);
|
||||
void AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength);
|
||||
void AnswerProbe(const AnswerInfo &aInfo, RecordAndTypeArray &aRecordAndTypes);
|
||||
void AnswerNonProbe(const AnswerInfo &aInfo, RecordAndTypeArray &aRecordAndTypes);
|
||||
void ScheduleNsecAnswer(const AnswerInfo &aInfo);
|
||||
|
||||
template <typename EntryType> void HandleTimer(EntryContext &aContext);
|
||||
@@ -1086,6 +1131,47 @@ private:
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void HandleLocalHostEventTimer(void) { mLocalHost.HandleEventTimer(); }
|
||||
|
||||
class LocalHost : public InstanceLocator
|
||||
{
|
||||
public:
|
||||
explicit LocalHost(Instance &aInstance);
|
||||
|
||||
const char *GetName(void) const { return mName.AsCString(); }
|
||||
Error SetName(const char *aName);
|
||||
void GenerateName(void);
|
||||
const AddressArray &GetIp4Addresses(void) const { return mIp4Addresses; }
|
||||
const AddressArray &GetIp6Addresses(void) const { return mIp6Addresses; }
|
||||
void HandleAddressEvent(const Ip6::Address &aAddress, bool aAdded, uint32_t aInfraIfIndex);
|
||||
void HandleEventTimer(void);
|
||||
void ClearAddresses(void);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kGuardTimeToProcessAddrEvents = 4; // msec
|
||||
|
||||
struct AddrEvent : public LinkedListEntry<AddrEvent>, public Heap::Allocatable<AddrEvent>
|
||||
{
|
||||
AddrEvent(const Ip6::Address &aAddress, bool aAdded);
|
||||
bool Matches(const Ip6::Address &aAddress) const { return mAddress == aAddress; }
|
||||
bool Matches(AddrType aType) const;
|
||||
|
||||
AddrEvent *mNext;
|
||||
Ip6::Address mAddress;
|
||||
bool mAdded;
|
||||
};
|
||||
|
||||
using EventTimer = TimerMilliIn<Core, &Core::HandleLocalHostEventTimer>;
|
||||
|
||||
Heap::String mName;
|
||||
AddressArray mIp4Addresses;
|
||||
AddressArray mIp6Addresses;
|
||||
OwningList<AddrEvent> mAddrEvents;
|
||||
EventTimer mEventTimer;
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
class HostEntry : public Entry, public LinkedListEntry<HostEntry>, public Heap::Allocatable<HostEntry>
|
||||
{
|
||||
friend class LinkedListEntry<HostEntry>;
|
||||
@@ -1095,15 +1181,18 @@ private:
|
||||
public:
|
||||
HostEntry(void);
|
||||
Error Init(Instance &aInstance, const Host &aHost) { return Init(aInstance, aHost.mHostName); }
|
||||
Error Init(Instance &aInstance, const LocalHost &aLocalHost) { return Init(aInstance, aLocalHost.GetName()); }
|
||||
Error Init(Instance &aInstance, const Key &aKey) { return Init(aInstance, aKey.mName); }
|
||||
bool IsEmpty(void) const;
|
||||
bool Matches(const Name &aName) const;
|
||||
bool Matches(const Host &aHost) const;
|
||||
bool Matches(const LocalHost &aLocalHost) const;
|
||||
bool Matches(const Key &aKey) const;
|
||||
bool Matches(const Heap::String &aName) const;
|
||||
bool Matches(State aState) const { return GetState() == aState; }
|
||||
bool Matches(const HostEntry &aEntry) const { return (this == &aEntry); }
|
||||
void Register(const Host &aHost, const Callback &aCallback);
|
||||
void Register(const LocalHost &aLocalHost, const Callback &aCallback);
|
||||
void Register(const Key &aKey, const Callback &aCallback);
|
||||
void Unregister(const Host &aHost);
|
||||
void Unregister(const Key &aKey);
|
||||
@@ -1119,6 +1208,15 @@ private:
|
||||
#endif
|
||||
|
||||
private:
|
||||
struct AddrRecord : public RecordInfo, public Heap::Allocatable<AddrRecord>
|
||||
{
|
||||
void Clear(void);
|
||||
void UpdateAddresses(const Host &aHost);
|
||||
void UpdateAddresses(const AddressArray &aAddresses);
|
||||
|
||||
AddressArray mAddresses;
|
||||
};
|
||||
|
||||
Error Init(Instance &aInstance, const char *aName);
|
||||
void ClearHost(void);
|
||||
void ScheduleToRemoveIfEmpty(void);
|
||||
@@ -1127,18 +1225,21 @@ private:
|
||||
void PrepareResponseRecords(EntryContext &aContext);
|
||||
void UpdateRecordsState(const TxMessage &aResponse);
|
||||
void DetermineNextFireTime(void);
|
||||
void AppendAddressRecordsTo(TxMessage &aTxMessage, Section aSection);
|
||||
void AppendIp6AddressRecordsTo(TxMessage &aTxMessage, Section aSection);
|
||||
void AppendIp4AddressRecordsTo(TxMessage &aTxMessage, Section aSection);
|
||||
void AppendAddressRecordsTo(TxMessage &aTxMessage, Section aSection, AddrRecord &aAddrRecord, bool aIp6);
|
||||
void AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection);
|
||||
void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection);
|
||||
void AppendNameTo(TxMessage &aTxMessage, Section aSection);
|
||||
void MarkToAppendAddrRecordsInAdditionalData(void);
|
||||
|
||||
static void AppendEntryName(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
|
||||
|
||||
HostEntry *mNext;
|
||||
Heap::String mName;
|
||||
RecordInfo mAddrRecord;
|
||||
AddressArray mAddresses;
|
||||
uint16_t mNameOffset;
|
||||
HostEntry *mNext;
|
||||
Heap::String mName;
|
||||
AddrRecord mIp6AddrRecord;
|
||||
OwnedPtr<AddrRecord> mIp4AddrRecord;
|
||||
uint16_t mNameOffset;
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -2101,6 +2202,8 @@ private:
|
||||
template <typename CacheType, typename BrowserResolverType>
|
||||
Error Stop(const BrowserResolverType &aBrowserOrResolver);
|
||||
|
||||
void AfterInstanceInit(void);
|
||||
void HandleHostAddressEvent(const Ip6::Address &aAddress, bool aAdded, uint32_t aInfraIfIndex);
|
||||
void InvokeConflictCallback(const char *aName, const char *aServiceType);
|
||||
void HandleMessage(Message &aMessage, bool aIsUnicast, const AddressInfo &aSenderAddress);
|
||||
void AddPassiveSrvTxtCache(const char *aServiceInstance, const char *aServiceType);
|
||||
@@ -2140,6 +2243,7 @@ private:
|
||||
bool mIsQuestionUnicastAllowed;
|
||||
uint16_t mMaxMessageSize;
|
||||
uint32_t mInfraIfIndex;
|
||||
LocalHost mLocalHost;
|
||||
OwningList<HostEntry> mHostEntries;
|
||||
OwningList<ServiceEntry> mServiceEntries;
|
||||
OwningList<ServiceType> mServiceTypes;
|
||||
|
||||
+476
-4
@@ -245,7 +245,8 @@ struct DnsRecord : public Allocatable<DnsRecord>, public LinkedListEntry<DnsReco
|
||||
{
|
||||
RecordData(void) { memset(this, 0, sizeof(*this)); }
|
||||
|
||||
Ip6::Address mIp6Address; // For AAAAA (or A)
|
||||
Ip6::Address mIp6Address; // For AAAAA
|
||||
Ip4::Address mIp4Address; // For A
|
||||
SrvData mSrv; // For SRV
|
||||
Array<uint8_t, kMaxDataSize> mData; // For TXT or KEY
|
||||
DnsName mPtrName; // For PTR
|
||||
@@ -285,6 +286,12 @@ struct DnsRecord : public Allocatable<DnsRecord>, public LinkedListEntry<DnsReco
|
||||
|
||||
switch (mType)
|
||||
{
|
||||
case ResourceRecord::kTypeA:
|
||||
VerifyOrQuit(record.GetLength() == sizeof(Ip4::Address));
|
||||
SuccessOrQuit(aMessage.Read(offset, mData.mIp4Address));
|
||||
logStr.Append(" %s", mData.mIp4Address.ToString().AsCString());
|
||||
break;
|
||||
|
||||
case ResourceRecord::kTypeAaaa:
|
||||
VerifyOrQuit(record.GetLength() == sizeof(Ip6::Address));
|
||||
SuccessOrQuit(aMessage.Read(offset, mData.mIp6Address));
|
||||
@@ -415,6 +422,31 @@ struct DnsRecords : public OwningList<DnsRecord>
|
||||
return contains;
|
||||
}
|
||||
|
||||
bool ContainsA(const DnsNameString &aFullName,
|
||||
const Ip4::Address &aAddress,
|
||||
bool aCacheFlush,
|
||||
TtlCheckMode aTtlCheckMode,
|
||||
uint32_t aTtl = 0) const
|
||||
{
|
||||
bool contains = false;
|
||||
|
||||
for (const DnsRecord &record : *this)
|
||||
{
|
||||
if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeA) &&
|
||||
(record.mData.mIp4Address == aAddress))
|
||||
{
|
||||
VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
|
||||
VerifyOrExit(record.mCacheFlush == aCacheFlush);
|
||||
VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
|
||||
contains = true;
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return contains;
|
||||
}
|
||||
|
||||
bool ContainsKey(const DnsNameString &aFullName,
|
||||
const Data &aKeyData,
|
||||
bool aCacheFlush,
|
||||
@@ -556,7 +588,7 @@ struct DnsRecords : public OwningList<DnsRecord>
|
||||
}
|
||||
};
|
||||
|
||||
// Bit-flags used in `Validate()` with a `Service`
|
||||
// Bit-flags used in `Validate()` with a `Service` or `LocalHost`
|
||||
// to specify which records should be checked in the announce
|
||||
// message.
|
||||
|
||||
@@ -566,6 +598,8 @@ static constexpr uint8_t kCheckSrv = (1 << 0);
|
||||
static constexpr uint8_t kCheckTxt = (1 << 1);
|
||||
static constexpr uint8_t kCheckPtr = (1 << 2);
|
||||
static constexpr uint8_t kCheckServicesPtr = (1 << 3);
|
||||
static constexpr uint8_t kCheckAaaa = (1 << 4);
|
||||
static constexpr uint8_t kCheckA = (1 << 5);
|
||||
|
||||
enum GoodBye : bool // Used to indicate "goodbye" records (with zero TTL)
|
||||
{
|
||||
@@ -581,6 +615,16 @@ enum DnsMessageType : uint8_t
|
||||
kLegacyUnicastResponse,
|
||||
};
|
||||
|
||||
struct LocalHost
|
||||
{
|
||||
static constexpr uint32_t kTtl = 120;
|
||||
static constexpr uint16_t kMaxAddrs = 16;
|
||||
|
||||
char mName[Name::kMaxNameSize];
|
||||
Array<Ip6::Address, kMaxAddrs> mIp6Addrs;
|
||||
Array<Ip4::Address, kMaxAddrs> mIp4Addrs;
|
||||
};
|
||||
|
||||
struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMessage>
|
||||
{
|
||||
DnsMessage *mNext;
|
||||
@@ -743,6 +787,27 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
|
||||
}
|
||||
}
|
||||
|
||||
void ValidateAsProbeFor(const LocalHost &aLocalHost, bool aUnicastResponse) const
|
||||
{
|
||||
DnsNameString fullName;
|
||||
|
||||
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
|
||||
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
|
||||
|
||||
fullName.Append("%s.local.", aLocalHost.mName);
|
||||
VerifyOrQuit(mQuestions.Contains(fullName, aUnicastResponse));
|
||||
|
||||
for (const Ip6::Address &ip6Addr : aLocalHost.mIp6Addrs)
|
||||
{
|
||||
VerifyOrQuit(mAuthRecords.ContainsAaaa(fullName, ip6Addr, !kCacheFlush, kNonZeroTtl, LocalHost::kTtl));
|
||||
}
|
||||
|
||||
for (const Ip4::Address &ip4Addr : aLocalHost.mIp4Addrs)
|
||||
{
|
||||
VerifyOrQuit(mAuthRecords.ContainsA(fullName, ip4Addr, !kCacheFlush, kNonZeroTtl, LocalHost::kTtl));
|
||||
}
|
||||
}
|
||||
|
||||
void ValidateAsProbeFor(const Core::Service &aService, bool aUnicastResponse) const
|
||||
{
|
||||
DnsNameString serviceName;
|
||||
@@ -776,8 +841,7 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
|
||||
{
|
||||
DnsNameString fullName;
|
||||
TtlCheckMode ttlCheck;
|
||||
|
||||
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
|
||||
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
|
||||
|
||||
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
|
||||
|
||||
@@ -797,6 +861,49 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
|
||||
}
|
||||
}
|
||||
|
||||
void Validate(const LocalHost &aLocalHost,
|
||||
Section aSection,
|
||||
AnnounceCheckFlags aCheckFlags,
|
||||
GoodBye aIsGoodBye = kNotGoodBye) const
|
||||
{
|
||||
DnsNameString fullName;
|
||||
TtlCheckMode ttlCheck;
|
||||
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
|
||||
|
||||
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
|
||||
|
||||
VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
|
||||
|
||||
fullName.Append("%s.local.", aLocalHost.mName);
|
||||
|
||||
if (aCheckFlags & kCheckAaaa)
|
||||
{
|
||||
for (const Ip6::Address &ip6Addr : aLocalHost.mIp6Addrs)
|
||||
{
|
||||
VerifyOrQuit(
|
||||
RecordsFor(aSection).ContainsAaaa(fullName, ip6Addr, cacheFlushSet, ttlCheck, LocalHost::kTtl));
|
||||
}
|
||||
}
|
||||
|
||||
if (aCheckFlags & kCheckA)
|
||||
{
|
||||
for (const Ip4::Address &ip4Addr : aLocalHost.mIp4Addrs)
|
||||
{
|
||||
VerifyOrQuit(
|
||||
RecordsFor(aSection).ContainsA(fullName, ip4Addr, cacheFlushSet, ttlCheck, LocalHost::kTtl));
|
||||
}
|
||||
}
|
||||
|
||||
if (!aIsGoodBye && (aSection == kInAnswerSection))
|
||||
{
|
||||
bool shouldSeeAaaa = (aLocalHost.mIp6Addrs.GetLength() != 0);
|
||||
bool shouldSeeA = (aLocalHost.mIp4Addrs.GetLength() != 0);
|
||||
|
||||
VerifyOrQuit(mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeAaaa) == shouldSeeAaaa);
|
||||
VerifyOrQuit(mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeA) == shouldSeeA);
|
||||
}
|
||||
}
|
||||
|
||||
void Validate(const Core::Service &aService,
|
||||
Section aSection,
|
||||
AnnounceCheckFlags aCheckFlags,
|
||||
@@ -2057,6 +2164,370 @@ void TestHostReg(void)
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void TestLocalHost(void)
|
||||
{
|
||||
Core *mdns = InitTest();
|
||||
LocalHost localHost;
|
||||
Ip6::Address ip6Address;
|
||||
Ip4::Address ip4Address;
|
||||
const DnsMessage *dnsMsg;
|
||||
uint16_t heapAllocations;
|
||||
DnsNameString hostFullName;
|
||||
|
||||
Log("-------------------------------------------------------------------------------------------");
|
||||
Log("TestLocalHost");
|
||||
|
||||
AdvanceTime(1);
|
||||
|
||||
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
||||
|
||||
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
||||
|
||||
SuccessOrQuit(StringCopy(localHost.mName, mdns->GetLocalHostName()));
|
||||
Log("Local host name is \"%s\"", localHost.mName);
|
||||
|
||||
hostFullName.Append("%s.local.", localHost.mName);
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Add an IP6 address and IP4 address for local host, check probes and announcements");
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:cafe::1"));
|
||||
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
SuccessOrQuit(ip4Address.FromString("200.1.5.6"));
|
||||
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
|
||||
ip6Address.SetToIp4Mapped(ip4Address);
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
AdvanceTime(4);
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
||||
{
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime(250);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
|
||||
dnsMsg->ValidateAsProbeFor(localHost, /* aUnicastRequest */ (probeCount == 0));
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
}
|
||||
|
||||
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
||||
{
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
}
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Send a query for AAAA record and validate the response");
|
||||
|
||||
AdvanceTime(2000);
|
||||
|
||||
sDnsMessages.Clear();
|
||||
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAaaa);
|
||||
|
||||
AdvanceTime(1000);
|
||||
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
VerifyOrQuit(dnsMsg != nullptr);
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa);
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Send a query for A record and validate the response");
|
||||
|
||||
AdvanceTime(2000);
|
||||
|
||||
sDnsMessages.Clear();
|
||||
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeA);
|
||||
|
||||
AdvanceTime(1000);
|
||||
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
VerifyOrQuit(dnsMsg != nullptr);
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(localHost, kInAnswerSection, kCheckA);
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Send a query for ANY record and validate the response");
|
||||
|
||||
AdvanceTime(2000);
|
||||
|
||||
sDnsMessages.Clear();
|
||||
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAny);
|
||||
|
||||
AdvanceTime(1000);
|
||||
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
VerifyOrQuit(dnsMsg != nullptr);
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Send a query for non-existing record and validate the response with NSEC");
|
||||
|
||||
AdvanceTime(2000);
|
||||
|
||||
sDnsMessages.Clear();
|
||||
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeKey);
|
||||
|
||||
AdvanceTime(1000);
|
||||
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
VerifyOrQuit(dnsMsg != nullptr);
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
|
||||
VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeAaaa));
|
||||
VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeA));
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Signal a new host IPv6 address is added and validate new announcements");
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:cafe::22"));
|
||||
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime(5);
|
||||
|
||||
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
||||
{
|
||||
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa);
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
sDnsMessages.Clear();
|
||||
}
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Signal new host IPv6 addresses added and removed");
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:cafe::22"));
|
||||
localHost.mIp6Addrs.Remove(ip6Address);
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
||||
|
||||
// Add and then remove the same address quickly
|
||||
// It should not be included in the announcements.
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:cafe::333"));
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
AdvanceTime(1);
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:cafe::4444"));
|
||||
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
Log("Validate the announcements");
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime(4);
|
||||
|
||||
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
||||
{
|
||||
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa);
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
sDnsMessages.Clear();
|
||||
}
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Signal three new host IPv4 addresses added");
|
||||
|
||||
SuccessOrQuit(ip4Address.FromString("200.1.5.7"));
|
||||
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
|
||||
ip6Address.SetToIp4Mapped(ip4Address);
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
SuccessOrQuit(ip4Address.FromString("200.1.2.100"));
|
||||
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
|
||||
ip6Address.SetToIp4Mapped(ip4Address);
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
SuccessOrQuit(ip4Address.FromString("200.1.4.0"));
|
||||
SuccessOrQuit(localHost.mIp4Addrs.PushBack(ip4Address));
|
||||
ip6Address.SetToIp4Mapped(ip4Address);
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
Log("Validate the announcements");
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime(5);
|
||||
|
||||
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
||||
{
|
||||
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(localHost, kInAnswerSection, kCheckA);
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
sDnsMessages.Clear();
|
||||
}
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Signal all host IPv4 addresses are removed, validate goodbye announcements");
|
||||
|
||||
for (const Ip4::Address &ip4Addr : localHost.mIp4Addrs)
|
||||
{
|
||||
ip6Address.SetToIp4Mapped(ip4Addr);
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
||||
}
|
||||
|
||||
localHost.mIp4Addrs.Clear();
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime(5);
|
||||
|
||||
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
||||
{
|
||||
AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(localHost, kInAnswerSection, kCheckA, kGoodBye);
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
sDnsMessages.Clear();
|
||||
}
|
||||
|
||||
AdvanceTime(10 * 1000);
|
||||
VerifyOrQuit(sDnsMessages.IsEmpty());
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Signal removal of an IPv6 host address which was not added earlier");
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:cafe::beef"));
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
||||
|
||||
Log("Validate that there are no announcements");
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime(10 * 1000);
|
||||
VerifyOrQuit(sDnsMessages.IsEmpty());
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Signal remove and re-add of the same host IPv6 address quickly");
|
||||
|
||||
ip6Address = localHost.mIp6Addrs[0];
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ false, kInfraIfIndex);
|
||||
AdvanceTime(1);
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
Log("Validate that there are no announcements");
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime(10 * 1000);
|
||||
VerifyOrQuit(sDnsMessages.IsEmpty());
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Validate `SetLocalHostName()`");
|
||||
|
||||
VerifyOrQuit(mdns->SetLocalHostName("itsme") == kErrorInvalidState);
|
||||
|
||||
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
||||
|
||||
SuccessOrQuit(mdns->SetLocalHostName("itsme"));
|
||||
VerifyOrQuit(StringMatch(mdns->GetLocalHostName(), "itsme"));
|
||||
|
||||
localHost.mIp4Addrs.Clear();
|
||||
localHost.mIp6Addrs.Clear();
|
||||
|
||||
SuccessOrQuit(StringCopy(localHost.mName, mdns->GetLocalHostName()));
|
||||
Log("Local host name is \"%s\"", localHost.mName);
|
||||
|
||||
hostFullName.Append("%s.local.", localHost.mName);
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
Log("Re-enable mDNS module, add 4 new host IPv6 address and validate probe and announcements");
|
||||
|
||||
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:beef::a"));
|
||||
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:beef::b"));
|
||||
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:beef::c"));
|
||||
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString("fd00:beef::d"));
|
||||
SuccessOrQuit(localHost.mIp6Addrs.PushBack(ip6Address));
|
||||
otPlatMdnsHandleHostAddressEvent(sInstance, &ip6Address, /* aAdded */ true, kInfraIfIndex);
|
||||
|
||||
AdvanceTime(4);
|
||||
|
||||
sDnsMessages.Clear();
|
||||
|
||||
for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
|
||||
{
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime(250);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 4, /* Addnl */ 0);
|
||||
dnsMsg->ValidateAsProbeFor(localHost, /* aUnicastRequest */ (probeCount == 0));
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
}
|
||||
|
||||
for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
|
||||
{
|
||||
sDnsMessages.Clear();
|
||||
|
||||
AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
|
||||
|
||||
VerifyOrQuit(!sDnsMessages.IsEmpty());
|
||||
dnsMsg = sDnsMessages.GetHead();
|
||||
dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
|
||||
dnsMsg->Validate(localHost, kInAnswerSection, kCheckAaaa | kCheckA);
|
||||
VerifyOrQuit(dnsMsg->GetNext() == nullptr);
|
||||
}
|
||||
|
||||
AdvanceTime(1000);
|
||||
|
||||
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||
|
||||
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
|
||||
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
||||
|
||||
Log("End of test");
|
||||
|
||||
testFreeInstance(sInstance);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void TestKeyReg(void)
|
||||
{
|
||||
Core *mdns = InitTest();
|
||||
@@ -8182,6 +8653,7 @@ int main(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||
ot::Dns::Multicast::TestHostReg();
|
||||
ot::Dns::Multicast::TestLocalHost();
|
||||
ot::Dns::Multicast::TestKeyReg();
|
||||
ot::Dns::Multicast::TestServiceReg();
|
||||
ot::Dns::Multicast::TestUnregisterBeforeProbeFinished();
|
||||
|
||||
Reference in New Issue
Block a user