xref: /aosp_15_r20/external/ot-br-posix/src/ncp/ncp_host.cpp (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 #define OTBR_LOG_TAG "NCP_HOST"
30 
31 #include "ncp_host.hpp"
32 
33 #include <memory>
34 
35 #include <openthread/error.h>
36 #include <openthread/thread.h>
37 
38 #include <openthread/openthread-system.h>
39 
40 #include "lib/spinel/spinel_driver.hpp"
41 
42 #include "ncp/async_task.hpp"
43 
44 namespace otbr {
45 namespace Ncp {
46 
47 // =============================== NcpNetworkProperties ===============================
48 
NcpNetworkProperties(void)49 NcpNetworkProperties::NcpNetworkProperties(void)
50     : mDeviceRole(OT_DEVICE_ROLE_DISABLED)
51 {
52     memset(&mDatasetActiveTlvs, 0, sizeof(mDatasetActiveTlvs));
53 }
54 
GetDeviceRole(void) const55 otDeviceRole NcpNetworkProperties::GetDeviceRole(void) const
56 {
57     return mDeviceRole;
58 }
59 
SetDeviceRole(otDeviceRole aRole)60 void NcpNetworkProperties::SetDeviceRole(otDeviceRole aRole)
61 {
62     mDeviceRole = aRole;
63 }
64 
Ip6IsEnabled(void) const65 bool NcpNetworkProperties::Ip6IsEnabled(void) const
66 {
67     // TODO: Implement the method under NCP mode.
68     return false;
69 }
70 
GetPartitionId(void) const71 uint32_t NcpNetworkProperties::GetPartitionId(void) const
72 {
73     // TODO: Implement the method under NCP mode.
74     return 0;
75 }
76 
SetDatasetActiveTlvs(const otOperationalDatasetTlvs & aActiveOpDatasetTlvs)77 void NcpNetworkProperties::SetDatasetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs)
78 {
79     mDatasetActiveTlvs.mLength = aActiveOpDatasetTlvs.mLength;
80     memcpy(mDatasetActiveTlvs.mTlvs, aActiveOpDatasetTlvs.mTlvs, aActiveOpDatasetTlvs.mLength);
81 }
82 
GetDatasetActiveTlvs(otOperationalDatasetTlvs & aDatasetTlvs) const83 void NcpNetworkProperties::GetDatasetActiveTlvs(otOperationalDatasetTlvs &aDatasetTlvs) const
84 {
85     aDatasetTlvs.mLength = mDatasetActiveTlvs.mLength;
86     memcpy(aDatasetTlvs.mTlvs, mDatasetActiveTlvs.mTlvs, mDatasetActiveTlvs.mLength);
87 }
88 
GetDatasetPendingTlvs(otOperationalDatasetTlvs & aDatasetTlvs) const89 void NcpNetworkProperties::GetDatasetPendingTlvs(otOperationalDatasetTlvs &aDatasetTlvs) const
90 {
91     // TODO: Implement the method under NCP mode.
92     OTBR_UNUSED_VARIABLE(aDatasetTlvs);
93 }
94 
95 // ===================================== NcpHost ======================================
96 
NcpHost(const char * aInterfaceName,bool aDryRun)97 NcpHost::NcpHost(const char *aInterfaceName, bool aDryRun)
98     : mSpinelDriver(*static_cast<ot::Spinel::SpinelDriver *>(otSysGetSpinelDriver()))
99     , mNetif()
100 {
101     memset(&mConfig, 0, sizeof(mConfig));
102     mConfig.mInterfaceName = aInterfaceName;
103     mConfig.mDryRun        = aDryRun;
104     mConfig.mSpeedUpFactor = 1;
105 }
106 
GetCoprocessorVersion(void)107 const char *NcpHost::GetCoprocessorVersion(void)
108 {
109     return mSpinelDriver.GetVersion();
110 }
111 
Init(void)112 void NcpHost::Init(void)
113 {
114     otSysInit(&mConfig);
115     mNcpSpinel.Init(mSpinelDriver, *this);
116     mNetif.Init(mConfig.mInterfaceName,
117                 [this](const uint8_t *aData, uint16_t aLength) { return mNcpSpinel.Ip6Send(aData, aLength); });
118 
119     mNcpSpinel.Ip6SetAddressCallback(
120         [this](const std::vector<Ip6AddressInfo> &aAddrInfos) { mNetif.UpdateIp6UnicastAddresses(aAddrInfos); });
121     mNcpSpinel.Ip6SetAddressMulticastCallback(
122         [this](const std::vector<Ip6Address> &aAddrs) { mNetif.UpdateIp6MulticastAddresses(aAddrs); });
123     mNcpSpinel.NetifSetStateChangedCallback([this](bool aState) { mNetif.SetNetifState(aState); });
124 }
125 
Deinit(void)126 void NcpHost::Deinit(void)
127 {
128     mNcpSpinel.Deinit();
129     mNetif.Deinit();
130     otSysDeinit();
131 }
132 
Join(const otOperationalDatasetTlvs & aActiveOpDatasetTlvs,const AsyncResultReceiver & aReceiver)133 void NcpHost::Join(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, const AsyncResultReceiver &aReceiver)
134 {
135     AsyncTaskPtr task;
136     auto errorHandler = [aReceiver](otError aError, const std::string &aErrorInfo) { aReceiver(aError, aErrorInfo); };
137 
138     task = std::make_shared<AsyncTask>(errorHandler);
139     task->First([this, aActiveOpDatasetTlvs](AsyncTaskPtr aNext) {
140             mNcpSpinel.DatasetSetActiveTlvs(aActiveOpDatasetTlvs, std::move(aNext));
141         })
142         ->Then([this](AsyncTaskPtr aNext) { mNcpSpinel.Ip6SetEnabled(true, std::move(aNext)); })
143         ->Then([this](AsyncTaskPtr aNext) { mNcpSpinel.ThreadSetEnabled(true, std::move(aNext)); });
144     task->Run();
145 }
146 
Leave(const AsyncResultReceiver & aReceiver)147 void NcpHost::Leave(const AsyncResultReceiver &aReceiver)
148 {
149     AsyncTaskPtr task;
150     auto errorHandler = [aReceiver](otError aError, const std::string &aErrorInfo) { aReceiver(aError, aErrorInfo); };
151 
152     task = std::make_shared<AsyncTask>(errorHandler);
153     task->First([this](AsyncTaskPtr aNext) { mNcpSpinel.ThreadDetachGracefully(std::move(aNext)); })
154         ->Then([this](AsyncTaskPtr aNext) { mNcpSpinel.ThreadErasePersistentInfo(std::move(aNext)); });
155     task->Run();
156 }
157 
ScheduleMigration(const otOperationalDatasetTlvs & aPendingOpDatasetTlvs,const AsyncResultReceiver aReceiver)158 void NcpHost::ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatasetTlvs,
159                                 const AsyncResultReceiver       aReceiver)
160 {
161     otDeviceRole role  = GetDeviceRole();
162     otError      error = OT_ERROR_NONE;
163     auto errorHandler  = [aReceiver](otError aError, const std::string &aErrorInfo) { aReceiver(aError, aErrorInfo); };
164 
165     VerifyOrExit(role != OT_DEVICE_ROLE_DISABLED && role != OT_DEVICE_ROLE_DETACHED, error = OT_ERROR_INVALID_STATE);
166 
167     mNcpSpinel.DatasetMgmtSetPending(std::make_shared<otOperationalDatasetTlvs>(aPendingOpDatasetTlvs),
168                                      std::make_shared<AsyncTask>(errorHandler));
169 
170 exit:
171     if (error != OT_ERROR_NONE)
172     {
173         mTaskRunner.Post(
174             [aReceiver, error](void) { aReceiver(error, "Cannot schedule migration when this device is detached"); });
175     }
176 }
177 
SetThreadEnabled(bool aEnabled,const AsyncResultReceiver aReceiver)178 void NcpHost::SetThreadEnabled(bool aEnabled, const AsyncResultReceiver aReceiver)
179 {
180     OT_UNUSED_VARIABLE(aEnabled);
181 
182     // TODO: Implement SetThreadEnabled under NCP mode.
183     mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
184 }
185 
SetCountryCode(const std::string & aCountryCode,const AsyncResultReceiver & aReceiver)186 void NcpHost::SetCountryCode(const std::string &aCountryCode, const AsyncResultReceiver &aReceiver)
187 {
188     OT_UNUSED_VARIABLE(aCountryCode);
189 
190     // TODO: Implement SetCountryCode under NCP mode.
191     mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
192 }
193 
GetChannelMasks(const ChannelMasksReceiver & aReceiver,const AsyncResultReceiver & aErrReceiver)194 void NcpHost::GetChannelMasks(const ChannelMasksReceiver &aReceiver, const AsyncResultReceiver &aErrReceiver)
195 {
196     OT_UNUSED_VARIABLE(aReceiver);
197 
198     // TODO: Implement GetChannelMasks under NCP mode.
199     mTaskRunner.Post([aErrReceiver](void) { aErrReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
200 }
201 
SetChannelMaxPowers(const std::vector<ChannelMaxPower> & aChannelMaxPowers,const AsyncResultReceiver & aReceiver)202 void NcpHost::SetChannelMaxPowers(const std::vector<ChannelMaxPower> &aChannelMaxPowers,
203                                   const AsyncResultReceiver          &aReceiver)
204 {
205     OT_UNUSED_VARIABLE(aChannelMaxPowers);
206 
207     // TODO: Implement SetChannelMaxPowers under NCP mode.
208     mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
209 }
210 
AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)211 void NcpHost::AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)
212 {
213     // TODO: Implement AddThreadStateChangedCallback under NCP mode.
214     OT_UNUSED_VARIABLE(aCallback);
215 }
216 
Process(const MainloopContext & aMainloop)217 void NcpHost::Process(const MainloopContext &aMainloop)
218 {
219     mSpinelDriver.Process(&aMainloop);
220 }
221 
Update(MainloopContext & aMainloop)222 void NcpHost::Update(MainloopContext &aMainloop)
223 {
224     mSpinelDriver.GetSpinelInterface()->UpdateFdSet(&aMainloop);
225 
226     if (mSpinelDriver.HasPendingFrame())
227     {
228         aMainloop.mTimeout.tv_sec  = 0;
229         aMainloop.mTimeout.tv_usec = 0;
230     }
231 }
232 
233 } // namespace Ncp
234 } // namespace otbr
235