GAP:LE Scan Filter as Platform feature. 36/83836/12
authorh.sandeep <h.sandeep@samsung.com>
Fri, 12 Aug 2016 10:10:29 +0000 (15:40 +0530)
committerPyun DoHyun <dh79.pyun@samsung.com>
Wed, 2 Nov 2016 02:29:19 +0000 (19:29 -0700)
Basic code for LE scan filter.
1. Add scan filters.
2. Filter the scan result.
3. Delete the filters.

Change-Id: I8998540f1092a333d28e7ff810d2f309f7bf4d0b
Signed-off-by: h.sandeep <h.sandeep@samsung.com>
src/adapter.c

index defaa1c..2f9598a 100644 (file)
 #include "eir.h"
 
 #ifdef __TIZEN_PATCH__
+#define TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+#endif
+
+#ifdef __TIZEN_PATCH__
 #include "adapter_le_vsc_features.h"
 #endif
 
 
 #define LE_BEARER_POSTFIX      " LE"
 #define LE_BEARER_POSTFIX_LEN  3
+
+/* Slot value shall be changed when required */
+#define SCAN_FILTER_SLOTS_MAX 20
 #endif /* __TIZEN_PATCH__ */
 
 
@@ -331,6 +338,18 @@ struct btd_adapter {
 #ifdef __TIZEN_PATCH__
        guint private_addr_timeout;
        uint8_t central_rpa_res_support;
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       bool scan_filter_support;               /* platform's scan filtering support */
+       uint8_t scan_type;              /* scan type */
+       GSList *scan_params;    /* scan filter parameters */
+       GSList *addr_filters;   /* adress scan filters list */
+       GSList *service_data_changed_filters;   /* service data changed scan filters list */
+       GSList *service_uuid_filters;   /* service uuid scan filters list */
+       GSList *solicit_data_filters;   /* solicitation data scan filters list */
+       GSList *local_name_filters;     /* local name scan filters list */
+       GSList *manufaturer_data_filters;       /* manufacturer data scan filters list */
+       GSList *service_data_filters;   /* service data scan filters list */
+#endif
 #endif
        bool is_default;                /* true if adapter is default one */
 };
