xref: /aosp_15_r20/external/ot-br-posix/src/ncp/ncp_spinel.hpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
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 <openthread/dataset.h>
41 #include <openthread/error.h>
42 #include <openthread/link.h>
43 #include <openthread/thread.h>
44 
45 #include "lib/spinel/spinel.h"
46 #include "lib/spinel/spinel_buffer.hpp"
47 #include "lib/spinel/spinel_driver.hpp"
48 #include "lib/spinel/spinel_encoder.hpp"
49 
50 #include "common/task_runner.hpp"
51 #include "common/types.hpp"
52 #include "ncp/async_task.hpp"
53 
54 namespace otbr {
55 namespace Ncp {
56 
57 /**
58  * This interface is an observer to subscribe the network properties from NCP.
59  */
60 class PropsObserver
61 {
62 public:
63     /**
64      * Updates the device role.
65      *
66      * @param[in] aRole  The device role.
67      */
68     virtual void SetDeviceRole(otDeviceRole aRole) = 0;
69 
70     /**
71      * Updates the active dataset.
72      *
73      * @param[in] aActiveOpDatasetTlvs  The active dataset tlvs.
74      */
75     virtual void SetDatasetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs) = 0;
76 
77     /**
78      * The destructor.
79      */
80     virtual ~PropsObserver(void) = default;
81 };
82 
83 /**
84  * The class provides methods for controlling the Thread stack on the network co-processor (NCP).
85  */
86 class NcpSpinel
87 {
88 public:
89     using Ip6AddressTableCallback          = std::function<void(const std::vector<Ip6AddressInfo> &)>;
90     using Ip6MulticastAddressTableCallback = std::function<void(const std::vector<Ip6Address> &)>;
91     using NetifStateChangedCallback        = std::function<void(bool)>;
92 
93     /**
94      * Constructor.
95      */
96     NcpSpinel(void);
97 
98     /**
99      * Do the initialization.
100      *
101      * @param[in]  aSpinelDriver   A reference to the SpinelDriver instance that this object depends.
102      * @param[in]  aObserver       A reference to the Network properties observer.
103      */
104     void Init(ot::Spinel::SpinelDriver &aSpinelDriver, PropsObserver &aObserver);
105 
106     /**
107      * Do the de-initialization.
108      */
109     void Deinit(void);
110 
111     /**
112      * Returns the Co-processor version string.
113      */
GetCoprocessorVersion(void)114     const char *GetCoprocessorVersion(void) { return mSpinelDriver->GetVersion(); }
115 
116     /**
117      * This method sets the active dataset on the NCP.
118      *
119      * If this method is called again before the previous call completed, no action will be taken.
120      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
121      *
122      * @param[in] aActiveOpDatasetTlvs  A reference to the active operational dataset of the Thread network.
123      * @param[in] aAsyncTask            A pointer to an async result to receive the result of this operation.
124      */
125     void DatasetSetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, AsyncTaskPtr aAsyncTask);
126 
127     /**
128      * This method instructs the NCP to send a MGMT_SET to set Thread Pending Operational Dataset.
129      *
130      * If this method is called again before the previous call completed, no action will be taken.
131      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
132      *
133      * @param[in] aPendingOpDatasetTlvsPtr  A shared pointer to the pending operational dataset of the Thread network.
134      * @param[in] aAsyncTask                A pointer to an async result to receive the result of this operation.
135      */
136     void DatasetMgmtSetPending(std::shared_ptr<otOperationalDatasetTlvs> aPendingOpDatasetTlvsPtr,
137                                AsyncTaskPtr                              aAsyncTask);
138 
139     /**
140      * This method enableds/disables the IP6 on the NCP.
141      *
142      * If this method is called again before the previous call completed, no action will be taken.
143      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
144      *
145      * @param[in] aEnable     TRUE to enable and FALSE to disable.
146      * @param[in] aAsyncTask  A pointer to an async result to receive the result of this operation.
147      */
148     void Ip6SetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask);
149 
150     /**
151      * This method sets the callback to receive the IPv6 address table from the NCP.
152      *
153      * The callback will be invoked when receiving an IPv6 address table from the NCP. When the
154      * callback is invoked, the callback MUST copy the otIp6AddressInfo objects and maintain it
155      * if it's not used immediately (within the callback).
156      *
157      * @param[in] aCallback  The callback to handle the IP6 address table.
158      */
Ip6SetAddressCallback(const Ip6AddressTableCallback & aCallback)159     void Ip6SetAddressCallback(const Ip6AddressTableCallback &aCallback) { mIp6AddressTableCallback = aCallback; }
160 
161     /**
162      * This method sets the callback to receive the IPv6 multicast address table from the NCP.
163      *
164      * @param[in] aCallback  The callback to handle the IPv6 address table.
165      *
166      * The callback will be invoked when receiving an IPv6 multicast address table from the NCP.
167      * When the callback is invoked, the callback MUST copy the otIp6Address objects and maintain it
168      * if it's not used immediately (within the callback).
169      */
Ip6SetAddressMulticastCallback(const Ip6MulticastAddressTableCallback & aCallback)170     void Ip6SetAddressMulticastCallback(const Ip6MulticastAddressTableCallback &aCallback)
171     {
172         mIp6MulticastAddressTableCallback = aCallback;
173     }
174 
175     /**
176      * This methods sends an IP6 datagram through the NCP.
177      *
178      * @param[in] aData      A pointer to the beginning of the IP6 datagram.
179      * @param[in] aLength    The length of the datagram.
180      *
181      * @retval OTBR_ERROR_NONE  The datagram is sent to NCP successfully.
182      * @retval OTBR_ERROR_BUSY  NcpSpinel is busy with other requests.
183      */
184     otbrError Ip6Send(const uint8_t *aData, uint16_t aLength);
185 
186     /**
187      * This method enableds/disables the Thread network on the NCP.
188      *
189      * If this method is called again before the previous call completed, no action will be taken.
190      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
191      *
192      * @param[in] aEnable     TRUE to enable and FALSE to disable.
193      * @param[in] aAsyncTask  A pointer to an async result to receive the result of this operation.
194      */
195     void ThreadSetEnabled(bool aEnable, AsyncTaskPtr aAsyncTask);
196 
197     /**
198      * This method instructs the device to leave the current network gracefully.
199      *
200      * If this method is called again before the previous call completed, no action will be taken.
201      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
202      *
203      * @param[in] aAsyncTask  A pointer to an async result to receive the result of this operation.
204      */
205     void ThreadDetachGracefully(AsyncTaskPtr aAsyncTask);
206 
207     /**
208      * This method instructs the NCP to erase the persistent network info.
209      *
210      * If this method is called again before the previous call completed, no action will be taken.
211      * The new receiver @p aAsyncTask will be set a result OT_ERROR_BUSY.
212      *
213      * @param[in] aAsyncTask  A pointer to an async result to receive the result of this operation.
214      */
215     void ThreadErasePersistentInfo(AsyncTaskPtr aAsyncTask);
216 
217     /**
218      * This method sets the callback invoked when the network interface state changes.
219      *
220      * @param[in] aCallback  The callback invoked when the network interface state changes.
221      */
NetifSetStateChangedCallback(const NetifStateChangedCallback & aCallback)222     void NetifSetStateChangedCallback(const NetifStateChangedCallback &aCallback)
223     {
224         mNetifStateChangedCallback = aCallback;
225     }
226 
227 private:
228     using FailureHandler = std::function<void(otError)>;
229 
230     static constexpr uint8_t kMaxTids = 16;
231 
SafeInvoke(Function & aFunc,Args &&...aArgs)232     template <typename Function, typename... Args> static void SafeInvoke(Function &aFunc, Args &&...aArgs)
233     {
234         if (aFunc)
235         {
236             aFunc(std::forward<Args>(aArgs)...);
237         }
238     }
239 
CallAndClear(AsyncTaskPtr & aResult,otError aError,const std::string & aErrorInfo="")240     static void CallAndClear(AsyncTaskPtr &aResult, otError aError, const std::string &aErrorInfo = "")
241     {
242         if (aResult)
243         {
244             aResult->SetResult(aError, aErrorInfo);
245             aResult = nullptr;
246         }
247     }
248 
249     static otbrError SpinelDataUnpack(const uint8_t *aDataIn, spinel_size_t aDataLen, const char *aPackFormat, ...);
250 
251     static void HandleReceivedFrame(const uint8_t *aFrame,
252                                     uint16_t       aLength,
253                                     uint8_t        aHeader,
254                                     bool          &aSave,
255                                     void          *aContext);
256     void        HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame);
257     static void HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext);
258 
259     static otDeviceRole SpinelRoleToDeviceRole(spinel_net_role_t aRole);
260 
261     void      HandleNotification(const uint8_t *aFrame, uint16_t aLength);
262     void      HandleResponse(spinel_tid_t aTid, const uint8_t *aFrame, uint16_t aLength);
263     void      HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
264     otbrError HandleResponseForPropSet(spinel_tid_t      aTid,
265                                        spinel_prop_key_t aKey,
266                                        const uint8_t    *aData,
267                                        uint16_t          aLength);
268 
269     spinel_tid_t GetNextTid(void);
270     void         FreeTidTableItem(spinel_tid_t aTid);
271 
272     using EncodingFunc = std::function<otError(void)>;
273     otError SetProperty(spinel_prop_key_t aKey, const EncodingFunc &aEncodingFunc);
274     otError SendEncodedFrame(void);
275 
276     otError ParseIp6AddressTable(const uint8_t *aBuf, uint16_t aLength, std::vector<Ip6AddressInfo> &aAddressTable);
277     otError ParseIp6MulticastAddresses(const uint8_t *aBuf, uint8_t aLen, std::vector<Ip6Address> &aAddressList);
278     otError ParseIp6StreamNet(const uint8_t *aBuf, uint8_t aLen, const uint8_t *&aData, uint16_t &aDataLen);
279     otError ParseOperationalDatasetTlvs(const uint8_t *aBuf, uint8_t aLen, otOperationalDatasetTlvs &aDatasetTlvs);
280 
281     ot::Spinel::SpinelDriver *mSpinelDriver;
282     uint16_t                  mCmdTidsInUse; ///< Used transaction ids.
283     spinel_tid_t              mCmdNextTid;   ///< Next available transaction id.
284 
285     spinel_prop_key_t mWaitingKeyTable[kMaxTids]; ///< The property keys of ongoing transactions.
286     spinel_command_t  mCmdTable[kMaxTids];        ///< The mapping of spinel command and tids when the response
287                                                   ///< is LAST_STATUS.
288 
289     static constexpr uint16_t kTxBufferSize = 2048;
290     uint8_t                   mTxBuffer[kTxBufferSize];
291     ot::Spinel::Buffer        mNcpBuffer;
292     ot::Spinel::Encoder       mEncoder;
293     spinel_iid_t              mIid; /// < Interface Id used to in Spinel header
294 
295     TaskRunner mTaskRunner;
296 
297     PropsObserver *mPropsObserver;
298 
299     AsyncTaskPtr mDatasetSetActiveTask;
300     AsyncTaskPtr mDatasetMgmtSetPendingTask;
301     AsyncTaskPtr mIp6SetEnabledTask;
302     AsyncTaskPtr mThreadSetEnabledTask;
303     AsyncTaskPtr mThreadDetachGracefullyTask;
304     AsyncTaskPtr mThreadErasePersistentInfoTask;
305 
306     Ip6AddressTableCallback          mIp6AddressTableCallback;
307     Ip6MulticastAddressTableCallback mIp6MulticastAddressTableCallback;
308     NetifStateChangedCallback        mNetifStateChangedCallback;
309 };
310 
311 } // namespace Ncp
312 } // namespace otbr
313 
314 #endif // OTBR_AGENT_NCP_SPINEL_HPP_
315