* 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 "l2cap_if.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "module.h"
#include "semaphore.h"
#include "btm/btm_thread.h"
#include "l2cap.h"
#include "l2cap_cmn.h"
typedef struct {
uint16_t lpsm;
L2capService service;
void *context;
void (*cb)(uint16_t lpsm, int result);
} L2cifRegisterServiceContext;
static void L2cifRegisterService(const void *context)
{
L2cifRegisterServiceContext *ctx = NULL;
int result;
ctx = (L2cifRegisterServiceContext *)context;
result = L2CAP_RegisterService(ctx->lpsm, &(ctx->service), ctx->context);
if (ctx->cb != NULL) {
ctx->cb(ctx->lpsm, result);
}
L2capFree(ctx);
return;
}
int L2CIF_RegisterService(uint16_t lpsm, const L2capService *svc, void *context, void (*cb)(uint16_t lpsm, int result))
{
L2cifRegisterServiceContext *ctx = NULL;
if (svc == NULL) {
return BT_BAD_PARAM;
}
ctx = L2capAlloc(sizeof(L2cifRegisterServiceContext));
if (ctx == NULL) {
return BT_NO_MEMORY;
}
ctx->lpsm = lpsm;
(void)memcpy_s(&(ctx->service), sizeof(L2capService), svc, sizeof(L2capService));
ctx->context = context;
ctx->cb = cb;
L2capAsynchronousProcess(L2cifRegisterService, L2capFree, ctx);
return BT_SUCCESS;
}
typedef struct {
uint16_t lpsm;
void (*cb)(uint16_t lpsm, int result);
} L2cifDeregisterServiceContext;
static void L2cifDeregisterService(const void *context)
{
L2cifDeregisterServiceContext *ctx = NULL;
int result;
ctx = (L2cifDeregisterServiceContext *)context;
result = L2CAP_DeregisterService(ctx->lpsm);
if (ctx->cb != NULL) {
ctx->cb(ctx->lpsm, result);
}
L2capFree(ctx);
return;
}
void L2CIF_DeregisterService(uint16_t lpsm, void (*cb)(uint16_t lpsm, int result))
{
L2cifDeregisterServiceContext *ctx = NULL;
ctx = L2capAlloc(sizeof(L2cifDeregisterServiceContext));
if (ctx == NULL) {
LOG_WARN("malloc failed");
return;
}
ctx->lpsm = lpsm;
ctx->cb = cb;
L2capAsynchronousProcess(L2cifDeregisterService, L2capFree, ctx);
return;
}
typedef struct {
BtAddr addr;
uint16_t lpsm;
uint16_t rpsm;
void *context;
void (*cb)(const BtAddr *addr, uint16_t lcid, int result, void *context);
} L2cifConnectReqContext;
static void L2cifConnectReq(const void *context)
{
L2cifConnectReqContext *ctx = NULL;
uint16_t lcid = 0;
int result;
ctx = (L2cifConnectReqContext *)context;
result = L2CAP_ConnectReq(&(ctx->addr), ctx->lpsm, ctx->rpsm, &lcid);
if (ctx->cb != NULL) {
ctx->cb(&(ctx->addr), lcid, result, ctx->context);
}
L2capFree(ctx);
return;
}
int L2CIF_ConnectReq(const BtAddr *addr, uint16_t lpsm, uint16_t rpsm, void *context,
void (*cb)(const BtAddr *addr, uint16_t lcid, int result, void *context))
{
L2cifConnectReqContext *ctx = NULL;
if (addr == NULL) {
return BT_BAD_PARAM;
}
ctx = L2capAlloc(sizeof(L2cifConnectReqContext));
if (ctx == NULL) {
return BT_NO_MEMORY;
}
(void)memcpy_s(&(ctx->addr), sizeof(BtAddr), addr, sizeof(BtAddr));
ctx->lpsm = lpsm;
ctx->rpsm = rpsm;
ctx->context = context;
ctx->cb = cb;
L2capAsynchronousProcess(L2cifConnectReq, L2capFree, ctx);
return BT_SUCCESS;
}
typedef struct {
uint16_t lcid;
uint8_t id;
uint16_t result;
uint16_t status;
void (*cb)(uint16_t lcid, int result);
} L2cifConnectRspContext;
static void L2cifConnectRsp(const void *context)
{
L2cifConnectRspContext *ctx = NULL;
int result;
ctx = (L2cifConnectRspContext *)context;
result = L2CAP_ConnectRsp(ctx->lcid, ctx->id, ctx->result, ctx->status);
if (ctx->cb != NULL) {
ctx->cb(ctx->lcid, result);
}
L2capFree(ctx);
return;
}
void L2CIF_ConnectRsp(
uint16_t lcid, uint8_t id, uint16_t result, uint16_t status, void (*cb)(uint16_t lcid, int result))
{
L2cifConnectRspContext *ctx = NULL;
ctx = L2capAlloc(sizeof(L2cifConnectRspContext));
if (ctx == NULL) {
LOG_WARN("malloc failed");
return;
}
ctx->lcid = lcid;
ctx->id = id;
ctx->result = result;
ctx->status = status;
ctx->cb = cb;
L2capAsynchronousProcess(L2cifConnectRsp, L2capFree, ctx);
return;
}
typedef struct {
uint16_t lcid;
L2capConfigInfo cfg;
void (*cb)(uint16_t lcid, int result);
} L2cifConfigReqContext;
static void L2cifConfigReq(const void *context)
{
L2cifConfigReqContext *ctx = NULL;
int result;
ctx = (L2cifConfigReqContext *)context;
result = L2CAP_ConfigReq(ctx->lcid, &(ctx->cfg));
if (ctx->cb != NULL) {
ctx->cb(ctx->lcid, result);
}
L2capFree(ctx);
return;
}
int L2CIF_ConfigReq(uint16_t lcid, const L2capConfigInfo *cfg, void (*cb)(uint16_t lcid, int result))
{
L2cifConfigReqContext *ctx = NULL;
if (cfg == NULL) {
return BT_BAD_PARAM;
}
ctx = L2capAlloc(sizeof(L2cifConfigReqContext));
if (ctx == NULL) {
return BT_NO_MEMORY;
}
ctx->lcid = lcid;
(void)memcpy_s(&(ctx->cfg), sizeof(L2capConfigInfo), cfg, sizeof(L2capConfigInfo));
ctx->cb = cb;
L2capAsynchronousProcess(L2cifConfigReq, L2capFree, ctx);
return BT_SUCCESS;
}
typedef struct {
uint16_t lcid;
uint8_t id;
L2capConfigInfo cfg;
uint16_t result;
void (*cb)(uint16_t lcid, int result);
} L2cifConfigRspContext;
static void L2cifConfigRsp(const void *context)
{
L2cifConfigRspContext *ctx = NULL;
int result;
ctx = (L2cifConfigRspContext *)context;
result = L2CAP_ConfigRsp(ctx->lcid, ctx->id, &(ctx->cfg), ctx->result);
if (ctx->cb != NULL) {
ctx->cb(ctx->lcid, result);
}
L2capFree(ctx);
return;
}
int L2CIF_ConfigRsp(
uint16_t lcid, uint8_t id, const L2capConfigInfo *cfg, uint16_t result, void (*cb)(uint16_t lcid, int result))
{
L2cifConfigRspContext *ctx = NULL;
if (cfg == NULL) {
return BT_BAD_PARAM;
}
ctx = L2capAlloc(sizeof(L2cifConfigRspContext));
if (ctx == NULL) {
return BT_NO_MEMORY;
}
ctx->lcid = lcid;
ctx->id = id;
(void)memcpy_s(&(ctx->cfg), sizeof(L2capConfigInfo), cfg, sizeof(L2capConfigInfo));
ctx->result = result;
ctx->cb = cb;
L2capAsynchronousProcess(L2cifConfigRsp, L2capFree, ctx);
return BT_SUCCESS;
}
typedef struct {
uint16_t lcid;
void (*cb)(uint16_t lcid, int result);
} L2cifDisconnectionReqContext;
static void L2cifDisconnectionReq(const void *context)
{
L2cifDisconnectionReqContext *ctx = NULL;
int result;
ctx = (L2cifDisconnectionReqContext *)context;
result = L2CAP_DisconnectionReq(ctx->lcid);
if (ctx->cb != NULL) {
ctx->cb(ctx->lcid, result);
}
L2capFree(ctx);
return;
}
void L2CIF_DisconnectionReq(uint16_t lcid, void (*cb)(uint16_t lcid, int result))
{
L2cifDisconnectionReqContext *ctx = NULL;
ctx = L2capAlloc(sizeof(L2cifDisconnectionReqContext));
if (ctx == NULL) {
LOG_WARN("malloc failed");
return;
}
ctx->lcid = lcid;
ctx->cb = cb;
L2capAsynchronousProcess(L2cifDisconnectionReq, L2capFree, ctx);
return;
}
typedef struct {
uint16_t lcid;
uint8_t id;
void (*cb)(uint16_t lcid, int result);
} L2cifDisconnectionRspContext;
static void L2cifDisconnectionRsp(const void *context)
{
L2cifDisconnectionRspContext *ctx = NULL;
int result;
ctx = (L2cifDisconnectionRspContext *)context;
result = L2CAP_DisconnectionRsp(ctx->lcid, ctx->id);
if (ctx->cb != NULL) {
ctx->cb(ctx->lcid, result);
}
L2capFree(ctx);
return;
}
void L2CIF_DisconnectionRsp(uint16_t lcid, uint8_t id, void (*cb)(uint16_t lcid, int result))
{
L2cifDisconnectionRspContext *ctx = NULL;
ctx = L2capAlloc(sizeof(L2cifDisconnectionRspContext));
if (ctx == NULL) {
LOG_WARN("malloc failed");
return;
}
ctx->lcid = lcid;
ctx->id = id;
ctx->cb = cb;
L2capAsynchronousProcess(L2cifDisconnectionRsp, L2capFree, ctx);
return;
}
typedef struct {
uint16_t lcid;
uint8_t isBusy;
void (*cb)(uint16_t lcid, int result);
} L2cifLocalBusyContext;
static void L2cifLocalBusy(const void *context)
{
L2cifLocalBusyContext *ctx = NULL;
int result;
ctx = (L2cifLocalBusyContext *)context;
result = L2CAP_LocalBusy(ctx->lcid, ctx->isBusy);
if (ctx->cb != NULL) {
ctx->cb(ctx->lcid, result);
}
L2capFree(ctx);
return;
}
void L2CIF_LocalBusy(uint16_t lcid, uint8_t isBusy, void (*cb)(uint16_t lcid, int result))
{
L2cifLocalBusyContext *ctx = NULL;
ctx = L2capAlloc(sizeof(L2cifLocalBusyContext));
if (ctx == NULL) {
LOG_WARN("malloc failed");
return;
}
ctx->lcid = lcid;
ctx->isBusy = isBusy;
ctx->cb = cb;
L2capAsynchronousProcess(L2cifLocalBusy, L2capFree, ctx);
return;
}
typedef struct {
uint16_t lcid;
Packet *pkt;
void (*cb)(uint16_t lcid, int result);
} L2cifSendDataContext;
static void L2cifSendDataContextDestroy(void *context)
{
L2cifSendDataContext *ctx = NULL;
ctx = context;
PacketFree(ctx->pkt);
L2capFree(ctx);
return;
}
static void L2cifSendData(const void *context)
{
L2cifSendDataContext *ctx = NULL;
int result;
ctx = (L2cifSendDataContext *)context;
result = L2CAP_SendData(ctx->lcid, ctx->pkt);
if (ctx->cb != NULL) {
ctx->cb(ctx->lcid, result);
}
L2cifSendDataContextDestroy(ctx);
return;
}
int L2CIF_SendData(uint16_t lcid, const Packet *pkt, void (*cb)(uint16_t lcid, int result))
{
L2cifSendDataContext *ctx = NULL;
if (pkt == NULL) {
return BT_BAD_PARAM;
}
ctx = L2capAlloc(sizeof(L2cifSendDataContext));
if (ctx == NULL) {
return BT_NO_MEMORY;
}
ctx->lcid = lcid;
ctx->pkt = PacketRefMalloc((Packet *)pkt);
ctx->cb = cb;
L2capAsynchronousProcess(L2cifSendData, L2cifSendDataContextDestroy, ctx);
return BT_SUCCESS;
}
typedef struct {
L2capEcho echoCallback;
void *context;
} L2cifRegisterEchoContext;
static void L2cifRegisterEcho(const void *context)
{
L2cifRegisterEchoContext *ctx = NULL;
ctx = (L2cifRegisterEchoContext *)context;
L2CAP_RegisterEcho(&(ctx->echoCallback), ctx->context);
L2capFree(ctx);
return;
}
int L2CIF_RegisterEcho(const L2capEcho *echoCallback, void *context)
{
L2cifRegisterEchoContext *ctx = NULL;
if (echoCallback == NULL) {
return BT_BAD_PARAM;
}
ctx = L2capAlloc(sizeof(L2cifRegisterEchoContext));
if (ctx == NULL) {
return BT_NO_MEMORY;
}
(void)memcpy_s(&(ctx->echoCallback), sizeof(L2capEcho), echoCallback, sizeof(L2capEcho));
ctx->context = context;
L2capAsynchronousProcess(L2cifRegisterEcho, L2capFree, ctx);
return BT_SUCCESS;
}
static void L2cifDeregisterEcho(const void *context)
{
L2CAP_DeregisterEcho();
return;
}
void L2CIF_DeregisterEcho()
{
L2capAsynchronousProcess(L2cifDeregisterEcho, NULL, NULL);
return;
}
typedef struct {
uint16_t aclHandle;
uint8_t *data;
uint16_t dataLen;
void (*cb)(uint16_t aclHandle, int result);
} L2cifEchoReqContext;
static void L2cifEchoReqContextDestroy(void *context)
{
L2cifEchoReqContext *ctx = NULL;
ctx = context;
if (ctx->data != NULL) {
L2capFree(ctx->data);
}
L2capFree(ctx);
return;
}
static void L2cifEchoReq(const void *context)
{
L2cifEchoReqContext *ctx = NULL;
int result;
ctx = (L2cifEchoReqContext *)context;
result = L2CAP_EchoReq(ctx->aclHandle, ctx->data, ctx->dataLen);
if (ctx->cb != NULL) {
ctx->cb(ctx->aclHandle, result);
}
L2cifEchoReqContextDestroy(ctx);
return;
}
void L2CIF_EchoReq(
uint16_t aclHandle, const uint8_t *data, uint16_t dataLen, void (*cb)(uint16_t aclHandle, int result))
{
L2cifEchoReqContext *ctx = NULL;
ctx = L2capAlloc(sizeof(L2cifEchoReqContext));
if (ctx == NULL) {
LOG_WARN("malloc failed");
return;
}
ctx->aclHandle = aclHandle;
ctx->data = NULL;
ctx->dataLen = 0;
ctx->cb = cb;
if (data != NULL) {
ctx->data = L2capAlloc(dataLen);
if (ctx->data == NULL) {
LOG_WARN("malloc failed");
return;
}
(void)memcpy_s(ctx->data, dataLen, data, dataLen);
ctx->dataLen = dataLen;
}
L2capAsynchronousProcess(L2cifEchoReq, L2cifEchoReqContextDestroy, ctx);
return;
}
typedef struct {
uint16_t aclHandle;
uint8_t id;
uint8_t *data;
uint16_t dataLen;
void (*cb)(uint16_t aclHandle, int result);
} L2cifEchoRspContext;
static void L2cifEchoRspContextDestroy(void *context)
{
L2cifEchoRspContext *ctx = NULL;
ctx = context;
if (ctx->data != NULL) {
L2capFree(ctx->data);
}
L2capFree(ctx);
return;
}
static void L2cifEchoRsp(const void *context)
{
L2cifEchoRspContext *ctx = NULL;
int result;
ctx = (L2cifEchoRspContext *)context;
result = L2CAP_EchoRsp(ctx->aclHandle, ctx->id, ctx->data, ctx->dataLen);
if (ctx->cb != NULL) {
ctx->cb(ctx->aclHandle, result);
}
L2cifEchoRspContextDestroy(ctx);
return;
}
void L2CIF_EchoRsp(
uint16_t aclHandle, uint8_t id, const uint8_t *data, uint16_t dataLen, void (*cb)(uint16_t aclHandle, int result))
{
L2cifEchoRspContext *ctx = NULL;
ctx = L2capAlloc(sizeof(L2cifEchoRspContext));
if (ctx == NULL) {
LOG_WARN("malloc failed");
return;
}
ctx->aclHandle = aclHandle;
ctx->id = id;
ctx->data = NULL;
ctx->dataLen = 0;
ctx->cb = cb;
if (data != NULL) {
ctx->data = L2capAlloc(dataLen);
if (ctx->data == NULL) {
LOG_WARN("malloc failed");
return;
}
(void)memcpy_s(ctx->data, dataLen, data, dataLen);
ctx->dataLen = dataLen;
}
L2capAsynchronousProcess(L2cifEchoRsp, L2cifEchoRspContextDestroy, ctx);
return;
}
typedef struct {
Semaphore *sem;
int traceLevel;
} L2cifContext;
static void L2cifStartup(void *context)
{
L2cifContext *ctx = NULL;
ctx = context;
L2CAP_Initialize(ctx->traceLevel);
SemaphorePost(ctx->sem);
L2capFree(ctx);
return;
}
void L2CIF_Startup()
{
int result;
L2cifContext *ctx = NULL;
Semaphore *sem = NULL;
result = BTM_CreateProcessingQueue(PROCESSING_QUEUE_ID_LA2CAP, BTM_PROCESSING_QUEUE_SIZE_DEFAULT);
if (result != BT_SUCCESS) {
return;
}
sem = SemaphoreCreate(0);
if (sem == NULL) {
LOG_WARN("malloc failed");
return;
}
ctx = L2capAlloc(sizeof(L2cifContext));
if (ctx == NULL) {
LOG_WARN("malloc failed");
SemaphoreDelete(sem);
return;
}
ctx->sem = sem;
ctx->traceLevel = 0;
result = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_LA2CAP, L2cifStartup, ctx);
if (result != BT_SUCCESS) {
L2capFree(ctx);
SemaphoreDelete(sem);
return;
}
SemaphoreWait(sem);
SemaphoreDelete(sem);
return;
}
static void L2cifShutdown(void *context)
{
L2cifContext *ctx = NULL;
ctx = context;
L2CAP_Finalize();
BTM_DeleteProcessingQueue(PROCESSING_QUEUE_ID_LA2CAP);
SemaphorePost(ctx->sem);
L2capFree(ctx);
return;
}
void L2CIF_Shutdown()
{
int result;
L2cifContext *ctx = NULL;
Semaphore *sem = NULL;
sem = SemaphoreCreate(0);
if (sem == NULL) {
LOG_WARN("malloc failed");
return;
}
ctx = L2capAlloc(sizeof(L2cifContext));
if (ctx == NULL) {
LOG_WARN("malloc failed");
SemaphoreDelete(sem);
return;
}
ctx->sem = sem;
ctx->traceLevel = 0;
result = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_LA2CAP, L2cifShutdown, ctx);
if (result != BT_SUCCESS) {
L2capFree(ctx);
SemaphoreDelete(sem);
return;
}
SemaphoreWait(sem);
SemaphoreDelete(sem);
return;
}
void L2CIF_Initialize(int traceLevel)
{
return;
}
void L2CIF_Finalize()
{
return;
}
static Module g_l2cap = {
.name = MODULE_NAME_L2CAP,
.init = L2CIF_Initialize,
.startup = L2CIF_Startup,
.shutdown = L2CIF_Shutdown,
.cleanup = L2CIF_Finalize,
.dependencies = {MODULE_NAME_HCI},
};
MODULE_DECL(g_l2cap);