@@ -2815,6 +2834,910 @@ static void le_discovery_disconnect(DBusConnection *conn, void *user_data)
                                stop_discovery_complete, adapter, NULL);
 }
 
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+static void addr_filter_params_free(gpointer data, gpointer user_data)
+{
+       adapter_le_address_filter_params_t *params = data;
+
+       g_free(params);
+}
+
+static void uuid_filter_params_free(gpointer data, gpointer user_data)
+{
+       adapter_le_uuid_params_t *params = data;
+
+       g_free((char *)params->uuid);
+       g_free((char *)params->uuid_mask);
+       g_free(params);
+}
+
+static void manufacturer_filter_params_free(gpointer data, gpointer user_data)
+{
+       adapter_le_manf_data_params_t *params = data;
+
+       g_free((char *)params->man_data);
+       g_free((char *)params->man_data_mask);
+       g_free(params);
+}
+
+static void local_name_filter_params_free(gpointer data, gpointer user_data)
+{
+       adapter_le_local_name_params_t *params = data;
+
+       g_free((char *)params->local_name);
+       g_free(params);
+}
+
+static void service_data_filter_params_free(gpointer data, gpointer user_data)
+{
+       adapter_le_service_data_params_t *params = data;
+
+       g_free((char *)params->service_data);
+       g_free((char *)params->service_data_mask);
+       g_free(params);
+}
+
+static void scan_filter_params_free(gpointer data, gpointer user_data)
+{
+       adapter_le_scan_filter_param_t *params = data;
+       g_free(params);
+}
+
+int adapter_le_address_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_address_filter_params_t *params = a;
+       const char *address = b;
+       char addr[18];
+
+       ba2str(&params->broadcaster_addr, addr);
+       return strcasecmp(addr, address);
+}
+
+int adapter_le_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_uuid_params_t *params = a;
+       const char *uuid = b;
+
+       return strcasecmp((const char *)params->uuid, uuid);
+}
+
+int adapter_le_manufacturer_data_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_manf_data_params_t *params = a;
+       const struct eir_msd *msd = b;
+
+       if (msd->company == params->company_id)
+               return strncasecmp((const char *)params->man_data, msd->data, params->man_data_len);
+       else
+               return -1;
+}
+
+int adapter_le_local_name_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_local_name_params_t *params = a;
+       const char *name = b;
+
+       return strcasecmp(params->local_name, name);
+}
+
+int adapter_le_service_data_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_service_data_params_t *params = a;
+       const struct eir_sd *sd = b;
+       /* Todo, the service data format for 16 bit, 32bit and
+        * 128 bit uuids needs to addressed */
+       return strncasecmp((const char *)(params->service_data), sd->data, sd->data_len);
+}
+
+int adapter_le_address_filter_index_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_address_filter_params_t *params = a;
+       uint16_t filter_inex = GPOINTER_TO_UINT(b);
+
+       return params->filter_index - filter_inex;
+}
+
+int adapter_le_uuid_filter_index_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_uuid_params_t *params = a;
+       uint16_t filter_inex = GPOINTER_TO_UINT(b);
+
+       return params->filter_index - filter_inex;
+}
+
+int adapter_le_manufacturer_data_filter_index_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_manf_data_params_t *params = a;
+       uint16_t filter_inex = GPOINTER_TO_UINT(b);
+
+       return params->filter_index - filter_inex;
+}
+
+int adapter_le_local_name_filter_index_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_local_name_params_t *params = a;
+       uint16_t filter_inex = GPOINTER_TO_UINT(b);
+
+       return params->filter_index - filter_inex;
+}
+
+int adapter_le_service_data_filter_index_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_service_data_params_t *params = a;
+       uint16_t filter_inex = GPOINTER_TO_UINT(b);
+
+       return params->filter_index - filter_inex;
+}
+
+int adapter_le_scan_params_filter_index_cmp(gconstpointer a, gconstpointer b)
+{
+       const adapter_le_scan_filter_param_t *params = a;
+       uint16_t filter_inex = GPOINTER_TO_UINT(b);
+
+       return params->index - filter_inex;
+}
+
+static gboolean adapter_le_clear_platform_scan_filter_data (
+                       struct btd_adapter *adapter, int filter_index)
+{
+       DBG("");
+       GSList *list;
+       if (!adapter)
+               return FALSE;
+
+       list = g_slist_find_custom(adapter->addr_filters,
+               GINT_TO_POINTER(filter_index), adapter_le_address_filter_index_cmp);
+       if (list && list->data) {
+               /* Delete info from the struct to list */
+               adapter->addr_filters = g_slist_delete_link(adapter->addr_filters, list);
+       }
+       list = g_slist_find_custom(adapter->service_data_changed_filters,
+               GINT_TO_POINTER(filter_index), adapter_le_service_data_filter_index_cmp);
+       if (list && list->data) {
+               /* Delete info from the struct to list */
+               adapter->service_data_changed_filters = g_slist_delete_link(adapter->service_data_changed_filters, list);
+       }
+
+       list = g_slist_find_custom(adapter->service_uuid_filters,
+               GINT_TO_POINTER(filter_index), adapter_le_uuid_filter_index_cmp);
+       if (list && list->data) {
+               /* Delete info from the struct to list */
+               adapter->service_uuid_filters = g_slist_delete_link(adapter->service_uuid_filters, list);
+       }
+
+       list = g_slist_find_custom(adapter->solicit_data_filters,
+               GINT_TO_POINTER(filter_index), adapter_le_uuid_filter_index_cmp);
+       if (list && list->data) {
+               /* Delete info from the struct to list */
+               adapter->solicit_data_filters = g_slist_delete_link(adapter->solicit_data_filters, list);
+       }
+
+       list = g_slist_find_custom(adapter->local_name_filters,
+               GINT_TO_POINTER(filter_index), adapter_le_local_name_filter_index_cmp);
+       if (list && list->data) {
+               /* Delete info from the struct to list */
+               adapter->local_name_filters = g_slist_delete_link(adapter->local_name_filters, list);
+       }
+
+       list = g_slist_find_custom(adapter->manufaturer_data_filters,
+               GINT_TO_POINTER(filter_index), adapter_le_manufacturer_data_filter_index_cmp);
+       if (list && list->data) {
+               /* Delete info from the struct to list */
+               adapter->manufaturer_data_filters = g_slist_delete_link(adapter->manufaturer_data_filters, list);
+       }
+
+       list = g_slist_find_custom(adapter->service_data_filters,
+               GINT_TO_POINTER(filter_index), adapter_le_service_data_filter_index_cmp);
+       if (list && list->data) {
+               /* Delete info from the struct to list */
+               adapter->service_data_filters = g_slist_delete_link(adapter->service_data_filters, list);
+       }
+
+       list = g_slist_find_custom(adapter->scan_params,
+               GINT_TO_POINTER(filter_index), adapter_le_scan_params_filter_index_cmp);
+       if (list && list->data) {
+               /* Delete info from the struct to list */
+               adapter->scan_params = g_slist_delete_link(adapter->scan_params, list);
+       }
+
+       return TRUE;
+}
+
+static gboolean adapter_le_enable_platform_scan_filtering (
+                       struct btd_adapter *adapter, gboolean enable)
+{
+       if (!adapter)
+               return FALSE;
+
+       DBG("Platform scan filtering enable[%d]", enable);
+
+       adapter->scan_filter_support = enable;
+
+       return TRUE;
+}
+
+
+static gboolean adapter_le_service_add_addr_scan_filter_data(struct btd_adapter *adapter,
+                                               int filter_index, gchar *string, int addr_type)
+{
+       /* TYPE_DEVICE_ADDRESS */
+       adapter_le_address_filter_params_t *params;
+
+       DBG("");
+
+       params = g_new0(adapter_le_address_filter_params_t, 1);
+       if (!params)
+               return FALSE;
+
+       params->filter_index = filter_index;
+       str2ba(string, &params->broadcaster_addr);
+       params->bdaddr_type = addr_type;
+
+       /* Store the struct to list */
+       adapter->addr_filters = g_slist_append(adapter->addr_filters, params);
+       return TRUE;
+}
+
+static const char *adapter_le_service_find_addr_scan_filter_data(
+                                               struct btd_adapter *adapter, gchar *string)
+{
+       GSList *list;
+       DBG("");
+
+       list = g_slist_find_custom(adapter->addr_filters, string, adapter_le_address_cmp);
+       if (!list)
+               return NULL;
+       else
+               return list->data;
+
+       return NULL;
+}
+
+static gboolean adapter_le_service_delete_addr_scan_filter_data(struct btd_adapter *adapter,
+                                               int filter_index, gchar *string, int addr_type)
+{
+       GSList *list;
+       DBG("");
+
+       list = g_slist_find_custom(adapter->addr_filters, string, adapter_le_address_cmp);
+       if (!list)
+               return FALSE;
+       else
+               /* Delete info from the struct to list */
+               adapter->addr_filters = g_slist_delete_link(adapter->addr_filters, list);
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_clear_addr_scan_filter_data(struct btd_adapter *adapter)
+{
+       DBG("");
+
+       g_slist_free_full(adapter->addr_filters, addr_filter_params_free);
+       adapter->addr_filters = NULL;
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_add_uuid_scan_filter_data(struct btd_adapter *adapter,
+                                                       int filter_index, gboolean is_solicited, uint8_t *p_uuid,
+                                                       uint8_t *p_uuid_mask, int uuid_mask_len)
+{
+
+       adapter_le_uuid_params_t *params;
+       bt_uuid_t uuid;
+
+       DBG("");
+
+       params = g_new0(adapter_le_uuid_params_t, 1);
+       if (!params)
+               return FALSE;
+
+       if (uuid_mask_len == UUID_16_LEN) {
+               uint16_t *uuid16 = (void *)p_uuid;
+               sdp_uuid16_create(&uuid, get_be16(uuid16));
+       } else if (uuid_mask_len == UUID_32_LEN) {
+               uint32_t *uuid32 = (void *)p_uuid;
+               sdp_uuid32_create(&uuid, get_be32(uuid32));
+       } else {
+               sdp_uuid128_create(&uuid, p_uuid);
+       }
+       params->filter_index = filter_index;
+       params->uuid = bt_uuid2string(&uuid);
+       params->uuid_mask = g_new0(uint8_t, uuid_mask_len);
+        memcpy(params->uuid_mask, p_uuid_mask, uuid_mask_len);
+       params->uuid_len = uuid_mask_len;
+
+       /* Store the struct to list */
+       adapter->solicit_data_filters = g_slist_append(adapter->solicit_data_filters, params);
+
+       return TRUE;
+}
+
+static adapter_le_uuid_params_t *adapter_le_service_find_uuid_scan_filter_data(struct btd_adapter *adapter,
+                                                       uint8_t *p_uuid)
+{
+       GSList *list;
+       DBG("");
+
+       list = g_slist_find_custom(adapter->solicit_data_filters, p_uuid, adapter_le_uuid_cmp);
+       if (!list)
+               return NULL;
+       else
+               /* Delete info from the struct to list */
+               return list->data;
+
+       return NULL;
+}
+
+static gboolean adapter_le_service_delete_uuid_scan_filter_data(struct btd_adapter *adapter,
+                                                       int filter_index, gboolean is_solicited, uint8_t *p_uuid,
+                                                       uint8_t *p_uuid_mask, int uuid_mask_len)
+{
+       GSList *list;
+       DBG("");
+
+       list = g_slist_find_custom(adapter->solicit_data_filters, GINT_TO_POINTER(filter_index), adapter_le_uuid_filter_index_cmp);
+       if (!list)
+               return FALSE;
+       else {
+               adapter_le_uuid_params_t *params = list->data;
+               /* Delete info from the struct to list */
+               if (params && strcasecmp((const char *)params->uuid, (const char *)p_uuid)) {
+                       adapter->solicit_data_filters = g_slist_delete_link(adapter->solicit_data_filters, list);
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_clear_uuid_scan_filter_data(struct btd_adapter *adapter)
+{
+       DBG("");
+
+       g_slist_free_full(adapter->solicit_data_filters, uuid_filter_params_free);
+       adapter->solicit_data_filters = NULL;
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_add_manufacturer_scan_filter_data(struct btd_adapter *adapter,
+                                                       int filter_index, int company_id, int company_id_mask,
+                                                       uint8_t *p_data, uint8_t *p_mask, int data_len)
+{
+
+       adapter_le_manf_data_params_t *params;
+
+       DBG("");
+
+       params = g_new0(adapter_le_manf_data_params_t, 1);
+       if (!params)
+               return FALSE;
+
+       params->filter_index = filter_index;
+       params->company_id = company_id;
+       params->company_id_mask = company_id_mask;
+       params->man_data = g_new0(uint8_t, data_len);
+       memcpy(params->man_data, p_data, data_len);
+       params->man_data_mask = g_new0(uint8_t, data_len);
+        memcpy(params->man_data_mask, p_mask, data_len);
+       params->man_data_len = data_len;
+
+       /* Store the struct to list */
+       adapter->manufaturer_data_filters = g_slist_append(adapter->manufaturer_data_filters, params);
+
+       return TRUE;
+}
+
+static adapter_le_manf_data_params_t *adapter_le_service_find_manufacturer_scan_filter_data(struct btd_adapter *adapter,
+                                                       struct eir_msd *msd)
+{
+       GSList *list;
+       DBG("");
+       list = g_slist_find_custom(adapter->manufaturer_data_filters, msd, adapter_le_manufacturer_data_cmp);
+       if (!list)
+               return NULL;
+       else
+               return list->data;
+
+       return NULL;
+}
+
+static gboolean adapter_le_service_delete_manufacturer_scan_filter_data(struct btd_adapter *adapter,
+                                                       int filter_index, int company_id, int company_id_mask,
+                                                       uint8_t *p_data, uint8_t *p_mask, int data_len)
+{
+       GSList *list;
+       DBG("");
+       list = g_slist_find_custom(adapter->manufaturer_data_filters, GINT_TO_POINTER(filter_index), adapter_le_manufacturer_data_filter_index_cmp);
+       if (!list)
+               return FALSE;
+       else {
+               adapter_le_manf_data_params_t *params = list->data;
+               /* Delete info from the struct to list */
+               if (params && strcasecmp((const char *)params->man_data, (const char *)p_data)) {
+                       adapter->manufaturer_data_filters = g_slist_delete_link(adapter->manufaturer_data_filters, list);
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_clear_manufacturer_scan_filter_data(struct btd_adapter *adapter)
+{
+       DBG("");
+
+       g_slist_free_full(adapter->manufaturer_data_filters, manufacturer_filter_params_free);
+       adapter->manufaturer_data_filters = NULL;
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_add_local_name_scan_filter_data(struct btd_adapter *adapter,
+                                                                                       int filter_index, gchar *name)
+{
+
+       adapter_le_local_name_params_t *params;
+
+       DBG("");
+
+       params = g_new0(adapter_le_local_name_params_t, 1);
+       if (!params)
+               return FALSE;
+
+       params->filter_index = filter_index;
+       params->local_name = g_strdup(name);
+       params->name_len = strlen(name);
+
+       /* Store the struct to list */
+       adapter->local_name_filters = g_slist_append(adapter->local_name_filters, params);
+
+       return TRUE;
+}
+
+static adapter_le_local_name_params_t *adapter_le_service_find_local_name_scan_filter_data(
+                                                                                               struct btd_adapter *adapter,
+                                                                                               gchar *name)
+{
+       GSList *list;
+       DBG("");
+       list = g_slist_find_custom(adapter->local_name_filters, name, adapter_le_local_name_cmp);
+       if (!list)
+               return NULL;
+       else
+               return list->data;
+
+       return NULL;
+}
+
+static gboolean adapter_le_service_delete_local_name_scan_filter_data(struct btd_adapter *adapter,
+                                                                                               int filter_index, gchar *name)
+{
+       GSList *list;
+       DBG("");
+       list = g_slist_find_custom(adapter->local_name_filters, GINT_TO_POINTER(filter_index), adapter_le_local_name_filter_index_cmp);
+       if (!list)
+               return FALSE;
+       else {
+               adapter_le_local_name_params_t *params = list->data;
+               /* Delete info from the struct to list */
+               if (params && strcasecmp((const char *)params->local_name, (const char *)name)) {
+                       adapter->local_name_filters = g_slist_delete_link(adapter->local_name_filters, list);
+               }
+       }
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_clear_local_name_scan_filter_data(struct btd_adapter *adapter)
+{
+       DBG("");
+
+       g_slist_free_full(adapter->local_name_filters, local_name_filter_params_free);
+       adapter->local_name_filters = NULL;
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_add_service_scan_filter_data(struct btd_adapter *adapter,
+                                                       int filter_index, uint8_t *p_data, uint8_t *p_mask, int data_len)
+{
+       adapter_le_service_data_params_t *params;
+
+       DBG("");
+
+       params = g_new0(adapter_le_service_data_params_t, 1);
+       if (!params)
+               return FALSE;
+
+       params->filter_index = filter_index;
+       params->service_data = g_new0(uint8_t, data_len);
+       memcpy(params->service_data, p_data, data_len);
+       params->service_data_mask = g_new0(uint8_t, data_len);
+       memcpy(params->service_data_mask, p_mask, data_len);
+       params->service_data_len = data_len;
+
+       /* Store the struct to list */
+       adapter->service_data_filters = g_slist_append(adapter->service_data_filters, params);
+
+       return TRUE;
+}
+
+static adapter_le_service_data_params_t *adapter_le_service_find_service_scan_filter_data(
+                                                       struct btd_adapter *adapter, struct eir_sd *sd)
+{
+       GSList *list;
+       DBG("");
+
+       list = g_slist_find_custom(adapter->service_data_filters, sd, adapter_le_service_data_cmp);
+       if (!list)
+               return NULL;
+       else
+               return list->data;
+
+       return NULL;
+}
+
+static gboolean adapter_le_service_delete_service_scan_filter_data(struct btd_adapter *adapter,
+                                                       int filter_index, uint8_t *p_data, uint8_t *p_mask, int data_len)
+{
+       GSList *list;
+       DBG("");
+
+       list = g_slist_find_custom(adapter->service_data_filters, GINT_TO_POINTER(filter_index), adapter_le_service_data_filter_index_cmp);
+       if (!list)
+               return FALSE;
+       else {
+               adapter_le_service_data_params_t *params = list->data;
+               /* Delete info from the struct to list */
+               if (params && strcasecmp((const char *)params->service_data, (const char *)p_data)) {
+                       adapter->service_data_filters = g_slist_delete_link(adapter->service_data_filters, list);
+               }
+       }
+       return TRUE;
+}
+
+static gboolean adapter_le_service_clear_service_scan_filter_data(struct btd_adapter *adapter)
+{
+       DBG("");
+
+       g_slist_free_full(adapter->service_data_filters, service_data_filter_params_free);
+       adapter->service_data_filters = NULL;
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_add_scan_filter_params(struct btd_adapter *adapter,
+                                                       adapter_le_scan_filter_param_t *params)
+{
+       adapter_le_scan_filter_param_t *l_params;
+
+       DBG("");
+
+       l_params = g_new0(adapter_le_scan_filter_param_t, 1);
+       if (!l_params)
+               return FALSE;
+
+       l_params->action = params->action;
+       l_params->delivery_mode = params->delivery_mode;
+       l_params->feature = params->feature;
+       l_params->filter_logic_type = params->filter_logic_type;
+       l_params->index = params->index;
+       l_params->list_logic_type = params->list_logic_type;
+       l_params->onfound_timeout = params->onfound_timeout;
+       l_params->onfound_timeout_cnt = params->onfound_timeout_cnt;
+       l_params->rssi_high_threshold = params->rssi_high_threshold;
+       l_params->rssi_low_threshold = params->rssi_low_threshold;
+
+       /* Store the struct to list */
+       adapter->scan_params = g_slist_append(adapter->scan_params, l_params);
+
+       return TRUE;
+}
+
+static adapter_le_service_data_params_t *adapter_le_service_find_scan_filter_params(
+                                                       struct btd_adapter *adapter, int filter_index)
+{
+       GSList *list;
+       DBG("");
+
+       list = g_slist_find_custom(adapter->scan_params, GINT_TO_POINTER(filter_index), adapter_le_scan_params_filter_index_cmp);
+       if (!list)
+               return NULL;
+       else
+               return list->data;
+
+       return NULL;
+}
+
+static gboolean adapter_le_service_delete_scan_filter_params(struct btd_adapter *adapter,
+                                                       adapter_le_scan_filter_param_t *params)
+{
+       GSList *list;
+       DBG("");
+
+       list = g_slist_find_custom(adapter->scan_params, GINT_TO_POINTER(params->index), adapter_le_scan_params_filter_index_cmp);
+       if (!list)
+               return FALSE;
+       else
+               adapter->scan_params = g_slist_remove(adapter->scan_params, list);
+
+       return TRUE;
+}
+
+static gboolean adapter_le_service_clear_scan_filter_params(struct btd_adapter *adapter)
+{
+       DBG("");
+
+       g_slist_free_full(adapter->scan_params, scan_filter_params_free);
+       adapter->scan_params = NULL;
+
+       return TRUE;
+}
+
+int adapter_byte_arr_cmp_with_mask(const char *data1, const char *data2,
+        const char *mask, int data_len)
+{
+        int i;
+        char a, b;
+       if (data1 == NULL || data2 == NULL || mask == NULL)
+               return -1;
+        for (i = 0; i < data_len; i++) {
+                a = data1[i] & mask[i];
+                b = data2[i] & mask[i];
+                if (a != b)
+                        return (int)(a - b);
+                }
+        return 0;
+}
+
+static gboolean validate_for_filter_policy(struct btd_adapter *adapter, const struct eir_data *eir, gchar *addr)
+{
+       gboolean is_allowed = FALSE;
+       DBG("");
+
+       if (adapter->scan_filter_support == FALSE)
+               is_allowed = TRUE;
+       else {
+               if (adapter_le_service_find_addr_scan_filter_data(adapter, addr))
+                       is_allowed = TRUE;
+               if (eir->name) {
+                       if(adapter_le_service_find_local_name_scan_filter_data(adapter, eir->name))
+                               is_allowed = TRUE;
+                       }
+               if (eir->sd_list) {
+                       GSList *list = NULL;
+                       for (list = eir->sd_list; list != NULL; list = g_slist_next(list)) {
+                               struct eir_sd *sd = list->data;
+                               if (sd != NULL) {
+                                       static adapter_le_uuid_params_t *uuid_data = NULL;
+                                       static adapter_le_service_data_params_t *service_data = NULL;
+                                       static adapter_le_scan_filter_param_t *scan_param_data = NULL;
+                                       uuid_data = adapter_le_service_find_uuid_scan_filter_data(adapter, (uint8_t *)sd->uuid);
+                                       service_data = adapter_le_service_find_service_scan_filter_data(adapter, sd);
+                                       if (service_data != NULL) {
+                                               if (!adapter_byte_arr_cmp_with_mask((const char *)service_data->service_data,
+                                               (const char *)sd->data, (const char *)service_data->service_data_mask,
+                                               service_data->service_data_len)) {
+                                                       scan_param_data = adapter_le_service_find_scan_filter_params(adapter,
+                                                                               service_data->filter_index);
+                                                       if (scan_param_data && scan_param_data->rssi_high_threshold > eir->tx_power &&
+                                                               scan_param_data->rssi_low_threshold < eir->tx_power)
+                                                               is_allowed = TRUE;
+                                               }
+                                       }
+                                       if (uuid_data != NULL) {
+                                               if (!adapter_byte_arr_cmp_with_mask((const char *)uuid_data->uuid,
+                                               (const char *)sd->uuid, (const char *)uuid_data->uuid_mask,
+                                               uuid_data->uuid_len)) {
+                                                       scan_param_data = adapter_le_service_find_scan_filter_params(adapter,
+                                                                                               uuid_data->filter_index);
+                                                       if (scan_param_data && scan_param_data->rssi_high_threshold > eir->tx_power &&
+                                                               scan_param_data->rssi_low_threshold < eir->tx_power)
+                                                               is_allowed = TRUE;
+                                               }
+                                       }
+                                       if (is_allowed)
+                                               break;
+                               }
+                       }
+               }
+               if (eir->msd_list) {
+                       GSList *list = NULL;
+                       for (list = eir->msd_list; list != NULL; list = g_slist_next(list)) {
+                               struct eir_msd *msd = list->data;
+                               if (msd != NULL) {
+                                       static adapter_le_manf_data_params_t *manuf_data;
+                                       static adapter_le_scan_filter_param_t *scan_param_data = NULL;
+                                       manuf_data = adapter_le_service_find_manufacturer_scan_filter_data(adapter,
+                                                       msd);
+                                       if (manuf_data != NULL) {
+                                               if (!adapter_byte_arr_cmp_with_mask((const char *)msd->data,
+                                                       (const char *)manuf_data->man_data, (const char *)manuf_data->man_data_mask,
+                                                       manuf_data->man_data_len)) {
+                                                               scan_param_data = adapter_le_service_find_scan_filter_params(adapter,
+                                                                                                       manuf_data->filter_index);
+                                                               if (scan_param_data && scan_param_data->rssi_high_threshold > eir->tx_power &&
+                                                                       scan_param_data->rssi_low_threshold < eir->tx_power)
+                                                                       is_allowed = TRUE;
+                                                       }
+                                       }
+                               }
+                       }
+               }
+       }
+       return is_allowed;
+}
+
+gboolean adapter_le_set_platform_scan_filter_params(struct btd_adapter *adapter,
+                                       adapter_le_scan_filter_param_t *params)
+{
+       gboolean ret = TRUE;
+       DBG("adapter_le_scan_filter_param_t [%d]", params->index);
+       adapter_le_scan_filter_action_type action_type = params->action;
+
+       if (action_type == ADD) {
+               ret = adapter_le_service_add_scan_filter_params(adapter, params);
+       } else if (action_type == DELETE) {
+               ret = adapter_le_service_delete_scan_filter_params(adapter, params);
+       } else if (action_type == CLEAR) {
+               ret = adapter_le_service_clear_scan_filter_params(adapter);
+       } else {
+               DBG("filter_action error");
+               ret = FALSE;
+       }
+
+       DBG("Scan Filter VSC :: Action [%x]",
+                                       params->action);
+       return ret;
+}
+
+gboolean adapter_le_set_platform_scan_filter_data(struct btd_adapter *adapter,
+                                               int client_if, int action,
+                                               int filt_type, int filter_index,
+                                               int company_id,
+                                               int company_id_mask,
+                                               int uuid_len, uint8_t *p_uuid,
+                                               int uuid_mask_len, uint8_t *p_uuid_mask,
+                                               gchar *string, int addr_type,
+                                               int data_len, uint8_t *p_data,
+                                               int mask_len, uint8_t *p_mask)
+{
+       gboolean ret = TRUE;
+
+       DBG("");
+
+       switch (filt_type) {
+       case TYPE_DEVICE_ADDRESS: {
+               /* TYPE_DEVICE_ADDRESS */
+               adapter_le_scan_filter_action_type action_type = action;
+
+               if (action_type == ADD) {
+                       ret = adapter_le_service_add_addr_scan_filter_data(adapter,
+                                               filter_index, string, addr_type);
+               } else if (action_type == DELETE) {
+                       ret = adapter_le_service_delete_addr_scan_filter_data(adapter,
+                                               filter_index, string, addr_type);
+               } else if (action_type == CLEAR) {
+                       ret = adapter_le_service_clear_addr_scan_filter_data(adapter);
+               } else {
+                       DBG("filter_action error");
+                       ret = FALSE;
+               }
+
+               break;
+       }
+
+       case TYPE_SERVICE_UUID:
+       case TYPE_SOLICIT_UUID: {
+               adapter_le_scan_filter_action_type action_type = action;
+
+               gboolean is_solicited = (filt_type == TYPE_SOLICIT_UUID) ? TRUE : FALSE;
+
+               if (uuid_len != UUID_16_LEN && uuid_len != UUID_32_LEN
+                       && uuid_len != UUID_128_LEN) {
+                       DBG("UUID length error");
+                       return FALSE;
+               }
+
+               if (uuid_len != uuid_mask_len) {
+                       DBG("Both UUID and UUID_MASK length shoule be samed");
+                       return FALSE;
+               }
+
+               if (action_type == ADD) {
+                       ret = adapter_le_service_add_uuid_scan_filter_data(adapter,
+                                               filter_index, is_solicited, p_uuid,
+                                               p_uuid_mask, uuid_len);
+               } else if (action_type == DELETE) {
+                       ret = adapter_le_service_delete_uuid_scan_filter_data(adapter,
+                                               filter_index, is_solicited, p_uuid,
+                                               p_uuid_mask, uuid_len);
+               } else if (action_type == CLEAR) {
+                       ret = adapter_le_service_clear_uuid_scan_filter_data(adapter);
+               } else {
+                       DBG("filter_action error");
+                       ret = FALSE;
+               }
+
+               break;
+       }
+
+       case TYPE_LOCAL_NAME: {
+               adapter_le_scan_filter_action_type action_type = action;
+
+               if (action_type == ADD) {
+                       ret = adapter_le_service_add_local_name_scan_filter_data(adapter,
+                                               filter_index, (gchar*)string);
+               } else if (action_type == DELETE) {
+                       ret = adapter_le_service_delete_local_name_scan_filter_data(adapter,
+                                               filter_index, (gchar*)string);
+               } else if (action_type == CLEAR) {
+                       ret = adapter_le_service_clear_local_name_scan_filter_data(adapter);
+               } else {
+                       DBG("filter_action error");
+                       ret = FALSE;
+               }
+
+               break;
+       }
+
+       case TYPE_MANUFACTURER_DATA: {
+               adapter_le_scan_filter_action_type action_type = action;
+
+               if (data_len == 0 || (data_len != mask_len)) {
+                       DBG("parameter length error");
+                       return FALSE;
+               }
+
+               if (action_type == ADD) {
+                       ret = adapter_le_service_add_manufacturer_scan_filter_data(adapter,
+                                               filter_index,company_id, company_id_mask, p_data, p_mask, data_len);
+               } else if (action_type == DELETE) {
+                       ret = adapter_le_service_delete_manufacturer_scan_filter_data(adapter,
+                                               filter_index, company_id, company_id_mask, p_data, p_mask, data_len);
+               } else if (action_type == CLEAR) {
+                       ret = adapter_le_service_clear_manufacturer_scan_filter_data(adapter);
+               } else {
+                       DBG("filter_action error");
+                       ret = FALSE;
+               }
+
+               break;
+       }
+
+       case TYPE_SERVICE_DATA: {
+               adapter_le_scan_filter_action_type action_type = action;
+
+               if (data_len == 0 || (data_len != mask_len)) {
+                       DBG("parameter length error");
+                       return FALSE;
+               }
+
+               if (action_type == ADD) {
+                       ret = adapter_le_service_add_service_scan_filter_data(adapter,
+                                               filter_index, p_data, p_mask, data_len);
+               } else if (action_type == DELETE) {
+                       ret = adapter_le_service_delete_service_scan_filter_data(adapter,
+                                               filter_index, p_data, p_mask, data_len);
+               } else if (action_type == CLEAR) {
+                       ret = adapter_le_service_clear_service_scan_filter_data(adapter);
+               } else {
+                       DBG("filter_action error");
+                       ret = FALSE;
+               }
+
+               break;
+       }
+
+       default:
+               DBG("filter_type error");
+               ret = FALSE;
+       }
+
+       return ret;
+}
+#endif
 
 static int set_adv_data_flag(uint8_t *adv_data, uint8_t *data, int data_len)
 {
@@ -3307,6 +4230,9 @@ static DBusMessage *adapter_le_scan_filter_param_setup(DBusConnection *conn,
                                                DBusMessage *msg, void *data)
 {
        struct btd_adapter *adapter = data;
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       dbus_bool_t ctlr_filter_support = TRUE;
+#endif
        dbus_int32_t client_if, action, filt_index;
        dbus_int32_t feat_seln, list_logic_type, filt_logic_type;
        dbus_int32_t rssi_high_thres, rssi_low_thres, dely_mode;
@@ -3320,7 +4246,11 @@ static DBusMessage *adapter_le_scan_filter_param_setup(DBusConnection *conn,
                return btd_error_not_ready(msg);
 
        if (adapter_le_get_scan_filter_size() == 0)
+#ifndef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
                return btd_error_not_supported(msg);
+#else
+               ctlr_filter_support = FALSE;
+#endif
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
                                                DBUS_TYPE_INT32, &action,
@@ -3354,7 +4284,14 @@ static DBusMessage *adapter_le_scan_filter_param_setup(DBusConnection *conn,
                params.onlost_timeout = lost_timeout;
        }
 
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       if (ctlr_filter_support)
+#endif
        err = adapter_le_set_scan_filter_params(&params);
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       else
+               err = adapter_le_set_platform_scan_filter_params(adapter, &params);
+#endif
 
        if (!err)
                return btd_error_failed(msg, "Failed to scan filter param setup");
@@ -3377,14 +4314,25 @@ static DBusMessage *adapter_le_scan_filter_add_remove(DBusConnection *conn,
        uint8_t *p_uuid, *p_uuid_mask, *p_data, *p_mask;
        int32_t uuid_len = 0, uuid_mask_len = 0, data_len = 0, mask_len = 0;
        gboolean err;
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       dbus_bool_t ctlr_filter_support = TRUE;
+#endif
 
        DBG("adapter_le_scan_filter_add_remove");
 
        if (!(adapter->current_settings & MGMT_SETTING_POWERED))
                return btd_error_not_ready(msg);
 
-       if (adapter_le_get_scan_filter_size() == 0)
+       /* if controller does not support vendor specific scan filtering feature
+        * then add the filter into platform supported scan filters.
+        */
+       if (adapter_le_get_scan_filter_size() == 0) {
+#ifndef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
                return btd_error_not_supported(msg);
+#else
+               ctlr_filter_support = FALSE;
+#endif
+       }
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
                                                DBUS_TYPE_INT32, &action,
@@ -3420,11 +4368,20 @@ static DBusMessage *adapter_le_scan_filter_add_remove(DBusConnection *conn,
 
        DBG("addr %s, type %d", ida_string, addr_type);
 
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       if (ctlr_filter_support)
+#endif
        err = adapter_le_set_scan_filter_data(client_if, action, filt_type,
                        filt_index, company_id, company_id_mask,
                        uuid_len, p_uuid, uuid_mask_len, p_uuid_mask,
                        ida_string, addr_type, data_len, p_data, mask_len, p_mask);
-
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       else
+               err = adapter_le_set_platform_scan_filter_data(adapter, client_if, action, filt_type,
+                               filt_index, company_id, company_id_mask,
+                               uuid_len, p_uuid, uuid_mask_len, p_uuid_mask,
+                               ida_string, addr_type, data_len, p_data, mask_len, p_mask);
+#endif
        if (!err)
                return btd_error_failed(msg, "Failed to add/remove filter");
 
@@ -3438,6 +4395,9 @@ static DBusMessage *adapter_le_scan_filter_clear(DBusConnection *conn,
        dbus_int32_t client_if = 0;
        dbus_int32_t filt_index = 0;
        gboolean err;
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       dbus_bool_t ctlr_filter_support = TRUE;
+#endif
 
        DBG("adapter_le_scan_filter_clear");
 
@@ -3445,14 +4405,25 @@ static DBusMessage *adapter_le_scan_filter_clear(DBusConnection *conn,
                return btd_error_not_ready(msg);
 
        if (adapter_le_get_scan_filter_size() == 0)
+#ifndef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
                return btd_error_not_supported(msg);
+#else
+               ctlr_filter_support = FALSE;
+#endif
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
                                                DBUS_TYPE_INT32, &filt_index,
                                                DBUS_TYPE_INVALID))
                return btd_error_invalid_args(msg);
 
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       if (ctlr_filter_support)
+#endif
        err = adapter_le_clear_scan_filter_data(client_if, filt_index);
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       else
+               err = adapter_le_clear_platform_scan_filter_data(adapter, filt_index);
+#endif
 
        if (!err)
                return btd_error_failed(msg, "Failed to clear filter");
@@ -3468,21 +4439,40 @@ static DBusMessage *adapter_le_scan_filter_enable(DBusConnection *conn,
        dbus_bool_t enable = FALSE;
        dbus_int32_t client_if = 0;
        gboolean err;
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       dbus_bool_t ctlr_filter_support = TRUE;
+#endif
 
        DBG("adapter_le_scan_filter_enable");
 
        if (!(adapter->current_settings & MGMT_SETTING_POWERED))
                return btd_error_not_ready(msg);
 
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       /* if controller does not support vendor specific scan filtering feature
+        * then enable platform supported scan filtering functionalites.
+        */
+#endif
        if (adapter_le_get_scan_filter_size() == 0)
+#ifndef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
                return btd_error_not_supported(msg);
+#else
+               ctlr_filter_support = FALSE;
+#endif
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
                                                DBUS_TYPE_BOOLEAN, &enable,
                                                DBUS_TYPE_INVALID))
                return btd_error_invalid_args(msg);
 
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       if (ctlr_filter_support)
+#endif
        err = adapter_le_enable_scan_filtering(enable);
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       else
+               err = adapter_le_enable_platform_scan_filtering(adapter, enable);
+#endif
 
        if (!err)
                return btd_error_failed(msg, "Failed to enable scan filtering");
@@ -3518,6 +4508,7 @@ static DBusMessage *adapter_le_set_scan_params(DBusConnection *conn,
        cp.type = type;
        cp.interval = interval;
        cp.window = window;
+       adapter->scan_type = type;
 
        if (mgmt_send(adapter->mgmt, MGMT_OP_LE_SET_SCAN_PARAMS,
                                        adapter->dev_id, sizeof(cp), &cp,
@@ -5430,6 +6421,10 @@ static gboolean property_get_supported_le_features(
        }
 
        value = adapter_le_get_scan_filter_size();
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       if (value <= 0)
+               value = SCAN_FILTER_SLOTS_MAX;
+#endif
        if (value > 0) {
                str = g_strdup("max_filter");
                dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
@@ -7328,6 +8323,11 @@ static void adapter_start(struct btd_adapter *adapter)
        if (adapter_le_read_ble_feature_info())
                g_dbus_emit_property_changed(dbus_conn, adapter->path,
                        ADAPTER_INTERFACE, "SupportedLEFeatures");
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       else
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "SupportedLEFeatures");
+#endif
 
        adapter_get_adv_tx_power(adapter);
 
@@ -8750,6 +9750,9 @@ static void update_found_devices(struct btd_adapter *adapter,
        struct btd_device *dev;
        struct eir_data eir_data;
        bool name_known, discoverable;
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       bool is_allowed;
+#endif
        char addr[18];
 
        memset(&eir_data, 0, sizeof(eir_data));
@@ -8762,6 +9765,15 @@ static void update_found_devices(struct btd_adapter *adapter,
 
        ba2str(bdaddr, addr);
 
+#ifdef TIZEN_FEATURE_PLATFROM_SCAN_FILTER
+       /* Check if the any filter policy */
+       is_allowed = validate_for_filter_policy(adapter, &eir_data, addr);
+       if (!is_allowed && ((adapter->scan_type == 1 && adv_type == 04) ||
+                       adapter->scan_type == 0)) {
+               eir_data_free(&eir_data);
+               return;
+       }
+#endif
        dev = btd_adapter_find_device(adapter, bdaddr, bdaddr_type);
        if (!dev) {
                /*