143625864Smatthias.ringwald /* 2a0c35809S[email protected] * Copyright (C) 2014 BlueKitchen GmbH 31713bceaSmatthias.ringwald * 41713bceaSmatthias.ringwald * Redistribution and use in source and binary forms, with or without 51713bceaSmatthias.ringwald * modification, are permitted provided that the following conditions 61713bceaSmatthias.ringwald * are met: 71713bceaSmatthias.ringwald * 81713bceaSmatthias.ringwald * 1. Redistributions of source code must retain the above copyright 91713bceaSmatthias.ringwald * notice, this list of conditions and the following disclaimer. 101713bceaSmatthias.ringwald * 2. Redistributions in binary form must reproduce the above copyright 111713bceaSmatthias.ringwald * notice, this list of conditions and the following disclaimer in the 121713bceaSmatthias.ringwald * documentation and/or other materials provided with the distribution. 131713bceaSmatthias.ringwald * 3. Neither the name of the copyright holders nor the names of 141713bceaSmatthias.ringwald * contributors may be used to endorse or promote products derived 151713bceaSmatthias.ringwald * from this software without specific prior written permission. 166b64433eSmatthias.ringwald * 4. Any redistribution, use, or modification is done solely for 176b64433eSmatthias.ringwald * personal benefit and not for any commercial purpose or for 186b64433eSmatthias.ringwald * monetary gain. 191713bceaSmatthias.ringwald * 20a0c35809S[email protected] * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 211713bceaSmatthias.ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 221713bceaSmatthias.ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 231713bceaSmatthias.ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 241713bceaSmatthias.ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 251713bceaSmatthias.ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 261713bceaSmatthias.ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 271713bceaSmatthias.ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 281713bceaSmatthias.ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 291713bceaSmatthias.ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 301713bceaSmatthias.ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311713bceaSmatthias.ringwald * SUCH DAMAGE. 321713bceaSmatthias.ringwald * 33a0c35809S[email protected] * Please inquire about commercial licensing options at 34a0c35809S[email protected] * [email protected] 356b64433eSmatthias.ringwald * 361713bceaSmatthias.ringwald */ 371713bceaSmatthias.ringwald 381713bceaSmatthias.ringwald /* 3943625864Smatthias.ringwald * l2cap.c 4043625864Smatthias.ringwald * 4143625864Smatthias.ringwald * Logical Link Control and Adaption Protocl (L2CAP) 4243625864Smatthias.ringwald * 4343625864Smatthias.ringwald * Created by Matthias Ringwald on 5/16/09. 4443625864Smatthias.ringwald */ 4543625864Smatthias.ringwald 4643625864Smatthias.ringwald #include "l2cap.h" 47645658c9Smatthias.ringwald #include "hci.h" 482b3c6c9bSmatthias.ringwald #include "hci_dump.h" 4916ece135SMatthias Ringwald #include "btstack_debug.h" 500e2df43fSMatthias Ringwald #include "btstack_event.h" 51d3a9df87Smatthias.ringwald #include "btstack_memory.h" 5243625864Smatthias.ringwald 53cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 5483fd9c76SMatthias Ringwald #include "ble/sm.h" 5583fd9c76SMatthias Ringwald #endif 5683fd9c76SMatthias Ringwald 5743625864Smatthias.ringwald #include <stdarg.h> 5843625864Smatthias.ringwald #include <string.h> 5943625864Smatthias.ringwald 6043625864Smatthias.ringwald #include <stdio.h> 6143625864Smatthias.ringwald 624c744e21Smatthias.ringwald // nr of buffered acl packets in outgoing queue to get max performance 634c744e21Smatthias.ringwald #define NR_BUFFERED_ACL_PACKETS 3 644c744e21Smatthias.ringwald 6539bda6d5Smatthias.ringwald // used to cache l2cap rejects, echo, and informational requests 66e16a9cacSmatthias.ringwald #define NR_PENDING_SIGNALING_RESPONSES 3 6739bda6d5Smatthias.ringwald 6885aeef60SMatthias Ringwald // nr of credits provided to remote if credits fall below watermark 6985aeef60SMatthias Ringwald #define L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_WATERMARK 5 7085aeef60SMatthias Ringwald #define L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_INCREMENT 5 7185aeef60SMatthias Ringwald 7200d93d79Smatthias.ringwald // offsets for L2CAP SIGNALING COMMANDS 7300d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_CODE_OFFSET 0 7400d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_SIGID_OFFSET 1 7500d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2 7600d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_DATA_OFFSET 4 7700d93d79Smatthias.ringwald 785628cf69SMatthias Ringwald // internal table 795628cf69SMatthias Ringwald #define L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL 0 805628cf69SMatthias Ringwald #define L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL 1 815628cf69SMatthias Ringwald #define L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL 2 825628cf69SMatthias Ringwald #define L2CAP_FIXED_CHANNEL_TABLE_SIZE (L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL+1) 835628cf69SMatthias Ringwald 8433c40538SMatthias Ringwald // prototypes 8533c40538SMatthias Ringwald static void l2cap_finialize_channel_close(l2cap_channel_t *channel); 8633c40538SMatthias Ringwald static inline l2cap_service_t * l2cap_get_service(uint16_t psm); 8733c40538SMatthias Ringwald static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status); 8834e7e577SMatthias Ringwald static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel); 8933c40538SMatthias Ringwald static void l2cap_emit_channel_closed(l2cap_channel_t *channel); 9044276248SMatthias Ringwald static void l2cap_emit_incoming_connection(l2cap_channel_t *channel); 9133c40538SMatthias Ringwald static int l2cap_channel_ready_for_open(l2cap_channel_t *channel); 9233c40538SMatthias Ringwald static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 933d50b4baSMatthias Ringwald static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ); 9430725612SMatthias Ringwald static void l2cap_notify_channel_can_send(void); 9557be49d6SMatthias Ringwald 96cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 9757be49d6SMatthias Ringwald static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status); 9857be49d6SMatthias Ringwald static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel); 9957be49d6SMatthias Ringwald static l2cap_channel_t * l2cap_le_get_channel_for_local_cid(uint16_t local_cid); 10044276248SMatthias Ringwald static void l2cap_le_notify_channel_can_send(l2cap_channel_t *channel); 101828a7f7aSMatthias Ringwald static void l2cap_le_finialize_channel_close(l2cap_channel_t *channel); 102e7d0c9aaSMatthias Ringwald static inline l2cap_service_t * l2cap_le_get_service(uint16_t psm); 103e7d0c9aaSMatthias Ringwald #endif 10433c40538SMatthias Ringwald 1055628cf69SMatthias Ringwald typedef struct l2cap_fixed_channel { 1065628cf69SMatthias Ringwald btstack_packet_handler_t callback; 1072125de09SMatthias Ringwald uint8_t waiting_for_can_send_now; 1085628cf69SMatthias Ringwald } l2cap_fixed_channel_t; 1095628cf69SMatthias Ringwald 1105628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_channels; 1115628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_services; 11257be49d6SMatthias Ringwald 11357be49d6SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 1145628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_le_channels; 1155628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_le_services; 11657be49d6SMatthias Ringwald #endif 11739bda6d5Smatthias.ringwald 11839bda6d5Smatthias.ringwald // used to cache l2cap rejects, echo, and informational requests 1192b83fb7dSmatthias.ringwald static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES]; 1202b83fb7dSmatthias.ringwald static int signaling_responses_pending; 1212b83fb7dSmatthias.ringwald 12233c40538SMatthias Ringwald static uint8_t require_security_level2_for_outgoing_sdp; 12333c40538SMatthias Ringwald 124fb37a842SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 125fb37a842SMatthias Ringwald 12633c40538SMatthias Ringwald static btstack_packet_handler_t l2cap_event_packet_handler; 1275628cf69SMatthias Ringwald static l2cap_fixed_channel_t fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_SIZE]; 12839bda6d5Smatthias.ringwald 12934e7e577SMatthias Ringwald static uint16_t l2cap_fixed_channel_table_channel_id_for_index(int index){ 13034e7e577SMatthias Ringwald switch (index){ 13134e7e577SMatthias Ringwald case L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL: 13234e7e577SMatthias Ringwald return L2CAP_CID_ATTRIBUTE_PROTOCOL; 13334e7e577SMatthias Ringwald case L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL: 13434e7e577SMatthias Ringwald return L2CAP_CID_SECURITY_MANAGER_PROTOCOL; 13534e7e577SMatthias Ringwald case L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL: 13634e7e577SMatthias Ringwald return L2CAP_CID_CONNECTIONLESS_CHANNEL; 13734e7e577SMatthias Ringwald default: 13834e7e577SMatthias Ringwald return 0; 13934e7e577SMatthias Ringwald } 14034e7e577SMatthias Ringwald } 1415628cf69SMatthias Ringwald static int l2cap_fixed_channel_table_index_for_channel_id(uint16_t channel_id){ 1425628cf69SMatthias Ringwald switch (channel_id){ 1435628cf69SMatthias Ringwald case L2CAP_CID_ATTRIBUTE_PROTOCOL: 1445628cf69SMatthias Ringwald return L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL; 1455628cf69SMatthias Ringwald case L2CAP_CID_SECURITY_MANAGER_PROTOCOL: 1465628cf69SMatthias Ringwald return L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL; 1475628cf69SMatthias Ringwald case L2CAP_CID_CONNECTIONLESS_CHANNEL: 1485628cf69SMatthias Ringwald return L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL; 1495628cf69SMatthias Ringwald default: 1505628cf69SMatthias Ringwald return -1; 1515628cf69SMatthias Ringwald } 1525628cf69SMatthias Ringwald } 15339bda6d5Smatthias.ringwald 15434e7e577SMatthias Ringwald static int l2cap_fixed_channel_table_index_is_le(int index){ 15534e7e577SMatthias Ringwald if (index == L2CAP_CID_CONNECTIONLESS_CHANNEL) return 0; 15634e7e577SMatthias Ringwald return 1; 15734e7e577SMatthias Ringwald } 15834e7e577SMatthias Ringwald 15971de195eSMatthias Ringwald void l2cap_init(void){ 1602b83fb7dSmatthias.ringwald signaling_responses_pending = 0; 161808a48abSmatthias.ringwald 162f5454fc6Smatthias.ringwald l2cap_channels = NULL; 163f5454fc6Smatthias.ringwald l2cap_services = NULL; 164*a3dc965aSMatthias Ringwald 165*a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 1667192e786SMatthias Ringwald l2cap_le_services = NULL; 1677192e786SMatthias Ringwald l2cap_le_channels = NULL; 168*a3dc965aSMatthias Ringwald #endif 169f5454fc6Smatthias.ringwald 17033c40538SMatthias Ringwald l2cap_event_packet_handler = NULL; 1715628cf69SMatthias Ringwald memset(fixed_channels, 0, sizeof(fixed_channels)); 172f5454fc6Smatthias.ringwald 173ac301f95S[email protected] require_security_level2_for_outgoing_sdp = 0; 174ac301f95S[email protected] 175fcadd0caSmatthias.ringwald // 1762718e2e7Smatthias.ringwald // register callback with HCI 177fcadd0caSmatthias.ringwald // 178d9a7306aSMatthias Ringwald hci_event_callback_registration.callback = &l2cap_hci_event_handler; 179fb37a842SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 180fb37a842SMatthias Ringwald 181d9a7306aSMatthias Ringwald hci_register_acl_packet_handler(&l2cap_acl_handler); 182fb37a842SMatthias Ringwald 18315a95bd5SMatthias Ringwald gap_connectable_control(0); // no services yet 184fcadd0caSmatthias.ringwald } 185fcadd0caSmatthias.ringwald 186ffbf8201SMatthias Ringwald void l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){ 18733c40538SMatthias Ringwald l2cap_event_packet_handler = handler; 1881e6aba47Smatthias.ringwald } 1891e6aba47Smatthias.ringwald 19017a9b554SMatthias Ringwald static void l2cap_dispatch_to_channel(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){ 19158de5610Smatthias.ringwald (* (channel->packet_handler))(type, channel->local_cid, data, size); 19258de5610Smatthias.ringwald } 19358de5610Smatthias.ringwald 19444276248SMatthias Ringwald static void l2cap_emit_simple_event_with_cid(l2cap_channel_t * channel, uint8_t event_code){ 19544276248SMatthias Ringwald uint8_t event[4]; 19644276248SMatthias Ringwald event[0] = event_code; 19744276248SMatthias Ringwald event[1] = sizeof(event) - 2; 19844276248SMatthias Ringwald little_endian_store_16(event, 2, channel->local_cid); 19944276248SMatthias Ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 20044276248SMatthias Ringwald l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event)); 20144276248SMatthias Ringwald } 20244276248SMatthias Ringwald 20358de5610Smatthias.ringwald void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) { 204c9dc710bS[email protected] log_info("L2CAP_EVENT_CHANNEL_OPENED status 0x%x addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x local_mtu %u, remote_mtu %u, flush_timeout %u", 205fc64f94aSMatthias Ringwald status, bd_addr_to_str(channel->address), channel->con_handle, channel->psm, 206c9dc710bS[email protected] channel->local_cid, channel->remote_cid, channel->local_mtu, channel->remote_mtu, channel->flush_timeout); 207c9dc710bS[email protected] uint8_t event[23]; 20858de5610Smatthias.ringwald event[0] = L2CAP_EVENT_CHANNEL_OPENED; 20958de5610Smatthias.ringwald event[1] = sizeof(event) - 2; 21058de5610Smatthias.ringwald event[2] = status; 211724d70a2SMatthias Ringwald reverse_bd_addr(channel->address, &event[3]); 212fc64f94aSMatthias Ringwald little_endian_store_16(event, 9, channel->con_handle); 213f8fbdce0SMatthias Ringwald little_endian_store_16(event, 11, channel->psm); 214f8fbdce0SMatthias Ringwald little_endian_store_16(event, 13, channel->local_cid); 215f8fbdce0SMatthias Ringwald little_endian_store_16(event, 15, channel->remote_cid); 216f8fbdce0SMatthias Ringwald little_endian_store_16(event, 17, channel->local_mtu); 217f8fbdce0SMatthias Ringwald little_endian_store_16(event, 19, channel->remote_mtu); 218f8fbdce0SMatthias Ringwald little_endian_store_16(event, 21, channel->flush_timeout); 21958de5610Smatthias.ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 22017a9b554SMatthias Ringwald l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event)); 22158de5610Smatthias.ringwald } 22258de5610Smatthias.ringwald 22344276248SMatthias Ringwald static void l2cap_emit_channel_closed(l2cap_channel_t *channel) { 224e0abb8e7S[email protected] log_info("L2CAP_EVENT_CHANNEL_CLOSED local_cid 0x%x", channel->local_cid); 22544276248SMatthias Ringwald l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED); 22658de5610Smatthias.ringwald } 22758de5610Smatthias.ringwald 22844276248SMatthias Ringwald 22944276248SMatthias Ringwald static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel) { 23044276248SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_CAN_SEND_NOW local_cid 0x%x", channel); 23144276248SMatthias Ringwald uint8_t event[4]; 23244276248SMatthias Ringwald event[0] = L2CAP_EVENT_CAN_SEND_NOW; 23344276248SMatthias Ringwald event[1] = sizeof(event) - 2; 23444276248SMatthias Ringwald little_endian_store_16(event, 2, channel); 23544276248SMatthias Ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 23644276248SMatthias Ringwald packet_handler(HCI_EVENT_PACKET, channel, event, sizeof(event)); 23744276248SMatthias Ringwald } 23844276248SMatthias Ringwald 23944276248SMatthias Ringwald static void l2cap_emit_incoming_connection(l2cap_channel_t *channel) { 240e0abb8e7S[email protected] log_info("L2CAP_EVENT_INCOMING_CONNECTION addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x", 241fc64f94aSMatthias Ringwald bd_addr_to_str(channel->address), channel->con_handle, channel->psm, channel->local_cid, channel->remote_cid); 24258de5610Smatthias.ringwald uint8_t event[16]; 24358de5610Smatthias.ringwald event[0] = L2CAP_EVENT_INCOMING_CONNECTION; 24458de5610Smatthias.ringwald event[1] = sizeof(event) - 2; 245724d70a2SMatthias Ringwald reverse_bd_addr(channel->address, &event[2]); 246fc64f94aSMatthias Ringwald little_endian_store_16(event, 8, channel->con_handle); 247f8fbdce0SMatthias Ringwald little_endian_store_16(event, 10, channel->psm); 248f8fbdce0SMatthias Ringwald little_endian_store_16(event, 12, channel->local_cid); 249f8fbdce0SMatthias Ringwald little_endian_store_16(event, 14, channel->remote_cid); 25058de5610Smatthias.ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 25117a9b554SMatthias Ringwald l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event)); 2520af41d30Smatthias.ringwald } 253808a48abSmatthias.ringwald 254fc64f94aSMatthias Ringwald static void l2cap_emit_connection_parameter_update_response(hci_con_handle_t con_handle, uint16_t result){ 255ccf076adS[email protected] uint8_t event[6]; 256ccf076adS[email protected] event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE; 257ccf076adS[email protected] event[1] = 4; 258fc64f94aSMatthias Ringwald little_endian_store_16(event, 2, con_handle); 259f8fbdce0SMatthias Ringwald little_endian_store_16(event, 4, result); 260ccf076adS[email protected] hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 26133c40538SMatthias Ringwald if (!l2cap_event_packet_handler) return; 26233c40538SMatthias Ringwald (*l2cap_event_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 263ccf076adS[email protected] } 264ccf076adS[email protected] 2657f02f414SMatthias Ringwald static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){ 266665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 267665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 268665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 269665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 270b35f641cSmatthias.ringwald if ( channel->local_cid == local_cid) { 271f62db1e3Smatthias.ringwald return channel; 272f62db1e3Smatthias.ringwald } 273f62db1e3Smatthias.ringwald } 274f62db1e3Smatthias.ringwald return NULL; 275f62db1e3Smatthias.ringwald } 276f62db1e3Smatthias.ringwald 2770b9d7e78SMatthias Ringwald /// 2780b9d7e78SMatthias Ringwald 27930725612SMatthias Ringwald void l2cap_request_can_send_now_event(uint16_t local_cid){ 28030725612SMatthias Ringwald l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid); 28130725612SMatthias Ringwald if (!channel) return; 28230725612SMatthias Ringwald channel->waiting_for_can_send_now = 1; 28330725612SMatthias Ringwald l2cap_notify_channel_can_send(); 28430725612SMatthias Ringwald } 28530725612SMatthias Ringwald 2860b9d7e78SMatthias Ringwald void l2cap_request_can_send_fix_channel_now_event(hci_con_handle_t con_handle, uint16_t channel_id){ 2870b9d7e78SMatthias Ringwald int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id); 2880b9d7e78SMatthias Ringwald if (index < 0) return; 2890b9d7e78SMatthias Ringwald fixed_channels[index].waiting_for_can_send_now = 1; 2900b9d7e78SMatthias Ringwald l2cap_notify_channel_can_send(); 2910b9d7e78SMatthias Ringwald } 2920b9d7e78SMatthias Ringwald 2930b9d7e78SMatthias Ringwald /// 2940b9d7e78SMatthias Ringwald 2956b1fde37Smatthias.ringwald int l2cap_can_send_packet_now(uint16_t local_cid){ 2966b1fde37Smatthias.ringwald l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid); 2976b1fde37Smatthias.ringwald if (!channel) return 0; 2980b9d7e78SMatthias Ringwald return hci_can_send_acl_packet_now(channel->con_handle); 2997856fb31S[email protected] } 3007856fb31S[email protected] 30183e7cdd9SMatthias Ringwald int l2cap_can_send_prepared_packet_now(uint16_t local_cid){ 30283e7cdd9SMatthias Ringwald l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid); 30383e7cdd9SMatthias Ringwald if (!channel) return 0; 3040b9d7e78SMatthias Ringwald return hci_can_send_prepared_acl_packet_now(channel->con_handle); 30583e7cdd9SMatthias Ringwald } 30683e7cdd9SMatthias Ringwald 307fc64f94aSMatthias Ringwald int l2cap_can_send_fixed_channel_packet_now(hci_con_handle_t con_handle, uint16_t channel_id){ 3080b9d7e78SMatthias Ringwald return hci_can_send_acl_packet_now(con_handle); 3092125de09SMatthias Ringwald } 3100b9d7e78SMatthias Ringwald 3110b9d7e78SMatthias Ringwald /// 3123cab4fcaS[email protected] 31396cbd662Smatthias.ringwald uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){ 31496cbd662Smatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); 31596cbd662Smatthias.ringwald if (channel) { 31696cbd662Smatthias.ringwald return channel->remote_mtu; 31796cbd662Smatthias.ringwald } 31896cbd662Smatthias.ringwald return 0; 31996cbd662Smatthias.ringwald } 32096cbd662Smatthias.ringwald 321ec820d77SMatthias Ringwald static l2cap_channel_t * l2cap_channel_for_rtx_timer(btstack_timer_source_t * ts){ 322665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 323665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 324665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 325665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 3265932bd7cS[email protected] if ( &channel->rtx == ts) { 3275932bd7cS[email protected] return channel; 3285932bd7cS[email protected] } 3295932bd7cS[email protected] } 3305932bd7cS[email protected] return NULL; 3315932bd7cS[email protected] } 3325932bd7cS[email protected] 333ec820d77SMatthias Ringwald static void l2cap_rtx_timeout(btstack_timer_source_t * ts){ 3345932bd7cS[email protected] l2cap_channel_t * channel = l2cap_channel_for_rtx_timer(ts); 33595d2c8f4SMatthias Ringwald if (!channel) return; 3365932bd7cS[email protected] 3375932bd7cS[email protected] log_info("l2cap_rtx_timeout for local cid 0x%02x", channel->local_cid); 3385932bd7cS[email protected] 3395932bd7cS[email protected] // "When terminating the channel, it is not necessary to send a L2CAP_DisconnectReq 3405932bd7cS[email protected] // and enter WAIT_DISCONNECT state. Channels can be transitioned directly to the CLOSED state." 3415932bd7cS[email protected] // notify client 3425932bd7cS[email protected] l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_RTX_TIMEOUT); 3435932bd7cS[email protected] 3445932bd7cS[email protected] // discard channel 3459dcb2fb2S[email protected] // no need to stop timer here, it is removed from list during timer callback 346665d90f2SMatthias Ringwald btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel); 3475932bd7cS[email protected] btstack_memory_l2cap_channel_free(channel); 3485932bd7cS[email protected] } 3495932bd7cS[email protected] 3505932bd7cS[email protected] static void l2cap_stop_rtx(l2cap_channel_t * channel){ 3515932bd7cS[email protected] log_info("l2cap_stop_rtx for local cid 0x%02x", channel->local_cid); 352528a4a3bSMatthias Ringwald btstack_run_loop_remove_timer(&channel->rtx); 3535932bd7cS[email protected] } 3545932bd7cS[email protected] 3555932bd7cS[email protected] static void l2cap_start_rtx(l2cap_channel_t * channel){ 3565932bd7cS[email protected] l2cap_stop_rtx(channel); 357cb0ff06bS[email protected] log_info("l2cap_start_rtx for local cid 0x%02x", channel->local_cid); 358528a4a3bSMatthias Ringwald btstack_run_loop_set_timer_handler(&channel->rtx, l2cap_rtx_timeout); 359528a4a3bSMatthias Ringwald btstack_run_loop_set_timer(&channel->rtx, L2CAP_RTX_TIMEOUT_MS); 360528a4a3bSMatthias Ringwald btstack_run_loop_add_timer(&channel->rtx); 3615932bd7cS[email protected] } 3625932bd7cS[email protected] 3635932bd7cS[email protected] static void l2cap_start_ertx(l2cap_channel_t * channel){ 3645932bd7cS[email protected] log_info("l2cap_start_ertx for local cid 0x%02x", channel->local_cid); 3655932bd7cS[email protected] l2cap_stop_rtx(channel); 366528a4a3bSMatthias Ringwald btstack_run_loop_set_timer_handler(&channel->rtx, l2cap_rtx_timeout); 367528a4a3bSMatthias Ringwald btstack_run_loop_set_timer(&channel->rtx, L2CAP_ERTX_TIMEOUT_MS); 368528a4a3bSMatthias Ringwald btstack_run_loop_add_timer(&channel->rtx); 3695932bd7cS[email protected] } 3705932bd7cS[email protected] 37171de195eSMatthias Ringwald void l2cap_require_security_level_2_for_outgoing_sdp(void){ 372ac301f95S[email protected] require_security_level2_for_outgoing_sdp = 1; 373ac301f95S[email protected] } 374ac301f95S[email protected] 375df3354fcS[email protected] static int l2cap_security_level_0_allowed_for_PSM(uint16_t psm){ 376ac301f95S[email protected] return (psm == PSM_SDP) && (!require_security_level2_for_outgoing_sdp); 377df3354fcS[email protected] } 3785932bd7cS[email protected] 3797f02f414SMatthias Ringwald static int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){ 380b1d43497Smatthias.ringwald 381a35252c8S[email protected] if (!hci_can_send_acl_packet_now(handle)){ 3829da54300S[email protected] log_info("l2cap_send_signaling_packet, cannot send"); 383b1d43497Smatthias.ringwald return BTSTACK_ACL_BUFFERS_FULL; 384b1d43497Smatthias.ringwald } 385b1d43497Smatthias.ringwald 3869da54300S[email protected] // log_info("l2cap_send_signaling_packet type %u", cmd); 3872a373862S[email protected] hci_reserve_packet_buffer(); 388facf93fdS[email protected] uint8_t *acl_buffer = hci_get_outgoing_packet_buffer(); 38958de5610Smatthias.ringwald va_list argptr; 39058de5610Smatthias.ringwald va_start(argptr, identifier); 39170efece1S[email protected] uint16_t len = l2cap_create_signaling_classic(acl_buffer, handle, cmd, identifier, argptr); 39258de5610Smatthias.ringwald va_end(argptr); 3939da54300S[email protected] // log_info("l2cap_send_signaling_packet con %u!", handle); 394826f7347S[email protected] return hci_send_acl_packet_buffer(len); 39558de5610Smatthias.ringwald } 39658de5610Smatthias.ringwald 397a9a4c409SMatthias Ringwald #ifdef ENABLE_BLE 3987f02f414SMatthias Ringwald static int l2cap_send_le_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){ 39970efece1S[email protected] 400a35252c8S[email protected] if (!hci_can_send_acl_packet_now(handle)){ 4019da54300S[email protected] log_info("l2cap_send_signaling_packet, cannot send"); 40270efece1S[email protected] return BTSTACK_ACL_BUFFERS_FULL; 40370efece1S[email protected] } 40470efece1S[email protected] 4059da54300S[email protected] // log_info("l2cap_send_signaling_packet type %u", cmd); 4062a373862S[email protected] hci_reserve_packet_buffer(); 407facf93fdS[email protected] uint8_t *acl_buffer = hci_get_outgoing_packet_buffer(); 40870efece1S[email protected] va_list argptr; 40970efece1S[email protected] va_start(argptr, identifier); 41070efece1S[email protected] uint16_t len = l2cap_create_signaling_le(acl_buffer, handle, cmd, identifier, argptr); 41170efece1S[email protected] va_end(argptr); 4129da54300S[email protected] // log_info("l2cap_send_signaling_packet con %u!", handle); 413826f7347S[email protected] return hci_send_acl_packet_buffer(len); 41470efece1S[email protected] } 41570efece1S[email protected] #endif 41670efece1S[email protected] 417b1d43497Smatthias.ringwald uint8_t *l2cap_get_outgoing_buffer(void){ 418facf93fdS[email protected] return hci_get_outgoing_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes 419b1d43497Smatthias.ringwald } 4206218e6f1Smatthias.ringwald 4216b4af23dS[email protected] int l2cap_reserve_packet_buffer(void){ 4226b4af23dS[email protected] return hci_reserve_packet_buffer(); 4236b4af23dS[email protected] } 4246b4af23dS[email protected] 42568a0fcf7S[email protected] void l2cap_release_packet_buffer(void){ 42668a0fcf7S[email protected] hci_release_packet_buffer(); 42768a0fcf7S[email protected] } 42868a0fcf7S[email protected] 4297f107edaSMatthias Ringwald static void l2cap_setup_header(uint8_t * acl_buffer, hci_con_handle_t con_handle, uint16_t remote_cid, uint16_t len){ 4307f107edaSMatthias Ringwald 4317f107edaSMatthias Ringwald int pb = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02; 4327f107edaSMatthias Ringwald 4337f107edaSMatthias Ringwald // 0 - Connection handle : PB=pb : BC=00 4347f107edaSMatthias Ringwald little_endian_store_16(acl_buffer, 0, con_handle | (pb << 12) | (0 << 14)); 4357f107edaSMatthias Ringwald // 2 - ACL length 4367f107edaSMatthias Ringwald little_endian_store_16(acl_buffer, 2, len + 4); 4377f107edaSMatthias Ringwald // 4 - L2CAP packet length 4387f107edaSMatthias Ringwald little_endian_store_16(acl_buffer, 4, len + 0); 4397f107edaSMatthias Ringwald // 6 - L2CAP channel DEST 4407f107edaSMatthias Ringwald little_endian_store_16(acl_buffer, 6, remote_cid); 4417f107edaSMatthias Ringwald } 44268a0fcf7S[email protected] 443b1d43497Smatthias.ringwald int l2cap_send_prepared(uint16_t local_cid, uint16_t len){ 444b1d43497Smatthias.ringwald 445c8b9416aS[email protected] if (!hci_is_packet_buffer_reserved()){ 446c8b9416aS[email protected] log_error("l2cap_send_prepared called without reserving packet first"); 447c8b9416aS[email protected] return BTSTACK_ACL_BUFFERS_FULL; 448c8b9416aS[email protected] } 449c8b9416aS[email protected] 45058de5610Smatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); 451b1d43497Smatthias.ringwald if (!channel) { 4529da54300S[email protected] log_error("l2cap_send_prepared no channel for cid 0x%02x", local_cid); 453b1d43497Smatthias.ringwald return -1; // TODO: define error 4546218e6f1Smatthias.ringwald } 4556218e6f1Smatthias.ringwald 456fc64f94aSMatthias Ringwald if (!hci_can_send_prepared_acl_packet_now(channel->con_handle)){ 4579da54300S[email protected] log_info("l2cap_send_prepared cid 0x%02x, cannot send", local_cid); 458a35252c8S[email protected] return BTSTACK_ACL_BUFFERS_FULL; 459a35252c8S[email protected] } 460a35252c8S[email protected] 461fc64f94aSMatthias Ringwald log_debug("l2cap_send_prepared cid 0x%02x, handle %u, 1 credit used", local_cid, channel->con_handle); 462b1d43497Smatthias.ringwald 463facf93fdS[email protected] uint8_t *acl_buffer = hci_get_outgoing_packet_buffer(); 4647f107edaSMatthias Ringwald l2cap_setup_header(acl_buffer, channel->con_handle, channel->remote_cid, len); 46558de5610Smatthias.ringwald // send 4667f107edaSMatthias Ringwald return hci_send_acl_packet_buffer(len+8); 46758de5610Smatthias.ringwald } 46858de5610Smatthias.ringwald 469fc64f94aSMatthias Ringwald int l2cap_send_prepared_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint16_t len){ 4702149f12eSmatthias.ringwald 471c8b9416aS[email protected] if (!hci_is_packet_buffer_reserved()){ 472c8b9416aS[email protected] log_error("l2cap_send_prepared_connectionless called without reserving packet first"); 4732149f12eSmatthias.ringwald return BTSTACK_ACL_BUFFERS_FULL; 4742149f12eSmatthias.ringwald } 4752149f12eSmatthias.ringwald 476fc64f94aSMatthias Ringwald if (!hci_can_send_prepared_acl_packet_now(con_handle)){ 477fc64f94aSMatthias Ringwald log_info("l2cap_send_prepared_connectionless handle 0x%02x, cid 0x%02x, cannot send", con_handle, cid); 478c8b9416aS[email protected] return BTSTACK_ACL_BUFFERS_FULL; 479c8b9416aS[email protected] } 480c8b9416aS[email protected] 481fc64f94aSMatthias Ringwald log_debug("l2cap_send_prepared_connectionless handle %u, cid 0x%02x", con_handle, cid); 4822149f12eSmatthias.ringwald 483facf93fdS[email protected] uint8_t *acl_buffer = hci_get_outgoing_packet_buffer(); 4847f107edaSMatthias Ringwald l2cap_setup_header(acl_buffer, con_handle, cid, len); 4852149f12eSmatthias.ringwald // send 4867f107edaSMatthias Ringwald return hci_send_acl_packet_buffer(len+8); 4872149f12eSmatthias.ringwald } 4882149f12eSmatthias.ringwald 489ce8f182eSMatthias Ringwald int l2cap_send(uint16_t local_cid, uint8_t *data, uint16_t len){ 490b1d43497Smatthias.ringwald 491a35252c8S[email protected] l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); 492a35252c8S[email protected] if (!channel) { 493ce8f182eSMatthias Ringwald log_error("l2cap_send no channel for cid 0x%02x", local_cid); 494a35252c8S[email protected] return -1; // TODO: define error 495a35252c8S[email protected] } 496a35252c8S[email protected] 497f0efaa57S[email protected] if (len > channel->remote_mtu){ 498ce8f182eSMatthias Ringwald log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", local_cid); 499f0efaa57S[email protected] return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU; 500f0efaa57S[email protected] } 501f0efaa57S[email protected] 502fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)){ 503ce8f182eSMatthias Ringwald log_info("l2cap_send cid 0x%02x, cannot send", local_cid); 504b1d43497Smatthias.ringwald return BTSTACK_ACL_BUFFERS_FULL; 505b1d43497Smatthias.ringwald } 506b1d43497Smatthias.ringwald 5072a373862S[email protected] hci_reserve_packet_buffer(); 508facf93fdS[email protected] uint8_t *acl_buffer = hci_get_outgoing_packet_buffer(); 509b1d43497Smatthias.ringwald 510b1d43497Smatthias.ringwald memcpy(&acl_buffer[8], data, len); 511b1d43497Smatthias.ringwald 512b1d43497Smatthias.ringwald return l2cap_send_prepared(local_cid, len); 513b1d43497Smatthias.ringwald } 514b1d43497Smatthias.ringwald 515fc64f94aSMatthias Ringwald int l2cap_send_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint8_t *data, uint16_t len){ 5162149f12eSmatthias.ringwald 517fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(con_handle)){ 518ce8f182eSMatthias Ringwald log_info("l2cap_send cid 0x%02x, cannot send", cid); 5192149f12eSmatthias.ringwald return BTSTACK_ACL_BUFFERS_FULL; 5202149f12eSmatthias.ringwald } 5212149f12eSmatthias.ringwald 5222a373862S[email protected] hci_reserve_packet_buffer(); 523facf93fdS[email protected] uint8_t *acl_buffer = hci_get_outgoing_packet_buffer(); 5242149f12eSmatthias.ringwald 5252149f12eSmatthias.ringwald memcpy(&acl_buffer[8], data, len); 5262149f12eSmatthias.ringwald 527fc64f94aSMatthias Ringwald return l2cap_send_prepared_connectionless(con_handle, cid, len); 5282149f12eSmatthias.ringwald } 5292149f12eSmatthias.ringwald 530fc64f94aSMatthias Ringwald int l2cap_send_echo_request(hci_con_handle_t con_handle, uint8_t *data, uint16_t len){ 531fc64f94aSMatthias Ringwald return l2cap_send_signaling_packet(con_handle, ECHO_REQUEST, 0x77, len, data); 5320e37e417S[email protected] } 5330e37e417S[email protected] 53428ca2b46S[email protected] static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){ 53528ca2b46S[email protected] channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var | flag); 53628ca2b46S[email protected] } 53728ca2b46S[email protected] 53828ca2b46S[email protected] static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){ 53928ca2b46S[email protected] channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag); 54028ca2b46S[email protected] } 54128ca2b46S[email protected] 54228ca2b46S[email protected] 543b1d43497Smatthias.ringwald 5448158c421Smatthias.ringwald // MARK: L2CAP_RUN 5452cd0be45Smatthias.ringwald // process outstanding signaling tasks 5467f02f414SMatthias Ringwald static void l2cap_run(void){ 5472b83fb7dSmatthias.ringwald 54822c29ab4SMatthias Ringwald // log_info("l2cap_run: entered"); 54922c29ab4SMatthias Ringwald 5502b83fb7dSmatthias.ringwald // check pending signaling responses 5512b83fb7dSmatthias.ringwald while (signaling_responses_pending){ 5522b83fb7dSmatthias.ringwald 5532b83fb7dSmatthias.ringwald hci_con_handle_t handle = signaling_responses[0].handle; 554a35252c8S[email protected] 555a35252c8S[email protected] if (!hci_can_send_acl_packet_now(handle)) break; 556a35252c8S[email protected] 5572b83fb7dSmatthias.ringwald uint8_t sig_id = signaling_responses[0].sig_id; 5582b360848Smatthias.ringwald uint16_t infoType = signaling_responses[0].data; // INFORMATION_REQUEST 55963a7246aSmatthias.ringwald uint16_t result = signaling_responses[0].data; // CONNECTION_REQUEST, COMMAND_REJECT 560f53da564S[email protected] uint8_t response_code = signaling_responses[0].code; 5612b83fb7dSmatthias.ringwald 562f53da564S[email protected] // remove first item before sending (to avoid sending response mutliple times) 563f53da564S[email protected] signaling_responses_pending--; 564f53da564S[email protected] int i; 565f53da564S[email protected] for (i=0; i < signaling_responses_pending; i++){ 566f53da564S[email protected] memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t)); 567f53da564S[email protected] } 568f53da564S[email protected] 569f53da564S[email protected] switch (response_code){ 5702b360848Smatthias.ringwald case CONNECTION_REQUEST: 5712b360848Smatthias.ringwald l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, 0, 0, result, 0); 5722bd8b7e7S[email protected] // also disconnect if result is 0x0003 - security blocked 5734d816277S[email protected] if (result == 0x0003){ 5742bd8b7e7S[email protected] hci_disconnect_security_block(handle); 5754d816277S[email protected] } 5762b360848Smatthias.ringwald break; 5772b83fb7dSmatthias.ringwald case ECHO_REQUEST: 5782b83fb7dSmatthias.ringwald l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL); 5792b83fb7dSmatthias.ringwald break; 5802b83fb7dSmatthias.ringwald case INFORMATION_REQUEST: 5813b0484b3S[email protected] switch (infoType){ 5823b0484b3S[email protected] case 1: { // Connectionless MTU 5833b0484b3S[email protected] uint16_t connectionless_mtu = hci_max_acl_data_packet_length(); 5843b0484b3S[email protected] l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, sizeof(connectionless_mtu), &connectionless_mtu); 5853b0484b3S[email protected] break; 5863b0484b3S[email protected] } 5873b0484b3S[email protected] case 2: { // Extended Features Supported 588462e630dS[email protected] // extended features request supported, features: fixed channels, unicast connectionless data reception 589462e630dS[email protected] uint32_t features = 0x280; 5903b0484b3S[email protected] l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, sizeof(features), &features); 5913b0484b3S[email protected] break; 5923b0484b3S[email protected] } 5933b0484b3S[email protected] case 3: { // Fixed Channels Supported 5943b0484b3S[email protected] uint8_t map[8]; 5953b0484b3S[email protected] memset(map, 0, 8); 596288636a2SMatthias Ringwald map[0] = 0x06; // L2CAP Signaling Channel (0x02) + Connectionless reception (0x04) 5973b0484b3S[email protected] l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, sizeof(map), &map); 5983b0484b3S[email protected] break; 5993b0484b3S[email protected] } 6003b0484b3S[email protected] default: 6012b83fb7dSmatthias.ringwald // all other types are not supported 6022b83fb7dSmatthias.ringwald l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL); 6033b0484b3S[email protected] break; 6042b83fb7dSmatthias.ringwald } 6052b83fb7dSmatthias.ringwald break; 60663a7246aSmatthias.ringwald case COMMAND_REJECT: 6075ca8d57bS[email protected] l2cap_send_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL); 60863f0ac45SMatthias Ringwald break; 609a9a4c409SMatthias Ringwald #ifdef ENABLE_BLE 61063f0ac45SMatthias Ringwald case LE_CREDIT_BASED_CONNECTION_REQUEST: 61163f0ac45SMatthias Ringwald l2cap_send_le_signaling_packet(handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, sig_id, 0, 0, 0, 0, result); 61263f0ac45SMatthias Ringwald break; 61370efece1S[email protected] case COMMAND_REJECT_LE: 61470efece1S[email protected] l2cap_send_le_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL); 61563a7246aSmatthias.ringwald break; 61670efece1S[email protected] #endif 6172b83fb7dSmatthias.ringwald default: 6182b83fb7dSmatthias.ringwald // should not happen 6192b83fb7dSmatthias.ringwald break; 6202b83fb7dSmatthias.ringwald } 6212b83fb7dSmatthias.ringwald } 6222b83fb7dSmatthias.ringwald 623ae280e73Smatthias.ringwald uint8_t config_options[4]; 624665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 625665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 626665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 627baf94f06S[email protected] 628665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 62922c29ab4SMatthias Ringwald // log_info("l2cap_run: channel %p, state %u, var 0x%02x", channel, channel->state, channel->state_var); 6302cd0be45Smatthias.ringwald switch (channel->state){ 6312cd0be45Smatthias.ringwald 632df3354fcS[email protected] case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE: 633ad671560S[email protected] case L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT: 634fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 635a00031e2S[email protected] if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND) { 636ad671560S[email protected] channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND); 637fc64f94aSMatthias Ringwald l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 1, 0); 638ad671560S[email protected] } 639ad671560S[email protected] break; 640ad671560S[email protected] 64102b22dc4Smatthias.ringwald case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION: 642baf94f06S[email protected] if (!hci_can_send_command_packet_now()) break; 64364472d52Smatthias.ringwald // send connection request - set state first 64464472d52Smatthias.ringwald channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE; 64502b22dc4Smatthias.ringwald // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch 6468f8108aaSmatthias.ringwald hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1); 64702b22dc4Smatthias.ringwald break; 64802b22dc4Smatthias.ringwald 649e7ff783cSmatthias.ringwald case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE: 650fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 65122c29ab4SMatthias Ringwald channel->state = L2CAP_STATE_INVALID; 652fc64f94aSMatthias Ringwald l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, channel->reason, 0); 653e7ff783cSmatthias.ringwald // discard channel - l2cap_finialize_channel_close without sending l2cap close event 6549dcb2fb2S[email protected] l2cap_stop_rtx(channel); 655665d90f2SMatthias Ringwald btstack_linked_list_iterator_remove(&it); 656d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 657e7ff783cSmatthias.ringwald break; 658e7ff783cSmatthias.ringwald 659552d92a1Smatthias.ringwald case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT: 660fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 661fa8473a4Smatthias.ringwald channel->state = L2CAP_STATE_CONFIG; 66228ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ); 663fc64f94aSMatthias Ringwald l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0); 664552d92a1Smatthias.ringwald break; 665552d92a1Smatthias.ringwald 6666fdcc387Smatthias.ringwald case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST: 667fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 6686fdcc387Smatthias.ringwald // success, start l2cap handshake 669b1988dceSmatthias.ringwald channel->local_sig_id = l2cap_next_sig_id(); 6706fdcc387Smatthias.ringwald channel->state = L2CAP_STATE_WAIT_CONNECT_RSP; 671fc64f94aSMatthias Ringwald l2cap_send_signaling_packet( channel->con_handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid); 6725932bd7cS[email protected] l2cap_start_rtx(channel); 6736fdcc387Smatthias.ringwald break; 6746fdcc387Smatthias.ringwald 675fa8473a4Smatthias.ringwald case L2CAP_STATE_CONFIG: 676fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 67773cf2b3dSmatthias.ringwald if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){ 67863a7246aSmatthias.ringwald uint16_t flags = 0; 67928ca2b46S[email protected] channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP); 68063a7246aSmatthias.ringwald if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT) { 68163a7246aSmatthias.ringwald flags = 1; 68263a7246aSmatthias.ringwald } else { 68328ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP); 68463a7246aSmatthias.ringwald } 68563a7246aSmatthias.ringwald if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID){ 686fc64f94aSMatthias Ringwald l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_UNKNOWN_OPTIONS, 0, NULL); 68763a7246aSmatthias.ringwald } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU){ 68863a7246aSmatthias.ringwald config_options[0] = 1; // MTU 68963a7246aSmatthias.ringwald config_options[1] = 2; // len param 690f8fbdce0SMatthias Ringwald little_endian_store_16( (uint8_t*)&config_options, 2, channel->remote_mtu); 691fc64f94aSMatthias Ringwald l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, 0, 4, &config_options); 69263a7246aSmatthias.ringwald channelStateVarClearFlag(channel,L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU); 69363a7246aSmatthias.ringwald } else { 694fc64f94aSMatthias Ringwald l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, 0, 0, NULL); 69563a7246aSmatthias.ringwald } 69663a7246aSmatthias.ringwald channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT); 697fa8473a4Smatthias.ringwald } 69873cf2b3dSmatthias.ringwald else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){ 69928ca2b46S[email protected] channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ); 70028ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ); 701b1988dceSmatthias.ringwald channel->local_sig_id = l2cap_next_sig_id(); 702ae280e73Smatthias.ringwald config_options[0] = 1; // MTU 703ae280e73Smatthias.ringwald config_options[1] = 2; // len param 704f8fbdce0SMatthias Ringwald little_endian_store_16( (uint8_t*)&config_options, 2, channel->local_mtu); 705fc64f94aSMatthias Ringwald l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, 4, &config_options); 7065932bd7cS[email protected] l2cap_start_rtx(channel); 707fa8473a4Smatthias.ringwald } 708fa8473a4Smatthias.ringwald if (l2cap_channel_ready_for_open(channel)){ 709552d92a1Smatthias.ringwald channel->state = L2CAP_STATE_OPEN; 710552d92a1Smatthias.ringwald l2cap_emit_channel_opened(channel, 0); // success 711fa8473a4Smatthias.ringwald } 712552d92a1Smatthias.ringwald break; 713552d92a1Smatthias.ringwald 714e7ff783cSmatthias.ringwald case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE: 715fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 71622c29ab4SMatthias Ringwald channel->state = L2CAP_STATE_INVALID; 717fc64f94aSMatthias Ringwald l2cap_send_signaling_packet( channel->con_handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid); 7185932bd7cS[email protected] // we don't start an RTX timer for a disconnect - there's no point in closing the channel if the other side doesn't respond :) 719756102d3Smatthias.ringwald l2cap_finialize_channel_close(channel); // -- remove from list 720e7ff783cSmatthias.ringwald break; 721e7ff783cSmatthias.ringwald 722e7ff783cSmatthias.ringwald case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST: 723fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 724b1988dceSmatthias.ringwald channel->local_sig_id = l2cap_next_sig_id(); 7252cd0be45Smatthias.ringwald channel->state = L2CAP_STATE_WAIT_DISCONNECT; 726fc64f94aSMatthias Ringwald l2cap_send_signaling_packet( channel->con_handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid); 7272cd0be45Smatthias.ringwald break; 7282cd0be45Smatthias.ringwald default: 7292cd0be45Smatthias.ringwald break; 7302cd0be45Smatthias.ringwald } 7312cd0be45Smatthias.ringwald } 732da886c03S[email protected] 733a9a4c409SMatthias Ringwald #ifdef ENABLE_BLE 734cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 735efedfb4cSMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_le_channels); 736efedfb4cSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 7377f107edaSMatthias Ringwald uint8_t * acl_buffer; 7387f107edaSMatthias Ringwald uint8_t * l2cap_payload; 7397f107edaSMatthias Ringwald uint16_t pos; 7407f107edaSMatthias Ringwald uint16_t payload_size; 741efedfb4cSMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 742efedfb4cSMatthias Ringwald // log_info("l2cap_run: channel %p, state %u, var 0x%02x", channel, channel->state, channel->state_var); 743efedfb4cSMatthias Ringwald switch (channel->state){ 7445cb87675SMatthias Ringwald case L2CAP_STATE_WILL_SEND_LE_CONNECTION_REQUEST: 7455cb87675SMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 7465cb87675SMatthias Ringwald channel->state = L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE; 7475cb87675SMatthias Ringwald // le psm, source cid, mtu, mps, initial credits 7481b8b8d05SMatthias Ringwald channel->local_sig_id = l2cap_next_sig_id(); 74963f0ac45SMatthias Ringwald channel->credits_incoming = channel->new_credits_incoming; 75063f0ac45SMatthias Ringwald channel->new_credits_incoming = 0; 75163f0ac45SMatthias Ringwald l2cap_send_le_signaling_packet( channel->con_handle, LE_CREDIT_BASED_CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid, channel->local_mtu, 23, channel->credits_incoming); 7525cb87675SMatthias Ringwald break; 75323017473SMatthias Ringwald case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_ACCEPT: 75423017473SMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 75523017473SMatthias Ringwald // TODO: support larger MPS 75623017473SMatthias Ringwald channel->state = L2CAP_STATE_OPEN; 75763f0ac45SMatthias Ringwald channel->credits_incoming = channel->new_credits_incoming; 75863f0ac45SMatthias Ringwald channel->new_credits_incoming = 0; 75963f0ac45SMatthias Ringwald l2cap_send_le_signaling_packet(channel->con_handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->local_mtu, 23, channel->credits_incoming, 0); 76064e11ca9SMatthias Ringwald // notify client 76144276248SMatthias Ringwald l2cap_emit_le_channel_opened(channel, 0); 76223017473SMatthias Ringwald break; 763e7d0c9aaSMatthias Ringwald case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE: 764e7d0c9aaSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 765e7d0c9aaSMatthias Ringwald channel->state = L2CAP_STATE_INVALID; 76663f0ac45SMatthias Ringwald l2cap_send_le_signaling_packet(channel->con_handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, 0, 0, channel->reason); 767e7d0c9aaSMatthias Ringwald // discard channel - l2cap_finialize_channel_close without sending l2cap close event 768e7d0c9aaSMatthias Ringwald l2cap_stop_rtx(channel); 769e7d0c9aaSMatthias Ringwald btstack_linked_list_iterator_remove(&it); 770e7d0c9aaSMatthias Ringwald btstack_memory_l2cap_channel_free(channel); 771e7d0c9aaSMatthias Ringwald break; 7727f107edaSMatthias Ringwald case L2CAP_STATE_OPEN: 77385aeef60SMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 77485aeef60SMatthias Ringwald 77585aeef60SMatthias Ringwald // send credits 77685aeef60SMatthias Ringwald if (channel->new_credits_incoming){ 77785aeef60SMatthias Ringwald log_info("l2cap: sending %u credits", channel->new_credits_incoming); 77885aeef60SMatthias Ringwald channel->local_sig_id = l2cap_next_sig_id(); 77985aeef60SMatthias Ringwald uint16_t new_credits = channel->new_credits_incoming; 78085aeef60SMatthias Ringwald channel->new_credits_incoming = 0; 78185aeef60SMatthias Ringwald channel->credits_incoming += new_credits; 78285aeef60SMatthias Ringwald l2cap_send_le_signaling_packet(channel->con_handle, LE_FLOW_CONTROL_CREDIT, channel->local_sig_id, channel->remote_cid, new_credits); 78385aeef60SMatthias Ringwald break; 78485aeef60SMatthias Ringwald } 78585aeef60SMatthias Ringwald 78685aeef60SMatthias Ringwald // send data 7877f107edaSMatthias Ringwald if (!channel->send_sdu_buffer) break; 7887f107edaSMatthias Ringwald if (!channel->credits_outgoing) break; 78985aeef60SMatthias Ringwald 7907f107edaSMatthias Ringwald // send part of SDU 7917f107edaSMatthias Ringwald hci_reserve_packet_buffer(); 7927f107edaSMatthias Ringwald acl_buffer = hci_get_outgoing_packet_buffer(); 7937f107edaSMatthias Ringwald l2cap_payload = acl_buffer + 8; 7947f107edaSMatthias Ringwald pos = 0; 7957f107edaSMatthias Ringwald if (!channel->send_sdu_pos){ 7967f107edaSMatthias Ringwald // store SDU len 7977f107edaSMatthias Ringwald channel->send_sdu_pos += 2; 7987f107edaSMatthias Ringwald little_endian_store_16(l2cap_payload, pos, channel->send_sdu_len); 7997f107edaSMatthias Ringwald pos += 2; 8007f107edaSMatthias Ringwald } 8017f107edaSMatthias Ringwald payload_size = btstack_min(channel->send_sdu_len + 2 - channel->send_sdu_pos, channel->remote_mps - pos); 80285aeef60SMatthias Ringwald log_info("len %u, pos %u => payload %u, credits %u", channel->send_sdu_len, channel->send_sdu_pos, payload_size, channel->credits_outgoing); 8037f107edaSMatthias Ringwald memcpy(&l2cap_payload[pos], &channel->send_sdu_buffer[channel->send_sdu_pos-2], payload_size); // -2 for virtual SDU len 8047f107edaSMatthias Ringwald pos += payload_size; 8057f107edaSMatthias Ringwald channel->send_sdu_pos += payload_size; 80663f0ac45SMatthias Ringwald l2cap_setup_header(acl_buffer, channel->con_handle, channel->remote_cid, pos); 8077f107edaSMatthias Ringwald // done 8087f107edaSMatthias Ringwald 80985aeef60SMatthias Ringwald channel->credits_outgoing--; 8107f107edaSMatthias Ringwald 8117f107edaSMatthias Ringwald if (channel->send_sdu_pos >= channel->send_sdu_len + 2){ 8127f107edaSMatthias Ringwald channel->send_sdu_buffer = NULL; 81344276248SMatthias Ringwald // send done event 81444276248SMatthias Ringwald l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_PACKET_SENT); 81544276248SMatthias Ringwald // inform about can send now 81644276248SMatthias Ringwald l2cap_le_notify_channel_can_send(channel); 8177f107edaSMatthias Ringwald } 8187f107edaSMatthias Ringwald hci_send_acl_packet_buffer(8 + pos); 8197f107edaSMatthias Ringwald break; 820828a7f7aSMatthias Ringwald case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST: 821828a7f7aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 822828a7f7aSMatthias Ringwald channel->local_sig_id = l2cap_next_sig_id(); 823828a7f7aSMatthias Ringwald channel->state = L2CAP_STATE_WAIT_DISCONNECT; 824828a7f7aSMatthias Ringwald l2cap_send_le_signaling_packet( channel->con_handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid); 825828a7f7aSMatthias Ringwald break; 826828a7f7aSMatthias Ringwald case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE: 827828a7f7aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) break; 828828a7f7aSMatthias Ringwald channel->state = L2CAP_STATE_INVALID; 829828a7f7aSMatthias Ringwald l2cap_send_le_signaling_packet( channel->con_handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid); 830828a7f7aSMatthias Ringwald l2cap_le_finialize_channel_close(channel); // -- remove from list 831828a7f7aSMatthias Ringwald break; 832efedfb4cSMatthias Ringwald default: 833efedfb4cSMatthias Ringwald break; 834efedfb4cSMatthias Ringwald } 835efedfb4cSMatthias Ringwald } 836efedfb4cSMatthias Ringwald 837da886c03S[email protected] // send l2cap con paramter update if necessary 838da886c03S[email protected] hci_connections_get_iterator(&it); 839665d90f2SMatthias Ringwald while(btstack_linked_list_iterator_has_next(&it)){ 840665d90f2SMatthias Ringwald hci_connection_t * connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it); 8415d14fa8fSMatthias Ringwald if (connection->address_type != BD_ADDR_TYPE_LE_PUBLIC && connection->address_type != BD_ADDR_TYPE_LE_RANDOM) continue; 842b68d7bc3SMatthias Ringwald if (!hci_can_send_acl_packet_now(connection->con_handle)) continue; 843da886c03S[email protected] switch (connection->le_con_parameter_update_state){ 844b68d7bc3SMatthias Ringwald case CON_PARAMETER_UPDATE_SEND_REQUEST: 845b68d7bc3SMatthias Ringwald connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE; 846b68d7bc3SMatthias Ringwald l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_REQUEST, connection->le_con_param_update_identifier, 847b68d7bc3SMatthias Ringwald connection->le_conn_interval_min, connection->le_conn_interval_max, connection->le_conn_latency, connection->le_supervision_timeout); 848b68d7bc3SMatthias Ringwald break; 849da886c03S[email protected] case CON_PARAMETER_UPDATE_SEND_RESPONSE: 850b68d7bc3SMatthias Ringwald connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_CHANGE_HCI_CON_PARAMETERS; 851b68d7bc3SMatthias Ringwald l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 0); 852da886c03S[email protected] break; 853da886c03S[email protected] case CON_PARAMETER_UPDATE_DENY: 854b68d7bc3SMatthias Ringwald connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE; 855b68d7bc3SMatthias Ringwald l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 1); 856da886c03S[email protected] break; 857da886c03S[email protected] default: 858da886c03S[email protected] break; 859da886c03S[email protected] } 860da886c03S[email protected] } 8614d7157c3S[email protected] #endif 862cab29d48SMatthias Ringwald #endif 863da886c03S[email protected] 86422c29ab4SMatthias Ringwald // log_info("l2cap_run: exit"); 8652cd0be45Smatthias.ringwald } 8662cd0be45Smatthias.ringwald 8674aa9e837Smatthias.ringwald uint16_t l2cap_max_mtu(void){ 8684ff786cfS[email protected] return HCI_ACL_PAYLOAD_SIZE - L2CAP_HEADER_SIZE; 869fa8c92f6Smatthias.ringwald } 870fa8c92f6Smatthias.ringwald 87171de195eSMatthias Ringwald uint16_t l2cap_max_le_mtu(void){ 8724ff786cfS[email protected] return l2cap_max_mtu(); 873e5e1518dS[email protected] } 874e5e1518dS[email protected] 875fc64f94aSMatthias Ringwald static void l2cap_handle_connection_complete(hci_con_handle_t con_handle, l2cap_channel_t * channel){ 8762df5dadcS[email protected] if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) { 8775533f01eS[email protected] log_info("l2cap_handle_connection_complete expected state"); 8782df5dadcS[email protected] // success, start l2cap handshake 879fc64f94aSMatthias Ringwald channel->con_handle = con_handle; 8802df5dadcS[email protected] // check remote SSP feature first 8812df5dadcS[email protected] channel->state = L2CAP_STATE_WAIT_REMOTE_SUPPORTED_FEATURES; 8822df5dadcS[email protected] } 8832df5dadcS[email protected] } 8842df5dadcS[email protected] 8852df5dadcS[email protected] static void l2cap_handle_remote_supported_features_received(l2cap_channel_t * channel){ 8862df5dadcS[email protected] if (channel->state != L2CAP_STATE_WAIT_REMOTE_SUPPORTED_FEATURES) return; 8872df5dadcS[email protected] 8882df5dadcS[email protected] // we have been waiting for remote supported features, if both support SSP, 889ac301f95S[email protected] log_info("l2cap received remote supported features, sec_level_0_allowed for psm %u = %u", channel->psm, l2cap_security_level_0_allowed_for_PSM(channel->psm)); 890fc64f94aSMatthias Ringwald if (gap_ssp_supported_on_both_sides(channel->con_handle) && !l2cap_security_level_0_allowed_for_PSM(channel->psm)){ 8912df5dadcS[email protected] // request security level 2 8922df5dadcS[email protected] channel->state = L2CAP_STATE_WAIT_OUTGOING_SECURITY_LEVEL_UPDATE; 893fc64f94aSMatthias Ringwald gap_request_security_level(channel->con_handle, LEVEL_2); 8942df5dadcS[email protected] return; 8952df5dadcS[email protected] } 8962df5dadcS[email protected] // fine, go ahead 8972df5dadcS[email protected] channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST; 8982df5dadcS[email protected] } 8992df5dadcS[email protected] 900da144af5SMatthias Ringwald static l2cap_channel_t * l2cap_create_channel_entry(btstack_packet_handler_t packet_handler, bd_addr_t address, bd_addr_type_t address_type, 901da144af5SMatthias Ringwald uint16_t psm, uint16_t local_mtu, gap_security_level_t security_level){ 902da144af5SMatthias Ringwald 903da144af5SMatthias Ringwald l2cap_channel_t * channel = btstack_memory_l2cap_channel_get(); 904da144af5SMatthias Ringwald if (!channel) { 905da144af5SMatthias Ringwald return NULL; 906da144af5SMatthias Ringwald } 907da144af5SMatthias Ringwald 908da144af5SMatthias Ringwald // Init memory (make valgrind happy) 909da144af5SMatthias Ringwald memset(channel, 0, sizeof(l2cap_channel_t)); 910da144af5SMatthias Ringwald 911da144af5SMatthias Ringwald // fill in 912da144af5SMatthias Ringwald channel->packet_handler = packet_handler; 913da144af5SMatthias Ringwald bd_addr_copy(channel->address, address); 914da144af5SMatthias Ringwald channel->address_type = address_type; 915da144af5SMatthias Ringwald channel->psm = psm; 916da144af5SMatthias Ringwald channel->local_mtu = local_mtu; 917da144af5SMatthias Ringwald channel->remote_mtu = L2CAP_MINIMAL_MTU; 918da144af5SMatthias Ringwald channel->required_security_level = security_level; 919da144af5SMatthias Ringwald 920da144af5SMatthias Ringwald // 921da144af5SMatthias Ringwald channel->local_cid = l2cap_next_local_cid(); 922da144af5SMatthias Ringwald channel->con_handle = 0; 923da144af5SMatthias Ringwald 924da144af5SMatthias Ringwald // set initial state 925da144af5SMatthias Ringwald channel->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION; 926da144af5SMatthias Ringwald channel->state_var = L2CAP_CHANNEL_STATE_VAR_NONE; 927da144af5SMatthias Ringwald channel->remote_sig_id = L2CAP_SIG_ID_INVALID; 928da144af5SMatthias Ringwald channel->local_sig_id = L2CAP_SIG_ID_INVALID; 929da144af5SMatthias Ringwald return channel; 930da144af5SMatthias Ringwald } 931da144af5SMatthias Ringwald 9329077cb15SMatthias Ringwald /** 9339077cb15SMatthias Ringwald * @brief Creates L2CAP channel to the PSM of a remote device with baseband address. A new baseband connection will be initiated if necessary. 9349077cb15SMatthias Ringwald * @param packet_handler 9359077cb15SMatthias Ringwald * @param address 9369077cb15SMatthias Ringwald * @param psm 9379077cb15SMatthias Ringwald * @param mtu 9389077cb15SMatthias Ringwald * @param local_cid 9399077cb15SMatthias Ringwald */ 9409077cb15SMatthias Ringwald 941da144af5SMatthias Ringwald uint8_t l2cap_create_channel(btstack_packet_handler_t channel_packet_handler, bd_addr_t address, uint16_t psm, uint16_t local_mtu, uint16_t * out_local_cid){ 942da144af5SMatthias Ringwald log_info("L2CAP_CREATE_CHANNEL addr %s psm 0x%x mtu %u", bd_addr_to_str(address), psm, local_mtu); 943da144af5SMatthias Ringwald 944da144af5SMatthias Ringwald if (local_mtu > l2cap_max_mtu()) { 945da144af5SMatthias Ringwald local_mtu = l2cap_max_mtu(); 946da144af5SMatthias Ringwald } 947da144af5SMatthias Ringwald 948da144af5SMatthias Ringwald l2cap_channel_t * channel = l2cap_create_channel_entry(channel_packet_handler, address, BD_ADDR_TYPE_CLASSIC, psm, local_mtu, LEVEL_0); 949fc64f94aSMatthias Ringwald if (!channel) { 9509077cb15SMatthias Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 9519077cb15SMatthias Ringwald } 9529077cb15SMatthias Ringwald 9539077cb15SMatthias Ringwald // add to connections list 954fc64f94aSMatthias Ringwald btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel); 9559077cb15SMatthias Ringwald 9569077cb15SMatthias Ringwald // store local_cid 9579077cb15SMatthias Ringwald if (out_local_cid){ 958fc64f94aSMatthias Ringwald *out_local_cid = channel->local_cid; 9599077cb15SMatthias Ringwald } 9609077cb15SMatthias Ringwald 9619077cb15SMatthias Ringwald // check if hci connection is already usable 9629077cb15SMatthias Ringwald hci_connection_t * conn = hci_connection_for_bd_addr_and_type(address, BD_ADDR_TYPE_CLASSIC); 9639077cb15SMatthias Ringwald if (conn){ 964add0254bSMatthias Ringwald log_info("l2cap_create_channel, hci connection already exists"); 965fc64f94aSMatthias Ringwald l2cap_handle_connection_complete(conn->con_handle, channel); 9669077cb15SMatthias Ringwald // check if remote supported fearures are already received 9679077cb15SMatthias Ringwald if (conn->bonding_flags & BONDING_RECEIVED_REMOTE_FEATURES) { 968fc64f94aSMatthias Ringwald l2cap_handle_remote_supported_features_received(channel); 9699077cb15SMatthias Ringwald } 9709077cb15SMatthias Ringwald } 9719077cb15SMatthias Ringwald 9729077cb15SMatthias Ringwald l2cap_run(); 9739077cb15SMatthias Ringwald 9749077cb15SMatthias Ringwald return 0; 9759077cb15SMatthias Ringwald } 9769077cb15SMatthias Ringwald 977ce8f182eSMatthias Ringwald void 978ce8f182eSMatthias Ringwald l2cap_disconnect(uint16_t local_cid, uint8_t reason){ 979e0abb8e7S[email protected] log_info("L2CAP_DISCONNECT local_cid 0x%x reason 0x%x", local_cid, reason); 980b35f641cSmatthias.ringwald // find channel for local_cid 981b35f641cSmatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); 982f62db1e3Smatthias.ringwald if (channel) { 983e7ff783cSmatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; 984f62db1e3Smatthias.ringwald } 9852cd0be45Smatthias.ringwald // process 9862cd0be45Smatthias.ringwald l2cap_run(); 98743625864Smatthias.ringwald } 9881e6aba47Smatthias.ringwald 989afde0c52Smatthias.ringwald static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t status){ 990665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 991665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 992665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 993665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 994058e3d6bSMatthias Ringwald if ( bd_addr_cmp( channel->address, address) != 0) continue; 995c22aecc9S[email protected] // channel for this address found 996c22aecc9S[email protected] switch (channel->state){ 997c22aecc9S[email protected] case L2CAP_STATE_WAIT_CONNECTION_COMPLETE: 998c22aecc9S[email protected] case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION: 999afde0c52Smatthias.ringwald // failure, forward error code 1000afde0c52Smatthias.ringwald l2cap_emit_channel_opened(channel, status); 1001afde0c52Smatthias.ringwald // discard channel 10029dcb2fb2S[email protected] l2cap_stop_rtx(channel); 1003665d90f2SMatthias Ringwald btstack_linked_list_iterator_remove(&it); 1004d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 1005c22aecc9S[email protected] break; 1006c22aecc9S[email protected] default: 1007c22aecc9S[email protected] break; 1008afde0c52Smatthias.ringwald } 1009afde0c52Smatthias.ringwald } 1010afde0c52Smatthias.ringwald } 1011afde0c52Smatthias.ringwald 1012afde0c52Smatthias.ringwald static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t handle){ 1013665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 1014665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 1015665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1016665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 1017058e3d6bSMatthias Ringwald if ( ! bd_addr_cmp( channel->address, address) ){ 10182df5dadcS[email protected] l2cap_handle_connection_complete(handle, channel); 1019afde0c52Smatthias.ringwald } 1020afde0c52Smatthias.ringwald } 10216fdcc387Smatthias.ringwald // process 10226fdcc387Smatthias.ringwald l2cap_run(); 1023afde0c52Smatthias.ringwald } 1024b448a0e7Smatthias.ringwald 102533c40538SMatthias Ringwald static void l2cap_notify_channel_can_send(void){ 102633c40538SMatthias Ringwald btstack_linked_list_iterator_t it; 102733c40538SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 102833c40538SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 102933c40538SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 103033c40538SMatthias Ringwald if (!channel->waiting_for_can_send_now) continue; 1031fc64f94aSMatthias Ringwald if (!hci_can_send_acl_packet_now(channel->con_handle)) continue; 103233c40538SMatthias Ringwald channel->waiting_for_can_send_now = 0; 103334e7e577SMatthias Ringwald l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid); 103433c40538SMatthias Ringwald } 10352125de09SMatthias Ringwald 103644276248SMatthias Ringwald 10372125de09SMatthias Ringwald int i; 10382125de09SMatthias Ringwald for (i=0;i<L2CAP_FIXED_CHANNEL_TABLE_SIZE;i++){ 1039773c4106SMatthias Ringwald if (!fixed_channels[i].callback) continue; 10402125de09SMatthias Ringwald if (!fixed_channels[i].waiting_for_can_send_now) continue; 104134e7e577SMatthias Ringwald int can_send; 104234e7e577SMatthias Ringwald if (l2cap_fixed_channel_table_index_is_le(i)){ 104334e7e577SMatthias Ringwald can_send = hci_can_send_acl_le_packet_now(); 104434e7e577SMatthias Ringwald } else { 104534e7e577SMatthias Ringwald can_send = hci_can_send_acl_classic_packet_now(); 104634e7e577SMatthias Ringwald } 104734e7e577SMatthias Ringwald if (!can_send) continue; 104834e7e577SMatthias Ringwald fixed_channels[i].waiting_for_can_send_now = 0; 104934e7e577SMatthias Ringwald l2cap_emit_can_send_now(fixed_channels[i].callback, l2cap_fixed_channel_table_channel_id_for_index(i)); 10502125de09SMatthias Ringwald } 105133c40538SMatthias Ringwald } 105233c40538SMatthias Ringwald 1053d9a7306aSMatthias Ringwald static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *packet, uint16_t size){ 1054afde0c52Smatthias.ringwald 1055afde0c52Smatthias.ringwald bd_addr_t address; 1056afde0c52Smatthias.ringwald hci_con_handle_t handle; 1057665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 10582d00edd4Smatthias.ringwald int hci_con_used; 1059afde0c52Smatthias.ringwald 10600e2df43fSMatthias Ringwald switch(hci_event_packet_get_type(packet)){ 1061afde0c52Smatthias.ringwald 1062afde0c52Smatthias.ringwald // handle connection complete events 1063afde0c52Smatthias.ringwald case HCI_EVENT_CONNECTION_COMPLETE: 1064724d70a2SMatthias Ringwald reverse_bd_addr(&packet[5], address); 1065afde0c52Smatthias.ringwald if (packet[2] == 0){ 1066f8fbdce0SMatthias Ringwald handle = little_endian_read_16(packet, 3); 1067afde0c52Smatthias.ringwald l2cap_handle_connection_success_for_addr(address, handle); 1068afde0c52Smatthias.ringwald } else { 1069afde0c52Smatthias.ringwald l2cap_handle_connection_failed_for_addr(address, packet[2]); 1070afde0c52Smatthias.ringwald } 1071afde0c52Smatthias.ringwald break; 1072afde0c52Smatthias.ringwald 1073afde0c52Smatthias.ringwald // handle successful create connection cancel command 1074afde0c52Smatthias.ringwald case HCI_EVENT_COMMAND_COMPLETE: 1075073bd0faSMatthias Ringwald if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_create_connection_cancel)) { 1076afde0c52Smatthias.ringwald if (packet[5] == 0){ 1077724d70a2SMatthias Ringwald reverse_bd_addr(&packet[6], address); 1078afde0c52Smatthias.ringwald // CONNECTION TERMINATED BY LOCAL HOST (0X16) 1079afde0c52Smatthias.ringwald l2cap_handle_connection_failed_for_addr(address, 0x16); 108003cfbabcSmatthias.ringwald } 10811e6aba47Smatthias.ringwald } 108239d59809Smatthias.ringwald l2cap_run(); // try sending signaling packets first 108339d59809Smatthias.ringwald break; 108439d59809Smatthias.ringwald 108539d59809Smatthias.ringwald case HCI_EVENT_COMMAND_STATUS: 108639d59809Smatthias.ringwald l2cap_run(); // try sending signaling packets first 1087afde0c52Smatthias.ringwald break; 108827a923d0Smatthias.ringwald 10891e6aba47Smatthias.ringwald // handle disconnection complete events 1090afde0c52Smatthias.ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 1091c22aecc9S[email protected] // send l2cap disconnect events for all channels on this handle and free them 1092f8fbdce0SMatthias Ringwald handle = little_endian_read_16(packet, 3); 1093665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 1094665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1095665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 1096fc64f94aSMatthias Ringwald if (channel->con_handle != handle) continue; 109715ec09bbSmatthias.ringwald l2cap_emit_channel_closed(channel); 10989dcb2fb2S[email protected] l2cap_stop_rtx(channel); 1099665d90f2SMatthias Ringwald btstack_linked_list_iterator_remove(&it); 1100d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 110127a923d0Smatthias.ringwald } 1102*a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 1103991fea48SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_le_channels); 1104991fea48SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1105991fea48SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 1106991fea48SMatthias Ringwald if (channel->con_handle != handle) continue; 1107991fea48SMatthias Ringwald l2cap_emit_channel_closed(channel); 1108991fea48SMatthias Ringwald btstack_linked_list_iterator_remove(&it); 1109991fea48SMatthias Ringwald btstack_memory_l2cap_channel_free(channel); 1110991fea48SMatthias Ringwald } 1111991fea48SMatthias Ringwald #endif 1112afde0c52Smatthias.ringwald break; 1113fcadd0caSmatthias.ringwald 111433c40538SMatthias Ringwald // Notify channel packet handler if they can send now 111563fa3374SMatthias Ringwald case HCI_EVENT_TRANSPORT_PACKET_SENT: 11166218e6f1Smatthias.ringwald case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS: 111702b22dc4Smatthias.ringwald l2cap_run(); // try sending signaling packets first 111833c40538SMatthias Ringwald l2cap_notify_channel_can_send(); 11196218e6f1Smatthias.ringwald break; 11206218e6f1Smatthias.ringwald 1121ee091cf1Smatthias.ringwald // HCI Connection Timeouts 1122afde0c52Smatthias.ringwald case L2CAP_EVENT_TIMEOUT_CHECK: 1123f8fbdce0SMatthias Ringwald handle = little_endian_read_16(packet, 2); 1124bd04d84aSMatthias Ringwald if (gap_get_connection_type(handle) != GAP_CONNECTION_ACL) break; 112580ca58a0Smatthias.ringwald if (hci_authentication_active_for_handle(handle)) break; 11262d00edd4Smatthias.ringwald hci_con_used = 0; 1127665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 1128665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1129665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 1130fc64f94aSMatthias Ringwald if (channel->con_handle != handle) continue; 11312d00edd4Smatthias.ringwald hci_con_used = 1; 1132c22aecc9S[email protected] break; 1133ee091cf1Smatthias.ringwald } 11342d00edd4Smatthias.ringwald if (hci_con_used) break; 1135d94d3cafS[email protected] if (!hci_can_send_command_packet_now()) break; 11369edc8742Smatthias.ringwald hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection 1137afde0c52Smatthias.ringwald break; 1138ee091cf1Smatthias.ringwald 1139df3354fcS[email protected] case HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE: 1140f8fbdce0SMatthias Ringwald handle = little_endian_read_16(packet, 3); 1141665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 1142665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1143665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 1144fc64f94aSMatthias Ringwald if (channel->con_handle != handle) continue; 11452df5dadcS[email protected] l2cap_handle_remote_supported_features_received(channel); 1146df3354fcS[email protected] break; 1147df3354fcS[email protected] } 1148c22aecc9S[email protected] break; 1149df3354fcS[email protected] 11505611a760SMatthias Ringwald case GAP_EVENT_SECURITY_LEVEL: 1151f8fbdce0SMatthias Ringwald handle = little_endian_read_16(packet, 2); 1152bd63148eS[email protected] log_info("l2cap - security level update"); 1153665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 1154665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1155665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 1156fc64f94aSMatthias Ringwald if (channel->con_handle != handle) continue; 11575533f01eS[email protected] 1158bd63148eS[email protected] log_info("l2cap - state %u", channel->state); 1159bd63148eS[email protected] 1160e569dfd9SMatthias Ringwald gap_security_level_t actual_level = (gap_security_level_t) packet[4]; 11615533f01eS[email protected] gap_security_level_t required_level = channel->required_security_level; 11625533f01eS[email protected] 1163df3354fcS[email protected] switch (channel->state){ 1164df3354fcS[email protected] case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE: 11655533f01eS[email protected] if (actual_level >= required_level){ 1166f85a9399S[email protected] channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT; 116744276248SMatthias Ringwald l2cap_emit_incoming_connection(channel); 11681eb2563eS[email protected] } else { 1169775ecc36SMatthias Ringwald channel->reason = 0x0003; // security block 11701eb2563eS[email protected] channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE; 11711eb2563eS[email protected] } 1172df3354fcS[email protected] break; 1173df3354fcS[email protected] 1174df3354fcS[email protected] case L2CAP_STATE_WAIT_OUTGOING_SECURITY_LEVEL_UPDATE: 11755533f01eS[email protected] if (actual_level >= required_level){ 1176df3354fcS[email protected] channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST; 1177df3354fcS[email protected] } else { 1178df3354fcS[email protected] // disconnnect, authentication not good enough 1179df3354fcS[email protected] hci_disconnect_security_block(handle); 1180df3354fcS[email protected] } 1181df3354fcS[email protected] break; 1182df3354fcS[email protected] 1183df3354fcS[email protected] default: 1184df3354fcS[email protected] break; 1185df3354fcS[email protected] } 1186f85a9399S[email protected] } 1187f85a9399S[email protected] break; 1188f85a9399S[email protected] 1189afde0c52Smatthias.ringwald default: 1190afde0c52Smatthias.ringwald break; 1191afde0c52Smatthias.ringwald } 1192afde0c52Smatthias.ringwald 1193bd63148eS[email protected] l2cap_run(); 11941e6aba47Smatthias.ringwald } 11951e6aba47Smatthias.ringwald 1196afde0c52Smatthias.ringwald static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){ 1197b1988dceSmatthias.ringwald channel->remote_sig_id = identifier; 1198e7ff783cSmatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE; 1199e7ff783cSmatthias.ringwald l2cap_run(); 120084836b65Smatthias.ringwald } 120184836b65Smatthias.ringwald 12022b360848Smatthias.ringwald static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){ 12034cf56b4aSmatthias.ringwald // Vol 3, Part A, 4.3: "The DCID and SCID fields shall be ignored when the result field indi- cates the connection was refused." 12042b360848Smatthias.ringwald if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) { 12052b360848Smatthias.ringwald signaling_responses[signaling_responses_pending].handle = handle; 12062b360848Smatthias.ringwald signaling_responses[signaling_responses_pending].code = code; 12072b360848Smatthias.ringwald signaling_responses[signaling_responses_pending].sig_id = sig_id; 12082b360848Smatthias.ringwald signaling_responses[signaling_responses_pending].data = data; 12092b360848Smatthias.ringwald signaling_responses_pending++; 12102b360848Smatthias.ringwald l2cap_run(); 12112b360848Smatthias.ringwald } 12122b360848Smatthias.ringwald } 12132b360848Smatthias.ringwald 1214b35f641cSmatthias.ringwald static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){ 1215645658c9Smatthias.ringwald 12169da54300S[email protected] // log_info("l2cap_handle_connection_request for handle %u, psm %u cid 0x%02x", handle, psm, source_cid); 1217645658c9Smatthias.ringwald l2cap_service_t *service = l2cap_get_service(psm); 1218645658c9Smatthias.ringwald if (!service) { 1219645658c9Smatthias.ringwald // 0x0002 PSM not supported 12202b360848Smatthias.ringwald l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0002); 1221645658c9Smatthias.ringwald return; 1222645658c9Smatthias.ringwald } 1223645658c9Smatthias.ringwald 12245061f3afS[email protected] hci_connection_t * hci_connection = hci_connection_for_handle( handle ); 1225645658c9Smatthias.ringwald if (!hci_connection) { 12262b360848Smatthias.ringwald // 12279da54300S[email protected] log_error("no hci_connection for handle %u", handle); 1228645658c9Smatthias.ringwald return; 1229645658c9Smatthias.ringwald } 12302bd8b7e7S[email protected] 1231645658c9Smatthias.ringwald // alloc structure 12329da54300S[email protected] // log_info("l2cap_handle_connection_request register channel"); 1233da144af5SMatthias Ringwald l2cap_channel_t * channel = l2cap_create_channel_entry(service->packet_handler, hci_connection->address, BD_ADDR_TYPE_CLASSIC, 1234da144af5SMatthias Ringwald psm, service->mtu, service->required_security_level); 12352b360848Smatthias.ringwald if (!channel){ 12362b360848Smatthias.ringwald // 0x0004 No resources available 12372b360848Smatthias.ringwald l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0004); 12382b360848Smatthias.ringwald return; 12392b360848Smatthias.ringwald } 1240da144af5SMatthias Ringwald 1241fc64f94aSMatthias Ringwald channel->con_handle = handle; 1242b35f641cSmatthias.ringwald channel->remote_cid = source_cid; 1243b1988dceSmatthias.ringwald channel->remote_sig_id = sig_id; 1244645658c9Smatthias.ringwald 1245f53da564S[email protected] // limit local mtu to max acl packet length - l2cap header 12462985cb84Smatthias.ringwald if (channel->local_mtu > l2cap_max_mtu()) { 12472985cb84Smatthias.ringwald channel->local_mtu = l2cap_max_mtu(); 12489775e25bSmatthias.ringwald } 12499775e25bSmatthias.ringwald 1250645658c9Smatthias.ringwald // set initial state 1251df3354fcS[email protected] channel->state = L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE; 1252ad671560S[email protected] channel->state_var = L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND; 1253e405ae81Smatthias.ringwald 1254645658c9Smatthias.ringwald // add to connections list 1255665d90f2SMatthias Ringwald btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel); 1256645658c9Smatthias.ringwald 1257f85a9399S[email protected] // assert security requirements 12581eb2563eS[email protected] gap_request_security_level(handle, channel->required_security_level); 1259e405ae81Smatthias.ringwald } 1260645658c9Smatthias.ringwald 1261ce8f182eSMatthias Ringwald void l2cap_accept_connection(uint16_t local_cid){ 1262e0abb8e7S[email protected] log_info("L2CAP_ACCEPT_CONNECTION local_cid 0x%x", local_cid); 1263b35f641cSmatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); 1264e405ae81Smatthias.ringwald if (!channel) { 1265ce8f182eSMatthias Ringwald log_error("l2cap_accept_connection called but local_cid 0x%x not found", local_cid); 1266e405ae81Smatthias.ringwald return; 1267e405ae81Smatthias.ringwald } 1268e405ae81Smatthias.ringwald 1269552d92a1Smatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT; 1270e405ae81Smatthias.ringwald 1271552d92a1Smatthias.ringwald // process 1272552d92a1Smatthias.ringwald l2cap_run(); 1273e405ae81Smatthias.ringwald } 1274645658c9Smatthias.ringwald 12757ef6a7bbSMatthias Ringwald void l2cap_decline_connection(uint16_t local_cid){ 12767ef6a7bbSMatthias Ringwald log_info("L2CAP_DECLINE_CONNECTION local_cid 0x%x", local_cid); 1277b35f641cSmatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid); 1278e405ae81Smatthias.ringwald if (!channel) { 1279ce8f182eSMatthias Ringwald log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid); 1280e405ae81Smatthias.ringwald return; 1281e405ae81Smatthias.ringwald } 1282e7ff783cSmatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE; 12837ef6a7bbSMatthias Ringwald channel->reason = 0x04; // no resources available 1284e7ff783cSmatthias.ringwald l2cap_run(); 1285645658c9Smatthias.ringwald } 1286645658c9Smatthias.ringwald 12877f02f414SMatthias Ringwald static void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t *command){ 1288b1988dceSmatthias.ringwald 1289b1988dceSmatthias.ringwald channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET]; 1290b1988dceSmatthias.ringwald 1291f8fbdce0SMatthias Ringwald uint16_t flags = little_endian_read_16(command, 6); 129263a7246aSmatthias.ringwald if (flags & 1) { 129363a7246aSmatthias.ringwald channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT); 129463a7246aSmatthias.ringwald } 129563a7246aSmatthias.ringwald 12962784b77dSmatthias.ringwald // accept the other's configuration options 1297f8fbdce0SMatthias Ringwald uint16_t end_pos = 4 + little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET); 12983de7c0caSmatthias.ringwald uint16_t pos = 8; 12993de7c0caSmatthias.ringwald while (pos < end_pos){ 130063a7246aSmatthias.ringwald uint8_t option_hint = command[pos] >> 7; 130163a7246aSmatthias.ringwald uint8_t option_type = command[pos] & 0x7f; 130263a7246aSmatthias.ringwald log_info("l2cap cid %u, hint %u, type %u", channel->local_cid, option_hint, option_type); 130363a7246aSmatthias.ringwald pos++; 13041dc511deSmatthias.ringwald uint8_t length = command[pos++]; 13051dc511deSmatthias.ringwald // MTU { type(8): 1, len(8):2, MTU(16) } 130663a7246aSmatthias.ringwald if (option_type == 1 && length == 2){ 1307f8fbdce0SMatthias Ringwald channel->remote_mtu = little_endian_read_16(command, pos); 13089da54300S[email protected] // log_info("l2cap cid 0x%02x, remote mtu %u", channel->local_cid, channel->remote_mtu); 130963a7246aSmatthias.ringwald channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU); 131063a7246aSmatthias.ringwald } 13110fe7a9d0S[email protected] // Flush timeout { type(8):2, len(8): 2, Flush Timeout(16)} 13120fe7a9d0S[email protected] if (option_type == 2 && length == 2){ 1313f8fbdce0SMatthias Ringwald channel->flush_timeout = little_endian_read_16(command, pos); 13140fe7a9d0S[email protected] } 131563a7246aSmatthias.ringwald // check for unknown options 131663a7246aSmatthias.ringwald if (option_hint == 0 && (option_type == 0 || option_type >= 0x07)){ 1317c177a91cS[email protected] log_info("l2cap cid %u, unknown options", channel->local_cid); 131863a7246aSmatthias.ringwald channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID); 13191dc511deSmatthias.ringwald } 13201dc511deSmatthias.ringwald pos += length; 13211dc511deSmatthias.ringwald } 13222784b77dSmatthias.ringwald } 13232784b77dSmatthias.ringwald 1324fa8473a4Smatthias.ringwald static int l2cap_channel_ready_for_open(l2cap_channel_t *channel){ 13259da54300S[email protected] // log_info("l2cap_channel_ready_for_open 0x%02x", channel->state_var); 132673cf2b3dSmatthias.ringwald if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP) == 0) return 0; 132773cf2b3dSmatthias.ringwald if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP) == 0) return 0; 1328019f9b43SMatthias Ringwald // addition check that fixes re-entrance issue causing l2cap event channel opened twice 1329019f9b43SMatthias Ringwald if (channel->state == L2CAP_STATE_OPEN) return 0; 1330fa8473a4Smatthias.ringwald return 1; 1331fa8473a4Smatthias.ringwald } 1332fa8473a4Smatthias.ringwald 1333fa8473a4Smatthias.ringwald 13347f02f414SMatthias Ringwald static void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){ 13351e6aba47Smatthias.ringwald 133600d93d79Smatthias.ringwald uint8_t code = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET]; 133700d93d79Smatthias.ringwald uint8_t identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET]; 133838e5900eSmatthias.ringwald uint16_t result = 0; 13391e6aba47Smatthias.ringwald 13409da54300S[email protected] log_info("L2CAP signaling handler code %u, state %u", code, channel->state); 1341b35f641cSmatthias.ringwald 13429a011532Smatthias.ringwald // handle DISCONNECT REQUESTS seperately 13439a011532Smatthias.ringwald if (code == DISCONNECTION_REQUEST){ 13449a011532Smatthias.ringwald switch (channel->state){ 1345fa8473a4Smatthias.ringwald case L2CAP_STATE_CONFIG: 13469a011532Smatthias.ringwald case L2CAP_STATE_OPEN: 13472b83fb7dSmatthias.ringwald case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST: 13489a011532Smatthias.ringwald case L2CAP_STATE_WAIT_DISCONNECT: 13499a011532Smatthias.ringwald l2cap_handle_disconnect_request(channel, identifier); 13509a011532Smatthias.ringwald break; 13519a011532Smatthias.ringwald 13529a011532Smatthias.ringwald default: 13539a011532Smatthias.ringwald // ignore in other states 13549a011532Smatthias.ringwald break; 13559a011532Smatthias.ringwald } 13569a011532Smatthias.ringwald return; 13579a011532Smatthias.ringwald } 13589a011532Smatthias.ringwald 135956081214Smatthias.ringwald // @STATEMACHINE(l2cap) 13601e6aba47Smatthias.ringwald switch (channel->state) { 13611e6aba47Smatthias.ringwald 13621e6aba47Smatthias.ringwald case L2CAP_STATE_WAIT_CONNECT_RSP: 13631e6aba47Smatthias.ringwald switch (code){ 13641e6aba47Smatthias.ringwald case CONNECTION_RESPONSE: 13655932bd7cS[email protected] l2cap_stop_rtx(channel); 1366f8fbdce0SMatthias Ringwald result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4); 136738e5900eSmatthias.ringwald switch (result) { 136838e5900eSmatthias.ringwald case 0: 1369169f8b28Smatthias.ringwald // successful connection 1370f8fbdce0SMatthias Ringwald channel->remote_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET); 1371fa8473a4Smatthias.ringwald channel->state = L2CAP_STATE_CONFIG; 137228ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ); 137338e5900eSmatthias.ringwald break; 137438e5900eSmatthias.ringwald case 1: 13755932bd7cS[email protected] // connection pending. get some coffee, but start the ERTX 13765932bd7cS[email protected] l2cap_start_ertx(channel); 137738e5900eSmatthias.ringwald break; 137838e5900eSmatthias.ringwald default: 1379eb920dbeSmatthias.ringwald // channel closed 1380eb920dbeSmatthias.ringwald channel->state = L2CAP_STATE_CLOSED; 1381f32b992eSmatthias.ringwald // map l2cap connection response result to BTstack status enumeration 138238e5900eSmatthias.ringwald l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result); 1383eb920dbeSmatthias.ringwald 1384eb920dbeSmatthias.ringwald // drop link key if security block 1385eb920dbeSmatthias.ringwald if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){ 138615a95bd5SMatthias Ringwald gap_drop_link_key_for_bd_addr(channel->address); 1387eb920dbeSmatthias.ringwald } 1388eb920dbeSmatthias.ringwald 1389eb920dbeSmatthias.ringwald // discard channel 1390665d90f2SMatthias Ringwald btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel); 1391d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 139238e5900eSmatthias.ringwald break; 13931e6aba47Smatthias.ringwald } 13941e6aba47Smatthias.ringwald break; 139538e5900eSmatthias.ringwald 139638e5900eSmatthias.ringwald default: 13971e6aba47Smatthias.ringwald //@TODO: implement other signaling packets 139838e5900eSmatthias.ringwald break; 13991e6aba47Smatthias.ringwald } 14001e6aba47Smatthias.ringwald break; 14011e6aba47Smatthias.ringwald 1402fa8473a4Smatthias.ringwald case L2CAP_STATE_CONFIG: 1403f8fbdce0SMatthias Ringwald result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4); 1404ae280e73Smatthias.ringwald switch (code) { 1405ae280e73Smatthias.ringwald case CONFIGURE_REQUEST: 140628ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP); 1407ae280e73Smatthias.ringwald l2cap_signaling_handle_configure_request(channel, command); 140863a7246aSmatthias.ringwald if (!(channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT)){ 140963a7246aSmatthias.ringwald // only done if continuation not set 141063a7246aSmatthias.ringwald channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ); 141163a7246aSmatthias.ringwald } 1412ae280e73Smatthias.ringwald break; 14131e6aba47Smatthias.ringwald case CONFIGURE_RESPONSE: 14145932bd7cS[email protected] l2cap_stop_rtx(channel); 14155932bd7cS[email protected] switch (result){ 14165932bd7cS[email protected] case 0: // success 14175932bd7cS[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP); 14185932bd7cS[email protected] break; 14195932bd7cS[email protected] case 4: // pending 14205932bd7cS[email protected] l2cap_start_ertx(channel); 14215932bd7cS[email protected] break; 14225932bd7cS[email protected] default: 1423fe9d8984S[email protected] // retry on negative result 1424fe9d8984S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ); 1425fe9d8984S[email protected] break; 1426fe9d8984S[email protected] } 14275a67bd4aSmatthias.ringwald break; 14285a67bd4aSmatthias.ringwald default: 14295a67bd4aSmatthias.ringwald break; 14301e6aba47Smatthias.ringwald } 1431fa8473a4Smatthias.ringwald if (l2cap_channel_ready_for_open(channel)){ 1432fa8473a4Smatthias.ringwald // for open: 14335a67bd4aSmatthias.ringwald channel->state = L2CAP_STATE_OPEN; 1434fa8473a4Smatthias.ringwald l2cap_emit_channel_opened(channel, 0); 1435c8e4258aSmatthias.ringwald } 1436c8e4258aSmatthias.ringwald break; 1437f62db1e3Smatthias.ringwald 1438f62db1e3Smatthias.ringwald case L2CAP_STATE_WAIT_DISCONNECT: 1439f62db1e3Smatthias.ringwald switch (code) { 1440f62db1e3Smatthias.ringwald case DISCONNECTION_RESPONSE: 144127a923d0Smatthias.ringwald l2cap_finialize_channel_close(channel); 144227a923d0Smatthias.ringwald break; 14435a67bd4aSmatthias.ringwald default: 14445a67bd4aSmatthias.ringwald //@TODO: implement other signaling packets 14455a67bd4aSmatthias.ringwald break; 144627a923d0Smatthias.ringwald } 144727a923d0Smatthias.ringwald break; 144884836b65Smatthias.ringwald 144984836b65Smatthias.ringwald case L2CAP_STATE_CLOSED: 145084836b65Smatthias.ringwald // @TODO handle incoming requests 145184836b65Smatthias.ringwald break; 145284836b65Smatthias.ringwald 145384836b65Smatthias.ringwald case L2CAP_STATE_OPEN: 145484836b65Smatthias.ringwald //@TODO: implement other signaling packets, e.g. re-configure 145584836b65Smatthias.ringwald break; 145610642e45Smatthias.ringwald default: 145710642e45Smatthias.ringwald break; 145827a923d0Smatthias.ringwald } 14599da54300S[email protected] // log_info("new state %u", channel->state); 146027a923d0Smatthias.ringwald } 146127a923d0Smatthias.ringwald 146200d93d79Smatthias.ringwald 14637f02f414SMatthias Ringwald static void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * command){ 146400d93d79Smatthias.ringwald 146500d93d79Smatthias.ringwald // get code, signalind identifier and command len 146600d93d79Smatthias.ringwald uint8_t code = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET]; 146700d93d79Smatthias.ringwald uint8_t sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET]; 146800d93d79Smatthias.ringwald 146900d93d79Smatthias.ringwald // not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_REQUEST 147000d93d79Smatthias.ringwald if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_REQUEST){ 147163a7246aSmatthias.ringwald l2cap_register_signaling_response(handle, COMMAND_REJECT, sig_id, L2CAP_REJ_CMD_UNKNOWN); 147200d93d79Smatthias.ringwald return; 147300d93d79Smatthias.ringwald } 147400d93d79Smatthias.ringwald 147500d93d79Smatthias.ringwald // general commands without an assigned channel 147600d93d79Smatthias.ringwald switch(code) { 147700d93d79Smatthias.ringwald 147800d93d79Smatthias.ringwald case CONNECTION_REQUEST: { 1479f8fbdce0SMatthias Ringwald uint16_t psm = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET); 1480f8fbdce0SMatthias Ringwald uint16_t source_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2); 148100d93d79Smatthias.ringwald l2cap_handle_connection_request(handle, sig_id, psm, source_cid); 14822b83fb7dSmatthias.ringwald return; 148300d93d79Smatthias.ringwald } 148400d93d79Smatthias.ringwald 14852b360848Smatthias.ringwald case ECHO_REQUEST: 14862b360848Smatthias.ringwald l2cap_register_signaling_response(handle, code, sig_id, 0); 14872b83fb7dSmatthias.ringwald return; 148800d93d79Smatthias.ringwald 148900d93d79Smatthias.ringwald case INFORMATION_REQUEST: { 1490f8fbdce0SMatthias Ringwald uint16_t infoType = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET); 14912b360848Smatthias.ringwald l2cap_register_signaling_response(handle, code, sig_id, infoType); 14922b83fb7dSmatthias.ringwald return; 149300d93d79Smatthias.ringwald } 149400d93d79Smatthias.ringwald 149500d93d79Smatthias.ringwald default: 149600d93d79Smatthias.ringwald break; 149700d93d79Smatthias.ringwald } 149800d93d79Smatthias.ringwald 149900d93d79Smatthias.ringwald 150000d93d79Smatthias.ringwald // Get potential destination CID 1501f8fbdce0SMatthias Ringwald uint16_t dest_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET); 150200d93d79Smatthias.ringwald 150300d93d79Smatthias.ringwald // Find channel for this sig_id and connection handle 1504665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 1505665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_channels); 1506665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1507665d90f2SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 1508fc64f94aSMatthias Ringwald if (channel->con_handle != handle) continue; 150900d93d79Smatthias.ringwald if (code & 1) { 1510b1988dceSmatthias.ringwald // match odd commands (responses) by previous signaling identifier 1511b1988dceSmatthias.ringwald if (channel->local_sig_id == sig_id) { 151200d93d79Smatthias.ringwald l2cap_signaling_handler_channel(channel, command); 15134e32727eSmatthias.ringwald break; 151400d93d79Smatthias.ringwald } 151500d93d79Smatthias.ringwald } else { 1516b1988dceSmatthias.ringwald // match even commands (requests) by local channel id 151700d93d79Smatthias.ringwald if (channel->local_cid == dest_cid) { 151800d93d79Smatthias.ringwald l2cap_signaling_handler_channel(channel, command); 15194e32727eSmatthias.ringwald break; 152000d93d79Smatthias.ringwald } 152100d93d79Smatthias.ringwald } 152200d93d79Smatthias.ringwald } 152300d93d79Smatthias.ringwald } 152400d93d79Smatthias.ringwald 1525e7d0c9aaSMatthias Ringwald #ifdef ENABLE_BLE 1526c48b2a2cSMatthias Ringwald // @returns valid 1527c48b2a2cSMatthias Ringwald static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t * command, uint8_t sig_id){ 1528e7d0c9aaSMatthias Ringwald hci_connection_t * connection; 1529c48b2a2cSMatthias Ringwald uint16_t result; 1530c48b2a2cSMatthias Ringwald uint8_t event[10]; 153183fd9c76SMatthias Ringwald 1532cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 1533*a3dc965aSMatthias Ringwald btstack_linked_list_iterator_t it; 1534*a3dc965aSMatthias Ringwald l2cap_channel_t * channel; 1535*a3dc965aSMatthias Ringwald uint16_t local_cid; 153683fd9c76SMatthias Ringwald uint16_t le_psm; 153763f0ac45SMatthias Ringwald uint16_t new_credits; 153863f0ac45SMatthias Ringwald uint16_t credits_before; 1539e7d0c9aaSMatthias Ringwald l2cap_service_t * service; 154083fd9c76SMatthias Ringwald #endif 154100d93d79Smatthias.ringwald 15421b8b8d05SMatthias Ringwald uint8_t code = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET]; 154323017473SMatthias Ringwald log_info("l2cap_le_signaling_handler_dispatch: command 0x%02x, sig id %u", code, sig_id); 15441b8b8d05SMatthias Ringwald 15451b8b8d05SMatthias Ringwald switch (code){ 154600d93d79Smatthias.ringwald 1547c48b2a2cSMatthias Ringwald case CONNECTION_PARAMETER_UPDATE_RESPONSE: 1548c48b2a2cSMatthias Ringwald result = little_endian_read_16(command, 4); 1549ccf076adS[email protected] l2cap_emit_connection_parameter_update_response(handle, result); 1550ccf076adS[email protected] break; 1551da886c03S[email protected] 1552c48b2a2cSMatthias Ringwald case CONNECTION_PARAMETER_UPDATE_REQUEST: 1553e7d0c9aaSMatthias Ringwald connection = hci_connection_for_handle(handle); 1554da886c03S[email protected] if (connection){ 15556d91fb6cSMatthias Ringwald if (connection->role != HCI_ROLE_MASTER){ 15566d91fb6cSMatthias Ringwald // reject command without notifying upper layer when not in master role 1557c48b2a2cSMatthias Ringwald return 0; 15586d91fb6cSMatthias Ringwald } 1559da886c03S[email protected] int update_parameter = 1; 1560a4c06b28SMatthias Ringwald le_connection_parameter_range_t existing_range; 15614ced4e8cSMatthias Ringwald gap_get_connection_parameter_range(&existing_range); 1562c48b2a2cSMatthias Ringwald uint16_t le_conn_interval_min = little_endian_read_16(command,8); 1563c48b2a2cSMatthias Ringwald uint16_t le_conn_interval_max = little_endian_read_16(command,10); 1564c48b2a2cSMatthias Ringwald uint16_t le_conn_latency = little_endian_read_16(command,12); 1565c48b2a2cSMatthias Ringwald uint16_t le_supervision_timeout = little_endian_read_16(command,14); 1566da886c03S[email protected] 1567da886c03S[email protected] if (le_conn_interval_min < existing_range.le_conn_interval_min) update_parameter = 0; 1568da886c03S[email protected] if (le_conn_interval_max > existing_range.le_conn_interval_max) update_parameter = 0; 1569da886c03S[email protected] 1570da886c03S[email protected] if (le_conn_latency < existing_range.le_conn_latency_min) update_parameter = 0; 1571da886c03S[email protected] if (le_conn_latency > existing_range.le_conn_latency_max) update_parameter = 0; 1572da886c03S[email protected] 1573da886c03S[email protected] if (le_supervision_timeout < existing_range.le_supervision_timeout_min) update_parameter = 0; 1574da886c03S[email protected] if (le_supervision_timeout > existing_range.le_supervision_timeout_max) update_parameter = 0; 1575da886c03S[email protected] 1576da886c03S[email protected] if (update_parameter){ 1577da886c03S[email protected] connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_SEND_RESPONSE; 1578da886c03S[email protected] connection->le_conn_interval_min = le_conn_interval_min; 1579da886c03S[email protected] connection->le_conn_interval_max = le_conn_interval_max; 1580da886c03S[email protected] connection->le_conn_latency = le_conn_latency; 1581da886c03S[email protected] connection->le_supervision_timeout = le_supervision_timeout; 1582da886c03S[email protected] } else { 1583da886c03S[email protected] connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_DENY; 1584da886c03S[email protected] } 1585c48b2a2cSMatthias Ringwald connection->le_con_param_update_identifier = sig_id; 1586da886c03S[email protected] } 1587da886c03S[email protected] 158833c40538SMatthias Ringwald if (!l2cap_event_packet_handler) break; 1589c48b2a2cSMatthias Ringwald 1590c48b2a2cSMatthias Ringwald event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST; 1591c48b2a2cSMatthias Ringwald event[1] = 8; 1592c48b2a2cSMatthias Ringwald memcpy(&event[2], &command[4], 8); 1593c48b2a2cSMatthias Ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 159433c40538SMatthias Ringwald (*l2cap_event_packet_handler)( HCI_EVENT_PACKET, 0, event, sizeof(event)); 1595ccf076adS[email protected] break; 1596c48b2a2cSMatthias Ringwald 1597*a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 1598*a3dc965aSMatthias Ringwald 159963f0ac45SMatthias Ringwald case COMMAND_REJECT: 160063f0ac45SMatthias Ringwald // Find channel for this sig_id and connection handle 160163f0ac45SMatthias Ringwald channel = NULL; 160263f0ac45SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_le_channels); 160363f0ac45SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 160463f0ac45SMatthias Ringwald l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 160563f0ac45SMatthias Ringwald if (a_channel->con_handle != handle) continue; 160663f0ac45SMatthias Ringwald if (a_channel->local_sig_id != sig_id) continue; 160763f0ac45SMatthias Ringwald channel = a_channel; 160863f0ac45SMatthias Ringwald break; 160963f0ac45SMatthias Ringwald } 161063f0ac45SMatthias Ringwald if (!channel) break; 161163f0ac45SMatthias Ringwald 161263f0ac45SMatthias Ringwald // if received while waiting for le connection response, assume legacy device 161363f0ac45SMatthias Ringwald if (channel->state == L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE){ 161463f0ac45SMatthias Ringwald channel->state = L2CAP_STATE_CLOSED; 161563f0ac45SMatthias Ringwald // no official value for this, use: Connection refused – LE_PSM not supported - 0x0002 161644276248SMatthias Ringwald l2cap_emit_le_channel_opened(channel, 0x0002); 161763f0ac45SMatthias Ringwald 161863f0ac45SMatthias Ringwald // discard channel 161963f0ac45SMatthias Ringwald btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel); 162063f0ac45SMatthias Ringwald btstack_memory_l2cap_channel_free(channel); 162163f0ac45SMatthias Ringwald break; 162263f0ac45SMatthias Ringwald } 162363f0ac45SMatthias Ringwald break; 162463f0ac45SMatthias Ringwald 1625e7d0c9aaSMatthias Ringwald case LE_CREDIT_BASED_CONNECTION_REQUEST: 1626e7d0c9aaSMatthias Ringwald 1627e7d0c9aaSMatthias Ringwald // get hci connection, bail if not found (must not happen) 1628e7d0c9aaSMatthias Ringwald connection = hci_connection_for_handle(handle); 1629e7d0c9aaSMatthias Ringwald if (!connection) return 0; 1630e7d0c9aaSMatthias Ringwald 1631e7d0c9aaSMatthias Ringwald // check if service registered 1632e7d0c9aaSMatthias Ringwald le_psm = little_endian_read_16(command, 4); 1633e7d0c9aaSMatthias Ringwald service = l2cap_le_get_service(le_psm); 1634e7d0c9aaSMatthias Ringwald 1635e7d0c9aaSMatthias Ringwald if (service){ 1636e7d0c9aaSMatthias Ringwald 1637e7d0c9aaSMatthias Ringwald uint16_t source_cid = little_endian_read_16(command, 6); 1638e7d0c9aaSMatthias Ringwald if (source_cid < 0x40){ 1639e7d0c9aaSMatthias Ringwald // 0x0009 Connection refused - Invalid Source CID 1640e7d0c9aaSMatthias Ringwald l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, 0x0009); 1641e7d0c9aaSMatthias Ringwald return 1; 1642e7d0c9aaSMatthias Ringwald } 1643e7d0c9aaSMatthias Ringwald 1644e7d0c9aaSMatthias Ringwald // go through list of channels for this ACL connection and check if we get a match 1645e7d0c9aaSMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_le_channels); 1646e7d0c9aaSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 16471b8b8d05SMatthias Ringwald l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 16481b8b8d05SMatthias Ringwald if (a_channel->con_handle != handle) continue; 16491b8b8d05SMatthias Ringwald if (a_channel->remote_cid != source_cid) continue; 1650e7d0c9aaSMatthias Ringwald // 0x000a Connection refused - Source CID already allocated 1651e7d0c9aaSMatthias Ringwald l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, 0x000a); 1652e7d0c9aaSMatthias Ringwald return 1; 1653e7d0c9aaSMatthias Ringwald } 1654e7d0c9aaSMatthias Ringwald 165583fd9c76SMatthias Ringwald // security: check encryption 165683fd9c76SMatthias Ringwald if (service->required_security_level >= LEVEL_2){ 165783fd9c76SMatthias Ringwald if (sm_encryption_key_size(handle) == 0){ 165883fd9c76SMatthias Ringwald // 0x0008 Connection refused - insufficient encryption 165983fd9c76SMatthias Ringwald l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, 0x0008); 166083fd9c76SMatthias Ringwald return 1; 166183fd9c76SMatthias Ringwald } 166283fd9c76SMatthias Ringwald // anything less than 16 byte key size is insufficient 166383fd9c76SMatthias Ringwald if (sm_encryption_key_size(handle) < 16){ 166483fd9c76SMatthias Ringwald // 0x0007 Connection refused – insufficient encryption key size 166583fd9c76SMatthias Ringwald l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, 0x0007); 166683fd9c76SMatthias Ringwald return 1; 166783fd9c76SMatthias Ringwald } 166883fd9c76SMatthias Ringwald } 166983fd9c76SMatthias Ringwald 167083fd9c76SMatthias Ringwald // security: check authencation 167183fd9c76SMatthias Ringwald if (service->required_security_level >= LEVEL_3){ 167283fd9c76SMatthias Ringwald if (!sm_authenticated(handle)){ 167383fd9c76SMatthias Ringwald // 0x0005 Connection refused – insufficient authentication 167483fd9c76SMatthias Ringwald l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, 0x0005); 167583fd9c76SMatthias Ringwald return 1; 167683fd9c76SMatthias Ringwald } 167783fd9c76SMatthias Ringwald } 167883fd9c76SMatthias Ringwald 167983fd9c76SMatthias Ringwald // security: check authorization 168083fd9c76SMatthias Ringwald if (service->required_security_level >= LEVEL_4){ 168183fd9c76SMatthias Ringwald if (sm_authorization_state(handle) != AUTHORIZATION_GRANTED){ 168283fd9c76SMatthias Ringwald // 0x0006 Connection refused – insufficient authorization 168383fd9c76SMatthias Ringwald l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, 0x0006); 168483fd9c76SMatthias Ringwald return 1; 168583fd9c76SMatthias Ringwald } 168683fd9c76SMatthias Ringwald } 1687e7d0c9aaSMatthias Ringwald 1688e7d0c9aaSMatthias Ringwald // allocate channel 16891b8b8d05SMatthias Ringwald channel = l2cap_create_channel_entry(service->packet_handler, connection->address, 1690e7d0c9aaSMatthias Ringwald BD_ADDR_TYPE_LE_RANDOM, le_psm, service->mtu, service->required_security_level); 1691e7d0c9aaSMatthias Ringwald if (!channel){ 1692e7d0c9aaSMatthias Ringwald // 0x0004 Connection refused – no resources available 1693e7d0c9aaSMatthias Ringwald l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, 0x0004); 1694e7d0c9aaSMatthias Ringwald return 1; 1695e7d0c9aaSMatthias Ringwald } 1696e7d0c9aaSMatthias Ringwald 1697e7d0c9aaSMatthias Ringwald channel->con_handle = handle; 1698e7d0c9aaSMatthias Ringwald channel->remote_cid = source_cid; 1699e7d0c9aaSMatthias Ringwald channel->remote_sig_id = sig_id; 17007f107edaSMatthias Ringwald channel->remote_mtu = little_endian_read_16(command, 8); 17017f107edaSMatthias Ringwald channel->remote_mps = little_endian_read_16(command, 10); 17027f107edaSMatthias Ringwald channel->credits_outgoing = little_endian_read_16(command, 12); 1703e7d0c9aaSMatthias Ringwald 1704e7d0c9aaSMatthias Ringwald // set initial state 1705e7d0c9aaSMatthias Ringwald channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT; 1706c99bb618SMatthias Ringwald channel->state_var |= L2CAP_CHANNEL_STATE_VAR_INCOMING; 1707e7d0c9aaSMatthias Ringwald 1708e7d0c9aaSMatthias Ringwald // add to connections list 1709e7d0c9aaSMatthias Ringwald btstack_linked_list_add(&l2cap_le_channels, (btstack_linked_item_t *) channel); 1710e7d0c9aaSMatthias Ringwald 1711e7d0c9aaSMatthias Ringwald // post connection request event 171244276248SMatthias Ringwald l2cap_emit_le_incoming_connection(channel); 1713e7d0c9aaSMatthias Ringwald 1714e7d0c9aaSMatthias Ringwald } else { 1715e7d0c9aaSMatthias Ringwald // Connection refused – LE_PSM not supported 1716e7d0c9aaSMatthias Ringwald l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, 0x0002); 1717e7d0c9aaSMatthias Ringwald } 1718e7d0c9aaSMatthias Ringwald break; 17191b8b8d05SMatthias Ringwald 17201b8b8d05SMatthias Ringwald case LE_CREDIT_BASED_CONNECTION_RESPONSE: 17211b8b8d05SMatthias Ringwald // Find channel for this sig_id and connection handle 17221b8b8d05SMatthias Ringwald channel = NULL; 17231b8b8d05SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_le_channels); 17241b8b8d05SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 17251b8b8d05SMatthias Ringwald l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 17261b8b8d05SMatthias Ringwald if (a_channel->con_handle != handle) continue; 17271b8b8d05SMatthias Ringwald if (a_channel->local_sig_id != sig_id) continue; 17281b8b8d05SMatthias Ringwald channel = a_channel; 17291b8b8d05SMatthias Ringwald break; 17301b8b8d05SMatthias Ringwald } 17311b8b8d05SMatthias Ringwald if (!channel) break; 17321b8b8d05SMatthias Ringwald 17331b8b8d05SMatthias Ringwald // cid + 0 17341b8b8d05SMatthias Ringwald result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+8); 17351b8b8d05SMatthias Ringwald if (result){ 17361b8b8d05SMatthias Ringwald channel->state = L2CAP_STATE_CLOSED; 17371b8b8d05SMatthias Ringwald // map l2cap connection response result to BTstack status enumeration 173844276248SMatthias Ringwald l2cap_emit_le_channel_opened(channel, result); 17391b8b8d05SMatthias Ringwald 17401b8b8d05SMatthias Ringwald // discard channel 174163f0ac45SMatthias Ringwald btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel); 17421b8b8d05SMatthias Ringwald btstack_memory_l2cap_channel_free(channel); 17431b8b8d05SMatthias Ringwald break; 17441b8b8d05SMatthias Ringwald } 17451b8b8d05SMatthias Ringwald 17461b8b8d05SMatthias Ringwald // success 17471b8b8d05SMatthias Ringwald channel->remote_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0); 17481b8b8d05SMatthias Ringwald channel->remote_mtu = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 2); 17491b8b8d05SMatthias Ringwald channel->remote_mps = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 4); 17501b8b8d05SMatthias Ringwald channel->credits_outgoing = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 6); 17511b8b8d05SMatthias Ringwald channel->state = L2CAP_STATE_OPEN; 175244276248SMatthias Ringwald l2cap_emit_le_channel_opened(channel, result); 17531b8b8d05SMatthias Ringwald break; 17541b8b8d05SMatthias Ringwald 175585aeef60SMatthias Ringwald case LE_FLOW_CONTROL_CREDIT: 175685aeef60SMatthias Ringwald // find channel 175785aeef60SMatthias Ringwald local_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0); 175885aeef60SMatthias Ringwald channel = l2cap_le_get_channel_for_local_cid(local_cid); 175963f0ac45SMatthias Ringwald if (!channel) { 176063f0ac45SMatthias Ringwald log_error("l2cap: no channel for cid 0x%02x", local_cid); 176163f0ac45SMatthias Ringwald break; 176263f0ac45SMatthias Ringwald } 176363f0ac45SMatthias Ringwald new_credits = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 2); 176463f0ac45SMatthias Ringwald credits_before = channel->credits_outgoing; 176563f0ac45SMatthias Ringwald channel->credits_outgoing += new_credits; 176663f0ac45SMatthias Ringwald // check for credit overrun 176763f0ac45SMatthias Ringwald if (credits_before > channel->credits_outgoing){ 176863f0ac45SMatthias Ringwald log_error("l2cap: new credits caused overrrun for cid 0x%02x, disconnecting", local_cid); 176963f0ac45SMatthias Ringwald channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; 177063f0ac45SMatthias Ringwald break; 177163f0ac45SMatthias Ringwald } 177263f0ac45SMatthias Ringwald log_info("l2cap: %u credits for 0x%02x, now %u", new_credits, local_cid, channel->credits_outgoing); 177385aeef60SMatthias Ringwald break; 177485aeef60SMatthias Ringwald 1775828a7f7aSMatthias Ringwald case DISCONNECTION_REQUEST: 1776828a7f7aSMatthias Ringwald // find channel 1777828a7f7aSMatthias Ringwald local_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0); 1778828a7f7aSMatthias Ringwald channel = l2cap_le_get_channel_for_local_cid(local_cid); 177963f34e00SMatthias Ringwald if (!channel) { 178063f34e00SMatthias Ringwald log_error("l2cap: no channel for cid 0x%02x", local_cid); 178163f34e00SMatthias Ringwald break; 178263f34e00SMatthias Ringwald } 1783828a7f7aSMatthias Ringwald channel->remote_sig_id = sig_id; 1784828a7f7aSMatthias Ringwald channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE; 1785828a7f7aSMatthias Ringwald break; 1786828a7f7aSMatthias Ringwald 1787*a3dc965aSMatthias Ringwald #endif 1788*a3dc965aSMatthias Ringwald 178963f0ac45SMatthias Ringwald case DISCONNECTION_RESPONSE: 179063f0ac45SMatthias Ringwald break; 179163f0ac45SMatthias Ringwald 1792c48b2a2cSMatthias Ringwald default: 1793c48b2a2cSMatthias Ringwald // command unknown -> reject command 1794c48b2a2cSMatthias Ringwald return 0; 1795ccf076adS[email protected] } 1796c48b2a2cSMatthias Ringwald return 1; 1797c48b2a2cSMatthias Ringwald } 1798e7d0c9aaSMatthias Ringwald #endif 1799c48b2a2cSMatthias Ringwald 1800c48b2a2cSMatthias Ringwald static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ){ 1801c48b2a2cSMatthias Ringwald 1802c48b2a2cSMatthias Ringwald // Get Channel ID 1803c48b2a2cSMatthias Ringwald uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); 1804c48b2a2cSMatthias Ringwald hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet); 1805c48b2a2cSMatthias Ringwald 1806c48b2a2cSMatthias Ringwald switch (channel_id) { 1807c48b2a2cSMatthias Ringwald 1808c48b2a2cSMatthias Ringwald case L2CAP_CID_SIGNALING: { 1809c48b2a2cSMatthias Ringwald uint16_t command_offset = 8; 1810c48b2a2cSMatthias Ringwald while (command_offset < size) { 1811c48b2a2cSMatthias Ringwald // handle signaling commands 1812c48b2a2cSMatthias Ringwald l2cap_signaling_handler_dispatch(handle, &packet[command_offset]); 1813c48b2a2cSMatthias Ringwald 1814c48b2a2cSMatthias Ringwald // increment command_offset 1815c48b2a2cSMatthias Ringwald command_offset += L2CAP_SIGNALING_COMMAND_DATA_OFFSET + little_endian_read_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET); 1816c48b2a2cSMatthias Ringwald } 1817c48b2a2cSMatthias Ringwald break; 1818c48b2a2cSMatthias Ringwald } 1819c48b2a2cSMatthias Ringwald 1820e7d0c9aaSMatthias Ringwald #ifdef ENABLE_BLE 1821e7d0c9aaSMatthias Ringwald case L2CAP_CID_SIGNALING_LE: { 1822e7d0c9aaSMatthias Ringwald uint16_t sig_id = packet[COMPLETE_L2CAP_HEADER + 1]; 1823e7d0c9aaSMatthias Ringwald int valid = l2cap_le_signaling_handler_dispatch(handle, &packet[COMPLETE_L2CAP_HEADER], sig_id); 1824c48b2a2cSMatthias Ringwald if (!valid){ 18251bbc0b23S[email protected] l2cap_register_signaling_response(handle, COMMAND_REJECT_LE, sig_id, L2CAP_REJ_CMD_UNKNOWN); 1826ccf076adS[email protected] } 1827ccf076adS[email protected] break; 1828e7d0c9aaSMatthias Ringwald } 1829e7d0c9aaSMatthias Ringwald #endif 1830c48b2a2cSMatthias Ringwald 1831c48b2a2cSMatthias Ringwald case L2CAP_CID_ATTRIBUTE_PROTOCOL: 1832c48b2a2cSMatthias Ringwald if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL].callback) { 1833c48b2a2cSMatthias Ringwald (*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL].callback)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); 1834ccf076adS[email protected] } 1835c48b2a2cSMatthias Ringwald break; 1836c48b2a2cSMatthias Ringwald 1837c48b2a2cSMatthias Ringwald case L2CAP_CID_SECURITY_MANAGER_PROTOCOL: 1838c48b2a2cSMatthias Ringwald if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL].callback) { 1839c48b2a2cSMatthias Ringwald (*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL].callback)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); 1840c48b2a2cSMatthias Ringwald } 1841c48b2a2cSMatthias Ringwald break; 1842c48b2a2cSMatthias Ringwald 1843c48b2a2cSMatthias Ringwald case L2CAP_CID_CONNECTIONLESS_CHANNEL: 1844c48b2a2cSMatthias Ringwald if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL].callback) { 1845c48b2a2cSMatthias Ringwald (*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL].callback)(UCD_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); 1846c48b2a2cSMatthias Ringwald } 1847c48b2a2cSMatthias Ringwald break; 18481bbc0b23S[email protected] 18495652b5ffS[email protected] default: { 185000d93d79Smatthias.ringwald // Find channel for this channel_id and connection handle 185164e11ca9SMatthias Ringwald l2cap_channel_t * l2cap_channel; 185264e11ca9SMatthias Ringwald l2cap_channel = l2cap_get_channel_for_local_cid(channel_id); 1853d1fd2a88SMatthias Ringwald if (l2cap_channel) { 18543d50b4baSMatthias Ringwald l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); 185500d93d79Smatthias.ringwald } 1856*a3dc965aSMatthias Ringwald 1857*a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 185864e11ca9SMatthias Ringwald l2cap_channel = l2cap_le_get_channel_for_local_cid(channel_id); 185964e11ca9SMatthias Ringwald if (l2cap_channel) { 186085aeef60SMatthias Ringwald // credit counting 186185aeef60SMatthias Ringwald if (l2cap_channel->credits_incoming == 0){ 186285aeef60SMatthias Ringwald log_error("LE Data Channel packet received but no incoming credits"); 186385aeef60SMatthias Ringwald l2cap_channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; 186485aeef60SMatthias Ringwald break; 186585aeef60SMatthias Ringwald } 186685aeef60SMatthias Ringwald l2cap_channel->credits_incoming--; 186785aeef60SMatthias Ringwald 186885aeef60SMatthias Ringwald // automatic credits 186985aeef60SMatthias Ringwald if (l2cap_channel->credits_incoming < L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_WATERMARK && l2cap_channel->automatic_credits){ 187085aeef60SMatthias Ringwald l2cap_channel->new_credits_incoming = L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_INCREMENT; 187185aeef60SMatthias Ringwald } 187285aeef60SMatthias Ringwald 1873cd529728SMatthias Ringwald // first fragment 1874cd529728SMatthias Ringwald uint16_t pos = 0; 1875cd529728SMatthias Ringwald if (!l2cap_channel->receive_sdu_len){ 1876cd529728SMatthias Ringwald l2cap_channel->receive_sdu_len = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER); 1877cd529728SMatthias Ringwald l2cap_channel->receive_sdu_pos = 0; 1878cd529728SMatthias Ringwald pos += 2; 1879cd529728SMatthias Ringwald size -= 2; 1880cd529728SMatthias Ringwald } 1881cd529728SMatthias Ringwald memcpy(&l2cap_channel->receive_sdu_buffer[l2cap_channel->receive_sdu_pos], &packet[COMPLETE_L2CAP_HEADER+pos], size-COMPLETE_L2CAP_HEADER); 1882cd529728SMatthias Ringwald l2cap_channel->receive_sdu_pos += size - COMPLETE_L2CAP_HEADER; 1883cd529728SMatthias Ringwald // done? 188463f0ac45SMatthias Ringwald log_info("le packet pos %u, len %u", l2cap_channel->receive_sdu_pos, l2cap_channel->receive_sdu_len); 1885cd529728SMatthias Ringwald if (l2cap_channel->receive_sdu_pos >= l2cap_channel->receive_sdu_len){ 1886cd529728SMatthias Ringwald l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, l2cap_channel->receive_sdu_buffer, l2cap_channel->receive_sdu_len); 1887cd529728SMatthias Ringwald l2cap_channel->receive_sdu_len = 0; 1888cd529728SMatthias Ringwald } 188963f0ac45SMatthias Ringwald } else { 189063f0ac45SMatthias Ringwald log_error("LE Data Channel packet received but no channel found for cid 0x%02x", channel_id); 189164e11ca9SMatthias Ringwald } 189264e11ca9SMatthias Ringwald #endif 18935652b5ffS[email protected] break; 18945652b5ffS[email protected] } 18955652b5ffS[email protected] } 189600d93d79Smatthias.ringwald 18971eb2563eS[email protected] l2cap_run(); 18982718e2e7Smatthias.ringwald } 189900d93d79Smatthias.ringwald 190015ec09bbSmatthias.ringwald // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE 190127a923d0Smatthias.ringwald void l2cap_finialize_channel_close(l2cap_channel_t * channel){ 1902f62db1e3Smatthias.ringwald channel->state = L2CAP_STATE_CLOSED; 1903f62db1e3Smatthias.ringwald l2cap_emit_channel_closed(channel); 1904f62db1e3Smatthias.ringwald // discard channel 19059dcb2fb2S[email protected] l2cap_stop_rtx(channel); 1906665d90f2SMatthias Ringwald btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel); 1907d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 1908c8e4258aSmatthias.ringwald } 19091e6aba47Smatthias.ringwald 19108f2a52f4SMatthias Ringwald static l2cap_service_t * l2cap_get_service_internal(btstack_linked_list_t * services, uint16_t psm){ 1911665d90f2SMatthias Ringwald btstack_linked_list_iterator_t it; 1912665d90f2SMatthias Ringwald btstack_linked_list_iterator_init(&it, services); 1913665d90f2SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1914665d90f2SMatthias Ringwald l2cap_service_t * service = (l2cap_service_t *) btstack_linked_list_iterator_next(&it); 19159d9bbc01Smatthias.ringwald if ( service->psm == psm){ 19169d9bbc01Smatthias.ringwald return service; 19179d9bbc01Smatthias.ringwald }; 19189d9bbc01Smatthias.ringwald } 19199d9bbc01Smatthias.ringwald return NULL; 19209d9bbc01Smatthias.ringwald } 19219d9bbc01Smatthias.ringwald 19227192e786SMatthias Ringwald static inline l2cap_service_t * l2cap_get_service(uint16_t psm){ 19237192e786SMatthias Ringwald return l2cap_get_service_internal(&l2cap_services, psm); 19247192e786SMatthias Ringwald } 19257192e786SMatthias Ringwald 1926e0abb8e7S[email protected] 1927be2053a6SMatthias Ringwald uint8_t l2cap_register_service(btstack_packet_handler_t service_packet_handler, uint16_t psm, uint16_t mtu, gap_security_level_t security_level){ 1928be2053a6SMatthias Ringwald 1929be2053a6SMatthias Ringwald log_info("L2CAP_REGISTER_SERVICE psm 0x%x mtu %u", psm, mtu); 1930e0abb8e7S[email protected] 19314bb582b6Smatthias.ringwald // check for alread registered psm 19329d9bbc01Smatthias.ringwald l2cap_service_t *service = l2cap_get_service(psm); 1933277abc2cSmatthias.ringwald if (service) { 1934be2053a6SMatthias Ringwald log_error("l2cap_register_service: PSM %u already registered", psm); 1935be2053a6SMatthias Ringwald return L2CAP_SERVICE_ALREADY_REGISTERED; 1936277abc2cSmatthias.ringwald } 19379d9bbc01Smatthias.ringwald 19384bb582b6Smatthias.ringwald // alloc structure 1939bb69aaaeS[email protected] service = btstack_memory_l2cap_service_get(); 1940277abc2cSmatthias.ringwald if (!service) { 1941be2053a6SMatthias Ringwald log_error("l2cap_register_service: no memory for l2cap_service_t"); 1942be2053a6SMatthias Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 1943277abc2cSmatthias.ringwald } 19449d9bbc01Smatthias.ringwald 19459d9bbc01Smatthias.ringwald // fill in 19469d9bbc01Smatthias.ringwald service->psm = psm; 19479d9bbc01Smatthias.ringwald service->mtu = mtu; 194805ae8de3SMatthias Ringwald service->packet_handler = service_packet_handler; 1949df3354fcS[email protected] service->required_security_level = security_level; 19509d9bbc01Smatthias.ringwald 19519d9bbc01Smatthias.ringwald // add to services list 1952665d90f2SMatthias Ringwald btstack_linked_list_add(&l2cap_services, (btstack_linked_item_t *) service); 1953c0e866bfSmatthias.ringwald 1954c0e866bfSmatthias.ringwald // enable page scan 195515a95bd5SMatthias Ringwald gap_connectable_control(1); 19565842b6d9Smatthias.ringwald 1957be2053a6SMatthias Ringwald return 0; 19589d9bbc01Smatthias.ringwald } 19599d9bbc01Smatthias.ringwald 19607e8856ebSMatthias Ringwald uint8_t l2cap_unregister_service(uint16_t psm){ 1961e0abb8e7S[email protected] 1962e0abb8e7S[email protected] log_info("L2CAP_UNREGISTER_SERVICE psm 0x%x", psm); 1963e0abb8e7S[email protected] 19649d9bbc01Smatthias.ringwald l2cap_service_t *service = l2cap_get_service(psm); 19657e8856ebSMatthias Ringwald if (!service) return L2CAP_SERVICE_DOES_NOT_EXIST; 1966665d90f2SMatthias Ringwald btstack_linked_list_remove(&l2cap_services, (btstack_linked_item_t *) service); 1967d3a9df87Smatthias.ringwald btstack_memory_l2cap_service_free(service); 1968c0e866bfSmatthias.ringwald 1969c0e866bfSmatthias.ringwald // disable page scan when no services registered 19707e8856ebSMatthias Ringwald if (btstack_linked_list_empty(&l2cap_services)) { 197115a95bd5SMatthias Ringwald gap_connectable_control(0); 19729d9bbc01Smatthias.ringwald } 19737e8856ebSMatthias Ringwald return 0; 19747e8856ebSMatthias Ringwald } 19759d9bbc01Smatthias.ringwald 19765652b5ffS[email protected] // Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol 197705ae8de3SMatthias Ringwald void l2cap_register_fixed_channel(btstack_packet_handler_t the_packet_handler, uint16_t channel_id) { 19785628cf69SMatthias Ringwald int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id); 19795628cf69SMatthias Ringwald if (index < 0) return; 19805628cf69SMatthias Ringwald fixed_channels[index].callback = the_packet_handler; 19815652b5ffS[email protected] } 19825652b5ffS[email protected] 1983a9a4c409SMatthias Ringwald #ifdef ENABLE_BLE 19847192e786SMatthias Ringwald 1985cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS 198683fd9c76SMatthias Ringwald 198757be49d6SMatthias Ringwald static void l2cap_le_notify_channel_can_send(l2cap_channel_t *channel){ 198857be49d6SMatthias Ringwald if (!channel->waiting_for_can_send_now) return; 198957be49d6SMatthias Ringwald if (channel->send_sdu_buffer) return; 199057be49d6SMatthias Ringwald channel->waiting_for_can_send_now = 0; 199157be49d6SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_LE_CAN_SEND_NOW local_cid 0x%x", channel->local_cid); 199257be49d6SMatthias Ringwald l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_CAN_SEND_NOW); 199357be49d6SMatthias Ringwald } 199457be49d6SMatthias Ringwald 199557be49d6SMatthias Ringwald // 1BH2222 199657be49d6SMatthias Ringwald static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel) { 199757be49d6SMatthias Ringwald log_info("L2CAP_EVENT_LE_INCOMING_CONNECTION addr_type %u, addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x, remote_mtu %u", 199857be49d6SMatthias Ringwald channel->address_type, bd_addr_to_str(channel->address), channel->con_handle, channel->psm, channel->local_cid, channel->remote_cid, channel->remote_mtu); 199957be49d6SMatthias Ringwald uint8_t event[19]; 200057be49d6SMatthias Ringwald event[0] = L2CAP_EVENT_LE_INCOMING_CONNECTION; 200157be49d6SMatthias Ringwald event[1] = sizeof(event) - 2; 200257be49d6SMatthias Ringwald event[2] = channel->address_type; 200357be49d6SMatthias Ringwald reverse_bd_addr(channel->address, &event[3]); 200457be49d6SMatthias Ringwald little_endian_store_16(event, 9, channel->con_handle); 200557be49d6SMatthias Ringwald little_endian_store_16(event, 11, channel->psm); 200657be49d6SMatthias Ringwald little_endian_store_16(event, 13, channel->local_cid); 200757be49d6SMatthias Ringwald little_endian_store_16(event, 15, channel->remote_cid); 200857be49d6SMatthias Ringwald little_endian_store_16(event, 17, channel->remote_mtu); 200957be49d6SMatthias Ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 201057be49d6SMatthias Ringwald l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event)); 201157be49d6SMatthias Ringwald } 201257be49d6SMatthias Ringwald // 11BH22222 201357be49d6SMatthias Ringwald static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status) { 201457be49d6SMatthias Ringwald log_info("L2CAP_EVENT_LE_CHANNEL_OPENED status 0x%x addr_type %u addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x local_mtu %u, remote_mtu %u", 201557be49d6SMatthias Ringwald status, channel->address_type, bd_addr_to_str(channel->address), channel->con_handle, channel->psm, 201657be49d6SMatthias Ringwald channel->local_cid, channel->remote_cid, channel->local_mtu, channel->remote_mtu); 2017c99bb618SMatthias Ringwald uint8_t event[23]; 201857be49d6SMatthias Ringwald event[0] = L2CAP_EVENT_LE_CHANNEL_OPENED; 201957be49d6SMatthias Ringwald event[1] = sizeof(event) - 2; 202057be49d6SMatthias Ringwald event[2] = status; 202157be49d6SMatthias Ringwald event[3] = channel->address_type; 202257be49d6SMatthias Ringwald reverse_bd_addr(channel->address, &event[4]); 202357be49d6SMatthias Ringwald little_endian_store_16(event, 10, channel->con_handle); 2024c99bb618SMatthias Ringwald event[12] = channel->state_var & L2CAP_CHANNEL_STATE_VAR_INCOMING ? 1 : 0; 2025c99bb618SMatthias Ringwald little_endian_store_16(event, 13, channel->psm); 2026c99bb618SMatthias Ringwald little_endian_store_16(event, 15, channel->local_cid); 2027c99bb618SMatthias Ringwald little_endian_store_16(event, 17, channel->remote_cid); 2028c99bb618SMatthias Ringwald little_endian_store_16(event, 19, channel->local_mtu); 2029c99bb618SMatthias Ringwald little_endian_store_16(event, 21, channel->remote_mtu); 203057be49d6SMatthias Ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 203157be49d6SMatthias Ringwald l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event)); 203257be49d6SMatthias Ringwald } 203357be49d6SMatthias Ringwald 203457be49d6SMatthias Ringwald static l2cap_channel_t * l2cap_le_get_channel_for_local_cid(uint16_t local_cid){ 203557be49d6SMatthias Ringwald btstack_linked_list_iterator_t it; 203657be49d6SMatthias Ringwald btstack_linked_list_iterator_init(&it, &l2cap_le_channels); 203757be49d6SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 203857be49d6SMatthias Ringwald l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it); 203957be49d6SMatthias Ringwald if ( channel->local_cid == local_cid) { 204057be49d6SMatthias Ringwald return channel; 204157be49d6SMatthias Ringwald } 204257be49d6SMatthias Ringwald } 204357be49d6SMatthias Ringwald return NULL; 204457be49d6SMatthias Ringwald } 204557be49d6SMatthias Ringwald 204657be49d6SMatthias Ringwald // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE 204757be49d6SMatthias Ringwald void l2cap_le_finialize_channel_close(l2cap_channel_t * channel){ 204857be49d6SMatthias Ringwald channel->state = L2CAP_STATE_CLOSED; 204957be49d6SMatthias Ringwald l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED); 205057be49d6SMatthias Ringwald // discard channel 205157be49d6SMatthias Ringwald btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel); 205257be49d6SMatthias Ringwald btstack_memory_l2cap_channel_free(channel); 205357be49d6SMatthias Ringwald } 205457be49d6SMatthias Ringwald 2055e7d0c9aaSMatthias Ringwald static inline l2cap_service_t * l2cap_le_get_service(uint16_t le_psm){ 2056e7d0c9aaSMatthias Ringwald return l2cap_get_service_internal(&l2cap_le_services, le_psm); 20577192e786SMatthias Ringwald } 2058efedfb4cSMatthias Ringwald 2059da144af5SMatthias Ringwald uint8_t l2cap_le_register_service(btstack_packet_handler_t packet_handler, uint16_t psm, gap_security_level_t security_level){ 20607192e786SMatthias Ringwald 2061da144af5SMatthias Ringwald log_info("L2CAP_LE_REGISTER_SERVICE psm 0x%x", psm); 20627192e786SMatthias Ringwald 20637192e786SMatthias Ringwald // check for alread registered psm 20647192e786SMatthias Ringwald l2cap_service_t *service = l2cap_le_get_service(psm); 20657192e786SMatthias Ringwald if (service) { 2066da144af5SMatthias Ringwald return L2CAP_SERVICE_ALREADY_REGISTERED; 20677192e786SMatthias Ringwald } 20687192e786SMatthias Ringwald 20697192e786SMatthias Ringwald // alloc structure 20707192e786SMatthias Ringwald service = btstack_memory_l2cap_service_get(); 20717192e786SMatthias Ringwald if (!service) { 20727192e786SMatthias Ringwald log_error("l2cap_register_service_internal: no memory for l2cap_service_t"); 2073da144af5SMatthias Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 20747192e786SMatthias Ringwald } 20757192e786SMatthias Ringwald 20767192e786SMatthias Ringwald // fill in 20777192e786SMatthias Ringwald service->psm = psm; 2078da144af5SMatthias Ringwald service->mtu = 0; 20797192e786SMatthias Ringwald service->packet_handler = packet_handler; 20807192e786SMatthias Ringwald service->required_security_level = security_level; 20817192e786SMatthias Ringwald 20827192e786SMatthias Ringwald // add to services list 2083665d90f2SMatthias Ringwald btstack_linked_list_add(&l2cap_le_services, (btstack_linked_item_t *) service); 20847192e786SMatthias Ringwald 20857192e786SMatthias Ringwald // done 2086da144af5SMatthias Ringwald return 0; 20877192e786SMatthias Ringwald } 20887192e786SMatthias Ringwald 2089da144af5SMatthias Ringwald uint8_t l2cap_le_unregister_service(uint16_t psm) { 20907192e786SMatthias Ringwald log_info("L2CAP_LE_UNREGISTER_SERVICE psm 0x%x", psm); 20917192e786SMatthias Ringwald l2cap_service_t *service = l2cap_le_get_service(psm); 20929367f9b0SMatthias Ringwald if (!service) return L2CAP_SERVICE_DOES_NOT_EXIST; 2093da144af5SMatthias Ringwald 2094665d90f2SMatthias Ringwald btstack_linked_list_remove(&l2cap_le_services, (btstack_linked_item_t *) service); 20957192e786SMatthias Ringwald btstack_memory_l2cap_service_free(service); 2096da144af5SMatthias Ringwald return 0; 20977192e786SMatthias Ringwald } 2098da144af5SMatthias Ringwald 2099da144af5SMatthias Ringwald uint8_t l2cap_le_accept_connection(uint16_t local_cid, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits){ 2100e7d0c9aaSMatthias Ringwald // get channel 2101e7d0c9aaSMatthias Ringwald l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid); 2102e7d0c9aaSMatthias Ringwald if (!channel) return L2CAP_LOCAL_CID_DOES_NOT_EXIST; 2103e7d0c9aaSMatthias Ringwald 2104e7d0c9aaSMatthias Ringwald // validate state 2105e7d0c9aaSMatthias Ringwald if (channel->state != L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT){ 2106e7d0c9aaSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2107e7d0c9aaSMatthias Ringwald } 2108e7d0c9aaSMatthias Ringwald 2109efedfb4cSMatthias Ringwald // set state accept connection 211023017473SMatthias Ringwald channel->state = L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_ACCEPT; 211123017473SMatthias Ringwald channel->receive_sdu_buffer = receive_sdu_buffer; 211223017473SMatthias Ringwald channel->local_mtu = mtu; 211385aeef60SMatthias Ringwald channel->new_credits_incoming = initial_credits; 211485aeef60SMatthias Ringwald channel->automatic_credits = initial_credits == L2CAP_LE_AUTOMATIC_CREDITS; 211585aeef60SMatthias Ringwald 211685aeef60SMatthias Ringwald // test 211763f0ac45SMatthias Ringwald // channel->new_credits_incoming = 1; 2118e7d0c9aaSMatthias Ringwald 2119e7d0c9aaSMatthias Ringwald // go 2120e7d0c9aaSMatthias Ringwald l2cap_run(); 2121da144af5SMatthias Ringwald return 0; 2122da144af5SMatthias Ringwald } 2123da144af5SMatthias Ringwald 2124da144af5SMatthias Ringwald /** 2125da144af5SMatthias Ringwald * @brief Deny incoming LE Data Channel connection due to resource constraints 2126da144af5SMatthias Ringwald * @param local_cid L2CAP LE Data Channel Identifier 2127da144af5SMatthias Ringwald */ 2128da144af5SMatthias Ringwald 2129da144af5SMatthias Ringwald uint8_t l2cap_le_decline_connection(uint16_t local_cid){ 2130e7d0c9aaSMatthias Ringwald // get channel 2131e7d0c9aaSMatthias Ringwald l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid); 2132e7d0c9aaSMatthias Ringwald if (!channel) return L2CAP_LOCAL_CID_DOES_NOT_EXIST; 2133e7d0c9aaSMatthias Ringwald 2134e7d0c9aaSMatthias Ringwald // validate state 2135e7d0c9aaSMatthias Ringwald if (channel->state != L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT){ 2136e7d0c9aaSMatthias Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2137e7d0c9aaSMatthias Ringwald } 2138e7d0c9aaSMatthias Ringwald 2139efedfb4cSMatthias Ringwald // set state decline connection 2140e7d0c9aaSMatthias Ringwald channel->state = L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE; 2141e7d0c9aaSMatthias Ringwald channel->reason = 0x04; // no resources available 2142e7d0c9aaSMatthias Ringwald l2cap_run(); 2143da144af5SMatthias Ringwald return 0; 2144da144af5SMatthias Ringwald } 2145da144af5SMatthias Ringwald 21467dafa750SMatthias Ringwald uint8_t l2cap_le_create_channel(btstack_packet_handler_t packet_handler, hci_con_handle_t con_handle, 2147da144af5SMatthias Ringwald uint16_t psm, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits, gap_security_level_t security_level, 2148efedfb4cSMatthias Ringwald uint16_t * out_local_cid) { 2149efedfb4cSMatthias Ringwald 21507dafa750SMatthias Ringwald log_info("L2CAP_LE_CREATE_CHANNEL handle 0x%04x psm 0x%x mtu %u", con_handle, psm, mtu); 2151da144af5SMatthias Ringwald 21527dafa750SMatthias Ringwald 21537dafa750SMatthias Ringwald hci_connection_t * connection = hci_connection_for_handle(con_handle); 21547dafa750SMatthias Ringwald if (!connection) { 21557dafa750SMatthias Ringwald log_error("no hci_connection for handle 0x%04x", con_handle); 21567dafa750SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 21577dafa750SMatthias Ringwald } 21587dafa750SMatthias Ringwald 21597dafa750SMatthias Ringwald l2cap_channel_t * channel = l2cap_create_channel_entry(packet_handler, connection->address, connection->address_type, psm, mtu, security_level); 2160da144af5SMatthias Ringwald if (!channel) { 2161da144af5SMatthias Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 2162da144af5SMatthias Ringwald } 2163e7d0c9aaSMatthias Ringwald log_info("l2cap_le_create_channel %p", channel); 2164da144af5SMatthias Ringwald 2165da144af5SMatthias Ringwald // store local_cid 2166da144af5SMatthias Ringwald if (out_local_cid){ 2167da144af5SMatthias Ringwald *out_local_cid = channel->local_cid; 2168da144af5SMatthias Ringwald } 2169da144af5SMatthias Ringwald 21707dafa750SMatthias Ringwald // provide buffer 21717dafa750SMatthias Ringwald channel->con_handle = con_handle; 2172cd529728SMatthias Ringwald channel->receive_sdu_buffer = receive_sdu_buffer; 21737dafa750SMatthias Ringwald channel->state = L2CAP_STATE_WILL_SEND_LE_CONNECTION_REQUEST; 217485aeef60SMatthias Ringwald channel->new_credits_incoming = initial_credits; 217585aeef60SMatthias Ringwald channel->automatic_credits = initial_credits == L2CAP_LE_AUTOMATIC_CREDITS; 217685aeef60SMatthias Ringwald 2177efedfb4cSMatthias Ringwald // add to connections list 2178efedfb4cSMatthias Ringwald btstack_linked_list_add(&l2cap_le_channels, (btstack_linked_item_t *) channel); 2179efedfb4cSMatthias Ringwald 21807dafa750SMatthias Ringwald // go 218163f0ac45SMatthias Ringwald l2cap_run(); 2182da144af5SMatthias Ringwald return 0; 2183da144af5SMatthias Ringwald } 2184da144af5SMatthias Ringwald 2185da144af5SMatthias Ringwald /** 2186da144af5SMatthias Ringwald * @brief Provide credtis for LE Data Channel 2187da144af5SMatthias Ringwald * @param local_cid L2CAP LE Data Channel Identifier 2188da144af5SMatthias Ringwald * @param credits Number additional credits for peer 2189da144af5SMatthias Ringwald */ 219064e11ca9SMatthias Ringwald uint8_t l2cap_le_provide_credits(uint16_t local_cid, uint16_t credits){ 219163f0ac45SMatthias Ringwald 219263f0ac45SMatthias Ringwald l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid); 219363f0ac45SMatthias Ringwald if (!channel) { 219463f0ac45SMatthias Ringwald log_error("l2cap_le_provide_credits no channel for cid 0x%02x", local_cid); 219563f0ac45SMatthias Ringwald return L2CAP_LOCAL_CID_DOES_NOT_EXIST; 219663f0ac45SMatthias Ringwald } 219763f0ac45SMatthias Ringwald 2198efedfb4cSMatthias Ringwald // check state 219963f0ac45SMatthias Ringwald if (channel->state != L2CAP_STATE_OPEN){ 220063f0ac45SMatthias Ringwald log_error("l2cap_le_provide_credits but channel 0x%02x not open yet", local_cid); 220163f0ac45SMatthias Ringwald } 220263f0ac45SMatthias Ringwald 220363f0ac45SMatthias Ringwald // assert incoming credits + credits <= 0xffff 220463f0ac45SMatthias Ringwald uint32_t total_credits = channel->credits_incoming; 220563f0ac45SMatthias Ringwald total_credits += channel->new_credits_incoming; 220663f0ac45SMatthias Ringwald total_credits += credits; 220763f0ac45SMatthias Ringwald if (total_credits > 0xffff){ 220863f0ac45SMatthias Ringwald log_error("l2cap_le_provide_credits overrun: current %u, scheduled %u, additional %u", channel->credits_incoming, 220963f0ac45SMatthias Ringwald channel->new_credits_incoming, credits); 221063f0ac45SMatthias Ringwald } 221163f0ac45SMatthias Ringwald 2212efedfb4cSMatthias Ringwald // set credits_granted 221363f0ac45SMatthias Ringwald channel->new_credits_incoming += credits; 221463f0ac45SMatthias Ringwald 221563f0ac45SMatthias Ringwald // go 221663f0ac45SMatthias Ringwald l2cap_run(); 2217da144af5SMatthias Ringwald return 0; 2218da144af5SMatthias Ringwald } 2219da144af5SMatthias Ringwald 2220da144af5SMatthias Ringwald /** 2221da144af5SMatthias Ringwald * @brief Check if outgoing buffer is available and that there's space on the Bluetooth module 2222da144af5SMatthias Ringwald * @param local_cid L2CAP LE Data Channel Identifier 2223da144af5SMatthias Ringwald */ 222464e11ca9SMatthias Ringwald int l2cap_le_can_send_now(uint16_t local_cid){ 222544276248SMatthias Ringwald l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid); 222644276248SMatthias Ringwald if (!channel) { 222744276248SMatthias Ringwald log_error("l2cap_le_provide_credits no channel for cid 0x%02x", local_cid); 2228da144af5SMatthias Ringwald return 0; 2229da144af5SMatthias Ringwald } 2230da144af5SMatthias Ringwald 223144276248SMatthias Ringwald // check state 223244276248SMatthias Ringwald if (channel->state != L2CAP_STATE_OPEN) return 0; 223344276248SMatthias Ringwald 223444276248SMatthias Ringwald // check queue 223544276248SMatthias Ringwald if (channel->send_sdu_buffer) return 0; 223644276248SMatthias Ringwald 223744276248SMatthias Ringwald // fine, go ahead 223844276248SMatthias Ringwald return 1; 223944276248SMatthias Ringwald } 224044276248SMatthias Ringwald 2241da144af5SMatthias Ringwald /** 2242da144af5SMatthias Ringwald * @brief Request emission of L2CAP_EVENT_CAN_SEND_NOW as soon as possible 2243da144af5SMatthias Ringwald * @note L2CAP_EVENT_CAN_SEND_NOW might be emitted during call to this function 2244da144af5SMatthias Ringwald * so packet handler should be ready to handle it 2245da144af5SMatthias Ringwald * @param local_cid L2CAP LE Data Channel Identifier 2246da144af5SMatthias Ringwald */ 224764e11ca9SMatthias Ringwald uint8_t l2cap_le_request_can_send_now_event(uint16_t local_cid){ 224844276248SMatthias Ringwald l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid); 224944276248SMatthias Ringwald if (!channel) { 225044276248SMatthias Ringwald log_error("l2cap_le_request_can_send_now_event no channel for cid 0x%02x", local_cid); 225144276248SMatthias Ringwald return 0; 225244276248SMatthias Ringwald } 225344276248SMatthias Ringwald channel->waiting_for_can_send_now = 1; 225444276248SMatthias Ringwald l2cap_le_notify_channel_can_send(channel); 2255da144af5SMatthias Ringwald return 0; 2256da144af5SMatthias Ringwald } 2257da144af5SMatthias Ringwald 2258da144af5SMatthias Ringwald /** 2259da144af5SMatthias Ringwald * @brief Send data via LE Data Channel 2260da144af5SMatthias Ringwald * @note Since data larger then the maximum PDU needs to be segmented into multiple PDUs, data needs to stay valid until ... event 2261da144af5SMatthias Ringwald * @param local_cid L2CAP LE Data Channel Identifier 2262da144af5SMatthias Ringwald * @param data data to send 2263da144af5SMatthias Ringwald * @param size data size 2264da144af5SMatthias Ringwald */ 226564e11ca9SMatthias Ringwald uint8_t l2cap_le_send_data(uint16_t local_cid, uint8_t * data, uint16_t len){ 226664e11ca9SMatthias Ringwald 226764e11ca9SMatthias Ringwald l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid); 226864e11ca9SMatthias Ringwald if (!channel) { 226964e11ca9SMatthias Ringwald log_error("l2cap_send no channel for cid 0x%02x", local_cid); 2270828a7f7aSMatthias Ringwald return L2CAP_LOCAL_CID_DOES_NOT_EXIST; 227164e11ca9SMatthias Ringwald } 227264e11ca9SMatthias Ringwald 227364e11ca9SMatthias Ringwald if (len > channel->remote_mtu){ 227464e11ca9SMatthias Ringwald log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", local_cid); 227564e11ca9SMatthias Ringwald return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU; 227664e11ca9SMatthias Ringwald } 227764e11ca9SMatthias Ringwald 22787f107edaSMatthias Ringwald if (channel->send_sdu_buffer){ 227964e11ca9SMatthias Ringwald log_info("l2cap_send cid 0x%02x, cannot send", local_cid); 228064e11ca9SMatthias Ringwald return BTSTACK_ACL_BUFFERS_FULL; 228164e11ca9SMatthias Ringwald } 228264e11ca9SMatthias Ringwald 22837f107edaSMatthias Ringwald channel->send_sdu_buffer = data; 22847f107edaSMatthias Ringwald channel->send_sdu_len = len; 22857f107edaSMatthias Ringwald channel->send_sdu_pos = 0; 228664e11ca9SMatthias Ringwald 22877f107edaSMatthias Ringwald l2cap_run(); 22887f107edaSMatthias Ringwald return 0; 2289da144af5SMatthias Ringwald } 2290da144af5SMatthias Ringwald 2291da144af5SMatthias Ringwald /** 2292da144af5SMatthias Ringwald * @brief Disconnect from LE Data Channel 2293da144af5SMatthias Ringwald * @param local_cid L2CAP LE Data Channel Identifier 2294da144af5SMatthias Ringwald */ 2295828a7f7aSMatthias Ringwald uint8_t l2cap_le_disconnect(uint16_t local_cid) 2296da144af5SMatthias Ringwald { 2297828a7f7aSMatthias Ringwald l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid); 2298828a7f7aSMatthias Ringwald if (!channel) { 2299828a7f7aSMatthias Ringwald log_error("l2cap_send no channel for cid 0x%02x", local_cid); 2300828a7f7aSMatthias Ringwald return L2CAP_LOCAL_CID_DOES_NOT_EXIST; 2301828a7f7aSMatthias Ringwald } 2302828a7f7aSMatthias Ringwald 2303828a7f7aSMatthias Ringwald channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; 2304828a7f7aSMatthias Ringwald l2cap_run(); 2305da144af5SMatthias Ringwald return 0; 2306da144af5SMatthias Ringwald } 2307da144af5SMatthias Ringwald 23087f02f414SMatthias Ringwald #endif 230983fd9c76SMatthias Ringwald 231083fd9c76SMatthias Ringwald #endif 2311