@@ -52,6 +52,7 @@ BorderAgent::BorderAgent(Instance &aInstance)
5252#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
5353 , mIdInitialized (false )
5454#endif
55+ , mNotifyMeshCoPServiceChangedTask (aInstance)
5556#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
5657 , mEphemeralKeyManager (aInstance)
5758#endif
@@ -114,6 +115,7 @@ void BorderAgent::Start(void)
114115 pskc.Clear ();
115116
116117 mIsRunning = true ;
118+ PostNotifyMeshCoPServiceChangedTask ();
117119
118120 LogInfo (" Border Agent start listening on port %u" , GetUdpPort ());
119121
@@ -132,6 +134,7 @@ void BorderAgent::Stop(void)
132134
133135 mDtlsTransport .Close ();
134136 mIsRunning = false ;
137+ PostNotifyMeshCoPServiceChangedTask ();
135138
136139 LogInfo (" Border Agent stopped" );
137140
@@ -141,6 +144,13 @@ void BorderAgent::Stop(void)
141144
142145uint16_t BorderAgent::GetUdpPort (void ) const { return mDtlsTransport .GetUdpPort (); }
143146
147+ void BorderAgent::SetMeshCoPServiceChangedCallback (MeshCoPServiceChangedCallback aCallback, void *aContext)
148+ {
149+ mMeshCoPServiceChangedCallback .Set (aCallback, aContext);
150+
151+ mNotifyMeshCoPServiceChangedTask .Post ();
152+ }
153+
144154void BorderAgent::HandleNotifierEvents (Events aEvents)
145155{
146156 if (aEvents.Contains (kEventThreadRoleChanged ))
@@ -169,6 +179,12 @@ void BorderAgent::HandleNotifierEvents(Events aEvents)
169179 pskc.Clear ();
170180 }
171181
182+ if (aEvents.ContainsAny (kEventThreadRoleChanged | kEventThreadExtPanIdChanged | kEventThreadNetworkNameChanged |
183+ kEventThreadBackboneRouterStateChanged | kEventActiveDatasetChanged ))
184+ {
185+ PostNotifyMeshCoPServiceChangedTask ();
186+ }
187+
172188exit:
173189 return ;
174190}
@@ -316,6 +332,188 @@ template <> void BorderAgent::HandleTmf<kUriRelayRx>(Coap::Message &aMessage, co
316332 FreeMessageOnError (message, error);
317333}
318334
335+ void BorderAgent::NotifyMeshCoPServiceChanged (void )
336+ {
337+ MeshCoPTxtEncoder meshCoPTxtEncoder (GetInstance ());
338+
339+ VerifyOrExit (mMeshCoPServiceChangedCallback .IsSet ());
340+ SuccessOrAssert (meshCoPTxtEncoder.EncodeTxtData ());
341+
342+ mMeshCoPServiceChangedCallback .Invoke (meshCoPTxtEncoder.GetTxtData (), meshCoPTxtEncoder.GetTxtDataLen ());
343+
344+ exit:
345+ return ;
346+ }
347+
348+ void BorderAgent::PostNotifyMeshCoPServiceChangedTask (void )
349+ {
350+ if (mMeshCoPServiceChangedCallback .IsSet ())
351+ {
352+ mNotifyMeshCoPServiceChangedTask .Post ();
353+ }
354+ }
355+
356+ // ----------------------------------------------------------------------------------------------------------------------
357+ // BorderAgent::MeshCoPTxtEncoder
358+
359+ Error BorderAgent::MeshCoPTxtEncoder::AppendTxtEntry (const char *aKey, const void *aValue, uint16_t aValueLength)
360+ {
361+ Dns::TxtEntry txtEntry;
362+
363+ txtEntry.Init (aKey, reinterpret_cast <const uint8_t *>(aValue), aValueLength);
364+ return txtEntry.AppendTo (mAppender );
365+ }
366+
367+ template <> Error BorderAgent::MeshCoPTxtEncoder::AppendTxtEntry<NameData>(const char *aKey, const NameData &aObject)
368+ {
369+ return AppendTxtEntry (aKey, aObject.GetBuffer (), aObject.GetLength ());
370+ }
371+
372+ Error BorderAgent::MeshCoPTxtEncoder::EncodeTxtData (void )
373+ {
374+ #if OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_1
375+ static const char kThreadVersionString [] = " 1.1.1" ;
376+ #elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_2
377+ static const char kThreadVersionString [] = " 1.2.0" ;
378+ #elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_3
379+ static const char kThreadVersionString [] = " 1.3.0" ;
380+ #elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_3_1
381+ static const char kThreadVersionString [] = " 1.3.1" ;
382+ #elif OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_4
383+ static const char kThreadVersionString [] = " 1.4.0" ;
384+ #endif
385+
386+ Error error = kErrorNone ;
387+ #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
388+ Id id;
389+ #endif
390+ StateBitmap state;
391+
392+ #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
393+ if (Get<BorderAgent>().GetId (id) == kErrorNone )
394+ {
395+ SuccessOrExit (error = AppendTxtEntry (" id" , id));
396+ }
397+ #endif
398+ SuccessOrExit (error = AppendTxtEntry (" nn" , Get<NetworkNameManager>().GetNetworkName ().GetAsData ()));
399+ SuccessOrExit (error = AppendTxtEntry (" xp" , Get<ExtendedPanIdManager>().GetExtPanId ()));
400+ SuccessOrExit (error = AppendTxtEntry (" tv" , NameData (kThreadVersionString , sizeof (kThreadVersionString ) - 1 )));
401+ SuccessOrExit (error = AppendTxtEntry (" xa" , Get<Mac::Mac>().GetExtAddress ()));
402+
403+ state = GetStateBitmap ();
404+ SuccessOrExit (error = AppendTxtEntry (" sb" , BigEndian::HostSwap32 (state.ToUint32 ())));
405+
406+ if (state.mThreadIfStatus == kThreadIfStatusActive )
407+ {
408+ SuccessOrExit (error = AppendTxtEntry (
409+ " pt" , BigEndian::HostSwap32 (Get<Mle::MleRouter>().GetLeaderData ().GetPartitionId ())));
410+ if (Get<MeshCoP::ActiveDatasetManager>().GetTimestamp ().IsValid ())
411+ {
412+ SuccessOrExit (error = AppendTxtEntry (" at" , Get<MeshCoP::ActiveDatasetManager>().GetTimestamp ()));
413+ }
414+ }
415+
416+ #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
417+ SuccessOrExit (error = AppendBbrTxtEntry (state));
418+ #endif
419+ #if OTBR_ENABLE_BORDER_ROUTING
420+ SuccessOrExit (error = AppendOmrTxtEntry ());
421+ #endif
422+
423+ exit:
424+ return error;
425+ }
426+
427+ #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
428+ Error BorderAgent::MeshCoPTxtEncoder::AppendBbrTxtEntry (StateBitmap aState)
429+ {
430+ Error error = kErrorNone ;
431+ const DomainName &domainName = Get<MeshCoP::NetworkNameManager>().GetDomainName ();
432+
433+ if (aState.mBbrIsActive )
434+ {
435+ BackboneRouter::Config bbrConfig;
436+
437+ Get<BackboneRouter::Local>().GetConfig (bbrConfig);
438+ SuccessOrExit (error = AppendTxtEntry (" sq" , bbrConfig.mSequenceNumber ));
439+ SuccessOrExit (error = AppendTxtEntry (" bb" , BigEndian::HostSwap16 (BackboneRouter::kBackboneUdpPort )));
440+ }
441+
442+ error = AppendTxtEntry (
443+ " dn" , NameData (domainName.GetAsCString (), StringLength (domainName.GetAsCString (), sizeof (domainName))));
444+
445+ exit:
446+ return error;
447+ }
448+ #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
449+
450+ #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
451+ Error BorderAgent::MeshCoPTxtEncoder::AppendOmrTxtEntry (void )
452+ {
453+ Error error = kErrorNone ;
454+ Ip6::Prefix prefix;
455+ BorderRouter::RoutingManager::RoutePreference preference;
456+
457+ if ((error = Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix (prefix, preference)) == kErrorNone )
458+ {
459+ uint8_t omrData[Ip6::NetworkPrefix::kSize + 1 ];
460+ omrData[0 ] = prefix.GetLength ();
461+ memcpy (omrData + 1 , prefix.GetBytes (), prefix.GetBytesSize ());
462+
463+ SuccessOrExit (error = AppendTxtEntry (" omr" , omrData));
464+ }
465+
466+ exit:
467+ return error;
468+ }
469+ #endif
470+
471+ BorderAgent::MeshCoPTxtEncoder::StateBitmap BorderAgent::MeshCoPTxtEncoder::GetStateBitmap (void )
472+ {
473+ StateBitmap state;
474+
475+ state.mConnectionMode = kConnectionModePskc ;
476+ state.mAvailability = kAvailabilityHigh ;
477+
478+ switch (Get<Mle::MleRouter>().GetRole ())
479+ {
480+ case Mle::DeviceRole::kRoleDisabled :
481+ state.mThreadIfStatus = kThreadIfStatusNotInitialized ;
482+ state.mThreadRole = kThreadRoleDisabledOrDetached ;
483+ break ;
484+ case Mle::DeviceRole::kRoleDetached :
485+ state.mThreadIfStatus = kThreadIfStatusInitialized ;
486+ state.mThreadRole = kThreadRoleDisabledOrDetached ;
487+ break ;
488+ case Mle::DeviceRole::kRoleChild :
489+ state.mThreadIfStatus = kThreadIfStatusActive ;
490+ state.mThreadRole = kThreadRoleChild ;
491+ break ;
492+ case Mle::DeviceRole::kRoleRouter :
493+ state.mThreadIfStatus = kThreadIfStatusActive ;
494+ state.mThreadRole = kThreadRoleRouter ;
495+ break ;
496+ case Mle::DeviceRole::kRoleLeader :
497+ state.mThreadIfStatus = kThreadIfStatusActive ;
498+ state.mThreadRole = kThreadRoleLeader ;
499+ break ;
500+ }
501+
502+ #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
503+ state.mBbrIsActive = state.mThreadIfStatus == kThreadIfStatusActive &&
504+ Get<BackboneRouter::Local>().GetState () != BackboneRouter::Local::State::kStateDisabled ;
505+ state.mBbrIsPrimary = state.mThreadIfStatus == kThreadIfStatusActive &&
506+ Get<BackboneRouter::Local>().GetState () == BackboneRouter::Local::State::kStatePrimary ;
507+ #endif
508+
509+ #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
510+ state.mEpskcSupported =
511+ Get<BorderAgent::EphemeralKeyManager>().GetState () != EphemeralKeyManager::State::kStateDisabled ;
512+ #endif
513+
514+ return state;
515+ }
516+
319517// ----------------------------------------------------------------------------------------------------------------------
320518// BorderAgent::SessionIterator
321519
0 commit comments