summaryrefslogtreecommitdiffstats
path: root/utils/src
diff options
context:
space:
mode:
authorSrinu Jella <sjella@codeaurora.org>2015-10-08 17:14:16 +0530
committerSrinu Jella <sjella@codeaurora.org>2015-10-15 11:26:42 +0530
commit3692a46fd8a70dbaaaf9f88565d1116a0004e348 (patch)
tree5423b9ec81b0f19e83d1ea6431be1a8b26474265 /utils/src
parent372bc8d755d4fd727c6a85355532551bdd415bf5 (diff)
downloadandroid_system_bt-3692a46fd8a70dbaaaf9f88565d1116a0004e348.tar.gz
android_system_bt-3692a46fd8a70dbaaaf9f88565d1116a0004e348.tar.bz2
android_system_bt-3692a46fd8a70dbaaaf9f88565d1116a0004e348.zip
Bluetooth: Implement dynamic blacklist method for role switch
- Blacklist the device if it's rejected the role switch for max number of times.Same is added to the iot_devlist.conf file. - Maximum number of failed (BTM_MAX_SW_ROLE_FAILED_ATTEMPTS) attempts set to 3 and it is configurable. - Same blacklisted device is referred by the BTM module when any other module like profile is requesting for role switch and BTM module returns BTM_REPEATED_ATTEMPTS as the switch role status. - There is option to retry for role switch even though the device is blacklisted and it can be controlled by feature flag BTM_SAFE_REATTEMPT_ROLE_SWITCH. And by default it is enabled. CRs-Fixed: 831542 Change-Id: I570e1539578e60901794941ca46f0722e368a954
Diffstat (limited to 'utils/src')
-rw-r--r--utils/src/bt_utils.c884
1 files changed, 884 insertions, 0 deletions
diff --git a/utils/src/bt_utils.c b/utils/src/bt_utils.c
index 4a73c8057..4bd4abdf6 100644
--- a/utils/src/bt_utils.c
+++ b/utils/src/bt_utils.c
@@ -42,8 +42,38 @@
#include "btcore/include/module.h"
#include "osi/include/compat.h"
#include "osi/include/log.h"
+#include "gki.h"
+#include "list.h"
+#include <string.h>
/*******************************************************************************
+** Local type definitions
+*******************************************************************************/
+typedef struct {
+ char header_name[MAX_NAME_LEN]; // name of header in iot_devlist_conf file
+ list_t *devlist; // list of BD addresses
+ tBLACKLIST_METHOD method_type;
+} iot_header_node_t;
+
+typedef struct {
+ char dev_bd[3]; // BD address of blacklisted device
+} iot_devlist_bd_node_t;
+
+typedef struct {
+ char dev_name[MAX_NAME_LEN]; // Name of blacklisted device
+} iot_devlist_name_node_t;
+
+typedef struct {
+ char *header; // header name
+ unsigned char *dev_details; // details of blacklisted device
+ bool device_found;
+} iot_input_param;
+
+static list_t *iot_header_queue = NULL;
+#define MAX_LINE 2048
+#define MAX_ADDR_STR_LEN 9
+static pthread_mutex_t iot_mutex_lock;
+/*******************************************************************************
** Type definitions for callback functions
********************************************************************************/
static pthread_once_t g_DoSchedulingGroupOnce[TASK_HIGH_MAX];
@@ -65,11 +95,13 @@ static future_t *init(void) {
pthread_mutexattr_init(&lock_attr);
pthread_mutex_init(&gIdxLock, &lock_attr);
+ pthread_mutex_init(&iot_mutex_lock, NULL);
return NULL;
}
static future_t *clean_up(void) {
pthread_mutex_destroy(&gIdxLock);
+ pthread_mutex_destroy(&iot_mutex_lock);
return NULL;
}
@@ -174,3 +206,855 @@ void adjust_priority_a2dp(int start) {
}
}
}
+
+/*****************************************************************************
+**
+** Function check_bd_cb
+**
+** Description Compares the BD address.
+**
+** Returns returns true if the BD address matches otherwise false
+**
+*******************************************************************************/
+static bool check_bd_cb(void* node, void* cb_data)
+{
+ iot_devlist_bd_node_t *bd_node = (iot_devlist_bd_node_t*)node;
+ iot_input_param *input_param = (iot_input_param*)cb_data;
+
+ if (input_param->device_found == true)
+ return true;
+
+ if ((bd_node->dev_bd[0] == input_param->dev_details[0]) &&
+ (bd_node->dev_bd[1] == input_param->dev_details[1]) &&
+ (bd_node->dev_bd[2] == input_param->dev_details[2])) {
+ input_param->device_found = true;
+ return true;
+ }
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function check_name_cb
+**
+** Description Compares the Device name.
+**
+** Returns returns true if the name matches otherwise false
+**
+*******************************************************************************/
+static bool check_name_cb(void* node, void* cb_data)
+{
+ iot_devlist_name_node_t *name_node = (iot_devlist_name_node_t*)node;
+ iot_input_param *input_param = (iot_input_param*)cb_data;
+
+ if (input_param->device_found == true)
+ return true;
+
+ if (!strncmp(name_node->dev_name, (const char*)input_param->dev_details,
+ strlen((char *)input_param->dev_details))) {
+ input_param->device_found = true;
+ return true;
+ }
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function check_header_cb
+**
+** Description Iterates through the each entry in the header list and
+** calls the callback associated to each entry.
+**
+** Returns boolean
+**
+*******************************************************************************/
+static bool check_header_cb(void* node, void* cb_data)
+{
+ iot_header_node_t *header_node = (iot_header_node_t*)node;
+ iot_input_param *input_param = (iot_input_param*)cb_data;
+ if (!strcmp(header_node->header_name, input_param->header)) {
+ if(header_node->devlist) {
+ if (header_node->method_type == METHOD_BD)
+ list_foreach_ext(header_node->devlist, check_bd_cb, cb_data);
+ else if (header_node->method_type == METHOD_NAME)
+ list_foreach_ext(header_node->devlist, check_name_cb, cb_data);
+ }
+ }
+ return true;
+}
+
+/*****************************************************************************
+**
+** Function is_device_present
+**
+** Description Checks if the device is already present in the blacklisted
+** device list or not.The input can be address based or name
+** based.
+**
+** Returns true incase device is present false otherwise.
+**
+*******************************************************************************/
+bool is_device_present(char* header, unsigned char* device_details)
+{
+ int device_present = false;
+ iot_input_param input_param;
+ input_param.dev_details = device_details;
+ input_param.header = header;
+ input_param.device_found = false;
+
+ pthread_mutex_lock(&iot_mutex_lock);
+ if (!iot_header_queue) {
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+ list_foreach_ext(iot_header_queue, check_header_cb, &input_param);
+ pthread_mutex_unlock(&iot_mutex_lock);
+
+ if (input_param.device_found)
+ return true;
+ else
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function parse_bd
+**
+** Description It will read 3 bytes and copy them into node. It also
+** increments header pointer.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void parse_bd(char **start_ptr, iot_devlist_bd_node_t *bd)
+{
+ char *p_end;
+ bd->dev_bd[0] = (unsigned char)strtol(*start_ptr, &p_end, 16);
+ (*start_ptr) = p_end + 1;
+ bd->dev_bd[1] = (unsigned char)strtol(*start_ptr, &p_end, 16);
+ (*start_ptr) = p_end + 1;
+ bd->dev_bd[2] = (unsigned char)strtol(*start_ptr, &p_end, 16);
+ (*start_ptr) = p_end;
+}
+
+/*****************************************************************************
+**
+** Function parse_name
+**
+** Description It will read name and copy them into node. It also
+** increments header pointer.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void parse_name(char **start_ptr, iot_devlist_name_node_t *name)
+{
+ char *split = strchr(*start_ptr, ','); // split point to first occurrence of ,
+ int len = 0;
+ if (split == NULL) {
+ // check once for end of line, for the last name in list
+ split = strchr(*start_ptr, '\n');
+ if (split == NULL)
+ return;
+ }
+ len = (((split - (*start_ptr)) >= MAX_NAME_LEN) ? MAX_NAME_LEN - 1 :
+ (split - (*start_ptr)));
+ memcpy(name->dev_name, *start_ptr, len);
+ name->dev_name[len] = '\0';
+ *start_ptr = split;
+}
+
+/*****************************************************************************
+**
+** Function is_device_node_exist
+**
+** Description Checks if the device node is already present in the queue
+** or not.The input can be address based or name based.
+**
+** Returns true if the entry found else false.
+**
+*******************************************************************************/
+static bool is_device_node_exist(iot_header_node_t *header_entry, char* device_details,
+ tBLACKLIST_METHOD method_type)
+{
+ if(!header_entry || !header_entry->devlist)
+ return false;
+
+ for (const list_node_t *device_node = list_begin(header_entry->devlist);
+ device_node != list_end(header_entry->devlist);
+ device_node = list_next(device_node)) {
+ if(method_type == METHOD_BD) {
+ iot_devlist_bd_node_t *bd_addr_entry = list_node(device_node);
+ if(!memcmp(device_details, bd_addr_entry->dev_bd, 3)) {
+ return true;
+ }
+ }
+ else if(method_type == METHOD_NAME) {
+ iot_devlist_name_node_t *bd_name_entry = list_node(device_node);
+ if(!strcmp((char *)device_details, bd_name_entry->dev_name)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function populate_list
+**
+** Description It goes through the input buffer and add device node to the
+** header list if the valid entry is found.It ignores the
+** duplicated entries.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void populate_list(char *header_end, iot_header_node_t *node)
+{
+ if(node->devlist == NULL)
+ node->devlist = list_new(GKI_freebuf);
+ while(header_end && (*header_end != '\n')&&(*header_end != '\0')) // till end of line reached
+ {
+ // read from line buffer and copy to list
+ if (node->method_type == METHOD_BD) {
+ iot_devlist_bd_node_t *bd = GKI_getbuf(sizeof(iot_devlist_bd_node_t));
+ if(bd == NULL) {
+ ALOGE(" Unable to allocate memory for addr entry");
+ return;
+ }
+ header_end++;
+ parse_bd(&header_end, bd);
+ if(is_device_node_exist(node, (char *) bd, node->method_type)) {
+ GKI_freebuf(bd);
+ }
+ else {
+ list_append(node->devlist, bd);
+ }
+ }
+ else if (node->method_type == METHOD_NAME) {
+ iot_devlist_name_node_t *name = GKI_getbuf(sizeof(iot_devlist_name_node_t));
+ if(name == NULL) {
+ ALOGE(" Unable to allocate memory for name entry");
+ return;
+ }
+ header_end++;
+ parse_name(&header_end, name);
+ if(is_device_node_exist(node, (char *)name, node->method_type)) {
+ GKI_freebuf(name);
+ }
+ else {
+ list_append(node->devlist, name);
+ }
+ }
+ }
+}
+
+/*****************************************************************************
+**
+** Function create_header_node
+**
+** Description This function is used to create the header node.
+**
+** Returns valid pointer incase the node is created otherwise NULL.
+**
+*******************************************************************************/
+static iot_header_node_t *create_header_node(char* name, unsigned int len,
+ tBLACKLIST_METHOD method_type)
+{
+ iot_header_node_t *node = NULL;
+ if(len >= MAX_NAME_LEN) {
+ return NULL;
+ }
+ node = GKI_getbuf(sizeof(iot_header_node_t));
+ if (node == NULL) {
+ ALOGE(" Not enough memory to create the header node");
+ return NULL;
+ }
+ memcpy(node->header_name, name, len);
+ node->header_name[len] = '\0'; // header copied
+ node->method_type = method_type;
+ node->devlist = NULL;
+ return node;
+}
+
+/*****************************************************************************
+**
+** Function get_existing_header_node
+**
+** Description This function is used to get exisiting header node if present.
+**
+** Returns valid pointer incase the node is already prsent otherwise NULL.
+**
+*******************************************************************************/
+static iot_header_node_t *get_existing_header_node(char* name, unsigned int len)
+{
+ for (const list_node_t *node = list_begin(iot_header_queue);
+ node != list_end(iot_header_queue); node = list_next(node)) {
+ iot_header_node_t *entry = list_node(node);
+ if (!strncmp(entry->header_name, name, len)) {
+ return entry;
+ }
+ }
+ return NULL;
+}
+
+/*****************************************************************************
+**
+** Function populate_header
+**
+** Description It goes through the input buffer and add header node to the
+** main queue if the valid entry is found.It ignores the
+** duplicated entries.
+**
+** Returns void.
+**
+*******************************************************************************/
+static void populate_header(char* line_start, char *header_end)
+{
+ tBLACKLIST_METHOD method_type;
+ iot_header_node_t *node = NULL;
+
+ if (*(header_end + 3) == ':')
+ method_type = METHOD_BD;
+ else
+ method_type = METHOD_NAME;
+
+ if (!iot_header_queue) {
+ iot_header_queue = list_new(GKI_freebuf);
+ if (iot_header_queue == NULL) {
+ ALOGE(" Not enough memory to create the queue");
+ return;
+ }
+ }
+
+ if( (node = get_existing_header_node(line_start, header_end - line_start)) == NULL) {
+ node = create_header_node(line_start, header_end - line_start, method_type);
+ if(node)
+ list_append(iot_header_queue, node);
+ }
+ if(node)
+ populate_list(header_end, node);
+}
+
+/*****************************************************************************
+**
+** Function free_header_list
+**
+** Description This function is used to free all entries under blacklist
+** queue.
+**
+** Returns boolean
+**
+*******************************************************************************/
+static bool free_header_list(void* node)
+{
+ iot_header_node_t *header_node = (iot_header_node_t*)node;
+ list_free(header_node->devlist);
+ return true;
+}
+
+/*****************************************************************************
+**
+** Function unload_iot_devlist
+**
+** Description This function is used to free the IOT blacklist queue.
+**
+** Returns void
+**
+*******************************************************************************/
+void unload_iot_devlist()
+{
+ pthread_mutex_lock(&iot_mutex_lock);
+ if (!iot_header_queue) {
+ ALOGV(" Blacklist queue is not initialized ");
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return;
+ }
+ list_foreach(iot_header_queue, free_header_list);
+ list_free(iot_header_queue);
+ iot_header_queue = NULL;
+ pthread_mutex_unlock(&iot_mutex_lock);
+}
+
+/*****************************************************************************
+**
+** Function copy_file
+**
+** Description This function is used to copy one file to other.
+**
+** Returns true incase copy is successful otherwise false.
+**
+*******************************************************************************/
+static bool copy_file(const char *src, const char *dst)
+{
+ FILE *src_fp = NULL, *dst_fp = NULL;
+ int ch;
+
+ if( !src || !dst) {
+ return false;
+ }
+ src_fp = fopen(src, "rt");
+ if(src_fp)
+ dst_fp = fopen(dst, "wt");
+ if(src_fp && dst_fp) {
+ while( ( ch = fgetc(src_fp) ) != EOF ) {
+ fputc(ch, dst_fp);
+ }
+ fclose(dst_fp);
+ fclose(src_fp);
+ return true;
+ }
+ else {
+ if(src_fp)
+ fclose(src_fp);
+ if(dst_fp)
+ fclose(dst_fp);
+ return false;
+ }
+}
+
+/*****************************************************************************
+**
+** Function dump_all_iot_devices
+**
+** Description This function is used to print all blacklisted devices
+** which are loaded from iot_devlist.conf file..
+**
+** Returns void.
+**
+*******************************************************************************/
+static void dump_all_iot_devices(void)
+{
+ tBLACKLIST_METHOD method_type;
+
+ if(!iot_header_queue)
+ return;
+
+ for (const list_node_t *header_node = list_begin(iot_header_queue);
+ header_node != list_end(iot_header_queue);
+ header_node = list_next(header_node)) {
+ iot_header_node_t *header_entry = list_node(header_node);
+ method_type = header_entry->method_type;
+
+ if(!header_entry->devlist)
+ continue;
+
+ ALOGW(" ########### Blacklisted Device summary ##############");
+ for (const list_node_t *device_node = list_begin(header_entry->devlist);
+ device_node != list_end(header_entry->devlist);
+ device_node = list_next(device_node)) {
+ if(method_type == METHOD_BD) {
+ iot_devlist_bd_node_t *bd_addr_entry = list_node(device_node);
+ ALOGW(" Device %02X:%02X:%02X Blacklisted under %s",
+ bd_addr_entry->dev_bd[0], bd_addr_entry->dev_bd[1],
+ bd_addr_entry->dev_bd[2], header_entry->header_name);
+ }
+ else if(method_type == METHOD_NAME) {
+ iot_devlist_name_node_t *bd_name_entry = list_node(device_node);
+ ALOGW(" Device %s Blacklisted under %s", bd_name_entry->dev_name,
+ header_entry->header_name);
+ }
+ }
+ }
+}
+
+/*****************************************************************************
+**
+** Function load_iot_devlist_from_file
+**
+** Description This function is used to initialize the queue and load the
+** load the devices from file.
+**
+** Returns void.
+**
+*******************************************************************************/
+void load_iot_devlist_from_file(const char *filename)
+{
+ if (!filename) {
+ ALOGE(" Invalid IOT blacklist filename");
+ return;
+ }
+ char line_start[MAX_LINE];
+ int line_number = 0;
+ char *header_end = NULL;
+ FILE *iot_devlist_fp = fopen(filename, "rt");
+ if (iot_devlist_fp == NULL) {
+ if(!strcmp(filename, IOT_DEV_CONF_FILE)) {
+ //load it from system partition
+ if(copy_file(IOT_DEV_BASE_CONF_FILE, IOT_DEV_CONF_FILE) == false) {
+ ALOGE(" Can't copy it from Base file %s", IOT_DEV_BASE_CONF_FILE);
+ return;
+ }
+ else {
+ if((iot_devlist_fp = fopen(filename, "rt")) == NULL)
+ return;
+ }
+ }
+ else {
+ ALOGE(" File %s does not exist ",filename);
+ return;
+ }
+ }
+ while(fgets(line_start, MAX_LINE, iot_devlist_fp)) {
+ line_number++;
+ if((*line_start == '\n') ||(*line_start == '#')) {
+ ALOGV("line %d is empty",line_number);
+ continue;
+ }
+ header_end = strchr(line_start, '=');
+ if (header_end == NULL) {
+ ALOGV(" NOT A valid line %d", line_number);
+ continue;
+ }
+ populate_header(line_start, header_end);
+ }
+ dump_all_iot_devices();
+ fclose(iot_devlist_fp);
+}
+
+/*****************************************************************************
+**
+** Function load_iot_devlist
+**
+** Description This function is used to initialize the queue.
+**
+** Returns void.
+**
+*******************************************************************************/
+void load_iot_devlist(const char *filename)
+{
+ pthread_mutex_lock(&iot_mutex_lock);
+ load_iot_devlist_from_file(filename);
+ pthread_mutex_unlock(&iot_mutex_lock);
+}
+
+/*****************************************************************************
+**
+** Function add_iot_device
+**
+** Description This function is used to add the device to the blacklist file
+** as well as queue.
+**
+** Returns true incase the device is blacklisted otherwise fasle.
+**
+*******************************************************************************/
+bool add_iot_device(const char *filename, char* header,
+ unsigned char* device_details, tBLACKLIST_METHOD method_type)
+{
+ char line_start[MAX_LINE];
+ FILE *iot_devlist_fp;
+ char *header_end = NULL;
+ int index = 0, i, len = 0;
+
+ if((header == NULL) || (device_details == NULL)) {
+ ALOGE("Error adding device to the list: Invalid input data");
+ return false;
+ }
+ if (is_device_present (header , device_details)) {
+ ALOGW("Device already present in the blacklist");
+ return true;
+ }
+
+ pthread_mutex_lock(&iot_mutex_lock);
+ iot_devlist_fp = fopen(filename, "a");
+
+ if (iot_devlist_fp == NULL) {
+ ALOGE(" File %s does not exist ", filename);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+ /* first copy the header */
+ len = strlcpy(&line_start[index], header, strlen(header)+ 1);
+ index += len;
+
+ line_start[index++] = '=';
+ /* then copy the device addr/device name */
+ if(method_type == METHOD_BD) {
+ /* for addr take first 3 bytes */
+ for(i = 0; i < 3; i++) {
+ if(i < 2) {
+ len = snprintf(&line_start[index], MAX_LINE - index, "%02X:",
+ *(device_details + i));
+ }
+ else {
+ len = snprintf(&line_start[index], MAX_LINE - index, "%02X",
+ *(device_details + i));
+ }
+ index += len;
+ }
+ }
+ else if(method_type == METHOD_NAME) {
+ len = strlcpy(&line_start[index], (const char*) device_details,
+ strlen((const char*)device_details) + 1);
+ index += len;
+ }
+ /* append the new line characer at the end */
+ line_start[index++] = '\n';
+ line_start[index++] = '\0';
+
+ header_end = strchr(line_start,'=');
+ if(header_end) {
+ populate_header(line_start, header_end);
+ }
+ if(fputs(line_start, iot_devlist_fp)) {
+ fclose(iot_devlist_fp);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return true;
+ }
+ else {
+ fclose(iot_devlist_fp);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+}
+
+/*****************************************************************************
+**
+** Function form_bd_addr
+**
+** Description Adds the colon after 2 bytes to form valid BD address to
+** compare the entry prsent in file.
+**
+** Returns void
+**
+*******************************************************************************/
+static void form_bd_addr(char *addr, char *new_addr, int max_len)
+{
+ int i = 0, index = 0, len =0;
+ /* for addr take first 3 bytes */
+ for(i = 0; i < 3; i++) {
+ if(i < 2) {
+ len = snprintf(&new_addr[index], max_len - index, "%02X:",
+ *(addr + i));
+ }
+ else {
+ len = snprintf(&new_addr[index], max_len - index, "%02X",
+ *(addr + i));
+ }
+ index += len;
+ }
+ new_addr[max_len - 1]= '\0';
+}
+
+/*****************************************************************************
+**
+** Function remove_iot_device_from_queue
+**
+** Description This function is used remove the entry from internal queue.
+**
+** Returns true if the entry removed from queue else false.
+**
+*******************************************************************************/
+bool remove_iot_device_from_queue(unsigned char* device_details, char* header,
+ tBLACKLIST_METHOD method_type)
+{
+ if(!iot_header_queue)
+ return false;
+ for (const list_node_t *header_node = list_begin(iot_header_queue);
+ header_node != list_end(iot_header_queue);
+ header_node = list_next(header_node)) {
+ iot_header_node_t *header_entry = list_node(header_node);
+
+ if(!header_entry->devlist)
+ continue;
+
+ if((!strcmp(header, header_entry->header_name)) &&
+ method_type == header_entry->method_type) {
+
+ for (const list_node_t *device_node = list_begin(header_entry->devlist);
+ device_node != list_end(header_entry->devlist);
+ device_node = list_next(device_node)) {
+ if(method_type == METHOD_BD) {
+ iot_devlist_bd_node_t *bd_addr_entry = list_node(device_node);
+ if(!memcmp(device_details, bd_addr_entry->dev_bd, 3)) {
+ list_remove(header_entry->devlist, bd_addr_entry);
+ return true;
+ }
+ }
+ else if(method_type == METHOD_NAME) {
+ iot_devlist_name_node_t *bd_name_entry = list_node(device_node);
+ if(!strcmp((char *)device_details, bd_name_entry->dev_name)) {
+ list_remove(header_entry->devlist, bd_name_entry);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/*****************************************************************************
+**
+** Function edit_line
+**
+** Description This function is used to remove the device entry from the
+** inputted line buffer if the entry present.
+**
+** Returns true if the entry removed from line else false.
+**
+*******************************************************************************/
+static void edit_line(char *line_start, char *dev_info, int line_len)
+{
+ char *dev_ptr = strstr(line_start, dev_info);
+ char *comma_ptr = NULL;
+ int len_to_copy = 0;
+ if(dev_ptr) {
+ comma_ptr = strchr(dev_ptr, ',');
+ if(comma_ptr) {
+ len_to_copy = line_len - (comma_ptr - line_start + 1);
+ }
+ else {
+ *(dev_ptr - 1) = '\n';
+ *(dev_ptr) = '\0';
+ }
+ }
+ if(len_to_copy) {
+ memmove(dev_ptr, comma_ptr + 1, len_to_copy);
+ }
+}
+
+/*****************************************************************************
+**
+** Function is_single_entry_line
+**
+** Description This function is used to check the line consists of single
+** input line if the entry present.
+**
+** Returns true if the single entry present else false.
+**
+*******************************************************************************/
+static bool is_single_entry_line(char *line_start)
+{
+ char *comma_ptr = strchr(line_start, ',');
+ // check the char next to ,
+ if( !comma_ptr || (*(comma_ptr + 1) == '\n')) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/*****************************************************************************
+**
+** Function get_header_from_line
+**
+** Description This function is used to get the header from line buffer.
+**
+** Returns true if the header found else false.
+**
+*******************************************************************************/
+bool get_header_from_line(char *line_start, char* header)
+{
+ int i = 0;
+ if(!line_start || !header || !strchr(line_start, '=')) {
+ return false;
+ }
+ while (line_start[i] != '=') {
+ header[i] = line_start[i];
+ i++;
+ }
+ header[i] = '\0';
+ return true;
+}
+
+/*****************************************************************************
+**
+** Function remove_iot_device
+**
+** Description This function is used to remove the device from internal
+** blacklisted queue as well as black list file.
+**
+** Returns true if the device is removed else false.
+**
+*******************************************************************************/
+bool remove_iot_device(const char *filename, char* header,
+ unsigned char* device_details, tBLACKLIST_METHOD method_type)
+{
+ char line_start[MAX_LINE];
+ FILE *iot_devlist_fp, *iot_devlist_new_fp;
+ char *header_end = NULL;
+ char bd_addr[MAX_ADDR_STR_LEN];
+ char header_name[MAX_NAME_LEN] = { 0 };
+ char *dev = NULL;
+ int index = 0, i, len = 0;
+
+ if((header == NULL) || (device_details == NULL)) {
+ ALOGE("Invalid input data to add the device");
+ return false;
+ }
+ if (!is_device_present (header , device_details)) {
+ ALOGW("Device doesn't exist in the list");
+ return false;
+ }
+ pthread_mutex_lock(&iot_mutex_lock);
+ iot_devlist_fp = fopen(filename, "rt");
+
+ if (iot_devlist_fp == NULL) {
+ ALOGE(" File %s does not exist ", filename);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+ iot_devlist_new_fp = fopen(IOT_DEV_CONF_BKP_FILE, "wt");
+
+ if (iot_devlist_new_fp == NULL) {
+ ALOGE(" Unable to create backup file %s", IOT_DEV_CONF_BKP_FILE);
+ fclose(iot_devlist_fp);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return false;
+ }
+
+ /* then copy the device addr/device name */
+ while (fgets(line_start, sizeof line_start, iot_devlist_fp)) {
+ len = strlen(line_start);
+
+ if (len) {
+ get_header_from_line(line_start, header_name);
+ if(method_type == METHOD_BD) {
+ form_bd_addr((char*)device_details, bd_addr, MAX_ADDR_STR_LEN);
+ dev = bd_addr;
+ }
+ else if(method_type == METHOD_NAME) {
+ dev = (char *) device_details;
+ }
+ // copy as it is if the line consists comments
+ if( (line_start[0] == '#') || (line_start[0] == '/') ||
+ (line_start[0] == ' ') || (line_start[0] == '\n')) {
+ fputs(line_start, iot_devlist_new_fp);
+ }
+ else if((!strcmp(header_name, header)) && (strstr(line_start, dev))) {
+ if(is_single_entry_line(line_start)) {
+ if(!remove_iot_device_from_queue(device_details, header, method_type)) {
+ // if unable to remove from queue put the same line as it is
+ fputs(line_start, iot_devlist_new_fp);
+ }
+ else
+ ALOGE(" Removed %s device from blacklist file %s", dev, IOT_DEV_CONF_FILE);
+ }
+ else {
+ // multi line entry
+ if(remove_iot_device_from_queue(device_details, header, method_type)) {
+ edit_line(line_start, dev, len + 1);
+ fputs(line_start, iot_devlist_new_fp);
+ ALOGE(" Removed %s device from blacklist file %s", dev, IOT_DEV_CONF_FILE);
+ }
+ else {
+ fputs(line_start, iot_devlist_new_fp);
+ }
+ }
+ }
+ else {
+ fputs(line_start, iot_devlist_new_fp);
+ }
+ }
+ }
+
+ fclose(iot_devlist_fp);
+ fclose(iot_devlist_new_fp);
+ remove(filename);
+ rename(IOT_DEV_CONF_BKP_FILE, filename);
+ pthread_mutex_unlock(&iot_mutex_lock);
+ return true;
+}