Add scanner module
authorWootak Jung <wootak.jung@samsung.com>
Mon, 22 Feb 2021 00:41:40 +0000 (09:41 +0900)
committerWootak Jung <wootak.jung@samsung.com>
Sun, 11 Apr 2021 23:40:16 +0000 (08:40 +0900)
Signed-off-by: Wootak Jung <wootak.jung@samsung.com>
include/tds-api.h
include/tds-provider-common.h
include/tds-provider-service.h
src/tds-api.c
src/tds-provider-advertiser.c
src/tds-provider-aware.c
src/tds-provider-scanner.c
src/tds-provider-service.c

index 3afa5fc8ceadddb2580980f9e3e1d3d69624bc16..ee05262cd9e1480bf79c7600ae344059f4135648 100644 (file)
 
 #include <stdio.h>
 #include <stdint.h>
+#include "tds-provider-common.h"
 
 void _tds_bloom_filter_add_string(uint8_t *inFilterPtr, size_t inFilterLen, const char *inStr, size_t inLen);
 bool _tds_bloom_filter_contain_hash(const uint8_t *inFilterPtr, size_t inFilterLen, uint64_t inHash);
 bool _tds_bloom_filter_contain_string(const uint8_t *inFilterPtr, size_t inFilterLen, const char *inStr, size_t inLen);
-int _bt_tds_start_scan(bt_tds_provider_scan_result_cb cb, void *user_data);
-int _bt_tds_stop_scan();
+int _tds_start_scan(tds_role_e search_role, bt_tds_provider_scan_result_cb cb, void *user_data);
+int _tds_stop_scan();
 
 #endif /* __TDS_API_H__ */
index cca8aaf03e3a1502a9668f8de9aec25b2c3157b1..23339ee175392e5a58d9820ca76edd7bd41323b7 100644 (file)
 #include <glib.h>
 #include <gio/gio.h>
 
