xref: /aosp_15_r20/external/openthread/src/android/thread_network_hal/hal_interface.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1 /*
2  *  Copyright (c) 2022, 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 /**
30  * @file
31  *   This file includes the implementation for the IPC Binder interface to radio Co-Processor (RCP).
32  */
33 
34 #include "hal_interface.hpp"
35 
36 #if OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR
37 
38 #include <linux/gpio.h>
39 #include <linux/ioctl.h>
40 #include <linux/spi/spidev.h>
41 #include <sys/select.h>
42 
43 #include <android/binder_manager.h>
44 #include <android/binder_process.h>
45 
46 #include "common/code_utils.hpp"
47 
48 namespace ot {
49 namespace Posix {
50 using ::aidl::android::hardware::threadnetwork::IThreadChip;
51 using ::aidl::android::hardware::threadnetwork::IThreadChipCallback;
52 using ::ndk::ScopedAStatus;
53 
54 using ot::Spinel::SpinelInterface;
55 
HalInterface(const Url::Url & aRadioUrl)56 HalInterface::HalInterface(const Url::Url &aRadioUrl)
57     : mRxFrameCallback(nullptr)
58     , mRxFrameContext(nullptr)
59     , mRxFrameBuffer(nullptr)
60     , mThreadChip(nullptr)
61     , mThreadChipCallback(nullptr)
62     , mDeathRecipient(AIBinder_DeathRecipient_new(BinderDeathCallback))
63     , mBinderFd(-1)
64     , mHalInterfaceId(0)
65 {
66     IgnoreError(aRadioUrl.ParseUint8("id", mHalInterfaceId));
67     memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
68     mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor;
69 
70     VerifyOrDie(ABinderProcess_setupPolling(&mBinderFd) == ::STATUS_OK, OT_EXIT_FAILURE);
71     VerifyOrDie(mBinderFd >= 0, OT_EXIT_FAILURE);
72 }
73 
Init(SpinelInterface::ReceiveFrameCallback aCallback,void * aCallbackContext,SpinelInterface::RxFrameBuffer & aFrameBuffer)74 otError HalInterface::Init(SpinelInterface::ReceiveFrameCallback aCallback,
75                            void                                 *aCallbackContext,
76                            SpinelInterface::RxFrameBuffer       &aFrameBuffer)
77 {
78     static const std::string            kServicePrefix = std::string() + IThreadChip::descriptor + "/chip";
79     const char                         *value;
80     ScopedAStatus                       ndkStatus;
81     std::shared_ptr<ThreadChipCallback> callback;
82     std::string                         serviceName = kServicePrefix + std::to_string(mHalInterfaceId);
83 
84     otLogInfoPlat("[HAL] Wait for getting the service %s ...", serviceName.c_str());
85     mThreadChip = IThreadChip::fromBinder(::ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
86     VerifyOrDie(mThreadChip != nullptr, OT_EXIT_FAILURE);
87 
88     callback = ndk::SharedRefBase::make<ThreadChipCallback>(this);
89     VerifyOrDie(callback->asBinder().get() != nullptr, OT_EXIT_FAILURE);
90 
91     mThreadChipCallback = IThreadChipCallback::fromBinder(callback->asBinder());
92     VerifyOrDie(mThreadChipCallback != nullptr, OT_EXIT_FAILURE);
93 
94     VerifyOrDie(AIBinder_linkToDeath(mThreadChip->asBinder().get(), mDeathRecipient.get(), this) == STATUS_OK,
95                 OT_EXIT_FAILURE);
96 
97     ndkStatus = mThreadChip->open(mThreadChipCallback);
98     if (!ndkStatus.isOk())
99     {
100         otLogCritPlat("[HAL] Open the HAL interface failed: %s", ndkStatus.getMessage());
101         DieNow(OT_EXIT_FAILURE);
102     }
103 
104     mRxFrameCallback = aCallback;
105     mRxFrameContext  = aCallbackContext;
106     mRxFrameBuffer   = &aFrameBuffer;
107 
108     otLogInfoPlat("[HAL] Successfully got the service %s", serviceName.c_str());
109 
110     return OT_ERROR_NONE;
111 }
112 
BinderDeathCallback(void * aContext)113 void HalInterface::BinderDeathCallback(void *aContext)
114 {
115     OT_UNUSED_VARIABLE(aContext);
116 
117     otLogInfoPlat("[HAL] Thread network HAL is dead, exit!");
118     DieNow(OT_EXIT_FAILURE);
119 }
120 
~HalInterface(void)121 HalInterface::~HalInterface(void)
122 {
123     Deinit();
124 
125     if (mBinderFd >= 0)
126     {
127         close(mBinderFd);
128     }
129 }
130 
Deinit(void)131 void HalInterface::Deinit(void)
132 {
133     if (mThreadChip != nullptr)
134     {
135         mThreadChip->close();
136         AIBinder_unlinkToDeath(mThreadChip->asBinder().get(), mDeathRecipient.get(), this);
137         mThreadChip         = nullptr;
138         mThreadChipCallback = nullptr;
139     }
140 
141     mRxFrameCallback = nullptr;
142     mRxFrameContext  = nullptr;
143     mRxFrameBuffer   = nullptr;
144 }
145 
GetBusSpeed(void) const146 uint32_t HalInterface::GetBusSpeed(void) const
147 {
148     static const uint32_t kBusSpeed = 1000000;
149     return kBusSpeed;
150 }
151 
HardwareReset(void)152 otError HalInterface::HardwareReset(void) { return StatusToError(mThreadChip->hardwareReset()); }
153 
UpdateFdSet(void * aMainloopContext)154 void HalInterface::UpdateFdSet(void *aMainloopContext)
155 {
156     otSysMainloopContext *context = reinterpret_cast<otSysMainloopContext *>(aMainloopContext);
157 
158     assert(context != nullptr);
159 
160     if (mBinderFd >= 0)
161     {
162         FD_SET(mBinderFd, &context->mReadFdSet);
163         context->mMaxFd = std::max(context->mMaxFd, mBinderFd);
164     }
165 }
166 
Process(const void * aMainloopContext)167 void HalInterface::Process(const void *aMainloopContext)
168 {
169     const otSysMainloopContext *context = reinterpret_cast<const otSysMainloopContext *>(aMainloopContext);
170 
171     assert(context != nullptr);
172 
173     if ((mBinderFd >= 0) && FD_ISSET(mBinderFd, &context->mReadFdSet))
174     {
175         ABinderProcess_handlePolledCommands();
176     }
177 }
178 
WaitForFrame(uint64_t aTimeoutUs)179 otError HalInterface::WaitForFrame(uint64_t aTimeoutUs)
180 {
181     otError        error = OT_ERROR_NONE;
182     struct timeval timeout;
183     fd_set         readFdSet;
184     int            ret;
185 
186     VerifyOrExit(mBinderFd >= 0, error = OT_ERROR_FAILED);
187 
188     timeout.tv_sec  = static_cast<time_t>(aTimeoutUs / OT_US_PER_S);
189     timeout.tv_usec = static_cast<suseconds_t>(aTimeoutUs % OT_US_PER_S);
190 
191     FD_ZERO(&readFdSet);
192     FD_SET(mBinderFd, &readFdSet);
193 
194     ret = select(mBinderFd + 1, &readFdSet, nullptr, nullptr, &timeout);
195 
196     if ((ret > 0) && FD_ISSET(mBinderFd, &readFdSet))
197     {
198         ABinderProcess_handlePolledCommands();
199     }
200     else if (ret == 0)
201     {
202         ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
203     }
204     else if (errno != EINTR)
205     {
206         DieNow(OT_EXIT_ERROR_ERRNO);
207     }
208 
209 exit:
210 
211     if (error != OT_ERROR_NONE)
212     {
213         otLogWarnPlat("[HAL] Wait for frame failed: %s", otThreadErrorToString(error));
214     }
215 
216     return error;
217 }
218 
SendFrame(const uint8_t * aFrame,uint16_t aLength)219 otError HalInterface::SendFrame(const uint8_t *aFrame, uint16_t aLength)
220 {
221     otError       error = OT_ERROR_NONE;
222     ScopedAStatus status;
223 
224     VerifyOrExit((aFrame != nullptr) && (aLength <= kMaxFrameSize), error = OT_ERROR_INVALID_ARGS);
225     status = mThreadChip->sendSpinelFrame(std::vector<uint8_t>(aFrame, aFrame + aLength));
226     VerifyOrExit(!status.isOk(), error = OT_ERROR_NONE);
227     error = StatusToError(status);
228     otLogWarnPlat("[HAL] Send frame to HAL interface failed: %s", otThreadErrorToString(error));
229 
230 exit:
231     if (error == OT_ERROR_NONE)
232     {
233         mInterfaceMetrics.mTxFrameCount++;
234         mInterfaceMetrics.mTxFrameByteCount += aLength;
235     }
236 
237     return error;
238 }
239 
ReceiveFrameCallback(const std::vector<uint8_t> & aFrame)240 void HalInterface::ReceiveFrameCallback(const std::vector<uint8_t> &aFrame)
241 {
242     otError error = OT_ERROR_NONE;
243 
244     VerifyOrExit(mRxFrameBuffer != nullptr, error = OT_ERROR_FAILED);
245     VerifyOrExit(aFrame.size() > 0, error = OT_ERROR_FAILED);
246 
247     for (uint32_t i = 0; i < aFrame.size(); i++)
248     {
249         if ((error = mRxFrameBuffer->WriteByte(aFrame[i])) != OT_ERROR_NONE)
250         {
251             otLogNotePlat("[HAL] Drop the received spinel frame: %s", otThreadErrorToString(error));
252             mRxFrameBuffer->DiscardFrame();
253             ExitNow(error = OT_ERROR_NO_BUFS);
254         }
255     }
256 
257     if (mRxFrameCallback != nullptr)
258     {
259         mRxFrameCallback(mRxFrameContext);
260     }
261 
262 exit:
263     if (error == OT_ERROR_NONE)
264     {
265         mInterfaceMetrics.mRxFrameCount++;
266         mInterfaceMetrics.mRxFrameByteCount += aFrame.size();
267     }
268 
269     return;
270 }
271 
StatusToError(const ScopedAStatus & aStatus) const272 otError HalInterface::StatusToError(const ScopedAStatus &aStatus) const
273 {
274     otError error = OT_ERROR_FAILED;
275 
276     VerifyOrExit(!aStatus.isOk(), error = OT_ERROR_NONE);
277 
278     if (aStatus.getExceptionCode() == EX_ILLEGAL_STATE)
279     {
280         error = OT_ERROR_INVALID_STATE;
281     }
282     else if (aStatus.getExceptionCode() == EX_ILLEGAL_ARGUMENT)
283     {
284         error = OT_ERROR_INVALID_ARGS;
285     }
286     else if (aStatus.getExceptionCode() == EX_UNSUPPORTED_OPERATION)
287     {
288         error = OT_ERROR_NOT_IMPLEMENTED;
289     }
290     else if (aStatus.getExceptionCode() == EX_SERVICE_SPECIFIC)
291     {
292         switch (aStatus.getServiceSpecificError())
293         {
294         case IThreadChip::ERROR_FAILED:
295             error = OT_ERROR_FAILED;
296             break;
297         case IThreadChip::ERROR_BUSY:
298             error = OT_ERROR_BUSY;
299             break;
300         case IThreadChip::ERROR_NO_BUFS:
301             error = OT_ERROR_NO_BUFS;
302             break;
303         default:
304             error = OT_ERROR_FAILED;
305             break;
306         }
307     }
308 
309 exit:
310     return error;
311 }
312 
313 } // namespace Posix
314 } // namespace ot
315 
316 #endif // OPENTHREAD_POSIX_CONFIG_RCP_BUS == OT_POSIX_RCP_BUS_VENDOR
317