/*
* 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"
typedef struct {
uint16_t result;
GapServiceSecurityInfo serviceInfo;
void *context;
} RfcommSecurityResultInfo;
static void RfcommRecvChannelSecurityResultTsk(void *context)
{
LOG_INFO("%{public}s", __func__);
RfcommSecurityResultInfo *ctx = context;
if (ctx == NULL) {
LOG_ERROR("%{public}s context is NULL.", __func__);
return;
}
RfcommRecvChannelSecurityResult(ctx->result, ctx->serviceInfo, ctx->context);
free(ctx);
}
/**
* @brief This is the callback function registered when GAPIF_RequestSecurityAsync is called
* to receive the result of the security check.
*
* @param result The result of the security check.
* @param serviceInfo server information.
* @param context The context passed in when calling GAPIF_RequestSecurityAsync.
*/
static void RfcommRecvChannelSecurityResultCallback(uint16_t result, GapServiceSecurityInfo serviceInfo, void *context)
{
LOG_INFO("%{public}s result:%hu", __func__, result);
if (context == NULL) {
LOG_ERROR("%{public}s:DLC is closed.", __func__);
return;
}
RfcommSecurityResultInfo *ctx = malloc(sizeof(RfcommSecurityResultInfo));
if (ctx == NULL) {
return;
}
(void)memset_s(ctx, sizeof(RfcommSecurityResultInfo), 0x00, sizeof(RfcommSecurityResultInfo));
ctx->result = result;
ctx->context = context;
(void)memcpy_s(&ctx->serviceInfo, sizeof(GapServiceSecurityInfo), &serviceInfo, sizeof(GapServiceSecurityInfo));
int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommRecvChannelSecurityResultTsk, ctx);
if (ret != BT_SUCCESS) {
free(ctx);
}
}
static void RfcommRecvSessionSecurityResultTsk(void *context)
{
LOG_INFO("%{public}s", __func__);
RfcommSecurityResultInfo *ctx = context;
if (ctx == NULL) {
LOG_ERROR("%{public}s context is NULL.", __func__);
return;
}
RfcommRecvSessionSecurityResult(ctx->result, ctx->serviceInfo, ctx->context);
free(ctx);
}
static void RfcommRecvSessionSecurityResultCallback(uint16_t result, GapServiceSecurityInfo serviceInfo, void *context)
{
LOG_INFO("%{public}s result:%hu", __func__, result);
if (context == NULL) {
LOG_ERROR("%{public}s:Session is closed.", __func__);
return;
}
RfcommSecurityResultInfo *ctx = malloc(sizeof(RfcommSecurityResultInfo));
if (ctx == NULL) {
return;
}
(void)memset_s(ctx, sizeof(RfcommSecurityResultInfo), 0x00, sizeof(RfcommSecurityResultInfo));
ctx->result = result;
ctx->context = context;
(void)memcpy_s(&ctx->serviceInfo, sizeof(GapServiceSecurityInfo), &serviceInfo, sizeof(GapServiceSecurityInfo));
int ret = BTM_RunTaskInProcessingQueue(PROCESSING_QUEUE_ID_RFCOMM, RfcommRecvSessionSecurityResultTsk, ctx);
if (ret != BT_SUCCESS) {
free(ctx);
}
}
/**
* @brief Before initiating a connection or accepting a connection,
* the GAP interface is called to perform a security check.
*
* @param channel The pointer of the channel in the channel list.
* @param isServer Server side:true, client side:false.
* @return Returns RFCOMM_SUCCESS if the operation is successful, otherwise the operation fails.
*/
int RfcommCheckChannelSecurity(RfcommChannelInfo *channel, bool isServer)
{
LOG_INFO("%{public}s isServer:%{public}d", __func__, isServer);
GapRequestSecurityParam param;
(void)memset_s(¶m, sizeof(GapRequestSecurityParam), 0x00, sizeof(GapRequestSecurityParam));
param.callback = RfcommRecvChannelSecurityResultCallback;
param.info.channelId.rfcommChannel = channel->dlci >> RFCOMM_DLCI_SHIFT_SCN;
param.info.direction = isServer ? INCOMING : OUTGOING;
param.info.protocolId = SEC_PROTOCOL_RFCOMM;
param.info.serviceId = UNKNOWN_SERVICE;
param.context = channel;
int ret = GAPIF_RequestSecurityAsync(&(channel->session->btAddr), ¶m);
if (ret != BT_SUCCESS) {
LOG_DEBUG("%{public}s return error.", __func__);
}
return ret;
}
/**
* @brief Before initiating a connection or accepting a L2CAP connection,
* the GAP interface is called to perform a security check.
*
* @param session The pointer of the session in the session list.
* @param scn The rfcomm server channel number(Valid if this is initiator).
* @param isServer Server side:true, client side:false.
* @return Returns RFCOMM_SUCCESS if the operation is successful, otherwise the operation fails.
*/
int RfcommCheckSessionSecurity(RfcommSessionInfo *session, uint8_t scn, bool isServer)
{
LOG_INFO("%{public}s isServer:%{public}d", __func__, isServer);
GapRequestSecurityParam param;
(void)memset_s(¶m, sizeof(GapRequestSecurityParam), 0x00, sizeof(GapRequestSecurityParam));
param.callback = RfcommRecvSessionSecurityResultCallback;
param.context = (void*)session;
if (isServer) {
param.info.direction = INCOMING;
param.info.serviceId = RFCOMM;
param.info.protocolId = SEC_PROTOCOL_L2CAP;
param.info.channelId.l2capPsm = BT_PSM_RFCOMM;
} else {
param.info.direction = OUTGOING;
param.info.serviceId = UNKNOWN_SERVICE;
param.info.protocolId = SEC_PROTOCOL_RFCOMM;
param.info.channelId.rfcommChannel = scn;
}
int ret = GAPIF_RequestSecurityAsync(&(session->btAddr), ¶m);
if (ret != BT_SUCCESS) {
LOG_DEBUG("%{public}s return error.", __func__);
}
return ret;
}
/**
* @brief Register security information to GAP.
*
*/
void RfcommRegisterSecurity()
{
LOG_INFO("%{public}s", __func__);
GapServiceSecurityInfo serviceInfo = {INCOMING, RFCOMM, SEC_PROTOCOL_L2CAP, {BT_PSM_RFCOMM}};
int ret = GAPIF_RegisterServiceSecurityAsync(NULL, &serviceInfo, 0);
if (ret != BT_SUCCESS) {
LOG_DEBUG("%{public}s return error.", __func__);
}
}
/**
* @brief Deregister security information to GAP.
*
*/
void RfcommDeregisterSecurity()
{
LOG_INFO("%{public}s", __func__);
GapServiceSecurityInfo serviceInfo = {INCOMING, RFCOMM, SEC_PROTOCOL_L2CAP, {BT_PSM_RFCOMM}};
int ret = GAPIF_DeregisterServiceSecurityAsync(NULL, &serviceInfo);
if (ret != BT_SUCCESS) {
LOG_DEBUG("%{public}s return error.", __func__);
}
}