13deb3ec6SMatthias Ringwald /* 23deb3ec6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 33deb3ec6SMatthias Ringwald * 43deb3ec6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 53deb3ec6SMatthias Ringwald * modification, are permitted provided that the following conditions 63deb3ec6SMatthias Ringwald * are met: 73deb3ec6SMatthias Ringwald * 83deb3ec6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 93deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 103deb3ec6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 113deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 123deb3ec6SMatthias Ringwald * documentation and/or other materials provided with the distribution. 133deb3ec6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 143deb3ec6SMatthias Ringwald * contributors may be used to endorse or promote products derived 153deb3ec6SMatthias Ringwald * from this software without specific prior written permission. 163deb3ec6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 173deb3ec6SMatthias Ringwald * personal benefit and not for any commercial purpose or for 183deb3ec6SMatthias Ringwald * monetary gain. 193deb3ec6SMatthias Ringwald * 203deb3ec6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 213deb3ec6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 223deb3ec6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 253deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 263deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 273deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 283deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 293deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 303deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313deb3ec6SMatthias Ringwald * SUCH DAMAGE. 323deb3ec6SMatthias Ringwald * 333deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at 343deb3ec6SMatthias Ringwald * [email protected] 353deb3ec6SMatthias Ringwald * 363deb3ec6SMatthias Ringwald */ 373deb3ec6SMatthias Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "gatt_client.c" 39ab2c6ae4SMatthias Ringwald 403deb3ec6SMatthias Ringwald #include <stdint.h> 413deb3ec6SMatthias Ringwald #include <string.h> 42a95ca902SMatthias Ringwald #include <stddef.h> 433deb3ec6SMatthias Ringwald 447907f069SMatthias Ringwald #include "btstack_config.h" 453deb3ec6SMatthias Ringwald 46296289e3SMatthias Ringwald #include "ble/att_dispatch.h" 470e2df43fSMatthias Ringwald #include "ble/att_db.h" 480e2df43fSMatthias Ringwald #include "ble/gatt_client.h" 490e2df43fSMatthias Ringwald #include "ble/le_device_db.h" 500e2df43fSMatthias Ringwald #include "ble/sm.h" 51c40517c3SMatthias Ringwald #include "bluetooth_psm.h" 5216ece135SMatthias Ringwald #include "btstack_debug.h" 530e2df43fSMatthias Ringwald #include "btstack_event.h" 543deb3ec6SMatthias Ringwald #include "btstack_memory.h" 550e2df43fSMatthias Ringwald #include "btstack_run_loop.h" 560e2df43fSMatthias Ringwald #include "btstack_util.h" 573deb3ec6SMatthias Ringwald #include "hci.h" 583deb3ec6SMatthias Ringwald #include "hci_dump.h" 5958e8c9f5SMatthias Ringwald #include "hci_event_builder.h" 603deb3ec6SMatthias Ringwald #include "l2cap.h" 611450cdc6SMatthias Ringwald #include "classic/sdp_client.h" 621450cdc6SMatthias Ringwald #include "bluetooth_gatt.h" 631450cdc6SMatthias Ringwald #include "bluetooth_sdp.h" 641450cdc6SMatthias Ringwald #include "classic/sdp_util.h" 653deb3ec6SMatthias Ringwald 664797b71aSMatthias Ringwald #if defined(ENABLE_GATT_OVER_EATT) && !defined(ENABLE_L2CAP_ENHANCED_CREDIT_BASED_FLOW_CONTROL_MODE) 674797b71aSMatthias Ringwald #error "GATT Over EATT requires support for L2CAP Enhanced CoC. Please enable ENABLE_L2CAP_ENHANCED_CREDIT_BASED_FLOW_CONTROL_MODE" 684797b71aSMatthias Ringwald #endif 694797b71aSMatthias Ringwald 70b1da4983SMatthias Ringwald // L2CAP Test Spec p35 defines a minimum of 100 ms, but PTS might indicate an error if we sent after 100 ms 71b1da4983SMatthias Ringwald #define GATT_CLIENT_COLLISION_BACKOFF_MS 150 72b1da4983SMatthias Ringwald 739c662c9bSMatthias Ringwald static btstack_linked_list_t gatt_client_connections; 749c662c9bSMatthias Ringwald static btstack_linked_list_t gatt_client_value_listeners; 751a4874dcSMatthias Ringwald static btstack_linked_list_t gatt_client_service_value_listeners; 76842492f0SMatthias Ringwald #ifdef ENABLE_GATT_CLIENT_SERVICE_CHANGED 7758e8c9f5SMatthias Ringwald static btstack_linked_list_t gatt_client_service_changed_handler; 78842492f0SMatthias Ringwald #endif 79361b1363SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 80f4b33574SMatthias Ringwald static btstack_packet_callback_registration_t sm_event_callback_registration; 81544a5845SMatthias Ringwald static btstack_context_callback_registration_t gatt_client_deferred_event_emit; 82f4b33574SMatthias Ringwald 8311279da7SMatthias Ringwald // GATT Client Configuration 8411279da7SMatthias Ringwald static bool gatt_client_mtu_exchange_enabled; 8511279da7SMatthias Ringwald static gap_security_level_t gatt_client_required_security_level; 865cf6c434SJakob Krantz 873deb3ec6SMatthias Ringwald static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size); 88f4b33574SMatthias Ringwald static void gatt_client_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 895cf1669fSMatthias Ringwald static void gatt_client_report_error_if_pending(gatt_client_t *gatt_client, uint8_t att_error_code); 907a766ebfSMatthias Ringwald 917a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE 923deb3ec6SMatthias Ringwald static void att_signed_write_handle_cmac_result(uint8_t hash[8]); 937a766ebfSMatthias Ringwald #endif 943deb3ec6SMatthias Ringwald 9559b5e157SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC 9659b5e157SMatthias Ringwald static gatt_client_t * gatt_client_get_context_for_l2cap_cid(uint16_t l2cap_cid); 9759b5e157SMatthias Ringwald static void gatt_client_classic_handle_connected(gatt_client_t * gatt_client, uint8_t status); 9859b5e157SMatthias Ringwald static void gatt_client_classic_handle_disconnected(gatt_client_t * gatt_client); 99180cbe79SMatthias Ringwald static void gatt_client_classic_retry(btstack_timer_source_t * ts); 10059b5e157SMatthias Ringwald #endif 10159b5e157SMatthias Ringwald 10226166ecfSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 1037627a0deSMatthias Ringwald static bool gatt_client_le_enhanced_handle_can_send_query(gatt_client_t * gatt_client); 1046d0f6f49SMatthias Ringwald static void gatt_client_le_enhanced_retry(btstack_timer_source_t * ts); 10526166ecfSMatthias Ringwald #endif 10626166ecfSMatthias Ringwald 1073deb3ec6SMatthias Ringwald void gatt_client_init(void){ 1083deb3ec6SMatthias Ringwald gatt_client_connections = NULL; 1091a4874dcSMatthias Ringwald gatt_client_value_listeners = NULL; 1101a4874dcSMatthias Ringwald gatt_client_service_value_listeners = NULL; 111842492f0SMatthias Ringwald #ifdef ENABLE_GATT_CLIENT_SERVICE_CHANGED 11258e8c9f5SMatthias Ringwald gatt_client_service_changed_handler = NULL; 113842492f0SMatthias Ringwald #endif 11411279da7SMatthias Ringwald // default configuration 11511279da7SMatthias Ringwald gatt_client_mtu_exchange_enabled = true; 11611279da7SMatthias Ringwald gatt_client_required_security_level = LEVEL_0; 11711279da7SMatthias Ringwald 11811279da7SMatthias Ringwald // register for HCI Events 119f4b33574SMatthias Ringwald hci_event_callback_registration.callback = &gatt_client_event_packet_handler; 120361b1363SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 121361b1363SMatthias Ringwald 122f4b33574SMatthias Ringwald // register for SM Events 123f4b33574SMatthias Ringwald sm_event_callback_registration.callback = &gatt_client_event_packet_handler; 124f4b33574SMatthias Ringwald sm_add_event_handler(&sm_event_callback_registration); 125f4b33574SMatthias Ringwald 126361b1363SMatthias Ringwald // and ATT Client PDUs 1273deb3ec6SMatthias Ringwald att_dispatch_register_client(gatt_client_att_packet_handler); 1283deb3ec6SMatthias Ringwald } 1293deb3ec6SMatthias Ringwald 13011279da7SMatthias Ringwald void gatt_client_set_required_security_level(gap_security_level_t level){ 13111279da7SMatthias Ringwald gatt_client_required_security_level = level; 13211279da7SMatthias Ringwald } 13311279da7SMatthias Ringwald 134ec820d77SMatthias Ringwald static gatt_client_t * gatt_client_for_timer(btstack_timer_source_t * ts){ 135665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 136665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client_connections); 137665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1385cf1669fSMatthias Ringwald gatt_client_t * gatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it); 1395cf1669fSMatthias Ringwald if (&gatt_client->gc_timeout == ts) { 1405cf1669fSMatthias Ringwald return gatt_client; 1413deb3ec6SMatthias Ringwald } 1423deb3ec6SMatthias Ringwald } 1433deb3ec6SMatthias Ringwald return NULL; 1443deb3ec6SMatthias Ringwald } 1453deb3ec6SMatthias Ringwald 146ec820d77SMatthias Ringwald static void gatt_client_timeout_handler(btstack_timer_source_t * timer){ 1475cf1669fSMatthias Ringwald gatt_client_t * gatt_client = gatt_client_for_timer(timer); 1485cf1669fSMatthias Ringwald if (gatt_client == NULL) return; 1495cf1669fSMatthias Ringwald log_info("GATT client timeout handle, handle 0x%02x", gatt_client->con_handle); 1505cf1669fSMatthias Ringwald gatt_client_report_error_if_pending(gatt_client, ATT_ERROR_TIMEOUT); 1513deb3ec6SMatthias Ringwald } 1523deb3ec6SMatthias Ringwald 1535cf1669fSMatthias Ringwald static void gatt_client_timeout_start(gatt_client_t * gatt_client){ 1548ac3a0b3SMatthias Ringwald log_debug("GATT client timeout start, handle 0x%02x", gatt_client->con_handle); 1555cf1669fSMatthias Ringwald btstack_run_loop_remove_timer(&gatt_client->gc_timeout); 1565cf1669fSMatthias Ringwald btstack_run_loop_set_timer_handler(&gatt_client->gc_timeout, gatt_client_timeout_handler); 1575cf1669fSMatthias Ringwald btstack_run_loop_set_timer(&gatt_client->gc_timeout, 30000); // 30 seconds sm timeout 1585cf1669fSMatthias Ringwald btstack_run_loop_add_timer(&gatt_client->gc_timeout); 1593deb3ec6SMatthias Ringwald } 1603deb3ec6SMatthias Ringwald 1615cf1669fSMatthias Ringwald static void gatt_client_timeout_stop(gatt_client_t * gatt_client){ 1628ac3a0b3SMatthias Ringwald log_debug("GATT client timeout stop, handle 0x%02x", gatt_client->con_handle); 1635cf1669fSMatthias Ringwald btstack_run_loop_remove_timer(&gatt_client->gc_timeout); 1643deb3ec6SMatthias Ringwald } 1653deb3ec6SMatthias Ringwald 1661dfae9c7SMatthias Ringwald static gap_security_level_t gatt_client_le_security_level_for_connection(hci_con_handle_t con_handle){ 1671dfae9c7SMatthias Ringwald uint8_t encryption_key_size = gap_encryption_key_size(con_handle); 1681dfae9c7SMatthias Ringwald if (encryption_key_size == 0) return LEVEL_0; 1691dfae9c7SMatthias Ringwald 170ff3f1026SMatthias Ringwald bool authenticated = gap_authenticated(con_handle); 1711dfae9c7SMatthias Ringwald if (!authenticated) return LEVEL_2; 1721dfae9c7SMatthias Ringwald 1731dfae9c7SMatthias Ringwald return encryption_key_size == 16 ? LEVEL_4 : LEVEL_3; 1741dfae9c7SMatthias Ringwald } 1751dfae9c7SMatthias Ringwald 1765cf1669fSMatthias Ringwald static gatt_client_t * gatt_client_get_context_for_handle(uint16_t handle){ 177665d90f2SMatthias Ringwald btstack_linked_item_t *it; 178a0da043fSMatthias Ringwald for (it = (btstack_linked_item_t *) gatt_client_connections; it != NULL; it = it->next){ 1795cf1669fSMatthias Ringwald gatt_client_t * gatt_client = (gatt_client_t *) it; 1805cf1669fSMatthias Ringwald if (gatt_client->con_handle == handle){ 1815cf1669fSMatthias Ringwald return gatt_client; 1823deb3ec6SMatthias Ringwald } 1833deb3ec6SMatthias Ringwald } 1843deb3ec6SMatthias Ringwald return NULL; 1853deb3ec6SMatthias Ringwald } 1863deb3ec6SMatthias Ringwald 1873deb3ec6SMatthias Ringwald 1886b65794dSMilanka Ringwald // @return gatt_client context 1893deb3ec6SMatthias Ringwald // returns existing one, or tries to setup new one 19040faeb84SMilanka Ringwald static uint8_t gatt_client_provide_context_for_handle(hci_con_handle_t con_handle, gatt_client_t ** out_gatt_client){ 1915cf1669fSMatthias Ringwald gatt_client_t * gatt_client = gatt_client_get_context_for_handle(con_handle); 19240faeb84SMilanka Ringwald 19340faeb84SMilanka Ringwald if (gatt_client != NULL){ 19440faeb84SMilanka Ringwald *out_gatt_client = gatt_client; 19540faeb84SMilanka Ringwald return ERROR_CODE_SUCCESS; 19640faeb84SMilanka Ringwald } 1973deb3ec6SMatthias Ringwald 198ae1d1237SMatthias Ringwald // bail if no such hci connection 1990e0bba86SMatthias Ringwald hci_connection_t * hci_connection = hci_connection_for_handle(con_handle); 2000e0bba86SMatthias Ringwald if (hci_connection == NULL){ 201ae1d1237SMatthias Ringwald log_error("No connection for handle 0x%04x", con_handle); 20240faeb84SMilanka Ringwald *out_gatt_client = NULL; 20340faeb84SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 204ae1d1237SMatthias Ringwald } 20540faeb84SMilanka Ringwald 2065cf1669fSMatthias Ringwald gatt_client = btstack_memory_gatt_client_get(); 20740faeb84SMilanka Ringwald if (gatt_client == NULL){ 20840faeb84SMilanka Ringwald *out_gatt_client = NULL; 20940faeb84SMilanka Ringwald return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 21040faeb84SMilanka Ringwald } 2113deb3ec6SMatthias Ringwald // init state 212e9cdf30bSMatthias Ringwald gatt_client->bearer_type = ATT_BEARER_UNENHANCED_LE; 2135cf1669fSMatthias Ringwald gatt_client->con_handle = con_handle; 2145cf1669fSMatthias Ringwald gatt_client->mtu = ATT_DEFAULT_MTU; 2151dfae9c7SMatthias Ringwald gatt_client->security_level = gatt_client_le_security_level_for_connection(con_handle); 21611279da7SMatthias Ringwald if (gatt_client_mtu_exchange_enabled){ 2175cf1669fSMatthias Ringwald gatt_client->mtu_state = SEND_MTU_EXCHANGE; 2185cf6c434SJakob Krantz } else { 2195cf1669fSMatthias Ringwald gatt_client->mtu_state = MTU_AUTO_EXCHANGE_DISABLED; 2205cf6c434SJakob Krantz } 221052dc82aSMatthias Ringwald gatt_client->state = P_READY; 222d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DISCOVER_W2_SEND; 223cbd76cecSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 224cbd76cecSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_IDLE; 225cbd76cecSMatthias Ringwald #endif 2265cf1669fSMatthias Ringwald btstack_linked_list_add(&gatt_client_connections, (btstack_linked_item_t*)gatt_client); 2270e0bba86SMatthias Ringwald 2280e0bba86SMatthias Ringwald // get unenhanced att bearer state 2290e0bba86SMatthias Ringwald if (hci_connection->att_connection.mtu_exchanged){ 2300e0bba86SMatthias Ringwald gatt_client->mtu = hci_connection->att_connection.mtu; 2310e0bba86SMatthias Ringwald gatt_client->mtu_state = MTU_EXCHANGED; 2320e0bba86SMatthias Ringwald } 23340faeb84SMilanka Ringwald *out_gatt_client = gatt_client; 23440faeb84SMilanka Ringwald return ERROR_CODE_SUCCESS; 2353deb3ec6SMatthias Ringwald } 2363deb3ec6SMatthias Ringwald 237de27733dSMatthias Ringwald static bool is_ready(gatt_client_t * gatt_client){ 238052dc82aSMatthias Ringwald return gatt_client->state == P_READY; 239de27733dSMatthias Ringwald } 240de27733dSMatthias Ringwald 241de27733dSMatthias Ringwald static uint8_t gatt_client_provide_context_for_request(hci_con_handle_t con_handle, gatt_client_t ** out_gatt_client){ 242de27733dSMatthias Ringwald gatt_client_t * gatt_client = NULL; 243de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 24440faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 24540faeb84SMilanka Ringwald return status; 24640faeb84SMilanka Ringwald } 247de27733dSMatthias Ringwald 2487627a0deSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 2497627a0deSMatthias Ringwald if (gatt_client->eatt_state == GATT_CLIENT_EATT_READY){ 2507627a0deSMatthias Ringwald btstack_linked_list_iterator_t it; 2517627a0deSMatthias Ringwald gatt_client_t * eatt_client = NULL; 2527627a0deSMatthias Ringwald // find free eatt client 2537627a0deSMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client->eatt_clients); 2547627a0deSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2557627a0deSMatthias Ringwald gatt_client_t * client = (gatt_client_t *) btstack_linked_list_iterator_next(&it); 256052dc82aSMatthias Ringwald if (client->state == P_READY){ 2577627a0deSMatthias Ringwald eatt_client = client; 2587627a0deSMatthias Ringwald break; 2597627a0deSMatthias Ringwald } 2607627a0deSMatthias Ringwald } 2617627a0deSMatthias Ringwald if (eatt_client == NULL){ 2627627a0deSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2637627a0deSMatthias Ringwald } 2647627a0deSMatthias Ringwald gatt_client = eatt_client; 2657627a0deSMatthias Ringwald } 2667627a0deSMatthias Ringwald #endif 2677627a0deSMatthias Ringwald 268643a64fcSMatthias Ringwald if (is_ready(gatt_client) == false){ 269de27733dSMatthias Ringwald return GATT_CLIENT_IN_WRONG_STATE; 2703deb3ec6SMatthias Ringwald } 2713deb3ec6SMatthias Ringwald 272de27733dSMatthias Ringwald gatt_client_timeout_start(gatt_client); 273de27733dSMatthias Ringwald 274de27733dSMatthias Ringwald *out_gatt_client = gatt_client; 275de27733dSMatthias Ringwald 276de27733dSMatthias Ringwald return status; 2773deb3ec6SMatthias Ringwald } 2783deb3ec6SMatthias Ringwald 279fc64f94aSMatthias Ringwald int gatt_client_is_ready(hci_con_handle_t con_handle){ 28040faeb84SMilanka Ringwald gatt_client_t * gatt_client; 28140faeb84SMilanka Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 28240faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 28340faeb84SMilanka Ringwald return 0; 28440faeb84SMilanka Ringwald } 285aacf1b1aSMilanka Ringwald return is_ready(gatt_client) ? 1 : 0; 2863deb3ec6SMatthias Ringwald } 2873deb3ec6SMatthias Ringwald 2885cf6c434SJakob Krantz void gatt_client_mtu_enable_auto_negotiation(uint8_t enabled){ 28911279da7SMatthias Ringwald gatt_client_mtu_exchange_enabled = enabled != 0; 2905cf6c434SJakob Krantz } 2915cf6c434SJakob Krantz 292fc64f94aSMatthias Ringwald uint8_t gatt_client_get_mtu(hci_con_handle_t con_handle, uint16_t * mtu){ 29340faeb84SMilanka Ringwald gatt_client_t * gatt_client; 29440faeb84SMilanka Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 29540faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 2966201dbadSMatthias Ringwald *mtu = 0; 29740faeb84SMilanka Ringwald return status; 29840faeb84SMilanka Ringwald } 2997d2258b3SMilanka Ringwald 3005cf1669fSMatthias Ringwald if ((gatt_client->mtu_state == MTU_EXCHANGED) || (gatt_client->mtu_state == MTU_AUTO_EXCHANGE_DISABLED)){ 3015cf1669fSMatthias Ringwald *mtu = gatt_client->mtu; 3027d2258b3SMilanka Ringwald return ERROR_CODE_SUCCESS; 3033deb3ec6SMatthias Ringwald } 3043deb3ec6SMatthias Ringwald *mtu = ATT_DEFAULT_MTU; 305616edd56SMatthias Ringwald return GATT_CLIENT_IN_WRONG_STATE; 3063deb3ec6SMatthias Ringwald } 3073deb3ec6SMatthias Ringwald 3089228fd32SMatthias Ringwald static uint8_t *gatt_client_reserve_request_buffer(gatt_client_t *gatt_client) { 3097627a0deSMatthias Ringwald switch (gatt_client->bearer_type){ 3107627a0deSMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC 3117627a0deSMatthias Ringwald case ATT_BEARER_UNENHANCED_CLASSIC: 3127627a0deSMatthias Ringwald #endif 3137627a0deSMatthias Ringwald case ATT_BEARER_UNENHANCED_LE: 3149228fd32SMatthias Ringwald l2cap_reserve_packet_buffer(); 3159228fd32SMatthias Ringwald return l2cap_get_outgoing_buffer(); 3167627a0deSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 3177627a0deSMatthias Ringwald case ATT_BEARER_ENHANCED_LE: 3187627a0deSMatthias Ringwald return gatt_client->eatt_storage_buffer; 3197627a0deSMatthias Ringwald #endif 3207627a0deSMatthias Ringwald default: 3217627a0deSMatthias Ringwald btstack_unreachable(); 3227627a0deSMatthias Ringwald break; 3237627a0deSMatthias Ringwald } 3247627a0deSMatthias Ringwald return NULL; 3259228fd32SMatthias Ringwald } 3269228fd32SMatthias Ringwald 3273deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 3286e7b444cSMatthias Ringwald static uint8_t gatt_client_send(gatt_client_t * gatt_client, uint16_t len){ 32946012949SMatthias Ringwald switch (gatt_client->bearer_type){ 33046012949SMatthias Ringwald case ATT_BEARER_UNENHANCED_LE: 3316e7b444cSMatthias Ringwald return l2cap_send_prepared_connectionless(gatt_client->con_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, len); 33246012949SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC 33346012949SMatthias Ringwald case ATT_BEARER_UNENHANCED_CLASSIC: 33446012949SMatthias Ringwald return l2cap_send_prepared(gatt_client->l2cap_cid, len); 33546012949SMatthias Ringwald #endif 3367627a0deSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 3377627a0deSMatthias Ringwald case ATT_BEARER_ENHANCED_LE: 3387627a0deSMatthias Ringwald return l2cap_send(gatt_client->l2cap_cid, gatt_client->eatt_storage_buffer, len); 3397627a0deSMatthias Ringwald #endif 34046012949SMatthias Ringwald default: 34146012949SMatthias Ringwald btstack_unreachable(); 34246012949SMatthias Ringwald return ERROR_CODE_HARDWARE_FAILURE; 34346012949SMatthias Ringwald } 3443deb3ec6SMatthias Ringwald } 3453deb3ec6SMatthias Ringwald 3463deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 3476e7b444cSMatthias Ringwald static uint8_t att_confirmation(gatt_client_t * gatt_client) { 3489228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 3496e7b444cSMatthias Ringwald 3506e7b444cSMatthias Ringwald request[0] = ATT_HANDLE_VALUE_CONFIRMATION; 3516e7b444cSMatthias Ringwald 3526e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 1); 3536e7b444cSMatthias Ringwald } 3546e7b444cSMatthias Ringwald 3556e7b444cSMatthias Ringwald // precondition: can_send_packet_now == TRUE 3566e7b444cSMatthias Ringwald static uint8_t att_find_information_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t start_handle, 3576e7b444cSMatthias Ringwald uint16_t end_handle) { 3589228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 3596e7b444cSMatthias Ringwald 3603deb3ec6SMatthias Ringwald request[0] = request_type; 361f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, start_handle); 362f8fbdce0SMatthias Ringwald little_endian_store_16(request, 3, end_handle); 3633deb3ec6SMatthias Ringwald 3646e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 5); 3653deb3ec6SMatthias Ringwald } 3663deb3ec6SMatthias Ringwald 3673deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 3686e7b444cSMatthias Ringwald static uint8_t 3696e7b444cSMatthias Ringwald att_find_by_type_value_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_group_type, 3706e7b444cSMatthias Ringwald uint16_t start_handle, uint16_t end_handle, uint8_t *value, uint16_t value_size) { 3719228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 3723deb3ec6SMatthias Ringwald request[0] = request_type; 3739228fd32SMatthias Ringwald 374f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, start_handle); 375f8fbdce0SMatthias Ringwald little_endian_store_16(request, 3, end_handle); 376f8fbdce0SMatthias Ringwald little_endian_store_16(request, 5, attribute_group_type); 3776535961aSMatthias Ringwald (void)memcpy(&request[7], value, value_size); 3783deb3ec6SMatthias Ringwald 3796e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 7u + value_size); 3803deb3ec6SMatthias Ringwald } 3813deb3ec6SMatthias Ringwald 3823deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 3836e7b444cSMatthias Ringwald static uint8_t 3846e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid16(gatt_client_t *gatt_client, uint8_t request_type, uint16_t uuid16, 3856e7b444cSMatthias Ringwald uint16_t start_handle, uint16_t end_handle) { 3869228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 3876e7b444cSMatthias Ringwald 3883deb3ec6SMatthias Ringwald request[0] = request_type; 389f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, start_handle); 390f8fbdce0SMatthias Ringwald little_endian_store_16(request, 3, end_handle); 391f8fbdce0SMatthias Ringwald little_endian_store_16(request, 5, uuid16); 3923deb3ec6SMatthias Ringwald 3936e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 7); 3943deb3ec6SMatthias Ringwald } 3953deb3ec6SMatthias Ringwald 3963deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 3976e7b444cSMatthias Ringwald static uint8_t 3986e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid128(gatt_client_t *gatt_client, uint8_t request_type, const uint8_t *uuid128, 3996e7b444cSMatthias Ringwald uint16_t start_handle, uint16_t end_handle) { 4009228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 4016e7b444cSMatthias Ringwald 4023deb3ec6SMatthias Ringwald request[0] = request_type; 403f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, start_handle); 404f8fbdce0SMatthias Ringwald little_endian_store_16(request, 3, end_handle); 4059c80e4ccSMatthias Ringwald reverse_128(uuid128, &request[5]); 4063deb3ec6SMatthias Ringwald 4076e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 21); 4083deb3ec6SMatthias Ringwald } 4093deb3ec6SMatthias Ringwald 4103deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 4116e7b444cSMatthias Ringwald static uint8_t att_read_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_handle) { 4129228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 4136e7b444cSMatthias Ringwald 4143deb3ec6SMatthias Ringwald request[0] = request_type; 415f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, attribute_handle); 4163deb3ec6SMatthias Ringwald 4176e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 3); 4183deb3ec6SMatthias Ringwald } 4193deb3ec6SMatthias Ringwald 4203deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 4216e7b444cSMatthias Ringwald static uint8_t att_read_blob_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_handle, 4226e7b444cSMatthias Ringwald uint16_t value_offset) { 4239228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 4249228fd32SMatthias Ringwald 4253deb3ec6SMatthias Ringwald request[0] = request_type; 426f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, attribute_handle); 427f8fbdce0SMatthias Ringwald little_endian_store_16(request, 3, value_offset); 4283deb3ec6SMatthias Ringwald 4296e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 5); 4303deb3ec6SMatthias Ringwald } 4313deb3ec6SMatthias Ringwald 4326e7b444cSMatthias Ringwald static uint8_t 433f125a8efSMatthias Ringwald att_read_multiple_request_with_opcode(gatt_client_t *gatt_client, uint16_t num_value_handles, uint16_t *value_handles, uint8_t opcode) { 4349228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 4359228fd32SMatthias Ringwald 436f125a8efSMatthias Ringwald request[0] = opcode; 4379228fd32SMatthias Ringwald uint16_t i; 4389228fd32SMatthias Ringwald uint16_t offset = 1; 4393deb3ec6SMatthias Ringwald for (i=0;i<num_value_handles;i++){ 440f8fbdce0SMatthias Ringwald little_endian_store_16(request, offset, value_handles[i]); 4413deb3ec6SMatthias Ringwald offset += 2; 4423deb3ec6SMatthias Ringwald } 44325b7c058SMilanka Ringwald 4446e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, offset); 4453deb3ec6SMatthias Ringwald } 4463deb3ec6SMatthias Ringwald 447f125a8efSMatthias Ringwald static uint8_t 448f125a8efSMatthias Ringwald att_read_multiple_request(gatt_client_t *gatt_client, uint16_t num_value_handles, uint16_t *value_handles) { 449f125a8efSMatthias Ringwald return att_read_multiple_request_with_opcode(gatt_client, num_value_handles, value_handles, ATT_READ_MULTIPLE_REQUEST); 450f125a8efSMatthias Ringwald } 451f125a8efSMatthias Ringwald 452f125a8efSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 453f125a8efSMatthias Ringwald static uint8_t 454f125a8efSMatthias Ringwald att_read_multiple_variable_request(gatt_client_t *gatt_client, uint16_t num_value_handles, uint16_t *value_handles) { 455f125a8efSMatthias Ringwald return att_read_multiple_request_with_opcode(gatt_client, num_value_handles, value_handles, ATT_READ_MULTIPLE_VARIABLE_REQ); 456f125a8efSMatthias Ringwald } 457f125a8efSMatthias Ringwald #endif 458f125a8efSMatthias Ringwald 4597a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE 4603deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 4616e7b444cSMatthias Ringwald static uint8_t att_signed_write_request(gatt_client_t *gatt_client, uint16_t request_type, uint16_t attribute_handle, 4626e7b444cSMatthias Ringwald uint16_t value_length, uint8_t *value, uint32_t sign_counter, uint8_t sgn[8]) { 4639228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 4649228fd32SMatthias Ringwald 4653deb3ec6SMatthias Ringwald request[0] = request_type; 466f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, attribute_handle); 4676535961aSMatthias Ringwald (void)memcpy(&request[3], value, value_length); 468f8fbdce0SMatthias Ringwald little_endian_store_32(request, 3 + value_length, sign_counter); 4699c80e4ccSMatthias Ringwald reverse_64(sgn, &request[3 + value_length + 4]); 47025b7c058SMilanka Ringwald 4716e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 3 + value_length + 12); 4723deb3ec6SMatthias Ringwald } 4737a766ebfSMatthias Ringwald #endif 4743deb3ec6SMatthias Ringwald 4753deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 4766e7b444cSMatthias Ringwald static uint8_t 4776e7b444cSMatthias Ringwald att_write_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_handle, uint16_t value_length, 4786e7b444cSMatthias Ringwald uint8_t *value) { 4799228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 4809228fd32SMatthias Ringwald 4813deb3ec6SMatthias Ringwald request[0] = request_type; 482f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, attribute_handle); 4836535961aSMatthias Ringwald (void)memcpy(&request[3], value, value_length); 4843deb3ec6SMatthias Ringwald 4856e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 3u + value_length); 4863deb3ec6SMatthias Ringwald } 4873deb3ec6SMatthias Ringwald 4883deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 4896e7b444cSMatthias Ringwald static uint8_t att_execute_write_request(gatt_client_t *gatt_client, uint8_t request_type, uint8_t execute_write) { 4909228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 4919228fd32SMatthias Ringwald 4923deb3ec6SMatthias Ringwald request[0] = request_type; 4933deb3ec6SMatthias Ringwald request[1] = execute_write; 49425b7c058SMilanka Ringwald 4956e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 2); 4963deb3ec6SMatthias Ringwald } 4973deb3ec6SMatthias Ringwald 4983deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE 4996e7b444cSMatthias Ringwald static uint8_t att_prepare_write_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_handle, 5006e7b444cSMatthias Ringwald uint16_t value_offset, uint16_t blob_length, uint8_t *value) { 5019228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 5029228fd32SMatthias Ringwald 5033deb3ec6SMatthias Ringwald request[0] = request_type; 504f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, attribute_handle); 505f8fbdce0SMatthias Ringwald little_endian_store_16(request, 3, value_offset); 5066535961aSMatthias Ringwald (void)memcpy(&request[5], &value[value_offset], blob_length); 5073deb3ec6SMatthias Ringwald 5086e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 5u + blob_length); 5093deb3ec6SMatthias Ringwald } 5103deb3ec6SMatthias Ringwald 5116e7b444cSMatthias Ringwald static uint8_t att_exchange_mtu_request(gatt_client_t *gatt_client) { 5129228fd32SMatthias Ringwald uint8_t *request = gatt_client_reserve_request_buffer(gatt_client); 5139228fd32SMatthias Ringwald 5143deb3ec6SMatthias Ringwald request[0] = ATT_EXCHANGE_MTU_REQUEST; 5159228fd32SMatthias Ringwald uint16_t mtu = l2cap_max_le_mtu(); 516f8fbdce0SMatthias Ringwald little_endian_store_16(request, 1, mtu); 51725b7c058SMilanka Ringwald 5186e7b444cSMatthias Ringwald return gatt_client_send(gatt_client, 3); 5193deb3ec6SMatthias Ringwald } 5203deb3ec6SMatthias Ringwald 5215cf1669fSMatthias Ringwald static uint16_t write_blob_length(gatt_client_t * gatt_client){ 522dda77937SMatthias Ringwald uint16_t max_blob_length = gatt_client->mtu - 5u; 5235cf1669fSMatthias Ringwald if (gatt_client->attribute_offset >= gatt_client->attribute_length) { 5243deb3ec6SMatthias Ringwald return 0; 5253deb3ec6SMatthias Ringwald } 5265cf1669fSMatthias Ringwald uint16_t rest_length = gatt_client->attribute_length - gatt_client->attribute_offset; 5273deb3ec6SMatthias Ringwald if (max_blob_length > rest_length){ 5283deb3ec6SMatthias Ringwald return rest_length; 5293deb3ec6SMatthias Ringwald } 5303deb3ec6SMatthias Ringwald return max_blob_length; 5313deb3ec6SMatthias Ringwald } 5323deb3ec6SMatthias Ringwald 5335cf1669fSMatthias Ringwald static void send_gatt_services_request(gatt_client_t *gatt_client){ 5346e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_GROUP_TYPE_REQUEST, 5356e7b444cSMatthias Ringwald gatt_client->uuid16, gatt_client->start_group_handle, 5366e7b444cSMatthias Ringwald gatt_client->end_group_handle); 5373deb3ec6SMatthias Ringwald } 5383deb3ec6SMatthias Ringwald 5395cf1669fSMatthias Ringwald static void send_gatt_by_uuid_request(gatt_client_t *gatt_client, uint16_t attribute_group_type){ 54052377058SMatthias Ringwald if (gatt_client->uuid16 != 0u){ 5413deb3ec6SMatthias Ringwald uint8_t uuid16[2]; 5425cf1669fSMatthias Ringwald little_endian_store_16(uuid16, 0, gatt_client->uuid16); 5436e7b444cSMatthias Ringwald att_find_by_type_value_request(gatt_client, ATT_FIND_BY_TYPE_VALUE_REQUEST, attribute_group_type, 5446e7b444cSMatthias Ringwald gatt_client->start_group_handle, gatt_client->end_group_handle, uuid16, 2); 5453deb3ec6SMatthias Ringwald return; 5463deb3ec6SMatthias Ringwald } 5473deb3ec6SMatthias Ringwald uint8_t uuid128[16]; 5485cf1669fSMatthias Ringwald reverse_128(gatt_client->uuid128, uuid128); 5496e7b444cSMatthias Ringwald att_find_by_type_value_request(gatt_client, ATT_FIND_BY_TYPE_VALUE_REQUEST, attribute_group_type, 5506e7b444cSMatthias Ringwald gatt_client->start_group_handle, gatt_client->end_group_handle, uuid128, 16); 5513deb3ec6SMatthias Ringwald } 5523deb3ec6SMatthias Ringwald 5535cf1669fSMatthias Ringwald static void send_gatt_services_by_uuid_request(gatt_client_t *gatt_client){ 5545cf1669fSMatthias Ringwald send_gatt_by_uuid_request(gatt_client, GATT_PRIMARY_SERVICE_UUID); 5553deb3ec6SMatthias Ringwald } 5563deb3ec6SMatthias Ringwald 5575cf1669fSMatthias Ringwald static void send_gatt_included_service_uuid_request(gatt_client_t *gatt_client){ 5586e7b444cSMatthias Ringwald att_read_request(gatt_client, ATT_READ_REQUEST, gatt_client->query_start_handle); 5593deb3ec6SMatthias Ringwald } 5603deb3ec6SMatthias Ringwald 5615cf1669fSMatthias Ringwald static void send_gatt_included_service_request(gatt_client_t *gatt_client){ 5626e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_TYPE_REQUEST, 5636e7b444cSMatthias Ringwald GATT_INCLUDE_SERVICE_UUID, gatt_client->start_group_handle, 5646e7b444cSMatthias Ringwald gatt_client->end_group_handle); 5653deb3ec6SMatthias Ringwald } 5663deb3ec6SMatthias Ringwald 5675cf1669fSMatthias Ringwald static void send_gatt_characteristic_request(gatt_client_t *gatt_client){ 5686e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_TYPE_REQUEST, 5696e7b444cSMatthias Ringwald GATT_CHARACTERISTICS_UUID, gatt_client->start_group_handle, 5706e7b444cSMatthias Ringwald gatt_client->end_group_handle); 5713deb3ec6SMatthias Ringwald } 5723deb3ec6SMatthias Ringwald 5735cf1669fSMatthias Ringwald static void send_gatt_characteristic_descriptor_request(gatt_client_t *gatt_client){ 5746e7b444cSMatthias Ringwald att_find_information_request(gatt_client, ATT_FIND_INFORMATION_REQUEST, gatt_client->start_group_handle, 5756e7b444cSMatthias Ringwald gatt_client->end_group_handle); 5763deb3ec6SMatthias Ringwald } 5773deb3ec6SMatthias Ringwald 5785cf1669fSMatthias Ringwald static void send_gatt_read_characteristic_value_request(gatt_client_t *gatt_client){ 5796e7b444cSMatthias Ringwald att_read_request(gatt_client, ATT_READ_REQUEST, gatt_client->attribute_handle); 5803deb3ec6SMatthias Ringwald } 5813deb3ec6SMatthias Ringwald 5825cf1669fSMatthias Ringwald static void send_gatt_read_by_type_request(gatt_client_t * gatt_client){ 58352377058SMatthias Ringwald if (gatt_client->uuid16 != 0u){ 5846e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_TYPE_REQUEST, 5856e7b444cSMatthias Ringwald gatt_client->uuid16, gatt_client->start_group_handle, 5866e7b444cSMatthias Ringwald gatt_client->end_group_handle); 5873deb3ec6SMatthias Ringwald } else { 5886e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid128(gatt_client, ATT_READ_BY_TYPE_REQUEST, 5896e7b444cSMatthias Ringwald gatt_client->uuid128, gatt_client->start_group_handle, 5906e7b444cSMatthias Ringwald gatt_client->end_group_handle); 5913deb3ec6SMatthias Ringwald } 5923deb3ec6SMatthias Ringwald } 5933deb3ec6SMatthias Ringwald 5945cf1669fSMatthias Ringwald static void send_gatt_read_blob_request(gatt_client_t *gatt_client){ 59530952227SMilanka Ringwald if (gatt_client->attribute_offset == 0){ 5966e7b444cSMatthias Ringwald att_read_request(gatt_client, ATT_READ_REQUEST, gatt_client->attribute_handle); 59730952227SMilanka Ringwald } else { 5986e7b444cSMatthias Ringwald att_read_blob_request(gatt_client, ATT_READ_BLOB_REQUEST, gatt_client->attribute_handle, 5996e7b444cSMatthias Ringwald gatt_client->attribute_offset); 6003deb3ec6SMatthias Ringwald } 60130952227SMilanka Ringwald } 6023deb3ec6SMatthias Ringwald 6035cf1669fSMatthias Ringwald static void send_gatt_read_multiple_request(gatt_client_t * gatt_client){ 6046e7b444cSMatthias Ringwald att_read_multiple_request(gatt_client, gatt_client->read_multiple_handle_count, gatt_client->read_multiple_handles); 6053deb3ec6SMatthias Ringwald } 6063deb3ec6SMatthias Ringwald 607f125a8efSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 608f125a8efSMatthias Ringwald static void send_gatt_read_multiple_variable_request(gatt_client_t * gatt_client){ 609f125a8efSMatthias Ringwald att_read_multiple_variable_request(gatt_client, gatt_client->read_multiple_handle_count, gatt_client->read_multiple_handles); 610f125a8efSMatthias Ringwald } 611f125a8efSMatthias Ringwald #endif 612f125a8efSMatthias Ringwald 6135cf1669fSMatthias Ringwald static void send_gatt_write_attribute_value_request(gatt_client_t * gatt_client){ 6146e7b444cSMatthias Ringwald att_write_request(gatt_client, ATT_WRITE_REQUEST, gatt_client->attribute_handle, gatt_client->attribute_length, 6156e7b444cSMatthias Ringwald gatt_client->attribute_value); 6163deb3ec6SMatthias Ringwald } 6173deb3ec6SMatthias Ringwald 6185cf1669fSMatthias Ringwald static void send_gatt_write_client_characteristic_configuration_request(gatt_client_t * gatt_client){ 6196e7b444cSMatthias Ringwald att_write_request(gatt_client, ATT_WRITE_REQUEST, gatt_client->client_characteristic_configuration_handle, 2, 6206e7b444cSMatthias Ringwald gatt_client->client_characteristic_configuration_value); 6213deb3ec6SMatthias Ringwald } 6223deb3ec6SMatthias Ringwald 6235cf1669fSMatthias Ringwald static void send_gatt_prepare_write_request(gatt_client_t * gatt_client){ 6246e7b444cSMatthias Ringwald att_prepare_write_request(gatt_client, ATT_PREPARE_WRITE_REQUEST, gatt_client->attribute_handle, 6256e7b444cSMatthias Ringwald gatt_client->attribute_offset, write_blob_length(gatt_client), 6266e7b444cSMatthias Ringwald gatt_client->attribute_value); 6273deb3ec6SMatthias Ringwald } 6283deb3ec6SMatthias Ringwald 6295cf1669fSMatthias Ringwald static void send_gatt_execute_write_request(gatt_client_t * gatt_client){ 6306e7b444cSMatthias Ringwald att_execute_write_request(gatt_client, ATT_EXECUTE_WRITE_REQUEST, 1); 6313deb3ec6SMatthias Ringwald } 6323deb3ec6SMatthias Ringwald 6335cf1669fSMatthias Ringwald static void send_gatt_cancel_prepared_write_request(gatt_client_t * gatt_client){ 6346e7b444cSMatthias Ringwald att_execute_write_request(gatt_client, ATT_EXECUTE_WRITE_REQUEST, 0); 6353deb3ec6SMatthias Ringwald } 6363deb3ec6SMatthias Ringwald 637abdc9fb5SMatthias Ringwald #ifndef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY 6385cf1669fSMatthias Ringwald static void send_gatt_read_client_characteristic_configuration_request(gatt_client_t * gatt_client){ 6396e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_TYPE_REQUEST, 6406e7b444cSMatthias Ringwald GATT_CLIENT_CHARACTERISTICS_CONFIGURATION, 6416e7b444cSMatthias Ringwald gatt_client->start_group_handle, gatt_client->end_group_handle); 6423deb3ec6SMatthias Ringwald } 643abdc9fb5SMatthias Ringwald #endif 6443deb3ec6SMatthias Ringwald 6455cf1669fSMatthias Ringwald static void send_gatt_read_characteristic_descriptor_request(gatt_client_t * gatt_client){ 6466e7b444cSMatthias Ringwald att_read_request(gatt_client, ATT_READ_REQUEST, gatt_client->attribute_handle); 6473deb3ec6SMatthias Ringwald } 6483deb3ec6SMatthias Ringwald 6497a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE 6505cf1669fSMatthias Ringwald static void send_gatt_signed_write_request(gatt_client_t * gatt_client, uint32_t sign_counter){ 6516e7b444cSMatthias Ringwald att_signed_write_request(gatt_client, ATT_SIGNED_WRITE_COMMAND, gatt_client->attribute_handle, 6526e7b444cSMatthias Ringwald gatt_client->attribute_length, gatt_client->attribute_value, sign_counter, 6536e7b444cSMatthias Ringwald gatt_client->cmac); 6543deb3ec6SMatthias Ringwald } 6557a766ebfSMatthias Ringwald #endif 6563deb3ec6SMatthias Ringwald 6573deb3ec6SMatthias Ringwald static uint16_t get_last_result_handle_from_service_list(uint8_t * packet, uint16_t size){ 65839ac9711SMatthias Ringwald if (size < 2) return 0xffff; 6593deb3ec6SMatthias Ringwald uint8_t attr_length = packet[1]; 66039ac9711SMatthias Ringwald if ((2 + attr_length) > size) return 0xffff; 6614ea43905SMatthias Ringwald return little_endian_read_16(packet, size - attr_length + 2u); 6623deb3ec6SMatthias Ringwald } 6633deb3ec6SMatthias Ringwald 6643deb3ec6SMatthias Ringwald static uint16_t get_last_result_handle_from_characteristics_list(uint8_t * packet, uint16_t size){ 66539ac9711SMatthias Ringwald if (size < 2) return 0xffff; 6663deb3ec6SMatthias Ringwald uint8_t attr_length = packet[1]; 66739ac9711SMatthias Ringwald if ((2 + attr_length) > size) return 0xffff; 6684ea43905SMatthias Ringwald return little_endian_read_16(packet, size - attr_length + 3u); 6693deb3ec6SMatthias Ringwald } 6703deb3ec6SMatthias Ringwald 6713deb3ec6SMatthias Ringwald static uint16_t get_last_result_handle_from_included_services_list(uint8_t * packet, uint16_t size){ 67239ac9711SMatthias Ringwald if (size < 2) return 0xffff; 6733deb3ec6SMatthias Ringwald uint8_t attr_length = packet[1]; 67439ac9711SMatthias Ringwald if ((2 + attr_length) > size) return 0xffff; 675f8fbdce0SMatthias Ringwald return little_endian_read_16(packet, size - attr_length); 6763deb3ec6SMatthias Ringwald } 6773deb3ec6SMatthias Ringwald 678842492f0SMatthias Ringwald #ifdef ENABLE_GATT_CLIENT_SERVICE_CHANGED 67958e8c9f5SMatthias Ringwald static void gatt_client_service_emit_event(gatt_client_t * gatt_client, uint8_t * event, uint16_t size){ 68058e8c9f5SMatthias Ringwald btstack_linked_list_iterator_t it; 68158e8c9f5SMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client_service_changed_handler); 68258e8c9f5SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)) { 68358e8c9f5SMatthias Ringwald btstack_packet_callback_registration_t *callback = (btstack_packet_callback_registration_t *) btstack_linked_list_iterator_next(&it); 68458e8c9f5SMatthias Ringwald (*callback->callback)(HCI_EVENT_PACKET, (uint16_t) gatt_client->con_handle, event, size); 68558e8c9f5SMatthias Ringwald } 68658e8c9f5SMatthias Ringwald } 68758e8c9f5SMatthias Ringwald 68858e8c9f5SMatthias Ringwald static void 68958e8c9f5SMatthias Ringwald gatt_client_service_emit_database_hash(gatt_client_t *gatt_client, const uint8_t *value, uint16_t value_len) { 69058e8c9f5SMatthias Ringwald if (value_len == 16){ 69158e8c9f5SMatthias Ringwald uint8_t event[21]; 69258e8c9f5SMatthias Ringwald hci_event_builder_context_t context; 69358e8c9f5SMatthias Ringwald hci_event_builder_init(&context, event, sizeof(event), HCI_EVENT_GATTSERVICE_META, GATTSERVICE_SUBEVENT_GATT_DATABASE_HASH); 69458e8c9f5SMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 69558e8c9f5SMatthias Ringwald hci_event_builder_add_bytes(&context, value, 16); 69658e8c9f5SMatthias Ringwald gatt_client_service_emit_event(gatt_client, event, hci_event_builder_get_length(&context)); 69758e8c9f5SMatthias Ringwald } 69858e8c9f5SMatthias Ringwald } 69958e8c9f5SMatthias Ringwald 70058e8c9f5SMatthias Ringwald static void 70158e8c9f5SMatthias Ringwald gatt_client_service_emit_service_changed(gatt_client_t *gatt_client, const uint8_t *value, uint16_t value_len) { 70258e8c9f5SMatthias Ringwald if (value_len == 4){ 70358e8c9f5SMatthias Ringwald uint8_t event[9]; 70458e8c9f5SMatthias Ringwald hci_event_builder_context_t context; 70558e8c9f5SMatthias Ringwald hci_event_builder_init(&context, event, sizeof(event), HCI_EVENT_GATTSERVICE_META, GATTSERVICE_SUBEVENT_GATT_SERVICE_CHANGED); 70658e8c9f5SMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 70758e8c9f5SMatthias Ringwald hci_event_builder_add_bytes(&context, value, 4); 70858e8c9f5SMatthias Ringwald gatt_client_service_emit_event(gatt_client, event, hci_event_builder_get_length(&context)); 70958e8c9f5SMatthias Ringwald } 71058e8c9f5SMatthias Ringwald } 71158e8c9f5SMatthias Ringwald 712d9ced76fSMatthias Ringwald static void gatt_client_service_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 713e2c98440SMatthias Ringwald UNUSED(channel); // ok: handling own l2cap events 714e2c98440SMatthias Ringwald UNUSED(size); // ok: there is no channel 715e2c98440SMatthias Ringwald 716d9ced76fSMatthias Ringwald hci_con_handle_t con_handle; 717d9ced76fSMatthias Ringwald gatt_client_t *gatt_client; 718d9ced76fSMatthias Ringwald gatt_client_service_t service; 719d9ced76fSMatthias Ringwald gatt_client_characteristic_t characteristic; 720d9ced76fSMatthias Ringwald switch (packet_type) { 721d9ced76fSMatthias Ringwald case HCI_EVENT_PACKET: 722d9ced76fSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 723d9ced76fSMatthias Ringwald case GATT_EVENT_SERVICE_QUERY_RESULT: 724d9ced76fSMatthias Ringwald con_handle = gatt_event_service_query_result_get_handle(packet); 725d9ced76fSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 726d9ced76fSMatthias Ringwald btstack_assert(gatt_client != NULL); 727d9ced76fSMatthias Ringwald btstack_assert(gatt_client->gatt_service_state == GATT_CLIENT_SERVICE_DISCOVER_W4_DONE); 728d9ced76fSMatthias Ringwald gatt_event_service_query_result_get_service(packet, &service); 729d9ced76fSMatthias Ringwald gatt_client->gatt_service_start_group_handle = service.start_group_handle; 730d9ced76fSMatthias Ringwald gatt_client->gatt_service_end_group_handle = service.end_group_handle; 731d9ced76fSMatthias Ringwald break; 732d9ced76fSMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 733d9ced76fSMatthias Ringwald con_handle = gatt_event_characteristic_query_result_get_handle(packet); 734d9ced76fSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 735d9ced76fSMatthias Ringwald btstack_assert(gatt_client != NULL); 736d9ced76fSMatthias Ringwald btstack_assert(gatt_client->gatt_service_state == GATT_CLIENT_SERVICE_DISCOVER_CHARACTERISTICS_W4_DONE); 737d9ced76fSMatthias Ringwald gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 738d9ced76fSMatthias Ringwald switch (characteristic.uuid16){ 739d9ced76fSMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_GATT_SERVICE_CHANGED: 740d9ced76fSMatthias Ringwald gatt_client->gatt_service_changed_value_handle = characteristic.value_handle; 741d9ced76fSMatthias Ringwald gatt_client->gatt_service_changed_end_handle = characteristic.end_handle; 742d9ced76fSMatthias Ringwald break; 743d9ced76fSMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_DATABASE_HASH: 744d9ced76fSMatthias Ringwald gatt_client->gatt_service_database_hash_value_handle = characteristic.value_handle; 745d9ced76fSMatthias Ringwald gatt_client->gatt_service_database_hash_end_handle = characteristic.end_handle; 746d9ced76fSMatthias Ringwald break; 747d9ced76fSMatthias Ringwald default: 748d9ced76fSMatthias Ringwald break; 749d9ced76fSMatthias Ringwald } 750d9ced76fSMatthias Ringwald break; 751d9ced76fSMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: 752d9ced76fSMatthias Ringwald con_handle = gatt_event_characteristic_value_query_result_get_handle(packet); 753d9ced76fSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 754d9ced76fSMatthias Ringwald btstack_assert(gatt_client != NULL); 755d9ced76fSMatthias Ringwald btstack_assert(gatt_client->gatt_service_state == GATT_CLIENT_SERVICE_DATABASE_HASH_READ_W4_DONE); 75658e8c9f5SMatthias Ringwald gatt_client_service_emit_database_hash(gatt_client, 75758e8c9f5SMatthias Ringwald gatt_event_characteristic_value_query_result_get_value(packet), 75858e8c9f5SMatthias Ringwald gatt_event_characteristic_value_query_result_get_value_length(packet)); 759d9ced76fSMatthias Ringwald break; 760d9ced76fSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 761d9ced76fSMatthias Ringwald con_handle = gatt_event_query_complete_get_handle(packet); 762d9ced76fSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 763d9ced76fSMatthias Ringwald btstack_assert(gatt_client != NULL); 764d9ced76fSMatthias Ringwald switch (gatt_client->gatt_service_state) { 765d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_DISCOVER_W4_DONE: 766d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DISCOVER_CHARACTERISTICS_W2_SEND; 767d9ced76fSMatthias Ringwald break; 768d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_DISCOVER_CHARACTERISTICS_W4_DONE: 769d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_SERVICE_CHANGED_WRITE_CCCD_W2_SEND; 770d9ced76fSMatthias Ringwald break; 771d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_SERVICE_CHANGED_WRITE_CCCD_W4_DONE: 772d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DATABASE_HASH_READ_W2_SEND; 773d9ced76fSMatthias Ringwald break; 774d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_DATABASE_HASH_READ_W4_DONE: 775d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DATABASE_HASH_WRITE_CCCD_W2_SEND; 776d9ced76fSMatthias Ringwald break; 777d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_DATABASE_HASH_WRITE_CCCD_W4_DONE: 778d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DONE; 779d9ced76fSMatthias Ringwald break; 780d9ced76fSMatthias Ringwald default: 781d9ced76fSMatthias Ringwald btstack_unreachable(); 782d9ced76fSMatthias Ringwald break; 783d9ced76fSMatthias Ringwald } 784d9ced76fSMatthias Ringwald break; 785d9ced76fSMatthias Ringwald default: 786d9ced76fSMatthias Ringwald break; 787d9ced76fSMatthias Ringwald } 788d9ced76fSMatthias Ringwald break; 789d9ced76fSMatthias Ringwald default: 790d9ced76fSMatthias Ringwald break; 791d9ced76fSMatthias Ringwald } 792d9ced76fSMatthias Ringwald } 793842492f0SMatthias Ringwald #endif 794d9ced76fSMatthias Ringwald 79553e9c18fSMatthias Ringwald static void gatt_client_notify_can_send_query(gatt_client_t * gatt_client){ 79619c614acSMatthias Ringwald 79719c614acSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 79819c614acSMatthias Ringwald // if eatt is ready, notify all clients that can send a query 79919c614acSMatthias Ringwald if (gatt_client->eatt_state == GATT_CLIENT_EATT_READY){ 80019c614acSMatthias Ringwald btstack_linked_list_iterator_t it; 80119c614acSMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client->eatt_clients); 80219c614acSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 80319c614acSMatthias Ringwald gatt_client_t * client = (gatt_client_t *) btstack_linked_list_iterator_next(&it); 804052dc82aSMatthias Ringwald if (client->state == P_READY){ 80519c614acSMatthias Ringwald // call callback 80619c614acSMatthias Ringwald btstack_context_callback_registration_t * callback = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&gatt_client->query_requests); 80719c614acSMatthias Ringwald if (callback == NULL) { 80819c614acSMatthias Ringwald return; 80919c614acSMatthias Ringwald } 81019c614acSMatthias Ringwald (*callback->callback)(callback->context); 81119c614acSMatthias Ringwald } 81219c614acSMatthias Ringwald } 81319c614acSMatthias Ringwald return; 81419c614acSMatthias Ringwald } 81519c614acSMatthias Ringwald #endif 81619c614acSMatthias Ringwald 817842492f0SMatthias Ringwald while (gatt_client->state == P_READY){ 818842492f0SMatthias Ringwald bool query_sent = false; 819842492f0SMatthias Ringwald UNUSED(query_sent); 820842492f0SMatthias Ringwald 821842492f0SMatthias Ringwald #ifdef ENABLE_GATT_CLIENT_SERVICE_CHANGED 822d9ced76fSMatthias Ringwald uint8_t status = ERROR_CODE_SUCCESS; 823d9ced76fSMatthias Ringwald gatt_client_service_t gatt_service; 824d9ced76fSMatthias Ringwald gatt_client_characteristic_t characteristic; 825d9ced76fSMatthias Ringwald switch (gatt_client->gatt_service_state){ 826d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_DISCOVER_W2_SEND: 827d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DISCOVER_W4_DONE; 828d9ced76fSMatthias Ringwald status = gatt_client_discover_primary_services_by_uuid16(&gatt_client_service_packet_handler, 829d9ced76fSMatthias Ringwald gatt_client->con_handle, 830d9ced76fSMatthias Ringwald ORG_BLUETOOTH_SERVICE_GENERIC_ATTRIBUTE); 831d9ced76fSMatthias Ringwald query_sent = true; 832d9ced76fSMatthias Ringwald break; 833d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_DISCOVER_CHARACTERISTICS_W2_SEND: 834d9ced76fSMatthias Ringwald if (gatt_client->gatt_service_start_group_handle != 0){ 835d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DISCOVER_CHARACTERISTICS_W4_DONE; 836d9ced76fSMatthias Ringwald gatt_service.start_group_handle = gatt_client->gatt_service_start_group_handle; 837d9ced76fSMatthias Ringwald gatt_service.end_group_handle = gatt_client->gatt_service_end_group_handle; 838d9ced76fSMatthias Ringwald status = gatt_client_discover_characteristics_for_service(&gatt_client_service_packet_handler, gatt_client->con_handle, &gatt_service); 839d9ced76fSMatthias Ringwald query_sent = true; 840d9ced76fSMatthias Ringwald break; 841d9ced76fSMatthias Ringwald } 842d9ced76fSMatthias Ringwald 843d9ced76fSMatthias Ringwald /* fall through */ 844d9ced76fSMatthias Ringwald 845d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_SERVICE_CHANGED_WRITE_CCCD_W2_SEND: 846d9ced76fSMatthias Ringwald if (gatt_client->gatt_service_changed_value_handle != 0){ 847d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_SERVICE_CHANGED_WRITE_CCCD_W4_DONE; 848d9ced76fSMatthias Ringwald characteristic.value_handle = gatt_client->gatt_service_changed_value_handle; 849d9ced76fSMatthias Ringwald characteristic.end_handle = gatt_client->gatt_service_changed_end_handle; 850d9ced76fSMatthias Ringwald // we assume good case. We cannot do much otherwise 851d9ced76fSMatthias Ringwald characteristic.properties = ATT_PROPERTY_INDICATE; 852d9ced76fSMatthias Ringwald status = gatt_client_write_client_characteristic_configuration(&gatt_client_service_packet_handler, 853d9ced76fSMatthias Ringwald gatt_client->con_handle, &characteristic, 854d9ced76fSMatthias Ringwald GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION); 855d9ced76fSMatthias Ringwald query_sent = true; 856d9ced76fSMatthias Ringwald break; 857d9ced76fSMatthias Ringwald } 858d9ced76fSMatthias Ringwald 859d9ced76fSMatthias Ringwald /* fall through */ 860d9ced76fSMatthias Ringwald 861d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_DATABASE_HASH_READ_W2_SEND: 862d9ced76fSMatthias Ringwald if (gatt_client->gatt_service_database_hash_value_handle != 0){ 863d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DATABASE_HASH_READ_W4_DONE; 864d9ced76fSMatthias Ringwald status = gatt_client_read_value_of_characteristics_by_uuid16(&gatt_client_service_packet_handler, 865d9ced76fSMatthias Ringwald gatt_client->con_handle, 866d9ced76fSMatthias Ringwald 0x0001, 0xffff, ORG_BLUETOOTH_CHARACTERISTIC_DATABASE_HASH); 867d9ced76fSMatthias Ringwald query_sent = true; 868d9ced76fSMatthias Ringwald break; 869d9ced76fSMatthias Ringwald } 870d9ced76fSMatthias Ringwald 871d9ced76fSMatthias Ringwald /* fall through */ 872d9ced76fSMatthias Ringwald 873d9ced76fSMatthias Ringwald case GATT_CLIENT_SERVICE_DATABASE_HASH_WRITE_CCCD_W2_SEND: 874d9ced76fSMatthias Ringwald if (gatt_client->gatt_service_database_hash_value_handle != 0) { 875d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DATABASE_HASH_WRITE_CCCD_W4_DONE; 876d9ced76fSMatthias Ringwald characteristic.value_handle = gatt_client->gatt_service_database_hash_value_handle; 877d9ced76fSMatthias Ringwald characteristic.end_handle = gatt_client->gatt_service_database_hash_end_handle; 878d9ced76fSMatthias Ringwald // we assume good case. We cannot do much otherwise 879d9ced76fSMatthias Ringwald characteristic.properties = ATT_PROPERTY_INDICATE; 880d9ced76fSMatthias Ringwald status = gatt_client_write_client_characteristic_configuration(&gatt_client_service_packet_handler, 881d9ced76fSMatthias Ringwald gatt_client->con_handle, 882d9ced76fSMatthias Ringwald &characteristic, 883d9ced76fSMatthias Ringwald GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION); 884d9ced76fSMatthias Ringwald query_sent = true; 885d9ced76fSMatthias Ringwald break; 886d9ced76fSMatthias Ringwald } 887d9ced76fSMatthias Ringwald 888d9ced76fSMatthias Ringwald // DONE 889d9ced76fSMatthias Ringwald gatt_client->gatt_service_state = GATT_CLIENT_SERVICE_DONE; 890d9ced76fSMatthias Ringwald break; 891d9ced76fSMatthias Ringwald default: 892d9ced76fSMatthias Ringwald break; 893d9ced76fSMatthias Ringwald } 894d9ced76fSMatthias Ringwald btstack_assert(status == ERROR_CODE_SUCCESS); 895d9ced76fSMatthias Ringwald UNUSED(status); 896d9ced76fSMatthias Ringwald if (query_sent){ 897d9ced76fSMatthias Ringwald continue; 898d9ced76fSMatthias Ringwald } 899842492f0SMatthias Ringwald #endif 900d9ced76fSMatthias Ringwald 90126166ecfSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 902d9ced76fSMatthias Ringwald query_sent = gatt_client_le_enhanced_handle_can_send_query(gatt_client); 90326166ecfSMatthias Ringwald if (query_sent){ 90426166ecfSMatthias Ringwald continue; 90526166ecfSMatthias Ringwald } 90626166ecfSMatthias Ringwald #endif 90753e9c18fSMatthias Ringwald btstack_context_callback_registration_t * callback = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&gatt_client->query_requests); 90809834412SMatthias Ringwald if (callback == NULL) { 90909834412SMatthias Ringwald return; 91053e9c18fSMatthias Ringwald } 91109834412SMatthias Ringwald (*callback->callback)(callback->context); 91253e9c18fSMatthias Ringwald } 91353e9c18fSMatthias Ringwald } 91453e9c18fSMatthias Ringwald 91523d583b8SMatthias Ringwald // test if notification/indication should be delivered to application (BLESA) 91623d583b8SMatthias Ringwald static bool gatt_client_accept_server_message(gatt_client_t *gatt_client) { 91723d583b8SMatthias Ringwald // ignore messages until re-encryption is complete 91823d583b8SMatthias Ringwald if (gap_reconnect_security_setup_active(gatt_client->con_handle)) return false; 91923d583b8SMatthias Ringwald 92023d583b8SMatthias Ringwald // after that ignore if bonded but not encrypted 92123d583b8SMatthias Ringwald return !gap_bonded(gatt_client->con_handle) || (gap_encryption_key_size(gatt_client->con_handle) > 0); 92223d583b8SMatthias Ringwald } 92323d583b8SMatthias Ringwald 9249c662c9bSMatthias Ringwald static void emit_event_new(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){ 9259c662c9bSMatthias Ringwald if (!callback) return; 9269da9850bSMatthias Ringwald hci_dump_btstack_event(packet, size); 9279c662c9bSMatthias Ringwald (*callback)(HCI_EVENT_PACKET, 0, packet, size); 9283deb3ec6SMatthias Ringwald } 9293deb3ec6SMatthias Ringwald 9305cf1669fSMatthias Ringwald static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){ 93188371317SMatthias Ringwald // @format H122 93288371317SMatthias Ringwald uint8_t packet[9]; 9336a88036eSMatthias Ringwald hci_event_builder_context_t context; 9346a88036eSMatthias Ringwald hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_QUERY_COMPLETE, 0); 9356a88036eSMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 93688371317SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->service_id); 93788371317SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->connection_id); 9386a88036eSMatthias Ringwald hci_event_builder_add_08(&context, att_status); 9396a88036eSMatthias Ringwald emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context)); 9403deb3ec6SMatthias Ringwald } 9413deb3ec6SMatthias Ringwald 942045d700dSDavid Lechner static void emit_gatt_service_query_result_event(gatt_client_t * gatt_client, uint16_t start_group_handle, uint16_t end_group_handle, const uint8_t * uuid128){ 943521f5820SMatthias Ringwald // @format H22X 944521f5820SMatthias Ringwald uint8_t packet[28]; 945c668d4cfSMatthias Ringwald hci_event_builder_context_t context; 946c668d4cfSMatthias Ringwald hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_SERVICE_QUERY_RESULT, 0); 947c668d4cfSMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 948521f5820SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->service_id); 949521f5820SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->connection_id); 950c668d4cfSMatthias Ringwald hci_event_builder_add_16(&context, start_group_handle); 951c668d4cfSMatthias Ringwald hci_event_builder_add_16(&context, end_group_handle); 952c668d4cfSMatthias Ringwald hci_event_builder_add_128(&context, uuid128); 953c668d4cfSMatthias Ringwald emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context)); 9543deb3ec6SMatthias Ringwald } 9553deb3ec6SMatthias Ringwald 956045d700dSDavid Lechner static void emit_gatt_included_service_query_result_event(gatt_client_t * gatt_client, uint16_t include_handle, uint16_t start_group_handle, uint16_t end_group_handle, const uint8_t * uuid128){ 957d578995fSMatthias Ringwald // @format H22X 958d578995fSMatthias Ringwald uint8_t packet[30]; 959d8ef101dSMatthias Ringwald hci_event_builder_context_t context; 960d8ef101dSMatthias Ringwald hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_INCLUDED_SERVICE_QUERY_RESULT, 0); 961d8ef101dSMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 962d578995fSMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->service_id); 963d578995fSMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->connection_id); 964d8ef101dSMatthias Ringwald hci_event_builder_add_16(&context, include_handle); 965d8ef101dSMatthias Ringwald hci_event_builder_add_16(&context, start_group_handle); 966d8ef101dSMatthias Ringwald hci_event_builder_add_16(&context, end_group_handle); 967d8ef101dSMatthias Ringwald hci_event_builder_add_128(&context, uuid128); 968d8ef101dSMatthias Ringwald emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context)); 9693deb3ec6SMatthias Ringwald } 9703deb3ec6SMatthias Ringwald 9715cf1669fSMatthias Ringwald static void emit_gatt_characteristic_query_result_event(gatt_client_t * gatt_client, uint16_t start_handle, uint16_t value_handle, uint16_t end_handle, 972045d700dSDavid Lechner uint16_t properties, const uint8_t * uuid128){ 973185497a5SMatthias Ringwald // @format H22Y 974185497a5SMatthias Ringwald uint8_t packet[32]; 975b5a7d6a2SMatthias Ringwald hci_event_builder_context_t context; 976b5a7d6a2SMatthias Ringwald hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_CHARACTERISTIC_QUERY_RESULT, 0); 977b5a7d6a2SMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 978185497a5SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->service_id); 979185497a5SMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->connection_id); 980b5a7d6a2SMatthias Ringwald hci_event_builder_add_16(&context, start_handle); 981b5a7d6a2SMatthias Ringwald hci_event_builder_add_16(&context, value_handle); 982b5a7d6a2SMatthias Ringwald hci_event_builder_add_16(&context, end_handle); 983b5a7d6a2SMatthias Ringwald hci_event_builder_add_16(&context, properties); 984b5a7d6a2SMatthias Ringwald hci_event_builder_add_128(&context, uuid128); 985b5a7d6a2SMatthias Ringwald emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context)); 9863deb3ec6SMatthias Ringwald } 9873deb3ec6SMatthias Ringwald 9883deb3ec6SMatthias Ringwald static void emit_gatt_all_characteristic_descriptors_result_event( 989045d700dSDavid Lechner gatt_client_t * gatt_client, uint16_t descriptor_handle, const uint8_t * uuid128){ 9905a6c9e2aSMatthias Ringwald // @format H22Z 9915a6c9e2aSMatthias Ringwald uint8_t packet[26]; 9921cfd1613SMatthias Ringwald hci_event_builder_context_t context; 9931cfd1613SMatthias Ringwald hci_event_builder_init(&context, packet, sizeof(packet), GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT, 0); 9941cfd1613SMatthias Ringwald hci_event_builder_add_con_handle(&context, gatt_client->con_handle); 9955a6c9e2aSMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->service_id); 9965a6c9e2aSMatthias Ringwald hci_event_builder_add_16(&context, gatt_client->connection_id); 9971cfd1613SMatthias Ringwald hci_event_builder_add_16(&context, descriptor_handle); 9981cfd1613SMatthias Ringwald hci_event_builder_add_128(&context, uuid128); 9991cfd1613SMatthias Ringwald emit_event_new(gatt_client->callback, packet, hci_event_builder_get_length(&context)); 10003deb3ec6SMatthias Ringwald } 10013deb3ec6SMatthias Ringwald 10025cf1669fSMatthias Ringwald static void emit_gatt_mtu_exchanged_result_event(gatt_client_t * gatt_client, uint16_t new_mtu){ 10038f37572aSJakob Krantz // @format H2 10048f37572aSJakob Krantz uint8_t packet[6]; 10058f37572aSJakob Krantz packet[0] = GATT_EVENT_MTU; 10064ea43905SMatthias Ringwald packet[1] = sizeof(packet) - 2u; 10075cf1669fSMatthias Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 10088f37572aSJakob Krantz little_endian_store_16(packet, 4, new_mtu); 10095cf1669fSMatthias Ringwald att_dispatch_client_mtu_exchanged(gatt_client->con_handle, new_mtu); 10105cf1669fSMatthias Ringwald emit_event_new(gatt_client->callback, packet, sizeof(packet)); 10118f37572aSJakob Krantz } 101223d583b8SMatthias Ringwald 101323d583b8SMatthias Ringwald // helper 101423d583b8SMatthias Ringwald static void gatt_client_handle_transaction_complete(gatt_client_t *gatt_client, uint8_t att_status) { 1015052dc82aSMatthias Ringwald gatt_client->state = P_READY; 101623d583b8SMatthias Ringwald gatt_client_timeout_stop(gatt_client); 101723d583b8SMatthias Ringwald emit_gatt_complete_event(gatt_client, att_status); 101823d583b8SMatthias Ringwald gatt_client_notify_can_send_query(gatt_client); 101923d583b8SMatthias Ringwald } 102023d583b8SMatthias Ringwald 102123d583b8SMatthias Ringwald // @return packet pointer 1022f6a28e25SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite HCI + L2CAP packet headers + 4 pre_buffer bytes 1023f6a28e25SMatthias Ringwald #define CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE 12 10248450fbf5SMatthias Ringwald static uint8_t * 10258450fbf5SMatthias Ringwald setup_characteristic_value_packet(const gatt_client_t *gatt_client, uint8_t type, uint16_t attribute_handle, 102601e6dd7fSMatthias Ringwald uint8_t *value, uint16_t length, uint16_t service_id, uint16_t connection_id) { 102723d583b8SMatthias Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 102823d583b8SMatthias Ringwald // copy value into test packet for testing 102923d583b8SMatthias Ringwald static uint8_t packet[1000]; 1030f51e6883SMatthias Ringwald memcpy(&packet[CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE], value, length); 103123d583b8SMatthias Ringwald #else 103223d583b8SMatthias Ringwald // before the value inside the ATT PDU 103323d583b8SMatthias Ringwald uint8_t * packet = value - CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE; 103423d583b8SMatthias Ringwald #endif 103523d583b8SMatthias Ringwald packet[0] = type; 103623d583b8SMatthias Ringwald packet[1] = CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE - 2 + length; 10378450fbf5SMatthias Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 103801e6dd7fSMatthias Ringwald little_endian_store_16(packet, 4, service_id); 103901e6dd7fSMatthias Ringwald little_endian_store_16(packet, 6, connection_id); 1040f6a28e25SMatthias Ringwald little_endian_store_16(packet, 8, attribute_handle); 1041f6a28e25SMatthias Ringwald little_endian_store_16(packet, 10, length); 104223d583b8SMatthias Ringwald return packet; 104323d583b8SMatthias Ringwald } 104423d583b8SMatthias Ringwald 104523d583b8SMatthias Ringwald // @return packet pointer 1046b641e2afSMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite HCI + L2CAP packet headers + 6 pre_buffer bytes 1047b641e2afSMatthias Ringwald #define LONG_CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE 14 1048f51e6883SMatthias Ringwald 1049f51e6883SMatthias Ringwald // L2CAP Header (4) + ACL Header (4) => 8 bytes 1050f51e6883SMatthias Ringwald #if !defined(HCI_INCOMING_PRE_BUFFER_SIZE) || ((HCI_INCOMING_PRE_BUFFER_SIZE < LONG_CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE - 8)) 1051f51e6883SMatthias Ringwald #error "Long Characteristic reads requires HCI_INCOMING_PRE_BUFFER_SIZE >= 2" 1052f51e6883SMatthias Ringwald #endif 1053f51e6883SMatthias Ringwald 10543e78e462SMatthias Ringwald static uint8_t * 10553e78e462SMatthias Ringwald setup_long_characteristic_value_packet(const gatt_client_t *gatt_client, uint8_t type, uint16_t attribute_handle, 10563e78e462SMatthias Ringwald uint16_t offset, uint8_t *value, uint16_t length) { 105723d583b8SMatthias Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 105823d583b8SMatthias Ringwald // avoid using pre ATT headers. 1059464b6e7bSMatthias Ringwald // copy value into test packet for testing 1060464b6e7bSMatthias Ringwald static uint8_t packet[1000]; 1061464b6e7bSMatthias Ringwald memcpy(&packet[LONG_CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE], value, length); 1062464b6e7bSMatthias Ringwald #else 106323d583b8SMatthias Ringwald // before the value inside the ATT PDU 106423d583b8SMatthias Ringwald uint8_t * packet = value - LONG_CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE; 1065464b6e7bSMatthias Ringwald #endif 106623d583b8SMatthias Ringwald packet[0] = type; 106723d583b8SMatthias Ringwald packet[1] = LONG_CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE - 2 + length; 10683e78e462SMatthias Ringwald little_endian_store_16(packet, 2, gatt_client->con_handle); 1069b641e2afSMatthias Ringwald little_endian_store_16(packet, 4, gatt_client->service_id); 1070b641e2afSMatthias Ringwald little_endian_store_16(packet, 6, gatt_client->connection_id); 1071b641e2afSMatthias Ringwald little_endian_store_16(packet, 8, attribute_handle); 1072b641e2afSMatthias Ringwald little_endian_store_16(packet, 10, offset); 1073b641e2afSMatthias Ringwald little_endian_store_16(packet, 12, length); 107423d583b8SMatthias Ringwald return packet; 107523d583b8SMatthias Ringwald } 107623d583b8SMatthias Ringwald 1077f7a42e72SMatthias Ringwald #if (LONG_CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE > CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE) 1078f7a42e72SMatthias Ringwald #define REPORT_PREBUFFER_HEADER LONG_CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE 1079f7a42e72SMatthias Ringwald #else 1080f7a42e72SMatthias Ringwald #define REPORT_PREBUFFER_HEADER CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE 1081f7a42e72SMatthias Ringwald #endif 1082f7a42e72SMatthias Ringwald 10838f37572aSJakob Krantz /// 10845cf1669fSMatthias Ringwald static void report_gatt_services(gatt_client_t * gatt_client, uint8_t * packet, uint16_t size){ 108539ac9711SMatthias Ringwald if (size < 2) return; 10863deb3ec6SMatthias Ringwald uint8_t attr_length = packet[1]; 10874ea43905SMatthias Ringwald uint8_t uuid_length = attr_length - 4u; 10883deb3ec6SMatthias Ringwald 10893deb3ec6SMatthias Ringwald int i; 109039ac9711SMatthias Ringwald for (i = 2; (i+attr_length) <= size; i += attr_length){ 1091f8fbdce0SMatthias Ringwald uint16_t start_group_handle = little_endian_read_16(packet,i); 1092f8fbdce0SMatthias Ringwald uint16_t end_group_handle = little_endian_read_16(packet,i+2); 10933deb3ec6SMatthias Ringwald uint8_t uuid128[16]; 10943deb3ec6SMatthias Ringwald uint16_t uuid16 = 0; 10953deb3ec6SMatthias Ringwald 10964ea43905SMatthias Ringwald if (uuid_length == 2u){ 1097f8fbdce0SMatthias Ringwald uuid16 = little_endian_read_16(packet, i+4); 1098e1a125dfSMatthias Ringwald uuid_add_bluetooth_prefix((uint8_t*) &uuid128, uuid16); 109939ac9711SMatthias Ringwald } else if (uuid_length == 16u) { 11009c80e4ccSMatthias Ringwald reverse_128(&packet[i+4], uuid128); 110139ac9711SMatthias Ringwald } else { 110239ac9711SMatthias Ringwald return; 11033deb3ec6SMatthias Ringwald } 11045cf1669fSMatthias Ringwald emit_gatt_service_query_result_event(gatt_client, start_group_handle, end_group_handle, uuid128); 11053deb3ec6SMatthias Ringwald } 11063deb3ec6SMatthias Ringwald } 11073deb3ec6SMatthias Ringwald 110823d583b8SMatthias Ringwald static void report_gatt_characteristic_start_found(gatt_client_t * gatt_client, uint16_t start_handle, uint8_t properties, uint16_t value_handle, uint8_t * uuid, uint16_t uuid_length){ 11093deb3ec6SMatthias Ringwald uint8_t uuid128[16]; 11103deb3ec6SMatthias Ringwald uint16_t uuid16 = 0; 11114ea43905SMatthias Ringwald if (uuid_length == 2u){ 1112f8fbdce0SMatthias Ringwald uuid16 = little_endian_read_16(uuid, 0); 1113e1a125dfSMatthias Ringwald uuid_add_bluetooth_prefix((uint8_t*) uuid128, uuid16); 11144ea43905SMatthias Ringwald } else if (uuid_length == 16u){ 11159c80e4ccSMatthias Ringwald reverse_128(uuid, uuid128); 1116d73c9dbeSMilanka Ringwald } else { 1117d73c9dbeSMilanka Ringwald return; 11183deb3ec6SMatthias Ringwald } 11193deb3ec6SMatthias Ringwald 11205cf1669fSMatthias Ringwald if (gatt_client->filter_with_uuid && (memcmp(gatt_client->uuid128, uuid128, 16) != 0)) return; 11213deb3ec6SMatthias Ringwald 11225cf1669fSMatthias Ringwald gatt_client->characteristic_properties = properties; 11235cf1669fSMatthias Ringwald gatt_client->characteristic_start_handle = start_handle; 11245cf1669fSMatthias Ringwald gatt_client->attribute_handle = value_handle; 11253deb3ec6SMatthias Ringwald 11265cf1669fSMatthias Ringwald if (gatt_client->filter_with_uuid) return; 11273deb3ec6SMatthias Ringwald 11285cf1669fSMatthias Ringwald gatt_client->uuid16 = uuid16; 11295cf1669fSMatthias Ringwald (void)memcpy(gatt_client->uuid128, uuid128, 16); 11303deb3ec6SMatthias Ringwald } 11313deb3ec6SMatthias Ringwald 113223d583b8SMatthias Ringwald static void report_gatt_characteristic_end_found(gatt_client_t * gatt_client, uint16_t end_handle){ 11333deb3ec6SMatthias Ringwald // TODO: stop searching if filter and uuid found 11343deb3ec6SMatthias Ringwald 11355cf1669fSMatthias Ringwald if (!gatt_client->characteristic_start_handle) return; 11363deb3ec6SMatthias Ringwald 11375cf1669fSMatthias Ringwald emit_gatt_characteristic_query_result_event(gatt_client, gatt_client->characteristic_start_handle, gatt_client->attribute_handle, 11385cf1669fSMatthias Ringwald end_handle, gatt_client->characteristic_properties, gatt_client->uuid128); 11393deb3ec6SMatthias Ringwald 11405cf1669fSMatthias Ringwald gatt_client->characteristic_start_handle = 0; 11413deb3ec6SMatthias Ringwald } 11423deb3ec6SMatthias Ringwald 114323d583b8SMatthias Ringwald 11445cf1669fSMatthias Ringwald static void report_gatt_characteristics(gatt_client_t * gatt_client, uint8_t * packet, uint16_t size){ 11454ea43905SMatthias Ringwald if (size < 2u) return; 11463deb3ec6SMatthias Ringwald uint8_t attr_length = packet[1]; 11474ea43905SMatthias Ringwald if ((attr_length != 7u) && (attr_length != 21u)) return; 11484ea43905SMatthias Ringwald uint8_t uuid_length = attr_length - 5u; 11493deb3ec6SMatthias Ringwald int i; 11504ea43905SMatthias Ringwald for (i = 2u; (i + attr_length) <= size; i += attr_length){ 1151f8fbdce0SMatthias Ringwald uint16_t start_handle = little_endian_read_16(packet, i); 11523deb3ec6SMatthias Ringwald uint8_t properties = packet[i+2]; 1153f8fbdce0SMatthias Ringwald uint16_t value_handle = little_endian_read_16(packet, i+3); 115423d583b8SMatthias Ringwald report_gatt_characteristic_end_found(gatt_client, start_handle - 1u); 115523d583b8SMatthias Ringwald report_gatt_characteristic_start_found(gatt_client, start_handle, properties, value_handle, &packet[i + 5], 115623d583b8SMatthias Ringwald uuid_length); 11573deb3ec6SMatthias Ringwald } 11583deb3ec6SMatthias Ringwald } 11593deb3ec6SMatthias Ringwald 11605cf1669fSMatthias Ringwald static void report_gatt_included_service_uuid16(gatt_client_t * gatt_client, uint16_t include_handle, uint16_t uuid16){ 11613deb3ec6SMatthias Ringwald uint8_t normalized_uuid128[16]; 1162e1a125dfSMatthias Ringwald uuid_add_bluetooth_prefix(normalized_uuid128, uuid16); 11635cf1669fSMatthias Ringwald emit_gatt_included_service_query_result_event(gatt_client, include_handle, gatt_client->query_start_handle, 11645cf1669fSMatthias Ringwald gatt_client->query_end_handle, normalized_uuid128); 11653deb3ec6SMatthias Ringwald } 11663deb3ec6SMatthias Ringwald 1167045d700dSDavid Lechner static void report_gatt_included_service_uuid128(gatt_client_t * gatt_client, uint16_t include_handle, const uint8_t * uuid128){ 11685cf1669fSMatthias Ringwald emit_gatt_included_service_query_result_event(gatt_client, include_handle, gatt_client->query_start_handle, 11695cf1669fSMatthias Ringwald gatt_client->query_end_handle, uuid128); 11703deb3ec6SMatthias Ringwald } 11713deb3ec6SMatthias Ringwald 1172d03dbc9cSMatthias Ringwald static void report_gatt_characteristic_value_change(gatt_client_t *gatt_client, uint8_t event_type, uint16_t value_handle, uint8_t *value, int length) { 11731a4874dcSMatthias Ringwald uint8_t * packet; 11742c937a66SMatthias Ringwald 11751a4874dcSMatthias Ringwald // Single Characteristic listener, setup packet with service + connection id = 0 11761a4874dcSMatthias Ringwald packet = setup_characteristic_value_packet(gatt_client, event_type, value_handle, value, length, 0, 0); 11772c937a66SMatthias Ringwald btstack_linked_list_iterator_t it; 11782c937a66SMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client_value_listeners); 11792c937a66SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)) { 11802c937a66SMatthias Ringwald gatt_client_notification_t *notification = (gatt_client_notification_t *) btstack_linked_list_iterator_next(&it); 11812c937a66SMatthias Ringwald if ((notification->con_handle != GATT_CLIENT_ANY_CONNECTION) && (notification->con_handle != gatt_client->con_handle)) continue; 11822c937a66SMatthias Ringwald if ((notification->attribute_handle != GATT_CLIENT_ANY_VALUE_HANDLE) && (notification->attribute_handle != value_handle)) continue; 11831a4874dcSMatthias Ringwald 11841a4874dcSMatthias Ringwald (*notification->callback)(HCI_EVENT_PACKET, 0, packet, CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE + length); 11851a4874dcSMatthias Ringwald } 11861a4874dcSMatthias Ringwald 11871a4874dcSMatthias Ringwald // Service characteristics 11881a4874dcSMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client_service_value_listeners); 11891a4874dcSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 11901a4874dcSMatthias Ringwald const gatt_client_service_notification_t * notification = (gatt_client_service_notification_t*) btstack_linked_list_iterator_next(&it); 11911a4874dcSMatthias Ringwald if (notification->con_handle != gatt_client->con_handle) continue; 11921a4874dcSMatthias Ringwald if (notification->start_group_handle > value_handle) continue; 11931a4874dcSMatthias Ringwald if (notification->end_group_handle < value_handle) continue; 11941a4874dcSMatthias Ringwald // (re)setup value packet with service and connection id (to avoid patching event later) 11951a4874dcSMatthias Ringwald packet = setup_characteristic_value_packet(gatt_client, event_type, value_handle, value, length, notification->service_id, notification->connection_id); 11962c937a66SMatthias Ringwald (*notification->callback)(HCI_EVENT_PACKET, 0, packet, CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE + length); 11972c937a66SMatthias Ringwald } 1198d03dbc9cSMatthias Ringwald } 1199d03dbc9cSMatthias Ringwald 12003deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes 12010fde3c5eSMatthias Ringwald static void report_gatt_notification(gatt_client_t *gatt_client, uint16_t value_handle, uint8_t *value, int length) { 12020fde3c5eSMatthias Ringwald if (!gatt_client_accept_server_message(gatt_client)) return; 1203d03dbc9cSMatthias Ringwald report_gatt_characteristic_value_change(gatt_client, GATT_EVENT_NOTIFICATION, value_handle, value, length); 12043deb3ec6SMatthias Ringwald } 12053deb3ec6SMatthias Ringwald 12063deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes 12070fde3c5eSMatthias Ringwald static void report_gatt_indication(gatt_client_t *gatt_client, uint16_t value_handle, uint8_t *value, int length) { 12080fde3c5eSMatthias Ringwald if (!gatt_client_accept_server_message(gatt_client)) return; 1209842492f0SMatthias Ringwald #ifdef ENABLE_GATT_CLIENT_SERVICE_CHANGED 121058e8c9f5SMatthias Ringwald // Directly Handle GATT Service Changed and Database Hash indications 121158e8c9f5SMatthias Ringwald if (value_handle == gatt_client->gatt_service_database_hash_value_handle){ 121258e8c9f5SMatthias Ringwald gatt_client_service_emit_database_hash(gatt_client, value, length); 121358e8c9f5SMatthias Ringwald } 121458e8c9f5SMatthias Ringwald if (value_handle == gatt_client->gatt_service_changed_value_handle){ 121558e8c9f5SMatthias Ringwald gatt_client_service_emit_service_changed(gatt_client, value, length); 121658e8c9f5SMatthias Ringwald } 1217842492f0SMatthias Ringwald #endif 1218d03dbc9cSMatthias Ringwald report_gatt_characteristic_value_change(gatt_client, GATT_EVENT_INDICATION, value_handle, value, length); 12193deb3ec6SMatthias Ringwald } 12203deb3ec6SMatthias Ringwald 12213deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes 12225cf1669fSMatthias Ringwald static void report_gatt_characteristic_value(gatt_client_t * gatt_client, uint16_t attribute_handle, uint8_t * value, uint16_t length){ 12238450fbf5SMatthias Ringwald uint8_t * packet = setup_characteristic_value_packet( 122401e6dd7fSMatthias Ringwald gatt_client, GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT, attribute_handle, value, length, gatt_client->service_id, gatt_client->connection_id); 122523d583b8SMatthias Ringwald emit_event_new(gatt_client->callback, packet, CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE + length); 12263deb3ec6SMatthias Ringwald } 12273deb3ec6SMatthias Ringwald 12283deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes 12295cf1669fSMatthias Ringwald static void report_gatt_long_characteristic_value_blob(gatt_client_t * gatt_client, uint16_t attribute_handle, uint8_t * blob, uint16_t blob_length, int value_offset){ 12303e78e462SMatthias Ringwald uint8_t * packet = setup_long_characteristic_value_packet(gatt_client, 12313e78e462SMatthias Ringwald GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT, 12323e78e462SMatthias Ringwald attribute_handle, value_offset, 12333e78e462SMatthias Ringwald blob, blob_length); 123423d583b8SMatthias Ringwald emit_event_new(gatt_client->callback, packet, blob_length + LONG_CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE); 12353deb3ec6SMatthias Ringwald } 12363deb3ec6SMatthias Ringwald 12375cf1669fSMatthias Ringwald static void report_gatt_characteristic_descriptor(gatt_client_t * gatt_client, uint16_t descriptor_handle, uint8_t *value, uint16_t value_length, uint16_t value_offset){ 12389ec2630cSMatthias Ringwald UNUSED(value_offset); 12398450fbf5SMatthias Ringwald uint8_t * packet = setup_characteristic_value_packet(gatt_client, GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT, 12408450fbf5SMatthias Ringwald descriptor_handle, value, 124101e6dd7fSMatthias Ringwald value_length, gatt_client->service_id, gatt_client->connection_id); 12425cf1669fSMatthias Ringwald emit_event_new(gatt_client->callback, packet, value_length + 8u); 12433deb3ec6SMatthias Ringwald } 12443deb3ec6SMatthias Ringwald 12455cf1669fSMatthias Ringwald static void report_gatt_long_characteristic_descriptor(gatt_client_t * gatt_client, uint16_t descriptor_handle, uint8_t *blob, uint16_t blob_length, uint16_t value_offset){ 12463e78e462SMatthias Ringwald uint8_t * packet = setup_long_characteristic_value_packet(gatt_client, 12473e78e462SMatthias Ringwald GATT_EVENT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT, 12483e78e462SMatthias Ringwald descriptor_handle, value_offset, 12493e78e462SMatthias Ringwald blob, blob_length); 125023d583b8SMatthias Ringwald emit_event_new(gatt_client->callback, packet, blob_length + LONG_CHARACTERISTIC_VALUE_EVENT_HEADER_SIZE); 12513deb3ec6SMatthias Ringwald } 12523deb3ec6SMatthias Ringwald 12535cf1669fSMatthias Ringwald static void report_gatt_all_characteristic_descriptors(gatt_client_t * gatt_client, uint8_t * packet, uint16_t size, uint16_t pair_size){ 12543deb3ec6SMatthias Ringwald int i; 12554ea43905SMatthias Ringwald for (i = 0u; (i + pair_size) <= size; i += pair_size){ 1256f8fbdce0SMatthias Ringwald uint16_t descriptor_handle = little_endian_read_16(packet,i); 12573deb3ec6SMatthias Ringwald uint8_t uuid128[16]; 12583deb3ec6SMatthias Ringwald uint16_t uuid16 = 0; 12594ea43905SMatthias Ringwald if (pair_size == 4u){ 1260f8fbdce0SMatthias Ringwald uuid16 = little_endian_read_16(packet,i+2); 1261e1a125dfSMatthias Ringwald uuid_add_bluetooth_prefix(uuid128, uuid16); 12623deb3ec6SMatthias Ringwald } else { 12639c80e4ccSMatthias Ringwald reverse_128(&packet[i+2], uuid128); 12643deb3ec6SMatthias Ringwald } 12655cf1669fSMatthias Ringwald emit_gatt_all_characteristic_descriptors_result_event(gatt_client, descriptor_handle, uuid128); 12663deb3ec6SMatthias Ringwald } 12673deb3ec6SMatthias Ringwald 12683deb3ec6SMatthias Ringwald } 12693deb3ec6SMatthias Ringwald 127052377058SMatthias Ringwald static bool is_query_done(gatt_client_t * gatt_client, uint16_t last_result_handle){ 12715cf1669fSMatthias Ringwald return last_result_handle >= gatt_client->end_group_handle; 12723deb3ec6SMatthias Ringwald } 12733deb3ec6SMatthias Ringwald 12745cf1669fSMatthias Ringwald static void trigger_next_query(gatt_client_t * gatt_client, uint16_t last_result_handle, gatt_client_state_t next_query_state){ 12755cf1669fSMatthias Ringwald if (is_query_done(gatt_client, last_result_handle)){ 1276526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 12773deb3ec6SMatthias Ringwald return; 12783deb3ec6SMatthias Ringwald } 12793deb3ec6SMatthias Ringwald // next 12805cf1669fSMatthias Ringwald gatt_client->start_group_handle = last_result_handle + 1u; 1281052dc82aSMatthias Ringwald gatt_client->state = next_query_state; 12823deb3ec6SMatthias Ringwald } 12833deb3ec6SMatthias Ringwald 12845cf1669fSMatthias Ringwald static void trigger_next_included_service_query(gatt_client_t * gatt_client, uint16_t last_result_handle){ 12855cf1669fSMatthias Ringwald trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_INCLUDED_SERVICE_QUERY); 12863deb3ec6SMatthias Ringwald } 12873deb3ec6SMatthias Ringwald 12885cf1669fSMatthias Ringwald static void trigger_next_service_query(gatt_client_t * gatt_client, uint16_t last_result_handle){ 12895cf1669fSMatthias Ringwald trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_SERVICE_QUERY); 12903deb3ec6SMatthias Ringwald } 12913deb3ec6SMatthias Ringwald 12925cf1669fSMatthias Ringwald static void trigger_next_service_by_uuid_query(gatt_client_t * gatt_client, uint16_t last_result_handle){ 12935cf1669fSMatthias Ringwald trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_SERVICE_WITH_UUID_QUERY); 12943deb3ec6SMatthias Ringwald } 12953deb3ec6SMatthias Ringwald 12965cf1669fSMatthias Ringwald static void trigger_next_characteristic_query(gatt_client_t * gatt_client, uint16_t last_result_handle){ 12975cf1669fSMatthias Ringwald if (is_query_done(gatt_client, last_result_handle)){ 12983deb3ec6SMatthias Ringwald // report last characteristic 129923d583b8SMatthias Ringwald report_gatt_characteristic_end_found(gatt_client, gatt_client->end_group_handle); 13003deb3ec6SMatthias Ringwald } 13015cf1669fSMatthias Ringwald trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY); 13023deb3ec6SMatthias Ringwald } 13033deb3ec6SMatthias Ringwald 13045cf1669fSMatthias Ringwald static void trigger_next_characteristic_descriptor_query(gatt_client_t * gatt_client, uint16_t last_result_handle){ 13055cf1669fSMatthias Ringwald trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY); 13063deb3ec6SMatthias Ringwald } 13073deb3ec6SMatthias Ringwald 13085cf1669fSMatthias Ringwald static void trigger_next_read_by_type_query(gatt_client_t * gatt_client, uint16_t last_result_handle){ 13095cf1669fSMatthias Ringwald trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_READ_BY_TYPE_REQUEST); 13103deb3ec6SMatthias Ringwald } 13113deb3ec6SMatthias Ringwald 13125cf1669fSMatthias Ringwald static void trigger_next_prepare_write_query(gatt_client_t * gatt_client, gatt_client_state_t next_query_state, gatt_client_state_t done_state){ 13135cf1669fSMatthias Ringwald gatt_client->attribute_offset += write_blob_length(gatt_client); 13145cf1669fSMatthias Ringwald uint16_t next_blob_length = write_blob_length(gatt_client); 13153deb3ec6SMatthias Ringwald 13164ea43905SMatthias Ringwald if (next_blob_length == 0u){ 1317052dc82aSMatthias Ringwald gatt_client->state = done_state; 13183deb3ec6SMatthias Ringwald return; 13193deb3ec6SMatthias Ringwald } 1320052dc82aSMatthias Ringwald gatt_client->state = next_query_state; 13213deb3ec6SMatthias Ringwald } 13223deb3ec6SMatthias Ringwald 13235cf1669fSMatthias Ringwald static void trigger_next_blob_query(gatt_client_t * gatt_client, gatt_client_state_t next_query_state, uint16_t received_blob_length){ 13243deb3ec6SMatthias Ringwald 1325dda77937SMatthias Ringwald uint16_t max_blob_length = gatt_client->mtu - 1u; 13263deb3ec6SMatthias Ringwald if (received_blob_length < max_blob_length){ 1327526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 13283deb3ec6SMatthias Ringwald return; 13293deb3ec6SMatthias Ringwald } 13303deb3ec6SMatthias Ringwald 13315cf1669fSMatthias Ringwald gatt_client->attribute_offset += received_blob_length; 1332052dc82aSMatthias Ringwald gatt_client->state = next_query_state; 13333deb3ec6SMatthias Ringwald } 13343deb3ec6SMatthias Ringwald 133523d583b8SMatthias Ringwald void gatt_client_listen_for_characteristic_value_updates(gatt_client_notification_t * notification, btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){ 133623d583b8SMatthias Ringwald notification->callback = callback; 133723d583b8SMatthias Ringwald notification->con_handle = con_handle; 133823d583b8SMatthias Ringwald if (characteristic == NULL){ 133923d583b8SMatthias Ringwald notification->attribute_handle = GATT_CLIENT_ANY_VALUE_HANDLE; 134023d583b8SMatthias Ringwald } else { 134123d583b8SMatthias Ringwald notification->attribute_handle = characteristic->value_handle; 134223d583b8SMatthias Ringwald } 134323d583b8SMatthias Ringwald btstack_linked_list_add(&gatt_client_value_listeners, (btstack_linked_item_t*) notification); 134423d583b8SMatthias Ringwald } 134523d583b8SMatthias Ringwald 134623d583b8SMatthias Ringwald void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){ 134723d583b8SMatthias Ringwald btstack_linked_list_remove(&gatt_client_value_listeners, (btstack_linked_item_t*) notification); 134823d583b8SMatthias Ringwald } 13493deb3ec6SMatthias Ringwald 13501a4874dcSMatthias Ringwald void gatt_client_listen_for_service_characteristic_value_updates(gatt_client_service_notification_t * notification, 13511a4874dcSMatthias Ringwald btstack_packet_handler_t callback, 13521a4874dcSMatthias Ringwald hci_con_handle_t con_handle, 13531a4874dcSMatthias Ringwald gatt_client_service_t * service, 13541a4874dcSMatthias Ringwald uint16_t service_id, 13551a4874dcSMatthias Ringwald uint16_t connection_id){ 13561a4874dcSMatthias Ringwald notification->callback = callback; 13571a4874dcSMatthias Ringwald notification->con_handle = con_handle; 13581a4874dcSMatthias Ringwald notification->start_group_handle = service->start_group_handle; 13591a4874dcSMatthias Ringwald notification->end_group_handle = service->end_group_handle; 13601a4874dcSMatthias Ringwald notification->service_id = 0; 13611a4874dcSMatthias Ringwald notification->connection_id = 0; 13621a4874dcSMatthias Ringwald btstack_linked_list_add(&gatt_client_value_listeners, (btstack_linked_item_t*) notification); 1363*fd01917fSMatthias Ringwald } 13641a4874dcSMatthias Ringwald 13651a4874dcSMatthias Ringwald /** 13661a4874dcSMatthias Ringwald * @brief Stop listening to characteristic value updates for registered service with 13671a4874dcSMatthias Ringwald * the gatt_client_listen_for_characteristic_value_updates function. 13681a4874dcSMatthias Ringwald * @param notification struct used in gatt_client_listen_for_characteristic_value_updates 13691a4874dcSMatthias Ringwald */ 13701a4874dcSMatthias Ringwald void gatt_client_stop_listening_for_service_characteristic_value_updates(gatt_client_service_notification_t * notification){ 13711a4874dcSMatthias Ringwald btstack_linked_list_remove(&gatt_client_service_value_listeners, (btstack_linked_item_t*) notification); 13721a4874dcSMatthias Ringwald } 13731a4874dcSMatthias Ringwald 137462f7b41dSMatthias Ringwald static bool is_value_valid(gatt_client_t *gatt_client, uint8_t *packet, uint16_t size){ 1375f8fbdce0SMatthias Ringwald uint16_t attribute_handle = little_endian_read_16(packet, 1); 1376f8fbdce0SMatthias Ringwald uint16_t value_offset = little_endian_read_16(packet, 3); 13773deb3ec6SMatthias Ringwald 137862f7b41dSMatthias Ringwald if (gatt_client->attribute_handle != attribute_handle) return false; 137962f7b41dSMatthias Ringwald if (gatt_client->attribute_offset != value_offset) return false; 13805cf1669fSMatthias Ringwald return memcmp(&gatt_client->attribute_value[gatt_client->attribute_offset], &packet[5], size - 5u) == 0u; 13813deb3ec6SMatthias Ringwald } 13823deb3ec6SMatthias Ringwald 13830038504eSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE 138492a7335eSMatthias Ringwald static void gatt_client_run_for_client_start_signed_write(gatt_client_t *gatt_client) { 138592a7335eSMatthias Ringwald sm_key_t csrk; 138692a7335eSMatthias Ringwald le_device_db_local_csrk_get(gatt_client->le_device_index, csrk); 138792a7335eSMatthias Ringwald uint32_t sign_counter = le_device_db_local_counter_get(gatt_client->le_device_index); 1388052dc82aSMatthias Ringwald gatt_client->state = P_W4_CMAC_RESULT; 138992a7335eSMatthias Ringwald sm_cmac_signed_write_start(csrk, ATT_SIGNED_WRITE_COMMAND, gatt_client->attribute_handle, gatt_client->attribute_length, gatt_client->attribute_value, sign_counter, att_signed_write_handle_cmac_result); 139092a7335eSMatthias Ringwald } 13910038504eSMatthias Ringwald #endif 139292a7335eSMatthias Ringwald 139392a7335eSMatthias Ringwald // returns true if packet was sent 13941979f09cSMatthias Ringwald static bool gatt_client_run_for_gatt_client(gatt_client_t * gatt_client){ 13953deb3ec6SMatthias Ringwald 1396e4d159baSMatthias Ringwald // wait until re-encryption is complete 13971979f09cSMatthias Ringwald if (gap_reconnect_security_setup_active(gatt_client->con_handle)) return false; 1398d1e1a57fSMatthias Ringwald 1399e4d159baSMatthias Ringwald // wait until re-encryption is complete 14001979f09cSMatthias Ringwald if (gatt_client->reencryption_active) return false; 14016c124bc2SMatthias Ringwald 140211279da7SMatthias Ringwald // wait until pairing complete (either reactive authentication or due to required security level) 14031979f09cSMatthias Ringwald if (gatt_client->wait_for_authentication_complete) return false; 140411279da7SMatthias Ringwald 1405052dc82aSMatthias Ringwald bool client_request_pending = gatt_client->state != P_READY; 1406fd14b205SMatthias Ringwald 14071aa9e3e8SMatthias Ringwald // verify security level for Mandatory Authentication over LE 140846012949SMatthias Ringwald bool check_security; 140946012949SMatthias Ringwald switch (gatt_client->bearer_type){ 141046012949SMatthias Ringwald case ATT_BEARER_UNENHANCED_LE: 141146012949SMatthias Ringwald check_security = true; 141246012949SMatthias Ringwald break; 141346012949SMatthias Ringwald default: 14149ced96e1SMatthias Ringwald check_security = false; 141546012949SMatthias Ringwald break; 14169ced96e1SMatthias Ringwald } 14179ced96e1SMatthias Ringwald if (client_request_pending && (gatt_client_required_security_level > gatt_client->security_level) && check_security){ 14181dfae9c7SMatthias Ringwald log_info("Trigger pairing, current security level %u, required %u\n", gatt_client->security_level, gatt_client_required_security_level); 14192197dbafSMatthias Ringwald gatt_client->wait_for_authentication_complete = true; 142011279da7SMatthias Ringwald // set att error code for pairing failure based on required level 142111279da7SMatthias Ringwald switch (gatt_client_required_security_level){ 142211279da7SMatthias Ringwald case LEVEL_4: 142311279da7SMatthias Ringwald case LEVEL_3: 142411279da7SMatthias Ringwald gatt_client->pending_error_code = ATT_ERROR_INSUFFICIENT_AUTHENTICATION; 142511279da7SMatthias Ringwald break; 142611279da7SMatthias Ringwald default: 142711279da7SMatthias Ringwald gatt_client->pending_error_code = ATT_ERROR_INSUFFICIENT_ENCRYPTION; 142811279da7SMatthias Ringwald break; 142911279da7SMatthias Ringwald } 143011279da7SMatthias Ringwald sm_request_pairing(gatt_client->con_handle); 143111279da7SMatthias Ringwald // sm probably just sent a pdu 14321979f09cSMatthias Ringwald return true; 143311279da7SMatthias Ringwald } 1434f4b33574SMatthias Ringwald 14355cf1669fSMatthias Ringwald switch (gatt_client->mtu_state) { 1436544128c3SMatthias Ringwald case SEND_MTU_EXCHANGE: 14375cf1669fSMatthias Ringwald gatt_client->mtu_state = SENT_MTU_EXCHANGE; 14386e7b444cSMatthias Ringwald att_exchange_mtu_request(gatt_client); 14391979f09cSMatthias Ringwald return true; 14403deb3ec6SMatthias Ringwald case SENT_MTU_EXCHANGE: 14411979f09cSMatthias Ringwald return false; 14423deb3ec6SMatthias Ringwald default: 14433deb3ec6SMatthias Ringwald break; 14443deb3ec6SMatthias Ringwald } 14453deb3ec6SMatthias Ringwald 14465cf1669fSMatthias Ringwald if (gatt_client->send_confirmation){ 144752377058SMatthias Ringwald gatt_client->send_confirmation = false; 14486e7b444cSMatthias Ringwald att_confirmation(gatt_client); 14491979f09cSMatthias Ringwald return true; 14503deb3ec6SMatthias Ringwald } 14513deb3ec6SMatthias Ringwald 14523deb3ec6SMatthias Ringwald // check MTU for writes 1453052dc82aSMatthias Ringwald switch (gatt_client->state){ 14543deb3ec6SMatthias Ringwald case P_W2_SEND_WRITE_CHARACTERISTIC_VALUE: 14553deb3ec6SMatthias Ringwald case P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR: 1456dda77937SMatthias Ringwald if (gatt_client->attribute_length <= (gatt_client->mtu - 3u)) break; 1457dda77937SMatthias Ringwald log_error("gatt_client_run: value len %u > MTU %u - 3\n", gatt_client->attribute_length,gatt_client->mtu); 1458526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH); 14591979f09cSMatthias Ringwald return false; 14603deb3ec6SMatthias Ringwald default: 14613deb3ec6SMatthias Ringwald break; 14623deb3ec6SMatthias Ringwald } 14633deb3ec6SMatthias Ringwald 14640038504eSMatthias Ringwald bool packet_sent = true; 14650038504eSMatthias Ringwald bool done = true; 1466052dc82aSMatthias Ringwald switch (gatt_client->state){ 14673deb3ec6SMatthias Ringwald case P_W2_SEND_SERVICE_QUERY: 1468052dc82aSMatthias Ringwald gatt_client->state = P_W4_SERVICE_QUERY_RESULT; 14695cf1669fSMatthias Ringwald send_gatt_services_request(gatt_client); 14700038504eSMatthias Ringwald break; 14713deb3ec6SMatthias Ringwald 14723deb3ec6SMatthias Ringwald case P_W2_SEND_SERVICE_WITH_UUID_QUERY: 1473052dc82aSMatthias Ringwald gatt_client->state = P_W4_SERVICE_WITH_UUID_RESULT; 14745cf1669fSMatthias Ringwald send_gatt_services_by_uuid_request(gatt_client); 14750038504eSMatthias Ringwald break; 14763deb3ec6SMatthias Ringwald 14773deb3ec6SMatthias Ringwald case P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY: 1478052dc82aSMatthias Ringwald gatt_client->state = P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT; 14795cf1669fSMatthias Ringwald send_gatt_characteristic_request(gatt_client); 14800038504eSMatthias Ringwald break; 14813deb3ec6SMatthias Ringwald 14823deb3ec6SMatthias Ringwald case P_W2_SEND_CHARACTERISTIC_WITH_UUID_QUERY: 1483052dc82aSMatthias Ringwald gatt_client->state = P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT; 14845cf1669fSMatthias Ringwald send_gatt_characteristic_request(gatt_client); 14850038504eSMatthias Ringwald break; 14863deb3ec6SMatthias Ringwald 14873deb3ec6SMatthias Ringwald case P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY: 1488052dc82aSMatthias Ringwald gatt_client->state = P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT; 14895cf1669fSMatthias Ringwald send_gatt_characteristic_descriptor_request(gatt_client); 14900038504eSMatthias Ringwald break; 14913deb3ec6SMatthias Ringwald 14923deb3ec6SMatthias Ringwald case P_W2_SEND_INCLUDED_SERVICE_QUERY: 1493052dc82aSMatthias Ringwald gatt_client->state = P_W4_INCLUDED_SERVICE_QUERY_RESULT; 14945cf1669fSMatthias Ringwald send_gatt_included_service_request(gatt_client); 14950038504eSMatthias Ringwald break; 14963deb3ec6SMatthias Ringwald 14973deb3ec6SMatthias Ringwald case P_W2_SEND_INCLUDED_SERVICE_WITH_UUID_QUERY: 1498052dc82aSMatthias Ringwald gatt_client->state = P_W4_INCLUDED_SERVICE_UUID_WITH_QUERY_RESULT; 14995cf1669fSMatthias Ringwald send_gatt_included_service_uuid_request(gatt_client); 15000038504eSMatthias Ringwald break; 15013deb3ec6SMatthias Ringwald 15023deb3ec6SMatthias Ringwald case P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY: 1503052dc82aSMatthias Ringwald gatt_client->state = P_W4_READ_CHARACTERISTIC_VALUE_RESULT; 15045cf1669fSMatthias Ringwald send_gatt_read_characteristic_value_request(gatt_client); 15050038504eSMatthias Ringwald break; 15063deb3ec6SMatthias Ringwald 15073deb3ec6SMatthias Ringwald case P_W2_SEND_READ_BLOB_QUERY: 1508052dc82aSMatthias Ringwald gatt_client->state = P_W4_READ_BLOB_RESULT; 15095cf1669fSMatthias Ringwald send_gatt_read_blob_request(gatt_client); 15100038504eSMatthias Ringwald break; 15113deb3ec6SMatthias Ringwald 15123deb3ec6SMatthias Ringwald case P_W2_SEND_READ_BY_TYPE_REQUEST: 1513052dc82aSMatthias Ringwald gatt_client->state = P_W4_READ_BY_TYPE_RESPONSE; 15145cf1669fSMatthias Ringwald send_gatt_read_by_type_request(gatt_client); 15150038504eSMatthias Ringwald break; 15163deb3ec6SMatthias Ringwald 15173deb3ec6SMatthias Ringwald case P_W2_SEND_READ_MULTIPLE_REQUEST: 1518052dc82aSMatthias Ringwald gatt_client->state = P_W4_READ_MULTIPLE_RESPONSE; 15195cf1669fSMatthias Ringwald send_gatt_read_multiple_request(gatt_client); 15200038504eSMatthias Ringwald break; 15213deb3ec6SMatthias Ringwald 1522f125a8efSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 1523f125a8efSMatthias Ringwald case P_W2_SEND_READ_MULTIPLE_VARIABLE_REQUEST: 1524052dc82aSMatthias Ringwald gatt_client->state = P_W4_READ_MULTIPLE_VARIABLE_RESPONSE; 1525f125a8efSMatthias Ringwald send_gatt_read_multiple_variable_request(gatt_client); 1526f125a8efSMatthias Ringwald break; 1527f125a8efSMatthias Ringwald #endif 1528f125a8efSMatthias Ringwald 15293deb3ec6SMatthias Ringwald case P_W2_SEND_WRITE_CHARACTERISTIC_VALUE: 1530052dc82aSMatthias Ringwald gatt_client->state = P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT; 15315cf1669fSMatthias Ringwald send_gatt_write_attribute_value_request(gatt_client); 15320038504eSMatthias Ringwald break; 15333deb3ec6SMatthias Ringwald 15343deb3ec6SMatthias Ringwald case P_W2_PREPARE_WRITE: 1535052dc82aSMatthias Ringwald gatt_client->state = P_W4_PREPARE_WRITE_RESULT; 15365cf1669fSMatthias Ringwald send_gatt_prepare_write_request(gatt_client); 15370038504eSMatthias Ringwald break; 15383deb3ec6SMatthias Ringwald 15393deb3ec6SMatthias Ringwald case P_W2_PREPARE_WRITE_SINGLE: 1540052dc82aSMatthias Ringwald gatt_client->state = P_W4_PREPARE_WRITE_SINGLE_RESULT; 15415cf1669fSMatthias Ringwald send_gatt_prepare_write_request(gatt_client); 15420038504eSMatthias Ringwald break; 15433deb3ec6SMatthias Ringwald 15443deb3ec6SMatthias Ringwald case P_W2_PREPARE_RELIABLE_WRITE: 1545052dc82aSMatthias Ringwald gatt_client->state = P_W4_PREPARE_RELIABLE_WRITE_RESULT; 15465cf1669fSMatthias Ringwald send_gatt_prepare_write_request(gatt_client); 15470038504eSMatthias Ringwald break; 15483deb3ec6SMatthias Ringwald 15493deb3ec6SMatthias Ringwald case P_W2_EXECUTE_PREPARED_WRITE: 1550052dc82aSMatthias Ringwald gatt_client->state = P_W4_EXECUTE_PREPARED_WRITE_RESULT; 15515cf1669fSMatthias Ringwald send_gatt_execute_write_request(gatt_client); 15520038504eSMatthias Ringwald break; 15533deb3ec6SMatthias Ringwald 15543deb3ec6SMatthias Ringwald case P_W2_CANCEL_PREPARED_WRITE: 1555052dc82aSMatthias Ringwald gatt_client->state = P_W4_CANCEL_PREPARED_WRITE_RESULT; 15565cf1669fSMatthias Ringwald send_gatt_cancel_prepared_write_request(gatt_client); 15570038504eSMatthias Ringwald break; 15583deb3ec6SMatthias Ringwald 15593deb3ec6SMatthias Ringwald case P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH: 1560052dc82aSMatthias Ringwald gatt_client->state = P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT; 15615cf1669fSMatthias Ringwald send_gatt_cancel_prepared_write_request(gatt_client); 15620038504eSMatthias Ringwald break; 15633deb3ec6SMatthias Ringwald 1564abdc9fb5SMatthias Ringwald #ifdef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY 1565abdc9fb5SMatthias Ringwald case P_W2_SEND_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY: 1566abdc9fb5SMatthias Ringwald // use Find Information 15675cf1669fSMatthias Ringwald gatt_client->gatt_client_state = P_W4_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT; 15685cf1669fSMatthias Ringwald send_gatt_characteristic_descriptor_request(gatt_client); 1569abdc9fb5SMatthias Ringwald #else 15703deb3ec6SMatthias Ringwald case P_W2_SEND_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY: 1571abdc9fb5SMatthias Ringwald // Use Read By Type 1572052dc82aSMatthias Ringwald gatt_client->state = P_W4_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT; 15735cf1669fSMatthias Ringwald send_gatt_read_client_characteristic_configuration_request(gatt_client); 1574abdc9fb5SMatthias Ringwald #endif 15750038504eSMatthias Ringwald break; 15763deb3ec6SMatthias Ringwald 15773deb3ec6SMatthias Ringwald case P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY: 1578052dc82aSMatthias Ringwald gatt_client->state = P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT; 15795cf1669fSMatthias Ringwald send_gatt_read_characteristic_descriptor_request(gatt_client); 15800038504eSMatthias Ringwald break; 15813deb3ec6SMatthias Ringwald 15823deb3ec6SMatthias Ringwald case P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY: 1583052dc82aSMatthias Ringwald gatt_client->state = P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT; 15845cf1669fSMatthias Ringwald send_gatt_read_blob_request(gatt_client); 15850038504eSMatthias Ringwald break; 15863deb3ec6SMatthias Ringwald 15873deb3ec6SMatthias Ringwald case P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR: 1588052dc82aSMatthias Ringwald gatt_client->state = P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT; 15895cf1669fSMatthias Ringwald send_gatt_write_attribute_value_request(gatt_client); 15900038504eSMatthias Ringwald break; 15913deb3ec6SMatthias Ringwald 15923deb3ec6SMatthias Ringwald case P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION: 1593052dc82aSMatthias Ringwald gatt_client->state = P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT; 15945cf1669fSMatthias Ringwald send_gatt_write_client_characteristic_configuration_request(gatt_client); 15950038504eSMatthias Ringwald break; 15963deb3ec6SMatthias Ringwald 15973deb3ec6SMatthias Ringwald case P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR: 1598052dc82aSMatthias Ringwald gatt_client->state = P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT; 15995cf1669fSMatthias Ringwald send_gatt_prepare_write_request(gatt_client); 16000038504eSMatthias Ringwald break; 16013deb3ec6SMatthias Ringwald 16023deb3ec6SMatthias Ringwald case P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR: 1603052dc82aSMatthias Ringwald gatt_client->state = P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT; 16045cf1669fSMatthias Ringwald send_gatt_execute_write_request(gatt_client); 16050038504eSMatthias Ringwald break; 16063deb3ec6SMatthias Ringwald 16077a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE 1608793cf6ceSMatthias Ringwald case P_W4_IDENTITY_RESOLVING: 16095cf1669fSMatthias Ringwald log_info("P_W4_IDENTITY_RESOLVING - state %x", sm_identity_resolving_state(gatt_client->con_handle)); 16105cf1669fSMatthias Ringwald switch (sm_identity_resolving_state(gatt_client->con_handle)){ 1611793cf6ceSMatthias Ringwald case IRK_LOOKUP_SUCCEEDED: 16125cf1669fSMatthias Ringwald gatt_client->le_device_index = sm_le_device_index(gatt_client->con_handle); 1613052dc82aSMatthias Ringwald gatt_client->state = P_W4_CMAC_READY; 161492a7335eSMatthias Ringwald if (sm_cmac_ready()){ 161592a7335eSMatthias Ringwald gatt_client_run_for_client_start_signed_write(gatt_client); 161692a7335eSMatthias Ringwald } 1617793cf6ceSMatthias Ringwald break; 1618793cf6ceSMatthias Ringwald case IRK_LOOKUP_FAILED: 1619526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_BONDING_INFORMATION_MISSING); 162092a7335eSMatthias Ringwald break; 1621793cf6ceSMatthias Ringwald default: 162292a7335eSMatthias Ringwald break; 1623793cf6ceSMatthias Ringwald } 16240038504eSMatthias Ringwald packet_sent = false; 16250038504eSMatthias Ringwald break; 1626793cf6ceSMatthias Ringwald 16273deb3ec6SMatthias Ringwald case P_W4_CMAC_READY: 16283deb3ec6SMatthias Ringwald if (sm_cmac_ready()){ 162992a7335eSMatthias Ringwald gatt_client_run_for_client_start_signed_write(gatt_client); 16303deb3ec6SMatthias Ringwald } 16310038504eSMatthias Ringwald packet_sent = false; 16320038504eSMatthias Ringwald break; 16333deb3ec6SMatthias Ringwald 16343deb3ec6SMatthias Ringwald case P_W2_SEND_SIGNED_WRITE: { 16354c7c987fSMatthias Ringwald gatt_client->state = P_W4_SEND_SIGNED_WRITE_DONE; 16363deb3ec6SMatthias Ringwald // bump local signing counter 16375cf1669fSMatthias Ringwald uint32_t sign_counter = le_device_db_local_counter_get(gatt_client->le_device_index); 16385cf1669fSMatthias Ringwald le_device_db_local_counter_set(gatt_client->le_device_index, sign_counter + 1); 163964b12680SMatthias Ringwald // send signed write command 16405cf1669fSMatthias Ringwald send_gatt_signed_write_request(gatt_client, sign_counter); 16413deb3ec6SMatthias Ringwald // finally, notifiy client that write is complete 1642526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 1643b68ac7a5SMatthias Ringwald break; 16443deb3ec6SMatthias Ringwald } 16457a766ebfSMatthias Ringwald #endif 16463deb3ec6SMatthias Ringwald default: 1647b68ac7a5SMatthias Ringwald done = false; 16483deb3ec6SMatthias Ringwald break; 16493deb3ec6SMatthias Ringwald } 165047181045SMatthias Ringwald 16510038504eSMatthias Ringwald if (done){ 16520038504eSMatthias Ringwald return packet_sent; 16530038504eSMatthias Ringwald } 16540038504eSMatthias Ringwald 165559d34cd2SMatthias Ringwald // write without response callback 165659d34cd2SMatthias Ringwald btstack_context_callback_registration_t * callback = 165759d34cd2SMatthias Ringwald (btstack_context_callback_registration_t *) btstack_linked_list_pop(&gatt_client->write_without_response_requests); 165859d34cd2SMatthias Ringwald if (callback != NULL){ 165959d34cd2SMatthias Ringwald (*callback->callback)(callback->context); 166059d34cd2SMatthias Ringwald return true; 166159d34cd2SMatthias Ringwald } 166259d34cd2SMatthias Ringwald 166359d34cd2SMatthias Ringwald // requested can send now old 1664f688bdb8SMatthias Ringwald if (gatt_client->write_without_response_callback != NULL){ 16655cf1669fSMatthias Ringwald btstack_packet_handler_t packet_handler = gatt_client->write_without_response_callback; 16665cf1669fSMatthias Ringwald gatt_client->write_without_response_callback = NULL; 166747181045SMatthias Ringwald uint8_t event[4]; 166847181045SMatthias Ringwald event[0] = GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE; 16694ea43905SMatthias Ringwald event[1] = sizeof(event) - 2u; 16705cf1669fSMatthias Ringwald little_endian_store_16(event, 2, gatt_client->con_handle); 16715cf1669fSMatthias Ringwald packet_handler(HCI_EVENT_PACKET, gatt_client->con_handle, event, sizeof(event)); 16721979f09cSMatthias Ringwald return true; // to trigger requeueing (even if higher layer didn't sent) 167347181045SMatthias Ringwald } 167447181045SMatthias Ringwald 16751979f09cSMatthias Ringwald return false; 16763deb3ec6SMatthias Ringwald } 16773deb3ec6SMatthias Ringwald 1678544128c3SMatthias Ringwald static void gatt_client_run(void){ 1679544128c3SMatthias Ringwald btstack_linked_item_t *it; 1680109c2548SMatthias Ringwald bool packet_sent; 16817627a0deSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 16827627a0deSMatthias Ringwald btstack_linked_list_iterator_t it_eatt; 16837627a0deSMatthias Ringwald #endif 1684a0da043fSMatthias Ringwald for (it = (btstack_linked_item_t *) gatt_client_connections; it != NULL; it = it->next){ 16855cf1669fSMatthias Ringwald gatt_client_t * gatt_client = (gatt_client_t *) it; 168646012949SMatthias Ringwald switch (gatt_client->bearer_type){ 168746012949SMatthias Ringwald case ATT_BEARER_UNENHANCED_LE: 16887627a0deSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 16897627a0deSMatthias Ringwald btstack_linked_list_iterator_init(&it_eatt, &gatt_client->eatt_clients); 16907627a0deSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it_eatt)) { 16917627a0deSMatthias Ringwald gatt_client_t * eatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it_eatt); 1692052dc82aSMatthias Ringwald if (eatt_client->state != P_READY){ 16934c226876SMatthias Ringwald if (att_dispatch_client_can_send_now(gatt_client->con_handle)){ 16947627a0deSMatthias Ringwald gatt_client_run_for_gatt_client(eatt_client); 16957627a0deSMatthias Ringwald } 16967627a0deSMatthias Ringwald } 16977627a0deSMatthias Ringwald } 16987627a0deSMatthias Ringwald #endif 169946012949SMatthias Ringwald if (!att_dispatch_client_can_send_now(gatt_client->con_handle)) { 170046012949SMatthias Ringwald att_dispatch_client_request_can_send_now_event(gatt_client->con_handle); 170146012949SMatthias Ringwald return; 170246012949SMatthias Ringwald } 1703109c2548SMatthias Ringwald packet_sent = gatt_client_run_for_gatt_client(gatt_client); 170446012949SMatthias Ringwald if (packet_sent){ 170546012949SMatthias Ringwald // request new permission 170646012949SMatthias Ringwald att_dispatch_client_request_can_send_now_event(gatt_client->con_handle); 170746012949SMatthias Ringwald // requeue client for fairness and exit 170846012949SMatthias Ringwald // note: iterator has become invalid 170946012949SMatthias Ringwald btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client); 171046012949SMatthias Ringwald btstack_linked_list_add_tail(&gatt_client_connections, (btstack_linked_item_t *) gatt_client); 171146012949SMatthias Ringwald return; 171246012949SMatthias Ringwald } 171346012949SMatthias Ringwald break; 17141450cdc6SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC 171546012949SMatthias Ringwald case ATT_BEARER_UNENHANCED_CLASSIC: 17161450cdc6SMatthias Ringwald if (gatt_client->con_handle == HCI_CON_HANDLE_INVALID) { 17171450cdc6SMatthias Ringwald continue; 17181450cdc6SMatthias Ringwald } 17191aa9e3e8SMatthias Ringwald 17201aa9e3e8SMatthias Ringwald // handle GATT over BR/EDR 17214c226876SMatthias Ringwald if (att_dispatch_client_can_send_now(gatt_client->con_handle) == false) { 17224c226876SMatthias Ringwald att_dispatch_client_request_can_send_now_event(gatt_client->con_handle); 17231aa9e3e8SMatthias Ringwald return; 17241aa9e3e8SMatthias Ringwald } 1725109c2548SMatthias Ringwald packet_sent = gatt_client_run_for_gatt_client(gatt_client); 17261aa9e3e8SMatthias Ringwald if (packet_sent){ 17271aa9e3e8SMatthias Ringwald // request new permission 17281aa9e3e8SMatthias Ringwald att_dispatch_client_request_can_send_now_event(gatt_client->con_handle); 17291aa9e3e8SMatthias Ringwald // requeue client for fairness and exit 17301aa9e3e8SMatthias Ringwald // note: iterator has become invalid 17311aa9e3e8SMatthias Ringwald btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client); 17321aa9e3e8SMatthias Ringwald btstack_linked_list_add_tail(&gatt_client_connections, (btstack_linked_item_t *) gatt_client); 17331aa9e3e8SMatthias Ringwald return; 17341aa9e3e8SMatthias Ringwald } 173546012949SMatthias Ringwald break; 17361450cdc6SMatthias Ringwald #endif 173746012949SMatthias Ringwald default: 173846012949SMatthias Ringwald btstack_unreachable(); 173946012949SMatthias Ringwald break; 1740544128c3SMatthias Ringwald } 174146012949SMatthias Ringwald 174246012949SMatthias Ringwald 1743544128c3SMatthias Ringwald } 17443deb3ec6SMatthias Ringwald } 17453deb3ec6SMatthias Ringwald 1746544a5845SMatthias Ringwald // emit complete event, used to avoid emitting event from API call 1747544a5845SMatthias Ringwald static void gatt_client_emit_events(void * context){ 1748544a5845SMatthias Ringwald UNUSED(context); 1749544a5845SMatthias Ringwald btstack_linked_item_t *it; 1750544a5845SMatthias Ringwald for (it = (btstack_linked_item_t *) gatt_client_connections; it != NULL; it = it->next) { 1751544a5845SMatthias Ringwald gatt_client_t *gatt_client = (gatt_client_t *) it; 1752544a5845SMatthias Ringwald if (gatt_client->state == P_W2_EMIT_QUERY_COMPLETE_EVENT){ 1753544a5845SMatthias Ringwald gatt_client->state = P_READY; 1754544a5845SMatthias Ringwald emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS); 1755544a5845SMatthias Ringwald } 1756544a5845SMatthias Ringwald } 1757544a5845SMatthias Ringwald } 1758544a5845SMatthias Ringwald 17595cf1669fSMatthias Ringwald static void gatt_client_report_error_if_pending(gatt_client_t *gatt_client, uint8_t att_error_code) { 1760643a64fcSMatthias Ringwald if (is_ready(gatt_client)) return; 1761526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, att_error_code); 17623deb3ec6SMatthias Ringwald } 17633deb3ec6SMatthias Ringwald 176478c4542aSMatthias Ringwald static void gatt_client_handle_reencryption_complete(const uint8_t * packet){ 176578c4542aSMatthias Ringwald hci_con_handle_t con_handle = sm_event_reencryption_complete_get_handle(packet); 176678c4542aSMatthias Ringwald gatt_client_t * gatt_client = gatt_client_get_context_for_handle(con_handle); 176778c4542aSMatthias Ringwald if (gatt_client == NULL) return; 176878c4542aSMatthias Ringwald 176978c4542aSMatthias Ringwald // update security level 177078c4542aSMatthias Ringwald gatt_client->security_level = gatt_client_le_security_level_for_connection(con_handle); 177178c4542aSMatthias Ringwald 177278c4542aSMatthias Ringwald gatt_client->reencryption_result = sm_event_reencryption_complete_get_status(packet); 177378c4542aSMatthias Ringwald gatt_client->reencryption_active = false; 17742197dbafSMatthias Ringwald gatt_client->wait_for_authentication_complete = false; 177578c4542aSMatthias Ringwald 1776052dc82aSMatthias Ringwald if (gatt_client->state == P_READY) return; 177778c4542aSMatthias Ringwald 177878c4542aSMatthias Ringwald switch (sm_event_reencryption_complete_get_status(packet)){ 177978c4542aSMatthias Ringwald case ERROR_CODE_SUCCESS: 178078c4542aSMatthias Ringwald log_info("re-encryption success, retry operation"); 178178c4542aSMatthias Ringwald break; 178278c4542aSMatthias Ringwald case ERROR_CODE_AUTHENTICATION_FAILURE: 178378c4542aSMatthias Ringwald case ERROR_CODE_PIN_OR_KEY_MISSING: 178478c4542aSMatthias Ringwald #if defined(ENABLE_GATT_CLIENT_PAIRING) && !defined(ENABLE_LE_PROACTIVE_AUTHENTICATION) 178578c4542aSMatthias Ringwald if (gatt_client_required_security_level == LEVEL_0) { 178678c4542aSMatthias Ringwald // re-encryption failed for reactive authentication with pairing and we have a pending client request 178778c4542aSMatthias Ringwald // => try to resolve it by deleting bonding information if we started pairing before 178878c4542aSMatthias Ringwald // delete bonding information 178978c4542aSMatthias Ringwald int le_device_db_index = sm_le_device_index(gatt_client->con_handle); 179078c4542aSMatthias Ringwald btstack_assert(le_device_db_index >= 0); 179178c4542aSMatthias Ringwald log_info("reactive auth with pairing: delete bonding and start pairing"); 179278c4542aSMatthias Ringwald #ifdef ENABLE_LE_PRIVACY_ADDRESS_RESOLUTION 179378c4542aSMatthias Ringwald hci_remove_le_device_db_entry_from_resolving_list((uint16_t) le_device_db_index); 179478c4542aSMatthias Ringwald #endif 179578c4542aSMatthias Ringwald le_device_db_remove(le_device_db_index); 179678c4542aSMatthias Ringwald // trigger pairing again 179778c4542aSMatthias Ringwald sm_request_pairing(gatt_client->con_handle); 179878c4542aSMatthias Ringwald break; 179978c4542aSMatthias Ringwald } 180078c4542aSMatthias Ringwald #endif 180178c4542aSMatthias Ringwald // report bonding information missing 1802526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_BONDING_INFORMATION_MISSING); 180378c4542aSMatthias Ringwald break; 180478c4542aSMatthias Ringwald default: 180578c4542aSMatthias Ringwald // report bonding information missing 1806526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, gatt_client->pending_error_code); 180778c4542aSMatthias Ringwald break; 180878c4542aSMatthias Ringwald } 180978c4542aSMatthias Ringwald } 181078c4542aSMatthias Ringwald 181178c4542aSMatthias Ringwald static void gatt_client_handle_disconnection_complete(const uint8_t * packet){ 181278c4542aSMatthias Ringwald log_info("GATT Client: HCI_EVENT_DISCONNECTION_COMPLETE"); 181378c4542aSMatthias Ringwald hci_con_handle_t con_handle = little_endian_read_16(packet,3); 181478c4542aSMatthias Ringwald gatt_client_t * gatt_client = gatt_client_get_context_for_handle(con_handle); 181578c4542aSMatthias Ringwald if (gatt_client == NULL) return; 181678c4542aSMatthias Ringwald 181778c4542aSMatthias Ringwald gatt_client_report_error_if_pending(gatt_client, ATT_ERROR_HCI_DISCONNECT_RECEIVED); 181878c4542aSMatthias Ringwald gatt_client_timeout_stop(gatt_client); 181978c4542aSMatthias Ringwald btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client); 182078c4542aSMatthias Ringwald btstack_memory_gatt_client_free(gatt_client); 182178c4542aSMatthias Ringwald } 182278c4542aSMatthias Ringwald 1823f4b33574SMatthias Ringwald static void gatt_client_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 18241ac26e06SMatthias Ringwald UNUSED(channel); // ok: handling own l2cap events 18251ac26e06SMatthias Ringwald UNUSED(size); // ok: there is no channel 18269ec2630cSMatthias Ringwald 1827361b1363SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 1828361b1363SMatthias Ringwald 1829f4b33574SMatthias Ringwald hci_con_handle_t con_handle; 18305cf1669fSMatthias Ringwald gatt_client_t * gatt_client; 18310e2df43fSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 18323deb3ec6SMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 183378c4542aSMatthias Ringwald gatt_client_handle_disconnection_complete(packet); 18343deb3ec6SMatthias Ringwald break; 1835f4b33574SMatthias Ringwald 1836f4b33574SMatthias Ringwald // Pairing complete (with/without bonding=storing of pairing information) 1837f4b33574SMatthias Ringwald case SM_EVENT_PAIRING_COMPLETE: 1838f4b33574SMatthias Ringwald con_handle = sm_event_pairing_complete_get_handle(packet); 18395cf1669fSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 18405cf1669fSMatthias Ringwald if (gatt_client == NULL) break; 1841f4b33574SMatthias Ringwald 18421dfae9c7SMatthias Ringwald // update security level 18431dfae9c7SMatthias Ringwald gatt_client->security_level = gatt_client_le_security_level_for_connection(con_handle); 18441dfae9c7SMatthias Ringwald 18453503dc74SMatthias Ringwald if (gatt_client->wait_for_authentication_complete){ 18462197dbafSMatthias Ringwald gatt_client->wait_for_authentication_complete = false; 1847f688bdb8SMatthias Ringwald if (sm_event_pairing_complete_get_status(packet) != ERROR_CODE_SUCCESS){ 18485cf1669fSMatthias Ringwald log_info("pairing failed, report previous error 0x%x", gatt_client->pending_error_code); 1849ec9babacSMatthias Ringwald gatt_client_report_error_if_pending(gatt_client, gatt_client->pending_error_code); 1850f4b33574SMatthias Ringwald } else { 1851f4b33574SMatthias Ringwald log_info("pairing success, retry operation"); 18523deb3ec6SMatthias Ringwald } 1853f4b33574SMatthias Ringwald } 1854f4b33574SMatthias Ringwald break; 185511279da7SMatthias Ringwald 1856793cf6ceSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE 1857793cf6ceSMatthias Ringwald // Identity Resolving completed (no code, gatt_client_run will continue) 1858793cf6ceSMatthias Ringwald case SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED: 1859793cf6ceSMatthias Ringwald case SM_EVENT_IDENTITY_RESOLVING_FAILED: 1860793cf6ceSMatthias Ringwald break; 1861793cf6ceSMatthias Ringwald #endif 1862a95ca902SMatthias Ringwald 18638918bbdaSMatthias Ringwald // re-encryption started 18648918bbdaSMatthias Ringwald case SM_EVENT_REENCRYPTION_STARTED: 18658918bbdaSMatthias Ringwald con_handle = sm_event_reencryption_complete_get_handle(packet); 18668918bbdaSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 18678918bbdaSMatthias Ringwald if (gatt_client == NULL) break; 18688918bbdaSMatthias Ringwald 18698918bbdaSMatthias Ringwald gatt_client->reencryption_active = true; 18708918bbdaSMatthias Ringwald gatt_client->reencryption_result = ERROR_CODE_SUCCESS; 18718918bbdaSMatthias Ringwald break; 18728918bbdaSMatthias Ringwald 1873ec9babacSMatthias Ringwald // re-encryption complete 1874ec9babacSMatthias Ringwald case SM_EVENT_REENCRYPTION_COMPLETE: 187578c4542aSMatthias Ringwald gatt_client_handle_reencryption_complete(packet); 1876ec9babacSMatthias Ringwald break; 18773deb3ec6SMatthias Ringwald default: 18783deb3ec6SMatthias Ringwald break; 18793deb3ec6SMatthias Ringwald } 18803deb3ec6SMatthias Ringwald 1881361b1363SMatthias Ringwald gatt_client_run(); 18823deb3ec6SMatthias Ringwald } 18833deb3ec6SMatthias Ringwald 18842da0d963SMatthias Ringwald static void gatt_client_handle_att_read_response(gatt_client_t *gatt_client, uint8_t *packet, uint16_t size) { 1885052dc82aSMatthias Ringwald switch (gatt_client->state) { 18862da0d963SMatthias Ringwald case P_W4_INCLUDED_SERVICE_UUID_WITH_QUERY_RESULT: 18872da0d963SMatthias Ringwald if (size >= 17) { 18882da0d963SMatthias Ringwald uint8_t uuid128[16]; 18892da0d963SMatthias Ringwald reverse_128(&packet[1], uuid128); 18902da0d963SMatthias Ringwald report_gatt_included_service_uuid128(gatt_client, gatt_client->start_group_handle, uuid128); 18912da0d963SMatthias Ringwald } 18922da0d963SMatthias Ringwald trigger_next_included_service_query(gatt_client, gatt_client->start_group_handle); 18935611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 18943deb3ec6SMatthias Ringwald break; 18952da0d963SMatthias Ringwald 18962da0d963SMatthias Ringwald case P_W4_READ_CHARACTERISTIC_VALUE_RESULT: 18972da0d963SMatthias Ringwald report_gatt_characteristic_value(gatt_client, gatt_client->attribute_handle, &packet[1], size - 1u); 1898526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 18992da0d963SMatthias Ringwald break; 19002da0d963SMatthias Ringwald 19012da0d963SMatthias Ringwald case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT: 19022da0d963SMatthias Ringwald report_gatt_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, &packet[1], 19032da0d963SMatthias Ringwald size - 1u, 0u); 1904526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 19052da0d963SMatthias Ringwald break; 19062da0d963SMatthias Ringwald 19072da0d963SMatthias Ringwald // Use ATT_READ_REQUEST for first blob of Read Long Characteristic 19082da0d963SMatthias Ringwald case P_W4_READ_BLOB_RESULT: 19092da0d963SMatthias Ringwald report_gatt_long_characteristic_value_blob(gatt_client, gatt_client->attribute_handle, &packet[1], 19102da0d963SMatthias Ringwald size - 1u, gatt_client->attribute_offset); 19112da0d963SMatthias Ringwald trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_QUERY, size - 1u); 19122da0d963SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 19132da0d963SMatthias Ringwald break; 19142da0d963SMatthias Ringwald 19152da0d963SMatthias Ringwald // Use ATT_READ_REQUEST for first blob of Read Long Characteristic Descriptor 19162da0d963SMatthias Ringwald case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT: 19172da0d963SMatthias Ringwald report_gatt_long_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, &packet[1], 19182da0d963SMatthias Ringwald size - 1u, gatt_client->attribute_offset); 19192da0d963SMatthias Ringwald trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY, 19202da0d963SMatthias Ringwald size - 1u); 19212da0d963SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 19222da0d963SMatthias Ringwald break; 19232da0d963SMatthias Ringwald 19243deb3ec6SMatthias Ringwald default: 19253deb3ec6SMatthias Ringwald break; 19263deb3ec6SMatthias Ringwald } 19272da0d963SMatthias Ringwald } 19283deb3ec6SMatthias Ringwald 19292da0d963SMatthias Ringwald static void gatt_client_handle_att_read_by_type_response(gatt_client_t *gatt_client, uint8_t *packet, uint16_t size) { 1930052dc82aSMatthias Ringwald switch (gatt_client->state) { 19313deb3ec6SMatthias Ringwald case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT: 19325cf1669fSMatthias Ringwald report_gatt_characteristics(gatt_client, packet, size); 1933cf8e5718SMatthias Ringwald trigger_next_characteristic_query(gatt_client, 1934cf8e5718SMatthias Ringwald get_last_result_handle_from_characteristics_list(packet, size)); 19355611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR 19363deb3ec6SMatthias Ringwald break; 19373deb3ec6SMatthias Ringwald case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT: 19385cf1669fSMatthias Ringwald report_gatt_characteristics(gatt_client, packet, size); 1939cf8e5718SMatthias Ringwald trigger_next_characteristic_query(gatt_client, 1940cf8e5718SMatthias Ringwald get_last_result_handle_from_characteristics_list(packet, size)); 19415611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR 19423deb3ec6SMatthias Ringwald break; 1943cf8e5718SMatthias Ringwald case P_W4_INCLUDED_SERVICE_QUERY_RESULT: { 19444ea43905SMatthias Ringwald if (size < 2u) break; 19453deb3ec6SMatthias Ringwald uint16_t uuid16 = 0; 19463deb3ec6SMatthias Ringwald uint16_t pair_size = packet[1]; 19473deb3ec6SMatthias Ringwald 19484ea43905SMatthias Ringwald if (pair_size == 6u) { 19494ea43905SMatthias Ringwald if (size < 8u) break; 19503deb3ec6SMatthias Ringwald // UUIDs not available, query first included service 19515cf1669fSMatthias Ringwald gatt_client->start_group_handle = little_endian_read_16(packet, 2); // ready for next query 19525cf1669fSMatthias Ringwald gatt_client->query_start_handle = little_endian_read_16(packet, 4); 19535cf1669fSMatthias Ringwald gatt_client->query_end_handle = little_endian_read_16(packet, 6); 1954052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_INCLUDED_SERVICE_WITH_UUID_QUERY; 19553deb3ec6SMatthias Ringwald break; 19563deb3ec6SMatthias Ringwald } 19573deb3ec6SMatthias Ringwald 19584ea43905SMatthias Ringwald if (pair_size != 8u) break; 19599f698c82SMatthias Ringwald 19609f698c82SMatthias Ringwald // UUIDs included, report all of them 19613deb3ec6SMatthias Ringwald uint16_t offset; 19624ea43905SMatthias Ringwald for (offset = 2u; (offset + 8u) <= size; offset += pair_size) { 1963f8fbdce0SMatthias Ringwald uint16_t include_handle = little_endian_read_16(packet, offset); 19645cf1669fSMatthias Ringwald gatt_client->query_start_handle = little_endian_read_16(packet, offset + 2u); 19655cf1669fSMatthias Ringwald gatt_client->query_end_handle = little_endian_read_16(packet, offset + 4u); 19664ea43905SMatthias Ringwald uuid16 = little_endian_read_16(packet, offset + 6u); 19675cf1669fSMatthias Ringwald report_gatt_included_service_uuid16(gatt_client, include_handle, uuid16); 19683deb3ec6SMatthias Ringwald } 19693deb3ec6SMatthias Ringwald 1970cf8e5718SMatthias Ringwald trigger_next_included_service_query(gatt_client, 1971cf8e5718SMatthias Ringwald get_last_result_handle_from_included_services_list(packet, 1972cf8e5718SMatthias Ringwald size)); 19735611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 19743deb3ec6SMatthias Ringwald break; 19753deb3ec6SMatthias Ringwald } 1976abdc9fb5SMatthias Ringwald #ifndef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY 19773deb3ec6SMatthias Ringwald case P_W4_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT: 19785cf1669fSMatthias Ringwald gatt_client->client_characteristic_configuration_handle = little_endian_read_16(packet, 2); 1979052dc82aSMatthias Ringwald gatt_client->state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION; 19803deb3ec6SMatthias Ringwald break; 1981abdc9fb5SMatthias Ringwald #endif 19823deb3ec6SMatthias Ringwald case P_W4_READ_BY_TYPE_RESPONSE: { 19833deb3ec6SMatthias Ringwald uint16_t pair_size = packet[1]; 198439ac9711SMatthias Ringwald // set last result handle to last valid handle, only used if pair_size invalid 198539ac9711SMatthias Ringwald uint16_t last_result_handle = 0xffff; 198639ac9711SMatthias Ringwald if (pair_size > 2) { 19873deb3ec6SMatthias Ringwald uint16_t offset; 19883deb3ec6SMatthias Ringwald for (offset = 2; offset < size; offset += pair_size) { 1989f8fbdce0SMatthias Ringwald uint16_t value_handle = little_endian_read_16(packet, offset); 1990cf8e5718SMatthias Ringwald report_gatt_characteristic_value(gatt_client, value_handle, &packet[offset + 2u], 1991cf8e5718SMatthias Ringwald pair_size - 2u); 19923deb3ec6SMatthias Ringwald last_result_handle = value_handle; 19933deb3ec6SMatthias Ringwald } 199439ac9711SMatthias Ringwald } 19955cf1669fSMatthias Ringwald trigger_next_read_by_type_query(gatt_client, last_result_handle); 19963deb3ec6SMatthias Ringwald break; 19973deb3ec6SMatthias Ringwald } 19983deb3ec6SMatthias Ringwald default: 19993deb3ec6SMatthias Ringwald break; 20003deb3ec6SMatthias Ringwald } 200139ac9711SMatthias Ringwald } 2002dc13fd8dSMatthias Ringwald 20032da0d963SMatthias Ringwald static void gatt_client_handle_att_write_response(gatt_client_t *gatt_client) { 2004052dc82aSMatthias Ringwald switch (gatt_client->state) { 20052da0d963SMatthias Ringwald case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT: 2006526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 20073deb3ec6SMatthias Ringwald break; 20082da0d963SMatthias Ringwald case P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT: 2009526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 20103deb3ec6SMatthias Ringwald break; 20112da0d963SMatthias Ringwald case P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: 2012526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 20132da0d963SMatthias Ringwald break; 20142da0d963SMatthias Ringwald default: 20152da0d963SMatthias Ringwald break; 20162da0d963SMatthias Ringwald } 20172da0d963SMatthias Ringwald } 2018dc13fd8dSMatthias Ringwald 20192da0d963SMatthias Ringwald static void gatt_client_handle_att_response(gatt_client_t * gatt_client, uint8_t * packet, uint16_t size) { 20204740230fSMatthias Ringwald uint8_t att_status; 20212da0d963SMatthias Ringwald switch (packet[0]) { 20222da0d963SMatthias Ringwald case ATT_EXCHANGE_MTU_RESPONSE: { 20232da0d963SMatthias Ringwald if (size < 3u) break; 202446012949SMatthias Ringwald bool update_gatt_server_att_mtu = false; 20252da0d963SMatthias Ringwald uint16_t remote_rx_mtu = little_endian_read_16(packet, 1); 20262da0d963SMatthias Ringwald uint16_t local_rx_mtu = l2cap_max_le_mtu(); 202746012949SMatthias Ringwald switch (gatt_client->bearer_type){ 202846012949SMatthias Ringwald case ATT_BEARER_UNENHANCED_LE: 202946012949SMatthias Ringwald update_gatt_server_att_mtu = true; 203046012949SMatthias Ringwald break; 20312da0d963SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC 203246012949SMatthias Ringwald case ATT_BEARER_UNENHANCED_CLASSIC: 20332da0d963SMatthias Ringwald local_rx_mtu = gatt_client->mtu; 203446012949SMatthias Ringwald break; 20352da0d963SMatthias Ringwald #endif 203646012949SMatthias Ringwald default: 203746012949SMatthias Ringwald btstack_unreachable(); 203846012949SMatthias Ringwald break; 203946012949SMatthias Ringwald } 204046012949SMatthias Ringwald 20412da0d963SMatthias Ringwald uint16_t mtu = (remote_rx_mtu < local_rx_mtu) ? remote_rx_mtu : local_rx_mtu; 20422da0d963SMatthias Ringwald 20432da0d963SMatthias Ringwald // set gatt client mtu 20442da0d963SMatthias Ringwald gatt_client->mtu = mtu; 20452da0d963SMatthias Ringwald gatt_client->mtu_state = MTU_EXCHANGED; 20462da0d963SMatthias Ringwald 204746012949SMatthias Ringwald if (update_gatt_server_att_mtu){ 20482da0d963SMatthias Ringwald // set per connection mtu state - for fixed channel 20492da0d963SMatthias Ringwald hci_connection_t *hci_connection = hci_connection_for_handle(gatt_client->con_handle); 20502da0d963SMatthias Ringwald hci_connection->att_connection.mtu = gatt_client->mtu; 20512da0d963SMatthias Ringwald hci_connection->att_connection.mtu_exchanged = true; 20522da0d963SMatthias Ringwald } 20532da0d963SMatthias Ringwald emit_gatt_mtu_exchanged_result_event(gatt_client, gatt_client->mtu); 20542da0d963SMatthias Ringwald break; 20552da0d963SMatthias Ringwald } 20562da0d963SMatthias Ringwald case ATT_READ_BY_GROUP_TYPE_RESPONSE: 2057052dc82aSMatthias Ringwald switch (gatt_client->state) { 20582da0d963SMatthias Ringwald case P_W4_SERVICE_QUERY_RESULT: 20592da0d963SMatthias Ringwald report_gatt_services(gatt_client, packet, size); 20602da0d963SMatthias Ringwald trigger_next_service_query(gatt_client, get_last_result_handle_from_service_list(packet, size)); 206130952227SMilanka Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 206230952227SMilanka Ringwald break; 20633deb3ec6SMatthias Ringwald default: 20643deb3ec6SMatthias Ringwald break; 20653deb3ec6SMatthias Ringwald } 20663deb3ec6SMatthias Ringwald break; 20672da0d963SMatthias Ringwald case ATT_HANDLE_VALUE_NOTIFICATION: 20682da0d963SMatthias Ringwald if (size < 3u) return; 20692da0d963SMatthias Ringwald report_gatt_notification(gatt_client, little_endian_read_16(packet, 1u), &packet[3], size - 3u); 20702da0d963SMatthias Ringwald return; 2071cbba69d5SMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 2072cbba69d5SMatthias Ringwald case ATT_MULTIPLE_HANDLE_VALUE_NTF: 2073cbba69d5SMatthias Ringwald if (size >= 5u) { 2074cbba69d5SMatthias Ringwald uint16_t offset = 1; 2075cbba69d5SMatthias Ringwald while (true){ 2076cbba69d5SMatthias Ringwald uint16_t value_handle = little_endian_read_16(packet, offset); 2077cbba69d5SMatthias Ringwald offset += 2; 2078cbba69d5SMatthias Ringwald uint16_t value_length = little_endian_read_16(packet, offset); 2079cbba69d5SMatthias Ringwald offset += 2; 2080cbba69d5SMatthias Ringwald if ((offset + value_length) > size) break; 2081cbba69d5SMatthias Ringwald report_gatt_notification(gatt_client, value_handle, &packet[offset], value_length); 2082cbba69d5SMatthias Ringwald offset += value_length; 2083cbba69d5SMatthias Ringwald } 2084cbba69d5SMatthias Ringwald } 2085cbba69d5SMatthias Ringwald return; 2086cbba69d5SMatthias Ringwald #endif 20872da0d963SMatthias Ringwald case ATT_HANDLE_VALUE_INDICATION: 20882da0d963SMatthias Ringwald if (size < 3u) break; 20892da0d963SMatthias Ringwald report_gatt_indication(gatt_client, little_endian_read_16(packet, 1u), &packet[3], size - 3u); 209052377058SMatthias Ringwald gatt_client->send_confirmation = true; 20912da0d963SMatthias Ringwald break; 20922da0d963SMatthias Ringwald case ATT_READ_BY_TYPE_RESPONSE: 20932da0d963SMatthias Ringwald gatt_client_handle_att_read_by_type_response(gatt_client, packet, size); 20942da0d963SMatthias Ringwald break; 20952da0d963SMatthias Ringwald case ATT_READ_RESPONSE: 20962da0d963SMatthias Ringwald gatt_client_handle_att_read_response(gatt_client, packet, size); 20972da0d963SMatthias Ringwald break; 2098cf8e5718SMatthias Ringwald case ATT_FIND_BY_TYPE_VALUE_RESPONSE: { 20993deb3ec6SMatthias Ringwald uint8_t pair_size = 4; 21003deb3ec6SMatthias Ringwald int i; 21013deb3ec6SMatthias Ringwald uint16_t start_group_handle; 21025611a760SMatthias Ringwald uint16_t end_group_handle = 0xffff; // asserts GATT_EVENT_QUERY_COMPLETE is emitted if no results 21034ea43905SMatthias Ringwald for (i = 1u; (i + pair_size) <= size; i += pair_size) { 2104f8fbdce0SMatthias Ringwald start_group_handle = little_endian_read_16(packet, i); 2105f8fbdce0SMatthias Ringwald end_group_handle = little_endian_read_16(packet, i + 2); 2106cf8e5718SMatthias Ringwald emit_gatt_service_query_result_event(gatt_client, start_group_handle, end_group_handle, 2107cf8e5718SMatthias Ringwald gatt_client->uuid128); 21083deb3ec6SMatthias Ringwald } 21095cf1669fSMatthias Ringwald trigger_next_service_by_uuid_query(gatt_client, end_group_handle); 21105611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 21113deb3ec6SMatthias Ringwald break; 21123deb3ec6SMatthias Ringwald } 2113cf8e5718SMatthias Ringwald case ATT_FIND_INFORMATION_REPLY: { 21144ea43905SMatthias Ringwald if (size < 2u) break; 2115a6121b51SMilanka Ringwald 21163deb3ec6SMatthias Ringwald uint8_t pair_size = 4; 21174ea43905SMatthias Ringwald if (packet[1u] == 2u) { 21183deb3ec6SMatthias Ringwald pair_size = 18; 21193deb3ec6SMatthias Ringwald } 2120a6121b51SMilanka Ringwald uint16_t offset = 2; 2121a6121b51SMilanka Ringwald 2122a6121b51SMilanka Ringwald if (size < (pair_size + offset)) break; 2123f8fbdce0SMatthias Ringwald uint16_t last_descriptor_handle = little_endian_read_16(packet, size - pair_size); 2124abdc9fb5SMatthias Ringwald 2125abdc9fb5SMatthias Ringwald #ifdef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY 21265cf1669fSMatthias Ringwald log_info("ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY, state %x", gatt_client->gatt_client_state); 21275cf1669fSMatthias Ringwald if (gatt_client->gatt_client_state == P_W4_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT){ 2128abdc9fb5SMatthias Ringwald // iterate over descriptors looking for CCC 2129abdc9fb5SMatthias Ringwald if (pair_size == 4){ 2130a6121b51SMilanka Ringwald while ((offset + 4) <= size){ 2131abdc9fb5SMatthias Ringwald uint16_t uuid16 = little_endian_read_16(packet, offset + 2); 2132abdc9fb5SMatthias Ringwald if (uuid16 == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION){ 21335cf1669fSMatthias Ringwald gatt_client->client_characteristic_configuration_handle = little_endian_read_16(packet, offset); 21345cf1669fSMatthias Ringwald gatt_client->gatt_client_state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION; 21355cf1669fSMatthias Ringwald log_info("CCC found %x", gatt_client->client_characteristic_configuration_handle); 2136abdc9fb5SMatthias Ringwald break; 2137abdc9fb5SMatthias Ringwald } 2138abdc9fb5SMatthias Ringwald offset += pair_size; 2139abdc9fb5SMatthias Ringwald } 2140abdc9fb5SMatthias Ringwald } 21415cf1669fSMatthias Ringwald if (is_query_done(gatt_client, last_descriptor_handle)){ 2142abdc9fb5SMatthias Ringwald 2143abdc9fb5SMatthias Ringwald } else { 2144abdc9fb5SMatthias Ringwald // next 21455cf1669fSMatthias Ringwald gatt_client->start_group_handle = last_descriptor_handle + 1; 21465cf1669fSMatthias Ringwald gatt_client->gatt_client_state = P_W2_SEND_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY; 2147abdc9fb5SMatthias Ringwald } 2148abdc9fb5SMatthias Ringwald break; 2149abdc9fb5SMatthias Ringwald } 2150abdc9fb5SMatthias Ringwald #endif 21515cf1669fSMatthias Ringwald report_gatt_all_characteristic_descriptors(gatt_client, &packet[2], size - 2u, pair_size); 21525cf1669fSMatthias Ringwald trigger_next_characteristic_descriptor_query(gatt_client, last_descriptor_handle); 21535611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 21543deb3ec6SMatthias Ringwald break; 21553deb3ec6SMatthias Ringwald } 21563deb3ec6SMatthias Ringwald 21573deb3ec6SMatthias Ringwald case ATT_WRITE_RESPONSE: 21582da0d963SMatthias Ringwald gatt_client_handle_att_write_response(gatt_client); 21593deb3ec6SMatthias Ringwald break; 21603deb3ec6SMatthias Ringwald 21613deb3ec6SMatthias Ringwald case ATT_READ_BLOB_RESPONSE: { 21624ea43905SMatthias Ringwald uint16_t received_blob_length = size - 1u; 2163052dc82aSMatthias Ringwald switch (gatt_client->state) { 21643deb3ec6SMatthias Ringwald case P_W4_READ_BLOB_RESULT: 2165cf8e5718SMatthias Ringwald report_gatt_long_characteristic_value_blob(gatt_client, gatt_client->attribute_handle, &packet[1], 2166cf8e5718SMatthias Ringwald received_blob_length, gatt_client->attribute_offset); 21675cf1669fSMatthias Ringwald trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_QUERY, received_blob_length); 21685611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 21693deb3ec6SMatthias Ringwald break; 21703deb3ec6SMatthias Ringwald case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT: 21715cf1669fSMatthias Ringwald report_gatt_long_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, 21723deb3ec6SMatthias Ringwald &packet[1], received_blob_length, 21735cf1669fSMatthias Ringwald gatt_client->attribute_offset); 2174cf8e5718SMatthias Ringwald trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY, 2175cf8e5718SMatthias Ringwald received_blob_length); 21765611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 21773deb3ec6SMatthias Ringwald break; 21783deb3ec6SMatthias Ringwald default: 21793deb3ec6SMatthias Ringwald break; 21803deb3ec6SMatthias Ringwald } 21813deb3ec6SMatthias Ringwald break; 21823deb3ec6SMatthias Ringwald } 21833deb3ec6SMatthias Ringwald case ATT_PREPARE_WRITE_RESPONSE: 2184052dc82aSMatthias Ringwald switch (gatt_client->state) { 21853deb3ec6SMatthias Ringwald case P_W4_PREPARE_WRITE_SINGLE_RESULT: 21865cf1669fSMatthias Ringwald if (is_value_valid(gatt_client, packet, size)) { 21874740230fSMatthias Ringwald att_status = ATT_ERROR_SUCCESS; 21883deb3ec6SMatthias Ringwald } else { 21894740230fSMatthias Ringwald att_status = ATT_ERROR_DATA_MISMATCH; 21903deb3ec6SMatthias Ringwald } 2191526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, att_status); 21923deb3ec6SMatthias Ringwald break; 21933deb3ec6SMatthias Ringwald 21943deb3ec6SMatthias Ringwald case P_W4_PREPARE_WRITE_RESULT: { 21955cf1669fSMatthias Ringwald gatt_client->attribute_offset = little_endian_read_16(packet, 3); 21965cf1669fSMatthias Ringwald trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_WRITE, P_W2_EXECUTE_PREPARED_WRITE); 21975611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 21983deb3ec6SMatthias Ringwald break; 21993deb3ec6SMatthias Ringwald } 22003deb3ec6SMatthias Ringwald case P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: { 22015cf1669fSMatthias Ringwald gatt_client->attribute_offset = little_endian_read_16(packet, 3); 2202cf8e5718SMatthias Ringwald trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR, 2203cf8e5718SMatthias Ringwald P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR); 22045611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 22053deb3ec6SMatthias Ringwald break; 22063deb3ec6SMatthias Ringwald } 22073deb3ec6SMatthias Ringwald case P_W4_PREPARE_RELIABLE_WRITE_RESULT: { 22085cf1669fSMatthias Ringwald if (is_value_valid(gatt_client, packet, size)) { 22095cf1669fSMatthias Ringwald gatt_client->attribute_offset = little_endian_read_16(packet, 3); 2210cf8e5718SMatthias Ringwald trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_RELIABLE_WRITE, 2211cf8e5718SMatthias Ringwald P_W2_EXECUTE_PREPARED_WRITE); 22125611a760SMatthias Ringwald // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done 22133deb3ec6SMatthias Ringwald break; 22143deb3ec6SMatthias Ringwald } 2215052dc82aSMatthias Ringwald gatt_client->state = P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH; 22163deb3ec6SMatthias Ringwald break; 22173deb3ec6SMatthias Ringwald } 22183deb3ec6SMatthias Ringwald default: 22193deb3ec6SMatthias Ringwald break; 22203deb3ec6SMatthias Ringwald } 22213deb3ec6SMatthias Ringwald break; 22223deb3ec6SMatthias Ringwald 22233deb3ec6SMatthias Ringwald case ATT_EXECUTE_WRITE_RESPONSE: 2224052dc82aSMatthias Ringwald switch (gatt_client->state) { 22253deb3ec6SMatthias Ringwald case P_W4_EXECUTE_PREPARED_WRITE_RESULT: 2226526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 22273deb3ec6SMatthias Ringwald break; 22283deb3ec6SMatthias Ringwald case P_W4_CANCEL_PREPARED_WRITE_RESULT: 2229526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 22303deb3ec6SMatthias Ringwald break; 22313deb3ec6SMatthias Ringwald case P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT: 2232526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_DATA_MISMATCH); 22333deb3ec6SMatthias Ringwald break; 22343deb3ec6SMatthias Ringwald case P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: 2235526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 22363deb3ec6SMatthias Ringwald break; 22373deb3ec6SMatthias Ringwald default: 22383deb3ec6SMatthias Ringwald break; 22393deb3ec6SMatthias Ringwald 22403deb3ec6SMatthias Ringwald } 22413deb3ec6SMatthias Ringwald break; 22423deb3ec6SMatthias Ringwald 22433deb3ec6SMatthias Ringwald case ATT_READ_MULTIPLE_RESPONSE: 2244052dc82aSMatthias Ringwald switch (gatt_client->state) { 22453deb3ec6SMatthias Ringwald case P_W4_READ_MULTIPLE_RESPONSE: 22465cf1669fSMatthias Ringwald report_gatt_characteristic_value(gatt_client, 0u, &packet[1], size - 1u); 2247526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 22483deb3ec6SMatthias Ringwald break; 22493deb3ec6SMatthias Ringwald default: 22503deb3ec6SMatthias Ringwald break; 22513deb3ec6SMatthias Ringwald } 22523deb3ec6SMatthias Ringwald break; 22533deb3ec6SMatthias Ringwald 2254f125a8efSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 2255f125a8efSMatthias Ringwald case ATT_READ_MULTIPLE_VARIABLE_RSP: 2256052dc82aSMatthias Ringwald switch (gatt_client->state) { 2257169b9876SMatthias Ringwald case P_W4_READ_MULTIPLE_VARIABLE_RESPONSE: 2258f125a8efSMatthias Ringwald report_gatt_characteristic_value(gatt_client, 0u, &packet[1], size - 1u); 2259f125a8efSMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 2260f125a8efSMatthias Ringwald break; 2261f125a8efSMatthias Ringwald default: 2262f125a8efSMatthias Ringwald break; 2263f125a8efSMatthias Ringwald } 2264f125a8efSMatthias Ringwald break; 2265f125a8efSMatthias Ringwald #endif 2266f125a8efSMatthias Ringwald 22673deb3ec6SMatthias Ringwald case ATT_ERROR_RESPONSE: 22684ea43905SMatthias Ringwald if (size < 5u) return; 22694740230fSMatthias Ringwald att_status = packet[4]; 22704740230fSMatthias Ringwald switch (att_status) { 22713deb3ec6SMatthias Ringwald case ATT_ERROR_ATTRIBUTE_NOT_FOUND: { 2272052dc82aSMatthias Ringwald switch (gatt_client->state) { 22733deb3ec6SMatthias Ringwald case P_W4_SERVICE_QUERY_RESULT: 22743deb3ec6SMatthias Ringwald case P_W4_SERVICE_WITH_UUID_RESULT: 22753deb3ec6SMatthias Ringwald case P_W4_INCLUDED_SERVICE_QUERY_RESULT: 22763deb3ec6SMatthias Ringwald case P_W4_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT: 2277526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 22783deb3ec6SMatthias Ringwald break; 22793deb3ec6SMatthias Ringwald case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT: 22803deb3ec6SMatthias Ringwald case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT: 228123d583b8SMatthias Ringwald report_gatt_characteristic_end_found(gatt_client, gatt_client->end_group_handle); 2282526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, ATT_ERROR_SUCCESS); 22833deb3ec6SMatthias Ringwald break; 22843deb3ec6SMatthias Ringwald case P_W4_READ_BY_TYPE_RESPONSE: 22855cf1669fSMatthias Ringwald if (gatt_client->start_group_handle == gatt_client->query_start_handle) { 22864740230fSMatthias Ringwald att_status = ATT_ERROR_ATTRIBUTE_NOT_FOUND; 22873deb3ec6SMatthias Ringwald } else { 22884740230fSMatthias Ringwald att_status = ATT_ERROR_SUCCESS; 22893deb3ec6SMatthias Ringwald } 2290526859e7SMatthias Ringwald gatt_client_handle_transaction_complete(gatt_client, att_status); 22913deb3ec6SMatthias Ringwald break; 22923deb3ec6SMatthias Ringwald default: 22934740230fSMatthias Ringwald gatt_client_report_error_if_pending(gatt_client, att_status); 22943deb3ec6SMatthias Ringwald break; 22953deb3ec6SMatthias Ringwald } 22963deb3ec6SMatthias Ringwald break; 22973deb3ec6SMatthias Ringwald } 2298f4b33574SMatthias Ringwald 2299f4b33574SMatthias Ringwald #ifdef ENABLE_GATT_CLIENT_PAIRING 2300f4b33574SMatthias Ringwald 2301f4b33574SMatthias Ringwald case ATT_ERROR_INSUFFICIENT_AUTHENTICATION: 2302f4b33574SMatthias Ringwald case ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE: 2303a0e0c2beSMatthias Ringwald case ATT_ERROR_INSUFFICIENT_ENCRYPTION: { 2304a0e0c2beSMatthias Ringwald 2305f4b33574SMatthias Ringwald // security too low 23065cf1669fSMatthias Ringwald if (gatt_client->security_counter > 0) { 23074740230fSMatthias Ringwald gatt_client_report_error_if_pending(gatt_client, att_status); 2308f4b33574SMatthias Ringwald break; 2309f4b33574SMatthias Ringwald } 2310f4b33574SMatthias Ringwald // start security 23115cf1669fSMatthias Ringwald gatt_client->security_counter++; 2312f4b33574SMatthias Ringwald 2313f4b33574SMatthias Ringwald // setup action 2314f4b33574SMatthias Ringwald int retry = 1; 2315052dc82aSMatthias Ringwald switch (gatt_client->state){ 2316f4b33574SMatthias Ringwald case P_W4_READ_CHARACTERISTIC_VALUE_RESULT: 2317052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY ; 2318f4b33574SMatthias Ringwald break; 2319f4b33574SMatthias Ringwald case P_W4_READ_BLOB_RESULT: 2320052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_BLOB_QUERY; 2321f4b33574SMatthias Ringwald break; 2322f4b33574SMatthias Ringwald case P_W4_READ_BY_TYPE_RESPONSE: 2323052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_BY_TYPE_REQUEST; 2324f4b33574SMatthias Ringwald break; 2325f4b33574SMatthias Ringwald case P_W4_READ_MULTIPLE_RESPONSE: 2326052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_MULTIPLE_REQUEST; 2327f4b33574SMatthias Ringwald break; 2328f125a8efSMatthias Ringwald case P_W4_READ_MULTIPLE_VARIABLE_RESPONSE: 2329052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_MULTIPLE_VARIABLE_REQUEST; 2330f125a8efSMatthias Ringwald break; 2331f4b33574SMatthias Ringwald case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT: 2332052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_WRITE_CHARACTERISTIC_VALUE; 2333f4b33574SMatthias Ringwald break; 2334f4b33574SMatthias Ringwald case P_W4_PREPARE_WRITE_RESULT: 2335052dc82aSMatthias Ringwald gatt_client->state = P_W2_PREPARE_WRITE; 2336f4b33574SMatthias Ringwald break; 2337f4b33574SMatthias Ringwald case P_W4_PREPARE_WRITE_SINGLE_RESULT: 2338052dc82aSMatthias Ringwald gatt_client->state = P_W2_PREPARE_WRITE_SINGLE; 2339f4b33574SMatthias Ringwald break; 2340f4b33574SMatthias Ringwald case P_W4_PREPARE_RELIABLE_WRITE_RESULT: 2341052dc82aSMatthias Ringwald gatt_client->state = P_W2_PREPARE_RELIABLE_WRITE; 2342f4b33574SMatthias Ringwald break; 2343f4b33574SMatthias Ringwald case P_W4_EXECUTE_PREPARED_WRITE_RESULT: 2344052dc82aSMatthias Ringwald gatt_client->state = P_W2_EXECUTE_PREPARED_WRITE; 2345f4b33574SMatthias Ringwald break; 2346f4b33574SMatthias Ringwald case P_W4_CANCEL_PREPARED_WRITE_RESULT: 2347052dc82aSMatthias Ringwald gatt_client->state = P_W2_CANCEL_PREPARED_WRITE; 2348f4b33574SMatthias Ringwald break; 2349f4b33574SMatthias Ringwald case P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT: 2350052dc82aSMatthias Ringwald gatt_client->state = P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH; 2351f4b33574SMatthias Ringwald break; 2352f4b33574SMatthias Ringwald case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT: 2353052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY; 2354f4b33574SMatthias Ringwald break; 2355f4b33574SMatthias Ringwald case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT: 2356052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY; 2357f4b33574SMatthias Ringwald break; 2358f4b33574SMatthias Ringwald case P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: 2359052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR; 2360f4b33574SMatthias Ringwald break; 2361f4b33574SMatthias Ringwald case P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT: 2362052dc82aSMatthias Ringwald gatt_client->state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION; 2363f4b33574SMatthias Ringwald break; 2364f4b33574SMatthias Ringwald case P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: 2365052dc82aSMatthias Ringwald gatt_client->state = P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR; 2366f4b33574SMatthias Ringwald break; 2367f4b33574SMatthias Ringwald case P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: 2368052dc82aSMatthias Ringwald gatt_client->state = P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR; 2369f4b33574SMatthias Ringwald break; 2370f4b33574SMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE 237130cf4543SMilanka Ringwald case P_W4_SEND_SIGNED_WRITE_DONE: 2372052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_SIGNED_WRITE; 2373f4b33574SMatthias Ringwald break; 2374f4b33574SMatthias Ringwald #endif 2375f4b33574SMatthias Ringwald default: 2376052dc82aSMatthias Ringwald log_info("retry not supported for state %x", gatt_client->state); 2377f4b33574SMatthias Ringwald retry = 0; 2378f4b33574SMatthias Ringwald break; 2379f4b33574SMatthias Ringwald } 2380f4b33574SMatthias Ringwald 2381f4b33574SMatthias Ringwald if (!retry) { 23824740230fSMatthias Ringwald gatt_client_report_error_if_pending(gatt_client, att_status); 2383f4b33574SMatthias Ringwald break; 2384f4b33574SMatthias Ringwald } 2385f4b33574SMatthias Ringwald 2386f4b33574SMatthias Ringwald log_info("security error, start pairing"); 2387f4b33574SMatthias Ringwald 2388f060f108SMatthias Ringwald // start pairing for higher security level 23892197dbafSMatthias Ringwald gatt_client->wait_for_authentication_complete = true; 23904740230fSMatthias Ringwald gatt_client->pending_error_code = att_status; 23915cf1669fSMatthias Ringwald sm_request_pairing(gatt_client->con_handle); 2392f4b33574SMatthias Ringwald break; 2393a0e0c2beSMatthias Ringwald } 2394f4b33574SMatthias Ringwald #endif 2395f4b33574SMatthias Ringwald 2396f4b33574SMatthias Ringwald // nothing we can do about that 2397f4b33574SMatthias Ringwald case ATT_ERROR_INSUFFICIENT_AUTHORIZATION: 23983deb3ec6SMatthias Ringwald default: 23994740230fSMatthias Ringwald gatt_client_report_error_if_pending(gatt_client, att_status); 24003deb3ec6SMatthias Ringwald break; 24013deb3ec6SMatthias Ringwald } 24023deb3ec6SMatthias Ringwald break; 24033deb3ec6SMatthias Ringwald 24043deb3ec6SMatthias Ringwald default: 24053deb3ec6SMatthias Ringwald log_info("ATT Handler, unhandled response type 0x%02x", packet[0]); 24063deb3ec6SMatthias Ringwald break; 24073deb3ec6SMatthias Ringwald } 2408cf8e5718SMatthias Ringwald } 2409cf8e5718SMatthias Ringwald 2410cf8e5718SMatthias Ringwald static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size) { 2411cf8e5718SMatthias Ringwald gatt_client_t *gatt_client; 2412180cbe79SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC 2413b1da4983SMatthias Ringwald uint8_t status; 2414b1da4983SMatthias Ringwald hci_connection_t * hci_connection; 2415180cbe79SMatthias Ringwald hci_con_handle_t con_handle; 2416180cbe79SMatthias Ringwald #endif 2417180cbe79SMatthias Ringwald 2418cf8e5718SMatthias Ringwald if (size < 1u) return; 241959b5e157SMatthias Ringwald switch (packet_type){ 242059b5e157SMatthias Ringwald case HCI_EVENT_PACKET: 242159b5e157SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 242259b5e157SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC 242359b5e157SMatthias Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 242459b5e157SMatthias Ringwald status = l2cap_event_channel_opened_get_status(packet); 242559b5e157SMatthias Ringwald gatt_client = gatt_client_get_context_for_l2cap_cid(l2cap_event_channel_opened_get_local_cid(packet)); 2426de5a18caSMatthias Ringwald if (gatt_client != NULL){ 2427180cbe79SMatthias Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 2428180cbe79SMatthias Ringwald hci_connection = hci_connection_for_handle(con_handle); 2429ab6f9d8fSMatthias Ringwald if (status == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES){ 2430ab6f9d8fSMatthias Ringwald if ((hci_connection != NULL) && hci_connection->att_server.incoming_connection_request) { 2431180cbe79SMatthias Ringwald log_info("Collision, retry in 100ms"); 2432180cbe79SMatthias Ringwald gatt_client->state = P_W2_L2CAP_CONNECT; 2433180cbe79SMatthias Ringwald // set timer for retry 2434b1da4983SMatthias Ringwald btstack_run_loop_set_timer(&gatt_client->gc_timeout, GATT_CLIENT_COLLISION_BACKOFF_MS); 2435180cbe79SMatthias Ringwald btstack_run_loop_set_timer_handler(&gatt_client->gc_timeout, gatt_client_classic_retry); 2436180cbe79SMatthias Ringwald btstack_run_loop_add_timer(&gatt_client->gc_timeout); 2437180cbe79SMatthias Ringwald break; 2438180cbe79SMatthias Ringwald } 2439ab6f9d8fSMatthias Ringwald } 244059b5e157SMatthias Ringwald // if status != 0, gatt_client will be discarded 2441052dc82aSMatthias Ringwald gatt_client->state = P_READY; 244259b5e157SMatthias Ringwald gatt_client->con_handle = l2cap_event_channel_opened_get_handle(packet); 244359b5e157SMatthias Ringwald gatt_client->mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 244459b5e157SMatthias Ringwald gatt_client_classic_handle_connected(gatt_client, status); 2445de5a18caSMatthias Ringwald } 244659b5e157SMatthias Ringwald break; 244759b5e157SMatthias Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 244859b5e157SMatthias Ringwald gatt_client = gatt_client_get_context_for_l2cap_cid(l2cap_event_channel_closed_get_local_cid(packet)); 2449de5a18caSMatthias Ringwald if (gatt_client != NULL){ 245059b5e157SMatthias Ringwald // discard gatt client object 245159b5e157SMatthias Ringwald gatt_client_classic_handle_disconnected(gatt_client); 2452de5a18caSMatthias Ringwald } 245359b5e157SMatthias Ringwald break; 245459b5e157SMatthias Ringwald #endif 2455cf8e5718SMatthias Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 24563deb3ec6SMatthias Ringwald gatt_client_run(); 2457cf8e5718SMatthias Ringwald break; 2458cf8e5718SMatthias Ringwald // att_server has negotiated the mtu for this connection, cache if context exists 2459cf8e5718SMatthias Ringwald case ATT_EVENT_MTU_EXCHANGE_COMPLETE: 2460cf8e5718SMatthias Ringwald if (size < 6u) break; 2461cf8e5718SMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(handle); 2462de5a18caSMatthias Ringwald if (gatt_client != NULL) { 2463cf8e5718SMatthias Ringwald gatt_client->mtu = little_endian_read_16(packet, 4); 2464de5a18caSMatthias Ringwald } 2465cf8e5718SMatthias Ringwald break; 2466cf8e5718SMatthias Ringwald default: 2467cf8e5718SMatthias Ringwald break; 2468cf8e5718SMatthias Ringwald } 246959b5e157SMatthias Ringwald break; 2470cf8e5718SMatthias Ringwald 247159b5e157SMatthias Ringwald case ATT_DATA_PACKET: 2472cf8e5718SMatthias Ringwald // special cases: notifications & indications motivate creating context 2473cf8e5718SMatthias Ringwald switch (packet[0]) { 2474cf8e5718SMatthias Ringwald case ATT_HANDLE_VALUE_NOTIFICATION: 2475cf8e5718SMatthias Ringwald case ATT_HANDLE_VALUE_INDICATION: 2476cf8e5718SMatthias Ringwald gatt_client_provide_context_for_handle(handle, &gatt_client); 2477cf8e5718SMatthias Ringwald break; 2478cf8e5718SMatthias Ringwald default: 2479cf8e5718SMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(handle); 2480cf8e5718SMatthias Ringwald break; 2481cf8e5718SMatthias Ringwald } 2482cf8e5718SMatthias Ringwald 2483cf8e5718SMatthias Ringwald if (gatt_client != NULL) { 2484cf8e5718SMatthias Ringwald gatt_client_handle_att_response(gatt_client, packet, size); 2485cf8e5718SMatthias Ringwald gatt_client_run(); 2486cf8e5718SMatthias Ringwald } 248759b5e157SMatthias Ringwald break; 248859b5e157SMatthias Ringwald 248959b5e157SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC 249059b5e157SMatthias Ringwald case L2CAP_DATA_PACKET: 249159b5e157SMatthias Ringwald gatt_client = gatt_client_get_context_for_l2cap_cid(handle); 2492de5a18caSMatthias Ringwald if (gatt_client != NULL){ 249359b5e157SMatthias Ringwald gatt_client_handle_att_response(gatt_client, packet, size); 249459b5e157SMatthias Ringwald gatt_client_run(); 2495de5a18caSMatthias Ringwald } 249659b5e157SMatthias Ringwald break; 249759b5e157SMatthias Ringwald #endif 249859b5e157SMatthias Ringwald 249959b5e157SMatthias Ringwald default: 250059b5e157SMatthias Ringwald break; 250159b5e157SMatthias Ringwald } 25023deb3ec6SMatthias Ringwald } 25033deb3ec6SMatthias Ringwald 25047a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE 25053deb3ec6SMatthias Ringwald static void att_signed_write_handle_cmac_result(uint8_t hash[8]){ 2506665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 2507665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client_connections); 2508665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 25095cf1669fSMatthias Ringwald gatt_client_t * gatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it); 2510052dc82aSMatthias Ringwald if (gatt_client->state == P_W4_CMAC_RESULT){ 25113deb3ec6SMatthias Ringwald // store result 25125cf1669fSMatthias Ringwald (void)memcpy(gatt_client->cmac, hash, 8); 25135cf1669fSMatthias Ringwald // reverse_64(hash, gatt_client->cmac); 2514052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_SIGNED_WRITE; 25153deb3ec6SMatthias Ringwald gatt_client_run(); 25163deb3ec6SMatthias Ringwald return; 25173deb3ec6SMatthias Ringwald } 25183deb3ec6SMatthias Ringwald } 25193deb3ec6SMatthias Ringwald } 25203deb3ec6SMatthias Ringwald 2521b45b7749SMilanka Ringwald uint8_t gatt_client_signed_write_without_response(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t message_len, uint8_t * message){ 252240faeb84SMilanka Ringwald gatt_client_t * gatt_client; 252340faeb84SMilanka Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 252440faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 252540faeb84SMilanka Ringwald return status; 252640faeb84SMilanka Ringwald } 252740faeb84SMilanka Ringwald if (is_ready(gatt_client) == 0){ 252840faeb84SMilanka Ringwald return GATT_CLIENT_IN_WRONG_STATE; 252940faeb84SMilanka Ringwald } 25303deb3ec6SMatthias Ringwald 25315cf1669fSMatthias Ringwald gatt_client->callback = callback; 2532b45b7749SMilanka Ringwald gatt_client->attribute_handle = value_handle; 25335cf1669fSMatthias Ringwald gatt_client->attribute_length = message_len; 25345cf1669fSMatthias Ringwald gatt_client->attribute_value = message; 2535052dc82aSMatthias Ringwald gatt_client->state = P_W4_IDENTITY_RESOLVING; 25363deb3ec6SMatthias Ringwald gatt_client_run(); 253725b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 25383deb3ec6SMatthias Ringwald } 25397a766ebfSMatthias Ringwald #endif 25403deb3ec6SMatthias Ringwald 2541711e6c80SMatthias Ringwald uint8_t gatt_client_discover_primary_services(btstack_packet_handler_t callback, hci_con_handle_t con_handle){ 254240faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2543de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 254440faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 254540faeb84SMilanka Ringwald return status; 254640faeb84SMilanka Ringwald } 25473deb3ec6SMatthias Ringwald 25485cf1669fSMatthias Ringwald gatt_client->callback = callback; 25495cf1669fSMatthias Ringwald gatt_client->start_group_handle = 0x0001; 25505cf1669fSMatthias Ringwald gatt_client->end_group_handle = 0xffff; 2551052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_SERVICE_QUERY; 25528d1f34d3SMatheus Eduardo Garbelini gatt_client->uuid16 = GATT_PRIMARY_SERVICE_UUID; 25533deb3ec6SMatthias Ringwald gatt_client_run(); 255425b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 25553deb3ec6SMatthias Ringwald } 25563deb3ec6SMatthias Ringwald 25578d1f34d3SMatheus Eduardo Garbelini uint8_t gatt_client_discover_secondary_services(btstack_packet_handler_t callback, hci_con_handle_t con_handle){ 255840faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2559de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 256040faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 256140faeb84SMilanka Ringwald return status; 256240faeb84SMilanka Ringwald } 25638d1f34d3SMatheus Eduardo Garbelini 25648d1f34d3SMatheus Eduardo Garbelini gatt_client->callback = callback; 25658d1f34d3SMatheus Eduardo Garbelini gatt_client->start_group_handle = 0x0001; 25668d1f34d3SMatheus Eduardo Garbelini gatt_client->end_group_handle = 0xffff; 2567052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_SERVICE_QUERY; 25688d1f34d3SMatheus Eduardo Garbelini gatt_client->uuid16 = GATT_SECONDARY_SERVICE_UUID; 25698d1f34d3SMatheus Eduardo Garbelini gatt_client_run(); 25708d1f34d3SMatheus Eduardo Garbelini return ERROR_CODE_SUCCESS; 25718d1f34d3SMatheus Eduardo Garbelini } 25723deb3ec6SMatthias Ringwald 257368ced5c9SMatthias Ringwald uint8_t gatt_client_discover_primary_services_by_uuid16_with_context(btstack_packet_handler_t callback, hci_con_handle_t con_handle, 257468ced5c9SMatthias Ringwald uint16_t uuid16, uint16_t service_id, uint16_t connection_id){ 257540faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2576de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 257740faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 257840faeb84SMilanka Ringwald return status; 257940faeb84SMilanka Ringwald } 25803deb3ec6SMatthias Ringwald 25815cf1669fSMatthias Ringwald gatt_client->callback = callback; 258268ced5c9SMatthias Ringwald gatt_client->service_id = service_id; 258368ced5c9SMatthias Ringwald gatt_client->connection_id = connection_id; 25845cf1669fSMatthias Ringwald gatt_client->start_group_handle = 0x0001; 25855cf1669fSMatthias Ringwald gatt_client->end_group_handle = 0xffff; 2586052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_SERVICE_WITH_UUID_QUERY; 25875cf1669fSMatthias Ringwald gatt_client->uuid16 = uuid16; 25885cf1669fSMatthias Ringwald uuid_add_bluetooth_prefix((uint8_t*) &(gatt_client->uuid128), gatt_client->uuid16); 25893deb3ec6SMatthias Ringwald gatt_client_run(); 259025b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 25913deb3ec6SMatthias Ringwald } 25923deb3ec6SMatthias Ringwald 259368ced5c9SMatthias Ringwald uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){ 259468ced5c9SMatthias Ringwald return gatt_client_discover_primary_services_by_uuid16_with_context(callback, con_handle, uuid16, 0, 0); 259568ced5c9SMatthias Ringwald } 259668ced5c9SMatthias Ringwald 2597711e6c80SMatthias Ringwald uint8_t gatt_client_discover_primary_services_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, const uint8_t * uuid128){ 259840faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2599de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 260040faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 260140faeb84SMilanka Ringwald return status; 260240faeb84SMilanka Ringwald } 26033deb3ec6SMatthias Ringwald 26045cf1669fSMatthias Ringwald gatt_client->callback = callback; 26055cf1669fSMatthias Ringwald gatt_client->start_group_handle = 0x0001; 26065cf1669fSMatthias Ringwald gatt_client->end_group_handle = 0xffff; 26075cf1669fSMatthias Ringwald gatt_client->uuid16 = 0; 26085cf1669fSMatthias Ringwald (void)memcpy(gatt_client->uuid128, uuid128, 16); 2609052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_SERVICE_WITH_UUID_QUERY; 26103deb3ec6SMatthias Ringwald gatt_client_run(); 261125b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 26123deb3ec6SMatthias Ringwald } 26133deb3ec6SMatthias Ringwald 26148183ac30SMatthias Ringwald uint8_t gatt_client_discover_characteristics_for_service_with_context(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service, 26158183ac30SMatthias Ringwald uint16_t service_id, uint16_t connection_id){ 261640faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2617de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 261840faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 261940faeb84SMilanka Ringwald return status; 262040faeb84SMilanka Ringwald } 26213deb3ec6SMatthias Ringwald 26225cf1669fSMatthias Ringwald gatt_client->callback = callback; 26238183ac30SMatthias Ringwald gatt_client->service_id = service_id; 26248183ac30SMatthias Ringwald gatt_client->connection_id = connection_id; 26255cf1669fSMatthias Ringwald gatt_client->start_group_handle = service->start_group_handle; 26265cf1669fSMatthias Ringwald gatt_client->end_group_handle = service->end_group_handle; 2627ab415e75SMatthias Ringwald gatt_client->filter_with_uuid = false; 26285cf1669fSMatthias Ringwald gatt_client->characteristic_start_handle = 0; 2629052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY; 26303deb3ec6SMatthias Ringwald gatt_client_run(); 263125b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 26323deb3ec6SMatthias Ringwald } 26338183ac30SMatthias Ringwald 26348183ac30SMatthias Ringwald uint8_t gatt_client_discover_characteristics_for_service(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service){ 26358183ac30SMatthias Ringwald return gatt_client_discover_characteristics_for_service_with_context(callback, con_handle, service, 0, 0); 26368183ac30SMatthias Ringwald } 26378183ac30SMatthias Ringwald 2638aa43543aSMatthias Ringwald uint8_t gatt_client_find_included_services_for_service_with_context(btstack_packet_handler_t callback, hci_con_handle_t con_handle, 2639aa43543aSMatthias Ringwald gatt_client_service_t * service, uint16_t service_id, uint16_t connection_id){ 264040faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2641de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 264240faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 264340faeb84SMilanka Ringwald return status; 264440faeb84SMilanka Ringwald } 2645de27733dSMatthias Ringwald 26465cf1669fSMatthias Ringwald gatt_client->callback = callback; 2647aa43543aSMatthias Ringwald gatt_client->service_id = service_id; 2648aa43543aSMatthias Ringwald gatt_client->connection_id = connection_id; 26495cf1669fSMatthias Ringwald gatt_client->start_group_handle = service->start_group_handle; 26505cf1669fSMatthias Ringwald gatt_client->end_group_handle = service->end_group_handle; 2651052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_INCLUDED_SERVICE_QUERY; 26523deb3ec6SMatthias Ringwald 26533deb3ec6SMatthias Ringwald gatt_client_run(); 265425b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 26553deb3ec6SMatthias Ringwald } 26563deb3ec6SMatthias Ringwald 2657aa43543aSMatthias Ringwald uint8_t gatt_client_find_included_services_for_service(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service) { 2658aa43543aSMatthias Ringwald return gatt_client_find_included_services_for_service_with_context(callback, con_handle, service, 0, 0); 2659aa43543aSMatthias Ringwald } 2660aa43543aSMatthias Ringwald 2661711e6c80SMatthias Ringwald uint8_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){ 266240faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2663de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 266440faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 266540faeb84SMilanka Ringwald return status; 266640faeb84SMilanka Ringwald } 26673deb3ec6SMatthias Ringwald 26685cf1669fSMatthias Ringwald gatt_client->callback = callback; 26695cf1669fSMatthias Ringwald gatt_client->start_group_handle = start_handle; 26705cf1669fSMatthias Ringwald gatt_client->end_group_handle = end_handle; 2671ab415e75SMatthias Ringwald gatt_client->filter_with_uuid = true; 26725cf1669fSMatthias Ringwald gatt_client->uuid16 = uuid16; 26735cf1669fSMatthias Ringwald uuid_add_bluetooth_prefix((uint8_t*) &(gatt_client->uuid128), uuid16); 26745cf1669fSMatthias Ringwald gatt_client->characteristic_start_handle = 0; 2675052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_CHARACTERISTIC_WITH_UUID_QUERY; 26763deb3ec6SMatthias Ringwald gatt_client_run(); 267725b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 26783deb3ec6SMatthias Ringwald } 26793deb3ec6SMatthias Ringwald 2680045d700dSDavid Lechner uint8_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){ 268140faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2682de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 268340faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 268440faeb84SMilanka Ringwald return status; 268540faeb84SMilanka Ringwald } 26863deb3ec6SMatthias Ringwald 26875cf1669fSMatthias Ringwald gatt_client->callback = callback; 26885cf1669fSMatthias Ringwald gatt_client->start_group_handle = start_handle; 26895cf1669fSMatthias Ringwald gatt_client->end_group_handle = end_handle; 2690ab415e75SMatthias Ringwald gatt_client->filter_with_uuid = true; 26915cf1669fSMatthias Ringwald gatt_client->uuid16 = 0; 26925cf1669fSMatthias Ringwald (void)memcpy(gatt_client->uuid128, uuid128, 16); 26935cf1669fSMatthias Ringwald gatt_client->characteristic_start_handle = 0; 2694052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_CHARACTERISTIC_WITH_UUID_QUERY; 26953deb3ec6SMatthias Ringwald gatt_client_run(); 269625b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 26973deb3ec6SMatthias Ringwald } 26983deb3ec6SMatthias Ringwald 26993deb3ec6SMatthias Ringwald 2700b45b7749SMilanka Ringwald uint8_t gatt_client_discover_characteristics_for_service_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service, uint16_t uuid16){ 2701b45b7749SMilanka Ringwald return gatt_client_discover_characteristics_for_handle_range_by_uuid16(callback, con_handle, service->start_group_handle, service->end_group_handle, uuid16); 27023deb3ec6SMatthias Ringwald } 27033deb3ec6SMatthias Ringwald 2704b45b7749SMilanka Ringwald uint8_t gatt_client_discover_characteristics_for_service_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service, const uint8_t * uuid128){ 2705b45b7749SMilanka Ringwald return gatt_client_discover_characteristics_for_handle_range_by_uuid128(callback, con_handle, service->start_group_handle, service->end_group_handle, uuid128); 27063deb3ec6SMatthias Ringwald } 27073deb3ec6SMatthias Ringwald 2708a94d23eaSMatthias Ringwald uint8_t gatt_client_discover_characteristic_descriptors_with_context(btstack_packet_handler_t callback, hci_con_handle_t con_handle, 2709a94d23eaSMatthias Ringwald gatt_client_characteristic_t * characteristic, uint16_t service_id, uint16_t connection_id){ 271040faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2711de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 271240faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 271340faeb84SMilanka Ringwald return status; 271440faeb84SMilanka Ringwald } 27153deb3ec6SMatthias Ringwald 2716a94d23eaSMatthias Ringwald gatt_client->service_id = service_id; 2717a94d23eaSMatthias Ringwald gatt_client->connection_id = connection_id; 2718a94d23eaSMatthias Ringwald 2719544a5845SMatthias Ringwald // check if there is space for characteristics descriptors 2720544a5845SMatthias Ringwald if (characteristic->end_handle > characteristic->value_handle){ 27215cf1669fSMatthias Ringwald gatt_client->callback = callback; 27225cf1669fSMatthias Ringwald gatt_client->start_group_handle = characteristic->value_handle + 1u; 27235cf1669fSMatthias Ringwald gatt_client->end_group_handle = characteristic->end_handle; 2724052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY; 27253deb3ec6SMatthias Ringwald gatt_client_run(); 2726544a5845SMatthias Ringwald } else { 2727544a5845SMatthias Ringwald // schedule gatt complete event on next run loop iteration otherwise 2728544a5845SMatthias Ringwald gatt_client->state = P_W2_EMIT_QUERY_COMPLETE_EVENT; 2729544a5845SMatthias Ringwald gatt_client_deferred_event_emit.callback = gatt_client_emit_events; 2730544a5845SMatthias Ringwald btstack_run_loop_execute_on_main_thread(&gatt_client_deferred_event_emit); 2731544a5845SMatthias Ringwald } 273225b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 27333deb3ec6SMatthias Ringwald } 27343deb3ec6SMatthias Ringwald 2735a94d23eaSMatthias Ringwald uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){ 2736a94d23eaSMatthias Ringwald return gatt_client_discover_characteristic_descriptors_with_context(callback, con_handle, characteristic, 0, 0); 2737a94d23eaSMatthias Ringwald } 2738a94d23eaSMatthias Ringwald 2739e38d764eSMatthias Ringwald uint8_t gatt_client_read_value_of_characteristic_using_value_handle_with_context(btstack_packet_handler_t callback, 2740e38d764eSMatthias Ringwald hci_con_handle_t con_handle, 2741e38d764eSMatthias Ringwald uint16_t value_handle, 2742e38d764eSMatthias Ringwald uint16_t service_id, 2743e38d764eSMatthias Ringwald uint16_t connection_id) { 274440faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2745de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 274640faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 274740faeb84SMilanka Ringwald return status; 274840faeb84SMilanka Ringwald } 27493deb3ec6SMatthias Ringwald 27505cf1669fSMatthias Ringwald gatt_client->callback = callback; 2751e38d764eSMatthias Ringwald gatt_client->service_id = service_id; 2752e38d764eSMatthias Ringwald gatt_client->connection_id = connection_id; 27535cf1669fSMatthias Ringwald gatt_client->attribute_handle = value_handle; 27545cf1669fSMatthias Ringwald gatt_client->attribute_offset = 0; 2755052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY; 27563deb3ec6SMatthias Ringwald gatt_client_run(); 275725b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 27583deb3ec6SMatthias Ringwald } 27593deb3ec6SMatthias Ringwald 2760e38d764eSMatthias Ringwald uint8_t gatt_client_read_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle){ 2761e38d764eSMatthias Ringwald return gatt_client_read_value_of_characteristic_using_value_handle_with_context(callback, con_handle, value_handle, 0, 0); 2762e38d764eSMatthias Ringwald 2763e38d764eSMatthias Ringwald } 2764e38d764eSMatthias Ringwald 2765711e6c80SMatthias Ringwald uint8_t gatt_client_read_value_of_characteristics_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){ 276640faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2767de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 276840faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 276940faeb84SMilanka Ringwald return status; 277040faeb84SMilanka Ringwald } 27713deb3ec6SMatthias Ringwald 27725cf1669fSMatthias Ringwald gatt_client->callback = callback; 27735cf1669fSMatthias Ringwald gatt_client->start_group_handle = start_handle; 27745cf1669fSMatthias Ringwald gatt_client->end_group_handle = end_handle; 27755cf1669fSMatthias Ringwald gatt_client->query_start_handle = start_handle; 27765cf1669fSMatthias Ringwald gatt_client->query_end_handle = end_handle; 27775cf1669fSMatthias Ringwald gatt_client->uuid16 = uuid16; 27785cf1669fSMatthias Ringwald uuid_add_bluetooth_prefix((uint8_t*) &(gatt_client->uuid128), uuid16); 2779052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_BY_TYPE_REQUEST; 27803deb3ec6SMatthias Ringwald gatt_client_run(); 278125b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 27823deb3ec6SMatthias Ringwald } 27833deb3ec6SMatthias Ringwald 2784045d700dSDavid Lechner uint8_t gatt_client_read_value_of_characteristics_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){ 278540faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2786de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 278740faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 278840faeb84SMilanka Ringwald return status; 278940faeb84SMilanka Ringwald } 27903deb3ec6SMatthias Ringwald 27915cf1669fSMatthias Ringwald gatt_client->callback = callback; 27925cf1669fSMatthias Ringwald gatt_client->start_group_handle = start_handle; 27935cf1669fSMatthias Ringwald gatt_client->end_group_handle = end_handle; 27945cf1669fSMatthias Ringwald gatt_client->query_start_handle = start_handle; 27955cf1669fSMatthias Ringwald gatt_client->query_end_handle = end_handle; 27965cf1669fSMatthias Ringwald gatt_client->uuid16 = 0; 27975cf1669fSMatthias Ringwald (void)memcpy(gatt_client->uuid128, uuid128, 16); 2798052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_BY_TYPE_REQUEST; 27993deb3ec6SMatthias Ringwald gatt_client_run(); 280025b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 28013deb3ec6SMatthias Ringwald } 28023deb3ec6SMatthias Ringwald 28033deb3ec6SMatthias Ringwald 2804b45b7749SMilanka Ringwald uint8_t gatt_client_read_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){ 2805b45b7749SMilanka Ringwald return gatt_client_read_value_of_characteristic_using_value_handle(callback, con_handle, characteristic->value_handle); 28063deb3ec6SMatthias Ringwald } 28073deb3ec6SMatthias Ringwald 2808b45b7749SMilanka Ringwald uint8_t gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t offset){ 280940faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2810de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 281140faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 281240faeb84SMilanka Ringwald return status; 281340faeb84SMilanka Ringwald } 28143deb3ec6SMatthias Ringwald 28155cf1669fSMatthias Ringwald gatt_client->callback = callback; 2816b45b7749SMilanka Ringwald gatt_client->attribute_handle = value_handle; 28175cf1669fSMatthias Ringwald gatt_client->attribute_offset = offset; 2818052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_BLOB_QUERY; 28193deb3ec6SMatthias Ringwald gatt_client_run(); 282025b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 28213deb3ec6SMatthias Ringwald } 2822691e02c2SMatthias Ringwald uint8_t gatt_client_read_long_value_of_characteristic_using_value_handle_with_context(btstack_packet_handler_t callback, 2823691e02c2SMatthias Ringwald hci_con_handle_t con_handle, uint16_t value_handle, 2824691e02c2SMatthias Ringwald uint16_t service_id, uint16_t connection_id){ 2825691e02c2SMatthias Ringwald // TODO: move into gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset once 2826691e02c2SMatthias Ringwald // gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset_and_context exists 2827691e02c2SMatthias Ringwald gatt_client_t * gatt_client; 2828691e02c2SMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 2829691e02c2SMatthias Ringwald if (status != ERROR_CODE_SUCCESS){ 2830691e02c2SMatthias Ringwald return status; 2831691e02c2SMatthias Ringwald } 2832691e02c2SMatthias Ringwald gatt_client->service_id = service_id; 2833691e02c2SMatthias Ringwald gatt_client->connection_id = connection_id; 2834691e02c2SMatthias Ringwald return gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(callback, con_handle, value_handle, 0); 2835691e02c2SMatthias Ringwald } 28363deb3ec6SMatthias Ringwald 2837b45b7749SMilanka Ringwald uint8_t gatt_client_read_long_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle){ 2838691e02c2SMatthias Ringwald return gatt_client_read_long_value_of_characteristic_using_value_handle_with_context(callback, con_handle, value_handle, 0, 0); 28393deb3ec6SMatthias Ringwald } 28403deb3ec6SMatthias Ringwald 2841b45b7749SMilanka Ringwald uint8_t gatt_client_read_long_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){ 2842b45b7749SMilanka Ringwald return gatt_client_read_long_value_of_characteristic_using_value_handle(callback, con_handle, characteristic->value_handle); 28433deb3ec6SMatthias Ringwald } 28443deb3ec6SMatthias Ringwald 2845f125a8efSMatthias Ringwald static uint8_t gatt_client_read_multiple_characteristic_values_with_state(btstack_packet_handler_t callback, hci_con_handle_t con_handle, int num_value_handles, uint16_t * value_handles, gatt_client_state_t state){ 284640faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2847de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 284840faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 284940faeb84SMilanka Ringwald return status; 285040faeb84SMilanka Ringwald } 28513deb3ec6SMatthias Ringwald 2852f125a8efSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 2853f125a8efSMatthias Ringwald if (state == P_W2_SEND_READ_MULTIPLE_VARIABLE_REQUEST){ 2854f125a8efSMatthias Ringwald if (gatt_client->bearer_type != ATT_BEARER_ENHANCED_LE){ 2855f125a8efSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2856f125a8efSMatthias Ringwald } 2857f125a8efSMatthias Ringwald } 2858f125a8efSMatthias Ringwald #endif 2859f125a8efSMatthias Ringwald 28605cf1669fSMatthias Ringwald gatt_client->callback = callback; 28615cf1669fSMatthias Ringwald gatt_client->read_multiple_handle_count = num_value_handles; 28625cf1669fSMatthias Ringwald gatt_client->read_multiple_handles = value_handles; 2863052dc82aSMatthias Ringwald gatt_client->state = state; 28643deb3ec6SMatthias Ringwald gatt_client_run(); 286525b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 28663deb3ec6SMatthias Ringwald } 28673deb3ec6SMatthias Ringwald 2868f125a8efSMatthias Ringwald uint8_t gatt_client_read_multiple_characteristic_values(btstack_packet_handler_t callback, hci_con_handle_t con_handle, int num_value_handles, uint16_t * value_handles){ 2869f125a8efSMatthias Ringwald return gatt_client_read_multiple_characteristic_values_with_state(callback, con_handle, num_value_handles, value_handles, P_W2_SEND_READ_MULTIPLE_REQUEST); 2870f125a8efSMatthias Ringwald } 2871f125a8efSMatthias Ringwald 2872f125a8efSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 2873f125a8efSMatthias Ringwald uint8_t gatt_client_read_multiple_variable_characteristic_values(btstack_packet_handler_t callback, hci_con_handle_t con_handle, int num_value_handles, uint16_t * value_handles){ 2874f125a8efSMatthias Ringwald return gatt_client_read_multiple_characteristic_values_with_state(callback, con_handle, num_value_handles, value_handles, P_W2_SEND_READ_MULTIPLE_VARIABLE_REQUEST); 2875f125a8efSMatthias Ringwald } 2876f125a8efSMatthias Ringwald #endif 2877f125a8efSMatthias Ringwald 2878de9f8e94SMatthias Ringwald uint8_t gatt_client_write_value_of_characteristic_without_response(hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){ 287940faeb84SMilanka Ringwald gatt_client_t * gatt_client; 288040faeb84SMilanka Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 288140faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 288240faeb84SMilanka Ringwald return status; 288340faeb84SMilanka Ringwald } 28843deb3ec6SMatthias Ringwald 2885dda77937SMatthias Ringwald if (value_length > (gatt_client->mtu - 3u)) return GATT_CLIENT_VALUE_TOO_LONG; 28865cf1669fSMatthias Ringwald if (!att_dispatch_client_can_send_now(gatt_client->con_handle)) return GATT_CLIENT_BUSY; 28873deb3ec6SMatthias Ringwald 28886e7b444cSMatthias Ringwald return att_write_request(gatt_client, ATT_WRITE_COMMAND, value_handle, value_length, value); 28893deb3ec6SMatthias Ringwald } 2890b444aa75SMatthias Ringwald uint8_t gatt_client_write_value_of_characteristic_with_context(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, 2891b444aa75SMatthias Ringwald uint16_t value_length, uint8_t * value, uint16_t service_id, uint16_t connection_id){ 289240faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2893de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 289440faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 289540faeb84SMilanka Ringwald return status; 289640faeb84SMilanka Ringwald } 28973deb3ec6SMatthias Ringwald 28985cf1669fSMatthias Ringwald gatt_client->callback = callback; 2899b444aa75SMatthias Ringwald gatt_client->service_id = service_id; 2900b444aa75SMatthias Ringwald gatt_client->connection_id = connection_id; 29015cf1669fSMatthias Ringwald gatt_client->attribute_handle = value_handle; 29025cf1669fSMatthias Ringwald gatt_client->attribute_length = value_length; 2903b45b7749SMilanka Ringwald gatt_client->attribute_value = value; 2904052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_WRITE_CHARACTERISTIC_VALUE; 29053deb3ec6SMatthias Ringwald gatt_client_run(); 290625b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 29073deb3ec6SMatthias Ringwald } 2908b444aa75SMatthias Ringwald uint8_t gatt_client_write_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value) { 2909b444aa75SMatthias Ringwald return gatt_client_write_value_of_characteristic_with_context(callback, con_handle, value_handle, value_length, value, 0, 0); 2910b444aa75SMatthias Ringwald } 29113deb3ec6SMatthias Ringwald 2912b45b7749SMilanka Ringwald uint8_t gatt_client_write_long_value_of_characteristic_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t offset, uint16_t value_length, uint8_t * value){ 291340faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2914de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 291540faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 291640faeb84SMilanka Ringwald return status; 291740faeb84SMilanka Ringwald } 29183deb3ec6SMatthias Ringwald 29195cf1669fSMatthias Ringwald gatt_client->callback = callback; 29205cf1669fSMatthias Ringwald gatt_client->attribute_handle = value_handle; 29215cf1669fSMatthias Ringwald gatt_client->attribute_length = value_length; 29225cf1669fSMatthias Ringwald gatt_client->attribute_offset = offset; 2923b45b7749SMilanka Ringwald gatt_client->attribute_value = value; 2924052dc82aSMatthias Ringwald gatt_client->state = P_W2_PREPARE_WRITE; 29253deb3ec6SMatthias Ringwald gatt_client_run(); 292625b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 29273deb3ec6SMatthias Ringwald } 29283deb3ec6SMatthias Ringwald 2929b538fb89SMatthias Ringwald uint8_t gatt_client_write_long_value_of_characteristic_with_context(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value, uint16_t service_id, uint16_t connection_id){ 2930b538fb89SMatthias Ringwald // TODO: move into gatt_client_write_long_value_of_characteristic_with_offset once gatt_client_write_long_value_of_characteristic_with_offset_with_context exists 2931b538fb89SMatthias Ringwald gatt_client_t * gatt_client; 2932b538fb89SMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 2933b538fb89SMatthias Ringwald if (status != ERROR_CODE_SUCCESS){ 2934b538fb89SMatthias Ringwald return status; 2935b538fb89SMatthias Ringwald } 2936b538fb89SMatthias Ringwald gatt_client->service_id = service_id; 2937b538fb89SMatthias Ringwald gatt_client->connection_id = connection_id; 29389c662c9bSMatthias Ringwald return gatt_client_write_long_value_of_characteristic_with_offset(callback, con_handle, value_handle, 0, value_length, value); 29393deb3ec6SMatthias Ringwald } 29403deb3ec6SMatthias Ringwald 2941b538fb89SMatthias Ringwald uint8_t gatt_client_write_long_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){ 2942b538fb89SMatthias Ringwald return gatt_client_write_long_value_of_characteristic_with_context(callback, con_handle, value_handle, value_length, value, 0, 0); 2943b538fb89SMatthias Ringwald } 2944b538fb89SMatthias Ringwald 2945711e6c80SMatthias Ringwald uint8_t gatt_client_reliable_write_long_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){ 294640faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2947de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 294840faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 294940faeb84SMilanka Ringwald return status; 295040faeb84SMilanka Ringwald } 29513deb3ec6SMatthias Ringwald 29525cf1669fSMatthias Ringwald gatt_client->callback = callback; 29535cf1669fSMatthias Ringwald gatt_client->attribute_handle = value_handle; 29545cf1669fSMatthias Ringwald gatt_client->attribute_length = value_length; 29555cf1669fSMatthias Ringwald gatt_client->attribute_offset = 0; 29565cf1669fSMatthias Ringwald gatt_client->attribute_value = value; 2957052dc82aSMatthias Ringwald gatt_client->state = P_W2_PREPARE_RELIABLE_WRITE; 29583deb3ec6SMatthias Ringwald gatt_client_run(); 295925b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 29603deb3ec6SMatthias Ringwald } 29613deb3ec6SMatthias Ringwald 2962cb5b2b64SMatthias Ringwald uint8_t gatt_client_write_client_characteristic_configuration_with_context(btstack_packet_handler_t callback, hci_con_handle_t con_handle, 2963cb5b2b64SMatthias Ringwald gatt_client_characteristic_t * characteristic, uint16_t configuration, uint16_t service_id, uint16_t connection_id){ 296440faeb84SMilanka Ringwald gatt_client_t * gatt_client; 2965de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 296640faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 296740faeb84SMilanka Ringwald return status; 296840faeb84SMilanka Ringwald } 29693deb3ec6SMatthias Ringwald 29708915696fSMilanka Ringwald if (configuration > 3){ 29718915696fSMilanka Ringwald return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 29728915696fSMilanka Ringwald } 29738915696fSMilanka Ringwald 29743deb3ec6SMatthias Ringwald if ( (configuration & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) && 29754ea43905SMatthias Ringwald ((characteristic->properties & ATT_PROPERTY_NOTIFY) == 0u)) { 2976d8e8f12aSMatthias Ringwald log_info("gatt_client_write_client_characteristic_configuration: GATT_CLIENT_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED"); 2977616edd56SMatthias Ringwald return GATT_CLIENT_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED; 29783deb3ec6SMatthias Ringwald } else if ( (configuration & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION) && 29794ea43905SMatthias Ringwald ((characteristic->properties & ATT_PROPERTY_INDICATE) == 0u)){ 2980d8e8f12aSMatthias Ringwald log_info("gatt_client_write_client_characteristic_configuration: GATT_CLIENT_CHARACTERISTIC_INDICATION_NOT_SUPPORTED"); 2981616edd56SMatthias Ringwald return GATT_CLIENT_CHARACTERISTIC_INDICATION_NOT_SUPPORTED; 29823deb3ec6SMatthias Ringwald } 29833deb3ec6SMatthias Ringwald 29845cf1669fSMatthias Ringwald gatt_client->callback = callback; 2985cb5b2b64SMatthias Ringwald gatt_client->service_id = service_id; 2986cb5b2b64SMatthias Ringwald gatt_client->connection_id = connection_id; 29875cf1669fSMatthias Ringwald gatt_client->start_group_handle = characteristic->value_handle; 29885cf1669fSMatthias Ringwald gatt_client->end_group_handle = characteristic->end_handle; 29895cf1669fSMatthias Ringwald little_endian_store_16(gatt_client->client_characteristic_configuration_value, 0, configuration); 29903deb3ec6SMatthias Ringwald 2991abdc9fb5SMatthias Ringwald #ifdef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY 29925cf1669fSMatthias Ringwald gatt_client->gatt_client_state = P_W2_SEND_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY; 2993abdc9fb5SMatthias Ringwald #else 2994052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY; 2995abdc9fb5SMatthias Ringwald #endif 29963deb3ec6SMatthias Ringwald gatt_client_run(); 29979cb80b17SMilanka Ringwald return ERROR_CODE_SUCCESS; 29983deb3ec6SMatthias Ringwald } 29993deb3ec6SMatthias Ringwald 3000cb5b2b64SMatthias Ringwald uint8_t gatt_client_write_client_characteristic_configuration(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic, uint16_t configuration){ 3001cb5b2b64SMatthias Ringwald return gatt_client_write_client_characteristic_configuration_with_context(callback, con_handle, characteristic, configuration, 0, 0); 3002cb5b2b64SMatthias Ringwald } 3003cb5b2b64SMatthias Ringwald 3004711e6c80SMatthias Ringwald uint8_t gatt_client_read_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle){ 300540faeb84SMilanka Ringwald gatt_client_t * gatt_client; 3006de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 300740faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 300840faeb84SMilanka Ringwald return status; 300940faeb84SMilanka Ringwald } 30103deb3ec6SMatthias Ringwald 30115cf1669fSMatthias Ringwald gatt_client->callback = callback; 30125cf1669fSMatthias Ringwald gatt_client->attribute_handle = descriptor_handle; 30133deb3ec6SMatthias Ringwald 3014052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY; 30153deb3ec6SMatthias Ringwald gatt_client_run(); 301625b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 30173deb3ec6SMatthias Ringwald } 30183deb3ec6SMatthias Ringwald 3019711e6c80SMatthias Ringwald uint8_t gatt_client_read_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor){ 30209c662c9bSMatthias Ringwald return gatt_client_read_characteristic_descriptor_using_descriptor_handle(callback, con_handle, descriptor->handle); 30213deb3ec6SMatthias Ringwald } 30223deb3ec6SMatthias Ringwald 3023711e6c80SMatthias Ringwald uint8_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t offset){ 302440faeb84SMilanka Ringwald gatt_client_t * gatt_client; 3025de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 302640faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 302740faeb84SMilanka Ringwald return status; 302840faeb84SMilanka Ringwald } 30293deb3ec6SMatthias Ringwald 30305cf1669fSMatthias Ringwald gatt_client->callback = callback; 30315cf1669fSMatthias Ringwald gatt_client->attribute_handle = descriptor_handle; 30325cf1669fSMatthias Ringwald gatt_client->attribute_offset = offset; 3033052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY; 30343deb3ec6SMatthias Ringwald gatt_client_run(); 303525b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 30363deb3ec6SMatthias Ringwald } 30373deb3ec6SMatthias Ringwald 3038711e6c80SMatthias Ringwald uint8_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle){ 30399c662c9bSMatthias Ringwald return gatt_client_read_long_characteristic_descriptor_using_descriptor_handle_with_offset(callback, con_handle, descriptor_handle, 0); 30403deb3ec6SMatthias Ringwald } 30413deb3ec6SMatthias Ringwald 3042711e6c80SMatthias Ringwald uint8_t gatt_client_read_long_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor){ 30439c662c9bSMatthias Ringwald return gatt_client_read_long_characteristic_descriptor_using_descriptor_handle(callback, con_handle, descriptor->handle); 30443deb3ec6SMatthias Ringwald } 30453deb3ec6SMatthias Ringwald 3046b45b7749SMilanka Ringwald uint8_t gatt_client_write_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t value_length, uint8_t * value){ 304740faeb84SMilanka Ringwald gatt_client_t * gatt_client; 3048de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 304940faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 305040faeb84SMilanka Ringwald return status; 305140faeb84SMilanka Ringwald } 30523deb3ec6SMatthias Ringwald 30535cf1669fSMatthias Ringwald gatt_client->callback = callback; 30545cf1669fSMatthias Ringwald gatt_client->attribute_handle = descriptor_handle; 3055b45b7749SMilanka Ringwald gatt_client->attribute_length = value_length; 30565cf1669fSMatthias Ringwald gatt_client->attribute_offset = 0; 3057b45b7749SMilanka Ringwald gatt_client->attribute_value = value; 3058052dc82aSMatthias Ringwald gatt_client->state = P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR; 30593deb3ec6SMatthias Ringwald gatt_client_run(); 306025b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 30613deb3ec6SMatthias Ringwald } 30623deb3ec6SMatthias Ringwald 306348cdff9cSMilanka Ringwald uint8_t gatt_client_write_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor, uint16_t value_length, uint8_t * value){ 306448cdff9cSMilanka Ringwald return gatt_client_write_characteristic_descriptor_using_descriptor_handle(callback, con_handle, descriptor->handle, value_length, value); 30653deb3ec6SMatthias Ringwald } 30663deb3ec6SMatthias Ringwald 3067b45b7749SMilanka Ringwald uint8_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t offset, uint16_t value_length, uint8_t * value){ 306840faeb84SMilanka Ringwald gatt_client_t * gatt_client; 3069de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 307040faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 307140faeb84SMilanka Ringwald return status; 307240faeb84SMilanka Ringwald } 30733deb3ec6SMatthias Ringwald 30745cf1669fSMatthias Ringwald gatt_client->callback = callback; 30755cf1669fSMatthias Ringwald gatt_client->attribute_handle = descriptor_handle; 3076b45b7749SMilanka Ringwald gatt_client->attribute_length = value_length; 30775cf1669fSMatthias Ringwald gatt_client->attribute_offset = offset; 3078b45b7749SMilanka Ringwald gatt_client->attribute_value = value; 3079052dc82aSMatthias Ringwald gatt_client->state = P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR; 30803deb3ec6SMatthias Ringwald gatt_client_run(); 308125b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 30823deb3ec6SMatthias Ringwald } 30833deb3ec6SMatthias Ringwald 3084b45b7749SMilanka Ringwald uint8_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t value_length, uint8_t * value){ 3085b45b7749SMilanka Ringwald return gatt_client_write_long_characteristic_descriptor_using_descriptor_handle_with_offset(callback, con_handle, descriptor_handle, 0, value_length, value); 30863deb3ec6SMatthias Ringwald } 30873deb3ec6SMatthias Ringwald 3088b45b7749SMilanka Ringwald uint8_t gatt_client_write_long_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor, uint16_t value_length, uint8_t * value){ 3089b45b7749SMilanka Ringwald return gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(callback, con_handle, descriptor->handle, value_length, value); 30903deb3ec6SMatthias Ringwald } 30913deb3ec6SMatthias Ringwald 30923deb3ec6SMatthias Ringwald /** 30933deb3ec6SMatthias Ringwald * @brief -> gatt complete event 30943deb3ec6SMatthias Ringwald */ 3095b45b7749SMilanka Ringwald uint8_t gatt_client_prepare_write(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint16_t value_length, uint8_t * value){ 309640faeb84SMilanka Ringwald gatt_client_t * gatt_client; 3097de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 309840faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 309940faeb84SMilanka Ringwald return status; 310040faeb84SMilanka Ringwald } 31013deb3ec6SMatthias Ringwald 31025cf1669fSMatthias Ringwald gatt_client->callback = callback; 31035cf1669fSMatthias Ringwald gatt_client->attribute_handle = attribute_handle; 3104b45b7749SMilanka Ringwald gatt_client->attribute_length = value_length; 31055cf1669fSMatthias Ringwald gatt_client->attribute_offset = offset; 3106b45b7749SMilanka Ringwald gatt_client->attribute_value = value; 3107052dc82aSMatthias Ringwald gatt_client->state = P_W2_PREPARE_WRITE_SINGLE; 31083deb3ec6SMatthias Ringwald gatt_client_run(); 310925b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 31103deb3ec6SMatthias Ringwald } 31113deb3ec6SMatthias Ringwald 31123deb3ec6SMatthias Ringwald /** 31133deb3ec6SMatthias Ringwald * @brief -> gatt complete event 31143deb3ec6SMatthias Ringwald */ 3115711e6c80SMatthias Ringwald uint8_t gatt_client_execute_write(btstack_packet_handler_t callback, hci_con_handle_t con_handle){ 311640faeb84SMilanka Ringwald gatt_client_t * gatt_client; 3117de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 311840faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 311940faeb84SMilanka Ringwald return status; 312040faeb84SMilanka Ringwald } 31213deb3ec6SMatthias Ringwald 31225cf1669fSMatthias Ringwald gatt_client->callback = callback; 3123052dc82aSMatthias Ringwald gatt_client->state = P_W2_EXECUTE_PREPARED_WRITE; 31243deb3ec6SMatthias Ringwald gatt_client_run(); 312525b7c058SMilanka Ringwald return ERROR_CODE_SUCCESS; 31263deb3ec6SMatthias Ringwald } 31273deb3ec6SMatthias Ringwald 31283deb3ec6SMatthias Ringwald /** 31293deb3ec6SMatthias Ringwald * @brief -> gatt complete event 31303deb3ec6SMatthias Ringwald */ 3131711e6c80SMatthias Ringwald uint8_t gatt_client_cancel_write(btstack_packet_handler_t callback, hci_con_handle_t con_handle){ 313240faeb84SMilanka Ringwald gatt_client_t * gatt_client; 3133de27733dSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client); 313440faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 313540faeb84SMilanka Ringwald return status; 313640faeb84SMilanka Ringwald } 31373deb3ec6SMatthias Ringwald 31385cf1669fSMatthias Ringwald gatt_client->callback = callback; 3139052dc82aSMatthias Ringwald gatt_client->state = P_W2_CANCEL_PREPARED_WRITE; 31403deb3ec6SMatthias Ringwald gatt_client_run(); 31417d2258b3SMilanka Ringwald return ERROR_CODE_SUCCESS; 31423deb3ec6SMatthias Ringwald } 31433deb3ec6SMatthias Ringwald 3144313e337bSMatthias Ringwald void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){ 31456ba2ad22SMatthias Ringwald service->start_group_handle = little_endian_read_16(packet, offset); 31466ba2ad22SMatthias Ringwald service->end_group_handle = little_endian_read_16(packet, offset + 2); 31476ba2ad22SMatthias Ringwald reverse_128(&packet[offset + 4], service->uuid128); 31486ba2ad22SMatthias Ringwald if (uuid_has_bluetooth_prefix(service->uuid128)){ 31496ba2ad22SMatthias Ringwald service->uuid16 = big_endian_read_32(service->uuid128, 0); 3150c839c6f9SMatthias Ringwald } else { 3151c839c6f9SMatthias Ringwald service->uuid16 = 0; 31526ba2ad22SMatthias Ringwald } 31536ba2ad22SMatthias Ringwald } 31546ba2ad22SMatthias Ringwald 3155313e337bSMatthias Ringwald void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){ 31566ba2ad22SMatthias Ringwald characteristic->start_handle = little_endian_read_16(packet, offset); 31576ba2ad22SMatthias Ringwald characteristic->value_handle = little_endian_read_16(packet, offset + 2); 31586ba2ad22SMatthias Ringwald characteristic->end_handle = little_endian_read_16(packet, offset + 4); 31596ba2ad22SMatthias Ringwald characteristic->properties = little_endian_read_16(packet, offset + 6); 316086c38559SMatthias Ringwald reverse_128(&packet[offset+8], characteristic->uuid128); 31616ba2ad22SMatthias Ringwald if (uuid_has_bluetooth_prefix(characteristic->uuid128)){ 31626ba2ad22SMatthias Ringwald characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0); 3163c839c6f9SMatthias Ringwald } else { 3164c839c6f9SMatthias Ringwald characteristic->uuid16 = 0; 31656ba2ad22SMatthias Ringwald } 31666ba2ad22SMatthias Ringwald } 31676ba2ad22SMatthias Ringwald 3168313e337bSMatthias Ringwald void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){ 31696ba2ad22SMatthias Ringwald descriptor->handle = little_endian_read_16(packet, offset); 31706ba2ad22SMatthias Ringwald reverse_128(&packet[offset+2], descriptor->uuid128); 3171b4895529SJakob Krantz if (uuid_has_bluetooth_prefix(descriptor->uuid128)){ 3172b4895529SJakob Krantz descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0); 3173c839c6f9SMatthias Ringwald } else { 3174c839c6f9SMatthias Ringwald descriptor->uuid16 = 0; 3175b4895529SJakob Krantz } 31766ba2ad22SMatthias Ringwald } 31775cf6c434SJakob Krantz 31785cf6c434SJakob Krantz void gatt_client_send_mtu_negotiation(btstack_packet_handler_t callback, hci_con_handle_t con_handle){ 317940faeb84SMilanka Ringwald gatt_client_t * gatt_client; 318040faeb84SMilanka Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 318140faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 318240faeb84SMilanka Ringwald return; 318340faeb84SMilanka Ringwald } 318440faeb84SMilanka Ringwald if (gatt_client->mtu_state == MTU_AUTO_EXCHANGE_DISABLED){ 318540faeb84SMilanka Ringwald gatt_client->callback = callback; 318640faeb84SMilanka Ringwald gatt_client->mtu_state = SEND_MTU_EXCHANGE; 31875cf6c434SJakob Krantz gatt_client_run(); 31885cf6c434SJakob Krantz } 31895cf6c434SJakob Krantz } 319047181045SMatthias Ringwald 319159d34cd2SMatthias Ringwald uint8_t gatt_client_request_to_write_without_response(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle){ 319259d34cd2SMatthias Ringwald gatt_client_t * gatt_client; 319359d34cd2SMatthias Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 319459d34cd2SMatthias Ringwald if (status != ERROR_CODE_SUCCESS){ 319559d34cd2SMatthias Ringwald return status; 319659d34cd2SMatthias Ringwald } 319759d34cd2SMatthias Ringwald bool added = btstack_linked_list_add_tail(&gatt_client->write_without_response_requests, (btstack_linked_item_t*) callback_registration); 31982832a98aSMatthias Ringwald if (added == false){ 319959d34cd2SMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 32002832a98aSMatthias Ringwald } else { 32012832a98aSMatthias Ringwald att_dispatch_client_request_can_send_now_event(gatt_client->con_handle); 32022832a98aSMatthias Ringwald return ERROR_CODE_SUCCESS; 320359d34cd2SMatthias Ringwald } 320459d34cd2SMatthias Ringwald } 320559d34cd2SMatthias Ringwald 320653e9c18fSMatthias Ringwald uint8_t gatt_client_request_to_send_gatt_query(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle){ 320753e9c18fSMatthias Ringwald gatt_client_t * gatt_client; 320853e9c18fSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 320953e9c18fSMatthias Ringwald if (status != ERROR_CODE_SUCCESS){ 321053e9c18fSMatthias Ringwald return status; 321153e9c18fSMatthias Ringwald } 321253e9c18fSMatthias Ringwald bool added = btstack_linked_list_add_tail(&gatt_client->query_requests, (btstack_linked_item_t*) callback_registration); 32132832a98aSMatthias Ringwald if (added == false){ 321453e9c18fSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 32152832a98aSMatthias Ringwald } else { 32162832a98aSMatthias Ringwald gatt_client_notify_can_send_query(gatt_client); 32172832a98aSMatthias Ringwald return ERROR_CODE_SUCCESS; 321853e9c18fSMatthias Ringwald } 321953e9c18fSMatthias Ringwald } 322053e9c18fSMatthias Ringwald 322148553f67SDirk Helbig uint8_t gatt_client_remove_gatt_query(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle){ 322248553f67SDirk Helbig gatt_client_t * gatt_client; 322348553f67SDirk Helbig uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 322448553f67SDirk Helbig if (status != ERROR_CODE_SUCCESS){ 322548553f67SDirk Helbig return status; 322648553f67SDirk Helbig } 322748553f67SDirk Helbig (void)btstack_linked_list_remove(&gatt_client->query_requests, (btstack_linked_item_t*) callback_registration); 322848553f67SDirk Helbig return ERROR_CODE_SUCCESS; 322948553f67SDirk Helbig } 323048553f67SDirk Helbig 323147181045SMatthias Ringwald uint8_t gatt_client_request_can_write_without_response_event(btstack_packet_handler_t callback, hci_con_handle_t con_handle){ 323240faeb84SMilanka Ringwald gatt_client_t * gatt_client; 323340faeb84SMilanka Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 323440faeb84SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 323540faeb84SMilanka Ringwald return status; 323640faeb84SMilanka Ringwald } 323740faeb84SMilanka Ringwald if (gatt_client->write_without_response_callback != NULL){ 323840faeb84SMilanka Ringwald return GATT_CLIENT_IN_WRONG_STATE; 323940faeb84SMilanka Ringwald } 324040faeb84SMilanka Ringwald gatt_client->write_without_response_callback = callback; 324140faeb84SMilanka Ringwald att_dispatch_client_request_can_send_now_event(gatt_client->con_handle); 32427d2258b3SMilanka Ringwald return ERROR_CODE_SUCCESS; 324347181045SMatthias Ringwald } 3244842492f0SMatthias Ringwald 3245842492f0SMatthias Ringwald #ifdef ENABLE_GATT_CLIENT_SERVICE_CHANGED 324658e8c9f5SMatthias Ringwald void gatt_client_add_service_changed_handler(btstack_packet_callback_registration_t * callback) { 324758e8c9f5SMatthias Ringwald btstack_linked_list_add_tail(&gatt_client_service_changed_handler, (btstack_linked_item_t*) callback); 324858e8c9f5SMatthias Ringwald } 3249a6121b51SMilanka Ringwald 325058e8c9f5SMatthias Ringwald void gatt_client_remove_service_changed_handler(btstack_packet_callback_registration_t * callback){ 325158e8c9f5SMatthias Ringwald btstack_linked_list_remove(&gatt_client_service_changed_handler, (btstack_linked_item_t*) callback); 325258e8c9f5SMatthias Ringwald } 3253842492f0SMatthias Ringwald #endif 32547627a0deSMatthias Ringwald 32557627a0deSMatthias Ringwald #if defined(ENABLE_GATT_OVER_CLASSIC) || defined(ENABLE_GATT_OVER_EATT) 32561450cdc6SMatthias Ringwald 32571450cdc6SMatthias Ringwald #include "hci_event.h" 32581450cdc6SMatthias Ringwald 32591450cdc6SMatthias Ringwald static const hci_event_t gatt_client_connected = { 3260b2d70d58SMatthias Ringwald GATT_EVENT_CONNECTED, 0, "11BH" 32611450cdc6SMatthias Ringwald }; 32621450cdc6SMatthias Ringwald 32636b4a68c3SMatthias Ringwald static const hci_event_t gatt_client_disconnected = { 32646b4a68c3SMatthias Ringwald GATT_EVENT_DISCONNECTED, 0, "H" 32656b4a68c3SMatthias Ringwald }; 32661c7a19feSMatthias Ringwald 3267b2d70d58SMatthias Ringwald static void 3268b2d70d58SMatthias Ringwald gatt_client_emit_connected(btstack_packet_handler_t callback, uint8_t status, bd_addr_type_t addr_type, bd_addr_t addr, 32691c7a19feSMatthias Ringwald hci_con_handle_t con_handle) { 32701c7a19feSMatthias Ringwald uint8_t buffer[20]; 32711c7a19feSMatthias Ringwald uint16_t len = hci_event_create_from_template_and_arguments(buffer, sizeof(buffer), &gatt_client_connected, status, addr, con_handle); 32721c7a19feSMatthias Ringwald (*callback)(HCI_EVENT_PACKET, 0, buffer, len); 32731c7a19feSMatthias Ringwald } 32741c7a19feSMatthias Ringwald 32757627a0deSMatthias Ringwald #endif 32767627a0deSMatthias Ringwald 32777627a0deSMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC 32787627a0deSMatthias Ringwald 32797627a0deSMatthias Ringwald #include "bluetooth_psm.h" 32807627a0deSMatthias Ringwald 32817627a0deSMatthias Ringwald // single active SDP query 32827627a0deSMatthias Ringwald static gatt_client_t * gatt_client_classic_active_sdp_query; 32837627a0deSMatthias Ringwald 32847627a0deSMatthias Ringwald // macos protocol descriptor list requires 16 bytes 32857627a0deSMatthias Ringwald static uint8_t gatt_client_classic_sdp_buffer[32]; 32867627a0deSMatthias Ringwald 32876b4a68c3SMatthias Ringwald 32881450cdc6SMatthias Ringwald static gatt_client_t * gatt_client_get_context_for_classic_addr(bd_addr_t addr){ 32891450cdc6SMatthias Ringwald btstack_linked_item_t *it; 32901450cdc6SMatthias Ringwald for (it = (btstack_linked_item_t *) gatt_client_connections; it != NULL; it = it->next){ 32911450cdc6SMatthias Ringwald gatt_client_t * gatt_client = (gatt_client_t *) it; 32921450cdc6SMatthias Ringwald if (memcmp(gatt_client->addr, addr, 6) == 0){ 32931450cdc6SMatthias Ringwald return gatt_client; 32941450cdc6SMatthias Ringwald } 32951450cdc6SMatthias Ringwald } 32961450cdc6SMatthias Ringwald return NULL; 32971450cdc6SMatthias Ringwald } 32981450cdc6SMatthias Ringwald 32991450cdc6SMatthias Ringwald static gatt_client_t * gatt_client_get_context_for_l2cap_cid(uint16_t l2cap_cid){ 33001450cdc6SMatthias Ringwald btstack_linked_item_t *it; 33011450cdc6SMatthias Ringwald for (it = (btstack_linked_item_t *) gatt_client_connections; it != NULL; it = it->next){ 33021450cdc6SMatthias Ringwald gatt_client_t * gatt_client = (gatt_client_t *) it; 33031450cdc6SMatthias Ringwald if (gatt_client->l2cap_cid == l2cap_cid){ 33041450cdc6SMatthias Ringwald return gatt_client; 33051450cdc6SMatthias Ringwald } 33061450cdc6SMatthias Ringwald } 33071450cdc6SMatthias Ringwald return NULL; 33081450cdc6SMatthias Ringwald } 33091450cdc6SMatthias Ringwald 33101450cdc6SMatthias Ringwald static void gatt_client_classic_handle_connected(gatt_client_t * gatt_client, uint8_t status){ 3311b2d70d58SMatthias Ringwald // cache peer information 33121450cdc6SMatthias Ringwald bd_addr_t addr; 3313d5529700SMatthias Ringwald // cppcheck-suppress uninitvar ; addr is reported as uninitialized although it's the destination of the memcpy 33141450cdc6SMatthias Ringwald memcpy(addr, gatt_client->addr, 6); 3315b2d70d58SMatthias Ringwald bd_addr_type_t addr_type = gatt_client->addr_type; 3316b2d70d58SMatthias Ringwald gatt_client->addr_type = BD_ADDR_TYPE_ACL; 33171450cdc6SMatthias Ringwald hci_con_handle_t con_handle = gatt_client->con_handle; 33181450cdc6SMatthias Ringwald btstack_packet_handler_t callback = gatt_client->callback; 3319b2d70d58SMatthias Ringwald 33209ed6f53cSMatthias Ringwald if (status != ERROR_CODE_SUCCESS){ 33213b0e0cc5SMatthias Ringwald btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client); 33223b0e0cc5SMatthias Ringwald btstack_memory_gatt_client_free(gatt_client); 33233b0e0cc5SMatthias Ringwald } 3324b2d70d58SMatthias Ringwald 3325b2d70d58SMatthias Ringwald gatt_client_emit_connected(callback, status, addr_type, addr, con_handle); 33261450cdc6SMatthias Ringwald } 33271450cdc6SMatthias Ringwald 3328180cbe79SMatthias Ringwald static void gatt_client_classic_retry(btstack_timer_source_t * ts){ 3329180cbe79SMatthias Ringwald gatt_client_t * gatt_client = gatt_client_for_timer(ts); 3330180cbe79SMatthias Ringwald if (gatt_client != NULL){ 3331180cbe79SMatthias Ringwald gatt_client->state = P_W4_L2CAP_CONNECTION; 3332180cbe79SMatthias Ringwald att_dispatch_classic_connect(gatt_client->addr, gatt_client->l2cap_psm, &gatt_client->l2cap_cid); 3333180cbe79SMatthias Ringwald } 3334180cbe79SMatthias Ringwald } 3335180cbe79SMatthias Ringwald 33366b4a68c3SMatthias Ringwald static void gatt_client_classic_handle_disconnected(gatt_client_t * gatt_client){ 33376b4a68c3SMatthias Ringwald 33386b4a68c3SMatthias Ringwald gatt_client_report_error_if_pending(gatt_client, ATT_ERROR_HCI_DISCONNECT_RECEIVED); 33396b4a68c3SMatthias Ringwald gatt_client_timeout_stop(gatt_client); 33406b4a68c3SMatthias Ringwald 33416b4a68c3SMatthias Ringwald hci_con_handle_t con_handle = gatt_client->con_handle; 33426b4a68c3SMatthias Ringwald btstack_packet_handler_t callback = gatt_client->callback; 33436b4a68c3SMatthias Ringwald btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client); 33446b4a68c3SMatthias Ringwald btstack_memory_gatt_client_free(gatt_client); 33456b4a68c3SMatthias Ringwald 33466b4a68c3SMatthias Ringwald uint8_t buffer[20]; 33476b4a68c3SMatthias Ringwald uint16_t len = hci_event_create_from_template_and_arguments(buffer, sizeof(buffer), &gatt_client_disconnected, con_handle); 33486b4a68c3SMatthias Ringwald (*callback)(HCI_EVENT_PACKET, 0, buffer, len); 33496b4a68c3SMatthias Ringwald } 33506b4a68c3SMatthias Ringwald 33511450cdc6SMatthias Ringwald static void gatt_client_handle_sdp_client_query_attribute_value(gatt_client_t * connection, uint8_t *packet){ 33521450cdc6SMatthias Ringwald des_iterator_t des_list_it; 33531450cdc6SMatthias Ringwald des_iterator_t prot_it; 33541450cdc6SMatthias Ringwald 33551450cdc6SMatthias Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= sizeof(gatt_client_classic_sdp_buffer)) { 33561450cdc6SMatthias Ringwald gatt_client_classic_sdp_buffer[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 33571450cdc6SMatthias Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 33581450cdc6SMatthias Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 33591450cdc6SMatthias Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 33601450cdc6SMatthias Ringwald for (des_iterator_init(&des_list_it, gatt_client_classic_sdp_buffer); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 33611450cdc6SMatthias Ringwald uint8_t *des_element; 33621450cdc6SMatthias Ringwald uint8_t *element; 33631450cdc6SMatthias Ringwald uint32_t uuid; 33641450cdc6SMatthias Ringwald 33651450cdc6SMatthias Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 33661450cdc6SMatthias Ringwald 33671450cdc6SMatthias Ringwald des_element = des_iterator_get_element(&des_list_it); 33681450cdc6SMatthias Ringwald des_iterator_init(&prot_it, des_element); 33691450cdc6SMatthias Ringwald element = des_iterator_get_element(&prot_it); 33701450cdc6SMatthias Ringwald 33711450cdc6SMatthias Ringwald if (de_get_element_type(element) != DE_UUID) continue; 33721450cdc6SMatthias Ringwald 33731450cdc6SMatthias Ringwald uuid = de_get_uuid32(element); 33741450cdc6SMatthias Ringwald des_iterator_next(&prot_it); 33751450cdc6SMatthias Ringwald // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both 33761450cdc6SMatthias Ringwald switch (uuid){ 33771450cdc6SMatthias Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 33781450cdc6SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 33791450cdc6SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->l2cap_psm); 33801450cdc6SMatthias Ringwald break; 33811450cdc6SMatthias Ringwald default: 33821450cdc6SMatthias Ringwald break; 33831450cdc6SMatthias Ringwald } 33841450cdc6SMatthias Ringwald } 33851450cdc6SMatthias Ringwald break; 33861450cdc6SMatthias Ringwald 33871450cdc6SMatthias Ringwald default: 33881450cdc6SMatthias Ringwald break; 33891450cdc6SMatthias Ringwald } 33901450cdc6SMatthias Ringwald } 33911450cdc6SMatthias Ringwald } 33921450cdc6SMatthias Ringwald } 33931450cdc6SMatthias Ringwald 33941450cdc6SMatthias Ringwald static void gatt_client_classic_sdp_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){ 33951450cdc6SMatthias Ringwald gatt_client_t * gatt_client = gatt_client_classic_active_sdp_query; 33961450cdc6SMatthias Ringwald btstack_assert(gatt_client != NULL); 33971450cdc6SMatthias Ringwald uint8_t status; 33981450cdc6SMatthias Ringwald 33991450cdc6SMatthias Ringwald // TODO: handle sdp events, get l2cap psm 34001450cdc6SMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 34011450cdc6SMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 34021450cdc6SMatthias Ringwald gatt_client_handle_sdp_client_query_attribute_value(gatt_client, packet); 34031450cdc6SMatthias Ringwald // TODO: 34041450cdc6SMatthias Ringwald return; 34051450cdc6SMatthias Ringwald case SDP_EVENT_QUERY_COMPLETE: 34061450cdc6SMatthias Ringwald status = sdp_event_query_complete_get_status(packet); 34071450cdc6SMatthias Ringwald gatt_client_classic_active_sdp_query = NULL; 34081450cdc6SMatthias Ringwald log_info("l2cap psm: %0x, status %02x", gatt_client->l2cap_psm, status); 34091450cdc6SMatthias Ringwald if (status != ERROR_CODE_SUCCESS) break; 34101450cdc6SMatthias Ringwald if (gatt_client->l2cap_psm == 0) { 34111450cdc6SMatthias Ringwald status = SDP_SERVICE_NOT_FOUND; 34121450cdc6SMatthias Ringwald break; 34131450cdc6SMatthias Ringwald } 34141450cdc6SMatthias Ringwald break; 34151450cdc6SMatthias Ringwald default: 34161450cdc6SMatthias Ringwald btstack_assert(false); 34171450cdc6SMatthias Ringwald return; 34181450cdc6SMatthias Ringwald } 34191450cdc6SMatthias Ringwald 34201450cdc6SMatthias Ringwald // done 34211450cdc6SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 3422052dc82aSMatthias Ringwald gatt_client->state = P_W4_L2CAP_CONNECTION; 342359b5e157SMatthias Ringwald status = att_dispatch_classic_connect(gatt_client->addr, gatt_client->l2cap_psm, &gatt_client->l2cap_cid); 34241450cdc6SMatthias Ringwald } 34251450cdc6SMatthias Ringwald if (status != ERROR_CODE_SUCCESS) { 34261450cdc6SMatthias Ringwald gatt_client_classic_handle_connected(gatt_client, status); 34271450cdc6SMatthias Ringwald } 34281450cdc6SMatthias Ringwald } 34291450cdc6SMatthias Ringwald 34301450cdc6SMatthias Ringwald static void gatt_client_classic_sdp_start(void * context){ 34311450cdc6SMatthias Ringwald gatt_client_classic_active_sdp_query = (gatt_client_t *) context; 3432052dc82aSMatthias Ringwald gatt_client_classic_active_sdp_query->state = P_W4_SDP_QUERY; 34331450cdc6SMatthias Ringwald sdp_client_query_uuid16(gatt_client_classic_sdp_handler, gatt_client_classic_active_sdp_query->addr, ORG_BLUETOOTH_SERVICE_GENERIC_ATTRIBUTE); 34341450cdc6SMatthias Ringwald } 34351450cdc6SMatthias Ringwald 343674daebdeSMatthias Ringwald static void gatt_client_classic_emit_connected(void * context){ 343774daebdeSMatthias Ringwald gatt_client_t * gatt_client = (gatt_client_t *) context; 3438052dc82aSMatthias Ringwald gatt_client->state = P_READY; 3439b2d70d58SMatthias Ringwald gatt_client_emit_connected(gatt_client->callback, ERROR_CODE_SUCCESS, gatt_client->addr_type, gatt_client->addr, gatt_client->con_handle); 344074daebdeSMatthias Ringwald } 344174daebdeSMatthias Ringwald 34421450cdc6SMatthias Ringwald uint8_t gatt_client_classic_connect(btstack_packet_handler_t callback, bd_addr_t addr){ 34431450cdc6SMatthias Ringwald gatt_client_t * gatt_client = gatt_client_get_context_for_classic_addr(addr); 34441450cdc6SMatthias Ringwald if (gatt_client != NULL){ 34451450cdc6SMatthias Ringwald return ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS; 34461450cdc6SMatthias Ringwald } 34471450cdc6SMatthias Ringwald gatt_client = btstack_memory_gatt_client_get(); 34481450cdc6SMatthias Ringwald if (gatt_client == NULL){ 34491450cdc6SMatthias Ringwald return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 34501450cdc6SMatthias Ringwald } 34511450cdc6SMatthias Ringwald // init state 3452e9cdf30bSMatthias Ringwald gatt_client->bearer_type = ATT_BEARER_UNENHANCED_CLASSIC; 34531450cdc6SMatthias Ringwald gatt_client->con_handle = HCI_CON_HANDLE_INVALID; 34541450cdc6SMatthias Ringwald memcpy(gatt_client->addr, addr, 6); 3455b2d70d58SMatthias Ringwald gatt_client->addr_type = BD_ADDR_TYPE_ACL; 34561450cdc6SMatthias Ringwald gatt_client->mtu = ATT_DEFAULT_MTU; 34571450cdc6SMatthias Ringwald gatt_client->security_level = LEVEL_0; 34581450cdc6SMatthias Ringwald gatt_client->mtu_state = MTU_AUTO_EXCHANGE_DISABLED; 34591450cdc6SMatthias Ringwald gatt_client->callback = callback; 3460cbd76cecSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 3461cbd76cecSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_IDLE; 3462cbd76cecSMatthias Ringwald #endif 34631450cdc6SMatthias Ringwald btstack_linked_list_add(&gatt_client_connections, (btstack_linked_item_t*)gatt_client); 346474daebdeSMatthias Ringwald 346574daebdeSMatthias Ringwald // schedule emitted event if already connected, otherwise 346674daebdeSMatthias Ringwald bool already_connected = false; 346774daebdeSMatthias Ringwald hci_connection_t * hci_connection = hci_connection_for_bd_addr_and_type(addr, BD_ADDR_TYPE_ACL); 346874daebdeSMatthias Ringwald if (hci_connection != NULL){ 346974daebdeSMatthias Ringwald if (hci_connection->att_server.l2cap_cid != 0){ 347074daebdeSMatthias Ringwald already_connected = true; 347174daebdeSMatthias Ringwald } 347274daebdeSMatthias Ringwald } 3473052dc82aSMatthias Ringwald gatt_client->callback_request.context = gatt_client; 347474daebdeSMatthias Ringwald if (already_connected){ 347574daebdeSMatthias Ringwald gatt_client->con_handle = hci_connection->con_handle; 3476052dc82aSMatthias Ringwald gatt_client->callback_request.callback = &gatt_client_classic_emit_connected; 3477052dc82aSMatthias Ringwald gatt_client->state = P_W2_EMIT_CONNECTED; 3478052dc82aSMatthias Ringwald btstack_run_loop_execute_on_main_thread(&gatt_client->callback_request); 347974daebdeSMatthias Ringwald } else { 3480052dc82aSMatthias Ringwald gatt_client->callback_request.callback = &gatt_client_classic_sdp_start; 3481052dc82aSMatthias Ringwald gatt_client->state = P_W2_SDP_QUERY; 3482052dc82aSMatthias Ringwald sdp_client_register_query_callback(&gatt_client->callback_request); 348374daebdeSMatthias Ringwald } 3484b7b03a30SMatthias Ringwald return ERROR_CODE_SUCCESS; 34851450cdc6SMatthias Ringwald } 34861450cdc6SMatthias Ringwald 34871450cdc6SMatthias Ringwald uint8_t gatt_client_classic_disconnect(btstack_packet_handler_t callback, hci_con_handle_t con_handle){ 34881450cdc6SMatthias Ringwald gatt_client_t * gatt_client = gatt_client_get_context_for_handle(con_handle); 34891450cdc6SMatthias Ringwald if (gatt_client == NULL){ 34901450cdc6SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 34911450cdc6SMatthias Ringwald } 34921450cdc6SMatthias Ringwald gatt_client->callback = callback; 34931450cdc6SMatthias Ringwald return l2cap_disconnect(gatt_client->l2cap_cid); 34941450cdc6SMatthias Ringwald } 34951450cdc6SMatthias Ringwald #endif 34961450cdc6SMatthias Ringwald 349726166ecfSMatthias Ringwald #ifdef ENABLE_GATT_OVER_EATT 349826166ecfSMatthias Ringwald 349926166ecfSMatthias Ringwald #define MAX_NR_EATT_CHANNELS 5 35007627a0deSMatthias Ringwald 35017627a0deSMatthias Ringwald static void gatt_client_le_enhanced_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 35027627a0deSMatthias Ringwald 3503df0a5c68SMatthias Ringwald static uint8_t gatt_client_le_enhanced_num_eatt_clients_in_state(gatt_client_t * gatt_client, gatt_client_state_t state){ 3504df0a5c68SMatthias Ringwald uint8_t num_clients = 0; 3505df0a5c68SMatthias Ringwald btstack_linked_list_iterator_t it; 3506df0a5c68SMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client->eatt_clients); 3507df0a5c68SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3508df0a5c68SMatthias Ringwald gatt_client_t * eatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it); 3509df0a5c68SMatthias Ringwald if (eatt_client->state == state){ 3510df0a5c68SMatthias Ringwald num_clients++; 3511df0a5c68SMatthias Ringwald } 3512df0a5c68SMatthias Ringwald } 3513df0a5c68SMatthias Ringwald return num_clients; 3514df0a5c68SMatthias Ringwald } 3515df0a5c68SMatthias Ringwald 35167627a0deSMatthias Ringwald static void gatt_client_eatt_finalize(gatt_client_t * gatt_client) { 35177627a0deSMatthias Ringwald // free eatt clients 35187627a0deSMatthias Ringwald btstack_linked_list_iterator_t it; 35197627a0deSMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client_connections); 35207627a0deSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)) { 35217627a0deSMatthias Ringwald gatt_client_t *eatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it); 35227627a0deSMatthias Ringwald btstack_linked_list_iterator_remove(&it); 35237627a0deSMatthias Ringwald btstack_memory_gatt_client_free(eatt_client); 35247627a0deSMatthias Ringwald } 35257627a0deSMatthias Ringwald } 35267627a0deSMatthias Ringwald 35277627a0deSMatthias Ringwald // all channels connected 35287627a0deSMatthias Ringwald static void gatt_client_le_enhanced_handle_connected(gatt_client_t * gatt_client, uint8_t status) { 35297627a0deSMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 3530df0a5c68SMatthias Ringwald uint8_t num_ready = gatt_client_le_enhanced_num_eatt_clients_in_state(gatt_client, P_READY); 3531df0a5c68SMatthias Ringwald if (num_ready > 0){ 35327627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_READY; 3533df0a5c68SMatthias Ringwald // free unused channels 3534df0a5c68SMatthias Ringwald btstack_linked_list_iterator_t it; 3535df0a5c68SMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client_connections); 3536df0a5c68SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)) { 3537df0a5c68SMatthias Ringwald gatt_client_t *eatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it); 3538df0a5c68SMatthias Ringwald if (eatt_client->state == P_L2CAP_CLOSED){ 3539df0a5c68SMatthias Ringwald btstack_linked_list_iterator_remove(&it); 3540df0a5c68SMatthias Ringwald btstack_memory_gatt_client_free(eatt_client); 3541df0a5c68SMatthias Ringwald } 3542df0a5c68SMatthias Ringwald } 3543df0a5c68SMatthias Ringwald } else { 35446d0f6f49SMatthias Ringwald hci_connection_t * hci_connection = hci_connection_for_handle(gatt_client->con_handle); 35456d0f6f49SMatthias Ringwald btstack_assert(hci_connection != NULL); 35466d0f6f49SMatthias Ringwald if (hci_connection->att_server.incoming_connection_request){ 35476d0f6f49SMatthias Ringwald hci_connection->att_server.incoming_connection_request = false; 35486d0f6f49SMatthias Ringwald log_info("Collision, retry in 100ms"); 35496d0f6f49SMatthias Ringwald gatt_client->state = P_W2_L2CAP_CONNECT; 35506d0f6f49SMatthias Ringwald // set timer for retry 3551b1da4983SMatthias Ringwald btstack_run_loop_set_timer(&gatt_client->gc_timeout, GATT_CLIENT_COLLISION_BACKOFF_MS); 35526d0f6f49SMatthias Ringwald btstack_run_loop_set_timer_handler(&gatt_client->gc_timeout, gatt_client_le_enhanced_retry); 35536d0f6f49SMatthias Ringwald btstack_run_loop_add_timer(&gatt_client->gc_timeout); 35546d0f6f49SMatthias Ringwald return; 35556d0f6f49SMatthias Ringwald } else { 3556df0a5c68SMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_IDLE; 3557df0a5c68SMatthias Ringwald status = ERROR_CODE_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES; 3558df0a5c68SMatthias Ringwald } 35596d0f6f49SMatthias Ringwald } 35607627a0deSMatthias Ringwald } else { 35617627a0deSMatthias Ringwald gatt_client_eatt_finalize(gatt_client); 35627627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_IDLE; 35637627a0deSMatthias Ringwald } 35647627a0deSMatthias Ringwald 3565b2d70d58SMatthias Ringwald gatt_client_emit_connected(gatt_client->callback, status, gatt_client->addr_type, gatt_client->addr, gatt_client->con_handle); 35667627a0deSMatthias Ringwald } 35677627a0deSMatthias Ringwald 35687627a0deSMatthias Ringwald // single channel disconnected 35697627a0deSMatthias Ringwald static void gatt_client_le_enhanced_handle_ecbm_disconnected(gatt_client_t * gatt_client, gatt_client_t * eatt_client) { 35707627a0deSMatthias Ringwald 35717627a0deSMatthias Ringwald // report error 35727627a0deSMatthias Ringwald gatt_client_report_error_if_pending(eatt_client, ATT_ERROR_HCI_DISCONNECT_RECEIVED); 35737627a0deSMatthias Ringwald 35747627a0deSMatthias Ringwald // free memory 35757627a0deSMatthias Ringwald btstack_linked_list_remove(&gatt_client->eatt_clients, (btstack_linked_item_t *) eatt_client); 35767627a0deSMatthias Ringwald btstack_memory_gatt_client_free(eatt_client); 35777627a0deSMatthias Ringwald 3578570bdd2dSMatthias Ringwald // last channel 35797627a0deSMatthias Ringwald if (btstack_linked_list_empty(&gatt_client->eatt_clients)){ 3580570bdd2dSMatthias Ringwald hci_connection_t * hci_connection = hci_connection_for_handle(gatt_client->con_handle); 3581570bdd2dSMatthias Ringwald hci_connection->att_server.eatt_outgoing_active = false; 3582570bdd2dSMatthias Ringwald 3583570bdd2dSMatthias Ringwald if (gatt_client->eatt_state == GATT_CLIENT_EATT_READY) { 3584570bdd2dSMatthias Ringwald // report disconnected if last channel closed 35857627a0deSMatthias Ringwald uint8_t buffer[20]; 35867627a0deSMatthias Ringwald uint16_t len = hci_event_create_from_template_and_arguments(buffer, sizeof(buffer), &gatt_client_disconnected, gatt_client->con_handle); 35877627a0deSMatthias Ringwald (*gatt_client->callback)(HCI_EVENT_PACKET, 0, buffer, len); 35887627a0deSMatthias Ringwald } 35897627a0deSMatthias Ringwald } 35907627a0deSMatthias Ringwald } 35917627a0deSMatthias Ringwald 35927627a0deSMatthias Ringwald static gatt_client_t * gatt_client_le_enhanced_get_context_for_l2cap_cid(uint16_t l2cap_cid, gatt_client_t ** out_eatt_client){ 35937627a0deSMatthias Ringwald btstack_linked_list_iterator_t it; 35947627a0deSMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client_connections); 35957627a0deSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)) { 35967627a0deSMatthias Ringwald gatt_client_t * gatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it); 35977627a0deSMatthias Ringwald btstack_linked_list_iterator_t it2; 35987627a0deSMatthias Ringwald btstack_linked_list_iterator_init(&it2, &gatt_client->eatt_clients); 35997627a0deSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it2)) { 36007627a0deSMatthias Ringwald gatt_client_t * eatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it2); 36017627a0deSMatthias Ringwald if (eatt_client->l2cap_cid == l2cap_cid){ 36027627a0deSMatthias Ringwald *out_eatt_client = eatt_client; 36037627a0deSMatthias Ringwald return gatt_client; 36047627a0deSMatthias Ringwald } 36057627a0deSMatthias Ringwald } 36067627a0deSMatthias Ringwald } 36077627a0deSMatthias Ringwald return NULL; 36087627a0deSMatthias Ringwald } 36097627a0deSMatthias Ringwald 36107627a0deSMatthias Ringwald static void gatt_client_le_enhanced_setup_l2cap_channel(gatt_client_t * gatt_client){ 36117627a0deSMatthias Ringwald uint8_t num_channels = gatt_client->eatt_num_clients; 36127627a0deSMatthias Ringwald 36137627a0deSMatthias Ringwald // setup channels 36147627a0deSMatthias Ringwald uint16_t buffer_size_per_client = gatt_client->eatt_storage_size / num_channels; 3615f7a42e72SMatthias Ringwald uint16_t max_mtu = (buffer_size_per_client - REPORT_PREBUFFER_HEADER) / 2; 36167627a0deSMatthias Ringwald uint8_t * receive_buffers[MAX_NR_EATT_CHANNELS]; 36177627a0deSMatthias Ringwald uint16_t new_cids[MAX_NR_EATT_CHANNELS]; 36187627a0deSMatthias Ringwald memset(gatt_client->eatt_storage_buffer, 0, gatt_client->eatt_storage_size); 36197627a0deSMatthias Ringwald uint8_t i; 36207627a0deSMatthias Ringwald for (i=0;i<gatt_client->eatt_num_clients; i++){ 3621f7a42e72SMatthias Ringwald receive_buffers[i] = &gatt_client->eatt_storage_buffer[REPORT_PREBUFFER_HEADER]; 3622f7a42e72SMatthias Ringwald gatt_client->eatt_storage_buffer += REPORT_PREBUFFER_HEADER + max_mtu; 36237627a0deSMatthias Ringwald } 36247627a0deSMatthias Ringwald 36257627a0deSMatthias Ringwald log_info("%u EATT clients with receive buffer size %u", gatt_client->eatt_num_clients, buffer_size_per_client); 36267627a0deSMatthias Ringwald 3627f7a42e72SMatthias Ringwald uint8_t status = l2cap_ecbm_create_channels(&gatt_client_le_enhanced_packet_handler, 3628f7a42e72SMatthias Ringwald gatt_client->con_handle, 36297627a0deSMatthias Ringwald gatt_client->security_level, 3630f7a42e72SMatthias Ringwald BLUETOOTH_PSM_EATT, num_channels, 3631f7a42e72SMatthias Ringwald L2CAP_LE_AUTOMATIC_CREDITS, 36327627a0deSMatthias Ringwald buffer_size_per_client, 3633f7a42e72SMatthias Ringwald receive_buffers, 3634f7a42e72SMatthias Ringwald new_cids); 36357627a0deSMatthias Ringwald 36367627a0deSMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 36377627a0deSMatthias Ringwald i = 0; 36387627a0deSMatthias Ringwald btstack_linked_list_iterator_t it; 36397627a0deSMatthias Ringwald btstack_linked_list_iterator_init(&it, &gatt_client->eatt_clients); 36407627a0deSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)) { 36417627a0deSMatthias Ringwald gatt_client_t *new_eatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it); 36427627a0deSMatthias Ringwald 36437627a0deSMatthias Ringwald // init state with new cid and transmit buffer 36447627a0deSMatthias Ringwald new_eatt_client->bearer_type = ATT_BEARER_ENHANCED_LE; 36457627a0deSMatthias Ringwald new_eatt_client->con_handle = gatt_client->con_handle; 36467627a0deSMatthias Ringwald new_eatt_client->mtu = 64; 36477627a0deSMatthias Ringwald new_eatt_client->security_level = LEVEL_0; 36487627a0deSMatthias Ringwald new_eatt_client->mtu_state = MTU_AUTO_EXCHANGE_DISABLED; 3649052dc82aSMatthias Ringwald new_eatt_client->state = P_W4_L2CAP_CONNECTION; 36507627a0deSMatthias Ringwald new_eatt_client->l2cap_cid = new_cids[i]; 36517627a0deSMatthias Ringwald new_eatt_client->eatt_storage_buffer = gatt_client->eatt_storage_buffer; 3652f7a42e72SMatthias Ringwald gatt_client->eatt_storage_buffer += max_mtu; 36537627a0deSMatthias Ringwald i++; 36547627a0deSMatthias Ringwald } 36557627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_L2CAP_SETUP; 36567627a0deSMatthias Ringwald } else { 36577627a0deSMatthias Ringwald gatt_client_le_enhanced_handle_connected(gatt_client, status); 36587627a0deSMatthias Ringwald } 365926166ecfSMatthias Ringwald } 366026166ecfSMatthias Ringwald 36616d0f6f49SMatthias Ringwald static void gatt_client_le_enhanced_retry(btstack_timer_source_t * ts){ 36626d0f6f49SMatthias Ringwald gatt_client_t * gatt_client = gatt_client_for_timer(ts); 36636d0f6f49SMatthias Ringwald if (gatt_client != NULL){ 36646d0f6f49SMatthias Ringwald gatt_client->state = P_W4_L2CAP_CONNECTION; 36656d0f6f49SMatthias Ringwald gatt_client_le_enhanced_setup_l2cap_channel(gatt_client); 36666d0f6f49SMatthias Ringwald } 36676d0f6f49SMatthias Ringwald } 36686d0f6f49SMatthias Ringwald 366926166ecfSMatthias Ringwald static void gatt_client_le_enhanced_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 36707627a0deSMatthias Ringwald gatt_client_t *gatt_client; 36717627a0deSMatthias Ringwald gatt_client_t *eatt_client; 367226166ecfSMatthias Ringwald hci_con_handle_t con_handle; 36737627a0deSMatthias Ringwald uint16_t l2cap_cid; 367426166ecfSMatthias Ringwald uint8_t status; 367526166ecfSMatthias Ringwald gatt_client_characteristic_t characteristic; 36767627a0deSMatthias Ringwald gatt_client_service_t service; 367726166ecfSMatthias Ringwald switch (packet_type) { 367826166ecfSMatthias Ringwald case HCI_EVENT_PACKET: 367926166ecfSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 36807627a0deSMatthias Ringwald case GATT_EVENT_SERVICE_QUERY_RESULT: 36817627a0deSMatthias Ringwald con_handle = gatt_event_service_query_result_get_handle(packet); 36827627a0deSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 36837627a0deSMatthias Ringwald btstack_assert(gatt_client != NULL); 36847627a0deSMatthias Ringwald btstack_assert(gatt_client->eatt_state == GATT_CLIENT_EATT_DISCOVER_GATT_SERVICE_W4_DONE); 36857627a0deSMatthias Ringwald gatt_event_service_query_result_get_service(packet, &service); 36867627a0deSMatthias Ringwald gatt_client->gatt_service_start_group_handle = service.start_group_handle; 36877627a0deSMatthias Ringwald gatt_client->gatt_service_end_group_handle = service.end_group_handle; 36887627a0deSMatthias Ringwald break; 368926166ecfSMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: 369026166ecfSMatthias Ringwald con_handle = gatt_event_characteristic_value_query_result_get_handle(packet); 369126166ecfSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 369226166ecfSMatthias Ringwald btstack_assert(gatt_client != NULL); 36937627a0deSMatthias Ringwald btstack_assert(gatt_client->eatt_state == GATT_CLIENT_EATT_READ_SERVER_SUPPORTED_FEATURES_W4_DONE); 369426166ecfSMatthias Ringwald if (gatt_event_characteristic_value_query_result_get_value_length(packet) >= 1) { 36957627a0deSMatthias Ringwald gatt_client->gatt_server_supported_features = gatt_event_characteristic_value_query_result_get_value(packet)[0]; 369626166ecfSMatthias Ringwald } 369726166ecfSMatthias Ringwald break; 369826166ecfSMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 369926166ecfSMatthias Ringwald con_handle = gatt_event_characteristic_query_result_get_handle(packet); 370026166ecfSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 370126166ecfSMatthias Ringwald btstack_assert(gatt_client != NULL); 37027627a0deSMatthias Ringwald btstack_assert(gatt_client->eatt_state == GATT_CLIENT_EATT_FIND_CLIENT_SUPPORTED_FEATURES_W4_DONE); 37037627a0deSMatthias Ringwald gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic); 370426166ecfSMatthias Ringwald gatt_client->gatt_client_supported_features_handle = characteristic.value_handle; 370526166ecfSMatthias Ringwald break; 370626166ecfSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 370726166ecfSMatthias Ringwald con_handle = gatt_event_query_complete_get_handle(packet); 370826166ecfSMatthias Ringwald gatt_client = gatt_client_get_context_for_handle(con_handle); 370926166ecfSMatthias Ringwald btstack_assert(gatt_client != NULL); 37107627a0deSMatthias Ringwald switch (gatt_client->eatt_state){ 37117627a0deSMatthias Ringwald case GATT_CLIENT_EATT_DISCOVER_GATT_SERVICE_W4_DONE: 37127627a0deSMatthias Ringwald if (gatt_client->gatt_service_start_group_handle == 0){ 37137627a0deSMatthias Ringwald gatt_client_le_enhanced_handle_connected(gatt_client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 37147627a0deSMatthias Ringwald } else { 37157627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_READ_SERVER_SUPPORTED_FEATURES_W2_SEND; 37167627a0deSMatthias Ringwald } 37177627a0deSMatthias Ringwald break; 37187627a0deSMatthias Ringwald case GATT_CLIENT_EATT_READ_SERVER_SUPPORTED_FEATURES_W4_DONE: 37197627a0deSMatthias Ringwald if ((gatt_client->gatt_server_supported_features & 1) == 0) { 37207627a0deSMatthias Ringwald gatt_client_le_enhanced_handle_connected(gatt_client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 37217627a0deSMatthias Ringwald } else { 37227627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_FIND_CLIENT_SUPPORTED_FEATURES_W2_SEND; 37237627a0deSMatthias Ringwald } 37247627a0deSMatthias Ringwald break; 37257627a0deSMatthias Ringwald case GATT_CLIENT_EATT_FIND_CLIENT_SUPPORTED_FEATURES_W4_DONE: 37267627a0deSMatthias Ringwald if (gatt_client->gatt_client_supported_features_handle == 0){ 37277627a0deSMatthias Ringwald gatt_client_le_enhanced_handle_connected(gatt_client, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); 37287627a0deSMatthias Ringwald } else { 37297627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_WRITE_ClIENT_SUPPORTED_FEATURES_W2_SEND; 37307627a0deSMatthias Ringwald } 37317627a0deSMatthias Ringwald break; 37327627a0deSMatthias Ringwald case GATT_CLIENT_EATT_WRITE_ClIENT_SUPPORTED_FEATURES_W4_DONE: 37337627a0deSMatthias Ringwald gatt_client_le_enhanced_setup_l2cap_channel(gatt_client); 373426166ecfSMatthias Ringwald break; 373526166ecfSMatthias Ringwald default: 373626166ecfSMatthias Ringwald break; 373726166ecfSMatthias Ringwald } 373826166ecfSMatthias Ringwald break; 37397627a0deSMatthias Ringwald case L2CAP_EVENT_ECBM_CHANNEL_OPENED: 37407627a0deSMatthias Ringwald l2cap_cid = l2cap_event_ecbm_channel_opened_get_local_cid(packet); 37417627a0deSMatthias Ringwald gatt_client = gatt_client_le_enhanced_get_context_for_l2cap_cid(l2cap_cid, &eatt_client); 37427627a0deSMatthias Ringwald 37437627a0deSMatthias Ringwald btstack_assert(gatt_client != NULL); 37447627a0deSMatthias Ringwald btstack_assert(eatt_client != NULL); 3745052dc82aSMatthias Ringwald btstack_assert(eatt_client->state == P_W4_L2CAP_CONNECTION); 37467627a0deSMatthias Ringwald 37477627a0deSMatthias Ringwald status = l2cap_event_channel_opened_get_status(packet); 37487627a0deSMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 3749052dc82aSMatthias Ringwald eatt_client->state = P_READY; 37507627a0deSMatthias Ringwald eatt_client->mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 37517627a0deSMatthias Ringwald } else { 3752df0a5c68SMatthias Ringwald eatt_client->state = P_L2CAP_CLOSED; 37537627a0deSMatthias Ringwald } 3754df0a5c68SMatthias Ringwald // connected if opened event for all channels received 3755df0a5c68SMatthias Ringwald if (gatt_client_le_enhanced_num_eatt_clients_in_state(gatt_client, P_W4_L2CAP_CONNECTION) == 0){ 37567627a0deSMatthias Ringwald gatt_client_le_enhanced_handle_connected(gatt_client, ERROR_CODE_SUCCESS); 37577627a0deSMatthias Ringwald } 37587627a0deSMatthias Ringwald break; 37597627a0deSMatthias Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 37607627a0deSMatthias Ringwald l2cap_cid = l2cap_event_channel_closed_get_local_cid(packet); 37617627a0deSMatthias Ringwald gatt_client = gatt_client_le_enhanced_get_context_for_l2cap_cid(l2cap_cid, &eatt_client); 37627627a0deSMatthias Ringwald btstack_assert(gatt_client != NULL); 37637627a0deSMatthias Ringwald btstack_assert(eatt_client != NULL); 37647627a0deSMatthias Ringwald gatt_client_le_enhanced_handle_ecbm_disconnected(gatt_client, eatt_client); 37657627a0deSMatthias Ringwald break; 37667627a0deSMatthias Ringwald default: 37677627a0deSMatthias Ringwald break; 37687627a0deSMatthias Ringwald } 37697627a0deSMatthias Ringwald break; 37707627a0deSMatthias Ringwald case L2CAP_DATA_PACKET: 37717627a0deSMatthias Ringwald gatt_client = gatt_client_le_enhanced_get_context_for_l2cap_cid(channel, &eatt_client); 37727627a0deSMatthias Ringwald btstack_assert(gatt_client != NULL); 3773ce82ac7fSMatthias Ringwald btstack_assert(eatt_client != NULL); 3774ce82ac7fSMatthias Ringwald gatt_client_handle_att_response(eatt_client, packet, size); 37757627a0deSMatthias Ringwald gatt_client_run(); 37767627a0deSMatthias Ringwald break; 377726166ecfSMatthias Ringwald default: 377826166ecfSMatthias Ringwald break; 377926166ecfSMatthias Ringwald } 378026166ecfSMatthias Ringwald } 378126166ecfSMatthias Ringwald 37827627a0deSMatthias Ringwald static bool gatt_client_le_enhanced_handle_can_send_query(gatt_client_t * gatt_client){ 378326166ecfSMatthias Ringwald uint8_t status = ERROR_CODE_SUCCESS; 378426166ecfSMatthias Ringwald uint8_t gatt_client_supported_features = 0x06; // eatt + multiple value notifications 378526166ecfSMatthias Ringwald switch (gatt_client->eatt_state){ 37867627a0deSMatthias Ringwald case GATT_CLIENT_EATT_DISCOVER_GATT_SERVICE_W2_SEND: 37877627a0deSMatthias Ringwald gatt_client->gatt_service_start_group_handle = 0; 37887627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_DISCOVER_GATT_SERVICE_W4_DONE; 37897627a0deSMatthias Ringwald status = gatt_client_discover_primary_services_by_uuid16(&gatt_client_le_enhanced_packet_handler, 37907627a0deSMatthias Ringwald gatt_client->con_handle, 37917627a0deSMatthias Ringwald ORG_BLUETOOTH_SERVICE_GENERIC_ATTRIBUTE); 37927627a0deSMatthias Ringwald break; 379326166ecfSMatthias Ringwald case GATT_CLIENT_EATT_READ_SERVER_SUPPORTED_FEATURES_W2_SEND: 37947627a0deSMatthias Ringwald gatt_client->gatt_server_supported_features = 0; 37957627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_READ_SERVER_SUPPORTED_FEATURES_W4_DONE; 379626166ecfSMatthias Ringwald status = gatt_client_read_value_of_characteristics_by_uuid16(&gatt_client_le_enhanced_packet_handler, 37977627a0deSMatthias Ringwald gatt_client->con_handle, 37987627a0deSMatthias Ringwald gatt_client->gatt_service_start_group_handle, 37997627a0deSMatthias Ringwald gatt_client->gatt_service_end_group_handle, 380026166ecfSMatthias Ringwald ORG_BLUETOOTH_CHARACTERISTIC_SERVER_SUPPORTED_FEATURES); 380126166ecfSMatthias Ringwald return true; 380226166ecfSMatthias Ringwald case GATT_CLIENT_EATT_FIND_CLIENT_SUPPORTED_FEATURES_W2_SEND: 38037627a0deSMatthias Ringwald gatt_client->gatt_client_supported_features_handle = 0; 38047627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_FIND_CLIENT_SUPPORTED_FEATURES_W4_DONE; 380526166ecfSMatthias Ringwald status = gatt_client_discover_characteristics_for_handle_range_by_uuid16(&gatt_client_le_enhanced_packet_handler, 38067627a0deSMatthias Ringwald gatt_client->con_handle, 38077627a0deSMatthias Ringwald gatt_client->gatt_service_start_group_handle, 38087627a0deSMatthias Ringwald gatt_client->gatt_service_end_group_handle, 38097627a0deSMatthias Ringwald ORG_BLUETOOTH_CHARACTERISTIC_CLIENT_SUPPORTED_FEATURES); 381026166ecfSMatthias Ringwald return true; 381126166ecfSMatthias Ringwald case GATT_CLIENT_EATT_WRITE_ClIENT_SUPPORTED_FEATURES_W2_SEND: 381226166ecfSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_WRITE_ClIENT_SUPPORTED_FEATURES_W4_DONE; 381326166ecfSMatthias Ringwald status = gatt_client_write_value_of_characteristic(&gatt_client_le_enhanced_packet_handler, gatt_client->con_handle, 381426166ecfSMatthias Ringwald gatt_client->gatt_client_supported_features_handle, 1, 381526166ecfSMatthias Ringwald &gatt_client_supported_features); 381626166ecfSMatthias Ringwald return true; 381726166ecfSMatthias Ringwald default: 381826166ecfSMatthias Ringwald break; 381926166ecfSMatthias Ringwald } 38207627a0deSMatthias Ringwald btstack_assert(status == ERROR_CODE_SUCCESS); 38217627a0deSMatthias Ringwald UNUSED(status); 382226166ecfSMatthias Ringwald return false; 382326166ecfSMatthias Ringwald } 382426166ecfSMatthias Ringwald 382526166ecfSMatthias Ringwald uint8_t gatt_client_le_enhanced_connect(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint8_t num_channels, uint8_t * storage_buffer, uint16_t storage_size) { 382626166ecfSMatthias Ringwald gatt_client_t * gatt_client; 382726166ecfSMatthias Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client); 382826166ecfSMatthias Ringwald if (status != ERROR_CODE_SUCCESS){ 382926166ecfSMatthias Ringwald return status; 383026166ecfSMatthias Ringwald } 383126166ecfSMatthias Ringwald 383226166ecfSMatthias Ringwald if (gatt_client->eatt_state != GATT_CLIENT_EATT_IDLE){ 383326166ecfSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 383426166ecfSMatthias Ringwald } 383526166ecfSMatthias Ringwald 3836f7a42e72SMatthias Ringwald // need one buffer for sending and one for receiving. Receiving includes pre-buffer for reports 38377627a0deSMatthias Ringwald uint16_t buffer_size_per_client = storage_size / num_channels; 3838f7a42e72SMatthias Ringwald uint16_t max_mtu = (buffer_size_per_client - REPORT_PREBUFFER_HEADER) / 2; 3839f7a42e72SMatthias Ringwald if (max_mtu < 64) { 38407627a0deSMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 38417627a0deSMatthias Ringwald } 38427627a0deSMatthias Ringwald 38437627a0deSMatthias Ringwald if ((num_channels == 0) || (num_channels > MAX_NR_EATT_CHANNELS)){ 38447627a0deSMatthias Ringwald return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; 38457627a0deSMatthias Ringwald } 38467627a0deSMatthias Ringwald 38477627a0deSMatthias Ringwald // create max num_channel eatt clients 38487627a0deSMatthias Ringwald uint8_t i; 38497627a0deSMatthias Ringwald btstack_linked_list_t eatt_clients = NULL; 38507627a0deSMatthias Ringwald for (i=0;i<num_channels;i++) { 38517627a0deSMatthias Ringwald gatt_client_t * new_gatt_client = btstack_memory_gatt_client_get(); 38527627a0deSMatthias Ringwald if (new_gatt_client == NULL) { 38537627a0deSMatthias Ringwald break; 38547627a0deSMatthias Ringwald } 38557627a0deSMatthias Ringwald btstack_linked_list_add(&eatt_clients, (btstack_linked_item_t*)new_gatt_client); 38567627a0deSMatthias Ringwald } 38577627a0deSMatthias Ringwald 38587627a0deSMatthias Ringwald if (i != num_channels){ 38597627a0deSMatthias Ringwald while (true){ 38607627a0deSMatthias Ringwald gatt_client = (gatt_client_t *) btstack_linked_list_pop(&eatt_clients); 38617627a0deSMatthias Ringwald if (gatt_client == NULL) { 38627627a0deSMatthias Ringwald break; 38637627a0deSMatthias Ringwald } 38647627a0deSMatthias Ringwald btstack_memory_gatt_client_free(gatt_client); 38657627a0deSMatthias Ringwald } 38667627a0deSMatthias Ringwald return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 38677627a0deSMatthias Ringwald } 38687627a0deSMatthias Ringwald 3869570bdd2dSMatthias Ringwald hci_connection_t * hci_connection = hci_connection_for_handle(con_handle); 3870570bdd2dSMatthias Ringwald hci_connection->att_server.eatt_outgoing_active = true; 3871570bdd2dSMatthias Ringwald 38727627a0deSMatthias Ringwald gatt_client->callback = callback; 38737627a0deSMatthias Ringwald gatt_client->eatt_num_clients = num_channels; 38747627a0deSMatthias Ringwald gatt_client->eatt_storage_buffer = storage_buffer; 38757627a0deSMatthias Ringwald gatt_client->eatt_storage_size = storage_size; 38767627a0deSMatthias Ringwald gatt_client->eatt_clients = eatt_clients; 38777627a0deSMatthias Ringwald gatt_client->eatt_state = GATT_CLIENT_EATT_DISCOVER_GATT_SERVICE_W2_SEND; 387826166ecfSMatthias Ringwald gatt_client_notify_can_send_query(gatt_client); 387926166ecfSMatthias Ringwald 388026166ecfSMatthias Ringwald return ERROR_CODE_SUCCESS; 388126166ecfSMatthias Ringwald } 388226166ecfSMatthias Ringwald 388326166ecfSMatthias Ringwald #endif 388426166ecfSMatthias Ringwald 3885a6121b51SMilanka Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 3886a6121b51SMilanka Ringwald void gatt_client_att_packet_handler_fuzz(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){ 3887a6121b51SMilanka Ringwald gatt_client_att_packet_handler(packet_type, handle, packet, size); 3888a6121b51SMilanka Ringwald } 3889ae1ee62dSMilanka Ringwald 389040faeb84SMilanka Ringwald uint8_t gatt_client_get_client(hci_con_handle_t con_handle, gatt_client_t ** out_gatt_client){ 389140faeb84SMilanka Ringwald uint8_t status = gatt_client_provide_context_for_handle(con_handle, out_gatt_client); 389240faeb84SMilanka Ringwald return status; 3893ae1ee62dSMilanka Ringwald } 3894a6121b51SMilanka Ringwald #endif 3895