-#define ret_if(expr) \
-       do { \
-               if (expr) { \
-                       TDS_ERR("(%s) return", #expr); \
-                       return; \
-               } \
-       } while (0)
-
-#define retv_if(expr, val) \
-       do { \
-               if (expr) { \
-                       TDS_ERR("(%s) return", #expr); \
-                       return (val); \
-               } \
-       } while (0)
-
-#define TDS_CHECK_PARAMETER(arg, func) \
+#define TDS_CHECK_INPUT_PARAMETER(arg) \
        do { \
                if (arg == NULL) { \
                        TDS_ERR("%s is NULL", #arg); \
-                       func BLUETOOTH_ERROR_INVALID_PARAM; \
+                       return TDS_ERROR_INVALID_PARAMETER; \
                } \
        } while (0)
 
@@ -55,6 +39,7 @@
 typedef enum {
        TDS_ERROR_NONE,
        TDS_ERROR_INTERNAL,
+       TDS_ERROR_INVALID_PARAMETER,
 } tds_error_e;
 
 typedef enum {
@@ -69,4 +54,11 @@ typedef enum {
        TDS_TRANSPORT_STATE_ON,
 } tds_transport_state_e;
 
+typedef enum {
+       TDS_ROLE_NOT_SPECIFIED,
+       TDS_ROLE_SEEKER,
+       TDS_ROLE_PROVIDER,
+       TDS_ROLE_BOTH,
+} tds_role_e;
+
 #endif /* __TDS_PROVIDER_COMMON_H__ */
index 1d1b2087b2825cda0980ea28eae6e88516150bd4..1c68256c35709083ea28d2511d63dc3738b55cfa 100644 (file)
 #ifndef __TDS_PROVIDER_SERVICE_H__
 #define __TDS_PROVIDER_SERVICE_H__
 
+#include <bluetooth_internal.h>
+
 int _tds_service_enable();
 int _tds_service_disable();
+int _tds_service_handle_transport_block(bt_tds_transport_block_list_s *info);
 
 #endif /* __TDS_PROVIDER_SERVICE_H__ */
index 623f4a499323abbbd3c306bac3bf00b52b633403..5bcfed8e99c54b4edbc39c723a57c04ea390efdb 100644 (file)
 #include <dlog.h>
 #include <bluetooth.h>
 #include <bluetooth_internal.h>
+#include "tds-provider-common.h"
+#include "tds-provider-log.h"
 #include "csiphash/csiphash.h"
 
-uint64_t siphash24(const void *src, unsigned long src_sz, const char key[16]);
+struct tds_scan_data_s {
+       tds_role_e search_role;
+       bt_tds_provider_scan_result_cb callback;
+       void *user_data;
+};
+
+static struct tds_scan_data_s *scan_data = NULL;
 
 #define kTDSSipHashKey ((const uint8_t *) \
     "\x00\x00\x00\x00\x00\x00\x00\x00" \
@@ -29,6 +37,8 @@ uint64_t siphash24(const void *src, unsigned long src_sz, const char key[16]);
 )
 #define kTDSSipHashCount 4
 
+#define TRANSPORT_DISCOVERY_DATA_AD_TYPE 0x26
+
 void _tds_bloom_filter_add_string(uint8_t *inFilterPtr, size_t inFilterLen, const char *inStr, size_t inLen)
 {
        const size_t bitCount = inFilterLen * 8;
@@ -59,13 +69,193 @@ bool _tds_bloom_filter_contain_string(const uint8_t *inFilterPtr, size_t inFilte
        return _tds_bloom_filter_contain_hash(inFilterPtr, inFilterLen, hash);
 }
 
-int _bt_tds_start_scan(bt_tds_provider_scan_result_cb cb, void *user_data)
+static int __tds_get_ad_data_by_type(char *in_data, int in_len,
+               char in_type, char **data, int *data_len)
+{
+       if (in_data == NULL || data == NULL || data_len == NULL)
+               return TDS_ERROR_INTERNAL;
+
+       if (in_len < 0)
+               return TDS_ERROR_INTERNAL;
+
+       int i;
+       int len = 0;
+       int type = 0;
+
+       for (i = 0; i < in_len; i++) {
+               len = in_data[i];
+               if (len <= 0 || i + 1 >= in_len) {
+                       TDS_ERR("Invalid advertising data");
+                       return TDS_ERROR_INTERNAL;
+               }
+
+               type = in_data[i + 1];
+               if (type == in_type) {
+                       i = i + 2;
+                       len--;
+                       break;
+               }
+
+               i += len;
+               len = 0;
+       }
+
+       if (i + len > in_len) {
+               TDS_ERR("Invalid advertising data");
+               return TDS_ERROR_INTERNAL;
+       } else if (len == 0) {
+               //TDS_DBG("AD Type 0x%02x data is not set. skip", in_type);
+               *data = NULL;
+               *data_len = 0;
+               return TDS_ERROR_NONE;
+       }
+
+       *data = g_memdup(&in_data[i], len);
+       if (*data == NULL)
+               return TDS_ERROR_INTERNAL;
+       *data_len = len;
+
+       return TDS_ERROR_NONE;
+}
+
+static int __tds_parse_transport_blocks(tds_role_e search_role,
+               bt_tds_transport_block_list_s **info,
+               char *data, int data_len)
+{
+       int numblocks = 0;
+       int index = 2;
+       uint8_t flags;
+       int k;
+       GSList *info_list = NULL;
+       GSList *l = NULL;
+       tds_transport_data_s *td;
+
+       if (data_len < 3) {
+               TDS_ERR("Invalid TDS data, can not process!!");
+               return TDS_ERROR_INTERNAL;
+       }
+
+       while (index < data_len) {
+               flags = data[index-1];
+
+               TDS_INFO("Transport Block Role: %d, search_role: %d", flags & 0x03, search_role);
+               if (search_role != TDS_ROLE_BOTH && (flags & 0x03) != search_role) {
+                       TDS_INFO("Role Not Matched");
+                       continue;
+               }
+
+               td = g_malloc(sizeof(tds_transport_data_s));
+               td->length = data[index];
+               td->data = g_malloc0(td->length);
+
+               /* Fill Transport Block Data excluding Flag and Org ID */
+               for (k = 0; k < td->length; k++)
+                       td->data[k] = data[k + index + 1];
+
+               /* Get Transport Name  */
+               td->transport = data[index -2];
+               if (td->transport == 0x01)
+                       td->transport = BT_TDS_TRANSPORT_BT;
+               else if (td->transport == 0x02)
+                       td->transport = BT_TDS_TRANSPORT_WIFI_NAN;
+               else if (td->transport == 0x03)
+                       td->transport = BT_TDS_TRANSPORT_WIFI_SVC_ADV;
+               else if (td->transport == 0x04)
+                       td->transport = BT_TDS_TRANSPORT_CUSTOM;
+               else
+                       td->transport = BT_TDS_TRANSPORT_INVALID;
+
+               /* Get Transport Data Block Incomplete status */
+               if (flags & 0x04)
+                       td->is_data_complete = false;
+               else
+                       td->is_data_complete = true;
+
+               /* Get Transport's current state */
+               if (flags & 0x08)
+                       td->state = BT_TDS_TRANSPORT_STATE_ON;
+               else if (flags & 0x10)
+                       td->state = BT_TDS_TRANSPORT_STATE_UNAVAILABLE;
+               else
+                       td->state = BT_TDS_TRANSPORT_STATE_OFF;
+
+               /* Move to Next Block */
+               index = index + data[index] + 3;
+               info_list = g_slist_append(info_list, td);
+
+               (*info)->num_transport_block = ++numblocks;
+               TDS_DBG("Transport Block data length [%d] Flags [0x%x] Transport Name [0x%x] Block Num [%d]",
+                               td->length, flags, td->transport, numblocks);
+
+       }
+
+       if (info_list != NULL) {
+               (*info)->data = (tds_transport_data_s**)g_malloc0(g_slist_length(info_list) * sizeof(tds_transport_data_s*));
+               k = 0;
+               while (info_list) {
+                       l = info_list;
+                       (*info)->data[k++] = (tds_transport_data_s*)l->data;
+                       info_list = g_slist_remove(info_list, l->data);
+               }
+               return TDS_ERROR_NONE;
+       }
+       return TDS_ERROR_INTERNAL;
+}
+
+static void __tds_free_tds_scan_result_info(bt_tds_transport_block_list_s *info)
 {
-       /* TODO: need to use le_start_scan instead of seeking_provider */
-       return bt_tds_start_seeking_providers(cb, user_data);
+       int i;
+
+       if (info == NULL)
+               return;
+
+       for (i = 0; i < info->num_transport_block; i++) {
+               g_free(info->data[i]->data);
+               g_free(info->data[i]);
+       }
+
+       g_free(info);
 }
 
-int _bt_tds_stop_scan()
+static void __tds_scan_result_cb(int result,
+               bt_adapter_le_device_scan_result_info_s *scan_info, void *user_data)
 {
-       return bt_tds_stop_seeking_providers();
+       bt_tds_transport_block_list_s *info;
+       char *data = NULL;
+       int data_len = 0;
+
+       __tds_get_ad_data_by_type(scan_info->adv_data, scan_info->adv_data_len,
+                       TRANSPORT_DISCOVERY_DATA_AD_TYPE,
+                       &data, &data_len);
+       if (data == NULL)
+               return;
+
+       info = g_malloc0(sizeof(bt_tds_transport_block_list_s));
+       __tds_parse_transport_blocks(scan_data->search_role, &info, data, data_len);
+
+       if (scan_data->callback)
+               scan_data->callback(TDS_ERROR_NONE, scan_info->remote_address,
+                               info, scan_info, scan_data->user_data);
+
+       __tds_free_tds_scan_result_info(info);
+       g_free(data);
+}
+
+int _tds_start_scan(tds_role_e search_role, bt_tds_provider_scan_result_cb callback, void *user_data)
+{
+       TDS_CHECK_INPUT_PARAMETER(callback);
+
+       scan_data = g_malloc0(sizeof(struct tds_scan_data_s));
+       scan_data->search_role = search_role;
+       scan_data->callback = callback;
+       scan_data->user_data = user_data;
+
+       return bt_adapter_le_start_scan(__tds_scan_result_cb, NULL);
+}
+
+int _tds_stop_scan()
+{
+       g_free(scan_data);
+
+       return bt_adapter_le_stop_scan();
 }
index 56bfc9e80a06280aad73668b2dc3e70ad43f9fb8..20a956e209302ef1a433048a3ddc5a060ce80a7a 100644 (file)
@@ -22,6 +22,7 @@
 #include "tds-provider-common.h"
 #include "tds-provider-log.h"
 #include "tds-provider-service.h"
+#include "tds-provider-advertiser.h"
 #include "tds-api.h"
 
 static bt_advertiser_h advertiser;
@@ -33,7 +34,7 @@ static void __tds_advertiser_adv_state_changed_cb(int result,
                void *user_data)
 {
        TDS_INFO("Result: %d, Advertising %s", result,
-                       adv_state == BT_ADAPTER_LE_ADVERTISING_STARTED ? "started" : "stopped");
+                       adv_state == BT_ADAPTER_LE_ADVERTISING_STARTED ? "Started" : "Stopped");
        g_adv_started = TRUE;
 }
 
@@ -48,13 +49,20 @@ int _tds_advertiser_enable(tds_transport_state_e transport_state)
                return TDS_ERROR_NONE;
        }
 
+       /* Stop previous advertiser if existing */
+       ret = _tds_advertiser_disable();
+       if (ret != BT_ERROR_NONE) {
+               TDS_ERR("_tds_advertiser_disable() failed. ret: %d", ret);
+               return TDS_ERROR_INTERNAL;
+       }
+
        ret = bt_adapter_le_create_advertiser(&advertiser);
        if (ret != BT_ERROR_NONE) {
                TDS_ERR("bt_adapter_le_create_advertiser() failed. ret: %d", ret);
                return TDS_ERROR_INTERNAL;
        }
 
-       TDS_INFO("Create bloom filter");
+       TDS_INFO("Create Bloom Filter with 'provider' Operation");
        _tds_bloom_filter_add_string(transport_data, sizeof(transport_data),
                        TDS_BLOOM_FILTER_OPERATION_STR_PROVIDER, strlen(TDS_BLOOM_FILTER_OPERATION_STR_PROVIDER));
        /* TODO: actually, below strings are not required. need to check that keep or not */
@@ -101,6 +109,8 @@ int _tds_advertiser_disable()
                return TDS_ERROR_INTERNAL;
        }
 
+       TDS_INFO("Advertising Stopped");
+
        ret = bt_adapter_le_destroy_advertiser(advertiser);
        if (ret != BT_ERROR_NONE) {
                TDS_ERR("bt_tds_provider_unregister() failed. ret: %d", ret);
index bf50889147f3a7ce92ff00f61212f13ca0e65458..6cfaaf5bd8f8e248974d40ea50e61d77394b901a 100644 (file)
 #include "tds-provider-common.h"
 #include "tds-provider-log.h"
 
+static gboolean g_aware_enabled;
+
+static void __aware_enabled(wifi_aware_error_e error, void *user_data)
+{
+       if (error == WIFI_AWARE_ERROR_NONE) {
+               TDS_INFO("wifi-aware enabled");
+               g_aware_enabled = TRUE;
+       }
+}
+
 int _tds_aware_enable()
 {
+       int ret;
        TDS_DBG("Enter");
+
+       if (g_aware_enabled)
+               return TDS_ERROR_NONE;
+
+       ret = wifi_aware_initialize();
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               TDS_ERR("wifi_aware_initialize() failed. ret: 0x%x", ret);
+               return TDS_ERROR_INTERNAL;
+       }
+
+       ret = wifi_aware_enable(__aware_enabled, NULL);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               TDS_ERR("wifi_aware_enable() failed. ret: 0x%x", ret);
+               return TDS_ERROR_INTERNAL;
+       }
+
        return TDS_ERROR_NONE;
 }
 
 int _tds_aware_disable()
 {
+       int ret;
        TDS_DBG("Enter");
+
+       ret = wifi_aware_disable();
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               TDS_ERR("wifi_aware_disable() failed. ret: 0x%x", ret);
+               return TDS_ERROR_INTERNAL;
+       }
+
+       g_aware_enabled = FALSE;
        return TDS_ERROR_NONE;
 }
