/* * Copyright (C) 2021 Huawei Device Co., Ltd. * 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. */ #include "rfcomm_defs.h" static void RfcommRecvConnectReqCallback( uint16_t lcid, uint8_t id, const L2capConnectionInfo *info, uint16_t lpsm, void *context); static void RfcommRecvConnectRspCallback( uint16_t lcid, const L2capConnectionInfo *info, uint16_t result, uint16_t status, void *context); static void RfcommRecvConfigReqCallback(uint16_t lcid, uint8_t id, const L2capConfigInfo *cfg, void *context); static void RfcommRecvConfigRspCallback(uint16_t lcid, const L2capConfigInfo *cfg, uint16_t result, void *context); static void RfcommRecvDisconnectReqCallback(uint16_t lcid, uint8_t id, void *context); static void RfcommRecvDisconnectRspCallback(uint16_t lcid, void *context); static void RfcommDisconnectAbnormalCallback(uint16_t lcid, uint8_t reason, void *context); static void RfcommRecvDataCallback(uint16_t lcid, Packet *pkt, void *context); /** * @brief Register callback function to L2CAP when RFCOMM initialize. * */ void RfcommRegisterL2cap() { LOG_INFO("%{public}s", __func__); static const L2capService svc = { RfcommRecvConnectReqCallback, RfcommRecvConnectRspCallback, RfcommRecvConfigReqCallback, RfcommRecvConfigRspCallback, RfcommRecvDisconnectReqCallback, RfcommRecvDisconnectRspCallback, RfcommDisconnectAbnormalCallback, RfcommRecvDataCallback, NULL }; L2CIF_RegisterService(BT_PSM_RFCOMM, &svc, NULL, NULL); } /** * @brief Deregister L2CAP when RFCOMM finalize. * */ void RfcommDeregisterL2cap() { LOG_INFO("%{public}s", __func__); L2CIF_DeregisterService(BT_PSM_RFCOMM, NULL); } typedef struct { uint16_t lcid; uint8_t id; L2capConnectionInfo info; uint16_t lpsm; void *context; } RfcommRecvConnectReqInfo; static void RfcommRecvConnectReqTsk(void *context) { LOG_INFO("%{public}s", __func__); RfcommRecvConnectReqInfo *ctx = context; if (ctx == NULL) { LOG_ERROR("%{public}s context is NULL.", __func__); return; } RfcommRecvConnectReqCback(ctx->lcid, ctx->id, &ctx->info, ctx->lpsm); free(ctx); } void RfcommRecvConnectReqCallback( uint16_t lcid, uint8_t id, const L2capConnectionInfo *info, uint16_t lpsm, void *context) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); RfcommRecvConnectReqInfo *ctx = malloc(sizeof(RfcommRecvConnectReqInfo)); if (ctx == NULL) { return; } (void)memset_s(ctx, sizeof(RfcommRecvConnectReqInfo), 0x00, sizeof(RfcommRecvConnectReqInfo)); ctx->lcid = lcid; ctx->id = id; ctx->lpsm = lpsm; ctx->context = context; (void)memcpy_s(&ctx->info, sizeof(L2capConnectionInfo), info, sizeof(L2capConnectionInfo)); int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommRecvConnectReqTsk, ctx); if (ret != BT_SUCCESS) { free(ctx); } } typedef struct { uint16_t lcid; L2capConnectionInfo info; uint16_t result; uint16_t status; void *context; } RfcommRecvConnectRspInfo; static void RfcommRecvConnectRspTsk(void *context) { LOG_INFO("%{public}s", __func__); RfcommRecvConnectRspInfo *ctx = context; if (ctx == NULL) { LOG_ERROR("%{public}s context is NULL.", __func__); return; } RfcommRecvConnectRspCback(ctx->lcid, &ctx->info, ctx->result, ctx->status); free(ctx); } void RfcommRecvConnectRspCallback( uint16_t lcid, const L2capConnectionInfo *info, uint16_t result, uint16_t status, void *context) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); RfcommRecvConnectRspInfo *ctx = malloc(sizeof(RfcommRecvConnectRspInfo)); if (ctx == NULL) { return; } (void)memset_s(ctx, sizeof(RfcommRecvConnectRspInfo), 0x00, sizeof(RfcommRecvConnectRspInfo)); ctx->lcid = lcid; ctx->result = result; ctx->status = status; ctx->context = context; (void)memcpy_s(&ctx->info, sizeof(L2capConnectionInfo), info, sizeof(L2capConnectionInfo)); int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommRecvConnectRspTsk, ctx); if (ret != BT_SUCCESS) { free(ctx); } } typedef struct { uint16_t lcid; uint8_t id; L2capConfigInfo cfg; void *context; } RfcommRecvConfigReqInfo; static void RfcommRecvConfigReqTsk(void *context) { LOG_INFO("%{public}s", __func__); RfcommRecvConfigReqInfo *ctx = context; if (ctx == NULL) { LOG_ERROR("%{public}s context is NULL.", __func__); return; } RfcommRecvConfigReqCback(ctx->lcid, ctx->id, &ctx->cfg); free(ctx); } void RfcommRecvConfigReqCallback(uint16_t lcid, uint8_t id, const L2capConfigInfo *cfg, void *context) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); RfcommRecvConfigReqInfo *ctx = malloc(sizeof(RfcommRecvConfigReqInfo)); if (ctx == NULL) { return; } (void)memset_s(ctx, sizeof(RfcommRecvConfigReqInfo), 0x00, sizeof(RfcommRecvConfigReqInfo)); ctx->lcid = lcid; ctx->id = id; ctx->context = context; (void)memcpy_s(&ctx->cfg, sizeof(L2capConfigInfo), cfg, sizeof(L2capConfigInfo)); int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommRecvConfigReqTsk, ctx); if (ret != BT_SUCCESS) { free(ctx); } } typedef struct { uint16_t lcid; L2capConfigInfo cfg; uint16_t result; void *context; } RfcommRecvConfigRspInfo; static void RfcommRecvConfigRspTsk(void *context) { LOG_INFO("%{public}s", __func__); RfcommRecvConfigRspInfo *ctx = context; if (ctx == NULL) { LOG_ERROR("%{public}s context is NULL.", __func__); return; } RfcommRecvConfigRspCback(ctx->lcid, &ctx->cfg, ctx->result); free(ctx); } void RfcommRecvConfigRspCallback(uint16_t lcid, const L2capConfigInfo *cfg, uint16_t result, void *context) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); RfcommRecvConfigRspInfo *ctx = malloc(sizeof(RfcommRecvConfigRspInfo)); if (ctx == NULL) { return; } (void)memset_s(ctx, sizeof(RfcommRecvConfigRspInfo), 0x00, sizeof(RfcommRecvConfigRspInfo)); ctx->lcid = lcid; ctx->result = result; ctx->context = context; (void)memcpy_s(&ctx->cfg, sizeof(L2capConfigInfo), cfg, sizeof(L2capConfigInfo)); int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommRecvConfigRspTsk, ctx); if (ret != BT_SUCCESS) { free(ctx); } } typedef struct { uint16_t lcid; uint8_t id; void *context; } RfcommRecvDisconnectReqInfo; static void RfcommRecvDisconnectReqTsk(void *context) { LOG_INFO("%{public}s", __func__); RfcommRecvDisconnectReqInfo *ctx = context; if (ctx == NULL) { LOG_ERROR("%{public}s context is NULL.", __func__); return; } RfcommRecvDisconnectReqCback(ctx->lcid, ctx->id); free(ctx); } void RfcommRecvDisconnectReqCallback(uint16_t lcid, uint8_t id, void *context) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); RfcommRecvDisconnectReqInfo *ctx = malloc(sizeof(RfcommRecvDisconnectReqInfo)); if (ctx == NULL) { return; } (void)memset_s(ctx, sizeof(RfcommRecvDisconnectReqInfo), 0x00, sizeof(RfcommRecvDisconnectReqInfo)); ctx->lcid = lcid; ctx->id = id; ctx->context = context; int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommRecvDisconnectReqTsk, ctx); if (ret != BT_SUCCESS) { free(ctx); } } /** * @brief L2CAP calls this function to notify RFCOMM disconnect response from peer. * After receiving the response, RFCOMM calls the state machine. * * @param lcid L2CAP channel id. * @param context Context registered by RFCOMM to L2CAP. */ void RfcommRecvDisconnectRspCallback(uint16_t lcid, void *context) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); } typedef struct { uint16_t lcid; uint8_t reason; void *context; } RfcommDisconnectAbnormalInfo; static void RfcommDisconnectAbnormalTsk(void *context) { LOG_INFO("%{public}s", __func__); RfcommDisconnectAbnormalInfo *ctx = context; if (ctx == NULL) { LOG_ERROR("%{public}s context is NULL.", __func__); return; } RfcommDisconnectAbnormalCback(ctx->lcid, ctx->reason); free(ctx); } void RfcommDisconnectAbnormalCallback(uint16_t lcid, uint8_t reason, void *context) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); RfcommDisconnectAbnormalInfo *ctx = malloc(sizeof(RfcommDisconnectAbnormalInfo)); if (ctx == NULL) { return; } (void)memset_s(ctx, sizeof(RfcommDisconnectAbnormalInfo), 0x00, sizeof(RfcommDisconnectAbnormalInfo)); ctx->lcid = lcid; ctx->reason = reason; ctx->context = context; int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommDisconnectAbnormalTsk, ctx); if (ret != BT_SUCCESS) { free(ctx); } } typedef struct { uint16_t lcid; Packet *pkt; void *context; } RfcommRecvDataInfo; static void RfcommRecvDataTsk(void *context) { LOG_INFO("%{public}s", __func__); RfcommRecvDataInfo *ctx = context; if (ctx == NULL) { LOG_ERROR("%{public}s context is NULL.", __func__); return; } RfcommRecvDataCback(ctx->lcid, ctx->pkt); PacketFree(ctx->pkt); free(ctx); } void RfcommRecvDataCallback(uint16_t lcid, Packet *pkt, void *context) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); RfcommRecvDataInfo *ctx = malloc(sizeof(RfcommRecvDataInfo)); if (ctx == NULL) { return; } (void)memset_s(ctx, sizeof(RfcommRecvDataInfo), 0x00, sizeof(RfcommRecvDataInfo)); ctx->lcid = lcid; ctx->pkt = PacketRefMalloc(pkt); ctx->context = context; int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommRecvDataTsk, ctx); if (ret != BT_SUCCESS) { PacketFree(ctx->pkt); free(ctx); } } typedef struct { BtAddr addr; uint16_t lcid; int result; void *context; } RfcommSendConnectReqInfo; static void RfcommSendConnectReqCbackTsk(void *context) { LOG_INFO("%{public}s", __func__); RfcommSendConnectReqInfo *ctx = context; if (ctx == NULL) { LOG_ERROR("%{public}s context is NULL.", __func__); return; } RfcommSendConnectReqCback(&ctx->addr, ctx->lcid, ctx->result); free(ctx); } static void RfcommSendConnectReqCallback(const BtAddr *addr, uint16_t lcid, int result, void *context) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); RfcommSendConnectReqInfo *ctx = malloc(sizeof(RfcommSendConnectReqInfo)); if (ctx == NULL) { return; } (void)memset_s(ctx, sizeof(RfcommSendConnectReqInfo), 0x00, sizeof(RfcommSendConnectReqInfo)); ctx->lcid = lcid; ctx->result = result; (void)memcpy_s(&ctx->addr, sizeof(BtAddr), addr, sizeof(BtAddr)); ctx->context = context; int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommSendConnectReqCbackTsk, ctx); if (ret != BT_SUCCESS) { free(ctx); } } /** * @brief Call L2CAP_ConnectReq to request connection from L2CAP. * * @param addr The peer's BT address. * @param lcid The L2CAP's channel id. * @return Returns RFCOMM_SUCCESS if the operation is successful, otherwise the operation fails. */ int RfcommSendConnectReq(const BtAddr *addr) { LOG_INFO("%{public}s", __func__); int ret = L2CIF_ConnectReq(addr, BT_PSM_RFCOMM, BT_PSM_RFCOMM, NULL, RfcommSendConnectReqCallback); if (ret != RFCOMM_SUCCESS) { LOG_ERROR("%{public}s L2CIF_ConnectReq return value is error.", __func__); } return ret; } /** * @brief Call L2CAP_ConnectRsp to send connection response to peer. * * @param lcid The L2CAP's channel id. * @param id L2CAP's id information. * @param result The result of the response. * @param status The status information. * @return Returns RFCOMM_SUCCESS if the operation is successful, otherwise the operation fails. */ int RfcommSendConnectRsp(uint16_t lcid, uint8_t id, uint16_t result, uint16_t status) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); L2CIF_ConnectRsp(lcid, id, result, status, NULL); return RFCOMM_SUCCESS; } /** * @brief Call L2CAP_ConfigReq to send config request to peer. * * @param lcid The L2CAP's channel id. * @param cfg Config information. * @return Returns RFCOMM_SUCCESS if the operation is successful, otherwise the operation fails. */ int RfcommSendConfigReq(uint16_t lcid, const L2capConfigInfo *cfg) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); int ret = L2CIF_ConfigReq(lcid, cfg, NULL); if (ret != RFCOMM_SUCCESS) { LOG_ERROR("%{public}s L2CIF_ConfigReq return value is error.", __func__); } return ret; } /** * @brief Call L2CAP_ConfigRsp to send config response to peer. * * @param lcid The L2CAP's channel id. * @param id L2CAP's id information. * @param cfg Config information. * @param result The result of the response. * @return Returns RFCOMM_SUCCESS if the operation is successful, otherwise the operation fails. */ int RfcommSendConfigRsp(uint16_t lcid, uint8_t id, const L2capConfigInfo *cfg, uint16_t result) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); int ret = L2CIF_ConfigRsp(lcid, id, cfg, result, NULL); if (ret != RFCOMM_SUCCESS) { LOG_ERROR("%{public}s L2CIF_ConfigRsp return value is error.", __func__); } return ret; } /** * @brief Call L2CAP_DisconnectionReq to send disconnect request to peer. * * @param lcid The L2CAP's channel id. * @return Returns RFCOMM_SUCCESS if the operation is successful, otherwise the operation fails. */ int RfcommSendDisconnectReq(uint16_t lcid) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); L2CIF_DisconnectionReq(lcid, NULL); return RFCOMM_SUCCESS; } /** * @brief Call L2CAP_DisconnectionRsp to send disconnect response to peer. * * @param lcid The L2CAP's channel id. * @param id L2CAP's id information. * @return Returns RFCOMM_SUCCESS if the operation is successful, otherwise the operation fails. */ int RfcommSendDisconnectRsp(uint16_t lcid, uint8_t id) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); L2CIF_DisconnectionRsp(lcid, id, NULL); return RFCOMM_SUCCESS; } /** * @brief Call L2CAP_SendData to send RFCOMM frame to peer. * * @param lcid The L2CAP's channel id. * @param header RFCOMM frame header information. * @param headSize RFCOMM frame header length. * @param tail RFCOMM frame tail information. * @param pkt The RFCOMM frame information. * @return Returns RFCOMM_SUCCESS if the operation is successful, otherwise the operation fails. */ int RfcommSendData(uint16_t lcid, const uint8_t *header, uint8_t headSize, uint8_t tail, Packet *pkt) { LOG_INFO("%{public}s lcid:%hu", __func__, lcid); Packet *packet = NULL; uint8_t *headerBuf = NULL; uint8_t *tailBuf = NULL; if (pkt == NULL) { packet = PacketMalloc(headSize, 1, 0); } else { packet = PacketInheritMalloc(pkt, headSize, 1); } headerBuf = (uint8_t *)BufferPtr(PacketHead(packet)); tailBuf = (uint8_t *)BufferPtr(PacketTail(packet)); (void)memcpy_s(headerBuf, (sizeof(uint8_t) * headSize), header, (sizeof(uint8_t) * headSize)); *tailBuf = tail; int ret = L2CIF_SendData(lcid, packet, NULL); if (ret != RFCOMM_SUCCESS) { LOG_ERROR("%{public}s L2CIF_SendData return value is error.", __func__); } PacketFree(packet); return ret; }