l2cap: emit L2CAP_EVENT_CHANNEL_CAN_SEND_NOW after open or failed l2cap_can_send_now(..) request

This commit is contained in:
Matthias Ringwald 2016-02-05 17:37:51 +01:00
parent b072ba3345
commit 33c40538a6
2 changed files with 77 additions and 42 deletions

View File

@ -66,34 +66,35 @@
#define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2
#define L2CAP_SIGNALING_COMMAND_DATA_OFFSET 4
static void null_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
// 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(l2cap_channel_t *channel);
static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
static void l2cap_emit_connection_request(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_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t size );
// 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 uint8_t require_security_level2_for_outgoing_sdp;
static btstack_packet_callback_registration_t hci_event_callback_registration;
static btstack_linked_list_t l2cap_channels;
static btstack_linked_list_t l2cap_services;
static btstack_linked_list_t l2cap_le_channels;
static btstack_linked_list_t l2cap_le_services;
static void (*packet_handler) (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) = null_packet_handler;
static btstack_packet_handler_t attribute_protocol_packet_handler;
static btstack_packet_handler_t security_protocol_packet_handler;
static btstack_packet_handler_t connectionless_channel_packet_handler;
static uint8_t require_security_level2_for_outgoing_sdp;
// 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_channel_closed(l2cap_channel_t *channel);
static void l2cap_emit_connection_request(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_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t size );
static btstack_packet_handler_t l2cap_event_packet_handler;
void l2cap_init(void){
@ -104,7 +105,7 @@ void l2cap_init(void){
l2cap_le_services = NULL;
l2cap_le_channels = NULL;
packet_handler = null_packet_handler;
l2cap_event_packet_handler = NULL;
attribute_protocol_packet_handler = NULL;
security_protocol_packet_handler = NULL;
connectionless_channel_packet_handler = NULL;
@ -122,12 +123,8 @@ void l2cap_init(void){
hci_connectable_control(0); // no services yet
}
/** Register L2CAP packet handlers */
static void null_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
}
void l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
packet_handler = handler;
l2cap_event_packet_handler = handler;
}
static void l2cap_dispatch_to_channel(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){
@ -152,6 +149,14 @@ void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
little_endian_store_16(event, 21, channel->flush_timeout);
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
// if channel opened successfully, also send can send now if possible
if (status) return;
if (hci_can_send_acl_packet_now(channel->handle)){
l2cap_emit_can_send_now(channel);
} else {
channel->waiting_for_can_send_now = 1;
}
}
void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
@ -179,6 +184,16 @@ void l2cap_emit_connection_request(l2cap_channel_t *channel) {
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
}
static void l2cap_emit_can_send_now(l2cap_channel_t *channel) {
log_info("L2CAP_EVENT_CHANNEL_CAN_SEND_NOW local_cid 0x%x", channel->local_cid);
uint8_t event[4];
event[0] = L2CAP_EVENT_CAN_SEND_NOW;
event[1] = sizeof(event) - 2;
little_endian_store_16(event, 2, channel->local_cid);
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
}
static void l2cap_emit_connection_parameter_update_response(uint16_t handle, uint16_t result){
uint8_t event[6];
event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE;
@ -186,7 +201,8 @@ static void l2cap_emit_connection_parameter_update_response(uint16_t handle, uin
little_endian_store_16(event, 2, handle);
little_endian_store_16(event, 4, result);
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
(*packet_handler)(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){
@ -204,13 +220,21 @@ static l2cap_channel_t * l2cap_get_channel_for_local_cid(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);
if (!channel) return 0;
return hci_can_send_acl_packet_now(channel->handle);
int can_send = hci_can_send_acl_packet_now(channel->handle);
if (!can_send){
channel->waiting_for_can_send_now = 1;
}
return can_send;
}
int l2cap_can_send_prepared_packet_now(uint16_t local_cid){
l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
if (!channel) return 0;
return hci_can_send_prepared_acl_packet_now(channel->handle);
int can_send = hci_can_send_prepared_acl_packet_now(channel->handle);
if (!can_send){
channel->waiting_for_can_send_now = 1;
}
return can_send;
}
int l2cap_can_send_fixed_channel_packet_now(uint16_t handle){
@ -819,6 +843,18 @@ static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_
l2cap_run();
}
static void l2cap_notify_channel_can_send(void){
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->waiting_for_can_send_now) continue;
if (!hci_can_send_acl_packet_now(channel->handle)) continue;
channel->waiting_for_can_send_now = 0;
l2cap_emit_can_send_now(channel);
}
}
static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *packet, uint16_t size){
bd_addr_t address;
@ -870,10 +906,13 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
}
break;
// Notify channel packet handler if they can send now
case DAEMON_EVENT_HCI_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
case L2CAP_EVENT_TIMEOUT_CHECK:
handle = little_endian_read_16(packet, 2);
@ -892,17 +931,6 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection
break;
case DAEMON_EVENT_HCI_PACKET_SENT:
l2cap_run(); // try sending signaling packets first
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->packet_handler) continue;
(* (channel->packet_handler))(HCI_EVENT_PACKET, channel->local_cid, packet, size);
}
break;
case HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE:
handle = little_endian_read_16(packet, 3);
btstack_linked_list_iterator_init(&it, &l2cap_channels);
@ -1388,8 +1416,8 @@ static void l2cap_acl_handler(uint8_t packet_type, uint8_t *packet, uint16_t siz
}
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
(*packet_handler)( HCI_EVENT_PACKET, 0, event, sizeof(event));
if (!l2cap_event_packet_handler) break;
(*l2cap_event_packet_handler)( HCI_EVENT_PACKET, 0, event, sizeof(event));
break;
}
default: {

View File

@ -102,9 +102,16 @@ typedef struct {
// linked list - assert: first field
btstack_linked_item_t item;
// packet handler
btstack_packet_handler_t packet_handler;
// timer
btstack_timer_source_t rtx; // also used for ertx
L2CAP_STATE state;
L2CAP_CHANNEL_STATE_VAR state_var;
// info
bd_addr_t address;
hci_con_handle_t handle;
@ -124,11 +131,7 @@ typedef struct {
gap_security_level_t required_security_level;
uint8_t reason; // used in decline internal
btstack_timer_source_t rtx; // also used for ertx
// internal connection
btstack_packet_handler_t packet_handler;
uint8_t waiting_for_can_send_now;
} l2cap_channel_t;
@ -244,6 +247,10 @@ void l2cap_decline_connection(uint16_t local_cid, uint8_t reason);
* @brief Check if outgoing buffer is available and that there's space on the Bluetooth module
*/
int l2cap_can_send_packet_now(uint16_t local_cid);
/**
* @brief Check if there's space on the Bluetooth module
*/
int l2cap_can_send_prepared_packet_now(uint16_t local_cid);
/**