GSList *scanner_list = NULL;
static gboolean is_le_set_scan_parameter = FALSE;
static gboolean is_le_scanning = FALSE;
+static gboolean scan_filter_enabled = FALSE;
static bluetooth_le_scan_params_t le_scan_params = { BT_LE_ACTIVE_SCAN, 0, 0 };
return length;
}
+static int __bt_get_ad_data_by_type(const char *in_data, int in_len,
+ char in_type, char **data, int *data_len)
+{
+ if (in_data == NULL || data == NULL || data_len == NULL)
+ return BLUETOOTH_ERROR_INTERNAL;
+
+ if (in_len < 0)
+ return BLUETOOTH_ERROR_INTERNAL;
+
+ int i;
+ unsigned char len = 0;
+ int type = 0;
+
+ for (i = 0; i < in_len && i < BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - 1; i++) {
+ len = in_data[i];
+ if (len <= 0 || i + 1 >= in_len) {
+ BT_ERR("Invalid advertising data");
+ return BLUETOOTH_ERROR_INTERNAL;
+ }
+
+ type = in_data[i + 1];
+ if (type == in_type) {
+ i = i + 2;
+ len--;
+ break;
+ }
+
+ i += len;
+ len = 0;
+ }
+
+ if (i > BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - 1
+ || i + len > in_len
+ || i + len > BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - 1) {
+ BT_ERR("Invalid advertising data");
+ return BLUETOOTH_ERROR_INTERNAL;
+ } else if (len == 0) {
+ BT_DBG("AD Type 0x%02x data is not set", in_type);
+ *data = NULL;
+ *data_len = 0;
+ return BLUETOOTH_ERROR_NONE;
+ }
+
+ *data = g_memdup(&in_data[i], len);
+ if (*data == NULL)
+ return BLUETOOTH_ERROR_OUT_OF_MEMORY;
+ *data_len = len;
+
+ return BLUETOOTH_ERROR_NONE;
+}
+
+static gboolean __bt_check_scan_result_uuid(const char *adv_data,
+ int adv_data_len, const char *svc_uuid, int uuid_len,
+ const char *uuid_mask, char ad_type)
+{
+ char *data = NULL;
+ int data_len = 0;
+ int i;
+
+ __bt_get_ad_data_by_type(adv_data, adv_data_len,
+ ad_type, &data, &data_len);
+ if (data != NULL) {
+ for (i = 0; i < data_len; i += uuid_len) {
+ if (uuid_len > (data_len - i))
+ break;
+
+ if (_bt_byte_arr_cmp_with_mask(data + i,
+ svc_uuid, uuid_mask, uuid_len) == 0) {
+ g_free(data);
+ return TRUE;
+ }
+ }
+ g_free(data);
+ }
+
+ return FALSE;
+}
+
+static gboolean __bt_check_scan_result_with_filter(const char *device_address,
+ const char *adv_data, int adv_data_len,
+ const char *scan_data, int scan_data_len,
+ const bt_adapter_le_scanner_t *scanner)
+{
+ GSList *l;
+ bluetooth_le_scan_filter_t *filter_data = NULL;
+ char *data = NULL;
+ int data_len = 0;
+ gboolean is_matched = FALSE;
+ int idx;
+
+ if (scanner->filter_list == NULL) {
+ BT_INFO("This scanner is on Full Scan.");
+ return TRUE;
+ }
+
+ for (l = scanner->filter_list; l != NULL; l = g_slist_next(l)) {
+ filter_data = l->data;
+
+ if (filter_data->added_features &
+ BLUETOOTH_LE_SCAN_FILTER_FEATURE_DEVICE_ADDRESS) {
+ char address[BT_ADDRESS_STRING_SIZE] = { 0 };
+
+ _bt_convert_addr_type_to_string(address,
+ filter_data->device_address.addr);
+ if (strncmp(address, device_address,
+ BT_ADDRESS_STRING_SIZE) != 0)
+ continue;
+ }
+
+ /* Check service uuid filter */
+ if (filter_data->added_features &
+ BLUETOOTH_LE_SCAN_FILTER_FEATURE_SERVICE_UUID) {
+ is_matched = FALSE;
+ const int ad_type_uuids[] = {
+ BT_LE_AD_TYPE_INCOMP_LIST_16_BIT_SERVICE_CLASS_UUIDS,
+ BT_LE_AD_TYPE_COMP_LIST_16_BIT_SERVICE_CLASS_UUIDS,
+ BT_LE_AD_TYPE_INCOMP_LIST_128_BIT_SERVICE_CLASS_UUIDS,
+ BT_LE_AD_TYPE_COMP_LIST_128_BIT_SERVICE_CLASS_UUIDS
+ };
+
+ for (idx = 0; idx < sizeof(ad_type_uuids) / sizeof(bt_le_ad_type_t); idx++) {
+ /* Check service uuid in advertising data */
+ if (__bt_check_scan_result_uuid(adv_data, adv_data_len,
+ (const char *)filter_data->service_uuid.data.data,
+ filter_data->service_uuid.data_len,
+ (const char *)filter_data->service_uuid_mask.data.data,
+ ad_type_uuids[idx]) == TRUE) {
+ BT_INFO("Service UUID is matched in adv data.");
+ is_matched = TRUE;
+ break;
+ }
+
+ /* Check service uuid in scan response data */
+ if (__bt_check_scan_result_uuid(scan_data, scan_data_len,
+ (const char *)filter_data->service_uuid.data.data,
+ filter_data->service_uuid.data_len,
+ (const char *)filter_data->service_uuid_mask.data.data,
+ ad_type_uuids[idx]) == TRUE) {
+ BT_INFO("Service UUID is matched in scan data.");
+ is_matched = TRUE;
+ break;
+ }
+ }
+
+ /* Service UUID is NOT matched. Continue to next filter */
+ if (is_matched == FALSE)
+ continue;
+ }
+
+ /* Check solicitation uuid filter */
+ if (filter_data->added_features &
+ BLUETOOTH_LE_SCAN_FILTER_FEATURE_SERVICE_SOLICITATION_UUID) {
+ is_matched = FALSE;
+ const int ad_type_solicit_uuids[] = {
+ BT_LE_AD_TYPE_LIST_16_BIT_SERVICE_SOLICITATION_UUIDS,
+ BT_LE_AD_TYPE_LIST_128_BIT_SERVICE_SOLICITATION_UUIDS
+ };
+
+ for (idx = 0; idx < sizeof(ad_type_solicit_uuids) / sizeof(bt_le_ad_type_t); idx++) {
+ /* Check solicit uuid in advertising data */
+ if (__bt_check_scan_result_uuid(adv_data, adv_data_len,
+ (const char *)filter_data->service_solicitation_uuid.data.data,
+ filter_data->service_solicitation_uuid.data_len,
+ (const char *)filter_data->service_solicitation_uuid_mask.data.data,
+ ad_type_solicit_uuids[idx]) == TRUE) {
+ BT_INFO("Service Solicitation UUID is matched in adv data.");
+ is_matched = TRUE;
+ break;
+ }
+
+ /* Check solicit uuid in scan response data */
+ if (__bt_check_scan_result_uuid(scan_data, scan_data_len,
+ (const char *)filter_data->service_solicitation_uuid.data.data,
+ filter_data->service_solicitation_uuid.data_len,
+ (const char *)filter_data->service_solicitation_uuid_mask.data.data,
+ ad_type_solicit_uuids[idx]) == TRUE) {
+ BT_INFO("Service Solicitation UUID is matched in scan data.");
+ is_matched = TRUE;
+ break;
+ }
+ }
+
+ /* Service Solicitation UUID is NOT matched. Continue to next filter */
+ if (is_matched == FALSE)
+ continue;
+ }
+
+ /* Check device name filter */
+ if (filter_data->added_features &
+ BLUETOOTH_LE_SCAN_FILTER_FEATURE_DEVICE_NAME) {
+ char name[BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX] = {0, };
+ data = NULL;
+ data_len = 0;
+ is_matched = FALSE;
+
+ /* Check device name in advertising data */
+ __bt_get_ad_data_by_type(adv_data, adv_data_len,
+ BT_LE_AD_TYPE_COMPLETE_LOCAL_NAME,
+ &data, &data_len);
+ if (data != NULL) {
+ if (data_len >= BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX)
+ data_len = BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - 1;
+ memcpy(name, data, data_len);
+ name[data_len] = '\0';
+ g_free(data);
+ data = NULL;
+ if (strncmp(filter_data->device_name,
+ name, data_len) == 0) {
+ BT_INFO("Device Name is matched in adv data.");
+ is_matched = TRUE;
+ }
+ }
+
+ /* Check device name in scan response data */
+ __bt_get_ad_data_by_type(scan_data, scan_data_len,
+ BT_LE_AD_TYPE_COMPLETE_LOCAL_NAME,
+ &data, &data_len);
+ if (data != NULL) {
+ if (data_len >= BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX)
+ data_len = BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - 1;
+ memcpy(name, data, data_len);
+ name[data_len] = '\0';
+ g_free(data);
+ data = NULL;
+ if (strncmp(filter_data->device_name,
+ name, data_len) == 0) {
+ BT_INFO("Device Name is matched in scan data.");
+ is_matched = TRUE;
+ }
+ }
+
+ /* Device Name is NOT matched. Continue to next filter */
+ if (is_matched == FALSE)
+ continue;
+ }
+
+ /* Check manufacturer data filter */
+ if (filter_data->added_features &
+ BLUETOOTH_LE_SCAN_FILTER_FEATURE_MANUFACTURER_DATA) {
+ data = NULL;
+ data_len = 0;
+ is_matched = FALSE;
+
+ /* Check manufacturer data in advertising data */
+ __bt_get_ad_data_by_type(adv_data, adv_data_len,
+ BT_LE_AD_TYPE_MANUFACTURER_SPECIFIC_DATA,
+ &data, &data_len);
+ if (data != NULL) {
+ int manufacturer_id;
+ manufacturer_id = (data[1] << 8) + data[0];
+
+ if (filter_data->manufacturer_id == manufacturer_id) {
+ if (filter_data->manufacturer_data.data_len == 0) {
+ is_matched = TRUE;
+ } else {
+ if (data_len >= BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX)
+ data_len = BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - 1;
+ if (_bt_byte_arr_cmp_with_mask(data + 2,
+ (const char *)filter_data->manufacturer_data.data.data,
+ (const char *)filter_data->manufacturer_data_mask.data.data,
+ data_len - 2) == 0) {
+ BT_INFO("Manufacturer Data is matched in adv data.");
+ is_matched = TRUE;
+ }
+ }
+ }
+ g_free(data);
+ data = NULL;
+ }
+
+ /* Check manufacturer data in scan response data */
+ __bt_get_ad_data_by_type(scan_data, scan_data_len,
+ BT_LE_AD_TYPE_MANUFACTURER_SPECIFIC_DATA,
+ &data, &data_len);
+ if (data != NULL) {
+ int manufacturer_id;
+ manufacturer_id = (data[1] << 8) + data[0];
+
+ if (filter_data->manufacturer_id == manufacturer_id) {
+ if (filter_data->manufacturer_data.data_len == 0) {
+ is_matched = TRUE;
+ } else {
+ if (data_len >= BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX)
+ data_len = BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - 1;
+ if (_bt_byte_arr_cmp_with_mask(data + 2,
+ (const char *)filter_data->manufacturer_data.data.data,
+ (const char *)filter_data->manufacturer_data_mask.data.data,
+ data_len - 2) == 0) {
+ BT_INFO("Manufacturer Data is matched in scan data.");
+ is_matched = TRUE;
+ }
+ }
+ }
+ g_free(data);
+ data = NULL;
+ }
+
+ /* Manufacturer Data is NOT matched. Continue to next filter */
+ if (is_matched == FALSE)
+ continue;
+ }
+
+ /* Check service data filter */
+ if (filter_data->added_features &
+ BLUETOOTH_LE_SCAN_FILTER_FEATURE_SERVICE_DATA) {
+ data = NULL;
+ data_len = 0;
+ is_matched = FALSE;
+
+ /* Check service data in advertising data */
+ __bt_get_ad_data_by_type(adv_data,
+ adv_data_len,
+ BT_LE_AD_TYPE_SERVICE_DATA,
+ &data, &data_len);
+ if (data != NULL) {
+ if (data_len >= BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX)
+ data_len = BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - 1;
+ if (_bt_byte_arr_cmp_with_mask(data,
+ (const char *)filter_data->service_data.data.data,
+ (const char *)filter_data->service_data_mask.data.data,
+ data_len) == 0) {
+ BT_INFO("Service Data is matched in adv data.");
+ is_matched = TRUE;
+ }
+ g_free(data);
+ data = NULL;
+ }
+
+ /* Check service data in scan response data */
+ __bt_get_ad_data_by_type(scan_data,
+ scan_data_len,
+ BT_LE_AD_TYPE_SERVICE_DATA,
+ &data, &data_len);
+ if (data != NULL) {
+ if (data_len >= BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX)
+ data_len = BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX - 1;
+ if (_bt_byte_arr_cmp_with_mask(data,
+ (const char *)filter_data->service_data.data.data,
+ (const char *)filter_data->service_data_mask.data.data,
+ data_len) == 0) {
+ BT_INFO("Service Data is matched in scan data.");
+ is_matched = TRUE;
+ }
+ g_free(data);
+ data = NULL;
+ }
+
+ /* Service Data is NOT matched. Continue to next filter */
+ if (is_matched == FALSE)
+ continue;
+ }
+
+ BT_INFO("The scan result is conformable.");
+ return TRUE;
+ }
+
+ BT_INFO("The scan result is NOT conformable.");
+ return FALSE;
+}
+
static void __bt_le_handle_device_found(event_ble_scan_result_info *scan_result)
{
int result = BLUETOOTH_ERROR_NONE;
bt_adapter_le_scanner_t *scanner = NULL;
char address[BT_ADDRESS_STRING_SIZE];
int addr_type = 0x01; /* TODO: Need to get correct address type */
- unsigned char adv_ind_data[31];
- unsigned char scan_resp_data[31];
+ unsigned char adv_ind_data[BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX];
+ unsigned char scan_resp_data[BLUETOOTH_SCAN_RESP_DATA_LENGTH_MAX];
int adv_ind_len = 0;
int scan_resp_len = 0;
char *tmp_str = NULL;
memset(adv_ind_data, 0x00, sizeof(adv_ind_data));
adv_ind_len = __get_advertisement_data(
adv_ind_data, &(scan_result->adv_data[0]));
+ if (adv_ind_len > BLUETOOTH_ADVERTISING_DATA_LENGTH_MAX) {
+ BT_ERR("Invalid advertising data");
+ return;
+ }
memset(scan_resp_data, 0x00, sizeof(scan_resp_data));
scan_resp_len = __get_advertisement_data(
scan_resp_data, &(scan_result->adv_data[adv_ind_len]));
+ if (scan_resp_len > BLUETOOTH_SCAN_RESP_DATA_LENGTH_MAX) {
+ BT_ERR("Invalid scan response data");
+ return;
+ }
BT_INFO("Address: %s, RSSI: %d, adv_ind_len: %d, scan_resp_len: %d",
address, scan_result->rssi, adv_ind_len, scan_resp_len);
if (scanner->is_scanning == FALSE)
continue;
+ if (__bt_check_scan_result_with_filter(address, (const char *)adv_ind_data,
+ adv_ind_len, (const char *)scan_resp_data, scan_resp_len, scanner) == FALSE)
+ continue;
+
adv_data_param = g_variant_new_from_data((const GVariantType *)"ay",
adv_ind_data, adv_ind_len, TRUE, NULL, NULL);
scan_data_param = g_variant_new_from_data((const GVariantType *)"ay",
/* Check scanning is in progress or not by other users */
if (_bt_is_le_scanning()) {
int value = 1;
-
BT_INFO("LE Full Scan is already on progress");
g_idle_add(__send_le_scan_reply, (void *)(intptr_t)value);
- goto done;
- }
-
- if (is_le_set_scan_parameter == FALSE) {
- bluetooth_le_scan_params_t scan_params;
- /* Set default scan parameter same with BT_ADAPTER_LE_SCAN_MODE_LOW_ENERGY */
- scan_params.type = 0x01;
- scan_params.interval = 5120;
- scan_params.window = 512;
- _bt_set_scan_parameters(&scan_params);
+ /* Disable scan filter if filter is NULL */
+ if (scan_filter_enabled == TRUE) {
+ if (scanner->filter_list == NULL) {
+ BT_INFO("Disable LE Scan Filter");
+ ret = gattc_disable_scan_filter(0);
+ if (ret != OAL_STATUS_SUCCESS)
+ BT_ERR("gattc_disable_scan_filter failed");
+ scan_filter_enabled = FALSE;
+ } else {
+ BT_INFO("LE Filter Scan is continue");
+ }
+ } else {
+ BT_INFO("LE Full Scan is already on progress");
+ }
+ goto done;
} else {
- _bt_set_scan_parameters(&le_scan_params);
+ if (is_le_set_scan_parameter == FALSE) {
+ /* Set default scan parameter same with BT_ADAPTER_LE_SCAN_MODE_LOW_ENERGY */
+ bluetooth_le_scan_params_t scan_params;
+ scan_params.type = BT_LE_ACTIVE_SCAN;
+ scan_params.interval = 5120;
+ scan_params.window = 512;
+ _bt_set_scan_parameters(&scan_params);
+ } else
+ _bt_set_scan_parameters(&le_scan_params);
+
+ /* Enable scan filter if filter is exisiting */
+ if (scanner->filter_list == NULL) {
+ scan_filter_enabled = FALSE;
+ } else {
+ BT_INFO("Enable LE Scan Filter");
+ ret = gattc_enable_scan_filter(0);
+ if (ret != OAL_STATUS_SUCCESS)
+ BT_ERR("gattc_enable_scan_filter failed");
+ scan_filter_enabled = TRUE;
+ }
}
-// TODO: Enable scan filter
BT_INFO("Start LE Full Scan");
ret = gattc_start_le_discovery(g_gatt_client_id);