l2cap: reduce code size if ENABLE_CLASSIC not defined

This commit is contained in:
Matthias Ringwald 2016-10-19 14:27:25 +02:00
parent 3a18db10c5
commit 09e9d05bab

View File

@ -81,18 +81,23 @@
#define L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL 2 #define L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL 2
#define L2CAP_FIXED_CHANNEL_TABLE_SIZE (L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL+1) #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
// prototypes // prototypes
static void l2cap_finialize_channel_close(l2cap_channel_t *channel);
static inline l2cap_service_t * l2cap_get_service(uint16_t psm);
static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status);
static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel);
static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
static void l2cap_emit_incoming_connection(l2cap_channel_t *channel);
static int l2cap_channel_ready_for_open(l2cap_channel_t *channel);
static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ); static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size );
static void l2cap_notify_channel_can_send(void); static void l2cap_notify_channel_can_send(void);
static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel);
#ifdef ENABLE_CLASSIC
static void l2cap_finialize_channel_close(l2cap_channel_t *channel);
static inline l2cap_service_t * l2cap_get_service(uint16_t psm);
static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status);
static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
static void l2cap_emit_incoming_connection(l2cap_channel_t *channel);
static int l2cap_channel_ready_for_open(l2cap_channel_t *channel);
#endif
#ifdef ENABLE_LE_DATA_CHANNELS #ifdef ENABLE_LE_DATA_CHANNELS
static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status); static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status);
static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel); static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel);
@ -107,8 +112,11 @@ typedef struct l2cap_fixed_channel {
uint8_t waiting_for_can_send_now; uint8_t waiting_for_can_send_now;
} l2cap_fixed_channel_t; } l2cap_fixed_channel_t;
#ifdef ENABLE_CLASSIC
static btstack_linked_list_t l2cap_channels; static btstack_linked_list_t l2cap_channels;
static btstack_linked_list_t l2cap_services; static btstack_linked_list_t l2cap_services;
static uint8_t require_security_level2_for_outgoing_sdp;
#endif
#ifdef ENABLE_LE_DATA_CHANNELS #ifdef ENABLE_LE_DATA_CHANNELS
static btstack_linked_list_t l2cap_le_channels; static btstack_linked_list_t l2cap_le_channels;
@ -119,8 +127,6 @@ static btstack_linked_list_t l2cap_le_services;
static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES]; static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES];
static int signaling_responses_pending; static int signaling_responses_pending;
static uint8_t require_security_level2_for_outgoing_sdp;
static btstack_packet_callback_registration_t hci_event_callback_registration; static btstack_packet_callback_registration_t hci_event_callback_registration;
static btstack_packet_handler_t l2cap_event_packet_handler; static btstack_packet_handler_t l2cap_event_packet_handler;
@ -159,8 +165,11 @@ static int l2cap_fixed_channel_table_index_is_le(int index){
void l2cap_init(void){ void l2cap_init(void){
signaling_responses_pending = 0; signaling_responses_pending = 0;
#ifdef ENABLE_CLASSIC
l2cap_channels = NULL; l2cap_channels = NULL;
l2cap_services = NULL; l2cap_services = NULL;
require_security_level2_for_outgoing_sdp = 0;
#endif
#ifdef ENABLE_LE_DATA_CHANNELS #ifdef ENABLE_LE_DATA_CHANNELS
l2cap_le_services = NULL; l2cap_le_services = NULL;
@ -170,8 +179,6 @@ void l2cap_init(void){
l2cap_event_packet_handler = NULL; l2cap_event_packet_handler = NULL;
memset(fixed_channels, 0, sizeof(fixed_channels)); memset(fixed_channels, 0, sizeof(fixed_channels));
require_security_level2_for_outgoing_sdp = 0;
// //
// register callback with HCI // register callback with HCI
// //
@ -187,6 +194,88 @@ void l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t
l2cap_event_packet_handler = handler; l2cap_event_packet_handler = handler;
} }
void l2cap_request_can_send_fix_channel_now_event(hci_con_handle_t con_handle, uint16_t channel_id){
int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id);
if (index < 0) return;
fixed_channels[index].waiting_for_can_send_now = 1;
l2cap_notify_channel_can_send();
}
int l2cap_can_send_fixed_channel_packet_now(hci_con_handle_t con_handle, uint16_t channel_id){
return hci_can_send_acl_packet_now(con_handle);
}
uint8_t *l2cap_get_outgoing_buffer(void){
return hci_get_outgoing_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
}
int l2cap_reserve_packet_buffer(void){
return hci_reserve_packet_buffer();
}
void l2cap_release_packet_buffer(void){
hci_release_packet_buffer();
}
static void l2cap_setup_header(uint8_t * acl_buffer, hci_con_handle_t con_handle, uint16_t remote_cid, uint16_t len){
int pb = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02;
// 0 - Connection handle : PB=pb : BC=00
little_endian_store_16(acl_buffer, 0, con_handle | (pb << 12) | (0 << 14));
// 2 - ACL length
little_endian_store_16(acl_buffer, 2, len + 4);
// 4 - L2CAP packet length
little_endian_store_16(acl_buffer, 4, len + 0);
// 6 - L2CAP channel DEST
little_endian_store_16(acl_buffer, 6, remote_cid);
}
int l2cap_send_prepared_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint16_t len){
if (!hci_is_packet_buffer_reserved()){
log_error("l2cap_send_prepared_connectionless called without reserving packet first");
return BTSTACK_ACL_BUFFERS_FULL;
}
if (!hci_can_send_prepared_acl_packet_now(con_handle)){
log_info("l2cap_send_prepared_connectionless handle 0x%02x, cid 0x%02x, cannot send", con_handle, cid);
return BTSTACK_ACL_BUFFERS_FULL;
}
log_debug("l2cap_send_prepared_connectionless handle %u, cid 0x%02x", con_handle, cid);
uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
l2cap_setup_header(acl_buffer, con_handle, cid, len);
// send
return hci_send_acl_packet_buffer(len+8);
}
int l2cap_send_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint8_t *data, uint16_t len){
if (!hci_can_send_acl_packet_now(con_handle)){
log_info("l2cap_send cid 0x%02x, cannot send", cid);
return BTSTACK_ACL_BUFFERS_FULL;
}
hci_reserve_packet_buffer();
uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
memcpy(&acl_buffer[8], data, len);
return l2cap_send_prepared_connectionless(con_handle, cid, len);
}
static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel) {
log_info("L2CAP_EVENT_CHANNEL_CAN_SEND_NOW local_cid 0x%x", channel);
uint8_t event[4];
event[0] = L2CAP_EVENT_CAN_SEND_NOW;
event[1] = sizeof(event) - 2;
little_endian_store_16(event, 2, channel);
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
packet_handler(HCI_EVENT_PACKET, channel, event, sizeof(event));
}
#ifdef L2CAP_USES_CHANNELS
static void l2cap_dispatch_to_channel(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){ static void l2cap_dispatch_to_channel(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){
(* (channel->packet_handler))(type, channel->local_cid, data, size); (* (channel->packet_handler))(type, channel->local_cid, data, size);
} }
@ -199,7 +288,9 @@ static void l2cap_emit_simple_event_with_cid(l2cap_channel_t * channel, uint8_t
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event)); l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
} }
#endif
#ifdef ENABLE_CLASSIC
void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) { void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
log_info("L2CAP_EVENT_CHANNEL_OPENED status 0x%x addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x local_mtu %u, remote_mtu %u, flush_timeout %u", log_info("L2CAP_EVENT_CHANNEL_OPENED status 0x%x addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x local_mtu %u, remote_mtu %u, flush_timeout %u",
status, bd_addr_to_str(channel->address), channel->con_handle, channel->psm, status, bd_addr_to_str(channel->address), channel->con_handle, channel->psm,
@ -225,17 +316,6 @@ static void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED); l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED);
} }
static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel) {
log_info("L2CAP_EVENT_CHANNEL_CAN_SEND_NOW local_cid 0x%x", channel);
uint8_t event[4];
event[0] = L2CAP_EVENT_CAN_SEND_NOW;
event[1] = sizeof(event) - 2;
little_endian_store_16(event, 2, channel);
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
packet_handler(HCI_EVENT_PACKET, channel, event, sizeof(event));
}
static void l2cap_emit_incoming_connection(l2cap_channel_t *channel) { static void l2cap_emit_incoming_connection(l2cap_channel_t *channel) {
log_info("L2CAP_EVENT_INCOMING_CONNECTION addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x", log_info("L2CAP_EVENT_INCOMING_CONNECTION addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x",
bd_addr_to_str(channel->address), channel->con_handle, channel->psm, channel->local_cid, channel->remote_cid); bd_addr_to_str(channel->address), channel->con_handle, channel->psm, channel->local_cid, channel->remote_cid);
@ -251,17 +331,6 @@ static void l2cap_emit_incoming_connection(l2cap_channel_t *channel) {
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event)); l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
} }
static void l2cap_emit_connection_parameter_update_response(hci_con_handle_t con_handle, uint16_t result){
uint8_t event[6];
event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE;
event[1] = 4;
little_endian_store_16(event, 2, con_handle);
little_endian_store_16(event, 4, result);
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
if (!l2cap_event_packet_handler) return;
(*l2cap_event_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){ static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
btstack_linked_list_iterator_t it; btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &l2cap_channels); btstack_linked_list_iterator_init(&it, &l2cap_channels);
@ -283,15 +352,6 @@ void l2cap_request_can_send_now_event(uint16_t local_cid){
l2cap_notify_channel_can_send(); l2cap_notify_channel_can_send();
} }
void l2cap_request_can_send_fix_channel_now_event(hci_con_handle_t con_handle, uint16_t channel_id){
int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id);
if (index < 0) return;
fixed_channels[index].waiting_for_can_send_now = 1;
l2cap_notify_channel_can_send();
}
///
int l2cap_can_send_packet_now(uint16_t local_cid){ int l2cap_can_send_packet_now(uint16_t local_cid){
l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid); l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
if (!channel) return 0; if (!channel) return 0;
@ -303,13 +363,6 @@ int l2cap_can_send_prepared_packet_now(uint16_t local_cid){
if (!channel) return 0; if (!channel) return 0;
return hci_can_send_prepared_acl_packet_now(channel->con_handle); return hci_can_send_prepared_acl_packet_now(channel->con_handle);
} }
int l2cap_can_send_fixed_channel_packet_now(hci_con_handle_t con_handle, uint16_t channel_id){
return hci_can_send_acl_packet_now(con_handle);
}
///
uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){ uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){
l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
if (channel) { if (channel) {
@ -377,7 +430,6 @@ static int l2cap_security_level_0_allowed_for_PSM(uint16_t psm){
} }
static int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){ static int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
if (!hci_can_send_acl_packet_now(handle)){ if (!hci_can_send_acl_packet_now(handle)){
log_info("l2cap_send_signaling_packet, cannot send"); log_info("l2cap_send_signaling_packet, cannot send");
return BTSTACK_ACL_BUFFERS_FULL; return BTSTACK_ACL_BUFFERS_FULL;
@ -394,52 +446,6 @@ static int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_
return hci_send_acl_packet_buffer(len); return hci_send_acl_packet_buffer(len);
} }
#ifdef ENABLE_BLE
static int l2cap_send_le_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
if (!hci_can_send_acl_packet_now(handle)){
log_info("l2cap_send_signaling_packet, cannot send");
return BTSTACK_ACL_BUFFERS_FULL;
}
// log_info("l2cap_send_signaling_packet type %u", cmd);
hci_reserve_packet_buffer();
uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
va_list argptr;
va_start(argptr, identifier);
uint16_t len = l2cap_create_signaling_le(acl_buffer, handle, cmd, identifier, argptr);
va_end(argptr);
// log_info("l2cap_send_signaling_packet con %u!", handle);
return hci_send_acl_packet_buffer(len);
}
#endif
uint8_t *l2cap_get_outgoing_buffer(void){
return hci_get_outgoing_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
}
int l2cap_reserve_packet_buffer(void){
return hci_reserve_packet_buffer();
}
void l2cap_release_packet_buffer(void){
hci_release_packet_buffer();
}
static void l2cap_setup_header(uint8_t * acl_buffer, hci_con_handle_t con_handle, uint16_t remote_cid, uint16_t len){
int pb = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02;
// 0 - Connection handle : PB=pb : BC=00
little_endian_store_16(acl_buffer, 0, con_handle | (pb << 12) | (0 << 14));
// 2 - ACL length
little_endian_store_16(acl_buffer, 2, len + 4);
// 4 - L2CAP packet length
little_endian_store_16(acl_buffer, 4, len + 0);
// 6 - L2CAP channel DEST
little_endian_store_16(acl_buffer, 6, remote_cid);
}
int l2cap_send_prepared(uint16_t local_cid, uint16_t len){ int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
if (!hci_is_packet_buffer_reserved()){ if (!hci_is_packet_buffer_reserved()){
@ -466,26 +472,6 @@ int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
return hci_send_acl_packet_buffer(len+8); return hci_send_acl_packet_buffer(len+8);
} }
int l2cap_send_prepared_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint16_t len){
if (!hci_is_packet_buffer_reserved()){
log_error("l2cap_send_prepared_connectionless called without reserving packet first");
return BTSTACK_ACL_BUFFERS_FULL;
}
if (!hci_can_send_prepared_acl_packet_now(con_handle)){
log_info("l2cap_send_prepared_connectionless handle 0x%02x, cid 0x%02x, cannot send", con_handle, cid);
return BTSTACK_ACL_BUFFERS_FULL;
}
log_debug("l2cap_send_prepared_connectionless handle %u, cid 0x%02x", con_handle, cid);
uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
l2cap_setup_header(acl_buffer, con_handle, cid, len);
// send
return hci_send_acl_packet_buffer(len+8);
}
int l2cap_send(uint16_t local_cid, uint8_t *data, uint16_t len){ int l2cap_send(uint16_t local_cid, uint8_t *data, uint16_t len){
l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
@ -512,21 +498,6 @@ int l2cap_send(uint16_t local_cid, uint8_t *data, uint16_t len){
return l2cap_send_prepared(local_cid, len); return l2cap_send_prepared(local_cid, len);
} }
int l2cap_send_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint8_t *data, uint16_t len){
if (!hci_can_send_acl_packet_now(con_handle)){
log_info("l2cap_send cid 0x%02x, cannot send", cid);
return BTSTACK_ACL_BUFFERS_FULL;
}
hci_reserve_packet_buffer();
uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
memcpy(&acl_buffer[8], data, len);
return l2cap_send_prepared_connectionless(con_handle, cid, len);
}
int l2cap_send_echo_request(hci_con_handle_t con_handle, uint8_t *data, uint16_t len){ int l2cap_send_echo_request(hci_con_handle_t con_handle, uint8_t *data, uint16_t len){
return l2cap_send_signaling_packet(con_handle, ECHO_REQUEST, 0x77, len, data); return l2cap_send_signaling_packet(con_handle, ECHO_REQUEST, 0x77, len, data);
} }
@ -538,8 +509,36 @@ static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNE
static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){ static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag); channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag);
} }
#endif
#ifdef ENABLE_BLE
static int l2cap_send_le_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
if (!hci_can_send_acl_packet_now(handle)){
log_info("l2cap_send_le_signaling_packet, cannot send");
return BTSTACK_ACL_BUFFERS_FULL;
}
// log_info("l2cap_send_le_signaling_packet type %u", cmd);
hci_reserve_packet_buffer();
uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
va_list argptr;
va_start(argptr, identifier);
uint16_t len = l2cap_create_signaling_le(acl_buffer, handle, cmd, identifier, argptr);
va_end(argptr);
// log_info("l2cap_send_le_signaling_packet con %u!", handle);
return hci_send_acl_packet_buffer(len);
}
#endif
uint16_t l2cap_max_mtu(void){
return HCI_ACL_PAYLOAD_SIZE - L2CAP_HEADER_SIZE;
}
uint16_t l2cap_max_le_mtu(void){
return l2cap_max_mtu();
}
// MARK: L2CAP_RUN // MARK: L2CAP_RUN
// process outstanding signaling tasks // process outstanding signaling tasks
@ -559,6 +558,9 @@ static void l2cap_run(void){
uint16_t result = signaling_responses[0].data; // CONNECTION_REQUEST, COMMAND_REJECT uint16_t result = signaling_responses[0].data; // CONNECTION_REQUEST, COMMAND_REJECT
uint8_t response_code = signaling_responses[0].code; uint8_t response_code = signaling_responses[0].code;
// avoid warnings
(void) infoType;
// remove first item before sending (to avoid sending response mutliple times) // remove first item before sending (to avoid sending response mutliple times)
signaling_responses_pending--; signaling_responses_pending--;
int i; int i;
@ -567,6 +569,7 @@ static void l2cap_run(void){
} }
switch (response_code){ switch (response_code){
#ifdef ENABLE_CLASSIC
case CONNECTION_REQUEST: case CONNECTION_REQUEST:
l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, 0, 0, result, 0); l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, 0, 0, result, 0);
// also disconnect if result is 0x0003 - security blocked // also disconnect if result is 0x0003 - security blocked
@ -606,6 +609,7 @@ static void l2cap_run(void){
case COMMAND_REJECT: case COMMAND_REJECT:
l2cap_send_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL); l2cap_send_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL);
break; break;
#endif
#ifdef ENABLE_BLE #ifdef ENABLE_BLE
case LE_CREDIT_BASED_CONNECTION_REQUEST: case LE_CREDIT_BASED_CONNECTION_REQUEST:
l2cap_send_le_signaling_packet(handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, sig_id, 0, 0, 0, 0, result); l2cap_send_le_signaling_packet(handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, sig_id, 0, 0, 0, 0, result);
@ -620,8 +624,11 @@ static void l2cap_run(void){
} }
} }
uint8_t config_options[4];
btstack_linked_list_iterator_t it; btstack_linked_list_iterator_t it;
(void) it;
#ifdef ENABLE_CLASSIC
uint8_t config_options[4];
btstack_linked_list_iterator_init(&it, &l2cap_channels); btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){ while (btstack_linked_list_iterator_has_next(&it)){
@ -729,8 +736,8 @@ static void l2cap_run(void){
break; break;
} }
} }
#endif
#ifdef ENABLE_BLE
#ifdef ENABLE_LE_DATA_CHANNELS #ifdef ENABLE_LE_DATA_CHANNELS
btstack_linked_list_iterator_init(&it, &l2cap_le_channels); btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
while (btstack_linked_list_iterator_has_next(&it)){ while (btstack_linked_list_iterator_has_next(&it)){
@ -833,7 +840,9 @@ static void l2cap_run(void){
break; break;
} }
} }
#endif
#ifdef ENABLE_BLE
// send l2cap con paramter update if necessary // send l2cap con paramter update if necessary
hci_connections_get_iterator(&it); hci_connections_get_iterator(&it);
while(btstack_linked_list_iterator_has_next(&it)){ while(btstack_linked_list_iterator_has_next(&it)){
@ -858,20 +867,12 @@ static void l2cap_run(void){
break; break;
} }
} }
#endif
#endif #endif
// log_info("l2cap_run: exit"); // log_info("l2cap_run: exit");
} }
uint16_t l2cap_max_mtu(void){ #ifdef ENABLE_CLASSIC
return HCI_ACL_PAYLOAD_SIZE - L2CAP_HEADER_SIZE;
}
uint16_t l2cap_max_le_mtu(void){
return l2cap_max_mtu();
}
static void l2cap_handle_connection_complete(hci_con_handle_t con_handle, l2cap_channel_t * channel){ static void l2cap_handle_connection_complete(hci_con_handle_t con_handle, l2cap_channel_t * channel){
if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) { if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
log_info("l2cap_handle_connection_complete expected state"); log_info("l2cap_handle_connection_complete expected state");
@ -896,7 +897,9 @@ static void l2cap_handle_remote_supported_features_received(l2cap_channel_t * ch
// fine, go ahead // fine, go ahead
channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST; channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
} }
#endif
#ifdef L2CAP_USES_CHANNELS
static l2cap_channel_t * l2cap_create_channel_entry(btstack_packet_handler_t packet_handler, bd_addr_t address, bd_addr_type_t address_type, static l2cap_channel_t * l2cap_create_channel_entry(btstack_packet_handler_t packet_handler, bd_addr_t address, bd_addr_type_t address_type,
uint16_t psm, uint16_t local_mtu, gap_security_level_t security_level){ uint16_t psm, uint16_t local_mtu, gap_security_level_t security_level){
@ -928,6 +931,9 @@ static l2cap_channel_t * l2cap_create_channel_entry(btstack_packet_handler_t pac
channel->local_sig_id = L2CAP_SIG_ID_INVALID; channel->local_sig_id = L2CAP_SIG_ID_INVALID;
return channel; return channel;
} }
#endif
#ifdef ENABLE_CLASSIC
/** /**
* @brief Creates L2CAP channel to the PSM of a remote device with baseband address. A new baseband connection will be initiated if necessary. * @brief Creates L2CAP channel to the PSM of a remote device with baseband address. A new baseband connection will be initiated if necessary.
@ -1021,8 +1027,11 @@ static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_
// process // process
l2cap_run(); l2cap_run();
} }
#endif
static void l2cap_notify_channel_can_send(void){ static void l2cap_notify_channel_can_send(void){
#ifdef ENABLE_CLASSIC
btstack_linked_list_iterator_t it; btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &l2cap_channels); btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){ while (btstack_linked_list_iterator_has_next(&it)){
@ -1032,7 +1041,7 @@ static void l2cap_notify_channel_can_send(void){
channel->waiting_for_can_send_now = 0; channel->waiting_for_can_send_now = 0;
l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid); l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid);
} }
#endif
int i; int i;
for (i=0;i<L2CAP_FIXED_CHANNEL_TABLE_SIZE;i++){ for (i=0;i<L2CAP_FIXED_CHANNEL_TABLE_SIZE;i++){
@ -1054,11 +1063,28 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
bd_addr_t address; bd_addr_t address;
hci_con_handle_t handle; hci_con_handle_t handle;
btstack_linked_list_iterator_t it;
int hci_con_used; int hci_con_used;
btstack_linked_list_iterator_t it;
// avoid unused warnings
(void) address;
(void) hci_con_used;
(void) it;
switch(hci_event_packet_get_type(packet)){ switch(hci_event_packet_get_type(packet)){
// Notify channel packet handler if they can send now
case HCI_EVENT_TRANSPORT_PACKET_SENT:
case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
l2cap_run(); // try sending signaling packets first
l2cap_notify_channel_can_send();
break;
case HCI_EVENT_COMMAND_STATUS:
l2cap_run(); // try sending signaling packets first
break;
#ifdef ENABLE_CLASSIC
// handle connection complete events // handle connection complete events
case HCI_EVENT_CONNECTION_COMPLETE: case HCI_EVENT_CONNECTION_COMPLETE:
reverse_bd_addr(&packet[5], address); reverse_bd_addr(&packet[5], address);
@ -1069,7 +1095,7 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
l2cap_handle_connection_failed_for_addr(address, packet[2]); l2cap_handle_connection_failed_for_addr(address, packet[2]);
} }
break; break;
// handle successful create connection cancel command // handle successful create connection cancel command
case HCI_EVENT_COMMAND_COMPLETE: case HCI_EVENT_COMMAND_COMPLETE:
if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_create_connection_cancel)) { if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_create_connection_cancel)) {
@ -1081,15 +1107,13 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
} }
l2cap_run(); // try sending signaling packets first l2cap_run(); // try sending signaling packets first
break; break;
#endif
case HCI_EVENT_COMMAND_STATUS:
l2cap_run(); // try sending signaling packets first
break;
// handle disconnection complete events // handle disconnection complete events
case HCI_EVENT_DISCONNECTION_COMPLETE: case HCI_EVENT_DISCONNECTION_COMPLETE:
// send l2cap disconnect events for all channels on this handle and free them // send l2cap disconnect events for all channels on this handle and free them
handle = little_endian_read_16(packet, 3); handle = little_endian_read_16(packet, 3);
#ifdef ENABLE_CLASSIC
btstack_linked_list_iterator_init(&it, &l2cap_channels); btstack_linked_list_iterator_init(&it, &l2cap_channels);
while (btstack_linked_list_iterator_has_next(&it)){ while (btstack_linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
@ -1099,6 +1123,7 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
btstack_linked_list_iterator_remove(&it); btstack_linked_list_iterator_remove(&it);
btstack_memory_l2cap_channel_free(channel); btstack_memory_l2cap_channel_free(channel);
} }
#endif
#ifdef ENABLE_LE_DATA_CHANNELS #ifdef ENABLE_LE_DATA_CHANNELS
btstack_linked_list_iterator_init(&it, &l2cap_le_channels); btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
while (btstack_linked_list_iterator_has_next(&it)){ while (btstack_linked_list_iterator_has_next(&it)){
@ -1111,14 +1136,8 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
#endif #endif
break; break;
// Notify channel packet handler if they can send now
case HCI_EVENT_TRANSPORT_PACKET_SENT:
case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
l2cap_run(); // try sending signaling packets first
l2cap_notify_channel_can_send();
break;
// HCI Connection Timeouts // HCI Connection Timeouts
#ifdef ENABLE_CLASSIC
case L2CAP_EVENT_TIMEOUT_CHECK: case L2CAP_EVENT_TIMEOUT_CHECK:
handle = little_endian_read_16(packet, 2); handle = little_endian_read_16(packet, 2);
if (gap_get_connection_type(handle) != GAP_CONNECTION_ACL) break; if (gap_get_connection_type(handle) != GAP_CONNECTION_ACL) break;
@ -1185,6 +1204,7 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
} }
} }
break; break;
#endif
default: default:
break; break;
@ -1193,12 +1213,6 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
l2cap_run(); l2cap_run();
} }
static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){
channel->remote_sig_id = identifier;
channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
l2cap_run();
}
static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){ static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){
// Vol 3, Part A, 4.3: "The DCID and SCID fields shall be ignored when the result field indi- cates the connection was refused." // Vol 3, Part A, 4.3: "The DCID and SCID fields shall be ignored when the result field indi- cates the connection was refused."
if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) { if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) {
@ -1211,6 +1225,13 @@ static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t c
} }
} }
#ifdef ENABLE_CLASSIC
static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){
channel->remote_sig_id = identifier;
channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
l2cap_run();
}
static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){ static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){
// log_info("l2cap_handle_connection_request for handle %u, psm %u cid 0x%02x", handle, psm, source_cid); // log_info("l2cap_handle_connection_request for handle %u, psm %u cid 0x%02x", handle, psm, source_cid);
@ -1521,8 +1542,21 @@ static void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t *
} }
} }
} }
#endif
#ifdef ENABLE_BLE #ifdef ENABLE_BLE
static void l2cap_emit_connection_parameter_update_response(hci_con_handle_t con_handle, uint16_t result){
uint8_t event[6];
event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE;
event[1] = 4;
little_endian_store_16(event, 2, con_handle);
little_endian_store_16(event, 4, result);
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
if (!l2cap_event_packet_handler) return;
(*l2cap_event_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
// @returns valid // @returns valid
static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t * command, uint8_t sig_id){ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t * command, uint8_t sig_id){
hci_connection_t * connection; hci_connection_t * connection;
@ -1799,12 +1833,16 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ){ static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ){
l2cap_channel_t * l2cap_channel;
(void) l2cap_channel;
// Get Channel ID // Get Channel ID
uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet); hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet);
switch (channel_id) { switch (channel_id) {
#ifdef ENABLE_CLASSIC
case L2CAP_CID_SIGNALING: { case L2CAP_CID_SIGNALING: {
uint16_t command_offset = 8; uint16_t command_offset = 8;
while (command_offset < size) { while (command_offset < size) {
@ -1816,7 +1854,8 @@ static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa
} }
break; break;
} }
#endif
#ifdef ENABLE_BLE #ifdef ENABLE_BLE
case L2CAP_CID_SIGNALING_LE: { case L2CAP_CID_SIGNALING_LE: {
uint16_t sig_id = packet[COMPLETE_L2CAP_HEADER + 1]; uint16_t sig_id = packet[COMPLETE_L2CAP_HEADER + 1];
@ -1846,14 +1885,14 @@ static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa
} }
break; break;
default: { default:
#ifdef ENABLE_CLASSIC
// Find channel for this channel_id and connection handle // Find channel for this channel_id and connection handle
l2cap_channel_t * l2cap_channel;
l2cap_channel = l2cap_get_channel_for_local_cid(channel_id); l2cap_channel = l2cap_get_channel_for_local_cid(channel_id);
if (l2cap_channel) { if (l2cap_channel) {
l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
} }
#endif
#ifdef ENABLE_LE_DATA_CHANNELS #ifdef ENABLE_LE_DATA_CHANNELS
l2cap_channel = l2cap_le_get_channel_for_local_cid(channel_id); l2cap_channel = l2cap_le_get_channel_for_local_cid(channel_id);
if (l2cap_channel) { if (l2cap_channel) {
@ -1891,12 +1930,19 @@ static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa
} }
#endif #endif
break; break;
}
} }
l2cap_run(); l2cap_run();
} }
// 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;
}
#ifdef ENABLE_CLASSIC
// finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
void l2cap_finialize_channel_close(l2cap_channel_t * channel){ void l2cap_finialize_channel_close(l2cap_channel_t * channel){
channel->state = L2CAP_STATE_CLOSED; channel->state = L2CAP_STATE_CLOSED;
@ -1972,15 +2018,8 @@ uint8_t l2cap_unregister_service(uint16_t psm){
} }
return 0; return 0;
} }
#endif
// 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;
}
#ifdef ENABLE_BLE
#ifdef ENABLE_LE_DATA_CHANNELS #ifdef ENABLE_LE_DATA_CHANNELS
@ -2306,5 +2345,3 @@ uint8_t l2cap_le_disconnect(uint16_t local_cid)
} }
#endif #endif
#endif