xref: /aosp_15_r20/external/ot-br-posix/src/android/android_rcp_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 "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