mirror of
https://github.com/espressif/openthread.git
synced 2026-10-02 05:47:40 +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.
|
* @note This number versions both OpenThread platform and user APIs.
|
||||||
*/
|
*/
|
||||||
#define OPENTHREAD_API_VERSION (490)
|
#define OPENTHREAD_API_VERSION (491)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup api-instance
|
* @addtogroup api-instance
|
||||||
|
|||||||
@@ -203,6 +203,29 @@ bool otMdnsIsQuestionUnicastAllowed(otInstance *aInstance);
|
|||||||
*/
|
*/
|
||||||
void otMdnsSetConflictCallback(otInstance *aInstance, otMdnsConflictCallback aCallback);
|
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.
|
* 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.
|
* 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] aInstance The OpernThread instance.
|
||||||
* @param[in] aEnable Indicate whether to enable or disable.
|
* @param[in] aEnable Indicate whether to enable or disable.
|
||||||
* @param[in] aInfraInfIndex The infrastructure network interface index.
|
* @param[in] aInfraInfIndex The infrastructure network interface index.
|
||||||
@@ -154,6 +158,47 @@ extern void otPlatMdnsHandleReceive(otInstance *aInstance,
|
|||||||
bool aIsUnicast,
|
bool aIsUnicast,
|
||||||
const otPlatMdnsAddressInfo *aAddress);
|
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);
|
return ProcessEnableDisable(aArgs, otMdnsIsQuestionUnicastAllowed, otMdnsSetQuestionUnicastAllowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <> otError Mdns::Process<Cmd("localhostname")>(Arg aArgs[])
|
||||||
|
{
|
||||||
|
return ProcessGetSet(aArgs, otMdnsGetLocalHostName, otMdnsSetLocalHostName);
|
||||||
|
}
|
||||||
|
|
||||||
void Mdns::OutputHost(const otMdnsHost &aHost)
|
void Mdns::OutputHost(const otMdnsHost &aHost)
|
||||||
{
|
{
|
||||||
OutputLine("Host %s", aHost.mHostName);
|
OutputLine("Host %s", aHost.mHostName);
|
||||||
@@ -1209,6 +1214,7 @@ otError Mdns::Process(Arg aArgs[])
|
|||||||
CmdEntry("ip6resolvers"),
|
CmdEntry("ip6resolvers"),
|
||||||
CmdEntry("keys"),
|
CmdEntry("keys"),
|
||||||
#endif
|
#endif
|
||||||
|
CmdEntry("localhostname"),
|
||||||
CmdEntry("recordquerier"),
|
CmdEntry("recordquerier"),
|
||||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
||||||
CmdEntry("recordqueriers"),
|
CmdEntry("recordqueriers"),
|
||||||
|
|||||||
@@ -61,6 +61,16 @@ void otMdnsSetConflictCallback(otInstance *aInstance, otMdnsConflictCallback aCa
|
|||||||
AsCoreType(aInstance).Get<Dns::Multicast::Core>().SetConflictCallback(aCallback);
|
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,
|
otError otMdnsRegisterHost(otInstance *aInstance,
|
||||||
const otMdnsHost *aHost,
|
const otMdnsHost *aHost,
|
||||||
otMdnsRequestId aRequestId,
|
otMdnsRequestId aRequestId,
|
||||||
|
|||||||
@@ -405,6 +405,10 @@ void Instance::AfterInit(void)
|
|||||||
Get<Trel::Link>().AfterInit();
|
Get<Trel::Link>().AfterInit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||||
|
Get<Dns::Multicast::Core>().AfterInstanceInit();
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
|
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||||
|
|
||||||
#if OPENTHREAD_ENABLE_VENDOR_EXTENSION
|
#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));
|
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
|
// Core
|
||||||
|
|
||||||
@@ -70,6 +78,7 @@ Core::Core(Instance &aInstance)
|
|||||||
, mIsQuestionUnicastAllowed(kDefaultQuAllowed)
|
, mIsQuestionUnicastAllowed(kDefaultQuAllowed)
|
||||||
, mMaxMessageSize(kMaxMessageSize)
|
, mMaxMessageSize(kMaxMessageSize)
|
||||||
, mInfraIfIndex(0)
|
, mInfraIfIndex(0)
|
||||||
|
, mLocalHost(aInstance)
|
||||||
, mMultiPacketRxMessages(aInstance)
|
, mMultiPacketRxMessages(aInstance)
|
||||||
, mNextProbeTxTime(TimerMilli::GetNow() - 1)
|
, mNextProbeTxTime(TimerMilli::GetNow() - 1)
|
||||||
, mEntryTimer(aInstance)
|
, 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 Core::SetEnabled(bool aEnable, uint32_t aInfraIfIndex)
|
||||||
{
|
{
|
||||||
Error error = kErrorNone;
|
Error error = kErrorNone;
|
||||||
@@ -99,10 +121,8 @@ Error Core::SetEnabled(bool aEnable, uint32_t aInfraIfIndex)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogInfo("Disabling");
|
LogInfo("Disabling");
|
||||||
}
|
|
||||||
|
|
||||||
if (!mIsEnabled)
|
mLocalHost.ClearAddresses();
|
||||||
{
|
|
||||||
mHostEntries.Clear();
|
mHostEntries.Clear();
|
||||||
mServiceEntries.Clear();
|
mServiceEntries.Clear();
|
||||||
mServiceTypes.Clear();
|
mServiceTypes.Clear();
|
||||||
@@ -258,6 +278,12 @@ void Core::InvokeConflictCallback(const char *aName, const char *aServiceType)
|
|||||||
mConflictCallback(&GetInstance(), aName, 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)
|
void Core::HandleMessage(Message &aMessage, bool aIsUnicast, const AddressInfo &aSenderAddress)
|
||||||
{
|
{
|
||||||
OwnedPtr<Message> messagePtr(&aMessage);
|
OwnedPtr<Message> messagePtr(&aMessage);
|
||||||
@@ -540,6 +566,11 @@ exit:
|
|||||||
return matches;
|
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)
|
void Core::AddressArray::SetFrom(const Ip6::Address *aAddresses, uint16_t aNumAddresses)
|
||||||
{
|
{
|
||||||
Free();
|
Free();
|
||||||
@@ -1198,7 +1229,7 @@ bool Core::Entry::ShouldAnswerNsec(TimeMilli aNow) const
|
|||||||
return mMulticastNsecPending && (GetNsecAnswerTime() <= aNow);
|
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
|
// Schedule answers for all matching records in `aRecords` array
|
||||||
// to a given non-probe question.
|
// to a given non-probe question.
|
||||||
@@ -1206,9 +1237,9 @@ void Core::Entry::AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecord
|
|||||||
bool allEmptyOrZeroTtl = true;
|
bool allEmptyOrZeroTtl = true;
|
||||||
bool answerNsec = 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())
|
if (!record.CanAnswer())
|
||||||
{
|
{
|
||||||
@@ -1218,7 +1249,7 @@ void Core::Entry::AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecord
|
|||||||
|
|
||||||
allEmptyOrZeroTtl = false;
|
allEmptyOrZeroTtl = false;
|
||||||
|
|
||||||
if (QuestionMatches(aInfo.mQuestionRrType, aRecords[index].mType))
|
if (QuestionMatches(aInfo.mQuestionRrType, recordAndType.mType))
|
||||||
{
|
{
|
||||||
answerNsec = false;
|
answerNsec = false;
|
||||||
record.ScheduleAnswer(aInfo);
|
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 allEmptyOrZeroTtl = true;
|
||||||
bool shouldDelay = false;
|
bool shouldDelay = false;
|
||||||
@@ -1246,9 +1277,9 @@ void Core::Entry::AnswerProbe(const AnswerInfo &aInfo, RecordAndType *aRecords,
|
|||||||
|
|
||||||
OT_ASSERT(info.mIsProbe);
|
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;
|
TimeMilli lastMulticastTime;
|
||||||
|
|
||||||
if (!record.CanAnswer())
|
if (!record.CanAnswer())
|
||||||
@@ -1294,9 +1325,9 @@ void Core::Entry::AnswerProbe(const AnswerInfo &aInfo, RecordAndType *aRecords,
|
|||||||
info.mAnswerDelay = 0;
|
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:
|
exit:
|
||||||
@@ -1469,6 +1500,180 @@ exit:
|
|||||||
return error;
|
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
|
// 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 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 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::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)
|
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();
|
ExitNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
mAddrRecord.UpdateTtl(DetermineTtl(aHost.mTtl, kDefaultTtl));
|
mIp6AddrRecord.UpdateTtl(DetermineTtl(aHost.mTtl, kDefaultTtl));
|
||||||
mAddrRecord.UpdateProperty(mAddresses, AsCoreTypePtr(aHost.mAddresses), aHost.mAddressesLength);
|
mIp6AddrRecord.UpdateAddresses(aHost);
|
||||||
|
|
||||||
DetermineNextFireTime();
|
DetermineNextFireTime();
|
||||||
ScheduleTimer();
|
ScheduleTimer();
|
||||||
@@ -1535,6 +1753,46 @@ exit:
|
|||||||
return;
|
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)
|
void Core::HostEntry::Register(const Key &aKey, const Callback &aCallback)
|
||||||
{
|
{
|
||||||
Entry::Register(aKey, aCallback);
|
Entry::Register(aKey, aCallback);
|
||||||
@@ -1547,14 +1805,14 @@ void Core::HostEntry::Unregister(const Host &aHost)
|
|||||||
{
|
{
|
||||||
OT_UNUSED_VARIABLE(aHost);
|
OT_UNUSED_VARIABLE(aHost);
|
||||||
|
|
||||||
VerifyOrExit(mAddrRecord.IsPresent());
|
VerifyOrExit(mIp6AddrRecord.IsPresent());
|
||||||
|
|
||||||
ClearCallback();
|
ClearCallback();
|
||||||
|
|
||||||
switch (GetState())
|
switch (GetState())
|
||||||
{
|
{
|
||||||
case kRegistered:
|
case kRegistered:
|
||||||
mAddrRecord.UpdateTtl(0);
|
mIp6AddrRecord.UpdateTtl(0);
|
||||||
DetermineNextFireTime();
|
DetermineNextFireTime();
|
||||||
ScheduleTimer();
|
ScheduleTimer();
|
||||||
break;
|
break;
|
||||||
@@ -1585,8 +1843,12 @@ void Core::HostEntry::Unregister(const Key &aKey)
|
|||||||
|
|
||||||
void Core::HostEntry::ClearHost(void)
|
void Core::HostEntry::ClearHost(void)
|
||||||
{
|
{
|
||||||
mAddrRecord.Clear();
|
mIp6AddrRecord.Clear();
|
||||||
mAddresses.Free();
|
|
||||||
|
if (mIp4AddrRecord != nullptr)
|
||||||
|
{
|
||||||
|
mIp4AddrRecord->Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::HostEntry::ScheduleToRemoveIfEmpty(void)
|
void Core::HostEntry::ScheduleToRemoveIfEmpty(void)
|
||||||
@@ -1612,20 +1874,25 @@ exit:
|
|||||||
|
|
||||||
void Core::HostEntry::AnswerQuestion(const AnswerInfo &aInfo)
|
void Core::HostEntry::AnswerQuestion(const AnswerInfo &aInfo)
|
||||||
{
|
{
|
||||||
RecordAndType records[] = {
|
RecordAndTypeArray recordAndTypes;
|
||||||
{mAddrRecord, ResourceRecord::kTypeAaaa},
|
|
||||||
{mKeyRecord, ResourceRecord::kTypeKey},
|
|
||||||
};
|
|
||||||
|
|
||||||
VerifyOrExit(GetState() == kRegistered);
|
VerifyOrExit(GetState() == kRegistered);
|
||||||
|
|
||||||
|
recordAndTypes.Add(mIp6AddrRecord, ResourceRecord::kTypeAaaa);
|
||||||
|
recordAndTypes.Add(mKeyRecord, ResourceRecord::kTypeKey);
|
||||||
|
|
||||||
|
if (mIp4AddrRecord != nullptr)
|
||||||
|
{
|
||||||
|
recordAndTypes.Add(*mIp4AddrRecord, ResourceRecord::kTypeA);
|
||||||
|
}
|
||||||
|
|
||||||
if (aInfo.mIsProbe)
|
if (aInfo.mIsProbe)
|
||||||
{
|
{
|
||||||
AnswerProbe(aInfo, records, GetArrayLength(records));
|
AnswerProbe(aInfo, recordAndTypes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AnswerNonProbe(aInfo, records, GetArrayLength(records));
|
AnswerNonProbe(aInfo, recordAndTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
DetermineNextFireTime();
|
DetermineNextFireTime();
|
||||||
@@ -1644,7 +1911,12 @@ void Core::HostEntry::ClearAppendState(void)
|
|||||||
|
|
||||||
Entry::ClearAppendState();
|
Entry::ClearAppendState();
|
||||||
|
|
||||||
mAddrRecord.MarkAsNotAppended();
|
mIp6AddrRecord.MarkAsNotAppended();
|
||||||
|
|
||||||
|
if (mIp4AddrRecord != nullptr)
|
||||||
|
{
|
||||||
|
mIp4AddrRecord->MarkAsNotAppended();
|
||||||
|
}
|
||||||
|
|
||||||
mNameOffset = kUnspecifiedOffset;
|
mNameOffset = kUnspecifiedOffset;
|
||||||
}
|
}
|
||||||
@@ -1660,7 +1932,8 @@ void Core::HostEntry::PrepareProbe(TxMessage &aProbe)
|
|||||||
AppendNameTo(aProbe, kQuestionSection);
|
AppendNameTo(aProbe, kQuestionSection);
|
||||||
AppendQuestionTo(aProbe);
|
AppendQuestionTo(aProbe);
|
||||||
|
|
||||||
AppendAddressRecordsTo(aProbe, kAuthoritySection);
|
AppendIp6AddressRecordsTo(aProbe, kAuthoritySection);
|
||||||
|
AppendIp4AddressRecordsTo(aProbe, kAuthoritySection);
|
||||||
AppendKeyRecordTo(aProbe, kAuthoritySection);
|
AppendKeyRecordTo(aProbe, kAuthoritySection);
|
||||||
|
|
||||||
aProbe.CheckSizeLimitToPrepareAgain(prepareAgain);
|
aProbe.CheckSizeLimitToPrepareAgain(prepareAgain);
|
||||||
@@ -1670,7 +1943,13 @@ void Core::HostEntry::PrepareProbe(TxMessage &aProbe)
|
|||||||
|
|
||||||
void Core::HostEntry::StartAnnouncing(void)
|
void Core::HostEntry::StartAnnouncing(void)
|
||||||
{
|
{
|
||||||
mAddrRecord.StartAnnouncing();
|
mIp6AddrRecord.StartAnnouncing();
|
||||||
|
|
||||||
|
if (mIp4AddrRecord != nullptr)
|
||||||
|
{
|
||||||
|
mIp4AddrRecord->StartAnnouncing();
|
||||||
|
}
|
||||||
|
|
||||||
mKeyRecord.StartAnnouncing();
|
mKeyRecord.StartAnnouncing();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1695,9 +1974,15 @@ void Core::HostEntry::PrepareResponseRecords(EntryContext &aContext)
|
|||||||
bool appendNsec = false;
|
bool appendNsec = false;
|
||||||
TxMessage &response = aContext.mResponseMessage;
|
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;
|
appendNsec = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1718,7 +2003,12 @@ void Core::HostEntry::UpdateRecordsState(const TxMessage &aResponse)
|
|||||||
// Updates state after a response is prepared.
|
// Updates state after a response is prepared.
|
||||||
|
|
||||||
Entry::UpdateRecordsState(aResponse);
|
Entry::UpdateRecordsState(aResponse);
|
||||||
mAddrRecord.UpdateStateAfterAnswer(aResponse);
|
mIp6AddrRecord.UpdateStateAfterAnswer(aResponse);
|
||||||
|
|
||||||
|
if (mIp4AddrRecord != nullptr)
|
||||||
|
{
|
||||||
|
mIp4AddrRecord->UpdateStateAfterAnswer(aResponse);
|
||||||
|
}
|
||||||
|
|
||||||
if (IsEmpty())
|
if (IsEmpty())
|
||||||
{
|
{
|
||||||
@@ -1731,7 +2021,12 @@ void Core::HostEntry::DetermineNextFireTime(void)
|
|||||||
VerifyOrExit(GetState() == kRegistered);
|
VerifyOrExit(GetState() == kRegistered);
|
||||||
|
|
||||||
Entry::DetermineNextFireTime();
|
Entry::DetermineNextFireTime();
|
||||||
mAddrRecord.UpdateFireTimeOn(*this);
|
mIp6AddrRecord.UpdateFireTimeOn(*this);
|
||||||
|
|
||||||
|
if (mIp4AddrRecord != nullptr)
|
||||||
|
{
|
||||||
|
mIp4AddrRecord->UpdateFireTimeOn(*this);
|
||||||
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return;
|
return;
|
||||||
@@ -1742,33 +2037,72 @@ void Core::HostEntry::DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) con
|
|||||||
VerifyOrExit(GetState() == kRegistered);
|
VerifyOrExit(GetState() == kRegistered);
|
||||||
|
|
||||||
Entry::DetermineNextAggrTxTime(aNextAggrTxTime);
|
Entry::DetermineNextAggrTxTime(aNextAggrTxTime);
|
||||||
mAddrRecord.DetermineNextAggrTxTime(aNextAggrTxTime);
|
mIp6AddrRecord.DetermineNextAggrTxTime(aNextAggrTxTime);
|
||||||
|
|
||||||
|
if (mIp4AddrRecord != nullptr)
|
||||||
|
{
|
||||||
|
mIp4AddrRecord->DetermineNextAggrTxTime(aNextAggrTxTime);
|
||||||
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return;
|
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;
|
Message *message;
|
||||||
bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse);
|
bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse);
|
||||||
|
|
||||||
VerifyOrExit(mAddrRecord.CanAppend());
|
VerifyOrExit(aAddrRecord.CanAppend());
|
||||||
mAddrRecord.MarkAsAppended(aTxMessage, aSection);
|
aAddrRecord.MarkAsAppended(aTxMessage, aSection);
|
||||||
|
|
||||||
message = &aTxMessage.SelectMessageFor(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);
|
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);
|
aTxMessage.IncrementRecordCount(aSection);
|
||||||
}
|
}
|
||||||
@@ -1786,11 +2120,16 @@ void Core::HostEntry::AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection
|
|||||||
{
|
{
|
||||||
TypeArray types;
|
TypeArray types;
|
||||||
|
|
||||||
if (mAddrRecord.IsPresent() && (mAddrRecord.GetTtl() > 0))
|
if (mIp6AddrRecord.IsPresent() && (mIp6AddrRecord.GetTtl() > 0))
|
||||||
{
|
{
|
||||||
types.Add(ResourceRecord::kTypeAaaa);
|
types.Add(ResourceRecord::kTypeAaaa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((mIp4AddrRecord != nullptr) && mIp4AddrRecord->IsPresent() && (mIp4AddrRecord->GetTtl() > 0))
|
||||||
|
{
|
||||||
|
types.Add(ResourceRecord::kTypeA);
|
||||||
|
}
|
||||||
|
|
||||||
if (mKeyRecord.IsPresent() && (mKeyRecord.GetTtl() > 0))
|
if (mKeyRecord.IsPresent() && (mKeyRecord.GetTtl() > 0))
|
||||||
{
|
{
|
||||||
types.Add(ResourceRecord::kTypeKey);
|
types.Add(ResourceRecord::kTypeKey);
|
||||||
@@ -1820,18 +2159,28 @@ exit:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::HostEntry::MarkToAppendAddrRecordsInAdditionalData(void)
|
||||||
|
{
|
||||||
|
mIp6AddrRecord.MarkToAppendInAdditionalData();
|
||||||
|
|
||||||
|
if (mIp4AddrRecord != nullptr)
|
||||||
|
{
|
||||||
|
mIp4AddrRecord->MarkToAppendInAdditionalData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
||||||
|
|
||||||
Error Core::HostEntry::CopyInfoTo(Host &aHost, EntryState &aState) const
|
Error Core::HostEntry::CopyInfoTo(Host &aHost, EntryState &aState) const
|
||||||
{
|
{
|
||||||
Error error = kErrorNone;
|
Error error = kErrorNone;
|
||||||
|
|
||||||
VerifyOrExit(mAddrRecord.IsPresent(), error = kErrorNotFound);
|
VerifyOrExit(mIp6AddrRecord.IsPresent(), error = kErrorNotFound);
|
||||||
|
|
||||||
aHost.mHostName = mName.AsCString();
|
aHost.mHostName = mName.AsCString();
|
||||||
aHost.mAddresses = mAddresses.AsCArray();
|
aHost.mAddresses = mIp6AddrRecord.mAddresses.AsCArray();
|
||||||
aHost.mAddressesLength = mAddresses.GetLength();
|
aHost.mAddressesLength = mIp6AddrRecord.mAddresses.GetLength();
|
||||||
aHost.mTtl = mAddrRecord.GetTtl();
|
aHost.mTtl = mIp6AddrRecord.GetTtl();
|
||||||
aHost.mInfraIfIndex = Get<Core>().mInfraIfIndex;
|
aHost.mInfraIfIndex = Get<Core>().mInfraIfIndex;
|
||||||
aState = static_cast<EntryState>(GetState());
|
aState = static_cast<EntryState>(GetState());
|
||||||
|
|
||||||
@@ -1854,6 +2203,25 @@ exit:
|
|||||||
|
|
||||||
#endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
|
#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
|
// Core::ServiceEntry
|
||||||
|
|
||||||
@@ -2103,21 +2471,21 @@ exit:
|
|||||||
|
|
||||||
void Core::ServiceEntry::AnswerServiceNameQuestion(const AnswerInfo &aInfo)
|
void Core::ServiceEntry::AnswerServiceNameQuestion(const AnswerInfo &aInfo)
|
||||||
{
|
{
|
||||||
RecordAndType records[] = {
|
RecordAndTypeArray recordAndTypes;
|
||||||
{mSrvRecord, ResourceRecord::kTypeSrv},
|
|
||||||
{mTxtRecord, ResourceRecord::kTypeTxt},
|
|
||||||
{mKeyRecord, ResourceRecord::kTypeKey},
|
|
||||||
};
|
|
||||||
|
|
||||||
VerifyOrExit(GetState() == kRegistered);
|
VerifyOrExit(GetState() == kRegistered);
|
||||||
|
|
||||||
|
recordAndTypes.Add(mSrvRecord, ResourceRecord::kTypeSrv);
|
||||||
|
recordAndTypes.Add(mTxtRecord, ResourceRecord::kTypeTxt);
|
||||||
|
recordAndTypes.Add(mKeyRecord, ResourceRecord::kTypeKey);
|
||||||
|
|
||||||
if (aInfo.mIsProbe)
|
if (aInfo.mIsProbe)
|
||||||
{
|
{
|
||||||
AnswerProbe(aInfo, records, GetArrayLength(records));
|
AnswerProbe(aInfo, recordAndTypes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AnswerNonProbe(aInfo, records, GetArrayLength(records));
|
AnswerNonProbe(aInfo, recordAndTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
DetermineNextFireTime();
|
DetermineNextFireTime();
|
||||||
@@ -2313,7 +2681,7 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext)
|
|||||||
|
|
||||||
if (hostEntry != nullptr)
|
if (hostEntry != nullptr)
|
||||||
{
|
{
|
||||||
hostEntry->mAddrRecord.MarkToAppendInAdditionalData();
|
hostEntry->MarkToAppendAddrRecordsInAdditionalData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2324,7 +2692,7 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext)
|
|||||||
|
|
||||||
if ((mSrvRecord.GetTtl() > 0) && (hostEntry != nullptr))
|
if ((mSrvRecord.GetTtl() > 0) && (hostEntry != nullptr))
|
||||||
{
|
{
|
||||||
hostEntry->mAddrRecord.MarkToAppendInAdditionalData();
|
hostEntry->MarkToAppendAddrRecordsInAdditionalData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2352,9 +2720,17 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext)
|
|||||||
AppendTxtRecordTo(response, kAdditionalDataSection);
|
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()))
|
if (appendNsec || ShouldAnswerNsec(aContext.GetNow()))
|
||||||
@@ -2428,6 +2804,8 @@ void Core::ServiceEntry::DiscoverOffsetsAndHost(HostEntry *&aHostEntry)
|
|||||||
// and name compression offsets from the previously appended
|
// and name compression offsets from the previously appended
|
||||||
// entries.
|
// entries.
|
||||||
|
|
||||||
|
// TODO: Need to handle name matching host name
|
||||||
|
|
||||||
aHostEntry = Get<Core>().mHostEntries.FindMatching(mHostName);
|
aHostEntry = Get<Core>().mHostEntries.FindMatching(mHostName);
|
||||||
|
|
||||||
if ((aHostEntry != nullptr) && (aHostEntry->GetState() != GetState()))
|
if ((aHostEntry != nullptr) && (aHostEntry->GetState() != GetState()))
|
||||||
@@ -3709,7 +4087,7 @@ void Core::RxMessage::ProcessQuestion(Question &aQuestion)
|
|||||||
ExitNow();
|
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);
|
aQuestion.mEntry = Get<Core>().mHostEntries.FindMatching(name);
|
||||||
|
|
||||||
|
|||||||
+113
-9
@@ -77,16 +77,28 @@ extern "C" void otPlatMdnsHandleReceive(otInstance *aInstance,
|
|||||||
bool aIsUnicast,
|
bool aIsUnicast,
|
||||||
const otPlatMdnsAddressInfo *aAddress);
|
const otPlatMdnsAddressInfo *aAddress);
|
||||||
|
|
||||||
|
extern "C" void otPlatMdnsHandleHostAddressEvent(otInstance *aInstance,
|
||||||
|
const otIp6Address *aAddress,
|
||||||
|
bool aAdded,
|
||||||
|
uint32_t aInfraIfIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements Multicast DNS (mDNS) core.
|
* Implements Multicast DNS (mDNS) core.
|
||||||
*/
|
*/
|
||||||
class Core : public InstanceLocator, private NonCopyable
|
class Core : public InstanceLocator, private NonCopyable
|
||||||
{
|
{
|
||||||
|
friend class ot::Instance;
|
||||||
|
|
||||||
friend void otPlatMdnsHandleReceive(otInstance *aInstance,
|
friend void otPlatMdnsHandleReceive(otInstance *aInstance,
|
||||||
otMessage *aMessage,
|
otMessage *aMessage,
|
||||||
bool aIsUnicast,
|
bool aIsUnicast,
|
||||||
const otPlatMdnsAddressInfo *aAddress);
|
const otPlatMdnsAddressInfo *aAddress);
|
||||||
|
|
||||||
|
friend void otPlatMdnsHandleHostAddressEvent(otInstance *aInstance,
|
||||||
|
const otIp6Address *aAddress,
|
||||||
|
bool aAdded,
|
||||||
|
uint32_t aInfraIfIndex);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Initializes a `Core` instance.
|
* Initializes a `Core` instance.
|
||||||
@@ -165,6 +177,26 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool IsEnabled(void) const { return mIsEnabled; }
|
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
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF
|
||||||
/**
|
/**
|
||||||
* Notifies `AdvertisingProxy` that `InfraIf` state changed.
|
* Notifies `AdvertisingProxy` that `InfraIf` state changed.
|
||||||
@@ -817,6 +849,12 @@ private:
|
|||||||
kAppendedLabels,
|
kAppendedLabels,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AddrType : uint8_t
|
||||||
|
{
|
||||||
|
kIp4AddrType,
|
||||||
|
kIp6AddrType,
|
||||||
|
};
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
|
|
||||||
@@ -897,7 +935,9 @@ private:
|
|||||||
class AddressArray : public Heap::Array<Ip6::Address>
|
class AddressArray : public Heap::Array<Ip6::Address>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
bool IsEmpty(void) const { return (GetLength() == 0); }
|
||||||
bool Matches(const Ip6::Address *aAddresses, uint16_t aNumAddresses) const;
|
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);
|
void SetFrom(const Ip6::Address *aAddresses, uint16_t aNumAddresses);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1031,10 +1071,15 @@ private:
|
|||||||
|
|
||||||
struct RecordAndType
|
struct RecordAndType
|
||||||
{
|
{
|
||||||
RecordInfo &mRecord;
|
RecordInfo *mRecord;
|
||||||
uint16_t mType;
|
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);
|
typedef void (*NameAppender)(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
|
||||||
|
|
||||||
Entry(void);
|
Entry(void);
|
||||||
@@ -1056,8 +1101,8 @@ private:
|
|||||||
void DetermineNextFireTime(void);
|
void DetermineNextFireTime(void);
|
||||||
void DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) const;
|
void DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) const;
|
||||||
void ScheduleTimer(void);
|
void ScheduleTimer(void);
|
||||||
void AnswerProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength);
|
void AnswerProbe(const AnswerInfo &aInfo, RecordAndTypeArray &aRecordAndTypes);
|
||||||
void AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength);
|
void AnswerNonProbe(const AnswerInfo &aInfo, RecordAndTypeArray &aRecordAndTypes);
|
||||||
void ScheduleNsecAnswer(const AnswerInfo &aInfo);
|
void ScheduleNsecAnswer(const AnswerInfo &aInfo);
|
||||||
|
|
||||||
template <typename EntryType> void HandleTimer(EntryContext &aContext);
|
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>
|
class HostEntry : public Entry, public LinkedListEntry<HostEntry>, public Heap::Allocatable<HostEntry>
|
||||||
{
|
{
|
||||||
friend class LinkedListEntry<HostEntry>;
|
friend class LinkedListEntry<HostEntry>;
|
||||||
@@ -1095,15 +1181,18 @@ private:
|
|||||||
public:
|
public:
|
||||||
HostEntry(void);
|
HostEntry(void);
|
||||||
Error Init(Instance &aInstance, const Host &aHost) { return Init(aInstance, aHost.mHostName); }
|
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); }
|
Error Init(Instance &aInstance, const Key &aKey) { return Init(aInstance, aKey.mName); }
|
||||||
bool IsEmpty(void) const;
|
bool IsEmpty(void) const;
|
||||||
bool Matches(const Name &aName) const;
|
bool Matches(const Name &aName) const;
|
||||||
bool Matches(const Host &aHost) const;
|
bool Matches(const Host &aHost) const;
|
||||||
|
bool Matches(const LocalHost &aLocalHost) const;
|
||||||
bool Matches(const Key &aKey) const;
|
bool Matches(const Key &aKey) const;
|
||||||
bool Matches(const Heap::String &aName) const;
|
bool Matches(const Heap::String &aName) const;
|
||||||
bool Matches(State aState) const { return GetState() == aState; }
|
bool Matches(State aState) const { return GetState() == aState; }
|
||||||
bool Matches(const HostEntry &aEntry) const { return (this == &aEntry); }
|
bool Matches(const HostEntry &aEntry) const { return (this == &aEntry); }
|
||||||
void Register(const Host &aHost, const Callback &aCallback);
|
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 Register(const Key &aKey, const Callback &aCallback);
|
||||||
void Unregister(const Host &aHost);
|
void Unregister(const Host &aHost);
|
||||||
void Unregister(const Key &aKey);
|
void Unregister(const Key &aKey);
|
||||||
@@ -1119,6 +1208,15 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
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);
|
Error Init(Instance &aInstance, const char *aName);
|
||||||
void ClearHost(void);
|
void ClearHost(void);
|
||||||
void ScheduleToRemoveIfEmpty(void);
|
void ScheduleToRemoveIfEmpty(void);
|
||||||
@@ -1127,18 +1225,21 @@ private:
|
|||||||
void PrepareResponseRecords(EntryContext &aContext);
|
void PrepareResponseRecords(EntryContext &aContext);
|
||||||
void UpdateRecordsState(const TxMessage &aResponse);
|
void UpdateRecordsState(const TxMessage &aResponse);
|
||||||
void DetermineNextFireTime(void);
|
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 AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection);
|
||||||
void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection);
|
void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection);
|
||||||
void AppendNameTo(TxMessage &aTxMessage, Section aSection);
|
void AppendNameTo(TxMessage &aTxMessage, Section aSection);
|
||||||
|
void MarkToAppendAddrRecordsInAdditionalData(void);
|
||||||
|
|
||||||
static void AppendEntryName(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
|
static void AppendEntryName(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
|
||||||
|
|
||||||
HostEntry *mNext;
|
HostEntry *mNext;
|
||||||
Heap::String mName;
|
Heap::String mName;
|
||||||
RecordInfo mAddrRecord;
|
AddrRecord mIp6AddrRecord;
|
||||||
AddressArray mAddresses;
|
OwnedPtr<AddrRecord> mIp4AddrRecord;
|
||||||
uint16_t mNameOffset;
|
uint16_t mNameOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
@@ -2101,6 +2202,8 @@ private:
|
|||||||
template <typename CacheType, typename BrowserResolverType>
|
template <typename CacheType, typename BrowserResolverType>
|
||||||
Error Stop(const BrowserResolverType &aBrowserOrResolver);
|
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 InvokeConflictCallback(const char *aName, const char *aServiceType);
|
||||||
void HandleMessage(Message &aMessage, bool aIsUnicast, const AddressInfo &aSenderAddress);
|
void HandleMessage(Message &aMessage, bool aIsUnicast, const AddressInfo &aSenderAddress);
|
||||||
void AddPassiveSrvTxtCache(const char *aServiceInstance, const char *aServiceType);
|
void AddPassiveSrvTxtCache(const char *aServiceInstance, const char *aServiceType);
|
||||||
@@ -2140,6 +2243,7 @@ private:
|
|||||||
bool mIsQuestionUnicastAllowed;
|
bool mIsQuestionUnicastAllowed;
|
||||||
uint16_t mMaxMessageSize;
|
uint16_t mMaxMessageSize;
|
||||||
uint32_t mInfraIfIndex;
|
uint32_t mInfraIfIndex;
|
||||||
|
LocalHost mLocalHost;
|
||||||
OwningList<HostEntry> mHostEntries;
|
OwningList<HostEntry> mHostEntries;
|
||||||
OwningList<ServiceEntry> mServiceEntries;
|
OwningList<ServiceEntry> mServiceEntries;
|
||||||
OwningList<ServiceType> mServiceTypes;
|
OwningList<ServiceType> mServiceTypes;
|
||||||
|
|||||||
+476
-4
@@ -245,7 +245,8 @@ struct DnsRecord : public Allocatable<DnsRecord>, public LinkedListEntry<DnsReco
|
|||||||
{
|
{
|
||||||
RecordData(void) { memset(this, 0, sizeof(*this)); }
|
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
|
SrvData mSrv; // For SRV
|
||||||
Array<uint8_t, kMaxDataSize> mData; // For TXT or KEY
|
Array<uint8_t, kMaxDataSize> mData; // For TXT or KEY
|
||||||
DnsName mPtrName; // For PTR
|
DnsName mPtrName; // For PTR
|
||||||
@@ -285,6 +286,12 @@ struct DnsRecord : public Allocatable<DnsRecord>, public LinkedListEntry<DnsReco
|
|||||||
|
|
||||||
switch (mType)
|
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:
|
case ResourceRecord::kTypeAaaa:
|
||||||
VerifyOrQuit(record.GetLength() == sizeof(Ip6::Address));
|
VerifyOrQuit(record.GetLength() == sizeof(Ip6::Address));
|
||||||
SuccessOrQuit(aMessage.Read(offset, mData.mIp6Address));
|
SuccessOrQuit(aMessage.Read(offset, mData.mIp6Address));
|
||||||
@@ -415,6 +422,31 @@ struct DnsRecords : public OwningList<DnsRecord>
|
|||||||
return contains;
|
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,
|
bool ContainsKey(const DnsNameString &aFullName,
|
||||||
const Data &aKeyData,
|
const Data &aKeyData,
|
||||||
bool aCacheFlush,
|
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
|
// to specify which records should be checked in the announce
|
||||||
// message.
|
// message.
|
||||||
|
|
||||||
@@ -566,6 +598,8 @@ static constexpr uint8_t kCheckSrv = (1 << 0);
|
|||||||
static constexpr uint8_t kCheckTxt = (1 << 1);
|
static constexpr uint8_t kCheckTxt = (1 << 1);
|
||||||
static constexpr uint8_t kCheckPtr = (1 << 2);
|
static constexpr uint8_t kCheckPtr = (1 << 2);
|
||||||
static constexpr uint8_t kCheckServicesPtr = (1 << 3);
|
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)
|
enum GoodBye : bool // Used to indicate "goodbye" records (with zero TTL)
|
||||||
{
|
{
|
||||||
@@ -581,6 +615,16 @@ enum DnsMessageType : uint8_t
|
|||||||
kLegacyUnicastResponse,
|
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>
|
struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMessage>
|
||||||
{
|
{
|
||||||
DnsMessage *mNext;
|
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
|
void ValidateAsProbeFor(const Core::Service &aService, bool aUnicastResponse) const
|
||||||
{
|
{
|
||||||
DnsNameString serviceName;
|
DnsNameString serviceName;
|
||||||
@@ -776,8 +841,7 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
|
|||||||
{
|
{
|
||||||
DnsNameString fullName;
|
DnsNameString fullName;
|
||||||
TtlCheckMode ttlCheck;
|
TtlCheckMode ttlCheck;
|
||||||
|
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
|
||||||
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
|
|
||||||
|
|
||||||
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
|
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,
|
void Validate(const Core::Service &aService,
|
||||||
Section aSection,
|
Section aSection,
|
||||||
AnnounceCheckFlags aCheckFlags,
|
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)
|
void TestKeyReg(void)
|
||||||
{
|
{
|
||||||
Core *mdns = InitTest();
|
Core *mdns = InitTest();
|
||||||
@@ -8182,6 +8653,7 @@ int main(void)
|
|||||||
{
|
{
|
||||||
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
|
||||||
ot::Dns::Multicast::TestHostReg();
|
ot::Dns::Multicast::TestHostReg();
|
||||||
|
ot::Dns::Multicast::TestLocalHost();
|
||||||
ot::Dns::Multicast::TestKeyReg();
|
ot::Dns::Multicast::TestKeyReg();
|
||||||
ot::Dns::Multicast::TestServiceReg();
|
ot::Dns::Multicast::TestServiceReg();
|
||||||
ot::Dns::Multicast::TestUnregisterBeforeProbeFinished();
|
ot::Dns::Multicast::TestUnregisterBeforeProbeFinished();
|
||||||
|
|||||||
Reference in New Issue
Block a user