component/bt: use fixed_pkt_queue instead of fixed_queue for hci commands

some fixes after modifications:
  1. removed the use of waiting_command_t
  2. fix assert for HCI write_eir command
  3. fixed the crash upon handling command status event when trying to free to the HCI command buffer
  4. fixed the issue in transmitting HCI vendor specific commands
  5. fixed the lost command complete callbacks for HCI commands LE_RAND and LE_ENCRYPT
This commit is contained in:
wangmengyang 2022-07-19 22:16:12 +08:00
parent c3f5b85032
commit aaf1d3909d
9 changed files with 187 additions and 132 deletions

View File

@ -35,6 +35,7 @@
#include "osi/thread.h" #include "osi/thread.h"
#include "osi/mutex.h" #include "osi/mutex.h"
#include "osi/fixed_queue.h" #include "osi/fixed_queue.h"
#include "osi/fixed_pkt_queue.h"
#define HCI_HOST_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) #define HCI_HOST_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE)
#define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) #define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE)
@ -44,15 +45,6 @@
#define HCI_HOST_TASK_WORKQUEUE0_LEN (0) #define HCI_HOST_TASK_WORKQUEUE0_LEN (0)
#define HCI_HOST_TASK_WORKQUEUE1_LEN (5) #define HCI_HOST_TASK_WORKQUEUE1_LEN (5)
typedef struct {
uint16_t opcode;
future_t *complete_future;
command_complete_cb complete_callback;
command_status_cb status_callback;
void *context;
BT_HDR *command;
} waiting_command_t;
typedef struct { typedef struct {
bool timer_is_set; bool timer_is_set;
osi_alarm_t *command_response_timer; osi_alarm_t *command_response_timer;
@ -62,7 +54,7 @@ typedef struct {
typedef struct { typedef struct {
int command_credits; int command_credits;
fixed_queue_t *command_queue; fixed_pkt_queue_t *command_queue;
fixed_queue_t *packet_queue; fixed_queue_t *packet_queue;
command_waiting_response_t cmd_waiting_q; command_waiting_response_t cmd_waiting_q;
@ -93,14 +85,14 @@ static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks;
static int hci_layer_init_env(void); static int hci_layer_init_env(void);
static void hci_layer_deinit_env(void); static void hci_layer_deinit_env(void);
static void hci_host_thread_handler(void *arg); static void hci_host_thread_handler(void *arg);
static void event_command_ready(fixed_queue_t *queue); static void event_command_ready(fixed_pkt_queue_t *queue);
static void event_packet_ready(fixed_queue_t *queue); static void event_packet_ready(fixed_queue_t *queue);
static void restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q); static void restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q);
static void command_timed_out(void *context); static void command_timed_out(void *context);
static void hal_says_packet_ready(BT_HDR *packet); static void hal_says_packet_ready(BT_HDR *packet);
static bool filter_incoming_event(BT_HDR *packet); static bool filter_incoming_event(BT_HDR *packet);
static serial_data_type_t event_to_data_type(uint16_t event); static serial_data_type_t event_to_data_type(uint16_t event);
static waiting_command_t *get_waiting_command(command_opcode_t opcode); static pkt_linked_item_t *get_waiting_command(command_opcode_t opcode);
static void dispatch_reassembled(BT_HDR *packet); static void dispatch_reassembled(BT_HDR *packet);
static void dispatch_adv_report(pkt_linked_item_t *linked_pkt); static void dispatch_adv_report(pkt_linked_item_t *linked_pkt);
@ -156,9 +148,9 @@ static int hci_layer_init_env(void)
// as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control) // as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control)
// This value can change when you get a command complete or command status event. // This value can change when you get a command complete or command status event.
hci_host_env.command_credits = 1; hci_host_env.command_credits = 1;
hci_host_env.command_queue = fixed_queue_new(QUEUE_SIZE_MAX); hci_host_env.command_queue = fixed_pkt_queue_new(QUEUE_SIZE_MAX);
if (hci_host_env.command_queue) { if (hci_host_env.command_queue) {
fixed_queue_register_dequeue(hci_host_env.command_queue, event_command_ready); fixed_pkt_queue_register_dequeue(hci_host_env.command_queue, event_command_ready);
} else { } else {
HCI_TRACE_ERROR("%s unable to create pending command queue.", __func__); HCI_TRACE_ERROR("%s unable to create pending command queue.", __func__);
return -1; return -1;
@ -198,7 +190,7 @@ static void hci_layer_deinit_env(void)
command_waiting_response_t *cmd_wait_q; command_waiting_response_t *cmd_wait_q;
if (hci_host_env.command_queue) { if (hci_host_env.command_queue) {
fixed_queue_free(hci_host_env.command_queue, osi_free_func); fixed_pkt_queue_free(hci_host_env.command_queue, (fixed_pkt_queue_free_cb)osi_free_func);
} }
if (hci_host_env.packet_queue) { if (hci_host_env.packet_queue) {
fixed_queue_free(hci_host_env.packet_queue, osi_free_func); fixed_queue_free(hci_host_env.packet_queue, osi_free_func);
@ -230,9 +222,9 @@ static void hci_host_thread_handler(void *arg)
if (pkt != NULL) { if (pkt != NULL) {
packet_fragmenter->fragment_and_dispatch(pkt); packet_fragmenter->fragment_and_dispatch(pkt);
} else { } else {
if (!fixed_queue_is_empty(hci_host_env.command_queue) && if (!fixed_pkt_queue_is_empty(hci_host_env.command_queue) &&
hci_host_env.command_credits > 0) { hci_host_env.command_credits > 0) {
fixed_queue_process(hci_host_env.command_queue); fixed_pkt_queue_process(hci_host_env.command_queue);
} else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) { } else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) {
fixed_queue_process(hci_host_env.packet_queue); fixed_queue_process(hci_host_env.packet_queue);
} }
@ -246,48 +238,38 @@ static void transmit_command(
command_status_cb status_callback, command_status_cb status_callback,
void *context) void *context)
{ {
uint8_t *stream; hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(command);
waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata);
if (!wait_entry) {
HCI_TRACE_ERROR("%s couldn't allocate space for wait entry.", __func__);
return;
}
stream = command->data + command->offset;
STREAM_TO_UINT16(wait_entry->opcode, stream);
wait_entry->complete_callback = complete_callback;
wait_entry->status_callback = status_callback;
wait_entry->command = command;
wait_entry->context = context;
assert(command->layer_specific == HCI_CMD_BUF_TYPE_METADATA);
// Store the command message type in the event field // Store the command message type in the event field
// in case the upper layer didn't already // in case the upper layer didn't already
command->event = MSG_STACK_TO_HC_HCI_CMD; command->event = MSG_STACK_TO_HC_HCI_CMD;
HCI_TRACE_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", wait_entry->opcode); HCI_TRACE_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", metadata->opcode);
BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len);
fixed_queue_enqueue(hci_host_env.command_queue, wait_entry, FIXED_QUEUE_MAX_TIMEOUT); fixed_pkt_queue_enqueue(hci_host_env.command_queue, linked_pkt, FIXED_PKT_QUEUE_MAX_TIMEOUT);
hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); hci_host_task_post(OSI_THREAD_MAX_TIMEOUT);
} }
static future_t *transmit_command_futured(BT_HDR *command) static future_t *transmit_command_futured(BT_HDR *command)
{ {
waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(command);
assert(wait_entry != NULL); pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata);
assert(command->layer_specific == HCI_CMD_BUF_TYPE_METADATA);
metadata->flags_vnd |= HCI_CMD_MSG_F_VND_FUTURE;
future_t *future = future_new(); future_t *future = future_new();
uint8_t *stream = command->data + command->offset; metadata->complete_future = future;
STREAM_TO_UINT16(wait_entry->opcode, stream);
wait_entry->complete_future = future;
wait_entry->command = command;
// Store the command message type in the event field // Store the command message type in the event field
// in case the upper layer didn't already // in case the upper layer didn't already
command->event = MSG_STACK_TO_HC_HCI_CMD; command->event = MSG_STACK_TO_HC_HCI_CMD;
fixed_queue_enqueue(hci_host_env.command_queue, wait_entry, FIXED_QUEUE_MAX_TIMEOUT); fixed_pkt_queue_enqueue(hci_host_env.command_queue, linked_pkt, FIXED_PKT_QUEUE_MAX_TIMEOUT);
hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); hci_host_task_post(OSI_THREAD_MAX_TIMEOUT);
return future; return future;
} }
@ -295,8 +277,8 @@ static future_t *transmit_command_futured(BT_HDR *command)
static void transmit_downward(uint16_t type, void *data) static void transmit_downward(uint16_t type, void *data)
{ {
if (type == MSG_STACK_TO_HC_HCI_CMD) { if (type == MSG_STACK_TO_HC_HCI_CMD) {
transmit_command((BT_HDR *)data, NULL, NULL, NULL); HCI_TRACE_ERROR("%s legacy transmit of command. Use transmit_command instead.\n", __func__);
HCI_TRACE_WARNING("%s legacy transmit of command. Use transmit_command instead.\n", __func__); assert(0);
} else { } else {
fixed_queue_enqueue(hci_host_env.packet_queue, data, FIXED_QUEUE_MAX_TIMEOUT); fixed_queue_enqueue(hci_host_env.packet_queue, data, FIXED_QUEUE_MAX_TIMEOUT);
} }
@ -306,21 +288,18 @@ static void transmit_downward(uint16_t type, void *data)
// Command/packet transmitting functions // Command/packet transmitting functions
static void event_command_ready(fixed_queue_t *queue) static void event_command_ready(fixed_pkt_queue_t *queue)
{ {
waiting_command_t *wait_entry = NULL; pkt_linked_item_t *wait_entry = NULL;
command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q;
wait_entry = fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); wait_entry = fixed_pkt_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT);
if(wait_entry->opcode == HCI_HOST_NUM_PACKETS_DONE hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(wait_entry->data);
#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) if (metadata->flags_src & HCI_CMD_MSG_F_SRC_NOACK) {
|| wait_entry->opcode == HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL packet_fragmenter->fragment_and_dispatch(&metadata->command);
#endif hci_cmd_free_cb free_func = metadata->command_free_cb ? metadata->command_free_cb : (hci_cmd_free_cb) osi_free_func;
){ free_func(wait_entry);
packet_fragmenter->fragment_and_dispatch(wait_entry->command);
osi_free(wait_entry->command);
osi_free(wait_entry);
return; return;
} }
hci_host_env.command_credits--; hci_host_env.command_credits--;
@ -330,7 +309,7 @@ static void event_command_ready(fixed_queue_t *queue)
osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);
// Send it off // Send it off
packet_fragmenter->fragment_and_dispatch(wait_entry->command); packet_fragmenter->fragment_and_dispatch(&metadata->command);
restart_command_waiting_response_timer(cmd_wait_q); restart_command_waiting_response_timer(cmd_wait_q);
} }
@ -395,7 +374,7 @@ static void restart_command_waiting_response_timer(command_waiting_response_t *c
static void command_timed_out(void *context) static void command_timed_out(void *context)
{ {
command_waiting_response_t *cmd_wait_q = (command_waiting_response_t *)context; command_waiting_response_t *cmd_wait_q = (command_waiting_response_t *)context;
waiting_command_t *wait_entry; pkt_linked_item_t *wait_entry;
osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT); 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) ? wait_entry = (list_is_empty(cmd_wait_q->commands_pending_response) ?
@ -408,7 +387,8 @@ static void command_timed_out(void *context)
// We shouldn't try to recover the stack from this command timeout. // 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. // 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); hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(wait_entry->data);
HCI_TRACE_ERROR("%s hci layer timeout waiting for response to a command. opcode: 0x%x", __func__, metadata->opcode);
} }
} }
@ -432,7 +412,8 @@ static void hal_says_adv_rpt_ready(pkt_linked_item_t *linked_pkt)
// information, like how many commands are now able to be sent. // information, like how many commands are now able to be sent.
static bool filter_incoming_event(BT_HDR *packet) static bool filter_incoming_event(BT_HDR *packet)
{ {
waiting_command_t *wait_entry = NULL; pkt_linked_item_t *wait_entry = NULL;
hci_cmd_metadata_t *metadata = NULL;
uint8_t *stream = packet->data + packet->offset; uint8_t *stream = packet->data + packet->offset;
uint8_t event_code; uint8_t event_code;
command_opcode_t opcode; command_opcode_t opcode;
@ -446,10 +427,11 @@ static bool filter_incoming_event(BT_HDR *packet)
STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT8(hci_host_env.command_credits, stream);
STREAM_TO_UINT16(opcode, stream); STREAM_TO_UINT16(opcode, stream);
wait_entry = get_waiting_command(opcode); wait_entry = get_waiting_command(opcode);
metadata = (hci_cmd_metadata_t *)(wait_entry->data);
if (!wait_entry) { if (!wait_entry) {
HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode); HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode);
} else if (wait_entry->complete_callback) { } else if (metadata->command_complete_cb) {
wait_entry->complete_callback(packet, wait_entry->context); metadata->command_complete_cb(packet, metadata->context);
#if (BLE_50_FEATURE_SUPPORT == TRUE) #if (BLE_50_FEATURE_SUPPORT == TRUE)
BlE_SYNC *sync_info = btsnd_hcic_ble_get_sync_info(); BlE_SYNC *sync_info = btsnd_hcic_ble_get_sync_info();
if(!sync_info) { if(!sync_info) {
@ -461,8 +443,8 @@ static bool filter_incoming_event(BT_HDR *packet)
} }
} }
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
} else if (wait_entry->complete_future) { } else if (metadata->flags_vnd & HCI_CMD_MSG_F_VND_FUTURE) {
future_ready(wait_entry->complete_future, packet); future_ready((future_t *)(metadata->complete_future), packet);
} }
goto intercepted; goto intercepted;
@ -475,10 +457,11 @@ static bool filter_incoming_event(BT_HDR *packet)
// If a command generates a command status event, it won't be getting a command complete event // If a command generates a command status event, it won't be getting a command complete event
wait_entry = get_waiting_command(opcode); wait_entry = get_waiting_command(opcode);
metadata = (hci_cmd_metadata_t *)(wait_entry->data);
if (!wait_entry) { if (!wait_entry) {
HCI_TRACE_WARNING("%s command status event with no matching command. opcode: 0x%x", __func__, opcode); HCI_TRACE_WARNING("%s command status event with no matching command. opcode: 0x%x", __func__, opcode);
} else if (wait_entry->status_callback) { } else if (metadata->command_status_cb) {
wait_entry->status_callback(status, wait_entry->command, wait_entry->context); metadata->command_status_cb(status, &metadata->command, metadata->context);
} }
goto intercepted; goto intercepted;
@ -490,23 +473,22 @@ intercepted:
/*Tell HCI Host Task to continue TX Pending commands*/ /*Tell HCI Host Task to continue TX Pending commands*/
if (hci_host_env.command_credits && if (hci_host_env.command_credits &&
!fixed_queue_is_empty(hci_host_env.command_queue)) { !fixed_pkt_queue_is_empty(hci_host_env.command_queue)) {
hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); hci_host_task_post(OSI_THREAD_MAX_TIMEOUT);
} }
if (wait_entry) { if (wait_entry) {
// If it has a callback, it's responsible for freeing the packet // If it has a callback, it's responsible for freeing the packet
if (event_code == HCI_COMMAND_STATUS_EVT || if (event_code == HCI_COMMAND_STATUS_EVT ||
(!wait_entry->complete_callback && !wait_entry->complete_future)) { (!metadata->command_complete_cb && !metadata->complete_future)) {
osi_free(packet); osi_free(packet);
} }
// If it has a callback, it's responsible for freeing the command // If it has a callback, it's responsible for freeing the command
if (event_code == HCI_COMMAND_COMPLETE_EVT || !wait_entry->status_callback) { if (event_code == HCI_COMMAND_COMPLETE_EVT || !metadata->command_status_cb) {
osi_free(wait_entry->command); hci_cmd_free_cb free_func = metadata->command_free_cb ? metadata->command_free_cb : (hci_cmd_free_cb) osi_free_func;
free_func(wait_entry);
} }
osi_free(wait_entry);
} else { } else {
osi_free(packet); osi_free(packet);
} }
@ -553,7 +535,7 @@ static serial_data_type_t event_to_data_type(uint16_t event)
return 0; return 0;
} }
static waiting_command_t *get_waiting_command(command_opcode_t opcode) static pkt_linked_item_t *get_waiting_command(command_opcode_t opcode)
{ {
command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; 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); osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
@ -561,15 +543,15 @@ static waiting_command_t *get_waiting_command(command_opcode_t opcode)
for (const list_node_t *node = list_begin(cmd_wait_q->commands_pending_response); 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_end(cmd_wait_q->commands_pending_response);
node = list_next(node)) { node = list_next(node)) {
waiting_command_t *wait_entry = list_node(node); pkt_linked_item_t *wait_entry = list_node(node);
if (!wait_entry || wait_entry->opcode != opcode) { if (wait_entry) {
continue; hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(wait_entry->data);
if (metadata->opcode == opcode) {
list_remove(cmd_wait_q->commands_pending_response, wait_entry);
osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);
return wait_entry;
}
} }
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); osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);

