void btc_config_flush(void) { assert(config != NULL); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); config_save(config, CONFIG_FILE_PATH); osi_mutex_unlock(&lock); }
/* * Starts a oneshot timer with a timeout in seconds. */ void btu_start_timer_oneshot(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec) { osi_alarm_t *alarm = NULL; assert(p_tle != NULL); // Get the alarm for the timer list entry. osi_mutex_lock(&btu_oneshot_alarm_lock, OSI_MUTEX_MAX_TIMEOUT); if (!hash_map_has_key(btu_oneshot_alarm_hash_map, p_tle)) { alarm = osi_alarm_new("btu_oneshot", btu_oneshot_alarm_cb, (void *)p_tle, 0); hash_map_set(btu_oneshot_alarm_hash_map, p_tle, alarm); } osi_mutex_unlock(&btu_oneshot_alarm_lock); alarm = hash_map_get(btu_oneshot_alarm_hash_map, p_tle); if (alarm == NULL) { LOG_ERROR("%s Unable to create alarm", __func__); return; } osi_alarm_cancel(alarm); p_tle->event = type; p_tle->in_use = TRUE; // NOTE: This value is in seconds but stored in a ticks field. p_tle->ticks = timeout_sec; osi_alarm_set(alarm, (period_ms_t)(timeout_sec * 1000)); }
bool btc_config_set_bin(const char *section, const char *key, const uint8_t *value, size_t length) { const char *lookup = "0123456789abcdef"; assert(config != NULL); assert(section != NULL); assert(key != NULL); if (length > 0) { assert(value != NULL); } char *str = (char *)osi_calloc(length * 2 + 1); if (!str) { return false; } for (size_t i = 0; i < length; ++i) { str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F]; str[(i * 2) + 1] = lookup[value[i] & 0x0F]; } osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); config_set_string(config, section, key, str, false); osi_mutex_unlock(&lock); osi_free(str); return true; }
void btu_start_quick_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_ticks) { osi_alarm_t *alarm = NULL; assert(p_tle != NULL); // Get the alarm for the timer list entry. osi_mutex_lock(&btu_l2cap_alarm_lock, OSI_MUTEX_MAX_TIMEOUT); if (!hash_map_has_key(btu_l2cap_alarm_hash_map, p_tle)) { alarm = osi_alarm_new("btu_l2cap", btu_l2cap_alarm_cb, (void *)p_tle, 0); hash_map_set(btu_l2cap_alarm_hash_map, p_tle, (void *)alarm); } osi_mutex_unlock(&btu_l2cap_alarm_lock); alarm = hash_map_get(btu_l2cap_alarm_hash_map, p_tle); if (alarm == NULL) { LOG_ERROR("%s Unable to create alarm", __func__); return; } osi_alarm_cancel(alarm); p_tle->event = type; p_tle->ticks = timeout_ticks; p_tle->in_use = TRUE; // The quick timer ticks are 100ms long. osi_alarm_set(alarm, (period_ms_t)(timeout_ticks * 100)); }
bool btc_config_get_bin(const char *section, const char *key, uint8_t *value, size_t *length) { assert(config != NULL); assert(section != NULL); assert(key != NULL); assert(value != NULL); assert(length != NULL); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); const char *value_str = config_get_string(config, section, key, NULL); osi_mutex_unlock(&lock); if (!value_str) { return false; } size_t value_len = strlen(value_str); if ((value_len % 2) != 0 || *length < (value_len / 2)) { return false; } for (size_t i = 0; i < value_len; ++i) if (!isxdigit((unsigned char)value_str[i])) { return false; } for (*length = 0; *value_str; value_str += 2, *length += 1) { unsigned int val; sscanf(value_str, "%02x", &val); value[*length] = (uint8_t)(val); } return true; }
bool btc_config_remove_section(const char *section) { assert(config != NULL); assert(section != NULL); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); bool ret = config_remove_section(config, section); osi_mutex_unlock(&lock); return ret; }
bool btc_config_exist(const char *section, const char *key) { assert(config != NULL); assert(section != NULL); assert(key != NULL); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); bool ret = config_has_key(config, section, key); osi_mutex_unlock(&lock); return ret; }
bool btc_config_set_int(const char *section, const char *key, int value) { assert(config != NULL); assert(section != NULL); assert(key != NULL); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); config_set_int(config, section, key, value); osi_mutex_unlock(&lock); return true; }
static void restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q) { osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT); if (cmd_wait_q->timer_is_set) { osi_alarm_cancel(cmd_wait_q->command_response_timer); cmd_wait_q->timer_is_set = false; } if (!list_is_empty(cmd_wait_q->commands_pending_response)) { osi_alarm_set(cmd_wait_q->command_response_timer, COMMAND_PENDING_TIMEOUT); cmd_wait_q->timer_is_set = true; } osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); }
bool btc_compare_address_key_value(const char *section, char *key_type, void *key_value, int key_length) { assert(key_value != NULL); bool status = false; char value_str[100] = {0}; if(key_length > sizeof(value_str)/2) { return false; } btc_key_value_to_string((uint8_t *)key_value, value_str, key_length); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); if ((status = config_has_key_in_section(config, key_type, value_str)) == true) { config_remove_section(config, section); } osi_mutex_unlock(&lock); return status; }
bool btc_config_get_int(const char *section, const char *key, int *value) { assert(config != NULL); assert(section != NULL); assert(key != NULL); assert(value != NULL); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); bool ret = config_has_key(config, section, key); if (ret) { *value = config_get_int(config, section, key, *value); } osi_mutex_unlock(&lock); return ret; }
int btc_config_clear(void) { assert(config != NULL); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); config_free(config); config = config_new_empty(); if (config == NULL) { osi_mutex_unlock(&lock); return false; } int ret = config_save(config, CONFIG_FILE_PATH); osi_mutex_unlock(&lock); return ret; }
size_t btc_config_get_bin_length(const char *section, const char *key) { assert(config != NULL); assert(section != NULL); assert(key != NULL); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); const char *value_str = config_get_string(config, section, key, NULL); osi_mutex_unlock(&lock); if (!value_str) { return 0; } size_t value_len = strlen(value_str); return ((value_len % 2) != 0) ? 0 : (value_len / 2); }
void btc_config_save(void) { assert(config != NULL); // Garbage collection process: the config file accumulates // cached information about remote devices during regular // inquiry scans. We remove some of these junk entries // so the file doesn't grow indefinitely. We have to take care // to make sure we don't remove information about bonded // devices (hence the check for link keys). static const size_t CACHE_MAX = 256; const char *keys[CACHE_MAX]; size_t num_keys = 0; size_t total_candidates = 0; osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); for (const config_section_node_t *snode = config_section_begin(config); snode != config_section_end(config); snode = config_section_next(snode)) { const char *section = config_section_name(snode); if (!string_is_bdaddr(section)) { continue; } if (config_has_key(config, section, "LinkKey") || config_has_key(config, section, "LE_KEY_PENC") || config_has_key(config, section, "LE_KEY_PID") || config_has_key(config, section, "LE_KEY_PCSRK") || config_has_key(config, section, "LE_KEY_LENC") || config_has_key(config, section, "LE_KEY_LCSRK")) { continue; } if (num_keys < CACHE_MAX) { keys[num_keys++] = section; } ++total_candidates; } if (total_candidates > CACHE_MAX * 2) while (num_keys > 0) { config_remove_section(config, keys[--num_keys]); } config_save(config, CONFIG_FILE_PATH); osi_mutex_unlock(&lock); }
static void command_timed_out(void *context) { command_waiting_response_t *cmd_wait_q = (command_waiting_response_t *)context; waiting_command_t *wait_entry; osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT); wait_entry = (list_is_empty(cmd_wait_q->commands_pending_response) ? NULL : list_front(cmd_wait_q->commands_pending_response)); osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); if (wait_entry == NULL) { HCI_TRACE_ERROR("%s with no commands pending response", __func__); } else // We shouldn't try to recover the stack from this command timeout. // If it's caused by a software bug, fix it. If it's a hardware bug, fix it. { HCI_TRACE_ERROR("%s hci layer timeout waiting for response to a command. opcode: 0x%x", __func__, wait_entry->opcode); } }
bool btc_config_get_str(const char *section, const char *key, char *value, int *size_bytes) { assert(config != NULL); assert(section != NULL); assert(key != NULL); assert(value != NULL); assert(size_bytes != NULL); osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT); const char *stored_value = config_get_string(config, section, key, NULL); osi_mutex_unlock(&lock); if (!stored_value) { return false; } strlcpy(value, stored_value, *size_bytes); *size_bytes = strlen(value) + 1; return true; }
static waiting_command_t *get_waiting_command(command_opcode_t opcode) { command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT); for (const list_node_t *node = list_begin(cmd_wait_q->commands_pending_response); node != list_end(cmd_wait_q->commands_pending_response); node = list_next(node)) { waiting_command_t *wait_entry = list_node(node); if (!wait_entry || wait_entry->opcode != opcode) { continue; } list_remove(cmd_wait_q->commands_pending_response, wait_entry); osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); return wait_entry; } osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); return NULL; }
// Command/packet transmitting functions static void event_command_ready(fixed_queue_t *queue) { waiting_command_t *wait_entry = NULL; command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; wait_entry = fixed_queue_dequeue(queue); if(wait_entry->opcode == HCI_HOST_NUM_PACKETS_DONE){ packet_fragmenter->fragment_and_dispatch(wait_entry->command); osi_free(wait_entry->command); osi_free(wait_entry); return; } hci_host_env.command_credits--; // Move it to the list of commands awaiting response osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT); list_append(cmd_wait_q->commands_pending_response, wait_entry); osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); // Send it off packet_fragmenter->fragment_and_dispatch(wait_entry->command); restart_command_waiting_response_timer(cmd_wait_q); }