index 92b67593446c84b8128d9f1b63dd06230c86b404..d22bcf2cda77c94bde9396a245a017424168da6a 100644 (file)
 #include "tds-provider-common.h"
 #include "tds-provider-log.h"
 #include "tds-provider-service.h"
+#include "tds-api.h"
+
+static gboolean g_scan_started;
+
+static char *__tds_scanner_convert_transport_to_str(bt_tds_transport_e transport)
+{
+       switch (transport) {
+       case BT_TDS_TRANSPORT_BT:
+               return "BT";
+       case BT_TDS_TRANSPORT_CUSTOM:
+               return "CUSTOM";
+       case BT_TDS_TRANSPORT_WIFI_NAN:
+               return "WIFI_NAN";
+       case BT_TDS_TRANSPORT_WIFI_SVC_ADV:
+               return "WIFI_SVC_ADV";
+       case BT_TDS_TRANSPORT_INVALID:
+       default:
+               return "INVALID";
+       }
+}
+
+static char *__tds_scanner_convert_state_to_str(bt_tds_transport_state_e state)
+{
+       switch (state) {
+       case BT_TDS_TRANSPORT_STATE_OFF:
+               return "OFF";
+       case BT_TDS_TRANSPORT_STATE_ON:
+               return "ON";
+       case BT_TDS_TRANSPORT_STATE_UNAVAILABLE:
+       default:
+               return "UNAVAILABLE";
+       }
+}
+
+static void __tds_scanner_seeker_found_cb(int result,
+               const char *remote_address, bt_tds_transport_block_list_s *info,
+               bt_adapter_le_device_scan_result_info_s *scan_info, void *user_data)
+{
+       int i, j;
+       TDS_DBG("Enter");
+
+       if (info == NULL) {
+               TDS_ERR("info is NULL");
+               return;
+       }
+
+       TDS_INFO("Seeker found. result: %d, remote_address: %s, num of transport block: %d",
+                       result, remote_address, info->num_transport_block);
+
+       if (result == BT_ERROR_NONE) {
+               for (i = 0; i < info->num_transport_block; i++) {
+                       TDS_INFO("- Block index: %d", i);
+                       TDS_INFO("Transport ID: %s", __tds_scanner_convert_transport_to_str(info->data[i]->transport));
+                       TDS_INFO("Transport State: %s", __tds_scanner_convert_state_to_str(info->data[i]->state));
+                       TDS_INFO("Is Data Complete: %s", info->data[i]->is_data_complete ? "TRUE" : "FALSE");
+                       TDS_INFO("Length of Transport Data: %d", info->data[i]->length);
+                       for (j = 0; j < info->data[i]->length; j++)
+                               TDS_INFO("Transport Data[%d]: 0x%02x", j, info->data[i]->data[j]);
+               }
+
+               _tds_service_handle_transport_block(info);
+       }
+}
 
 int _tds_scanner_enable()
 {
+       int ret;
        TDS_DBG("Enter");
+
+       ret = _tds_start_scan(TDS_ROLE_SEEKER, __tds_scanner_seeker_found_cb, NULL);
+       if (ret != BT_ERROR_NONE) {
+               TDS_ERR("_tds_start_scan() failed. ret: %d", ret);
+               return TDS_ERROR_INTERNAL;
+       }
+
+       TDS_INFO("Scan Started");
+       g_scan_started = TRUE;
        return TDS_ERROR_NONE;
 }
 
 int _tds_scanner_disable()
 {
+       int ret ;
        TDS_DBG("Enter");
+
+       if (!g_scan_started)
+               return TDS_ERROR_NONE;
+
+       ret = _tds_stop_scan();
+       if (ret != BT_ERROR_NONE) {
+               TDS_ERR("_tds_stop_scan() failed. ret: %d", ret);
+               return TDS_ERROR_INTERNAL;
+       }
+
+       TDS_INFO("Scan Stopped");
+       g_scan_started = FALSE;
        return TDS_ERROR_NONE;
 }