View File

@ -27,7 +27,6 @@
#include "hci/hci_packet_factory.h" #include "hci/hci_packet_factory.h"
static BT_HDR *make_packet(size_t data_size);
static BT_HDR *make_command_no_params(uint16_t opcode); static BT_HDR *make_command_no_params(uint16_t opcode);
static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **stream_out); static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **stream_out);
@ -234,7 +233,9 @@ static BT_HDR *make_command_no_params(uint16_t opcode)
static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **stream_out) static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **stream_out)
{ {
BT_HDR *packet = make_packet(HCI_COMMAND_PREAMBLE_SIZE + parameter_size); BT_HDR *packet = HCI_GET_CMD_BUF(parameter_size);
hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(packet);
metadata->opcode = opcode;
uint8_t *stream = packet->data; uint8_t *stream = packet->data;
UINT16_TO_STREAM(stream, opcode); UINT16_TO_STREAM(stream, opcode);
@ -247,17 +248,6 @@ static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **st
return packet; return packet;
} }
static BT_HDR *make_packet(size_t data_size)
{
BT_HDR *ret = (BT_HDR *)osi_calloc(sizeof(BT_HDR) + data_size);
assert(ret);
ret->event = 0;
ret->offset = 0;
ret->layer_specific = 0;
ret->len = data_size;
return ret;
}
static const hci_packet_factory_t interface = { static const hci_packet_factory_t interface = {
make_reset, make_reset,
make_read_buffer_size, make_read_buffer_size,

View File

@ -25,6 +25,7 @@
#include "osi/osi.h" #include "osi/osi.h"
#include "osi/future.h" #include "osi/future.h"
#include "osi/thread.h" #include "osi/thread.h"
#include "osi/pkt_queue.h"
///// LEGACY DEFINITIONS ///// ///// LEGACY DEFINITIONS /////
@ -47,6 +48,7 @@
/* Local Bluetooth Controller ID for BR/EDR */ /* Local Bluetooth Controller ID for BR/EDR */
#define LOCAL_BR_EDR_CONTROLLER_ID 0 #define LOCAL_BR_EDR_CONTROLLER_ID 0
#define HCI_CMD_MSG_F_VND_FUTURE (0x01)
///// END LEGACY DEFINITIONS ///// ///// END LEGACY DEFINITIONS /////
typedef struct hci_hal_t hci_hal_t; typedef struct hci_hal_t hci_hal_t;

View File

@ -662,14 +662,13 @@ tBTM_DEV_STATUS_CB *BTM_RegisterForDeviceStatusNotif (tBTM_DEV_STATUS_CB *p_cb)
tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 param_len, tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 param_len,
UINT8 *p_param_buf, tBTM_VSC_CMPL_CB *p_cb) UINT8 *p_param_buf, tBTM_VSC_CMPL_CB *p_cb)
{ {
void *p_buf; BT_HDR *p_buf;
BTM_TRACE_EVENT ("BTM: BTM_VendorSpecificCommand: Opcode: 0x%04X, ParamLen: %i.", BTM_TRACE_EVENT ("BTM: BTM_VendorSpecificCommand: Opcode: 0x%04X, ParamLen: %i.",
opcode, param_len); opcode, param_len);
/* Allocate a buffer to hold HCI command plus the callback function */ /* Allocate a buffer to hold HCI command plus the callback function */
if ((p_buf = osi_malloc((UINT16)(sizeof(BT_HDR) + sizeof (tBTM_CMPL_CB *) + if ((p_buf = HCI_GET_CMD_BUF(param_len)) != NULL) {
param_len + HCIC_PREAMBLE_SIZE))) != NULL) {
/* Send the HCI command (opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC) */ /* Send the HCI command (opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC) */
btsnd_hcic_vendor_spec_cmd (p_buf, opcode, param_len, p_param_buf, (void *)p_cb); btsnd_hcic_vendor_spec_cmd (p_buf, opcode, param_len, p_param_buf, (void *)p_cb);

View File

@ -2395,6 +2395,7 @@ tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff, BOOLEAN fec_required)
if (controller_get_interface()->supports_extended_inquiry_response()) { if (controller_get_interface()->supports_extended_inquiry_response()) {
BTM_TRACE_API("Write Extended Inquiry Response to controller\n"); BTM_TRACE_API("Write Extended Inquiry Response to controller\n");
btsnd_hcic_write_ext_inquiry_response (p_buff, fec_required); btsnd_hcic_write_ext_inquiry_response (p_buff, fec_required);
osi_free(p_buff);
return BTM_SUCCESS; return BTM_SUCCESS;
} else { } else {
osi_free(p_buff); osi_free(p_buff);

View File

@ -43,6 +43,7 @@
#include "common/bt_trace.h" #include "common/bt_trace.h"
#include "osi/thread.h" #include "osi/thread.h"
#include "osi/pkt_queue.h"
//#include "osi/mutex.h" //#include "osi/mutex.h"
// TODO(zachoverflow): remove this horrible hack // TODO(zachoverflow): remove this horrible hack
#include "stack/btu.h" #include "stack/btu.h"
@ -451,15 +452,21 @@ void btu_hcif_send_cmd (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_buf)
STREAM_TO_UINT16(opcode, stream); STREAM_TO_UINT16(opcode, stream);
// Eww...horrible hackery here assert (p_buf->layer_specific == HCI_CMD_BUF_TYPE_METADATA);
/* If command was a VSC, then extract command_complete callback */ hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p_buf);
if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC metadata->command_complete_cb = btu_hcif_command_complete_evt;
metadata->command_status_cb = btu_hcif_command_status_evt;
metadata->opcode = opcode;
vsc_callback = metadata->context;
/* If command is not a VSC, then the context field should be empty */
if ((opcode & HCI_GRP_VENDOR_SPECIFIC) != HCI_GRP_VENDOR_SPECIFIC
#if BLE_INCLUDED == TRUE #if BLE_INCLUDED == TRUE
|| (opcode == HCI_BLE_RAND) && (opcode != HCI_BLE_RAND)
|| (opcode == HCI_BLE_ENCRYPT) && (opcode != HCI_BLE_ENCRYPT)
#endif #endif
) { ) {
vsc_callback = *((void **)(p_buf + 1)); assert (vsc_callback == NULL);
} }
hci_layer_get_interface()->transmit_command( hci_layer_get_interface()->transmit_command(
@ -472,6 +479,7 @@ void btu_hcif_send_cmd (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_buf)
btu_check_bt_sleep (); btu_check_bt_sleep ();
#endif #endif
} }
#if (BLE_50_FEATURE_SUPPORT == TRUE) #if (BLE_50_FEATURE_SUPPORT == TRUE)
UINT8 btu_hcif_send_cmd_sync (UINT8 controller_id, BT_HDR *p_buf) UINT8 btu_hcif_send_cmd_sync (UINT8 controller_id, BT_HDR *p_buf)
{ {
@ -492,15 +500,22 @@ UINT8 btu_hcif_send_cmd_sync (UINT8 controller_id, BT_HDR *p_buf)
sync_info->opcode = opcode; sync_info->opcode = opcode;
// Eww...horrible hackery here assert (p_buf->layer_specific == HCI_CMD_BUF_TYPE_METADATA);
/* If command was a VSC, then extract command_complete callback */ hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p_buf);
if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC metadata->command_complete_cb = btu_hcif_command_complete_evt;
metadata->command_status_cb = btu_hcif_command_status_evt;
metadata->command_free_cb = NULL;
metadata->opcode = opcode;
vsc_callback = metadata->context;
/* If command is not a VSC, then the context field should be empty */
if ((opcode & HCI_GRP_VENDOR_SPECIFIC) != HCI_GRP_VENDOR_SPECIFIC
#if BLE_INCLUDED == TRUE #if BLE_INCLUDED == TRUE
|| (opcode == HCI_BLE_RAND) && (opcode != HCI_BLE_RAND)
|| (opcode == HCI_BLE_ENCRYPT) && (opcode != HCI_BLE_ENCRYPT)
#endif #endif
) { ) {
vsc_callback = *((void **)(p_buf + 1)); assert (vsc_callback == NULL);
} }
hci_layer_get_interface()->transmit_command( hci_layer_get_interface()->transmit_command(
@ -1434,7 +1449,11 @@ static void btu_hcif_command_status_evt_on_task(BT_HDR *event)
stream, stream,
hack->context); hack->context);
osi_free(hack->command); // check the HCI command integrity: opcode
hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(hack->command);
assert(metadata->opcode == opcode);
HCI_FREE_CMD_BUF(hack->command);
osi_free(event); osi_free(event);
} }

View File

@ -33,7 +33,6 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#define HCI_GET_CMD_BUF(paramlen) ((BT_HDR *)osi_malloc(HCIC_PREAMBLE_SIZE + sizeof(BT_HDR) + paramlen))
#if (BLE_50_FEATURE_SUPPORT == TRUE) #if (BLE_50_FEATURE_SUPPORT == TRUE)
static BlE_SYNC ble_sync_info; static BlE_SYNC ble_sync_info;
@ -557,19 +556,17 @@ BOOLEAN btsnd_hcic_ble_encrypt (UINT8 *key, UINT8 key_len,
BT_HDR *p; BT_HDR *p;
UINT8 *pp; UINT8 *pp;
if ((p = HCI_GET_CMD_BUF(sizeof (void *) + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_ENCRYPT)) == NULL) {
HCIC_PARAM_SIZE_BLE_ENCRYPT)) == NULL) {
return (FALSE); return (FALSE);
} }
pp = (UINT8 *)(p + 1); pp = (UINT8 *)(p + 1);
p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ENCRYPT; p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ENCRYPT;
p->offset = sizeof(void *); p->offset = 0;
*((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */
pp += sizeof(void *); /* Skip over callback pointer */
hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p);
metadata->context = p_cmd_cplt_cback;
UINT16_TO_STREAM (pp, HCI_BLE_ENCRYPT); UINT16_TO_STREAM (pp, HCI_BLE_ENCRYPT);
UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_ENCRYPT); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_ENCRYPT);
@ -596,18 +593,17 @@ BOOLEAN btsnd_hcic_ble_rand (void *p_cmd_cplt_cback)
BT_HDR *p; BT_HDR *p;
UINT8 *pp; UINT8 *pp;
if ((p = HCI_GET_CMD_BUF(sizeof (void *) + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_RAND)) == NULL) {
HCIC_PARAM_SIZE_BLE_RAND)) == NULL) {
return (FALSE); return (FALSE);
} }
pp = (UINT8 *)(p + 1); pp = (UINT8 *)(p + 1);
p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RAND; p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RAND;
p->offset = sizeof(void *); p->offset = 0;
*((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */ hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p);
pp += sizeof(void *); /* Skip over callback pointer */ metadata->context = p_cmd_cplt_cback;
UINT16_TO_STREAM (pp, HCI_BLE_RAND); UINT16_TO_STREAM (pp, HCI_BLE_RAND);
UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_RAND); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_RAND);
@ -1046,6 +1042,9 @@ BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num)
p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL; p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL;
p->offset = 0; p->offset = 0;
hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p);
metadata->flags_src |= HCI_CMD_MSG_F_SRC_NOACK;
UINT16_TO_STREAM (pp, HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL); UINT16_TO_STREAM (pp, HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL);
UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL);
UINT16_TO_STREAM (pp, num); UINT16_TO_STREAM (pp, num);

