xref: /aosp_15_r20/hardware/interfaces/threadnetwork/aidl/default/socket_interface.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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