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