• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2024, 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  *   This file includes definitions for the spinel based Thread controller.
32  */
33 
34 #ifndef OTBR_AGENT_NCP_SPINEL_HPP_
35 #define OTBR_AGENT_NCP_SPINEL_HPP_
36 
37 #include <functional>
38 #include <memory>
39 
40 #include <vector>
41 
42 #include <openthread/dataset.h>
43 #include <openthread/error.h>
44 #include <openthread/link.h>
45 #include <openthread/thread.h>
46 #include <openthread/platform/dnssd.h>
47 
48 #include "lib/spinel/spinel.h"
49 #include "lib/spinel/spinel_buffer.hpp"
50 #include "lib/spinel/spinel_driver.hpp"
51 #include "lib/spinel/spinel_encoder.hpp"
52 
53 #include "common/task_runner.hpp"
54 #include "common/types.hpp"
55 #include "host/async_task.hpp"
56 #include "host/posix/infra_if.hpp"
57 #include "host/posix/netif.hpp"
58 #include "mdns/mdns.hpp"
59 
60 namespace otbr {
61 namespace Host {
62 
63 /**
64  * This interface is an observer to subscribe the network properties from NCP.
65  */
66 class PropsObserver
67 {
68 public:
69     /**
70      * Updates the device role.
71      *
72      * @param[in] aRole  The device role.
73      */
74     virtual void SetDeviceRole(otDeviceRole aRole) = 0;
75 
76     /**
77      * Updates the active dataset.
78      *
79      * @param[in] aActiveOpDatasetTlvs  The active dataset tlvs.
80      */
81     virtual void SetDatasetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs) = 0;
82 
83     /**
84      * The destructor.
85      */
86     virtual ~PropsObserver(void) = default;
87 };
88 
89 /**
90  * The class provides methods for controlling the Thread stack on the network co-processor (NCP).
91  */
92 class NcpSpinel : public Netif::Dependencies, public InfraIf::Dependencies
93 {
94 public:
95     using Ip6AddressTableCallback          = std::function<void(const std::vector<Ip6AddressInfo> &)>;
96     using Ip6MulticastAddressTableCallback = std::function<void(const std::vector<Ip6Address> &)>;
97     using NetifStateChangedCallback        = std::function<void(bool)>;
98     using Ip6ReceiveCallback               = std::function<void(const uint8_t *, uint16_t)>;
99     using InfraIfSendIcmp6NdCallback = std::function<void(uint32_t, const otIp6Address &, const uint8_t *, uint16_t)>;
100 
101     /**
102      * Constructor.
103      */
104     NcpSpinel(void);
105 
106     /**
107      * Do the initialization.
108      *
109      * @param[in]  aSpinelDriver   A reference to the SpinelDriver instance that this object depends.
110      * @param[in]  aObserver       A reference to the Network properties observer.
111      */
112     void Init(ot::Spinel::SpinelDriver &aSpinelDriver, PropsObserver &aObserver);
113 
114     /**
115      * Do the de-initialization.
116      */
117     void Deinit(void);
118 
119     /**
120      * Returns the Co-processor version string.
121      */
GetCoprocessorVersion(void)122     const char *GetCoprocessorVersion(void) { return mSpinelDriver->GetVersion(); }
123 
124     /**
125      * This method sets the active dataset on the NCP.
126      *
127      * If this method is called again before the previous call completed, no action will be taken.
128      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
129      *
130      * @param[in] aActiveOpDatasetTlvs  A reference to the active operational dataset of the Thread network.
131      * @param[in] aAsyncTask            A pointer to an async result to receive the result of this operation.
132      */
133     void DatasetSetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, AsyncTaskPtr aAsyncTask);
134 
135     /**
136      * This method instructs the NCP to send a MGMT_SET to set Thread Pending Operational Dataset.
137      *
138      * If this method is called again before the previous call completed, no action will be taken.
139      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
140      *
141      * @param[in] aPendingOpDatasetTlvsPtr  A shared pointer to the pending operational dataset of the Thread network.
142      * @param[in] aAsyncTask                A pointer to an async result to receive the result of this operation.
143      */
144     void DatasetMgmtSetPending(std::shared_ptr<otOperationalDatasetTlvs> aPendingOpDatasetTlvsPtr,
145                                AsyncTaskPtr                              aAsyncTask);
146 
147     /**
148      * This method enableds/disables the IP6 on the NCP.
149      *
150      * If this method is called again before the previous call completed, no action will be taken.
151      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
152      *
153      * @param[in] aEnable     TRUE to enable and FALSE to disable.
154      * @param[in] aAsyncTask  A pointer to an async result to receive the result of this operation.
155      */
156     void Ip6SetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask);
157 
158     /**
159      * This method sets the callback to receive the IPv6 address table from the NCP.
160      *
161      * The callback will be invoked when receiving an IPv6 address table from the NCP. When the
162      * callback is invoked, the callback MUST copy the otIp6AddressInfo objects and maintain it
163      * if it's not used immediately (within the callback).
164      *
165      * @param[in] aCallback  The callback to handle the IP6 address table.
166      */
Ip6SetAddressCallback(const Ip6AddressTableCallback & aCallback)167     void Ip6SetAddressCallback(const Ip6AddressTableCallback &aCallback) { mIp6AddressTableCallback = aCallback; }
168 
169     /**
170      * This method sets the callback to receive the IPv6 multicast address table from the NCP.
171      *
172      * @param[in] aCallback  The callback to handle the IPv6 address table.
173      *
174      * The callback will be invoked when receiving an IPv6 multicast address table from the NCP.
175      * When the callback is invoked, the callback MUST copy the otIp6Address objects and maintain it
176      * if it's not used immediately (within the callback).
177      */
Ip6SetAddressMulticastCallback(const Ip6MulticastAddressTableCallback & aCallback)178     void Ip6SetAddressMulticastCallback(const Ip6MulticastAddressTableCallback &aCallback)
179     {
180         mIp6MulticastAddressTableCallback = aCallback;
181     }
182 
183     /**
184      * This method sets the callback to receive IP6 datagrams.
185      *
186      * @param[in] aCallback  The callback to receive IP6 datagrams.
187      */
Ip6SetReceiveCallback(const Ip6ReceiveCallback & aCallback)188     void Ip6SetReceiveCallback(const Ip6ReceiveCallback &aCallback) { mIp6ReceiveCallback = aCallback; }
189 
190     /**
191      * This methods sends an IP6 datagram through the NCP.
192      *
193      * @param[in] aData      A pointer to the beginning of the IP6 datagram.
194      * @param[in] aLength    The length of the datagram.
195      *
196      * @retval OTBR_ERROR_NONE  The datagram is sent to NCP successfully.
197      * @retval OTBR_ERROR_BUSY  NcpSpinel is busy with other requests.
198      */
199     otbrError Ip6Send(const uint8_t *aData, uint16_t aLength) override;
200 
201     /**
202      * This method enableds/disables the Thread network on the NCP.
203      *
204      * If this method is called again before the previous call completed, no action will be taken.
205      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
206      *
207      * @param[in] aEnable     TRUE to enable and FALSE to disable.
208      * @param[in] aAsyncTask  A pointer to an async result to receive the result of this operation.
209      */
210     void ThreadSetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask);
211 
212     /**
213      * This method instructs the device to leave the current network gracefully.
214      *
215      * If this method is called again before the previous call completed, no action will be taken.
216      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
217      *
218      * @param[in] aAsyncTask  A pointer to an async result to receive the result of this operation.
219      */
220     void ThreadDetachGracefully(AsyncTaskPtr aAsyncTask);
221 
222     /**
223      * This method instructs the NCP to erase the persistent network info.
224      *
225      * If this method is called again before the previous call completed, no action will be taken.
226      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
227      *
228      * @param[in] aAsyncTask  A pointer to an async result to receive the result of this operation.
229      */
230     void ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask);
231 
232     /**
233      * This method sets the callback invoked when the network interface state changes.
234      *
235      * @param[in] aCallback  The callback invoked when the network interface state changes.
236      */
NetifSetStateChangedCallback(const NetifStateChangedCallback & aCallback)237     void NetifSetStateChangedCallback(const NetifStateChangedCallback &aCallback)
238     {
239         mNetifStateChangedCallback = aCallback;
240     }
241 
242     /**
243      * This method sets the function to send an Icmp6 ND message on the infrastructure link.
244      *
245      * @param[in] aCallback  The callback to send an Icmp6 ND message on the infrastructure link.
246      */
InfraIfSetIcmp6NdSendCallback(const InfraIfSendIcmp6NdCallback & aCallback)247     void InfraIfSetIcmp6NdSendCallback(const InfraIfSendIcmp6NdCallback &aCallback)
248     {
249         mInfraIfIcmp6NdCallback = aCallback;
250     }
251 
252 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
253     /**
254      * This method enables/disables the SRP Server on NCP.
255      *
256      * @param[in] aEnable  A boolean to enable/disable the SRP server.
257      */
258     void SrpServerSetEnabled(bool aEnabled);
259 
260     /**
261      * This method enables/disables the auto-enable mode on SRP Server on NCP.
262      *
263      * @param[in] aEnable  A boolean to enable/disable the SRP server.
264      */
265     void SrpServerSetAutoEnableMode(bool aEnabled);
266 
267     /**
268      * This method sets the dnssd state on NCP.
269      *
270      * @param[in] aState  The dnssd state.
271      */
272     void DnssdSetState(Mdns::Publisher::State aState);
273 
274     /**
275      * This method sets the mDNS Publisher object.
276      *
277      * @param[in] aPublisher  A pointer to the mDNS Publisher object.
278      */
SetMdnsPublisher(otbr::Mdns::Publisher * aPublisher)279     void SetMdnsPublisher(otbr::Mdns::Publisher *aPublisher)
280     {
281         mPublisher = aPublisher;
282     }
283 #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY
284 
285 private:
286     using FailureHandler = std::function<void(otError)>;
287 
288     static constexpr uint8_t  kMaxTids             = 16;
289     static constexpr uint16_t kCallbackDataMaxSize = sizeof(uint64_t); // Maximum size of a function pointer.
290     static constexpr uint16_t kMaxSubTypes         = 8;                // Maximum number of sub types in a MDNS service.
291 
SafeInvoke(Function & aFunc,Args &&...aArgs)292     template <typename Function, typename... Args> static void SafeInvoke(Function &aFunc, Args &&...aArgs)
293     {
294         if (aFunc)
295         {
296             aFunc(std::forward<Args>(aArgs)...);
297         }
298     }
299 
CallAndClear(AsyncTaskPtr & aResult,otError aError,const std::string & aErrorInfo="")300     static void CallAndClear(AsyncTaskPtr &aResult, otError aError, const std::string &aErrorInfo = "")
301     {
302         if (aResult)
303         {
304             aResult->SetResult(aError, aErrorInfo);
305             aResult = nullptr;
306         }
307     }
308 
309     static otbrError SpinelDataUnpack(const uint8_t *aDataIn, spinel_size_t aDataLen, const char *aPackFormat, ...);
310 
311     static void HandleReceivedFrame(const uint8_t *aFrame,
312                                     uint16_t       aLength,
313                                     uint8_t        aHeader,
314                                     bool          &aSave,
315                                     void          *aContext);
316     void        HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame);
317     static void HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext);
318 
319     static otDeviceRole SpinelRoleToDeviceRole(spinel_net_role_t aRole);
320 
321     void      HandleNotification(const uint8_t *aFrame, uint16_t aLength);
322     void      HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_t aLength);
323     void      HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
324     void      HandleValueInserted(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
325     void      HandleValueRemoved(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
326     otbrError HandleResponseForPropSet(spinel_tid_t      aTid,
327                                        spinel_prop_key_t aKey,
328                                        const uint8_t    *aData,
329                                        uint16_t          aLength);
330     otbrError HandleResponseForPropInsert(spinel_tid_t      aTid,
331                                           spinel_command_t  aCmd,
332                                           spinel_prop_key_t aKey,
333                                           const uint8_t    *aData,
334                                           uint16_t          aLength);
335     otbrError HandleResponseForPropRemove(spinel_tid_t      aTid,
336                                           spinel_command_t  aCmd,
337                                           spinel_prop_key_t aKey,
338                                           const uint8_t    *aData,
339                                           uint16_t          aLength);
340 
341     otbrError Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdded) override;
342 
343     spinel_tid_t GetNextTid(void);
344     void         FreeTidTableItem(spinel_tid_t aTid);
345 
346     using EncodingFunc = std::function<otError(ot::Spinel::Encoder &aEncoder)>;
347     otError SendCommand(spinel_command_t aCmd, spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc);
348     otError SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc);
349     otError InsertProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc);
350     otError RemoveProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc);
351 
352     otError SendEncodedFrame(void);
353 
354     otError ParseIp6AddressTable(const uint8_t *aBuf, uint16_t aLength, std::vector<Ip6AddressInfo> &aAddressTable);
355     otError ParseIp6MulticastAddresses(const uint8_t *aBuf, uint16_t aLen, std::vector<Ip6Address> &aAddressList);
356     otError ParseIp6StreamNet(const uint8_t *aBuf, uint16_t aLen, const uint8_t *&aData, uint16_t &aDataLen);
357     otError ParseOperationalDatasetTlvs(const uint8_t *aBuf, uint16_t aLen, otOperationalDatasetTlvs &aDatasetTlvs);
358     otError ParseInfraIfIcmp6Nd(const uint8_t       *aBuf,
359                                 uint8_t              aLen,
360                                 uint32_t            &aInfraIfIndex,
361                                 const otIp6Address *&aAddr,
362                                 const uint8_t      *&aData,
363                                 uint16_t            &aDataLen);
364     otError SendDnssdResult(otPlatDnssdRequestId aRequestId, const std::vector<uint8_t> &aCallbackData, otError aError);
365 
366     otbrError SetInfraIf(uint32_t                       aInfraIfIndex,
367                          bool                           aIsRunning,
368                          const std::vector<Ip6Address> &aIp6Addresses) override;
369     otbrError HandleIcmp6Nd(uint32_t          aInfraIfIndex,
370                             const Ip6Address &aIp6Address,
371                             const uint8_t    *aData,
372                             uint16_t          aDataLen) override;
373 
374     ot::Spinel::SpinelDriver *mSpinelDriver;
375     uint16_t                  mCmdTidsInUse; ///< Used transaction ids.
376     spinel_tid_t              mCmdNextTid;   ///< Next available transaction id.
377 
378     spinel_prop_key_t mWaitingKeyTable[kMaxTids]; ///< The property keys of ongoing transactions.
379     spinel_command_t  mCmdTable[kMaxTids];        ///< The mapping of spinel command and tids when the response
380                                                   ///< is LAST_STATUS.
381 
382     static constexpr uint16_t kTxBufferSize = 2048;
383     uint8_t                   mTxBuffer[kTxBufferSize];
384     ot::Spinel::Buffer        mNcpBuffer;
385     ot::Spinel::Encoder       mEncoder;
386     spinel_iid_t              mIid; /// < Interface Id used to in Spinel header
387 
388     TaskRunner mTaskRunner;
389 
390     PropsObserver *mPropsObserver;
391 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
392     otbr::Mdns::Publisher *mPublisher;
393 #endif
394 
395     AsyncTaskPtr mDatasetSetActiveTask;
396     AsyncTaskPtr mDatasetMgmtSetPendingTask;
397     AsyncTaskPtr mIp6SetEnabledTask;
398     AsyncTaskPtr mThreadSetEnabledTask;
399     AsyncTaskPtr mThreadDetachGracefullyTask;
400     AsyncTaskPtr mThreadErasePersistentInfoTask;
401 
402     Ip6AddressTableCallback          mIp6AddressTableCallback;
403     Ip6MulticastAddressTableCallback mIp6MulticastAddressTableCallback;
404     Ip6ReceiveCallback               mIp6ReceiveCallback;
405     NetifStateChangedCallback        mNetifStateChangedCallback;
406     InfraIfSendIcmp6NdCallback       mInfraIfIcmp6NdCallback;
407 };
408 
409 } // namespace Host
410 } // namespace otbr
411 
412 #endif // OTBR_AGENT_NCP_SPINEL_HPP_
413