l2cap and rfcomm close connection functionality was moved to deamon

This commit is contained in:
mila@ringwald.ch 2014-08-22 13:46:37 +00:00
parent 5d227f2503
commit 03ce1a58ea
5 changed files with 133 additions and 87 deletions

View File

@ -108,6 +108,8 @@ typedef struct {
connection_t * connection;
linked_list_t rfcomm_cids;
linked_list_t rfcomm_services;
linked_list_t l2cap_cids;
linked_list_t l2cap_psms;
// power mode
HCI_POWER_MODE power_mode;
@ -117,6 +119,15 @@ typedef struct {
} client_state_t;
typedef struct linked_list_uint16 {
linked_item_t item;
uint16_t value;
} linked_list_uint16_t;
typedef struct gatt_client_helper {
uint16_t characteristic_length;
} gatt_client_helper_t;
// MARK: prototypes
static void handle_sdp_rfcomm_service_result(sdp_query_event_t * event, void * context);
static void handle_sdp_client_query_result(sdp_query_event_t * event);
@ -127,6 +138,8 @@ static int clients_require_discoverable(void);
static void clients_clear_power_request(void);
static void start_power_off_timer(void);
static void stop_power_off_timer(void);
static client_state_t * client_for_connection(connection_t *connection);
// MARK: globals
static hci_transport_t * transport;
@ -172,28 +185,129 @@ static void daemon_no_connections_timeout(struct timer *ts){
// ATT_MTU - 1
#define ATT_MAX_ATTRIBUTE_SIZE 22
static void daemon_add_client_rfcomm_service(connection_t * conn, uint16_t service_channel){
}
static void daemon_remove_client_rfcomm_service(connection_t * conn, uint16_t service_channel){
}
static void daemon_add_client_rfcomm_channel(connection_t * conn, uint16_t cid){
}
static void daemon_remove_client_rfcomm_channel(connection_t * conn, uint16_t cid){
static void add_uint16_to_list(linked_list_t *list, uint16_t value){
linked_list_uint16_t * item = malloc(sizeof(linked_list_uint16_t));
if (!item) return;
item->value = value;
linked_list_add(list, (linked_item_t *) item);
}
static void daemon_add_client_l2cap_service(connection_t * conn, uint16_t psm){
}
static void daemon_remove_client_l2cap_service(connection_t * conn, uint16_t psm){
}
static void daemon_add_client_l2cap_channel(connection_t * conn, uint16_t cid){
}
static void daemon_remove_client_l2cap_channel(connection_t * conn, uint16_t cid){
static void remove_and_free_uint16_from_list(linked_list_t *list, uint16_t value){
linked_list_iterator_t it;
linked_list_iterator_init(&it, list);
while (linked_list_iterator_has_next(&it)){
linked_list_uint16_t * item = (linked_list_uint16_t*) linked_list_iterator_next(&it);
if ( item->value != value) continue;
linked_list_remove(list, (linked_item_t *) item);
free(item);
}
}
static void daemon_add_client_rfcomm_service(connection_t * connection, uint16_t service_channel){
client_state_t * client_state = client_for_connection(connection);
if (!client_state) return;
add_uint16_to_list(&client_state->rfcomm_services, service_channel);
}
typedef struct gatt_client_helper {
uint16_t characteristic_length;
} gatt_client_helper_t;
static void daemon_remove_client_rfcomm_service(connection_t * connection, uint16_t service_channel){
client_state_t * client_state = client_for_connection(connection);
if (!client_state) return;
remove_and_free_uint16_from_list(&client_state->rfcomm_services, service_channel);
}
static void daemon_add_client_rfcomm_channel(connection_t * connection, uint16_t cid){
client_state_t * client_state = client_for_connection(connection);
if (!client_state) return;
add_uint16_to_list(&client_state->rfcomm_cids, cid);
}
static void daemon_remove_client_rfcomm_channel(connection_t * connection, uint16_t cid){
client_state_t * client_state = client_for_connection(connection);
if (!client_state) return;
remove_and_free_uint16_from_list(&client_state->rfcomm_cids, cid);
}
static void daemon_add_client_l2cap_service(connection_t * connection, uint16_t psm){
client_state_t * client_state = client_for_connection(connection);
if (!client_state) return;
add_uint16_to_list(&client_state->l2cap_psms, psm);
}
static void daemon_remove_client_l2cap_service(connection_t * connection, uint16_t psm){
client_state_t * client_state = client_for_connection(connection);
if (!client_state) return;
remove_and_free_uint16_from_list(&client_state->l2cap_psms, psm);
}
static void daemon_add_client_l2cap_channel(connection_t * connection, uint16_t cid){
client_state_t * client_state = client_for_connection(connection);
if (!client_state) return;
add_uint16_to_list(&client_state->l2cap_cids, cid);
}
static void daemon_remove_client_l2cap_channel(connection_t * connection, uint16_t cid){
client_state_t * client_state = client_for_connection(connection);
if (!client_state) return;
remove_and_free_uint16_from_list(&client_state->l2cap_cids, cid);
}
static void daemon_rfcomm_close_connection(linked_list_t *rfcomm_services, linked_list_t *rfcomm_cids){
linked_list_iterator_t it;
linked_list_iterator_init(&it, rfcomm_services);
while (linked_list_iterator_has_next(&it)){
linked_list_uint16_t * item = (linked_list_uint16_t*) linked_list_iterator_next(&it);
rfcomm_unregister_service_internal(item->value);
linked_list_remove(rfcomm_services, (linked_item_t *) item);
free(item);
}
linked_list_iterator_init(&it, rfcomm_cids);
while (linked_list_iterator_has_next(&it)){
linked_list_uint16_t * item = (linked_list_uint16_t*) linked_list_iterator_next(&it);
rfcomm_disconnect_internal(item->value);
linked_list_remove(rfcomm_cids, (linked_item_t *) item);
free(item);
}
}
static void daemon_l2cap_close_connection(linked_list_t *l2cap_psms, linked_list_t *l2cap_cids){
linked_list_iterator_t it;
linked_list_iterator_init(&it, l2cap_psms);
while (linked_list_iterator_has_next(&it)){
linked_list_uint16_t * item = (linked_list_uint16_t*) linked_list_iterator_next(&it);
l2cap_unregister_service_internal(NULL, item->value);
linked_list_remove(l2cap_psms, (linked_item_t *) item);
free(item);
}
linked_list_iterator_init(&it, l2cap_cids);
while (linked_list_iterator_has_next(&it)){
linked_list_uint16_t * item = (linked_list_uint16_t*) linked_list_iterator_next(&it);
l2cap_disconnect_internal(item->value, 0); // note: reason isn't used
linked_list_remove(l2cap_cids, (linked_item_t *) item);
free(item);
}
}
static void daemon_disconnect_client(connection_t * connection){
log_info("Daemon disconnect client %p\n",connection);
client_state_t * client = client_for_connection(connection);
if (!client) return;
sdp_unregister_services_for_connection(connection);
daemon_rfcomm_close_connection(&client->rfcomm_services, &client->rfcomm_cids);
daemon_l2cap_close_connection(&client->l2cap_psms, &client->l2cap_cids);
#ifdef HAVE_BLE
// NOTE: experimental - disconnect all LE connections where GATT Client was used
gatt_client_disconnect_connection(connection);
#endif
linked_list_remove(&clients, (linked_item_t *) client);
free(client);
}
static gatt_client_t * daemon_provide_gatt_client_context_for_handle(uint16_t handle){
gatt_client_t *context;
@ -496,7 +610,7 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
break;
case RFCOMM_UNREGISTER_SERVICE:
service_channel = READ_BT_16(packet, 3);
daemon_remove_client_rfcomm_service(service_channel);
daemon_remove_client_rfcomm_service(connection, service_channel);
rfcomm_unregister_service_internal(service_channel);
break;
case RFCOMM_ACCEPT_CONNECTION:
@ -770,24 +884,13 @@ static int daemon_client_handler(connection_t *connection, uint16_t packet_type,
break;
case DAEMON_EVENT_CONNECTION_CLOSED:
log_info("DAEMON_EVENT_CONNECTION_CLOSED %p\n",connection);
sdp_unregister_services_for_connection(connection);
rfcomm_close_connection(connection);
l2cap_close_connection(connection);
#ifdef HAVE_BLE
// NOTE: experimental - disconnect all LE connections where GATT Client was used
gatt_client_disconnect_connection(connection);
#endif
daemon_disconnect_client(connection);
sdp_query_rfcomm_deregister_callback();
// no clients -> no HCI connections
if (!clients){
hci_disconnect_all();
}
client = client_for_connection(connection);
if (!client) break;
linked_list_remove(&clients, (linked_item_t *) client);
free(client);
// update discoverable mode
hci_discoverable_control(clients_require_discoverable());
// start power off, if last active client

View File

@ -1486,32 +1486,6 @@ void l2cap_unregister_service_internal(void *connection, uint16_t psm){
hci_connectable_control(0);
}
//
void l2cap_close_connection(void *connection){
linked_list_iterator_t it;
// close open channels
linked_list_iterator_init(&it, &l2cap_channels);
while (linked_list_iterator_has_next(&it)){
l2cap_channel_t * channel = (l2cap_channel_t *) linked_list_iterator_next(&it);
if (channel->connection != connection) continue;
channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
channel->connection = NULL;
}
// unregister services
linked_list_iterator_init(&it, &l2cap_services);
while (linked_list_iterator_has_next(&it)){
l2cap_service_t * service = (l2cap_service_t *) linked_list_iterator_next(&it);
if (service->connection != connection) continue;
linked_list_iterator_remove(&it);
btstack_memory_l2cap_service_free(service);
}
// process
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 packet_handler, uint16_t channel_id) {

View File

@ -225,8 +225,6 @@ uint16_t l2cap_max_le_mtu(void);
int l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len);
void l2cap_close_connection(void *connection);
int l2cap_send_echo_request(uint16_t handle, uint8_t *data, uint16_t len);
void l2cap_require_security_level_2_for_outgoing_sdp(); // testing

View File

@ -2257,34 +2257,6 @@ void rfcomm_grant_credits(uint16_t rfcomm_cid, uint8_t credits){
rfcomm_run();
}
//
void rfcomm_close_connection(void *connection){
linked_item_t *it;
// close open channels
for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
rfcomm_channel_t * channel = (rfcomm_channel_t *)it;
if (channel->connection != connection) continue;
channel->state = RFCOMM_CHANNEL_SEND_DISC;
channel->connection = NULL;
}
// unregister services
it = (linked_item_t *) &rfcomm_services;
while (it->next) {
rfcomm_service_t * service = (rfcomm_service_t *) it->next;
if (service->connection == connection){
it->next = it->next->next;
btstack_memory_rfcomm_service_free(service);
} else {
it = it->next;
}
}
// process
rfcomm_run();
}

View File

@ -363,7 +363,6 @@ typedef struct {
} rfcomm_channel_t;
void rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
void rfcomm_close_connection(void *connection);
/** Embedded API **/