index 4c495434e53f8469932140bd84b4539a2fadc3c2..c948e6693ba61b0ceb2afab5798f044793515d87 100644 (file)
 #include "tds-provider-aware.h"
 #include "tds-api.h"
 
+static char *g_local_address;
+
 static int __tds_service_start()
 {
        int ret;
 
+       ret = bt_adapter_get_address(&g_local_address);
+       if (ret != BT_ERROR_NONE) {
+               TDS_ERR("bt_adapter_get_address() failed. ret: %d", ret);
+               return TDS_ERROR_INTERNAL;
+       }
+
+       TDS_INFO("g_local_address: %s", g_local_address);
+
        ret = _tds_scanner_enable();
        if (ret != TDS_ERROR_NONE) {
                TDS_ERR("_tds_scanner_enable() failed. ret: %d", ret);
@@ -120,6 +130,8 @@ int _tds_service_enable()
                        TDS_ERR("__tds_service_start() failed. ret: %d", ret);
                        return TDS_ERROR_INTERNAL;
                }
+       } else {
+               TDS_INFO("BT Adapter Disabled");
        }
 
        return TDS_ERROR_NONE;
@@ -130,6 +142,9 @@ int _tds_service_disable()
        int ret;
        TDS_DBG("Enter");
 
+       if (g_local_address)
+               free(g_local_address);
+
        ret = bt_adapter_unset_state_changed_cb();
        if (ret != BT_ERROR_NONE) {
                TDS_ERR("bt_deinitialize() failed. ret: %d", ret);
@@ -150,3 +165,55 @@ int _tds_service_disable()
 
        return TDS_ERROR_NONE;
 }
