xref: /aosp_15_r20/external/ot-br-posix/src/trel_dnssd/trel_dnssd.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1*4a64e381SAndroid Build Coastguard Worker /*
2*4a64e381SAndroid Build Coastguard Worker  *    Copyright (c) 2021, The OpenThread Authors.
3*4a64e381SAndroid Build Coastguard Worker  *    All rights reserved.
4*4a64e381SAndroid Build Coastguard Worker  *
5*4a64e381SAndroid Build Coastguard Worker  *    Redistribution and use in source and binary forms, with or without
6*4a64e381SAndroid Build Coastguard Worker  *    modification, are permitted provided that the following conditions are met:
7*4a64e381SAndroid Build Coastguard Worker  *    1. Redistributions of source code must retain the above copyright
8*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer.
9*4a64e381SAndroid Build Coastguard Worker  *    2. Redistributions in binary form must reproduce the above copyright
10*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer in the
11*4a64e381SAndroid Build Coastguard Worker  *       documentation and/or other materials provided with the distribution.
12*4a64e381SAndroid Build Coastguard Worker  *    3. Neither the name of the copyright holder nor the
13*4a64e381SAndroid Build Coastguard Worker  *       names of its contributors may be used to endorse or promote products
14*4a64e381SAndroid Build Coastguard Worker  *       derived from this software without specific prior written permission.
15*4a64e381SAndroid Build Coastguard Worker  *
16*4a64e381SAndroid Build Coastguard Worker  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*4a64e381SAndroid Build Coastguard Worker  *    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*4a64e381SAndroid Build Coastguard Worker  *    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*4a64e381SAndroid Build Coastguard Worker  *    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*4a64e381SAndroid Build Coastguard Worker  *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*4a64e381SAndroid Build Coastguard Worker  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*4a64e381SAndroid Build Coastguard Worker  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*4a64e381SAndroid Build Coastguard Worker  *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*4a64e381SAndroid Build Coastguard Worker  *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*4a64e381SAndroid Build Coastguard Worker  *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*4a64e381SAndroid Build Coastguard Worker  *    POSSIBILITY OF SUCH DAMAGE.
27*4a64e381SAndroid Build Coastguard Worker  */
28*4a64e381SAndroid Build Coastguard Worker 
29*4a64e381SAndroid Build Coastguard Worker /**
30*4a64e381SAndroid Build Coastguard Worker  * @file
31*4a64e381SAndroid Build Coastguard Worker  *   This file includes implementation of TREL DNS-SD over mDNS.
32*4a64e381SAndroid Build Coastguard Worker  */
33*4a64e381SAndroid Build Coastguard Worker 
34*4a64e381SAndroid Build Coastguard Worker #if OTBR_ENABLE_TREL
35*4a64e381SAndroid Build Coastguard Worker 
36*4a64e381SAndroid Build Coastguard Worker #define OTBR_LOG_TAG "TrelDns"
37*4a64e381SAndroid Build Coastguard Worker 
38*4a64e381SAndroid Build Coastguard Worker #include "trel_dnssd/trel_dnssd.hpp"
39*4a64e381SAndroid Build Coastguard Worker 
40*4a64e381SAndroid Build Coastguard Worker #include <inttypes.h>
41*4a64e381SAndroid Build Coastguard Worker #include <net/if.h>
42*4a64e381SAndroid Build Coastguard Worker 
43*4a64e381SAndroid Build Coastguard Worker #include <openthread/instance.h>
44*4a64e381SAndroid Build Coastguard Worker #include <openthread/link.h>
45*4a64e381SAndroid Build Coastguard Worker #include <openthread/platform/trel.h>
46*4a64e381SAndroid Build Coastguard Worker 
47*4a64e381SAndroid Build Coastguard Worker #include "common/code_utils.hpp"
48*4a64e381SAndroid Build Coastguard Worker #include "utils/hex.hpp"
49*4a64e381SAndroid Build Coastguard Worker #include "utils/string_utils.hpp"
50*4a64e381SAndroid Build Coastguard Worker 
51*4a64e381SAndroid Build Coastguard Worker static const char kTrelServiceName[] = "_trel._udp";
52*4a64e381SAndroid Build Coastguard Worker 
53*4a64e381SAndroid Build Coastguard Worker static otbr::TrelDnssd::TrelDnssd *sTrelDnssd = nullptr;
54*4a64e381SAndroid Build Coastguard Worker 
trelDnssdInitialize(const char * aTrelNetif)55*4a64e381SAndroid Build Coastguard Worker void trelDnssdInitialize(const char *aTrelNetif)
56*4a64e381SAndroid Build Coastguard Worker {
57*4a64e381SAndroid Build Coastguard Worker     sTrelDnssd->Initialize(aTrelNetif);
58*4a64e381SAndroid Build Coastguard Worker }
59*4a64e381SAndroid Build Coastguard Worker 
trelDnssdStartBrowse(void)60*4a64e381SAndroid Build Coastguard Worker void trelDnssdStartBrowse(void)
61*4a64e381SAndroid Build Coastguard Worker {
62*4a64e381SAndroid Build Coastguard Worker     sTrelDnssd->StartBrowse();
63*4a64e381SAndroid Build Coastguard Worker }
64*4a64e381SAndroid Build Coastguard Worker 
trelDnssdStopBrowse(void)65*4a64e381SAndroid Build Coastguard Worker void trelDnssdStopBrowse(void)
66*4a64e381SAndroid Build Coastguard Worker {
67*4a64e381SAndroid Build Coastguard Worker     sTrelDnssd->StopBrowse();
68*4a64e381SAndroid Build Coastguard Worker }
69*4a64e381SAndroid Build Coastguard Worker 
trelDnssdRegisterService(uint16_t aPort,const uint8_t * aTxtData,uint8_t aTxtLength)70*4a64e381SAndroid Build Coastguard Worker void trelDnssdRegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
71*4a64e381SAndroid Build Coastguard Worker {
72*4a64e381SAndroid Build Coastguard Worker     sTrelDnssd->RegisterService(aPort, aTxtData, aTxtLength);
73*4a64e381SAndroid Build Coastguard Worker }
74*4a64e381SAndroid Build Coastguard Worker 
trelDnssdRemoveService(void)75*4a64e381SAndroid Build Coastguard Worker void trelDnssdRemoveService(void)
76*4a64e381SAndroid Build Coastguard Worker {
77*4a64e381SAndroid Build Coastguard Worker     sTrelDnssd->UnregisterService();
78*4a64e381SAndroid Build Coastguard Worker }
79*4a64e381SAndroid Build Coastguard Worker 
80*4a64e381SAndroid Build Coastguard Worker namespace otbr {
81*4a64e381SAndroid Build Coastguard Worker 
82*4a64e381SAndroid Build Coastguard Worker namespace TrelDnssd {
83*4a64e381SAndroid Build Coastguard Worker 
TrelDnssd(Ncp::RcpHost & aHost,Mdns::Publisher & aPublisher)84*4a64e381SAndroid Build Coastguard Worker TrelDnssd::TrelDnssd(Ncp::RcpHost &aHost, Mdns::Publisher &aPublisher)
85*4a64e381SAndroid Build Coastguard Worker     : mPublisher(aPublisher)
86*4a64e381SAndroid Build Coastguard Worker     , mHost(aHost)
87*4a64e381SAndroid Build Coastguard Worker {
88*4a64e381SAndroid Build Coastguard Worker     sTrelDnssd = this;
89*4a64e381SAndroid Build Coastguard Worker }
90*4a64e381SAndroid Build Coastguard Worker 
Initialize(std::string aTrelNetif)91*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::Initialize(std::string aTrelNetif)
92*4a64e381SAndroid Build Coastguard Worker {
93*4a64e381SAndroid Build Coastguard Worker     mTrelNetif = std::move(aTrelNetif);
94*4a64e381SAndroid Build Coastguard Worker     // Reset mTrelNetifIndex to 0 so that when this function is called with a different aTrelNetif
95*4a64e381SAndroid Build Coastguard Worker     // than the current mTrelNetif, CheckTrelNetifReady() will update mTrelNetifIndex accordingly.
96*4a64e381SAndroid Build Coastguard Worker     mTrelNetifIndex = 0;
97*4a64e381SAndroid Build Coastguard Worker 
98*4a64e381SAndroid Build Coastguard Worker     if (IsInitialized())
99*4a64e381SAndroid Build Coastguard Worker     {
100*4a64e381SAndroid Build Coastguard Worker         otbrLogDebug("Initialized on netif \"%s\"", mTrelNetif.c_str());
101*4a64e381SAndroid Build Coastguard Worker         CheckTrelNetifReady();
102*4a64e381SAndroid Build Coastguard Worker     }
103*4a64e381SAndroid Build Coastguard Worker     else
104*4a64e381SAndroid Build Coastguard Worker     {
105*4a64e381SAndroid Build Coastguard Worker         otbrLogDebug("Not initialized");
106*4a64e381SAndroid Build Coastguard Worker     }
107*4a64e381SAndroid Build Coastguard Worker }
108*4a64e381SAndroid Build Coastguard Worker 
StartBrowse(void)109*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::StartBrowse(void)
110*4a64e381SAndroid Build Coastguard Worker {
111*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(IsInitialized());
112*4a64e381SAndroid Build Coastguard Worker 
113*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("Start browsing %s services ...", kTrelServiceName);
114*4a64e381SAndroid Build Coastguard Worker 
115*4a64e381SAndroid Build Coastguard Worker     assert(mSubscriberId == 0);
116*4a64e381SAndroid Build Coastguard Worker     mSubscriberId = mPublisher.AddSubscriptionCallbacks(
117*4a64e381SAndroid Build Coastguard Worker         [this](const std::string &aType, const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo) {
118*4a64e381SAndroid Build Coastguard Worker             OnTrelServiceInstanceResolved(aType, aInstanceInfo);
119*4a64e381SAndroid Build Coastguard Worker         },
120*4a64e381SAndroid Build Coastguard Worker         /* aHostCallback */ nullptr);
121*4a64e381SAndroid Build Coastguard Worker 
122*4a64e381SAndroid Build Coastguard Worker     if (IsReady())
123*4a64e381SAndroid Build Coastguard Worker     {
124*4a64e381SAndroid Build Coastguard Worker         mPublisher.SubscribeService(kTrelServiceName, /* aInstanceName */ "");
125*4a64e381SAndroid Build Coastguard Worker     }
126*4a64e381SAndroid Build Coastguard Worker 
127*4a64e381SAndroid Build Coastguard Worker exit:
128*4a64e381SAndroid Build Coastguard Worker     return;
129*4a64e381SAndroid Build Coastguard Worker }
130*4a64e381SAndroid Build Coastguard Worker 
StopBrowse(void)131*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::StopBrowse(void)
132*4a64e381SAndroid Build Coastguard Worker {
133*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(IsInitialized());
134*4a64e381SAndroid Build Coastguard Worker 
135*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("Stop browsing %s service.", kTrelServiceName);
136*4a64e381SAndroid Build Coastguard Worker     assert(mSubscriberId > 0);
137*4a64e381SAndroid Build Coastguard Worker 
138*4a64e381SAndroid Build Coastguard Worker     mPublisher.RemoveSubscriptionCallbacks(mSubscriberId);
139*4a64e381SAndroid Build Coastguard Worker     mSubscriberId = 0;
140*4a64e381SAndroid Build Coastguard Worker 
141*4a64e381SAndroid Build Coastguard Worker     if (IsReady())
142*4a64e381SAndroid Build Coastguard Worker     {
143*4a64e381SAndroid Build Coastguard Worker         mPublisher.UnsubscribeService(kTrelServiceName, "");
144*4a64e381SAndroid Build Coastguard Worker     }
145*4a64e381SAndroid Build Coastguard Worker 
146*4a64e381SAndroid Build Coastguard Worker exit:
147*4a64e381SAndroid Build Coastguard Worker     return;
148*4a64e381SAndroid Build Coastguard Worker }
149*4a64e381SAndroid Build Coastguard Worker 
RegisterService(uint16_t aPort,const uint8_t * aTxtData,uint8_t aTxtLength)150*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::RegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
151*4a64e381SAndroid Build Coastguard Worker {
152*4a64e381SAndroid Build Coastguard Worker     assert(aPort > 0);
153*4a64e381SAndroid Build Coastguard Worker     assert(aTxtData != nullptr);
154*4a64e381SAndroid Build Coastguard Worker 
155*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(IsInitialized());
156*4a64e381SAndroid Build Coastguard Worker 
157*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("Register %s service: port=%u, TXT=%d bytes", kTrelServiceName, aPort, aTxtLength);
158*4a64e381SAndroid Build Coastguard Worker     otbrDump(OTBR_LOG_DEBUG, OTBR_LOG_TAG, "TXT", aTxtData, aTxtLength);
159*4a64e381SAndroid Build Coastguard Worker 
160*4a64e381SAndroid Build Coastguard Worker     if (mRegisterInfo.IsValid() && IsReady())
161*4a64e381SAndroid Build Coastguard Worker     {
162*4a64e381SAndroid Build Coastguard Worker         UnpublishTrelService();
163*4a64e381SAndroid Build Coastguard Worker     }
164*4a64e381SAndroid Build Coastguard Worker 
165*4a64e381SAndroid Build Coastguard Worker     mRegisterInfo.Assign(aPort, aTxtData, aTxtLength);
166*4a64e381SAndroid Build Coastguard Worker 
167*4a64e381SAndroid Build Coastguard Worker     if (IsReady())
168*4a64e381SAndroid Build Coastguard Worker     {
169*4a64e381SAndroid Build Coastguard Worker         PublishTrelService();
170*4a64e381SAndroid Build Coastguard Worker     }
171*4a64e381SAndroid Build Coastguard Worker 
172*4a64e381SAndroid Build Coastguard Worker exit:
173*4a64e381SAndroid Build Coastguard Worker     return;
174*4a64e381SAndroid Build Coastguard Worker }
175*4a64e381SAndroid Build Coastguard Worker 
UnregisterService(void)176*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::UnregisterService(void)
177*4a64e381SAndroid Build Coastguard Worker {
178*4a64e381SAndroid Build Coastguard Worker     // Return if service has not been registered
179*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(IsInitialized() && mRegisterInfo.IsValid());
180*4a64e381SAndroid Build Coastguard Worker 
181*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("Remove %s service", kTrelServiceName);
182*4a64e381SAndroid Build Coastguard Worker 
183*4a64e381SAndroid Build Coastguard Worker     if (IsReady())
184*4a64e381SAndroid Build Coastguard Worker     {
185*4a64e381SAndroid Build Coastguard Worker         UnpublishTrelService();
186*4a64e381SAndroid Build Coastguard Worker     }
187*4a64e381SAndroid Build Coastguard Worker 
188*4a64e381SAndroid Build Coastguard Worker     mRegisterInfo.Clear();
189*4a64e381SAndroid Build Coastguard Worker 
190*4a64e381SAndroid Build Coastguard Worker exit:
191*4a64e381SAndroid Build Coastguard Worker     return;
192*4a64e381SAndroid Build Coastguard Worker }
193*4a64e381SAndroid Build Coastguard Worker 
HandleMdnsState(Mdns::Publisher::State aState)194*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::HandleMdnsState(Mdns::Publisher::State aState)
195*4a64e381SAndroid Build Coastguard Worker {
196*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aState == Mdns::Publisher::State::kReady);
197*4a64e381SAndroid Build Coastguard Worker 
198*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("mDNS Publisher is Ready");
199*4a64e381SAndroid Build Coastguard Worker     mMdnsPublisherReady = true;
200*4a64e381SAndroid Build Coastguard Worker     RemoveAllPeers();
201*4a64e381SAndroid Build Coastguard Worker 
202*4a64e381SAndroid Build Coastguard Worker     if (mRegisterInfo.IsPublished())
203*4a64e381SAndroid Build Coastguard Worker     {
204*4a64e381SAndroid Build Coastguard Worker         mRegisterInfo.mInstanceName = "";
205*4a64e381SAndroid Build Coastguard Worker     }
206*4a64e381SAndroid Build Coastguard Worker 
207*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(IsInitialized());
208*4a64e381SAndroid Build Coastguard Worker     OnBecomeReady();
209*4a64e381SAndroid Build Coastguard Worker 
210*4a64e381SAndroid Build Coastguard Worker exit:
211*4a64e381SAndroid Build Coastguard Worker     return;
212*4a64e381SAndroid Build Coastguard Worker }
213*4a64e381SAndroid Build Coastguard Worker 
OnTrelServiceInstanceResolved(const std::string & aType,const Mdns::Publisher::DiscoveredInstanceInfo & aInstanceInfo)214*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::OnTrelServiceInstanceResolved(const std::string                             &aType,
215*4a64e381SAndroid Build Coastguard Worker                                               const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo)
216*4a64e381SAndroid Build Coastguard Worker {
217*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(StringUtils::EqualCaseInsensitive(aType, kTrelServiceName));
218*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(aInstanceInfo.mNetifIndex == mTrelNetifIndex);
219*4a64e381SAndroid Build Coastguard Worker 
220*4a64e381SAndroid Build Coastguard Worker     if (aInstanceInfo.mRemoved)
221*4a64e381SAndroid Build Coastguard Worker     {
222*4a64e381SAndroid Build Coastguard Worker         OnTrelServiceInstanceRemoved(aInstanceInfo.mName);
223*4a64e381SAndroid Build Coastguard Worker     }
224*4a64e381SAndroid Build Coastguard Worker     else
225*4a64e381SAndroid Build Coastguard Worker     {
226*4a64e381SAndroid Build Coastguard Worker         OnTrelServiceInstanceAdded(aInstanceInfo);
227*4a64e381SAndroid Build Coastguard Worker     }
228*4a64e381SAndroid Build Coastguard Worker 
229*4a64e381SAndroid Build Coastguard Worker exit:
230*4a64e381SAndroid Build Coastguard Worker     return;
231*4a64e381SAndroid Build Coastguard Worker }
232*4a64e381SAndroid Build Coastguard Worker 
GetTrelInstanceName(void)233*4a64e381SAndroid Build Coastguard Worker std::string TrelDnssd::GetTrelInstanceName(void)
234*4a64e381SAndroid Build Coastguard Worker {
235*4a64e381SAndroid Build Coastguard Worker     const otExtAddress *extaddr = otLinkGetExtendedAddress(mHost.GetInstance());
236*4a64e381SAndroid Build Coastguard Worker     std::string         name;
237*4a64e381SAndroid Build Coastguard Worker     char                nameBuf[sizeof(otExtAddress) * 2 + 1];
238*4a64e381SAndroid Build Coastguard Worker 
239*4a64e381SAndroid Build Coastguard Worker     Utils::Bytes2Hex(extaddr->m8, sizeof(otExtAddress), nameBuf);
240*4a64e381SAndroid Build Coastguard Worker     name = StringUtils::ToLowercase(nameBuf);
241*4a64e381SAndroid Build Coastguard Worker 
242*4a64e381SAndroid Build Coastguard Worker     assert(name.length() == sizeof(otExtAddress) * 2);
243*4a64e381SAndroid Build Coastguard Worker 
244*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("Using instance name %s", name.c_str());
245*4a64e381SAndroid Build Coastguard Worker     return name;
246*4a64e381SAndroid Build Coastguard Worker }
247*4a64e381SAndroid Build Coastguard Worker 
PublishTrelService(void)248*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::PublishTrelService(void)
249*4a64e381SAndroid Build Coastguard Worker {
250*4a64e381SAndroid Build Coastguard Worker     assert(mRegisterInfo.IsValid());
251*4a64e381SAndroid Build Coastguard Worker     assert(!mRegisterInfo.IsPublished());
252*4a64e381SAndroid Build Coastguard Worker     assert(mTrelNetifIndex > 0);
253*4a64e381SAndroid Build Coastguard Worker 
254*4a64e381SAndroid Build Coastguard Worker     mRegisterInfo.mInstanceName = GetTrelInstanceName();
255*4a64e381SAndroid Build Coastguard Worker     mPublisher.PublishService(/* aHostName */ "", mRegisterInfo.mInstanceName, kTrelServiceName,
256*4a64e381SAndroid Build Coastguard Worker                               Mdns::Publisher::SubTypeList{}, mRegisterInfo.mPort, mRegisterInfo.mTxtData,
257*4a64e381SAndroid Build Coastguard Worker                               [](otbrError aError) { HandlePublishTrelServiceError(aError); });
258*4a64e381SAndroid Build Coastguard Worker }
259*4a64e381SAndroid Build Coastguard Worker 
HandlePublishTrelServiceError(otbrError aError)260*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::HandlePublishTrelServiceError(otbrError aError)
261*4a64e381SAndroid Build Coastguard Worker {
262*4a64e381SAndroid Build Coastguard Worker     if (aError != OTBR_ERROR_NONE)
263*4a64e381SAndroid Build Coastguard Worker     {
264*4a64e381SAndroid Build Coastguard Worker         otbrLogErr("Failed to publish TREL service: %s. TREL won't be working.", otbrErrorString(aError));
265*4a64e381SAndroid Build Coastguard Worker     }
266*4a64e381SAndroid Build Coastguard Worker }
267*4a64e381SAndroid Build Coastguard Worker 
UnpublishTrelService(void)268*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::UnpublishTrelService(void)
269*4a64e381SAndroid Build Coastguard Worker {
270*4a64e381SAndroid Build Coastguard Worker     assert(mRegisterInfo.IsValid());
271*4a64e381SAndroid Build Coastguard Worker     assert(mRegisterInfo.IsPublished());
272*4a64e381SAndroid Build Coastguard Worker 
273*4a64e381SAndroid Build Coastguard Worker     mPublisher.UnpublishService(mRegisterInfo.mInstanceName, kTrelServiceName,
274*4a64e381SAndroid Build Coastguard Worker                                 [](otbrError aError) { HandleUnpublishTrelServiceError(aError); });
275*4a64e381SAndroid Build Coastguard Worker     mRegisterInfo.mInstanceName = "";
276*4a64e381SAndroid Build Coastguard Worker }
277*4a64e381SAndroid Build Coastguard Worker 
HandleUnpublishTrelServiceError(otbrError aError)278*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::HandleUnpublishTrelServiceError(otbrError aError)
279*4a64e381SAndroid Build Coastguard Worker {
280*4a64e381SAndroid Build Coastguard Worker     if (aError != OTBR_ERROR_NONE)
281*4a64e381SAndroid Build Coastguard Worker     {
282*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("Failed to unpublish TREL service: %s", otbrErrorString(aError));
283*4a64e381SAndroid Build Coastguard Worker     }
284*4a64e381SAndroid Build Coastguard Worker }
285*4a64e381SAndroid Build Coastguard Worker 
OnTrelServiceInstanceAdded(const Mdns::Publisher::DiscoveredInstanceInfo & aInstanceInfo)286*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::OnTrelServiceInstanceAdded(const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo)
287*4a64e381SAndroid Build Coastguard Worker {
288*4a64e381SAndroid Build Coastguard Worker     std::string        instanceName = StringUtils::ToLowercase(aInstanceInfo.mName);
289*4a64e381SAndroid Build Coastguard Worker     Ip6Address         selectedAddress;
290*4a64e381SAndroid Build Coastguard Worker     otPlatTrelPeerInfo peerInfo;
291*4a64e381SAndroid Build Coastguard Worker 
292*4a64e381SAndroid Build Coastguard Worker     // Remove any existing TREL service instance before adding
293*4a64e381SAndroid Build Coastguard Worker     OnTrelServiceInstanceRemoved(instanceName);
294*4a64e381SAndroid Build Coastguard Worker 
295*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("Peer discovered: %s hostname %s addresses %zu port %d priority %d "
296*4a64e381SAndroid Build Coastguard Worker                  "weight %d",
297*4a64e381SAndroid Build Coastguard Worker                  aInstanceInfo.mName.c_str(), aInstanceInfo.mHostName.c_str(), aInstanceInfo.mAddresses.size(),
298*4a64e381SAndroid Build Coastguard Worker                  aInstanceInfo.mPort, aInstanceInfo.mPriority, aInstanceInfo.mWeight);
299*4a64e381SAndroid Build Coastguard Worker 
300*4a64e381SAndroid Build Coastguard Worker     for (const auto &addr : aInstanceInfo.mAddresses)
301*4a64e381SAndroid Build Coastguard Worker     {
302*4a64e381SAndroid Build Coastguard Worker         otbrLogDebug("Peer address: %s", addr.ToString().c_str());
303*4a64e381SAndroid Build Coastguard Worker 
304*4a64e381SAndroid Build Coastguard Worker         // Skip anycast (Refer to https://datatracker.ietf.org/doc/html/rfc2373#section-2.6.1)
305*4a64e381SAndroid Build Coastguard Worker         if (addr.m64[1] == 0)
306*4a64e381SAndroid Build Coastguard Worker         {
307*4a64e381SAndroid Build Coastguard Worker             continue;
308*4a64e381SAndroid Build Coastguard Worker         }
309*4a64e381SAndroid Build Coastguard Worker 
310*4a64e381SAndroid Build Coastguard Worker         // If there are multiple addresses, we prefer the address
311*4a64e381SAndroid Build Coastguard Worker         // which is numerically smallest. This prefers GUA over ULA
312*4a64e381SAndroid Build Coastguard Worker         // (`fc00::/7`) and then link-local (`fe80::/10`).
313*4a64e381SAndroid Build Coastguard Worker 
314*4a64e381SAndroid Build Coastguard Worker         if (selectedAddress.IsUnspecified() || (addr < selectedAddress))
315*4a64e381SAndroid Build Coastguard Worker         {
316*4a64e381SAndroid Build Coastguard Worker             selectedAddress = addr;
317*4a64e381SAndroid Build Coastguard Worker         }
318*4a64e381SAndroid Build Coastguard Worker     }
319*4a64e381SAndroid Build Coastguard Worker 
320*4a64e381SAndroid Build Coastguard Worker     if (aInstanceInfo.mAddresses.empty())
321*4a64e381SAndroid Build Coastguard Worker     {
322*4a64e381SAndroid Build Coastguard Worker         otbrLogWarning("Peer %s does not have any IPv6 address, ignored", aInstanceInfo.mName.c_str());
323*4a64e381SAndroid Build Coastguard Worker         ExitNow();
324*4a64e381SAndroid Build Coastguard Worker     }
325*4a64e381SAndroid Build Coastguard Worker 
326*4a64e381SAndroid Build Coastguard Worker     peerInfo.mRemoved = false;
327*4a64e381SAndroid Build Coastguard Worker     memcpy(&peerInfo.mSockAddr.mAddress, &selectedAddress, sizeof(peerInfo.mSockAddr.mAddress));
328*4a64e381SAndroid Build Coastguard Worker     peerInfo.mSockAddr.mPort = aInstanceInfo.mPort;
329*4a64e381SAndroid Build Coastguard Worker     peerInfo.mTxtData        = aInstanceInfo.mTxtData.data();
330*4a64e381SAndroid Build Coastguard Worker     peerInfo.mTxtLength      = aInstanceInfo.mTxtData.size();
331*4a64e381SAndroid Build Coastguard Worker 
332*4a64e381SAndroid Build Coastguard Worker     {
333*4a64e381SAndroid Build Coastguard Worker         Peer peer(aInstanceInfo.mTxtData, peerInfo.mSockAddr);
334*4a64e381SAndroid Build Coastguard Worker 
335*4a64e381SAndroid Build Coastguard Worker         VerifyOrExit(peer.mValid, otbrLogWarning("Peer %s is invalid", aInstanceInfo.mName.c_str()));
336*4a64e381SAndroid Build Coastguard Worker 
337*4a64e381SAndroid Build Coastguard Worker         otPlatTrelHandleDiscoveredPeerInfo(mHost.GetInstance(), &peerInfo);
338*4a64e381SAndroid Build Coastguard Worker 
339*4a64e381SAndroid Build Coastguard Worker         mPeers.emplace(instanceName, peer);
340*4a64e381SAndroid Build Coastguard Worker         CheckPeersNumLimit();
341*4a64e381SAndroid Build Coastguard Worker     }
342*4a64e381SAndroid Build Coastguard Worker 
343*4a64e381SAndroid Build Coastguard Worker exit:
344*4a64e381SAndroid Build Coastguard Worker     return;
345*4a64e381SAndroid Build Coastguard Worker }
346*4a64e381SAndroid Build Coastguard Worker 
OnTrelServiceInstanceRemoved(const std::string & aInstanceName)347*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::OnTrelServiceInstanceRemoved(const std::string &aInstanceName)
348*4a64e381SAndroid Build Coastguard Worker {
349*4a64e381SAndroid Build Coastguard Worker     std::string instanceName = StringUtils::ToLowercase(aInstanceName);
350*4a64e381SAndroid Build Coastguard Worker     auto        it           = mPeers.find(instanceName);
351*4a64e381SAndroid Build Coastguard Worker 
352*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(it != mPeers.end());
353*4a64e381SAndroid Build Coastguard Worker 
354*4a64e381SAndroid Build Coastguard Worker     otbrLogDebug("Peer removed: %s", instanceName.c_str());
355*4a64e381SAndroid Build Coastguard Worker 
356*4a64e381SAndroid Build Coastguard Worker     // Remove the peer only when all instances are removed because one peer can have multiple instances if expired
357*4a64e381SAndroid Build Coastguard Worker     // instances were not properly removed by mDNS.
358*4a64e381SAndroid Build Coastguard Worker     if (CountDuplicatePeers(it->second) == 0)
359*4a64e381SAndroid Build Coastguard Worker     {
360*4a64e381SAndroid Build Coastguard Worker         NotifyRemovePeer(it->second);
361*4a64e381SAndroid Build Coastguard Worker     }
362*4a64e381SAndroid Build Coastguard Worker 
363*4a64e381SAndroid Build Coastguard Worker     mPeers.erase(it);
364*4a64e381SAndroid Build Coastguard Worker 
365*4a64e381SAndroid Build Coastguard Worker exit:
366*4a64e381SAndroid Build Coastguard Worker     return;
367*4a64e381SAndroid Build Coastguard Worker }
368*4a64e381SAndroid Build Coastguard Worker 
CheckPeersNumLimit(void)369*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::CheckPeersNumLimit(void)
370*4a64e381SAndroid Build Coastguard Worker {
371*4a64e381SAndroid Build Coastguard Worker     const PeerMap::value_type *oldestPeer = nullptr;
372*4a64e381SAndroid Build Coastguard Worker 
373*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(mPeers.size() >= kPeerCacheSize);
374*4a64e381SAndroid Build Coastguard Worker 
375*4a64e381SAndroid Build Coastguard Worker     for (const auto &entry : mPeers)
376*4a64e381SAndroid Build Coastguard Worker     {
377*4a64e381SAndroid Build Coastguard Worker         if (oldestPeer == nullptr || entry.second.mDiscoverTime < oldestPeer->second.mDiscoverTime)
378*4a64e381SAndroid Build Coastguard Worker         {
379*4a64e381SAndroid Build Coastguard Worker             oldestPeer = &entry;
380*4a64e381SAndroid Build Coastguard Worker         }
381*4a64e381SAndroid Build Coastguard Worker     }
382*4a64e381SAndroid Build Coastguard Worker 
383*4a64e381SAndroid Build Coastguard Worker     OnTrelServiceInstanceRemoved(oldestPeer->first);
384*4a64e381SAndroid Build Coastguard Worker 
385*4a64e381SAndroid Build Coastguard Worker exit:
386*4a64e381SAndroid Build Coastguard Worker     return;
387*4a64e381SAndroid Build Coastguard Worker }
388*4a64e381SAndroid Build Coastguard Worker 
NotifyRemovePeer(const Peer & aPeer)389*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::NotifyRemovePeer(const Peer &aPeer)
390*4a64e381SAndroid Build Coastguard Worker {
391*4a64e381SAndroid Build Coastguard Worker     otPlatTrelPeerInfo peerInfo;
392*4a64e381SAndroid Build Coastguard Worker 
393*4a64e381SAndroid Build Coastguard Worker     peerInfo.mRemoved   = true;
394*4a64e381SAndroid Build Coastguard Worker     peerInfo.mTxtData   = aPeer.mTxtData.data();
395*4a64e381SAndroid Build Coastguard Worker     peerInfo.mTxtLength = aPeer.mTxtData.size();
396*4a64e381SAndroid Build Coastguard Worker     peerInfo.mSockAddr  = aPeer.mSockAddr;
397*4a64e381SAndroid Build Coastguard Worker 
398*4a64e381SAndroid Build Coastguard Worker     otPlatTrelHandleDiscoveredPeerInfo(mHost.GetInstance(), &peerInfo);
399*4a64e381SAndroid Build Coastguard Worker }
400*4a64e381SAndroid Build Coastguard Worker 
RemoveAllPeers(void)401*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::RemoveAllPeers(void)
402*4a64e381SAndroid Build Coastguard Worker {
403*4a64e381SAndroid Build Coastguard Worker     for (const auto &entry : mPeers)
404*4a64e381SAndroid Build Coastguard Worker     {
405*4a64e381SAndroid Build Coastguard Worker         NotifyRemovePeer(entry.second);
406*4a64e381SAndroid Build Coastguard Worker     }
407*4a64e381SAndroid Build Coastguard Worker 
408*4a64e381SAndroid Build Coastguard Worker     mPeers.clear();
409*4a64e381SAndroid Build Coastguard Worker }
410*4a64e381SAndroid Build Coastguard Worker 
CheckTrelNetifReady(void)411*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::CheckTrelNetifReady(void)
412*4a64e381SAndroid Build Coastguard Worker {
413*4a64e381SAndroid Build Coastguard Worker     assert(IsInitialized());
414*4a64e381SAndroid Build Coastguard Worker 
415*4a64e381SAndroid Build Coastguard Worker     if (mTrelNetifIndex == 0)
416*4a64e381SAndroid Build Coastguard Worker     {
417*4a64e381SAndroid Build Coastguard Worker         mTrelNetifIndex = if_nametoindex(mTrelNetif.c_str());
418*4a64e381SAndroid Build Coastguard Worker 
419*4a64e381SAndroid Build Coastguard Worker         if (mTrelNetifIndex != 0)
420*4a64e381SAndroid Build Coastguard Worker         {
421*4a64e381SAndroid Build Coastguard Worker             otbrLogDebug("Netif %s is ready: index = %" PRIu32, mTrelNetif.c_str(), mTrelNetifIndex);
422*4a64e381SAndroid Build Coastguard Worker             OnBecomeReady();
423*4a64e381SAndroid Build Coastguard Worker         }
424*4a64e381SAndroid Build Coastguard Worker         else
425*4a64e381SAndroid Build Coastguard Worker         {
426*4a64e381SAndroid Build Coastguard Worker             uint16_t delay = kCheckNetifReadyIntervalMs;
427*4a64e381SAndroid Build Coastguard Worker 
428*4a64e381SAndroid Build Coastguard Worker             otbrLogWarning("Netif %s is not ready (%s), will retry after %d seconds", mTrelNetif.c_str(),
429*4a64e381SAndroid Build Coastguard Worker                            strerror(errno), delay / 1000);
430*4a64e381SAndroid Build Coastguard Worker             mTaskRunner.Post(Milliseconds(delay), [this]() { CheckTrelNetifReady(); });
431*4a64e381SAndroid Build Coastguard Worker         }
432*4a64e381SAndroid Build Coastguard Worker     }
433*4a64e381SAndroid Build Coastguard Worker }
434*4a64e381SAndroid Build Coastguard Worker 
IsReady(void) const435*4a64e381SAndroid Build Coastguard Worker bool TrelDnssd::IsReady(void) const
436*4a64e381SAndroid Build Coastguard Worker {
437*4a64e381SAndroid Build Coastguard Worker     assert(IsInitialized());
438*4a64e381SAndroid Build Coastguard Worker 
439*4a64e381SAndroid Build Coastguard Worker     return mTrelNetifIndex > 0 && mMdnsPublisherReady;
440*4a64e381SAndroid Build Coastguard Worker }
441*4a64e381SAndroid Build Coastguard Worker 
OnBecomeReady(void)442*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::OnBecomeReady(void)
443*4a64e381SAndroid Build Coastguard Worker {
444*4a64e381SAndroid Build Coastguard Worker     if (IsReady())
445*4a64e381SAndroid Build Coastguard Worker     {
446*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("TREL DNS-SD Is Now Ready: Netif=%s(%" PRIu32 "), SubscriberId=%" PRIu64 ", Register=%s!",
447*4a64e381SAndroid Build Coastguard Worker                     mTrelNetif.c_str(), mTrelNetifIndex, mSubscriberId, mRegisterInfo.mInstanceName.c_str());
448*4a64e381SAndroid Build Coastguard Worker 
449*4a64e381SAndroid Build Coastguard Worker         if (mSubscriberId > 0)
450*4a64e381SAndroid Build Coastguard Worker         {
451*4a64e381SAndroid Build Coastguard Worker             mPublisher.SubscribeService(kTrelServiceName, /* aInstanceName */ "");
452*4a64e381SAndroid Build Coastguard Worker         }
453*4a64e381SAndroid Build Coastguard Worker 
454*4a64e381SAndroid Build Coastguard Worker         if (mRegisterInfo.IsValid())
455*4a64e381SAndroid Build Coastguard Worker         {
456*4a64e381SAndroid Build Coastguard Worker             PublishTrelService();
457*4a64e381SAndroid Build Coastguard Worker         }
458*4a64e381SAndroid Build Coastguard Worker     }
459*4a64e381SAndroid Build Coastguard Worker }
460*4a64e381SAndroid Build Coastguard Worker 
CountDuplicatePeers(const TrelDnssd::Peer & aPeer)461*4a64e381SAndroid Build Coastguard Worker uint16_t TrelDnssd::CountDuplicatePeers(const TrelDnssd::Peer &aPeer)
462*4a64e381SAndroid Build Coastguard Worker {
463*4a64e381SAndroid Build Coastguard Worker     uint16_t count = 0;
464*4a64e381SAndroid Build Coastguard Worker 
465*4a64e381SAndroid Build Coastguard Worker     for (const auto &entry : mPeers)
466*4a64e381SAndroid Build Coastguard Worker     {
467*4a64e381SAndroid Build Coastguard Worker         if (&entry.second == &aPeer)
468*4a64e381SAndroid Build Coastguard Worker         {
469*4a64e381SAndroid Build Coastguard Worker             continue;
470*4a64e381SAndroid Build Coastguard Worker         }
471*4a64e381SAndroid Build Coastguard Worker 
472*4a64e381SAndroid Build Coastguard Worker         if (!memcmp(&entry.second.mSockAddr, &aPeer.mSockAddr, sizeof(otSockAddr)) &&
473*4a64e381SAndroid Build Coastguard Worker             !memcmp(&entry.second.mExtAddr, &aPeer.mExtAddr, sizeof(otExtAddress)))
474*4a64e381SAndroid Build Coastguard Worker         {
475*4a64e381SAndroid Build Coastguard Worker             count++;
476*4a64e381SAndroid Build Coastguard Worker         }
477*4a64e381SAndroid Build Coastguard Worker     }
478*4a64e381SAndroid Build Coastguard Worker 
479*4a64e381SAndroid Build Coastguard Worker     return count;
480*4a64e381SAndroid Build Coastguard Worker }
481*4a64e381SAndroid Build Coastguard Worker 
Assign(uint16_t aPort,const uint8_t * aTxtData,uint8_t aTxtLength)482*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::RegisterInfo::Assign(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
483*4a64e381SAndroid Build Coastguard Worker {
484*4a64e381SAndroid Build Coastguard Worker     assert(!IsPublished());
485*4a64e381SAndroid Build Coastguard Worker     assert(aPort > 0);
486*4a64e381SAndroid Build Coastguard Worker 
487*4a64e381SAndroid Build Coastguard Worker     mPort = aPort;
488*4a64e381SAndroid Build Coastguard Worker     mTxtData.assign(aTxtData, aTxtData + aTxtLength);
489*4a64e381SAndroid Build Coastguard Worker }
490*4a64e381SAndroid Build Coastguard Worker 
Clear(void)491*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::RegisterInfo::Clear(void)
492*4a64e381SAndroid Build Coastguard Worker {
493*4a64e381SAndroid Build Coastguard Worker     assert(!IsPublished());
494*4a64e381SAndroid Build Coastguard Worker 
495*4a64e381SAndroid Build Coastguard Worker     mPort = 0;
496*4a64e381SAndroid Build Coastguard Worker     mTxtData.clear();
497*4a64e381SAndroid Build Coastguard Worker }
498*4a64e381SAndroid Build Coastguard Worker 
499*4a64e381SAndroid Build Coastguard Worker const char TrelDnssd::Peer::kTxtRecordExtAddressKey[] = "xa";
500*4a64e381SAndroid Build Coastguard Worker 
ReadExtAddrFromTxtData(void)501*4a64e381SAndroid Build Coastguard Worker void TrelDnssd::Peer::ReadExtAddrFromTxtData(void)
502*4a64e381SAndroid Build Coastguard Worker {
503*4a64e381SAndroid Build Coastguard Worker     std::vector<Mdns::Publisher::TxtEntry> txtEntries;
504*4a64e381SAndroid Build Coastguard Worker 
505*4a64e381SAndroid Build Coastguard Worker     memset(&mExtAddr, 0, sizeof(mExtAddr));
506*4a64e381SAndroid Build Coastguard Worker 
507*4a64e381SAndroid Build Coastguard Worker     SuccessOrExit(Mdns::Publisher::DecodeTxtData(txtEntries, mTxtData.data(), mTxtData.size()));
508*4a64e381SAndroid Build Coastguard Worker 
509*4a64e381SAndroid Build Coastguard Worker     for (const auto &txtEntry : txtEntries)
510*4a64e381SAndroid Build Coastguard Worker     {
511*4a64e381SAndroid Build Coastguard Worker         if (txtEntry.mIsBooleanAttribute)
512*4a64e381SAndroid Build Coastguard Worker         {
513*4a64e381SAndroid Build Coastguard Worker             continue;
514*4a64e381SAndroid Build Coastguard Worker         }
515*4a64e381SAndroid Build Coastguard Worker 
516*4a64e381SAndroid Build Coastguard Worker         if (StringUtils::EqualCaseInsensitive(txtEntry.mKey, kTxtRecordExtAddressKey))
517*4a64e381SAndroid Build Coastguard Worker         {
518*4a64e381SAndroid Build Coastguard Worker             VerifyOrExit(txtEntry.mValue.size() == sizeof(mExtAddr));
519*4a64e381SAndroid Build Coastguard Worker 
520*4a64e381SAndroid Build Coastguard Worker             memcpy(mExtAddr.m8, txtEntry.mValue.data(), sizeof(mExtAddr));
521*4a64e381SAndroid Build Coastguard Worker             mValid = true;
522*4a64e381SAndroid Build Coastguard Worker             break;
523*4a64e381SAndroid Build Coastguard Worker         }
524*4a64e381SAndroid Build Coastguard Worker     }
525*4a64e381SAndroid Build Coastguard Worker 
526*4a64e381SAndroid Build Coastguard Worker exit:
527*4a64e381SAndroid Build Coastguard Worker 
528*4a64e381SAndroid Build Coastguard Worker     if (!mValid)
529*4a64e381SAndroid Build Coastguard Worker     {
530*4a64e381SAndroid Build Coastguard Worker         otbrLogInfo("Failed to dissect ExtAddr from peer TXT data");
531*4a64e381SAndroid Build Coastguard Worker     }
532*4a64e381SAndroid Build Coastguard Worker 
533*4a64e381SAndroid Build Coastguard Worker     return;
534*4a64e381SAndroid Build Coastguard Worker }
535*4a64e381SAndroid Build Coastguard Worker 
536*4a64e381SAndroid Build Coastguard Worker } // namespace TrelDnssd
537*4a64e381SAndroid Build Coastguard Worker 
538*4a64e381SAndroid Build Coastguard Worker } // namespace otbr
539*4a64e381SAndroid Build Coastguard Worker 
540*4a64e381SAndroid Build Coastguard Worker #endif // OTBR_ENABLE_TREL
541