• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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