* 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 "gap_le.h"
#include "gap_internal.h"
#include <securec.h>
#include "allocator.h"
#include "log.h"
#include "thread.h"
#include "btm/btm_le_sec.h"
#include "btm/btm_thread.h"
#include "hci/hci.h"
#include "hci/hci_error.h"
#include "smp/smp.h"
typedef enum {
ADV_REPORT,
EXTENDED_ADV_REPORT,
DIRECTED_ADV_REPORT,
} AdvReportType;
typedef struct {
AdvReportType reportType;
void *report;
bool processing;
BtmIdentityResolvingKey *IRKList;
uint16_t listCount;
uint16_t resolveIndex;
BtAddr addr;
bool doCallback;
} AdvReportRPAResolveInfo;
typedef struct {
GapScanCallback callback;
void *context;
} LeScanCallback;
typedef struct {
GapExScanCallback callback;
void *context;
} LeExScanCallback;
static LeScanCallback g_leScanCallback;
static LeExScanCallback g_leExScanCallback;
void GapFreeReportRPAResolveInfo(void *data)
{
AdvReportRPAResolveInfo *info = data;
switch (info->reportType) {
case ADV_REPORT: {
HciLeAdvertisingReport *report = info->report;
MEM_MALLOC.free(report->data);
break;
}
case EXTENDED_ADV_REPORT: {
HciLeExtendedAdvertisingReport *report = info->report;
MEM_MALLOC.free(report->data);
break;
}
case DIRECTED_ADV_REPORT:
default:
break;
}
MEM_MALLOC.free(info->report);
MEM_MALLOC.free(info->IRKList);
MEM_MALLOC.free(info);
}
int GAP_RegisterScanCallback(const GapScanCallback *callback, void *context)
{
LOG_INFO("%{public}s:%{public}s", __FUNCTION__, callback ? "register" : "NULL");
if (callback == NULL) {
(void)memset_s(
&g_leScanCallback.callback, sizeof(g_leScanCallback.callback), 0x00, sizeof(g_leScanCallback.callback));
} else {
g_leScanCallback.callback = *callback;
}
g_leScanCallback.context = context;
return GAP_SUCCESS;
}
int GAP_DeregisterScanCallback(void)
{
(void)memset_s(
&g_leScanCallback.callback, sizeof(g_leScanCallback.callback), 0x00, sizeof(g_leScanCallback.callback));
g_leScanCallback.context = NULL;
return GAP_SUCCESS;
}
int GAP_LeScanSetParam(GapLeScanParam param, uint8_t scanFilterPolity)
{
LOG_INFO("%{public}s:", __FUNCTION__);
int ret;
if (GapIsLeEnable() == false) {
return GAP_ERR_NOT_ENABLE;
}
if (GapLeRolesCheck(GAP_LE_ROLE_OBSERVER | GAP_LE_ROLE_CENTRAL) == false) {
ret = GAP_ERR_INVAL_STATE;
} else {
HciLeSetScanParametersParam hciCmdParam = {
.leScanType = param.scanType,
.leScanInterval = param.param.scanInterval,
.leScanWindow = param.param.scanWindow,
.ownAddressType = BTM_GetOwnAddressType(),
.scanningFilterPolicy = scanFilterPolity,
};
ret = HCI_LeSetScanParameters(&hciCmdParam);
}
return ret;
}
void GapLeScanSetParamComplete(const HciLeSetExtendedScanParametersReturnParam *param)
{
if (g_leScanCallback.callback.scanSetParamResult) {
g_leScanCallback.callback.scanSetParamResult(param->status, g_leScanCallback.context);
}
}
static void GapLeSetExAdvReportParam(GapExAdvReportParam *advParam, const HciLeExtendedAdvertisingReport *report)
{
if (advParam != NULL && report != NULL) {
advParam->advertisingSid = report->advertisingSID;
advParam->data = report->data;
advParam->dataLen = report->dataLength;
advParam->periodicAdvInterval = report->periodicAdvertisingInterval;
advParam->primaryPhy = report->primaryPHY;
advParam->rssi = report->rssi;
advParam->secondaryPhy = report->secondaryPHY;
advParam->txPower = report->txPower;
}
}
static void GapCallbackRPAAdvertisingReport(const AdvReportRPAResolveInfo *info, const BtAddr *currentAddr)
{
if (info == NULL) {
LOG_WARN("%{public}s: miss info", __FUNCTION__);
return;
}
HciLeAdvertisingReport *report = info->report;
if (report == NULL || (report->lengthData != 0 && report->data == NULL)) {
LOG_WARN("%{public}s: miss report or data", __FUNCTION__);
return;
}
LOG_INFO("%{public}s:" BT_ADDR_FMT " -> " BT_ADDR_FMT,
__FUNCTION__,
BT_ADDR_FMT_OUTPUT(report->address.raw),
BT_ADDR_FMT_OUTPUT(info->addr.addr));
if (g_leScanCallback.callback.advertisingReport) {
GapAdvReportParam reportParam = {
.dataLen = report->lengthData,
.data = report->data,
.rssi = report->rssi,
};
g_leScanCallback.callback.advertisingReport(
report->eventType, &info->addr, reportParam, currentAddr, g_leScanCallback.context);
}
}
static void GapCallbackRPAExtendedAdvertisingReport(const AdvReportRPAResolveInfo *info, const BtAddr *currentAddr)
{
if (info == NULL) {
LOG_WARN("%{public}s: miss info.", __FUNCTION__);
return;
}
HciLeExtendedAdvertisingReport *report = info->report;
GapExAdvReportParam advParam;
BtAddr directAddr;
if (report == NULL || ((report->dataLength != 0) && (report->data == NULL))) {
LOG_WARN("%{public}s: miss report or data", __FUNCTION__);
return;
}
GapLeSetExAdvReportParam(&advParam, report);
advParam.directAddr = &directAddr;
GapChangeHCIAddr(&directAddr, &report->directAddress, report->directAddressType);
LOG_INFO("%{public}s:" BT_ADDR_FMT " -> " BT_ADDR_FMT,
__FUNCTION__,
BT_ADDR_FMT_OUTPUT(report->address.raw),
BT_ADDR_FMT_OUTPUT(info->addr.addr));
if (g_leExScanCallback.callback.exAdvertisingReport) {
g_leExScanCallback.callback.exAdvertisingReport(
report->eventType, &info->addr, advParam, currentAddr, g_leExScanCallback.context);
}
}
static void GapCallbackRPADirectedAdvertisingReport(const AdvReportRPAResolveInfo *info, const BtAddr *currentAddr)
{
if (info == NULL || info->report == NULL) {
LOG_WARN("%{public}s: miss info or report", __FUNCTION__);
return;
}
HciLeDirectedAdvertisingReport *report = info->report;
BtAddr directAddr;
GapChangeHCIAddr(&directAddr, &report->directAddress, report->directAddressType);
LOG_INFO("%{public}s:" BT_ADDR_FMT " -> " BT_ADDR_FMT,
__FUNCTION__,
BT_ADDR_FMT_OUTPUT(report->address.raw),
BT_ADDR_FMT_OUTPUT(info->addr.addr));
if (g_leExScanCallback.callback.directedAdvertisingReport) {
GapDirectedAdvReportParam reportParam = {
.directAddr = &directAddr,
.rssi = report->rssi,
};
g_leExScanCallback.callback.directedAdvertisingReport(
report->eventType, &info->addr, reportParam, currentAddr, g_leExScanCallback.context);
}
}
void GapDoCallbackRPAAdvertisingReport(void *data, const BtAddr *currentAddr)
{
AdvReportRPAResolveInfo *info = data;
switch (info->reportType) {
case ADV_REPORT: {
GapCallbackRPAAdvertisingReport(info, currentAddr);
break;
}
case EXTENDED_ADV_REPORT: {
GapCallbackRPAExtendedAdvertisingReport(info, currentAddr);
break;
}
case DIRECTED_ADV_REPORT: {
GapCallbackRPADirectedAdvertisingReport(info, currentAddr);
break;
}
default:
break;
}
ListRemoveNode(GapGetLeRandomAddressBlock()->reportRPAResolveList, data);
}
void GapRPAResolveProcess(void)
{
int ret;
ListNode *node = ListGetFirstNode(GapGetLeRandomAddressBlock()->reportRPAResolveList);
while (node != 0) {
AdvReportRPAResolveInfo *info = ListGetNodeData(node);
if (info->processing) {
break;
}
if (!info->doCallback) {
LOG_DEBUG("%{public}s: " BT_ADDR_FMT " start resolve RPA",
__FUNCTION__, BT_ADDR_FMT_OUTPUT(info->addr.addr));
uint8_t addr[BT_ADDRESS_SIZE];
(void)memcpy_s(addr, BT_ADDRESS_SIZE, info->addr.addr, BT_ADDRESS_SIZE);
const uint8_t *addrPtr = addr;
const uint8_t *keyPtr = info->IRKList[info->resolveIndex].irk.key;
ret = SMP_AsyncResolveRPA(addrPtr, keyPtr);
if (ret != BT_SUCCESS) {
info->doCallback = true;
GapDoCallbackRPAAdvertisingReport(info, NULL);
} else {
info->processing = true;
}
break;
}
node = ListGetNextNode(node);
}
}
void GapResolveRPAResult(uint8_t status, bool result, const uint8_t *addr, const uint8_t *irk)
{
LOG_INFO("%{public}s: status:%02x, result:%02x", __FUNCTION__, status, result);
ListNode *node = ListGetFirstNode(GapGetLeRandomAddressBlock()->reportRPAResolveList);
while (node != 0) {
AdvReportRPAResolveInfo *info = ListGetNodeData(node);
BtAddr currentAddr = info->addr;
node = ListGetNextNode(node);
if (!info->processing) {
continue;
}
info->processing = false;
if (status == SMP_PAIR_STATUS_SUCCESS && result == true) {
if (memcmp(info->IRKList[info->resolveIndex].irk.key, irk, GAP_IRK_SIZE)) {
LOG_ERROR("%{public}s: IRK mismatch", __FUNCTION__);
} else {
BTM_UpdateCurrentRemoteAddress(&info->IRKList[info->resolveIndex].addr, &info->addr);
(void)memcpy_s(&info->addr, sizeof(BtAddr), &info->IRKList[info->resolveIndex].addr, sizeof(BtAddr));
}
info->doCallback = true;
} else {
info->resolveIndex++;
if (info->resolveIndex == info->listCount) {
info->doCallback = true;
}
}
if (info->doCallback) {
GapDoCallbackRPAAdvertisingReport(info, result ? ¤tAddr : NULL);
}
break;
}
GapRPAResolveProcess();
}
static AdvReportRPAResolveInfo *GapLeAllocAdvReportRPAResolveInfo(
BtAddr addr, AdvReportType type, const void *advReport)
{
AdvReportRPAResolveInfo *info = MEM_MALLOC.alloc(sizeof(AdvReportRPAResolveInfo));
void *report = NULL;
uint8_t *advData = NULL;
if (type == ADV_REPORT) {
advData = MEM_MALLOC.alloc(((const HciLeAdvertisingReport *)advReport)->lengthData);
if (advData != NULL) {
(void)memcpy_s(advData,
((const HciLeAdvertisingReport *)advReport)->lengthData,
((const HciLeAdvertisingReport *)advReport)->data,
((const HciLeAdvertisingReport *)advReport)->lengthData);
}
report = MEM_MALLOC.alloc(sizeof(HciLeAdvertisingReport));
if (report != NULL) {
(void)memcpy_s(report, sizeof(HciLeAdvertisingReport), advReport, sizeof(HciLeAdvertisingReport));
((HciLeAdvertisingReport *)report)->data = advData;
}
} else if (type == EXTENDED_ADV_REPORT) {
advData = MEM_MALLOC.alloc(((const HciLeExtendedAdvertisingReport *)advReport)->dataLength);
if (advData != NULL) {
(void)memcpy_s(advData,
((const HciLeExtendedAdvertisingReport *)advReport)->dataLength,
((const HciLeExtendedAdvertisingReport *)advReport)->data,
((const HciLeExtendedAdvertisingReport *)advReport)->dataLength);
}
report = MEM_MALLOC.alloc(sizeof(HciLeExtendedAdvertisingReport));
if (report != NULL) {
(void)memcpy_s(
report, sizeof(HciLeExtendedAdvertisingReport), advReport, sizeof(HciLeExtendedAdvertisingReport));
((HciLeExtendedAdvertisingReport *)report)->data = advData;
}
} else if (type == DIRECTED_ADV_REPORT) {
report = MEM_MALLOC.alloc(sizeof(HciLeDirectedAdvertisingReport));
if (report != NULL) {
(void)memcpy_s(
report, sizeof(HciLeDirectedAdvertisingReport), advReport, sizeof(HciLeDirectedAdvertisingReport));
}
}
if (info != NULL) {
info->report = report;
info->reportType = type;
info->resolveIndex = 0;
info->processing = false;
info->doCallback = false;
(void)memcpy_s(&info->addr, sizeof(BtAddr), &addr, sizeof(BtAddr));
}
return info;
}
static bool GapTryChangeAddressForIdentityAddress(BtAddr *addr)
{
BtAddr pairedAddr = {0};
int ret = BTM_GetPairdAddressFromRemoteIdentityAddress(addr, &pairedAddr);
if (ret == BT_SUCCESS) {
LOG_INFO("%{public}s:" BT_ADDR_FMT " -> " BT_ADDR_FMT,
__FUNCTION__,
BT_ADDR_FMT_OUTPUT(addr->addr),
BT_ADDR_FMT_OUTPUT(pairedAddr.addr));
*addr = pairedAddr;
return true;
}
return false;
}
static void GapOnLeAdvertisingReportEventProcessOnce(const HciLeAdvertisingReport *report)
{
BtAddr addr;
GapChangeHCIAddr(&addr, &report->address, report->addressType);
BtAddr currentAddr = addr;
uint8_t advType = report->eventType;
uint8_t rssi = report->rssi;
uint8_t dataLen = report->lengthData;
uint8_t *data = report->data;
if (GapAddrIsResolvablePrivateAddress(&addr)) {
BtmIdentityResolvingKey *deviceIRKList = NULL;
uint16_t listCount = 0;
int ret = BTM_GetAllRemoteIdentityResolvingKey(&deviceIRKList, &listCount);
if (ret == BT_SUCCESS && listCount != 0) {
AdvReportRPAResolveInfo *info = GapLeAllocAdvReportRPAResolveInfo(addr, ADV_REPORT, report);
if (info != NULL) {
info->IRKList = deviceIRKList;
info->listCount = listCount;
ListAddLast(GapGetLeRandomAddressBlock()->reportRPAResolveList, info);
GapRPAResolveProcess();
return;
}
}
if (deviceIRKList != NULL) {
MEM_MALLOC.free(deviceIRKList);
}
} else if (GapAddrIsIdentityAddress(&addr)) {
GapTryChangeAddressForIdentityAddress(&addr);
} else if (GapAddrIsStaticAddress(&addr) || GapAddrIsPublicAddress(&addr)) {
if (GapTryChangeAddressForIdentityAddress(&addr)) {
BTM_UpdateCurrentRemoteAddress(&addr, ¤tAddr);
}
}
LOG_INFO("%{public}s:" BT_ADDR_FMT " type=%hhu", __FUNCTION__, BT_ADDR_FMT_OUTPUT(addr.addr), addr.type);
if (g_leScanCallback.callback.advertisingReport) {
GapAdvReportParam reportParam = {
.dataLen = dataLen,
.data = data,
.rssi = rssi,
};
g_leScanCallback.callback.advertisingReport(advType, &addr, reportParam, NULL, g_leScanCallback.context);
}
}
void GapOnLeAdvertisingReportEvent(const HciLeAdvertisingReportEventParam *eventParam)
{
for (uint8_t i = 0; i < eventParam->numReports; i++) {
GapOnLeAdvertisingReportEventProcessOnce(&eventParam->reports[i]);
}
}
int GAP_LeScanSetEnable(uint8_t scanEnable, uint8_t filterDuplicates)
{
LOG_INFO("%{public}s:", __FUNCTION__);
int ret;
if (GapIsLeEnable() == false) {
return GAP_ERR_NOT_ENABLE;
}
if (GapLeRolesCheck(GAP_LE_ROLE_OBSERVER | GAP_LE_ROLE_CENTRAL) == false) {
ret = GAP_ERR_INVAL_STATE;
} else {
HciLeSetScanEnableParam hciCmdParam = {
.leScanEnable = scanEnable,
.filterDuplicates = filterDuplicates,
};
ret = HCI_LeSetScanEnable(&hciCmdParam);
}
return ret;
}
void GapLeScanSetEnableComplete(const HciLeSetScanEnableReturnParam *param)
{
if (g_leScanCallback.callback.scanSetEnableResult) {
g_leScanCallback.callback.scanSetEnableResult(param->status, g_leScanCallback.context);
}
}
int GAP_RegisterExScanCallback(const GapExScanCallback *callback, void *context)
{
LOG_INFO("%{public}s:%{public}s", __FUNCTION__, callback ? "register" : "NULL");
if (callback == NULL) {
(void)memset_s(&g_leExScanCallback.callback,
sizeof(g_leExScanCallback.callback),
0x00,
sizeof(g_leExScanCallback.callback));
} else {
g_leExScanCallback.callback = *callback;
}
g_leExScanCallback.context = context;
return GAP_SUCCESS;
}
int GAP_DeregisterExScanCallback(void)
{
(void)memset_s(
&g_leExScanCallback.callback, sizeof(g_leExScanCallback.callback), 0x00, sizeof(g_leExScanCallback.callback));
g_leExScanCallback.context = NULL;
return GAP_SUCCESS;
}
NO_SANITIZE("cfi")
static void GapOnLeExtendedAdvertisingReportEventProcessOnce(const HciLeExtendedAdvertisingReport *report)
{
BtAddr addr;
GapChangeHCIAddr(&addr, &report->address, report->addressType);
BtAddr currentAddr = addr;
uint8_t advType = report->eventType;
GapExAdvReportParam advParam;
BtAddr directAddr;
GapLeSetExAdvReportParam(&advParam, report);
GapChangeHCIAddr(&directAddr, &report->directAddress, report->directAddressType);
advParam.directAddr = &directAddr;
if (GapAddrIsResolvablePrivateAddress(&addr)) {
BtmIdentityResolvingKey *deviceIRKList = NULL;
uint16_t listCount = 0;
int ret = BTM_GetAllRemoteIdentityResolvingKey(&deviceIRKList, &listCount);
if (ret == BT_SUCCESS && listCount != 0) {
AdvReportRPAResolveInfo *info = GapLeAllocAdvReportRPAResolveInfo(addr, EXTENDED_ADV_REPORT, report);
if (info != NULL) {
info->IRKList = deviceIRKList;
info->listCount = listCount;
ListAddLast(GapGetLeRandomAddressBlock()->reportRPAResolveList, info);
GapRPAResolveProcess();
return;
}
}
if (deviceIRKList != NULL) {
MEM_MALLOC.free(deviceIRKList);
}
} else if (GapAddrIsIdentityAddress(&addr)) {
GapTryChangeAddressForIdentityAddress(&addr);
} else if (GapAddrIsStaticAddress(&addr) || GapAddrIsPublicAddress(&addr)) {
if (GapTryChangeAddressForIdentityAddress(&addr)) {
BTM_UpdateCurrentRemoteAddress(&addr, ¤tAddr);
}
}
LOG_INFO("%{public}s:" BT_ADDR_FMT " type=%hhu", __FUNCTION__, BT_ADDR_FMT_OUTPUT(addr.addr), addr.type);
if (g_leExScanCallback.callback.exAdvertisingReport) {
g_leExScanCallback.callback.exAdvertisingReport(advType, &addr, advParam, NULL, g_leExScanCallback.context);
}
}
void GapOnLeExtendedAdvertisingReportEvent(const HciLeExtendedAdvertisingReportEventParam *eventParam)
{
for (uint8_t i = 0; i < eventParam->numReports; i++) {
GapOnLeExtendedAdvertisingReportEventProcessOnce(&eventParam->reports[i]);
}
}
static void GapOnLeDirectedAdvertisingReportProcessOnce(const HciLeDirectedAdvertisingReport *report)
{
BtAddr addr;
GapChangeHCIAddr(&addr, &report->address, report->addressType);
BtAddr currentAddr = addr;
uint8_t advType = report->eventType;
BtAddr directAddr;
GapChangeHCIAddr(&directAddr, &report->directAddress, report->directAddressType);
int8_t rssi = report->rssi;
if (GapAddrIsResolvablePrivateAddress(&addr)) {
BtmIdentityResolvingKey *deviceIRKList = NULL;
uint16_t listCount = 0;
int ret = BTM_GetAllRemoteIdentityResolvingKey(&deviceIRKList, &listCount);
if (ret == BT_SUCCESS && listCount != 0) {
AdvReportRPAResolveInfo *info = GapLeAllocAdvReportRPAResolveInfo(addr, DIRECTED_ADV_REPORT, report);
if (info != NULL) {
info->IRKList = deviceIRKList;
info->listCount = listCount;
ListAddLast(GapGetLeRandomAddressBlock()->reportRPAResolveList, info);
GapRPAResolveProcess();
return;
}
}
if (deviceIRKList != NULL) {
MEM_MALLOC.free(deviceIRKList);
}
} else if (GapAddrIsIdentityAddress(&addr)) {
GapTryChangeAddressForIdentityAddress(&addr);
} else if (GapAddrIsStaticAddress(&addr) || GapAddrIsPublicAddress(&addr)) {
if (GapTryChangeAddressForIdentityAddress(&addr)) {
BTM_UpdateCurrentRemoteAddress(&addr, ¤tAddr);
}
}
LOG_INFO("%{public}s:" BT_ADDR_FMT " type=%hhu", __FUNCTION__, BT_ADDR_FMT_OUTPUT(addr.addr), addr.type);
if (g_leExScanCallback.callback.directedAdvertisingReport) {
GapDirectedAdvReportParam reportParam = {
.directAddr = &directAddr,
.rssi = rssi,
};
g_leExScanCallback.callback.directedAdvertisingReport(
advType, &addr, reportParam, NULL, g_leExScanCallback.context);
}
}
void GapOnLeDirectedAdvertisingReport(const HciLeDirectedAdvertisingReportEventParam *eventParam)
{
for (uint8_t i = 0; i < eventParam->numReports; i++) {
GapOnLeDirectedAdvertisingReportProcessOnce(&eventParam->reports[i]);
}
}
void GapOnLeScanTimeoutEvent(const void *eventParam)
{
if (g_leExScanCallback.callback.scanTimeoutEvent) {
g_leExScanCallback.callback.scanTimeoutEvent(g_leExScanCallback.context);
}
}
static int GapLeSetExtendedScanParameters(
uint8_t ownAddrType, uint8_t scanFilterPolity, uint8_t scanPhys, const GapLeScanParam param[])
{
int ret;
HciLeSetExtendedScanParametersParam hciCmdParam;
hciCmdParam.ownAddressType = ownAddrType;
hciCmdParam.ScanningFilterPolicy = scanFilterPolity;
hciCmdParam.ScanningPHYs = scanPhys;
hciCmdParam.sets = MEM_MALLOC.alloc(EXTENDED_SCAN_PHY_MAX_NUM * sizeof(HciLeExtendedScanParametersSet));
if (hciCmdParam.sets) {
for (uint8_t i = 0, jj = 0; i < EXTENDED_SCAN_PHY_MAX_NUM; i++) {
if ((scanPhys >> i) & 0x01) {
hciCmdParam.sets[jj].scanInterval = param[jj].param.scanInterval;
hciCmdParam.sets[jj].scanWindow = param[jj].param.scanWindow;
hciCmdParam.sets[jj].scanType = param[jj].scanType;
jj++;
}
}
ret = HCI_LeSetExtendedScanParameters(&hciCmdParam);
MEM_MALLOC.free(hciCmdParam.sets);
} else {
ret = GAP_ERR_OUT_OF_RES;
}
return ret;
}
NO_SANITIZE("cfi") void GapLeSetExtendedScanParametersComplete(const HciLeSetExtendedScanParametersReturnParam *param)
{
if (g_leExScanCallback.callback.scanExSetParamResult) {
g_leExScanCallback.callback.scanExSetParamResult(param->status, g_leExScanCallback.context);
}
}
int GAP_LeExScanSetParam(uint8_t scanFilterPolity, uint8_t scanPhys, const GapLeScanParam param[])
{
LOG_INFO("%{public}s:", __FUNCTION__);
int ret;
if (GapIsLeEnable() == false) {
return GAP_ERR_NOT_ENABLE;
}
if (GapLeRolesCheck(GAP_LE_ROLE_BROADCASTER | GAP_LE_ROLE_CENTRAL) == false) {
ret = GAP_ERR_INVAL_STATE;
} else {
ret = GapLeSetExtendedScanParameters(BTM_GetOwnAddressType(), scanFilterPolity, scanPhys, param);
}
return ret;
}
static int GapLeSetExtendedScanEnable(uint8_t scanEnable, uint8_t filterDuplicates, uint16_t duration, uint16_t period)
{
HciLeSetExtendedScanEnableParam hciCmdParam = {
.duration = duration,
.enable = scanEnable,
.filterDuplicates = filterDuplicates,
.period = period,
};
return HCI_LeSetExtendedScanEnable(&hciCmdParam);
}
NO_SANITIZE("cfi") void GapLeSetExtendedScanEnableComplete(const HciLeSetExtendedScanEnableReturnParam *param)
{
if (g_leExScanCallback.callback.scanExSetEnableResult) {
g_leExScanCallback.callback.scanExSetEnableResult(param->status, g_leExScanCallback.context);
}
}
int GAP_LeExScanSetEnable(uint8_t scanEnable, uint8_t filterDuplicates, uint16_t duration, uint16_t period)
{
LOG_INFO("%{public}s:", __FUNCTION__);
int ret;
if (GapIsLeEnable() == false) {
return GAP_ERR_NOT_ENABLE;
}
if (GapLeRolesCheck(GAP_LE_ROLE_BROADCASTER | GAP_LE_ROLE_CENTRAL) == false) {
ret = GAP_ERR_INVAL_STATE;
} else {
ret = GapLeSetExtendedScanEnable(scanEnable, filterDuplicates, duration, period);
}
return ret;
}