l2cap: manage fixed channels for ATT, SM, and Connectionless Data in l2cap_fixed_channel_t and keep in unified channels list

This commit is contained in:
Matthias Ringwald 2018-02-02 17:52:13 +01:00
parent 421cb1044d
commit fad84caf30
2 changed files with 124 additions and 159 deletions

View File

@ -74,12 +74,6 @@
#define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2
#define L2CAP_SIGNALING_COMMAND_DATA_OFFSET 4
// internal table
#define L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL 0
#define L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL 1
#define L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL 2
#define L2CAP_FIXED_CHANNEL_TABLE_SIZE (L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL+1)
#if defined(ENABLE_LE_DATA_CHANNELS) || defined(ENABLE_CLASSIC)
#define L2CAP_USES_CHANNELS
#endif
@ -120,11 +114,10 @@ static void l2cap_ertm_monitor_timeout_callback(btstack_timer_source_t * ts);
static void l2cap_ertm_retransmission_timeout_callback(btstack_timer_source_t * ts);
#endif
typedef struct l2cap_fixed_channel {
btstack_packet_handler_t callback;
uint8_t waiting_for_can_send_now;
uint8_t next_request;
} l2cap_fixed_channel_t;
// l2cap_fixed_channel_t entries
static l2cap_fixed_channel_t l2cap_fixed_channel_att;
static l2cap_fixed_channel_t l2cap_fixed_channel_sm;
static l2cap_fixed_channel_t l2cap_fixed_channel_connectionless;
#ifdef ENABLE_CLASSIC
static btstack_linked_list_t l2cap_services;
@ -135,19 +128,13 @@ static uint8_t require_security_level2_for_outgoing_sdp;
static btstack_linked_list_t l2cap_le_services;
#endif
#ifdef L2CAP_USES_CHANNELS
// single list of channels for Classic Channels, LE Data Channels, Classic Connectionless, ATT, and SM
static btstack_linked_list_t l2cap_channels;
#endif
// used to cache l2cap rejects, echo, and informational requests
static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES];
static int signaling_responses_pending;
static btstack_packet_callback_registration_t hci_event_callback_registration;
#define FIXED_CHANNEL_FIFO_INVALID_INDEX 0xff
static l2cap_fixed_channel_t fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_SIZE];
static uint8_t fixed_channel_head_index = FIXED_CHANNEL_FIFO_INVALID_INDEX;
static uint8_t fixed_channel_tail_index = FIXED_CHANNEL_FIFO_INVALID_INDEX;
#ifdef ENABLE_BLE
// only used for connection parameter update events
@ -565,7 +552,7 @@ static void l2cap_ertm_notify_channel_can_send(l2cap_channel_t * channel){
uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, l2cap_ertm_config_t * ertm_config, uint8_t * buffer, uint32_t size){
log_info("L2CAP_ACCEPT_ERTM_CONNECTION local_cid 0x%x", local_cid);
l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
l2cap_channel_t * channel = (l2cap_channel_t*) l2cap_get_channel_for_local_cid(local_cid);
if (!channel) {
log_error("l2cap_accept_connection called but local_cid 0x%x not found", local_cid);
return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
@ -588,7 +575,7 @@ uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, l2cap_ertm_config_t * e
}
uint8_t l2cap_ertm_set_busy(uint16_t local_cid){
l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
l2cap_channel_t * channel = (l2cap_channel_t*) l2cap_get_channel_for_local_cid( local_cid);
if (!channel) {
log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
@ -602,7 +589,7 @@ uint8_t l2cap_ertm_set_busy(uint16_t local_cid){
}
uint8_t l2cap_ertm_set_ready(uint16_t local_cid){
l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
l2cap_channel_t * channel = (l2cap_channel_t*) l2cap_get_channel_for_local_cid( local_cid);
if (!channel) {
log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
@ -728,44 +715,19 @@ static void l2cap_ertm_handle_in_sequence_sdu(l2cap_channel_t * l2cap_channel, l
#endif
static uint16_t l2cap_fixed_channel_table_channel_id_for_index(int index){
switch (index){
case L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL:
return L2CAP_CID_ATTRIBUTE_PROTOCOL;
case L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL:
return L2CAP_CID_SECURITY_MANAGER_PROTOCOL;
case L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL:
return L2CAP_CID_CONNECTIONLESS_CHANNEL;
default:
return 0;
}
}
static int l2cap_fixed_channel_table_index_for_channel_id(uint16_t channel_id){
switch (channel_id){
case L2CAP_CID_ATTRIBUTE_PROTOCOL:
return L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL;
case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
return L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL;
case L2CAP_CID_CONNECTIONLESS_CHANNEL:
return L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL;
default:
return -1;
}
}
static int l2cap_fixed_channel_table_index_is_le(int index){
if (index == L2CAP_CID_CONNECTIONLESS_CHANNEL) return 0;
return 1;
}
void l2cap_init(void){
signaling_responses_pending = 0;
#ifdef ENABLE_CLASSIC
l2cap_channels = NULL;
#ifdef ENABLE_CLASSIC
l2cap_services = NULL;
require_security_level2_for_outgoing_sdp = 0;
// Setup Connectionless Channel
l2cap_fixed_channel_connectionless.local_cid = L2CAP_CID_CONNECTIONLESS_CHANNEL;
l2cap_fixed_channel_connectionless.channel_type = L2CAP_CHANNEL_TYPE_FIXED;
btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) &l2cap_fixed_channel_connectionless);
#endif
#ifdef ENABLE_LE_DATA_CHANNELS
@ -775,13 +737,18 @@ void l2cap_init(void){
#ifdef ENABLE_BLE
l2cap_event_packet_handler = NULL;
l2cap_le_custom_max_mtu = 0;
#endif
memset(fixed_channels, 0, sizeof(fixed_channels));
int i;
for (i=0;i<L2CAP_FIXED_CHANNEL_TABLE_SIZE;i++){
fixed_channels[i].next_request = FIXED_CHANNEL_FIFO_INVALID_INDEX;
}
// Setup fixed ATT Channel
l2cap_fixed_channel_att.local_cid = L2CAP_CID_ATTRIBUTE_PROTOCOL;
l2cap_fixed_channel_att.channel_type = L2CAP_CHANNEL_TYPE_FIXED;
btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) &l2cap_fixed_channel_att);
// Setup fixed SM Channel
l2cap_fixed_channel_sm.local_cid = L2CAP_CID_SECURITY_MANAGER_PROTOCOL;
l2cap_fixed_channel_sm.channel_type = L2CAP_CHANNEL_TYPE_FIXED;
btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) &l2cap_fixed_channel_sm);
#endif
//
// register callback with HCI
//
@ -804,23 +771,11 @@ void l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t
}
void l2cap_request_can_send_fix_channel_now_event(hci_con_handle_t con_handle, uint16_t channel_id){
UNUSED(con_handle); // ok: there is no channel
UNUSED(con_handle); // ok: there is no con handle
int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id);
if (index < 0) return;
// check if already registered
if (fixed_channels[index].waiting_for_can_send_now) return;
// insert into queue
if (fixed_channel_tail_index == FIXED_CHANNEL_FIFO_INVALID_INDEX){
fixed_channel_head_index = index;
} else {
fixed_channels[fixed_channel_tail_index].next_request = index;
}
fixed_channel_tail_index = index;
fixed_channels[index].next_request = FIXED_CHANNEL_FIFO_INVALID_INDEX;
fixed_channels[index].waiting_for_can_send_now = 1;
l2cap_fixed_channel_t * channel = (l2cap_fixed_channel_t *) l2cap_get_channel_for_local_cid(channel_id);
if (!channel) return;
channel->waiting_for_can_send_now = 1;
l2cap_notify_channel_can_send();
}
@ -960,18 +915,29 @@ static void l2cap_emit_incoming_connection(l2cap_channel_t *channel) {
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
}
static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
static l2cap_fixed_channel_t * l2cap_channel_item_by_cid(uint16_t cid){
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if ( channel->local_cid == local_cid) {
l2cap_fixed_channel_t * channel = (l2cap_fixed_channel_t*) btstack_linked_list_iterator_next(&it);
if (channel->local_cid == cid) {
return channel;
}
}
return NULL;
}
// used for Classic Channels + LE Data Channels. local_cid >= 0x40
static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
if (local_cid < 0x40) return NULL;
return (l2cap_channel_t*) l2cap_channel_item_by_cid(local_cid);
}
// used for fixed channels in LE (ATT/SM) and Classic (Connectionless Channel). CID < 0x04
static l2cap_fixed_channel_t * l2cap_fixed_channel_for_channel_id(uint16_t local_cid){
if (local_cid >= 0x40) return NULL;
return (l2cap_fixed_channel_t*) l2cap_channel_item_by_cid(local_cid);
}
///
void l2cap_request_can_send_now_event(uint16_t local_cid){
@ -1017,12 +983,24 @@ uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){
return 0;
}
static int l2cap_is_dynamic_channel_type(l2cap_channel_type_t channel_type){
switch (channel_type){
case L2CAP_CHANNEL_TYPE_CLASSIC:
case L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL:
return 1;
default:
return 0;
}
}
// RTX Timer only exist for dynamic channels
static l2cap_channel_t * l2cap_channel_for_rtx_timer(btstack_timer_source_t * ts){
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if ( &channel->rtx == ts) {
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if (&channel->rtx == ts) {
return channel;
}
}
@ -1857,7 +1835,8 @@ static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t s
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if ( bd_addr_cmp( channel->address, address) != 0) continue;
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if (bd_addr_cmp( channel->address, address) != 0) continue;
// channel for this address found
switch (channel->state){
case L2CAP_STATE_WAIT_CONNECTION_COMPLETE:
@ -1875,6 +1854,7 @@ static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t s
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if (channel->state == L2CAP_STATE_EMIT_OPEN_FAILED_AND_DISCARD){
done = 0;
// failure, forward error code
@ -1895,6 +1875,7 @@ static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if ( ! bd_addr_cmp( channel->address, address) ){
l2cap_handle_connection_complete(handle, channel);
}
@ -1905,8 +1886,6 @@ static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_
#endif
static void l2cap_notify_channel_can_send(void){
#ifdef ENABLE_CLASSIC
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
@ -1916,62 +1895,6 @@ static void l2cap_notify_channel_can_send(void){
channel->waiting_for_can_send_now = 0;
l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid);
}
#endif
#if 1
if (fixed_channel_head_index != FIXED_CHANNEL_FIFO_INVALID_INDEX){
int can_send = 0;
int remove_entry = 1;
uint8_t i = fixed_channel_head_index;
if (fixed_channels[i].callback && fixed_channels[i].waiting_for_can_send_now){
if (l2cap_fixed_channel_table_index_is_le(i)){
#ifdef ENABLE_BLE
can_send = hci_can_send_acl_le_packet_now();
remove_entry = can_send;
#endif
} else {
#ifdef ENABLE_CLASSIC
can_send = hci_can_send_acl_classic_packet_now();
remove_entry = can_send;
#endif
}
}
// remove entry
if (remove_entry){
fixed_channels[i].waiting_for_can_send_now = 0;
fixed_channel_head_index = fixed_channels[i].next_request;
fixed_channels[i].next_request = FIXED_CHANNEL_FIFO_INVALID_INDEX;
if (fixed_channel_head_index == FIXED_CHANNEL_FIFO_INVALID_INDEX){
fixed_channel_tail_index = FIXED_CHANNEL_FIFO_INVALID_INDEX;
}
}
// notify
if (can_send) {
l2cap_emit_can_send_now(fixed_channels[i].callback, l2cap_fixed_channel_table_channel_id_for_index(i));
}
}
#else
int i;
for (i=0;i<L2CAP_FIXED_CHANNEL_TABLE_SIZE;i++){
if (!fixed_channels[i].callback) continue;
if (!fixed_channels[i].waiting_for_can_send_now) continue;
int can_send = 0;
if (l2cap_fixed_channel_table_index_is_le(i)){
#ifdef ENABLE_BLE
can_send = hci_can_send_acl_le_packet_now();
#endif
} else {
#ifdef ENABLE_CLASSIC
can_send = hci_can_send_acl_classic_packet_now();
#endif
}
if (!can_send) continue;
fixed_channels[i].waiting_for_can_send_now = 0;
l2cap_emit_can_send_now(fixed_channels[i].callback, l2cap_fixed_channel_table_channel_id_for_index(i));
}
#endif
}
#ifdef L2CAP_USES_CHANNELS
@ -2099,6 +2022,7 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if (channel->con_handle != handle) continue;
btstack_linked_list_iterator_remove(&it);
switch(channel->channel_type){
@ -2129,6 +2053,7 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if (channel->con_handle != handle) continue;
hci_con_used = 1;
break;
@ -2143,6 +2068,7 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if (channel->con_handle != handle) continue;
l2cap_handle_remote_supported_features_received(channel);
break;
@ -2155,6 +2081,7 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if (channel->con_handle != handle) continue;
gap_security_level_t actual_level = (gap_security_level_t) packet[4];
@ -2680,6 +2607,7 @@ static void l2cap_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t *
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if (channel->con_handle != handle) continue;
// bail if ERTM was requested but is not supported
if ((channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION) && ((connection->l2cap_state.extended_feature_mask & 0x08) == 0)){
@ -2726,6 +2654,7 @@ static void l2cap_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t *
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
if (channel->con_handle != handle) continue;
if (code & 1) {
// match odd commands (responses) by previous signaling identifier
@ -2842,6 +2771,7 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(a_channel->channel_type)) continue;
if (a_channel->con_handle != handle) continue;
if (a_channel->local_sig_id != sig_id) continue;
channel = a_channel;
@ -2886,6 +2816,7 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(a_channel->channel_type)) continue;
if (a_channel->con_handle != handle) continue;
if (a_channel->remote_cid != source_cid) continue;
// 0x000a Connection refused - Source CID already allocated
@ -2967,6 +2898,7 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
if (!l2cap_is_dynamic_channel_type(a_channel->channel_type)) continue;
if (a_channel->con_handle != handle) continue;
if (a_channel->local_sig_id != sig_id) continue;
channel = a_channel;
@ -3051,6 +2983,7 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
static void l2cap_acl_classic_handler(hci_con_handle_t handle, uint8_t *packet, uint16_t size){
#ifdef ENABLE_CLASSIC
l2cap_channel_t * l2cap_channel;
l2cap_fixed_channel_t * l2cap_fixed_channel;
uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
switch (channel_id) {
@ -3073,9 +3006,10 @@ static void l2cap_acl_classic_handler(hci_con_handle_t handle, uint8_t *packet,
break;
}
case L2CAP_CID_CONNECTIONLESS_CHANNEL:
if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL].callback) {
(*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL].callback)(UCD_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
}
l2cap_fixed_channel = l2cap_fixed_channel_for_channel_id(L2CAP_CID_CONNECTIONLESS_CHANNEL);
if (!l2cap_fixed_channel) break;
if (!l2cap_fixed_channel->packet_handler) break;
(*l2cap_fixed_channel->packet_handler)(UCD_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
break;
default:
@ -3266,6 +3200,8 @@ static void l2cap_acl_classic_handler(hci_con_handle_t handle, uint8_t *packet,
static void l2cap_acl_le_handler(hci_con_handle_t handle, uint8_t *packet, uint16_t size){
#ifdef ENABLE_BLE
l2cap_fixed_channel_t * l2cap_fixed_channel;
#ifdef ENABLE_LE_DATA_CHANNELS
l2cap_channel_t * l2cap_channel;
#endif
@ -3284,15 +3220,17 @@ static void l2cap_acl_le_handler(hci_con_handle_t handle, uint8_t *packet, uint1
}
case L2CAP_CID_ATTRIBUTE_PROTOCOL:
if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL].callback) {
(*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL].callback)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
}
l2cap_fixed_channel = l2cap_fixed_channel_for_channel_id(L2CAP_CID_ATTRIBUTE_PROTOCOL);
if (!l2cap_fixed_channel) break;
if (!l2cap_fixed_channel->packet_handler) break;
(*l2cap_fixed_channel->packet_handler)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
break;
case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL].callback) {
(*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL].callback)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
}
l2cap_fixed_channel = l2cap_fixed_channel_for_channel_id(L2CAP_CID_SECURITY_MANAGER_PROTOCOL);
if (!l2cap_fixed_channel) break;
if (!l2cap_fixed_channel->packet_handler) break;
(*l2cap_fixed_channel->packet_handler)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
break;
default:
@ -3369,9 +3307,9 @@ static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa
// Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
void l2cap_register_fixed_channel(btstack_packet_handler_t the_packet_handler, uint16_t channel_id) {
int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id);
if (index < 0) return;
fixed_channels[index].callback = the_packet_handler;
l2cap_fixed_channel_t * channel = l2cap_fixed_channel_for_channel_id(channel_id);
if (!channel) return;
channel->packet_handler = the_packet_handler;
}
#ifdef ENABLE_CLASSIC

