blob: 6f0f205d3850bc1becc0e500079d78fae1c95eca [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/************************************************************************************
*
* Filename: bt_utils.c
*
* Description: Miscellaneous helper functions
*
*
***********************************************************************************/
#define LOG_TAG "bt_utils"
#include "bt_utils.h"
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <unistd.h>
#include <utils/ThreadDefs.h>
#include <cutils/sched_policy.h>
#include "bt_types.h"
#include "btcore/include/module.h"
#include "osi/include/compat.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
#include "osi/include/properties.h"
#include "osi/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;
typedef struct {
bt_soc_type soc_type;
char* soc_name;
} soc_type_node;
static soc_type_node soc_type_entries[] = {
{ BT_SOC_SMD , "smd" },
{ BT_SOC_AR3K , "ath3k" },
{ BT_SOC_ROME , "rome" },
{ BT_SOC_CHEROKEE , "cherokee" },
{ BT_SOC_RESERVED , "" }
};
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];
static BOOLEAN g_DoSchedulingGroup[TASK_HIGH_MAX];
static pthread_mutex_t gIdxLock;
static int g_TaskIdx;
static int g_TaskIDs[TASK_HIGH_MAX];
static bt_soc_type soc_type;
#define INVALID_TASK_ID (-1)
static void init_soc_type();
static future_t *init(void) {
int i;
pthread_mutexattr_t lock_attr;
for(i = 0; i < TASK_HIGH_MAX; i++) {
g_DoSchedulingGroupOnce[i] = PTHREAD_ONCE_INIT;
g_DoSchedulingGroup[i] = TRUE;
g_TaskIDs[i] = INVALID_TASK_ID;
}
pthread_mutexattr_init(&lock_attr);
pthread_mutex_init(&gIdxLock, &lock_attr);
pthread_mutex_init(&iot_mutex_lock, NULL);
init_soc_type();
return NULL;
}
static future_t *clean_up(void) {
pthread_mutex_destroy(&gIdxLock);
pthread_mutex_destroy(&iot_mutex_lock);
return NULL;
}
EXPORT_SYMBOL const module_t bt_utils_module = {
.name = BT_UTILS_MODULE,
.init = init,
.start_up = NULL,
.shut_down = NULL,
.clean_up = clean_up,
.dependencies = {
NULL
}
};
/*****************************************************************************
**
** Function check_do_scheduling_group
**
** Description check if it is ok to change schedule group
**
** Returns void
**
*******************************************************************************/
static void check_do_scheduling_group(void) {
char buf[PROPERTY_VALUE_MAX];
int len = osi_property_get("debug.sys.noschedgroups", buf, "");
if (len > 0) {
int temp;
if (sscanf(buf, "%d", &temp) == 1) {
g_DoSchedulingGroup[g_TaskIdx] = temp == 0;
}
}
}
/*****************************************************************************
**
** Function raise_priority_a2dp
**
** Description Raise task priority for A2DP streaming
**
** Returns void
**
*******************************************************************************/
void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) {
int rc = 0;
int tid = gettid();
int priority = ANDROID_PRIORITY_AUDIO;
pthread_mutex_lock(&gIdxLock);
g_TaskIdx = high_task;
// TODO(armansito): Remove this conditional check once we find a solution
// for system/core on non-Android platforms.
#if defined(OS_GENERIC)
rc = -1;
#else // !defined(OS_GENERIC)
pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx], check_do_scheduling_group);
if (g_TaskIdx < TASK_HIGH_MAX && g_DoSchedulingGroup[g_TaskIdx]) {
// set_sched_policy does not support tid == 0
rc = set_sched_policy(tid, SP_AUDIO_SYS);
}
#endif // defined(OS_GENERIC)
g_TaskIDs[high_task] = tid;
pthread_mutex_unlock(&gIdxLock);
if (rc) {
LOG_WARN(LOG_TAG, "failed to change sched policy, tid %d, err: %d", tid, errno);
}
// always use urgent priority for HCI worker thread until we can adjust
// its prio individually. All other threads can be dynamically adjusted voa
// adjust_priority_a2dp()
priority = ANDROID_PRIORITY_URGENT_AUDIO;
if (setpriority(PRIO_PROCESS, tid, priority) < 0) {
LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
}
}
/*****************************************************************************
**
** Function adjust_priority_a2dp
**
** Description increase the a2dp consumer task priority temporarily when start
** audio playing, to avoid overflow the audio packet queue, restore
** the a2dp consumer task priority when stop audio playing.
**
** Returns void
**
*******************************************************************************/
void adjust_priority_a2dp(int start) {
int priority = start ? ANDROID_PRIORITY_URGENT_AUDIO : ANDROID_PRIORITY_AUDIO;
int tid;
int i;
for (i = 0; i < TASK_HIGH_MAX; i++)
{
tid = g_TaskIDs[i];
if (tid != INVALID_TASK_ID)
{
if (setpriority(PRIO_PROCESS, tid, priority) < 0)
{
LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", tid, priority);
}
}
}
}
/*****************************************************************************
**
** 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)
{
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(osi_free);
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 = (iot_devlist_bd_node_t *)osi_malloc(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)) {
osi_free(bd);
}
else {
list_append(node->devlist, bd);
}
}
else if (node->method_type == METHOD_NAME) {
iot_devlist_name_node_t *name = (iot_devlist_name_node_t *)osi_malloc(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)) {
osi_free(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 =(iot_header_node_t *) osi_malloc(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(osi_free);
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, void *context)
{
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, NULL);
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 bd_addr[MAX_ADDR_STR_LEN];
char header_name[MAX_NAME_LEN] = { 0 };
char *dev = NULL;
int 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;
}
/*****************************************************************************
**
** Function init_soc_type
**
** Description Get Bluetooth SoC type from system setting and stores it
** in soc_type.
**
** Returns void.
**
*******************************************************************************/
static void init_soc_type()
{
int ret = 0;
char bt_soc_type[PROPERTY_VALUE_MAX];
ALOGI("init_soc_type");
soc_type = BT_SOC_DEFAULT;
ret = property_get("qcom.bluetooth.soc", bt_soc_type, NULL);
if (ret != 0) {
int i;
ALOGI("qcom.bluetooth.soc set to %s\n", bt_soc_type);
for ( i = BT_SOC_AR3K ; i < BT_SOC_RESERVED ; i++ )
{
char* soc_name = soc_type_entries[i].soc_name;
if (!strcmp(bt_soc_type, soc_name)) {
soc_type = soc_type_entries[i].soc_type;
break;
}
}
}
}
/*****************************************************************************
**
** Function get_soc_type
**
** Description This function is used to get the Bluetooth SoC type.
**
** Returns bt_soc_type.
**
*******************************************************************************/
bt_soc_type get_soc_type()
{
return soc_type;
}