View File

@ -35,8 +35,6 @@
#include "btm_int.h" /* Included for UIPC_* macro definitions */ #include "btm_int.h" /* Included for UIPC_* macro definitions */
#define HCI_GET_CMD_BUF(paramlen) ((BT_HDR *)osi_malloc(HCIC_PREAMBLE_SIZE + sizeof(BT_HDR) + paramlen))
BOOLEAN btsnd_hcic_inquiry(const LAP inq_lap, UINT8 duration, UINT8 response_cnt) BOOLEAN btsnd_hcic_inquiry(const LAP inq_lap, UINT8 duration, UINT8 response_cnt)
{ {
BT_HDR *p; BT_HDR *p;
@ -1331,6 +1329,9 @@ BOOLEAN btsnd_hcic_host_num_xmitted_pkts (UINT8 num_handles, UINT16 *handle,
p->len = HCIC_PREAMBLE_SIZE + 1 + (num_handles * 4); p->len = HCIC_PREAMBLE_SIZE + 1 + (num_handles * 4);
p->offset = 0; p->offset = 0;
hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p);
metadata->flags_src |= HCI_CMD_MSG_F_SRC_NOACK;
UINT16_TO_STREAM (pp, HCI_HOST_NUM_PACKETS_DONE); UINT16_TO_STREAM (pp, HCI_HOST_NUM_PACKETS_DONE);
UINT8_TO_STREAM (pp, p->len - HCIC_PREAMBLE_SIZE); UINT8_TO_STREAM (pp, p->len - HCIC_PREAMBLE_SIZE);
@ -1431,9 +1432,13 @@ BOOLEAN btsnd_hcic_sniff_sub_rate(UINT16 handle, UINT16 max_lat,
#endif /* BTM_SSR_INCLUDED */ #endif /* BTM_SSR_INCLUDED */
/**** Extended Inquiry Response Commands ****/ /**** Extended Inquiry Response Commands ****/
void btsnd_hcic_write_ext_inquiry_response (void *buffer, UINT8 fec_req) void btsnd_hcic_write_ext_inquiry_response (BT_HDR *buffer, UINT8 fec_req)
{ {
BT_HDR *p = (BT_HDR *)buffer; BT_HDR *p;
if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_EXT_INQ_RESP)) == NULL) {
return;
}
UINT8 *pp = (UINT8 *)(p + 1); UINT8 *pp = (UINT8 *)(p + 1);
p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXT_INQ_RESP; p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXT_INQ_RESP;
@ -1441,9 +1446,10 @@ void btsnd_hcic_write_ext_inquiry_response (void *buffer, UINT8 fec_req)
UINT16_TO_STREAM (pp, HCI_WRITE_EXT_INQ_RESPONSE); UINT16_TO_STREAM (pp, HCI_WRITE_EXT_INQ_RESPONSE);
UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_EXT_INQ_RESP); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_EXT_INQ_RESP);
UINT8_TO_STREAM (pp, fec_req); UINT8_TO_STREAM (pp, fec_req);
memcpy(pp, buffer->data + 4, p->len - 4);
btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
} }
@ -1862,17 +1868,17 @@ BOOLEAN btsnd_hcic_write_pagescan_type (UINT8 type)
#error "HCI_CMD_POOL_BUF_SIZE must be larger than 268" #error "HCI_CMD_POOL_BUF_SIZE must be larger than 268"
#endif #endif
void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode, UINT8 len, void btsnd_hcic_vendor_spec_cmd (BT_HDR *buffer, UINT16 opcode, UINT8 len,
UINT8 *p_data, void *p_cmd_cplt_cback) UINT8 *p_data, void *p_cmd_cplt_cback)
{ {
BT_HDR *p = (BT_HDR *)buffer; BT_HDR *p = buffer;
UINT8 *pp = (UINT8 *)(p + 1); UINT8 *pp = (UINT8 *)(p + 1);
p->len = HCIC_PREAMBLE_SIZE + len; p->len = HCIC_PREAMBLE_SIZE + len;
p->offset = sizeof(void *); p->offset = 0;
*((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */ hci_cmd_metadata_t * metadata = HCI_GET_CMD_METAMSG(p);
pp += sizeof(void *); /* Skip over callback pointer */ metadata->context = p_cmd_cplt_cback;
UINT16_TO_STREAM (pp, HCI_GRP_VENDOR_SPECIFIC | opcode); UINT16_TO_STREAM (pp, HCI_GRP_VENDOR_SPECIFIC | opcode);
UINT8_TO_STREAM (pp, len); UINT8_TO_STREAM (pp, len);

View File

@ -19,9 +19,66 @@
#ifndef HCIMSGS_H #ifndef HCIMSGS_H
#define HCIMSGS_H #define HCIMSGS_H
#include <stddef.h>
#include "common/bt_target.h" #include "common/bt_target.h"
#include "stack/hcidefs.h" #include "stack/hcidefs.h"
#include "stack/bt_types.h" #include "stack/bt_types.h"
#include "osi/pkt_queue.h"
#include "osi/allocator.h"
#define HCI_CMD_BUF_TYPE_METADATA (0xa56e)
#define HCI_CMD_MSG_F_SRC_NOACK (0x01)
typedef void (*hci_cmd_cmpl_cb)(BT_HDR *response, void *context);
typedef void (*hci_cmd_stat_cb)(uint8_t status, BT_HDR *command, void *context);
typedef void (*hci_cmd_free_cb)(pkt_linked_item_t *linked_pkt);
typedef struct {
uint8_t flags_src;
uint8_t flags_vnd; // used for downstream layer
uint16_t opcode;
hci_cmd_cmpl_cb command_complete_cb;
hci_cmd_stat_cb command_status_cb;
void *context;
void *complete_future;
hci_cmd_free_cb command_free_cb;
BT_HDR command;
} hci_cmd_metadata_t;
#define HCI_CMD_METADATA_HDR_SIZE (sizeof(hci_cmd_metadata_t))
#define HCI_CMD_LINKED_BUF_SIZE(paramlen) (BT_PKT_LINKED_HDR_SIZE + HCI_CMD_METADATA_HDR_SIZE + HCIC_PREAMBLE_SIZE + (paramlen))
#define HCI_GET_CMD_METAMSG(cmd_ptr) (hci_cmd_metadata_t *)((void *)(cmd_ptr) - offsetof(hci_cmd_metadata_t, command))
#define HCI_GET_CMD_LINKED_STRUCT(metadata_ptr) (pkt_linked_item_t *)((void *)(metadata_ptr) - offsetof(pkt_linked_item_t, data))
static inline BT_HDR *hci_get_cmd_buf(size_t param_len)
{
pkt_linked_item_t *linked_pkt = osi_calloc(HCI_CMD_LINKED_BUF_SIZE(param_len));
if (linked_pkt == NULL) {
return NULL;
}
hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)linked_pkt->data;
BT_HDR *command = &metadata->command;
command->layer_specific = HCI_CMD_BUF_TYPE_METADATA;
command->len = HCIC_PREAMBLE_SIZE + param_len;
command->offset = 0;
return command;
}
static inline void hci_free_cmd_buf(BT_HDR *buf)
{
assert(buf->layer_specific == HCI_CMD_BUF_TYPE_METADATA);
hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(buf);
pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata);
osi_free(linked_pkt);
}
#define HCI_GET_CMD_BUF(param_len) hci_get_cmd_buf(param_len)
#define HCI_FREE_CMD_BUF(buf) hci_free_cmd_buf(buf)
void bte_main_hci_send(BT_HDR *p_msg, UINT16 event); void bte_main_hci_send(BT_HDR *p_msg, UINT16 event);
void bte_main_lpm_allow_bt_device_sleep(void); void bte_main_lpm_allow_bt_device_sleep(void);
@ -378,7 +435,7 @@ BOOLEAN btsnd_hcic_sniff_sub_rate(UINT16 handle, UINT16 max_lat,
#endif /* BTM_SSR_INCLUDED */ #endif /* BTM_SSR_INCLUDED */
/* Extended Inquiry Response */ /* Extended Inquiry Response */
void btsnd_hcic_write_ext_inquiry_response(void *buffer, UINT8 fec_req); void btsnd_hcic_write_ext_inquiry_response(BT_HDR *buffer, UINT8 fec_req);
#define HCIC_PARAM_SIZE_EXT_INQ_RESP 241 #define HCIC_PARAM_SIZE_EXT_INQ_RESP 241
@ -641,7 +698,7 @@ BOOLEAN btsnd_hcic_write_inquiry_mode(UINT8 type); /* Write Inquiry
#define HCID_GET_SCO_LEN(p) (*((UINT8 *)((p) + 1) + p->offset + 2)) #define HCID_GET_SCO_LEN(p) (*((UINT8 *)((p) + 1) + p->offset + 2))
void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode, void btsnd_hcic_vendor_spec_cmd (BT_HDR *buffer, UINT16 opcode,
UINT8 len, UINT8 *p_data, UINT8 len, UINT8 *p_data,
void *p_cmd_cplt_cback); void *p_cmd_cplt_cback);