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