View File

@ -117,10 +117,9 @@ typedef enum {
} L2CAP_CHANNEL_STATE_VAR;
typedef enum {
L2CAP_CHANNEL_TYPE_CLASSIC, // Basic or ERTM
L2CAP_CHANNEL_TYPE_CONNECTIONLESS, // Classic
L2CAP_CHANNEL_TYPE_LE_FIXED, // ATT + SM
L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL,
L2CAP_CHANNEL_TYPE_CLASSIC, // Classic Basic or ERTM
L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL, // LE
L2CAP_CHANNEL_TYPE_FIXED, // Classic Connectionless + LE ATT + LE SM
} l2cap_channel_type_t;
typedef struct {
@ -161,16 +160,46 @@ typedef struct {
} l2cap_ertm_config_t;
// info regarding an actual connection
// info regarding an actual channel
// note: l2cap_fixed_channel and l2cap_channel_t share commmon fields
typedef struct l2cap_fixed_channel {
// linked list - assert: first field
btstack_linked_item_t item;
// channel type
l2cap_channel_type_t channel_type;
// local cid, primary key for channel lookup
uint16_t local_cid;
// packet handler
btstack_packet_handler_t packet_handler;
// send request
uint8_t waiting_for_can_send_now;
// -- end of shared prefix
} l2cap_fixed_channel_t;
typedef struct {
// linked list - assert: first field
btstack_linked_item_t item;
// channel type
l2cap_channel_type_t channel_type;
// local cid, primary key for channel lookup
uint16_t local_cid;
// packet handler
btstack_packet_handler_t packet_handler;
// channel type
l2cap_channel_type_t channel_type;
// send request
uint8_t waiting_for_can_send_now;
// -- end of shared prefix
// timer
btstack_timer_source_t rtx; // also used for ertx
@ -187,7 +216,6 @@ typedef struct {
uint8_t remote_sig_id; // used by other side, needed for delayed response
uint8_t local_sig_id; // own signaling identifier
uint16_t local_cid;
uint16_t remote_cid;
uint16_t local_mtu;
@ -200,7 +228,6 @@ typedef struct {
gap_security_level_t required_security_level;
uint8_t reason; // used in decline internal
uint8_t waiting_for_can_send_now;
// LE Data Channels