/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * This file includes the implementation for the Socket interface to radio * (RCP). */ #include "socket_interface.hpp" #include #include #include #include #include #include #include #include "common/code_utils.hpp" #include "openthread/openthread-system.h" namespace aidl { namespace android { namespace hardware { namespace threadnetwork { SocketInterface::SocketInterface(const ot::Url::Url& aRadioUrl) : mReceiveFrameCallback(nullptr), mReceiveFrameContext(nullptr), mReceiveFrameBuffer(nullptr), mSockFd(-1), mRadioUrl(aRadioUrl) { memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics)); mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor; } otError SocketInterface::Init(ReceiveFrameCallback aCallback, void* aCallbackContext, RxFrameBuffer& aFrameBuffer) { otError error = OT_ERROR_NONE; VerifyOrExit(mSockFd == -1, error = OT_ERROR_ALREADY); mSockFd = OpenFile(mRadioUrl); VerifyOrExit(mSockFd != -1, error = OT_ERROR_FAILED); mReceiveFrameCallback = aCallback; mReceiveFrameContext = aCallbackContext; mReceiveFrameBuffer = &aFrameBuffer; exit: return error; } SocketInterface::~SocketInterface(void) { Deinit(); } void SocketInterface::Deinit(void) { CloseFile(); mReceiveFrameCallback = nullptr; mReceiveFrameContext = nullptr; mReceiveFrameBuffer = nullptr; } void SocketInterface::UpdateFdSet(void* aMainloopContext) { otSysMainloopContext* context = reinterpret_cast(aMainloopContext); assert(context != nullptr); FD_SET(mSockFd, &context->mReadFdSet); if (context->mMaxFd < mSockFd) { context->mMaxFd = mSockFd; } } int SocketInterface::OpenFile(const ot::Url::Url& aRadioUrl) { int fd = -1; sockaddr_un serverAddress; VerifyOrExit(sizeof(serverAddress.sun_path) > strlen(aRadioUrl.GetPath()), otLogCritPlat("Invalid file path length")); strncpy(serverAddress.sun_path, aRadioUrl.GetPath(), sizeof(serverAddress.sun_path)); serverAddress.sun_family = AF_UNIX; fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); VerifyOrExit(fd != -1, otLogCritPlat("open(): errno=%s", strerror(errno))); if (connect(fd, reinterpret_cast(&serverAddress), sizeof(serverAddress)) == -1) { otLogCritPlat("connect(): errno=%s", strerror(errno)); close(fd); fd = -1; } exit: return fd; } void SocketInterface::CloseFile(void) { VerifyOrExit(mSockFd != -1); VerifyOrExit(0 == close(mSockFd), otLogCritPlat("close(): errno=%s", strerror(errno))); VerifyOrExit(wait(nullptr) != -1 || errno == ECHILD, otLogCritPlat("wait(): errno=%s", strerror(errno))); mSockFd = -1; exit: return; } } // namespace threadnetwork } // namespace hardware } // namespace android } // namespace aidl