+
+int _tds_service_handle_transport_block(bt_tds_transport_block_list_s *info)
+{
+       int i;
+       TDS_DBG("Enter");
+
+       for (i = 0; i < info->num_transport_block; i++) {
+               if (info->data[i]->transport != BT_TDS_TRANSPORT_WIFI_NAN) {
+                       TDS_INFO("Organization ID not matched. org_id: %d", info->data[i]->transport);
+                       continue;
+               }
+
+               if (info->data[i]->state == BT_TDS_TRANSPORT_STATE_OFF) {
+                       if (_tds_bloom_filter_contain_string((unsigned char *)info->data[i]->data, info->data[i]->length,
+                                       TDS_BLOOM_FILTER_OPERATION_STR_SEEK, strlen(TDS_BLOOM_FILTER_OPERATION_STR_SEEK)) == TRUE) {
+                               TDS_INFO("Bloom Filter Operation 'seek' contained in Transport Block!!");
+                               _tds_advertiser_enable(TDS_TRANSPORT_STATE_OFF);
+                       } else if (_tds_bloom_filter_contain_string((unsigned char *)info->data[i]->data, info->data[i]->length,
+                                       TDS_BLOOM_FILTER_OPERATION_STR_BROWSE, strlen(TDS_BLOOM_FILTER_OPERATION_STR_BROWSE)) == TRUE) {
+                               TDS_INFO("Bloom Filter Operation 'browse' contained in Transport Block!!");
+                               _tds_advertiser_enable(TDS_TRANSPORT_STATE_ON);
+                               _tds_scanner_disable();
+                               _tds_aware_enable();
+                               /* TODO: Start NAN Service Discovery */
+                               _tds_advertiser_disable();
+                       } else {
+                               TDS_INFO("Unknown Operation");
+                       }
+               } else if (info->data[i]->state == BT_TDS_TRANSPORT_STATE_ON) {
+                       if (_tds_bloom_filter_contain_string((unsigned char *)info->data[i]->data, info->data[i]->length,
+                                       TDS_BLOOM_FILTER_OPERATION_STR_ACTIVATION, strlen(TDS_BLOOM_FILTER_OPERATION_STR_ACTIVATION)) == TRUE) {
+                               TDS_INFO("Bloom Filter Operation 'activation' contained in Transport Block!!");
+                               if (_tds_bloom_filter_contain_string((unsigned char *)info->data[i]->data, info->data[i]->length,
+                                               g_local_address, strlen(g_local_address)) == TRUE) {
+                                       TDS_INFO("Address Matched");
+                                       _tds_advertiser_disable();
+                                       _tds_scanner_disable();
+                                       _tds_aware_enable();
+                                       /* TODO: Start NAN Service Discovery */
+                               } else {
+                                       TDS_ERR("Address Not Matched");
+                               }
+                       } else {
+                               TDS_ERR("Unknown Operation");
+                       }
+               } else {
+                       TDS_ERR("Transport State Unavailable");
+               }
+       }
+
+       return TDS_ERROR_NONE;
+}