From 03ce1a58eabf8f534112c5766c2c1628b35a98aa Mon Sep 17 00:00:00 2001 From: "mila@ringwald.ch" Date: Fri, 22 Aug 2014 13:46:37 +0000 Subject: [PATCH] l2cap and rfcomm close connection functionality was moved to deamon --- src/daemon.c | 163 +++++++++++++++++++++++++++++++++++++++++---------- src/l2cap.c | 26 -------- src/l2cap.h | 2 - src/rfcomm.c | 28 --------- src/rfcomm.h | 1 - 5 files changed, 133 insertions(+), 87 deletions(-) diff --git a/src/daemon.c b/src/daemon.c index c01372734..9c4ce8545 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -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 diff --git a/src/l2cap.c b/src/l2cap.c index 15cc8eb12..195ac6577 100644 --- a/src/l2cap.c +++ b/src/l2cap.c @@ -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) { diff --git a/src/l2cap.h b/src/l2cap.h index 7be3c20a2..cd34d5445 100644 --- a/src/l2cap.h +++ b/src/l2cap.h @@ -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 diff --git a/src/rfcomm.c b/src/rfcomm.c index 7a5313b49..d01243014 100644 --- a/src/rfcomm.c +++ b/src/rfcomm.c @@ -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(); -} - diff --git a/src/rfcomm.h b/src/rfcomm.h index 62c29c9f1..ca5afe6a2 100644 --- a/src/rfcomm.h +++ b/src/rfcomm.h @@ -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 **/