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