1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /**
18 * @file
19 * This file includes the implementation for the Socket interface to radio
20 * (RCP).
21 */
22
23 #include "socket_interface.hpp"
24
25 #include <errno.h>
26 #include <linux/limits.h>
27 #include <openthread/logging.h>
28 #include <sys/inotify.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/un.h>
32 #include <sys/wait.h>
33 #include <unistd.h>
34
35 #include <string>
36 #include <vector>
37
38 #include "common/code_utils.hpp"
39 #include "openthread/error.h"
40 #include "openthread/openthread-system.h"
41 #include "platform-posix.h"
42
43 namespace aidl {
44 namespace android {
45 namespace hardware {
46 namespace threadnetwork {
47
48 const char SocketInterface::kLogModuleName[] = "SocketIntface";
49
SocketInterface(const ot::Url::Url & aRadioUrl)50 SocketInterface::SocketInterface(const ot::Url::Url& aRadioUrl)
51 : mReceiveFrameCallback(nullptr),
52 mReceiveFrameContext(nullptr),
53 mReceiveFrameBuffer(nullptr),
54 mRadioUrl(aRadioUrl) {
55 ResetStates();
56 }
57
Init(ReceiveFrameCallback aCallback,void * aCallbackContext,RxFrameBuffer & aFrameBuffer)58 otError SocketInterface::Init(ReceiveFrameCallback aCallback, void* aCallbackContext,
59 RxFrameBuffer& aFrameBuffer) {
60 otError error = InitSocket();
61
62 VerifyOrExit(error == OT_ERROR_NONE);
63
64 mReceiveFrameCallback = aCallback;
65 mReceiveFrameContext = aCallbackContext;
66 mReceiveFrameBuffer = &aFrameBuffer;
67
68 exit:
69 return error;
70 }
71
~SocketInterface(void)72 SocketInterface::~SocketInterface(void) {
73 Deinit();
74 }
75
Deinit(void)76 void SocketInterface::Deinit(void) {
77 CloseFile();
78
79 mReceiveFrameCallback = nullptr;
80 mReceiveFrameContext = nullptr;
81 mReceiveFrameBuffer = nullptr;
82 }
83
SendFrame(const uint8_t * aFrame,uint16_t aLength)84 otError SocketInterface::SendFrame(const uint8_t* aFrame, uint16_t aLength) {
85 Write(aFrame, aLength);
86
87 return OT_ERROR_NONE;
88 }
89
WaitForFrame(uint64_t aTimeoutUs)90 otError SocketInterface::WaitForFrame(uint64_t aTimeoutUs) {
91 otError error = OT_ERROR_NONE;
92 struct timeval timeout;
93 timeout.tv_sec = static_cast<time_t>(aTimeoutUs / OT_US_PER_S);
94 timeout.tv_usec = static_cast<suseconds_t>(aTimeoutUs % OT_US_PER_S);
95
96 fd_set readFds;
97 fd_set errorFds;
98 int rval;
99
100 FD_ZERO(&readFds);
101 FD_ZERO(&errorFds);
102 FD_SET(mSockFd, &readFds);
103 FD_SET(mSockFd, &errorFds);
104
105 rval = TEMP_FAILURE_RETRY(select(mSockFd + 1, &readFds, nullptr, &errorFds, &timeout));
106
107 if (rval > 0) {
108 if (FD_ISSET(mSockFd, &readFds)) {
109 Read();
110 } else if (FD_ISSET(mSockFd, &errorFds)) {
111 DieNowWithMessage("RCP error", OT_EXIT_FAILURE);
112 } else {
113 DieNow(OT_EXIT_FAILURE);
114 }
115 } else if (rval == 0) {
116 ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
117 } else {
118 DieNowWithMessage("Wait response", OT_EXIT_FAILURE);
119 }
120
121 exit:
122 return error;
123 }
124
WaitForHardwareResetCompletion(uint32_t aTimeoutMs)125 otError SocketInterface::WaitForHardwareResetCompletion(uint32_t aTimeoutMs) {
126 otError error = OT_ERROR_NONE;
127 int retries = 0;
128 int rval;
129
130 while (mIsHardwareResetting && retries++ < kMaxRetriesForSocketCloseCheck) {
131 struct timeval timeout;
132 timeout.tv_sec = static_cast<time_t>(aTimeoutMs / OT_MS_PER_S);
133 timeout.tv_usec = static_cast<suseconds_t>((aTimeoutMs % OT_MS_PER_S) * OT_MS_PER_S);
134
135 fd_set readFds;
136
137 FD_ZERO(&readFds);
138 FD_SET(mSockFd, &readFds);
139
140 rval = TEMP_FAILURE_RETRY(select(mSockFd + 1, &readFds, nullptr, nullptr, &timeout));
141
142 if (rval > 0) {
143 Read();
144 } else if (rval < 0) {
145 DieNowWithMessage("Wait response", OT_EXIT_ERROR_ERRNO);
146 } else {
147 LogInfo("Waiting for hardware reset, retry attempt: %d, max attempt: %d", retries,
148 kMaxRetriesForSocketCloseCheck);
149 }
150 }
151
152 VerifyOrExit(!mIsHardwareResetting, error = OT_ERROR_FAILED);
153
154 exit:
155 return error;
156 }
157
InitSocket()158 otError SocketInterface::InitSocket() {
159 otError error = OT_ERROR_NONE;
160 int retries = 0;
161
162 VerifyOrExit(mSockFd == -1, error = OT_ERROR_ALREADY);
163
164 while (retries++ < kMaxRetriesForSocketInit) {
165 WaitForSocketFileCreated(mRadioUrl.GetPath());
166 mSockFd = OpenFile(mRadioUrl);
167 VerifyOrExit(mSockFd == -1);
168 }
169 error = OT_ERROR_FAILED;
170
171 exit:
172 return error;
173 }
174
UpdateFdSet(void * aMainloopContext)175 void SocketInterface::UpdateFdSet(void* aMainloopContext) {
176 otSysMainloopContext* context = reinterpret_cast<otSysMainloopContext*>(aMainloopContext);
177
178 assert(context != nullptr);
179
180 VerifyOrExit(mSockFd != -1);
181
182 FD_SET(mSockFd, &context->mReadFdSet);
183
184 if (context->mMaxFd < mSockFd) {
185 context->mMaxFd = mSockFd;
186 }
187
188 exit:
189 return;
190 }
191
Process(const void * aMainloopContext)192 void SocketInterface::Process(const void* aMainloopContext) {
193 const otSysMainloopContext* context =
194 reinterpret_cast<const otSysMainloopContext*>(aMainloopContext);
195
196 assert(context != nullptr);
197
198 VerifyOrExit(mSockFd != -1);
199
200 if (FD_ISSET(mSockFd, &context->mReadFdSet)) {
201 Read();
202 }
203
204 exit:
205 return;
206 }
207
HardwareReset(void)208 otError SocketInterface::HardwareReset(void) {
209 otError error = OT_ERROR_NONE;
210 std::vector<uint8_t> resetCommand = {SPINEL_HEADER_FLAG, SPINEL_CMD_RESET, 0x04};
211
212 mIsHardwareResetting = true;
213 SendFrame(resetCommand.data(), resetCommand.size());
214
215 return WaitForHardwareResetCompletion(kMaxSelectTimeMs);
216 }
217
Read(void)218 void SocketInterface::Read(void) {
219 uint8_t buffer[kMaxFrameSize];
220 ssize_t rval;
221
222 VerifyOrExit(mSockFd != -1);
223
224 rval = TEMP_FAILURE_RETRY(read(mSockFd, buffer, sizeof(buffer)));
225
226 if (rval > 0) {
227 ProcessReceivedData(buffer, static_cast<uint16_t>(rval));
228 } else if (rval < 0) {
229 DieNow(OT_EXIT_ERROR_ERRNO);
230 } else {
231 LogWarn("Socket connection is closed by remote, isHardwareReset: %d", mIsHardwareResetting);
232 ResetStates();
233 InitSocket();
234 }
235
236 exit:
237 return;
238 }
239
Write(const uint8_t * aFrame,uint16_t aLength)240 void SocketInterface::Write(const uint8_t* aFrame, uint16_t aLength) {
241 ssize_t rval = TEMP_FAILURE_RETRY(write(mSockFd, aFrame, aLength));
242 VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO);
243 VerifyOrDie(rval > 0, OT_EXIT_FAILURE);
244 }
245
ProcessReceivedData(const uint8_t * aBuffer,uint16_t aLength)246 void SocketInterface::ProcessReceivedData(const uint8_t* aBuffer, uint16_t aLength) {
247 while (aLength--) {
248 uint8_t byte = *aBuffer++;
249 if (mReceiveFrameBuffer->CanWrite(sizeof(uint8_t))) {
250 IgnoreError(mReceiveFrameBuffer->WriteByte(byte));
251 } else {
252 HandleSocketFrame(this, OT_ERROR_NO_BUFS);
253 return;
254 }
255 }
256 HandleSocketFrame(this, OT_ERROR_NONE);
257 }
258
HandleSocketFrame(void * aContext,otError aError)259 void SocketInterface::HandleSocketFrame(void* aContext, otError aError) {
260 static_cast<SocketInterface*>(aContext)->HandleSocketFrame(aError);
261 }
262
HandleSocketFrame(otError aError)263 void SocketInterface::HandleSocketFrame(otError aError) {
264 VerifyOrExit((mReceiveFrameCallback != nullptr) && (mReceiveFrameBuffer != nullptr));
265
266 if (aError == OT_ERROR_NONE) {
267 mReceiveFrameCallback(mReceiveFrameContext);
268 } else {
269 mReceiveFrameBuffer->DiscardFrame();
270 LogWarn("Process socket frame failed: %s", otThreadErrorToString(aError));
271 }
272
273 exit:
274 return;
275 }
276
OpenFile(const ot::Url::Url & aRadioUrl)277 int SocketInterface::OpenFile(const ot::Url::Url& aRadioUrl) {
278 int fd = -1;
279 sockaddr_un serverAddress;
280
281 VerifyOrExit(sizeof(serverAddress.sun_path) > strlen(aRadioUrl.GetPath()),
282 LogCrit("Invalid file path length"));
283 strncpy(serverAddress.sun_path, aRadioUrl.GetPath(), sizeof(serverAddress.sun_path));
284 serverAddress.sun_family = AF_UNIX;
285
286 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
287 VerifyOrExit(fd != -1, LogCrit("open(): errno=%s", strerror(errno)));
288
289 if (connect(fd, reinterpret_cast<struct sockaddr*>(&serverAddress), sizeof(serverAddress)) ==
290 -1) {
291 LogCrit("connect(): errno=%s", strerror(errno));
292 close(fd);
293 fd = -1;
294 }
295
296 exit:
297 return fd;
298 }
299
CloseFile(void)300 void SocketInterface::CloseFile(void) {
301 VerifyOrExit(mSockFd != -1);
302
303 VerifyOrExit(0 == close(mSockFd), LogCrit("close(): errno=%s", strerror(errno)));
304 VerifyOrExit(wait(nullptr) != -1 || errno == ECHILD,
305 LogCrit("wait(): errno=%s", strerror(errno)));
306
307 mSockFd = -1;
308
309 exit:
310 return;
311 }
312
WaitForSocketFileCreated(const char * aPath)313 void SocketInterface::WaitForSocketFileCreated(const char* aPath) {
314 int inotifyFd;
315 int wd;
316 int lastSlashIdx;
317 std::string folderPath;
318 std::string socketPath(aPath);
319
320 VerifyOrExit(!IsSocketFileExisted(aPath));
321
322 inotifyFd = inotify_init();
323 VerifyOrDie(inotifyFd != -1, OT_EXIT_ERROR_ERRNO);
324
325 lastSlashIdx = socketPath.find_last_of('/');
326 VerifyOrDie(lastSlashIdx != std::string::npos, OT_EXIT_ERROR_ERRNO);
327
328 folderPath = socketPath.substr(0, lastSlashIdx);
329 wd = inotify_add_watch(inotifyFd, folderPath.c_str(), IN_CREATE);
330 VerifyOrDie(wd != -1, OT_EXIT_ERROR_ERRNO);
331
332 LogInfo("Waiting for socket file %s be created...", aPath);
333
334 while (true) {
335 fd_set fds;
336 FD_ZERO(&fds);
337 FD_SET(inotifyFd, &fds);
338 struct timeval timeout = {kMaxSelectTimeMs / OT_MS_PER_S,
339 (kMaxSelectTimeMs % OT_MS_PER_S) * OT_MS_PER_S};
340
341 int rval = select(inotifyFd + 1, &fds, nullptr, nullptr, &timeout);
342 VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO);
343
344 if (rval == 0 && IsSocketFileExisted(aPath)) {
345 break;
346 }
347
348 if (FD_ISSET(inotifyFd, &fds)) {
349 char buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
350 ssize_t bytesRead = read(inotifyFd, buffer, sizeof(buffer));
351
352 VerifyOrDie(bytesRead >= 0, OT_EXIT_ERROR_ERRNO);
353
354 struct inotify_event* event = reinterpret_cast<struct inotify_event*>(buffer);
355 if ((event->mask & IN_CREATE) && IsSocketFileExisted(aPath)) {
356 break;
357 }
358 }
359 }
360
361 close(inotifyFd);
362
363 exit:
364 LogInfo("Socket file: %s is created", aPath);
365 return;
366 }
367
IsSocketFileExisted(const char * aPath)368 bool SocketInterface::IsSocketFileExisted(const char* aPath) {
369 struct stat st;
370 return stat(aPath, &st) == 0 && S_ISSOCK(st.st_mode);
371 }
372
ResetStates()373 void SocketInterface::ResetStates() {
374 mSockFd = -1;
375 mIsHardwareResetting = false;
376 memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
377 mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor;
378 }
379
380 } // namespace threadnetwork
381 } // namespace hardware
382 } // namespace android
383 } // namespace aidl
384