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 "ARCP_HOST"
30
31 #include "android_rcp_host.hpp"
32
33 #include <net/if.h>
34 #include <vector>
35
36 #include <android-base/file.h>
37 #include <android-base/stringprintf.h>
38 #include <openthread/backbone_router_ftd.h>
39 #include <openthread/border_routing.h>
40 #include <openthread/dnssd_server.h>
41 #include <openthread/ip6.h>
42 #include <openthread/nat64.h>
43 #include <openthread/openthread-system.h>
44 #include <openthread/srp_server.h>
45 #include <openthread/thread.h>
46 #include <openthread/trel.h>
47 #include <openthread/platform/infra_if.h>
48 #include <openthread/platform/trel.h>
49
50 #include "android/common_utils.hpp"
51 #include "common/code_utils.hpp"
52
53 namespace otbr {
54 namespace Android {
55
56 AndroidRcpHost *AndroidRcpHost::sAndroidRcpHost = nullptr;
57
AndroidRcpHost(Ncp::RcpHost & aRcpHost)58 AndroidRcpHost::AndroidRcpHost(Ncp::RcpHost &aRcpHost)
59 : mRcpHost(aRcpHost)
60 , mConfiguration()
61 , mInfraIcmp6Socket(-1)
62 {
63 mInfraLinkState.interfaceName = "";
64
65 sAndroidRcpHost = this;
66 }
67
SetConfiguration(const OtDaemonConfiguration & aConfiguration,const std::shared_ptr<IOtStatusReceiver> & aReceiver)68 void AndroidRcpHost::SetConfiguration(const OtDaemonConfiguration &aConfiguration,
69 const std::shared_ptr<IOtStatusReceiver> &aReceiver)
70 {
71 otError error = OT_ERROR_NONE;
72 std::string message;
73 otLinkModeConfig linkModeConfig;
74
75 otbrLogInfo("Set configuration: %s", aConfiguration.toString().c_str());
76
77 VerifyOrExit(GetOtInstance() != nullptr, error = OT_ERROR_INVALID_STATE, message = "OT is not initialized");
78 VerifyOrExit(aConfiguration != mConfiguration);
79
80 // TODO: b/343814054 - Support enabling/disabling DHCPv6-PD.
81 VerifyOrExit(!aConfiguration.dhcpv6PdEnabled, error = OT_ERROR_NOT_IMPLEMENTED,
82 message = "DHCPv6-PD is not supported");
83 otNat64SetEnabled(GetOtInstance(), aConfiguration.nat64Enabled);
84 // DNS upstream query is enabled if and only if NAT64 is enabled.
85 otDnssdUpstreamQuerySetEnabled(GetOtInstance(), aConfiguration.nat64Enabled);
86
87 linkModeConfig = GetLinkModeConfig(aConfiguration.borderRouterEnabled);
88 SuccessOrExit(error = otThreadSetLinkMode(GetOtInstance(), linkModeConfig), message = "Failed to set link mode");
89 if (aConfiguration.borderRouterEnabled)
90 {
91 otSrpServerSetAutoEnableMode(GetOtInstance(), true);
92 SetBorderRouterEnabled(true);
93 }
94 else
95 {
96 // This automatically disables the auto-enable mode which is designed for border router
97 otSrpServerSetEnabled(GetOtInstance(), true);
98
99 SetBorderRouterEnabled(false);
100 }
101
102 mConfiguration = aConfiguration;
103
104 exit:
105 PropagateResult(error, message, aReceiver);
106 }
107
SetInfraLinkInterfaceName(const std::string & aInterfaceName,int aIcmp6Socket,const std::shared_ptr<IOtStatusReceiver> & aReceiver)108 void AndroidRcpHost::SetInfraLinkInterfaceName(const std::string &aInterfaceName,
109 int aIcmp6Socket,
110 const std::shared_ptr<IOtStatusReceiver> &aReceiver)
111 {
112 otError error = OT_ERROR_NONE;
113 std::string message;
114 const std::string infraIfName = aInterfaceName;
115 unsigned int infraIfIndex = if_nametoindex(infraIfName.c_str());
116
117 otbrLogInfo("Setting infra link state: %s", aInterfaceName.c_str());
118
119 VerifyOrExit(GetOtInstance() != nullptr, error = OT_ERROR_INVALID_STATE, message = "OT is not initialized");
120 VerifyOrExit(mConfiguration.borderRouterEnabled, error = OT_ERROR_INVALID_STATE,
121 message = "Set infra link state when border router is disabled");
122 VerifyOrExit(mInfraLinkState.interfaceName != aInterfaceName || aIcmp6Socket != mInfraIcmp6Socket);
123
124 if (infraIfIndex != 0 && aIcmp6Socket > 0)
125 {
126 SuccessOrExit(error = otBorderRoutingSetEnabled(GetOtInstance(), false /* aEnabled */),
127 message = "failed to disable border routing");
128 otSysSetInfraNetif(infraIfName.c_str(), aIcmp6Socket);
129 aIcmp6Socket = -1;
130 SuccessOrExit(error = otBorderRoutingInit(GetOtInstance(), infraIfIndex, otSysInfraIfIsRunning()),
131 message = "failed to initialize border routing");
132 SuccessOrExit(error = otBorderRoutingSetEnabled(GetOtInstance(), true /* aEnabled */),
133 message = "failed to enable border routing");
134 // TODO: b/320836258 - Make BBR independently configurable
135 otBackboneRouterSetEnabled(GetOtInstance(), true /* aEnabled */);
136 }
137 else
138 {
139 SuccessOrExit(error = otBorderRoutingSetEnabled(GetOtInstance(), false /* aEnabled */),
140 message = "failed to disable border routing");
141 otBackboneRouterSetEnabled(GetOtInstance(), false /* aEnabled */);
142 }
143
144 mInfraLinkState.interfaceName = aInterfaceName;
145 mInfraIcmp6Socket = aIcmp6Socket;
146
147 SetTrelEnabled(mTrelEnabled);
148
149 exit:
150 if (error != OT_ERROR_NONE)
151 {
152 close(aIcmp6Socket);
153 }
154 PropagateResult(error, message, aReceiver);
155 }
156
SetTrelEnabled(bool aEnabled)157 void AndroidRcpHost::SetTrelEnabled(bool aEnabled)
158 {
159 mTrelEnabled = aEnabled;
160
161 otbrLogInfo("%s TREL", aEnabled ? "Enabling" : "Disabling");
162
163 // Tear down TREL if it's been initialized/enabled already.
164 otTrelSetEnabled(GetOtInstance(), false);
165 otSysTrelDeinit();
166
167 if (mTrelEnabled && mInfraLinkState.interfaceName != "")
168 {
169 otSysTrelInit(mInfraLinkState.interfaceName.value_or("").c_str());
170 otTrelSetEnabled(GetOtInstance(), true);
171 }
172 }
173
SetInfraLinkNat64Prefix(const std::string & aNat64Prefix,const std::shared_ptr<IOtStatusReceiver> & aReceiver)174 void AndroidRcpHost::SetInfraLinkNat64Prefix(const std::string &aNat64Prefix,
175 const std::shared_ptr<IOtStatusReceiver> &aReceiver)
176 {
177 otError error = OT_ERROR_NONE;
178 std::string message;
179
180 otbrLogInfo("Setting infra link NAT64 prefix: %s", aNat64Prefix.c_str());
181
182 VerifyOrExit(mRcpHost.GetInstance() != nullptr, error = OT_ERROR_INVALID_STATE, message = "OT is not initialized");
183
184 mInfraLinkState.nat64Prefix = aNat64Prefix;
185 NotifyNat64PrefixDiscoveryDone();
186
187 exit:
188 PropagateResult(error, message, aReceiver);
189 }
190
RunOtCtlCommand(const std::string & aCommand,const bool aIsInteractive,const std::shared_ptr<IOtOutputReceiver> & aReceiver)191 void AndroidRcpHost::RunOtCtlCommand(const std::string &aCommand,
192 const bool aIsInteractive,
193 const std::shared_ptr<IOtOutputReceiver> &aReceiver)
194 {
195 otSysCliInitUsingDaemon(GetOtInstance());
196
197 if (!aCommand.empty())
198 {
199 std::string command = aCommand;
200
201 mIsOtCtlInteractiveMode = aIsInteractive;
202 mOtCtlOutputReceiver = aReceiver;
203
204 otCliInit(GetOtInstance(), AndroidRcpHost::OtCtlCommandCallback, this);
205 otCliInputLine(command.data());
206 }
207 }
208
OtCtlCommandCallback(void * aBinderServer,const char * aFormat,va_list aArguments)209 int AndroidRcpHost::OtCtlCommandCallback(void *aBinderServer, const char *aFormat, va_list aArguments)
210 {
211 return static_cast<AndroidRcpHost *>(aBinderServer)->OtCtlCommandCallback(aFormat, aArguments);
212 }
213
OtCtlCommandCallback(const char * aFormat,va_list aArguments)214 int AndroidRcpHost::OtCtlCommandCallback(const char *aFormat, va_list aArguments)
215 {
216 static const std::string kPrompt = "> ";
217 std::string output;
218
219 VerifyOrExit(mOtCtlOutputReceiver != nullptr, otSysCliInitUsingDaemon(GetOtInstance()));
220
221 android::base::StringAppendV(&output, aFormat, aArguments);
222
223 // Ignore CLI prompt
224 VerifyOrExit(output != kPrompt);
225
226 mOtCtlOutputReceiver->onOutput(output);
227
228 // Check if the command has completed (indicated by "Done" or "Error")
229 if (output.starts_with("Done") || output.starts_with("Error"))
230 {
231 mIsOtCtlOutputComplete = true;
232 }
233
234 // The OpenThread CLI consistently outputs "\r\n" as a newline character. Therefore, we use the presence of "\r\n"
235 // following "Done" or "Error" to signal the completion of a command's output.
236 if (mIsOtCtlOutputComplete && output.ends_with("\r\n"))
237 {
238 if (!mIsOtCtlInteractiveMode)
239 {
240 otSysCliInitUsingDaemon(GetOtInstance());
241 }
242 mIsOtCtlOutputComplete = false;
243 mOtCtlOutputReceiver->onComplete();
244 }
245
246 exit:
247 return output.length();
248 }
249
OutputCallback(void * aContext,const char * aFormat,va_list aArguments)250 static int OutputCallback(void *aContext, const char *aFormat, va_list aArguments)
251 {
252 std::string output;
253
254 android::base::StringAppendV(&output, aFormat, aArguments);
255
256 int length = output.length();
257
258 VerifyOrExit(android::base::WriteStringToFd(output, *(static_cast<int *>(aContext))), length = 0);
259
260 exit:
261 return length;
262 }
263
DumpCliCommand(std::string aCommand,int aFd)264 inline void DumpCliCommand(std::string aCommand, int aFd)
265 {
266 android::base::WriteStringToFd(aCommand + '\n', aFd);
267 otCliInputLine(aCommand.data());
268 }
269
Dump(int aFd,const char ** aArgs,uint32_t aNumArgs)270 binder_status_t AndroidRcpHost::Dump(int aFd, const char **aArgs, uint32_t aNumArgs)
271 {
272 OT_UNUSED_VARIABLE(aArgs);
273 OT_UNUSED_VARIABLE(aNumArgs);
274
275 otCliInit(GetOtInstance(), OutputCallback, &aFd);
276
277 DumpCliCommand("state", aFd);
278 DumpCliCommand("srp server state", aFd);
279 DumpCliCommand("srp server service", aFd);
280 DumpCliCommand("srp server host", aFd);
281 DumpCliCommand("dataset activetimestamp", aFd);
282 DumpCliCommand("dataset channel", aFd);
283 DumpCliCommand("dataset channelmask", aFd);
284 DumpCliCommand("dataset extpanid", aFd);
285 DumpCliCommand("dataset meshlocalprefix", aFd);
286 DumpCliCommand("dataset networkname", aFd);
287 DumpCliCommand("dataset panid", aFd);
288 DumpCliCommand("dataset securitypolicy", aFd);
289 DumpCliCommand("leaderdata", aFd);
290 DumpCliCommand("eidcache", aFd);
291 DumpCliCommand("counters mac", aFd);
292 DumpCliCommand("counters mle", aFd);
293 DumpCliCommand("counters ip", aFd);
294 DumpCliCommand("router table", aFd);
295 DumpCliCommand("neighbor table", aFd);
296 DumpCliCommand("ipaddr -v", aFd);
297 DumpCliCommand("netdata show", aFd);
298
299 fsync(aFd);
300
301 otSysCliInitUsingDaemon(GetOtInstance());
302
303 return STATUS_OK;
304 }
305
ToOtUpstreamDnsServerAddresses(const std::vector<std::string> & aAddresses)306 std::vector<otIp6Address> ToOtUpstreamDnsServerAddresses(const std::vector<std::string> &aAddresses)
307 {
308 std::vector<otIp6Address> addresses;
309
310 // TODO: b/363738575 - support IPv6
311 for (const auto &addressString : aAddresses)
312 {
313 otIp6Address ip6Address;
314 otIp4Address ip4Address;
315
316 if (otIp4AddressFromString(addressString.c_str(), &ip4Address) != OT_ERROR_NONE)
317 {
318 continue;
319 }
320 otIp4ToIp4MappedIp6Address(&ip4Address, &ip6Address);
321 addresses.push_back(ip6Address);
322 }
323
324 return addresses;
325 }
326
SetInfraLinkDnsServers(const std::vector<std::string> & aDnsServers,const std::shared_ptr<IOtStatusReceiver> & aReceiver)327 void AndroidRcpHost::SetInfraLinkDnsServers(const std::vector<std::string> &aDnsServers,
328 const std::shared_ptr<IOtStatusReceiver> &aReceiver)
329 {
330 otError error = OT_ERROR_NONE;
331 std::string message;
332 auto dnsServers = ToOtUpstreamDnsServerAddresses(aDnsServers);
333
334 otbrLogInfo("Setting infra link DNS servers: %d servers", aDnsServers.size());
335
336 VerifyOrExit(aDnsServers != mInfraLinkState.dnsServers);
337
338 mInfraLinkState.dnsServers = aDnsServers;
339 otSysUpstreamDnsSetServerList(dnsServers.data(), dnsServers.size());
340
341 exit:
342 PropagateResult(error, message, aReceiver);
343 }
344
NotifyNat64PrefixDiscoveryDone(void)345 void AndroidRcpHost::NotifyNat64PrefixDiscoveryDone(void)
346 {
347 otIp6Prefix nat64Prefix{};
348 uint32_t infraIfIndex = if_nametoindex(mInfraLinkState.interfaceName.value_or("").c_str());
349
350 otIp6PrefixFromString(mInfraLinkState.nat64Prefix.value_or("").c_str(), &nat64Prefix);
351 otPlatInfraIfDiscoverNat64PrefixDone(GetOtInstance(), infraIfIndex, &nat64Prefix);
352 }
353
GetOtInstance(void)354 otInstance *AndroidRcpHost::GetOtInstance(void)
355 {
356 return mRcpHost.GetInstance();
357 }
358
GetLinkModeConfig(bool aIsRouter)359 otLinkModeConfig AndroidRcpHost::GetLinkModeConfig(bool aIsRouter)
360 {
361 otLinkModeConfig linkModeConfig{};
362
363 if (aIsRouter)
364 {
365 linkModeConfig.mRxOnWhenIdle = true;
366 linkModeConfig.mDeviceType = true;
367 linkModeConfig.mNetworkData = true;
368 }
369 else
370 {
371 linkModeConfig.mRxOnWhenIdle = false;
372 linkModeConfig.mDeviceType = false;
373 linkModeConfig.mNetworkData = true;
374 }
375
376 return linkModeConfig;
377 }
378
SetBorderRouterEnabled(bool aEnabled)379 void AndroidRcpHost::SetBorderRouterEnabled(bool aEnabled)
380 {
381 otError error;
382
383 error = otBorderRoutingSetEnabled(GetOtInstance(), aEnabled);
384 if (error != OT_ERROR_NONE)
385 {
386 otbrLogWarning("Failed to %s Border Routing: %s", (aEnabled ? "enable" : "disable"),
387 otThreadErrorToString(error));
388 ExitNow();
389 }
390
391 otBackboneRouterSetEnabled(GetOtInstance(), aEnabled);
392
393 exit:
394 return;
395 }
396
otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)397 extern "C" otError otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)
398 {
399 OT_UNUSED_VARIABLE(aInfraIfIndex);
400
401 AndroidRcpHost *androidRcpHost = AndroidRcpHost::Get();
402 otError error = OT_ERROR_NONE;
403
404 VerifyOrExit(androidRcpHost != nullptr, error = OT_ERROR_INVALID_STATE);
405
406 androidRcpHost->NotifyNat64PrefixDiscoveryDone();
407
408 exit:
409 return error;
410 }
411
412 } // namespace Android
413 } // namespace otbr
414