From 85fc8321c8c4351c918b41f0c31237d22993d4a6 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Tue, 19 Jul 2022 22:16:12 +0800 Subject: [PATCH] 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 --- components/bt/host/bluedroid/hci/hci_layer.c | 136 ++++++++---------- .../host/bluedroid/hci/hci_packet_factory.c | 16 +-- .../bluedroid/hci/include/hci/hci_layer.h | 2 + .../bt/host/bluedroid/stack/btm/btm_devctl.c | 5 +- .../bt/host/bluedroid/stack/btm/btm_inq.c | 1 + .../bt/host/bluedroid/stack/btu/btu_hcif.c | 49 +++++-- .../bt/host/bluedroid/stack/hcic/hciblecmds.c | 23 ++- .../bt/host/bluedroid/stack/hcic/hcicmds.c | 26 ++-- .../bluedroid/stack/include/stack/hcimsgs.h | 61 +++++++- 9 files changed, 187 insertions(+), 132 deletions(-) diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 0365c45f93..8d79043dd4 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -35,6 +35,7 @@ #include "osi/thread.h" #include "osi/mutex.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_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) @@ -44,15 +45,6 @@ #define HCI_HOST_TASK_WORKQUEUE0_LEN (0) #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 { bool timer_is_set; osi_alarm_t *command_response_timer; @@ -62,7 +54,7 @@ typedef struct { typedef struct { int command_credits; - fixed_queue_t *command_queue; + fixed_pkt_queue_t *command_queue; fixed_queue_t *packet_queue; 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 void hci_layer_deinit_env(void); 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 restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q); static void command_timed_out(void *context); static void hal_says_packet_ready(BT_HDR *packet); static bool filter_incoming_event(BT_HDR *packet); 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_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) // This value can change when you get a command complete or command status event. 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) { - 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 { HCI_TRACE_ERROR("%s unable to create pending command queue.", __func__); return -1; @@ -198,7 +190,7 @@ static void hci_layer_deinit_env(void) command_waiting_response_t *cmd_wait_q; 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) { 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) { packet_fragmenter->fragment_and_dispatch(pkt); } 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) { - 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)) { fixed_queue_process(hci_host_env.packet_queue); } @@ -246,48 +238,38 @@ static void transmit_command( command_status_cb status_callback, void *context) { - uint8_t *stream; - waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); - 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; + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(command); + pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata); + assert(command->layer_specific == HCI_CMD_BUF_TYPE_METADATA); // Store the command message type in the event field // in case the upper layer didn't already 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); - 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); } static future_t *transmit_command_futured(BT_HDR *command) { - waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); - assert(wait_entry != NULL); + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(command); + 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(); - uint8_t *stream = command->data + command->offset; - STREAM_TO_UINT16(wait_entry->opcode, stream); - wait_entry->complete_future = future; - wait_entry->command = command; + metadata->complete_future = future; // Store the command message type in the event field // in case the upper layer didn't already 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); return future; } @@ -295,8 +277,8 @@ static future_t *transmit_command_futured(BT_HDR *command) static void transmit_downward(uint16_t type, void *data) { if (type == MSG_STACK_TO_HC_HCI_CMD) { - transmit_command((BT_HDR *)data, NULL, NULL, NULL); - HCI_TRACE_WARNING("%s legacy transmit of command. Use transmit_command instead.\n", __func__); + HCI_TRACE_ERROR("%s legacy transmit of command. Use transmit_command instead.\n", __func__); + assert(0); } else { 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 -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; - 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 -#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) - || wait_entry->opcode == HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL -#endif - ){ - packet_fragmenter->fragment_and_dispatch(wait_entry->command); - osi_free(wait_entry->command); - osi_free(wait_entry); + hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(wait_entry->data); + if (metadata->flags_src & HCI_CMD_MSG_F_SRC_NOACK) { + packet_fragmenter->fragment_and_dispatch(&metadata->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); return; } 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); // 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); } @@ -395,7 +374,7 @@ static void restart_command_waiting_response_timer(command_waiting_response_t *c static void command_timed_out(void *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); 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. // 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. 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 event_code; 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_UINT16(opcode, stream); wait_entry = get_waiting_command(opcode); + metadata = (hci_cmd_metadata_t *)(wait_entry->data); if (!wait_entry) { HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode); - } else if (wait_entry->complete_callback) { - wait_entry->complete_callback(packet, wait_entry->context); + } else if (metadata->command_complete_cb) { + metadata->command_complete_cb(packet, metadata->context); #if (BLE_50_FEATURE_SUPPORT == TRUE) BlE_SYNC *sync_info = btsnd_hcic_ble_get_sync_info(); if(!sync_info) { @@ -461,8 +443,8 @@ static bool filter_incoming_event(BT_HDR *packet) } } #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) - } else if (wait_entry->complete_future) { - future_ready(wait_entry->complete_future, packet); + } else if (metadata->flags_vnd & HCI_CMD_MSG_F_VND_FUTURE) { + future_ready((future_t *)(metadata->complete_future), packet); } 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 wait_entry = get_waiting_command(opcode); + metadata = (hci_cmd_metadata_t *)(wait_entry->data); if (!wait_entry) { HCI_TRACE_WARNING("%s command status event with no matching command. opcode: 0x%x", __func__, opcode); - } else if (wait_entry->status_callback) { - wait_entry->status_callback(status, wait_entry->command, wait_entry->context); + } else if (metadata->command_status_cb) { + metadata->command_status_cb(status, &metadata->command, metadata->context); } goto intercepted; @@ -490,23 +473,22 @@ intercepted: /*Tell HCI Host Task to continue TX Pending commands*/ 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); } if (wait_entry) { // If it has a callback, it's responsible for freeing the packet 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); } // If it has a callback, it's responsible for freeing the command - if (event_code == HCI_COMMAND_COMPLETE_EVT || !wait_entry->status_callback) { - osi_free(wait_entry->command); + if (event_code == HCI_COMMAND_COMPLETE_EVT || !metadata->command_status_cb) { + 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 { osi_free(packet); } @@ -553,7 +535,7 @@ static serial_data_type_t event_to_data_type(uint16_t event) 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; 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); 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; + pkt_linked_item_t *wait_entry = list_node(node); + if (wait_entry) { + 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); diff --git a/components/bt/host/bluedroid/hci/hci_packet_factory.c b/components/bt/host/bluedroid/hci/hci_packet_factory.c index 7fd7f0ddb9..5010e99d2f 100644 --- a/components/bt/host/bluedroid/hci/hci_packet_factory.c +++ b/components/bt/host/bluedroid/hci/hci_packet_factory.c @@ -27,7 +27,6 @@ #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(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) { - 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; 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; } -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 = { make_reset, make_read_buffer_size, diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h index 6ba4ccd18c..728c4997a8 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h @@ -25,6 +25,7 @@ #include "osi/osi.h" #include "osi/future.h" #include "osi/thread.h" +#include "osi/pkt_queue.h" ///// LEGACY DEFINITIONS ///// @@ -47,6 +48,7 @@ /* Local Bluetooth Controller ID for BR/EDR */ #define LOCAL_BR_EDR_CONTROLLER_ID 0 +#define HCI_CMD_MSG_F_VND_FUTURE (0x01) ///// END LEGACY DEFINITIONS ///// typedef struct hci_hal_t hci_hal_t; diff --git a/components/bt/host/bluedroid/stack/btm/btm_devctl.c b/components/bt/host/bluedroid/stack/btm/btm_devctl.c index e75535a931..4061ed4252 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_devctl.c @@ -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, 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.", opcode, param_len); /* Allocate a buffer to hold HCI command plus the callback function */ - if ((p_buf = osi_malloc((UINT16)(sizeof(BT_HDR) + sizeof (tBTM_CMPL_CB *) + - param_len + HCIC_PREAMBLE_SIZE))) != NULL) { + if ((p_buf = HCI_GET_CMD_BUF(param_len)) != NULL) { /* 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); diff --git a/components/bt/host/bluedroid/stack/btm/btm_inq.c b/components/bt/host/bluedroid/stack/btm/btm_inq.c index be8bc27b2b..21ebe81b9b 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_inq.c +++ b/components/bt/host/bluedroid/stack/btm/btm_inq.c @@ -2395,6 +2395,7 @@ tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff, BOOLEAN fec_required) if (controller_get_interface()->supports_extended_inquiry_response()) { BTM_TRACE_API("Write Extended Inquiry Response to controller\n"); btsnd_hcic_write_ext_inquiry_response (p_buff, fec_required); + osi_free(p_buff); return BTM_SUCCESS; } else { osi_free(p_buff); diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index d9130bd254..2ce46ec1bf 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -43,6 +43,7 @@ #include "common/bt_trace.h" #include "osi/thread.h" +#include "osi/pkt_queue.h" //#include "osi/mutex.h" // TODO(zachoverflow): remove this horrible hack #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); - // Eww...horrible hackery here - /* If command was a VSC, then extract command_complete callback */ - if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC + assert (p_buf->layer_specific == HCI_CMD_BUF_TYPE_METADATA); + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p_buf); + 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 - || (opcode == HCI_BLE_RAND) - || (opcode == HCI_BLE_ENCRYPT) + && (opcode != HCI_BLE_RAND) + && (opcode != HCI_BLE_ENCRYPT) #endif - ) { - vsc_callback = *((void **)(p_buf + 1)); + ) { + assert (vsc_callback == NULL); } 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 (); #endif } + #if (BLE_50_FEATURE_SUPPORT == TRUE) 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; - // Eww...horrible hackery here - /* If command was a VSC, then extract command_complete callback */ - if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC + assert (p_buf->layer_specific == HCI_CMD_BUF_TYPE_METADATA); + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p_buf); + 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 - || (opcode == HCI_BLE_RAND) - || (opcode == HCI_BLE_ENCRYPT) + && (opcode != HCI_BLE_RAND) + && (opcode != HCI_BLE_ENCRYPT) #endif - ) { - vsc_callback = *((void **)(p_buf + 1)); + ) { + assert (vsc_callback == NULL); } hci_layer_get_interface()->transmit_command( @@ -1434,7 +1449,11 @@ static void btu_hcif_command_status_evt_on_task(BT_HDR *event) stream, 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); } diff --git a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c index 50935f3be6..b816d0227b 100644 --- a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c +++ b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c @@ -33,7 +33,6 @@ #include #include -#define HCI_GET_CMD_BUF(paramlen) ((BT_HDR *)osi_malloc(HCIC_PREAMBLE_SIZE + sizeof(BT_HDR) + paramlen)) #if (BLE_50_FEATURE_SUPPORT == TRUE) static BlE_SYNC ble_sync_info; @@ -557,19 +556,17 @@ BOOLEAN btsnd_hcic_ble_encrypt (UINT8 *key, UINT8 key_len, BT_HDR *p; UINT8 *pp; - if ((p = HCI_GET_CMD_BUF(sizeof (void *) + - HCIC_PARAM_SIZE_BLE_ENCRYPT)) == NULL) { + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_ENCRYPT)) == NULL) { return (FALSE); } pp = (UINT8 *)(p + 1); p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ENCRYPT; - p->offset = sizeof(void *); - - *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */ - pp += sizeof(void *); /* Skip over callback pointer */ + p->offset = 0; + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p); + metadata->context = p_cmd_cplt_cback; UINT16_TO_STREAM (pp, HCI_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; UINT8 *pp; - if ((p = HCI_GET_CMD_BUF(sizeof (void *) + - HCIC_PARAM_SIZE_BLE_RAND)) == NULL) { + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_RAND)) == NULL) { return (FALSE); } pp = (UINT8 *)(p + 1); 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 */ - 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_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->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); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL); UINT16_TO_STREAM (pp, num); diff --git a/components/bt/host/bluedroid/stack/hcic/hcicmds.c b/components/bt/host/bluedroid/stack/hcic/hcicmds.c index 8ca8db0742..89995ebaa2 100644 --- a/components/bt/host/bluedroid/stack/hcic/hcicmds.c +++ b/components/bt/host/bluedroid/stack/hcic/hcicmds.c @@ -35,8 +35,6 @@ #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) { 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->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); 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 */ /**** 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); 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); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_EXT_INQ_RESP); - UINT8_TO_STREAM (pp, fec_req); + memcpy(pp, buffer->data + 4, p->len - 4); + 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" #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) { - BT_HDR *p = (BT_HDR *)buffer; + BT_HDR *p = buffer; UINT8 *pp = (UINT8 *)(p + 1); 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 */ - 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_GRP_VENDOR_SPECIFIC | opcode); UINT8_TO_STREAM (pp, len); diff --git a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h index 3a03c22dd4..223052264e 100644 --- a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h +++ b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h @@ -19,9 +19,66 @@ #ifndef HCIMSGS_H #define HCIMSGS_H +#include #include "common/bt_target.h" #include "stack/hcidefs.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_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 */ /* 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 @@ -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)) -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, void *p_cmd_cplt_cback);