Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / ot-br-posix / repo / src / agent / border_agent.cpp
1 /*
2  *    Copyright (c) 2017, The OpenThread Authors.
3  *    All rights reserved.
4  *
5  *    Redistribution and use in source and binary forms, with or without
6  *    modification, are permitted provided that the following conditions are met:
7  *    1. Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *    2. Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *    3. Neither the name of the copyright holder nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *    POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 /**
30  * @file
31  *   The file implements the Thread border agent.
32  */
33
34 #include "agent/border_agent.hpp"
35
36 #include <arpa/inet.h>
37 #include <assert.h>
38 #include <errno.h>
39 #include <netinet/in.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 #include <openthread/platform/toolchain.h>
46
47 #include "agent/border_agent.hpp"
48 #include "agent/ncp.hpp"
49 #include "agent/ncp_openthread.hpp"
50 #include "agent/uris.hpp"
51 #include "common/code_utils.hpp"
52 #include "common/logging.hpp"
53 #include "common/tlv.hpp"
54 #include "common/types.hpp"
55 #include "utils/hex.hpp"
56 #include "utils/strcpy_utils.hpp"
57
58 namespace otbr {
59
60 static const uint16_t kThreadVersion11 = 2; ///< Thread Version 1.1
61 static const uint16_t kThreadVersion12 = 3; ///< Thread Version 1.2
62
63 static const char kBorderAgentServiceType[] = "_meshcop._udp."; ///< Border agent service type of mDNS
64
65 /**
66  * Locators
67  *
68  */
69 enum
70 {
71     kAloc16Leader   = 0xfc00, ///< leader anycast locator.
72     kInvalidLocator = 0xffff, ///< invalid locator.
73 };
74
75 /**
76  * UDP ports
77  *
78  */
79 enum
80 {
81     kBorderAgentUdpPort = 49191, ///< Thread commissioning port.
82 };
83
84 BorderAgent::BorderAgent(Ncp::Controller *aNcp)
85     : mNcp(aNcp)
86 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
87     , mPublisher(Mdns::Publisher::Create(AF_UNSPEC, /* aDomain */ nullptr, HandleMdnsState, this))
88 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
89     , mAdvertisingProxy(*reinterpret_cast<Ncp::ControllerOpenThread *>(aNcp), *mPublisher)
90 #endif
91 #else
92     , mPublisher(nullptr)
93 #endif
94 #if OTBR_ENABLE_BACKBONE_ROUTER
95     , mBackboneAgent(*reinterpret_cast<Ncp::ControllerOpenThread *>(aNcp))
96 #endif
97     , mThreadStarted(false)
98 {
99 }
100
101 void BorderAgent::Init(void)
102 {
103     memset(mNetworkName, 0, sizeof(mNetworkName));
104     memset(mExtPanId, 0, sizeof(mExtPanId));
105     memset(mExtAddr, 0, sizeof(mExtAddr));
106     mExtPanIdInitialized = false;
107     mExtAddrInitialized  = false;
108     mThreadVersion       = 0;
109
110 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
111     mNcp->On(Ncp::kEventExtPanId, HandleExtPanId, this);
112     mNcp->On(Ncp::kEventNetworkName, HandleNetworkName, this);
113     mNcp->On(Ncp::kEventThreadVersion, HandleThreadVersion, this);
114     mNcp->On(Ncp::kEventExtAddr, HandleExtAddr, this);
115 #endif
116     mNcp->On(Ncp::kEventThreadState, HandleThreadState, this);
117     mNcp->On(Ncp::kEventPSKc, HandlePSKc, this);
118
119 #if OTBR_ENABLE_BACKBONE_ROUTER
120     mBackboneAgent.Init();
121 #endif
122
123     otbrLogResult(mNcp->RequestEvent(Ncp::kEventThreadState), "Check if Thread is up");
124     otbrLogResult(mNcp->RequestEvent(Ncp::kEventPSKc), "Check if PSKc is initialized");
125 }
126
127 otbrError BorderAgent::Start(void)
128 {
129     otbrError error = OTBR_ERROR_NONE;
130
131     VerifyOrExit(mThreadStarted && mPSKcInitialized, errno = EAGAIN, error = OTBR_ERROR_ERRNO);
132
133     // In case we didn't receive Thread down event.
134     Stop();
135
136 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
137     SuccessOrExit(error = mNcp->RequestEvent(Ncp::kEventNetworkName));
138     SuccessOrExit(error = mNcp->RequestEvent(Ncp::kEventExtPanId));
139     SuccessOrExit(error = mNcp->RequestEvent(Ncp::kEventThreadVersion));
140     SuccessOrExit(error = mNcp->RequestEvent(Ncp::kEventExtAddr));
141
142 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
143     mAdvertisingProxy.Start();
144 #endif
145
146     StartPublishService();
147 #endif // OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
148
149     // Suppress unused warning of label exit
150     ExitNow();
151
152 exit:
153     otbrLogResult(error, "Start Thread Border Agent");
154     return error;
155 }
156
157 void BorderAgent::Stop(void)
158 {
159 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
160     StopPublishService();
161 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
162     mAdvertisingProxy.Stop();
163 #endif
164 #endif
165 }
166
167 BorderAgent::~BorderAgent(void)
168 {
169     Stop();
170
171     if (mPublisher != nullptr)
172     {
173         delete mPublisher;
174         mPublisher = nullptr;
175     }
176 }
177
178 void BorderAgent::HandleMdnsState(Mdns::Publisher::State aState)
179 {
180     switch (aState)
181     {
182     case Mdns::Publisher::State::kReady:
183         PublishService();
184         break;
185     default:
186         otbrLog(OTBR_LOG_WARNING, "MDNS service not available!");
187         break;
188     }
189 }
190
191 void BorderAgent::UpdateFdSet(fd_set & aReadFdSet,
192                               fd_set & aWriteFdSet,
193                               fd_set & aErrorFdSet,
194                               int &    aMaxFd,
195                               timeval &aTimeout)
196 {
197 #if OTBR_ENABLE_BACKBONE_ROUTER
198     mBackboneAgent.UpdateFdSet(aReadFdSet, aWriteFdSet, aErrorFdSet, aMaxFd, aTimeout);
199 #endif
200
201     if (mPublisher != nullptr)
202     {
203         mPublisher->UpdateFdSet(aReadFdSet, aWriteFdSet, aErrorFdSet, aMaxFd, aTimeout);
204     }
205 }
206
207 void BorderAgent::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet)
208 {
209 #if OTBR_ENABLE_BACKBONE_ROUTER
210     mBackboneAgent.Process(aReadFdSet, aWriteFdSet, aErrorFdSet);
211 #endif
212     if (mPublisher != nullptr)
213     {
214         mPublisher->Process(aReadFdSet, aWriteFdSet, aErrorFdSet);
215     }
216 }
217
218 static const char *ThreadVersionToString(uint16_t aThreadVersion)
219 {
220     switch (aThreadVersion)
221     {
222     case kThreadVersion11:
223         return "1.1.1";
224     case kThreadVersion12:
225         return "1.2.0";
226     default:
227         otbrLog(OTBR_LOG_ERR, "unexpected thread version %hu", aThreadVersion);
228         abort();
229     }
230 }
231
232 void BorderAgent::PublishService(void)
233 {
234     assert(mNetworkName[0] != '\0');
235     assert(mExtPanIdInitialized);
236     assert(mExtAddrInitialized);
237     assert(mThreadVersion != 0);
238
239     const char *             versionString = ThreadVersionToString(mThreadVersion);
240     Mdns::Publisher::TxtList txtList{{"nn", mNetworkName},
241                                      {"xp", mExtPanId, sizeof(mExtPanId)},
242                                      {"tv", versionString},
243                                      // "dd" represents for device discriminator which
244                                      // should always be the IEEE 802.15.4 extended address.
245                                      {"dd", mExtAddr, sizeof(mExtAddr)}};
246
247     mPublisher->PublishService(/* aHostName */ nullptr, kBorderAgentUdpPort, mNetworkName, kBorderAgentServiceType,
248                                txtList);
249 }
250
251 void BorderAgent::StartPublishService(void)
252 {
253     VerifyOrExit(mNetworkName[0] != '\0');
254     VerifyOrExit(mExtPanIdInitialized);
255     VerifyOrExit(mExtAddrInitialized);
256     VerifyOrExit(mThreadVersion != 0);
257
258     if (mPublisher->IsStarted())
259     {
260         PublishService();
261     }
262     else
263     {
264         mPublisher->Start();
265     }
266
267 exit:
268     otbrLog(OTBR_LOG_INFO, "Start publishing service");
269 }
270
271 void BorderAgent::StopPublishService(void)
272 {
273     VerifyOrExit(mPublisher != nullptr);
274
275     if (mPublisher->IsStarted())
276     {
277         mPublisher->Stop();
278     }
279
280 exit:
281     otbrLog(OTBR_LOG_INFO, "Stop publishing service");
282 }
283
284 void BorderAgent::SetNetworkName(const char *aNetworkName)
285 {
286     strcpy_safe(mNetworkName, sizeof(mNetworkName), aNetworkName);
287
288 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
289     if (mThreadStarted)
290     {
291         // Restart publisher to publish new service name.
292         mPublisher->Stop();
293         StartPublishService();
294     }
295 #endif
296 }
297
298 void BorderAgent::SetExtPanId(const uint8_t *aExtPanId)
299 {
300     memcpy(mExtPanId, aExtPanId, sizeof(mExtPanId));
301     mExtPanIdInitialized = true;
302 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
303     if (mThreadStarted)
304     {
305         StartPublishService();
306     }
307 #endif
308 }
309
310 void BorderAgent::SetExtAddr(const uint8_t *aExtAddr)
311 {
312     memcpy(mExtAddr, aExtAddr, sizeof(mExtAddr));
313     mExtAddrInitialized = true;
314 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
315     if (mThreadStarted)
316     {
317         StartPublishService();
318     }
319 #endif
320 }
321
322 void BorderAgent::SetThreadVersion(uint16_t aThreadVersion)
323 {
324     mThreadVersion = aThreadVersion;
325 #if OTBR_ENABLE_MDNS_AVAHI || OTBR_ENABLE_MDNS_MDNSSD || OTBR_ENABLE_MDNS_MOJO
326     if (mThreadStarted)
327     {
328         StartPublishService();
329     }
330 #endif
331 }
332
333 void BorderAgent::HandlePSKc(void *aContext, int aEvent, va_list aArguments)
334 {
335     OT_UNUSED_VARIABLE(aEvent);
336
337     assert(aEvent == Ncp::kEventPSKc);
338
339     static_cast<BorderAgent *>(aContext)->HandlePSKc(va_arg(aArguments, const uint8_t *));
340 }
341
342 void BorderAgent::HandlePSKc(const uint8_t *aPSKc)
343 {
344     mPSKcInitialized = false;
345
346     for (size_t i = 0; i < kSizePSKc; ++i)
347     {
348         if (aPSKc[i] != 0)
349         {
350             mPSKcInitialized = true;
351             break;
352         }
353     }
354
355     if (mPSKcInitialized)
356     {
357         Start();
358     }
359     else
360     {
361         Stop();
362     }
363
364     otbrLog(OTBR_LOG_INFO, "PSKc is %s", (mPSKcInitialized ? "initialized" : "not initialized"));
365 }
366
367 void BorderAgent::HandleThreadState(bool aStarted)
368 {
369     VerifyOrExit(mThreadStarted != aStarted);
370
371     mThreadStarted = aStarted;
372
373     if (aStarted)
374     {
375         SuccessOrExit(mNcp->RequestEvent(Ncp::kEventPSKc));
376         Start();
377     }
378     else
379     {
380         Stop();
381     }
382
383 exit:
384     otbrLog(OTBR_LOG_INFO, "Thread is %s", (aStarted ? "up" : "down"));
385 }
386
387 void BorderAgent::HandleThreadState(void *aContext, int aEvent, va_list aArguments)
388 {
389     OT_UNUSED_VARIABLE(aEvent);
390
391     assert(aEvent == Ncp::kEventThreadState);
392
393     int started = va_arg(aArguments, int);
394     static_cast<BorderAgent *>(aContext)->HandleThreadState(started);
395 }
396
397 void BorderAgent::HandleNetworkName(void *aContext, int aEvent, va_list aArguments)
398 {
399     OT_UNUSED_VARIABLE(aEvent);
400
401     assert(aEvent == Ncp::kEventNetworkName);
402
403     const char *networkName = va_arg(aArguments, const char *);
404     static_cast<BorderAgent *>(aContext)->SetNetworkName(networkName);
405 }
406
407 void BorderAgent::HandleExtPanId(void *aContext, int aEvent, va_list aArguments)
408 {
409     OT_UNUSED_VARIABLE(aEvent);
410
411     assert(aEvent == Ncp::kEventExtPanId);
412
413     const uint8_t *xpanid = va_arg(aArguments, const uint8_t *);
414     static_cast<BorderAgent *>(aContext)->SetExtPanId(xpanid);
415 }
416
417 void BorderAgent::HandleThreadVersion(void *aContext, int aEvent, va_list aArguments)
418 {
419     OT_UNUSED_VARIABLE(aEvent);
420
421     assert(aEvent == Ncp::kEventThreadVersion);
422
423     // `uint16_t` has been promoted to `int`.
424     uint16_t threadVersion = static_cast<uint16_t>(va_arg(aArguments, int));
425     static_cast<BorderAgent *>(aContext)->SetThreadVersion(threadVersion);
426 }
427
428 void BorderAgent::HandleExtAddr(void *aContext, int aEvent, va_list aArguments)
429 {
430     OT_UNUSED_VARIABLE(aEvent);
431
432     assert(aEvent == Ncp::kEventExtAddr);
433
434     const uint8_t *extAddr = va_arg(aArguments, const uint8_t *);
435     static_cast<BorderAgent *>(aContext)->SetExtAddr(extAddr);
436 }
437
438 } // namespace otbr