• 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 #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 "host/async_task.hpp"
41 #include "lib/spinel/spinel_driver.hpp"
42 
43 namespace otbr {
44 namespace Host {
45 
46 // =============================== NcpNetworkProperties ===============================
47 
NcpNetworkProperties(void)48 NcpNetworkProperties::NcpNetworkProperties(void)
49     : mDeviceRole(OT_DEVICE_ROLE_DISABLED)
50 {
51     memset(&mDatasetActiveTlvs, 0, sizeof(mDatasetActiveTlvs));
52 }
53 
GetDeviceRole(void) const54 otDeviceRole NcpNetworkProperties::GetDeviceRole(void) const
55 {
56     return mDeviceRole;
57 }
58 
SetDeviceRole(otDeviceRole aRole)59 void NcpNetworkProperties::SetDeviceRole(otDeviceRole aRole)
60 {
61     mDeviceRole = aRole;
62 }
63 
Ip6IsEnabled(void) const64 bool NcpNetworkProperties::Ip6IsEnabled(void) const
65 {
66     // TODO: Implement the method under NCP mode.
67     return false;
68 }
69 
GetPartitionId(void) const70 uint32_t NcpNetworkProperties::GetPartitionId(void) const
71 {
72     // TODO: Implement the method under NCP mode.
73     return 0;
74 }
75 
SetDatasetActiveTlvs(const otOperationalDatasetTlvs & aActiveOpDatasetTlvs)76 void NcpNetworkProperties::SetDatasetActiveTlvs(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs)
77 {
78     mDatasetActiveTlvs.mLength = aActiveOpDatasetTlvs.mLength;
79     memcpy(mDatasetActiveTlvs.mTlvs, aActiveOpDatasetTlvs.mTlvs, aActiveOpDatasetTlvs.mLength);
80 }
81 
GetDatasetActiveTlvs(otOperationalDatasetTlvs & aDatasetTlvs) const82 void NcpNetworkProperties::GetDatasetActiveTlvs(otOperationalDatasetTlvs &aDatasetTlvs) const
83 {
84     aDatasetTlvs.mLength = mDatasetActiveTlvs.mLength;
85     memcpy(aDatasetTlvs.mTlvs, mDatasetActiveTlvs.mTlvs, mDatasetActiveTlvs.mLength);
86 }
87 
GetDatasetPendingTlvs(otOperationalDatasetTlvs & aDatasetTlvs) const88 void NcpNetworkProperties::GetDatasetPendingTlvs(otOperationalDatasetTlvs &aDatasetTlvs) const
89 {
90     // TODO: Implement the method under NCP mode.
91     OTBR_UNUSED_VARIABLE(aDatasetTlvs);
92 }
93 
94 // ===================================== NcpHost ======================================
95 
NcpHost(const char * aInterfaceName,const char * aBackboneInterfaceName,bool aDryRun)96 NcpHost::NcpHost(const char *aInterfaceName, const char *aBackboneInterfaceName, bool aDryRun)
97     : mSpinelDriver(*static_cast<ot::Spinel::SpinelDriver *>(otSysGetSpinelDriver()))
98     , mNetif(mNcpSpinel)
99     , mInfraIf(mNcpSpinel)
100 {
101     memset(&mConfig, 0, sizeof(mConfig));
102     mConfig.mInterfaceName         = aInterfaceName;
103     mConfig.mBackboneInterfaceName = aBackboneInterfaceName;
104     mConfig.mDryRun                = aDryRun;
105     mConfig.mSpeedUpFactor         = 1;
106 }
107 
GetCoprocessorVersion(void)108 const char *NcpHost::GetCoprocessorVersion(void)
109 {
110     return mSpinelDriver.GetVersion();
111 }
112 
Init(void)113 void NcpHost::Init(void)
114 {
115     otSysInit(&mConfig);
116     mNcpSpinel.Init(mSpinelDriver, *this);
117     mNetif.Init(mConfig.mInterfaceName);
118     mInfraIf.Init();
119 
120     mNcpSpinel.Ip6SetAddressCallback(
121         [this](const std::vector<Ip6AddressInfo> &aAddrInfos) { mNetif.UpdateIp6UnicastAddresses(aAddrInfos); });
122     mNcpSpinel.Ip6SetAddressMulticastCallback(
123         [this](const std::vector<Ip6Address> &aAddrs) { mNetif.UpdateIp6MulticastAddresses(aAddrs); });
124     mNcpSpinel.NetifSetStateChangedCallback([this](bool aState) { mNetif.SetNetifState(aState); });
125     mNcpSpinel.Ip6SetReceiveCallback(
126         [this](const uint8_t *aData, uint16_t aLength) { mNetif.Ip6Receive(aData, aLength); });
127     mNcpSpinel.InfraIfSetIcmp6NdSendCallback(
128         [this](uint32_t aInfraIfIndex, const otIp6Address &aAddr, const uint8_t *aData, uint16_t aDataLen) {
129             OTBR_UNUSED_VARIABLE(mInfraIf.SendIcmp6Nd(aInfraIfIndex, aAddr, aData, aDataLen));
130         });
131 
132     if (mConfig.mBackboneInterfaceName != nullptr && strlen(mConfig.mBackboneInterfaceName) > 0)
133     {
134         mInfraIf.SetInfraIf(mConfig.mBackboneInterfaceName);
135     }
136 
137 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
138 #if OTBR_ENABLE_SRP_SERVER_AUTO_ENABLE_MODE
139     // Let SRP server use auto-enable mode. The auto-enable mode delegates the control of SRP server to the Border
140     // Routing Manager. SRP server automatically starts when bi-directional connectivity is ready.
141     mNcpSpinel.SrpServerSetAutoEnableMode(/* aEnabled */ true);
142 #else
143     mNcpSpinel.SrpServerSetEnabled(/* aEnabled */ true);
144 #endif
145 #endif
146 }
147 
Deinit(void)148 void NcpHost::Deinit(void)
149 {
150     mNcpSpinel.Deinit();
151     mNetif.Deinit();
152     otSysDeinit();
153 }
154 
Join(const otOperationalDatasetTlvs & aActiveOpDatasetTlvs,const AsyncResultReceiver & aReceiver)155 void NcpHost::Join(const otOperationalDatasetTlvs &aActiveOpDatasetTlvs, const AsyncResultReceiver &aReceiver)
156 {
157     AsyncTaskPtr task;
158     auto errorHandler = [aReceiver](otError aError, const std::string &aErrorInfo) { aReceiver(aError, aErrorInfo); };
159 
160     task = std::make_shared<AsyncTask>(errorHandler);
161     task->First([this, aActiveOpDatasetTlvs](AsyncTaskPtr aNext) {
162             mNcpSpinel.DatasetSetActiveTlvs(aActiveOpDatasetTlvs, std::move(aNext));
163         })
164         ->Then([this](AsyncTaskPtr aNext) { mNcpSpinel.Ip6SetEnabled(true, std::move(aNext)); })
165         ->Then([this](AsyncTaskPtr aNext) { mNcpSpinel.ThreadSetEnabled(true, std::move(aNext)); });
166     task->Run();
167 }
168 
Leave(bool aEraseDataset,const AsyncResultReceiver & aReceiver)169 void NcpHost::Leave(bool aEraseDataset, const AsyncResultReceiver &aReceiver)
170 {
171     AsyncTaskPtr task;
172     auto errorHandler = [aReceiver](otError aError, const std::string &aErrorInfo) { aReceiver(aError, aErrorInfo); };
173 
174     task = std::make_shared<AsyncTask>(errorHandler);
175     task->First([this](AsyncTaskPtr aNext) { mNcpSpinel.ThreadDetachGracefully(std::move(aNext)); })
176         ->Then([this, aEraseDataset](AsyncTaskPtr aNext) {
177             if (aEraseDataset)
178             {
179                 mNcpSpinel.ThreadErasePersistentInfo(std::move(aNext));
180             }
181             else
182             {
183                 aNext->SetResult(OT_ERROR_NONE, "");
184             }
185         });
186     task->Run();
187 }
188 
ScheduleMigration(const otOperationalDatasetTlvs & aPendingOpDatasetTlvs,const AsyncResultReceiver aReceiver)189 void NcpHost::ScheduleMigration(const otOperationalDatasetTlvs &aPendingOpDatasetTlvs,
190                                 const AsyncResultReceiver       aReceiver)
191 {
192     otDeviceRole role  = GetDeviceRole();
193     otError      error = OT_ERROR_NONE;
194     auto errorHandler  = [aReceiver](otError aError, const std::string &aErrorInfo) { aReceiver(aError, aErrorInfo); };
195 
196     VerifyOrExit(role != OT_DEVICE_ROLE_DISABLED && role != OT_DEVICE_ROLE_DETACHED, error = OT_ERROR_INVALID_STATE);
197 
198     mNcpSpinel.DatasetMgmtSetPending(std::make_shared<otOperationalDatasetTlvs>(aPendingOpDatasetTlvs),
199                                      std::make_shared<AsyncTask>(errorHandler));
200 
201 exit:
202     if (error != OT_ERROR_NONE)
203     {
204         mTaskRunner.Post(
205             [aReceiver, error](void) { aReceiver(error, "Cannot schedule migration when this device is detached"); });
206     }
207 }
208 
SetThreadEnabled(bool aEnabled,const AsyncResultReceiver aReceiver)209 void NcpHost::SetThreadEnabled(bool aEnabled, const AsyncResultReceiver aReceiver)
210 {
211     OT_UNUSED_VARIABLE(aEnabled);
212 
213     // TODO: Implement SetThreadEnabled under NCP mode.
214     mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
215 }
216 
SetCountryCode(const std::string & aCountryCode,const AsyncResultReceiver & aReceiver)217 void NcpHost::SetCountryCode(const std::string &aCountryCode, const AsyncResultReceiver &aReceiver)
218 {
219     OT_UNUSED_VARIABLE(aCountryCode);
220 
221     // TODO: Implement SetCountryCode under NCP mode.
222     mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
223 }
224 
GetChannelMasks(const ChannelMasksReceiver & aReceiver,const AsyncResultReceiver & aErrReceiver)225 void NcpHost::GetChannelMasks(const ChannelMasksReceiver &aReceiver, const AsyncResultReceiver &aErrReceiver)
226 {
227     OT_UNUSED_VARIABLE(aReceiver);
228 
229     // TODO: Implement GetChannelMasks under NCP mode.
230     mTaskRunner.Post([aErrReceiver](void) { aErrReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
231 }
232 
233 #if OTBR_ENABLE_POWER_CALIBRATION
SetChannelMaxPowers(const std::vector<ChannelMaxPower> & aChannelMaxPowers,const AsyncResultReceiver & aReceiver)234 void NcpHost::SetChannelMaxPowers(const std::vector<ChannelMaxPower> &aChannelMaxPowers,
235                                   const AsyncResultReceiver          &aReceiver)
236 {
237     OT_UNUSED_VARIABLE(aChannelMaxPowers);
238 
239     // TODO: Implement SetChannelMaxPowers under NCP mode.
240     mTaskRunner.Post([aReceiver](void) { aReceiver(OT_ERROR_NOT_IMPLEMENTED, "Not implemented!"); });
241 }
242 #endif
243 
AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)244 void NcpHost::AddThreadStateChangedCallback(ThreadStateChangedCallback aCallback)
245 {
246     // TODO: Implement AddThreadStateChangedCallback under NCP mode.
247     OT_UNUSED_VARIABLE(aCallback);
248 }
249 
AddThreadEnabledStateChangedCallback(ThreadEnabledStateCallback aCallback)250 void NcpHost::AddThreadEnabledStateChangedCallback(ThreadEnabledStateCallback aCallback)
251 {
252     // TODO: Implement AddThreadEnabledStateChangedCallback under NCP mode.
253     OT_UNUSED_VARIABLE(aCallback);
254 }
255 
Process(const MainloopContext & aMainloop)256 void NcpHost::Process(const MainloopContext &aMainloop)
257 {
258     mSpinelDriver.Process(&aMainloop);
259 
260     mNetif.Process(&aMainloop);
261 }
262 
Update(MainloopContext & aMainloop)263 void NcpHost::Update(MainloopContext &aMainloop)
264 {
265     mSpinelDriver.GetSpinelInterface()->UpdateFdSet(&aMainloop);
266 
267     if (mSpinelDriver.HasPendingFrame())
268     {
269         aMainloop.mTimeout.tv_sec  = 0;
270         aMainloop.mTimeout.tv_usec = 0;
271     }
272 
273     mNetif.UpdateFdSet(&aMainloop);
274 }
275 
276 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
SetMdnsPublisher(Mdns::Publisher * aPublisher)277 void NcpHost::SetMdnsPublisher(Mdns::Publisher *aPublisher)
278 {
279     mNcpSpinel.SetMdnsPublisher(aPublisher);
280 }
281 
HandleMdnsState(Mdns::Publisher::State aState)282 void NcpHost::HandleMdnsState(Mdns::Publisher::State aState)
283 {
284     mNcpSpinel.DnssdSetState(aState);
285 }
286 #endif
287 
288 } // namespace Host
289 } // namespace otbr
290