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