xref: /btstack/src/l2cap.c (revision bdbe2e4960ce52956c85f51a3bd00b3edcbcf273)
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 
38ab2c6ae4SMatthias Ringwald #define __BTSTACK_FILE__ "l2cap.c"
39ab2c6ae4SMatthias Ringwald 
401713bceaSmatthias.ringwald /*
4143625864Smatthias.ringwald  *  l2cap.c
4243625864Smatthias.ringwald  *
4343625864Smatthias.ringwald  *  Logical Link Control and Adaption Protocl (L2CAP)
4443625864Smatthias.ringwald  *
4543625864Smatthias.ringwald  *  Created by Matthias Ringwald on 5/16/09.
4643625864Smatthias.ringwald  */
4743625864Smatthias.ringwald 
4843625864Smatthias.ringwald #include "l2cap.h"
49645658c9Smatthias.ringwald #include "hci.h"
502b3c6c9bSmatthias.ringwald #include "hci_dump.h"
51235946f1SMatthias Ringwald #include "bluetooth_sdp.h"
5216ece135SMatthias Ringwald #include "btstack_debug.h"
530e2df43fSMatthias Ringwald #include "btstack_event.h"
54d3a9df87Smatthias.ringwald #include "btstack_memory.h"
5543625864Smatthias.ringwald 
56cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
5783fd9c76SMatthias Ringwald #include "ble/sm.h"
5883fd9c76SMatthias Ringwald #endif
5983fd9c76SMatthias Ringwald 
6043625864Smatthias.ringwald #include <stdarg.h>
6143625864Smatthias.ringwald #include <string.h>
6243625864Smatthias.ringwald 
6343625864Smatthias.ringwald #include <stdio.h>
6443625864Smatthias.ringwald 
654c744e21Smatthias.ringwald // nr of buffered acl packets in outgoing queue to get max performance
664c744e21Smatthias.ringwald #define NR_BUFFERED_ACL_PACKETS 3
674c744e21Smatthias.ringwald 
6839bda6d5Smatthias.ringwald // used to cache l2cap rejects, echo, and informational requests
69e16a9cacSmatthias.ringwald #define NR_PENDING_SIGNALING_RESPONSES 3
7039bda6d5Smatthias.ringwald 
7185aeef60SMatthias Ringwald // nr of credits provided to remote if credits fall below watermark
7285aeef60SMatthias Ringwald #define L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_WATERMARK 5
7385aeef60SMatthias Ringwald #define L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_INCREMENT 5
7485aeef60SMatthias Ringwald 
7500d93d79Smatthias.ringwald // offsets for L2CAP SIGNALING COMMANDS
7600d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_CODE_OFFSET   0
7700d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_SIGID_OFFSET  1
7800d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2
7900d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_DATA_OFFSET   4
8000d93d79Smatthias.ringwald 
815628cf69SMatthias Ringwald // internal table
825628cf69SMatthias Ringwald #define L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL 0
835628cf69SMatthias Ringwald #define L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL  1
845628cf69SMatthias Ringwald #define L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL 2
855628cf69SMatthias Ringwald #define L2CAP_FIXED_CHANNEL_TABLE_SIZE (L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL+1)
865628cf69SMatthias Ringwald 
8709e9d05bSMatthias Ringwald #if defined(ENABLE_LE_DATA_CHANNELS) || defined(ENABLE_CLASSIC)
8809e9d05bSMatthias Ringwald #define L2CAP_USES_CHANNELS
8909e9d05bSMatthias Ringwald #endif
9009e9d05bSMatthias Ringwald 
9133c40538SMatthias Ringwald // prototypes
92675e6881SMatthias Ringwald static void l2cap_run(void);
9333c40538SMatthias Ringwald static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
943d50b4baSMatthias Ringwald static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size );
9530725612SMatthias Ringwald static void l2cap_notify_channel_can_send(void);
9609e9d05bSMatthias Ringwald static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel);
9709e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
9809e9d05bSMatthias Ringwald static void l2cap_finialize_channel_close(l2cap_channel_t *channel);
9909e9d05bSMatthias Ringwald static inline l2cap_service_t * l2cap_get_service(uint16_t psm);
10009e9d05bSMatthias Ringwald static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status);
10109e9d05bSMatthias Ringwald static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
10209e9d05bSMatthias Ringwald static void l2cap_emit_incoming_connection(l2cap_channel_t *channel);
10309e9d05bSMatthias Ringwald static int  l2cap_channel_ready_for_open(l2cap_channel_t *channel);
10409e9d05bSMatthias Ringwald #endif
105cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
10657be49d6SMatthias Ringwald static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status);
10757be49d6SMatthias Ringwald static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel);
10857be49d6SMatthias Ringwald static l2cap_channel_t * l2cap_le_get_channel_for_local_cid(uint16_t local_cid);
10944276248SMatthias Ringwald static void l2cap_le_notify_channel_can_send(l2cap_channel_t *channel);
110828a7f7aSMatthias Ringwald static void l2cap_le_finialize_channel_close(l2cap_channel_t *channel);
111e7d0c9aaSMatthias Ringwald static inline l2cap_service_t * l2cap_le_get_service(uint16_t psm);
112e7d0c9aaSMatthias Ringwald #endif
11333c40538SMatthias Ringwald 
1145628cf69SMatthias Ringwald typedef struct l2cap_fixed_channel {
1155628cf69SMatthias Ringwald     btstack_packet_handler_t callback;
1162125de09SMatthias Ringwald     uint8_t waiting_for_can_send_now;
1175628cf69SMatthias Ringwald } l2cap_fixed_channel_t;
1185628cf69SMatthias Ringwald 
11909e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1205628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_channels;
1215628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_services;
12209e9d05bSMatthias Ringwald static uint8_t require_security_level2_for_outgoing_sdp;
12309e9d05bSMatthias Ringwald #endif
12457be49d6SMatthias Ringwald 
12557be49d6SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
1265628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_le_channels;
1275628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_le_services;
12857be49d6SMatthias Ringwald #endif
12939bda6d5Smatthias.ringwald 
13039bda6d5Smatthias.ringwald // used to cache l2cap rejects, echo, and informational requests
1312b83fb7dSmatthias.ringwald static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES];
1322b83fb7dSmatthias.ringwald static int signaling_responses_pending;
1332b83fb7dSmatthias.ringwald 
134fb37a842SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
1355628cf69SMatthias Ringwald static l2cap_fixed_channel_t fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_SIZE];
13639bda6d5Smatthias.ringwald 
137d6ed9f9cSMatthias Ringwald #ifdef ENABLE_BLE
138d6ed9f9cSMatthias Ringwald // only used for connection parameter update events
139d6ed9f9cSMatthias Ringwald static btstack_packet_handler_t l2cap_event_packet_handler;
140d6ed9f9cSMatthias Ringwald #endif
141d6ed9f9cSMatthias Ringwald 
14285ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
14385ddcd84SMatthias Ringwald 
14485ddcd84SMatthias Ringwald /*
14585ddcd84SMatthias Ringwald  * CRC lookup table for generator polynom D^16 + D^15 + D^2 + 1
14685ddcd84SMatthias Ringwald  */
14785ddcd84SMatthias Ringwald static const uint16_t crc16_table[256] = {
14885ddcd84SMatthias Ringwald     0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
14985ddcd84SMatthias Ringwald     0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
15085ddcd84SMatthias Ringwald     0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
15185ddcd84SMatthias Ringwald     0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
15285ddcd84SMatthias Ringwald     0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
15385ddcd84SMatthias Ringwald     0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
15485ddcd84SMatthias Ringwald     0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
15585ddcd84SMatthias Ringwald     0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
15685ddcd84SMatthias Ringwald     0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
15785ddcd84SMatthias Ringwald     0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
15885ddcd84SMatthias Ringwald     0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
15985ddcd84SMatthias Ringwald     0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
16085ddcd84SMatthias Ringwald     0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
16185ddcd84SMatthias Ringwald     0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
16285ddcd84SMatthias Ringwald     0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
16385ddcd84SMatthias Ringwald     0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
16485ddcd84SMatthias Ringwald };
16585ddcd84SMatthias Ringwald 
16685ddcd84SMatthias Ringwald static uint16_t crc16_calc(uint8_t * data, uint16_t len){
16785ddcd84SMatthias Ringwald     uint16_t crc = 0;   // initial value = 0
16885ddcd84SMatthias Ringwald     while (len--){
16985ddcd84SMatthias Ringwald         crc = (crc >> 8) ^ crc16_table[ (crc ^ ((uint16_t) *data++)) & 0x00FF ];
17085ddcd84SMatthias Ringwald     }
17185ddcd84SMatthias Ringwald     return crc;
17285ddcd84SMatthias Ringwald }
17385ddcd84SMatthias Ringwald 
17485ddcd84SMatthias Ringwald #endif
17585ddcd84SMatthias Ringwald 
17685ddcd84SMatthias Ringwald 
17734e7e577SMatthias Ringwald static uint16_t l2cap_fixed_channel_table_channel_id_for_index(int index){
17834e7e577SMatthias Ringwald     switch (index){
17934e7e577SMatthias Ringwald         case L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL:
18034e7e577SMatthias Ringwald             return L2CAP_CID_ATTRIBUTE_PROTOCOL;
18134e7e577SMatthias Ringwald         case L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL:
18234e7e577SMatthias Ringwald             return L2CAP_CID_SECURITY_MANAGER_PROTOCOL;
18334e7e577SMatthias Ringwald         case L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL:
18434e7e577SMatthias Ringwald             return L2CAP_CID_CONNECTIONLESS_CHANNEL;
18534e7e577SMatthias Ringwald         default:
18634e7e577SMatthias Ringwald             return 0;
18734e7e577SMatthias Ringwald     }
18834e7e577SMatthias Ringwald }
1895628cf69SMatthias Ringwald static int l2cap_fixed_channel_table_index_for_channel_id(uint16_t channel_id){
1905628cf69SMatthias Ringwald     switch (channel_id){
1915628cf69SMatthias Ringwald         case L2CAP_CID_ATTRIBUTE_PROTOCOL:
1925628cf69SMatthias Ringwald             return L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL;
1935628cf69SMatthias Ringwald         case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
1945628cf69SMatthias Ringwald             return  L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL;
1955628cf69SMatthias Ringwald         case L2CAP_CID_CONNECTIONLESS_CHANNEL:
1965628cf69SMatthias Ringwald             return  L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL;
1975628cf69SMatthias Ringwald         default:
1985628cf69SMatthias Ringwald             return -1;
1995628cf69SMatthias Ringwald         }
2005628cf69SMatthias Ringwald }
20139bda6d5Smatthias.ringwald 
20234e7e577SMatthias Ringwald static int l2cap_fixed_channel_table_index_is_le(int index){
20334e7e577SMatthias Ringwald     if (index == L2CAP_CID_CONNECTIONLESS_CHANNEL) return 0;
20434e7e577SMatthias Ringwald     return 1;
20534e7e577SMatthias Ringwald }
20634e7e577SMatthias Ringwald 
20771de195eSMatthias Ringwald void l2cap_init(void){
2082b83fb7dSmatthias.ringwald     signaling_responses_pending = 0;
209808a48abSmatthias.ringwald 
21085ddcd84SMatthias Ringwald     uint8_t test[] = {0x0E, 0x00, 0x40, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 };
21185ddcd84SMatthias Ringwald     printf("crc16: %04x\n", crc16_calc(test, sizeof(test)));
21285ddcd84SMatthias Ringwald 
21309e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
214f5454fc6Smatthias.ringwald     l2cap_channels = NULL;
215f5454fc6Smatthias.ringwald     l2cap_services = NULL;
21609e9d05bSMatthias Ringwald     require_security_level2_for_outgoing_sdp = 0;
21709e9d05bSMatthias Ringwald #endif
218a3dc965aSMatthias Ringwald 
219a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2207192e786SMatthias Ringwald     l2cap_le_services = NULL;
2217192e786SMatthias Ringwald     l2cap_le_channels = NULL;
222a3dc965aSMatthias Ringwald #endif
223f5454fc6Smatthias.ringwald 
224d6ed9f9cSMatthias Ringwald #ifdef ENABLE_BLE
22533c40538SMatthias Ringwald     l2cap_event_packet_handler = NULL;
226d6ed9f9cSMatthias Ringwald #endif
2275628cf69SMatthias Ringwald     memset(fixed_channels, 0, sizeof(fixed_channels));
228f5454fc6Smatthias.ringwald 
229fcadd0caSmatthias.ringwald     //
2302718e2e7Smatthias.ringwald     // register callback with HCI
231fcadd0caSmatthias.ringwald     //
232d9a7306aSMatthias Ringwald     hci_event_callback_registration.callback = &l2cap_hci_event_handler;
233fb37a842SMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
234fb37a842SMatthias Ringwald 
235d9a7306aSMatthias Ringwald     hci_register_acl_packet_handler(&l2cap_acl_handler);
236fb37a842SMatthias Ringwald 
237be005ed6SMatthias Ringwald #ifdef ENABLE_CLASSIC
23815a95bd5SMatthias Ringwald     gap_connectable_control(0); // no services yet
239be005ed6SMatthias Ringwald #endif
240fcadd0caSmatthias.ringwald }
241fcadd0caSmatthias.ringwald 
242ffbf8201SMatthias Ringwald void l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
243d6ed9f9cSMatthias Ringwald #ifdef ENABLE_BLE
24433c40538SMatthias Ringwald     l2cap_event_packet_handler = handler;
245d6ed9f9cSMatthias Ringwald #else
246d6ed9f9cSMatthias Ringwald     UNUSED(handler);
247d6ed9f9cSMatthias Ringwald #endif
2481e6aba47Smatthias.ringwald }
2491e6aba47Smatthias.ringwald 
25009e9d05bSMatthias Ringwald void l2cap_request_can_send_fix_channel_now_event(hci_con_handle_t con_handle, uint16_t channel_id){
2519ec2630cSMatthias Ringwald     UNUSED(con_handle);
2529ec2630cSMatthias Ringwald 
25309e9d05bSMatthias Ringwald     int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id);
25409e9d05bSMatthias Ringwald     if (index < 0) return;
25509e9d05bSMatthias Ringwald     fixed_channels[index].waiting_for_can_send_now = 1;
25609e9d05bSMatthias Ringwald     l2cap_notify_channel_can_send();
25709e9d05bSMatthias Ringwald }
25809e9d05bSMatthias Ringwald 
25909e9d05bSMatthias Ringwald int  l2cap_can_send_fixed_channel_packet_now(hci_con_handle_t con_handle, uint16_t channel_id){
2609ec2630cSMatthias Ringwald     UNUSED(channel_id);
2619ec2630cSMatthias Ringwald 
26209e9d05bSMatthias Ringwald     return hci_can_send_acl_packet_now(con_handle);
26309e9d05bSMatthias Ringwald }
26409e9d05bSMatthias Ringwald 
26509e9d05bSMatthias Ringwald uint8_t *l2cap_get_outgoing_buffer(void){
26609e9d05bSMatthias Ringwald     return hci_get_outgoing_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
26709e9d05bSMatthias Ringwald }
26809e9d05bSMatthias Ringwald 
26909e9d05bSMatthias Ringwald int l2cap_reserve_packet_buffer(void){
27009e9d05bSMatthias Ringwald     return hci_reserve_packet_buffer();
27109e9d05bSMatthias Ringwald }
27209e9d05bSMatthias Ringwald 
27309e9d05bSMatthias Ringwald void l2cap_release_packet_buffer(void){
27409e9d05bSMatthias Ringwald     hci_release_packet_buffer();
27509e9d05bSMatthias Ringwald }
27609e9d05bSMatthias Ringwald 
277f511cefaSMatthias Ringwald static void l2cap_setup_header(uint8_t * acl_buffer, hci_con_handle_t con_handle, uint8_t packet_boundary, uint16_t remote_cid, uint16_t len){
27809e9d05bSMatthias Ringwald     // 0 - Connection handle : PB=pb : BC=00
279f511cefaSMatthias Ringwald     little_endian_store_16(acl_buffer, 0, con_handle | (packet_boundary << 12) | (0 << 14));
28009e9d05bSMatthias Ringwald     // 2 - ACL length
28109e9d05bSMatthias Ringwald     little_endian_store_16(acl_buffer, 2,  len + 4);
28209e9d05bSMatthias Ringwald     // 4 - L2CAP packet length
28309e9d05bSMatthias Ringwald     little_endian_store_16(acl_buffer, 4,  len + 0);
28409e9d05bSMatthias Ringwald     // 6 - L2CAP channel DEST
28509e9d05bSMatthias Ringwald     little_endian_store_16(acl_buffer, 6,  remote_cid);
28609e9d05bSMatthias Ringwald }
28709e9d05bSMatthias Ringwald 
288f511cefaSMatthias Ringwald // assumption - only on LE connections
28909e9d05bSMatthias Ringwald int l2cap_send_prepared_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint16_t len){
29009e9d05bSMatthias Ringwald 
29109e9d05bSMatthias Ringwald     if (!hci_is_packet_buffer_reserved()){
29209e9d05bSMatthias Ringwald         log_error("l2cap_send_prepared_connectionless called without reserving packet first");
29309e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
29409e9d05bSMatthias Ringwald     }
29509e9d05bSMatthias Ringwald 
29609e9d05bSMatthias Ringwald     if (!hci_can_send_prepared_acl_packet_now(con_handle)){
29709e9d05bSMatthias Ringwald         log_info("l2cap_send_prepared_connectionless handle 0x%02x, cid 0x%02x, cannot send", con_handle, cid);
29809e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
29909e9d05bSMatthias Ringwald     }
30009e9d05bSMatthias Ringwald 
30109e9d05bSMatthias Ringwald     log_debug("l2cap_send_prepared_connectionless handle %u, cid 0x%02x", con_handle, cid);
30209e9d05bSMatthias Ringwald 
30309e9d05bSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
304f511cefaSMatthias Ringwald     l2cap_setup_header(acl_buffer, con_handle, 0, cid, len);
30509e9d05bSMatthias Ringwald     // send
30609e9d05bSMatthias Ringwald     return hci_send_acl_packet_buffer(len+8);
30709e9d05bSMatthias Ringwald }
30809e9d05bSMatthias Ringwald 
309f511cefaSMatthias Ringwald // assumption - only on LE connections
31009e9d05bSMatthias Ringwald int l2cap_send_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint8_t *data, uint16_t len){
31109e9d05bSMatthias Ringwald 
31209e9d05bSMatthias Ringwald     if (!hci_can_send_acl_packet_now(con_handle)){
31309e9d05bSMatthias Ringwald         log_info("l2cap_send cid 0x%02x, cannot send", cid);
31409e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
31509e9d05bSMatthias Ringwald     }
31609e9d05bSMatthias Ringwald 
31709e9d05bSMatthias Ringwald     hci_reserve_packet_buffer();
31809e9d05bSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
31909e9d05bSMatthias Ringwald 
32009e9d05bSMatthias Ringwald     memcpy(&acl_buffer[8], data, len);
32109e9d05bSMatthias Ringwald 
32209e9d05bSMatthias Ringwald     return l2cap_send_prepared_connectionless(con_handle, cid, len);
32309e9d05bSMatthias Ringwald }
32409e9d05bSMatthias Ringwald 
32509e9d05bSMatthias Ringwald static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel) {
326d9d23054SMatthias Ringwald     log_debug("L2CAP_EVENT_CHANNEL_CAN_SEND_NOW local_cid 0x%x", channel);
32709e9d05bSMatthias Ringwald     uint8_t event[4];
32809e9d05bSMatthias Ringwald     event[0] = L2CAP_EVENT_CAN_SEND_NOW;
32909e9d05bSMatthias Ringwald     event[1] = sizeof(event) - 2;
33009e9d05bSMatthias Ringwald     little_endian_store_16(event, 2, channel);
33109e9d05bSMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
33209e9d05bSMatthias Ringwald     packet_handler(HCI_EVENT_PACKET, channel, event, sizeof(event));
33309e9d05bSMatthias Ringwald }
33409e9d05bSMatthias Ringwald 
33509e9d05bSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
33617a9b554SMatthias Ringwald static void l2cap_dispatch_to_channel(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){
33758de5610Smatthias.ringwald     (* (channel->packet_handler))(type, channel->local_cid, data, size);
33858de5610Smatthias.ringwald }
33958de5610Smatthias.ringwald 
34044276248SMatthias Ringwald static void l2cap_emit_simple_event_with_cid(l2cap_channel_t * channel, uint8_t event_code){
34144276248SMatthias Ringwald     uint8_t event[4];
34244276248SMatthias Ringwald     event[0] = event_code;
34344276248SMatthias Ringwald     event[1] = sizeof(event) - 2;
34444276248SMatthias Ringwald     little_endian_store_16(event, 2, channel->local_cid);
34544276248SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
34644276248SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
34744276248SMatthias Ringwald }
34809e9d05bSMatthias Ringwald #endif
34944276248SMatthias Ringwald 
35009e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
35158de5610Smatthias.ringwald void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
352c9dc710bS[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",
353fc64f94aSMatthias Ringwald              status, bd_addr_to_str(channel->address), channel->con_handle, channel->psm,
354c9dc710bS[email protected]              channel->local_cid, channel->remote_cid, channel->local_mtu, channel->remote_mtu, channel->flush_timeout);
355bab5f4f0SMatthias Ringwald     uint8_t event[24];
35658de5610Smatthias.ringwald     event[0] = L2CAP_EVENT_CHANNEL_OPENED;
35758de5610Smatthias.ringwald     event[1] = sizeof(event) - 2;
35858de5610Smatthias.ringwald     event[2] = status;
359724d70a2SMatthias Ringwald     reverse_bd_addr(channel->address, &event[3]);
360fc64f94aSMatthias Ringwald     little_endian_store_16(event,  9, channel->con_handle);
361f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 11, channel->psm);
362f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 13, channel->local_cid);
363f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 15, channel->remote_cid);
364f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 17, channel->local_mtu);
365f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 19, channel->remote_mtu);
366f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 21, channel->flush_timeout);
367bab5f4f0SMatthias Ringwald     event[23] = channel->state_var & L2CAP_CHANNEL_STATE_VAR_INCOMING ? 1 : 0;
36858de5610Smatthias.ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
36917a9b554SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
37058de5610Smatthias.ringwald }
37158de5610Smatthias.ringwald 
37244276248SMatthias Ringwald static void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
373e0abb8e7S[email protected]     log_info("L2CAP_EVENT_CHANNEL_CLOSED local_cid 0x%x", channel->local_cid);
37444276248SMatthias Ringwald     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED);
37558de5610Smatthias.ringwald }
37658de5610Smatthias.ringwald 
37744276248SMatthias Ringwald static void l2cap_emit_incoming_connection(l2cap_channel_t *channel) {
378e0abb8e7S[email protected]     log_info("L2CAP_EVENT_INCOMING_CONNECTION addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x",
379fc64f94aSMatthias Ringwald              bd_addr_to_str(channel->address), channel->con_handle,  channel->psm, channel->local_cid, channel->remote_cid);
38058de5610Smatthias.ringwald     uint8_t event[16];
38158de5610Smatthias.ringwald     event[0] = L2CAP_EVENT_INCOMING_CONNECTION;
38258de5610Smatthias.ringwald     event[1] = sizeof(event) - 2;
383724d70a2SMatthias Ringwald     reverse_bd_addr(channel->address, &event[2]);
384fc64f94aSMatthias Ringwald     little_endian_store_16(event,  8, channel->con_handle);
385f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 10, channel->psm);
386f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 12, channel->local_cid);
387f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 14, channel->remote_cid);
38858de5610Smatthias.ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
38917a9b554SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
3900af41d30Smatthias.ringwald }
391808a48abSmatthias.ringwald 
3927f02f414SMatthias Ringwald static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
393665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
394665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
395665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
396665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
397b35f641cSmatthias.ringwald         if ( channel->local_cid == local_cid) {
398f62db1e3Smatthias.ringwald             return channel;
399f62db1e3Smatthias.ringwald         }
400f62db1e3Smatthias.ringwald     }
401f62db1e3Smatthias.ringwald     return NULL;
402f62db1e3Smatthias.ringwald }
403f62db1e3Smatthias.ringwald 
4040b9d7e78SMatthias Ringwald ///
4050b9d7e78SMatthias Ringwald 
40630725612SMatthias Ringwald void l2cap_request_can_send_now_event(uint16_t local_cid){
40730725612SMatthias Ringwald     l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
40830725612SMatthias Ringwald     if (!channel) return;
40930725612SMatthias Ringwald     channel->waiting_for_can_send_now = 1;
41030725612SMatthias Ringwald     l2cap_notify_channel_can_send();
41130725612SMatthias Ringwald }
41230725612SMatthias Ringwald 
4136b1fde37Smatthias.ringwald int  l2cap_can_send_packet_now(uint16_t local_cid){
4146b1fde37Smatthias.ringwald     l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
4156b1fde37Smatthias.ringwald     if (!channel) return 0;
4160b9d7e78SMatthias Ringwald     return hci_can_send_acl_packet_now(channel->con_handle);
4177856fb31S[email protected] }
4187856fb31S[email protected] 
41983e7cdd9SMatthias Ringwald int  l2cap_can_send_prepared_packet_now(uint16_t local_cid){
42083e7cdd9SMatthias Ringwald     l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
42183e7cdd9SMatthias Ringwald     if (!channel) return 0;
4220b9d7e78SMatthias Ringwald     return hci_can_send_prepared_acl_packet_now(channel->con_handle);
42383e7cdd9SMatthias Ringwald }
42496cbd662Smatthias.ringwald uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){
42596cbd662Smatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
42696cbd662Smatthias.ringwald     if (channel) {
42796cbd662Smatthias.ringwald         return channel->remote_mtu;
42896cbd662Smatthias.ringwald     }
42996cbd662Smatthias.ringwald     return 0;
43096cbd662Smatthias.ringwald }
43196cbd662Smatthias.ringwald 
432ec820d77SMatthias Ringwald static l2cap_channel_t * l2cap_channel_for_rtx_timer(btstack_timer_source_t * ts){
433665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
434665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
435665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
436665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
4375932bd7cS[email protected]         if ( &channel->rtx == ts) {
4385932bd7cS[email protected]             return channel;
4395932bd7cS[email protected]         }
4405932bd7cS[email protected]     }
4415932bd7cS[email protected]     return NULL;
4425932bd7cS[email protected] }
4435932bd7cS[email protected] 
444ec820d77SMatthias Ringwald static void l2cap_rtx_timeout(btstack_timer_source_t * ts){
4455932bd7cS[email protected]     l2cap_channel_t * channel = l2cap_channel_for_rtx_timer(ts);
44695d2c8f4SMatthias Ringwald     if (!channel) return;
4475932bd7cS[email protected] 
4485932bd7cS[email protected]     log_info("l2cap_rtx_timeout for local cid 0x%02x", channel->local_cid);
4495932bd7cS[email protected] 
4505932bd7cS[email protected]     // "When terminating the channel, it is not necessary to send a L2CAP_DisconnectReq
4515932bd7cS[email protected]     //  and enter WAIT_DISCONNECT state. Channels can be transitioned directly to the CLOSED state."
4525932bd7cS[email protected]     // notify client
4535932bd7cS[email protected]     l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_RTX_TIMEOUT);
4545932bd7cS[email protected] 
4555932bd7cS[email protected]     // discard channel
4569dcb2fb2S[email protected]     // no need to stop timer here, it is removed from list during timer callback
457665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
4585932bd7cS[email protected]     btstack_memory_l2cap_channel_free(channel);
4595932bd7cS[email protected] }
4605932bd7cS[email protected] 
4615932bd7cS[email protected] static void l2cap_stop_rtx(l2cap_channel_t * channel){
4625932bd7cS[email protected]     log_info("l2cap_stop_rtx for local cid 0x%02x", channel->local_cid);
463528a4a3bSMatthias Ringwald     btstack_run_loop_remove_timer(&channel->rtx);
4645932bd7cS[email protected] }
4655932bd7cS[email protected] 
4665932bd7cS[email protected] static void l2cap_start_rtx(l2cap_channel_t * channel){
4675932bd7cS[email protected]     l2cap_stop_rtx(channel);
468cb0ff06bS[email protected]     log_info("l2cap_start_rtx for local cid 0x%02x", channel->local_cid);
469528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->rtx, l2cap_rtx_timeout);
470528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer(&channel->rtx, L2CAP_RTX_TIMEOUT_MS);
471528a4a3bSMatthias Ringwald     btstack_run_loop_add_timer(&channel->rtx);
4725932bd7cS[email protected] }
4735932bd7cS[email protected] 
4745932bd7cS[email protected] static void l2cap_start_ertx(l2cap_channel_t * channel){
4755932bd7cS[email protected]     log_info("l2cap_start_ertx for local cid 0x%02x", channel->local_cid);
4765932bd7cS[email protected]     l2cap_stop_rtx(channel);
477528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->rtx, l2cap_rtx_timeout);
478528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer(&channel->rtx, L2CAP_ERTX_TIMEOUT_MS);
479528a4a3bSMatthias Ringwald     btstack_run_loop_add_timer(&channel->rtx);
4805932bd7cS[email protected] }
4815932bd7cS[email protected] 
48271de195eSMatthias Ringwald void l2cap_require_security_level_2_for_outgoing_sdp(void){
483ac301f95S[email protected]     require_security_level2_for_outgoing_sdp = 1;
484ac301f95S[email protected] }
485ac301f95S[email protected] 
486df3354fcS[email protected] static int l2cap_security_level_0_allowed_for_PSM(uint16_t psm){
487235946f1SMatthias Ringwald     return (psm == BLUETOOTH_PROTOCOL_SDP) && (!require_security_level2_for_outgoing_sdp);
488df3354fcS[email protected] }
4895932bd7cS[email protected] 
4907f02f414SMatthias Ringwald static int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
491a35252c8S[email protected]     if (!hci_can_send_acl_packet_now(handle)){
4929da54300S[email protected]         log_info("l2cap_send_signaling_packet, cannot send");
493b1d43497Smatthias.ringwald         return BTSTACK_ACL_BUFFERS_FULL;
494b1d43497Smatthias.ringwald     }
495b1d43497Smatthias.ringwald 
4969da54300S[email protected]     // log_info("l2cap_send_signaling_packet type %u", cmd);
4972a373862S[email protected]     hci_reserve_packet_buffer();
498facf93fdS[email protected]     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
49958de5610Smatthias.ringwald     va_list argptr;
50058de5610Smatthias.ringwald     va_start(argptr, identifier);
50170efece1S[email protected]     uint16_t len = l2cap_create_signaling_classic(acl_buffer, handle, cmd, identifier, argptr);
50258de5610Smatthias.ringwald     va_end(argptr);
5039da54300S[email protected]     // log_info("l2cap_send_signaling_packet con %u!", handle);
504826f7347S[email protected]     return hci_send_acl_packet_buffer(len);
50558de5610Smatthias.ringwald }
50658de5610Smatthias.ringwald 
507f511cefaSMatthias Ringwald // assumption - only on Classic connections
508b1d43497Smatthias.ringwald int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
509b1d43497Smatthias.ringwald 
510c8b9416aS[email protected]     if (!hci_is_packet_buffer_reserved()){
511c8b9416aS[email protected]         log_error("l2cap_send_prepared called without reserving packet first");
512c8b9416aS[email protected]         return BTSTACK_ACL_BUFFERS_FULL;
513c8b9416aS[email protected]     }
514c8b9416aS[email protected] 
51558de5610Smatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
516b1d43497Smatthias.ringwald     if (!channel) {
5179da54300S[email protected]         log_error("l2cap_send_prepared no channel for cid 0x%02x", local_cid);
518b1d43497Smatthias.ringwald         return -1;   // TODO: define error
5196218e6f1Smatthias.ringwald     }
5206218e6f1Smatthias.ringwald 
521fc64f94aSMatthias Ringwald     if (!hci_can_send_prepared_acl_packet_now(channel->con_handle)){
5229da54300S[email protected]         log_info("l2cap_send_prepared cid 0x%02x, cannot send", local_cid);
523a35252c8S[email protected]         return BTSTACK_ACL_BUFFERS_FULL;
524a35252c8S[email protected]     }
525a35252c8S[email protected] 
526fc64f94aSMatthias Ringwald     log_debug("l2cap_send_prepared cid 0x%02x, handle %u, 1 credit used", local_cid, channel->con_handle);
527b1d43497Smatthias.ringwald 
52885ddcd84SMatthias Ringwald     int fcs_size = 0;
52985ddcd84SMatthias Ringwald 
53085ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
53185ddcd84SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
53285ddcd84SMatthias Ringwald         fcs_size = 2;
53385ddcd84SMatthias Ringwald     }
53485ddcd84SMatthias Ringwald #endif
53585ddcd84SMatthias Ringwald 
536f511cefaSMatthias Ringwald     // set non-flushable packet boundary flag if supported on Controller
537facf93fdS[email protected]     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
538f511cefaSMatthias Ringwald     uint8_t packet_boundary_flag = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02;
53985ddcd84SMatthias Ringwald     l2cap_setup_header(acl_buffer, channel->con_handle, packet_boundary_flag, channel->remote_cid, len + fcs_size);
54085ddcd84SMatthias Ringwald 
54185ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
54285ddcd84SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
54385ddcd84SMatthias Ringwald         // calculate FCS over l2cap data
54485ddcd84SMatthias Ringwald         uint16_t fcs = crc16_calc(acl_buffer + 4, 4 + len);
54585ddcd84SMatthias Ringwald         log_info("I-Frame: fcs 0x%04x", fcs);
54685ddcd84SMatthias Ringwald         little_endian_store_16(acl_buffer, 8 + len, fcs);
54758de5610Smatthias.ringwald     }
54885ddcd84SMatthias Ringwald #endif
54985ddcd84SMatthias Ringwald 
55085ddcd84SMatthias Ringwald     // send
55185ddcd84SMatthias Ringwald     return hci_send_acl_packet_buffer(len+8+fcs_size);
55285ddcd84SMatthias Ringwald }
55385ddcd84SMatthias Ringwald 
55485ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
55585ddcd84SMatthias Ringwald static inline uint16_t l2cap_encanced_control_field_for_information_frame(uint8_t tx_seq, int final, uint8_t req_seq, l2cap_segmentation_and_reassembly_t sar){
55685ddcd84SMatthias Ringwald     return (((uint16_t) sar) << 14) | (req_seq << 8) | (final << 7) | (tx_seq << 1) | 0;
55785ddcd84SMatthias Ringwald }
55885ddcd84SMatthias Ringwald static inline uint16_t l2cap_encanced_control_field_for_supevisor_frame(l2cap_supervisory_function_t supervisory_function, int poll, int final, uint8_t req_seq){
55938f62777SMatthias Ringwald     return (req_seq << 8) | (final << 7) | (poll << 4) | (((int) supervisory_function) << 2) | 1;
56085ddcd84SMatthias Ringwald }
56185ddcd84SMatthias Ringwald static int l2cap_next_ertm_seq_nr(int seq_nr){
56285ddcd84SMatthias Ringwald     return (seq_nr + 1) & 0x3f;
56385ddcd84SMatthias Ringwald }
564f0fb4cd7SMatthias Ringwald static void l2cap_ertm_next_tx_write_index(l2cap_channel_t * channel){
565f0fb4cd7SMatthias Ringwald     channel->tx_write_index++;
566f0fb4cd7SMatthias Ringwald     if (channel->tx_write_index < channel->num_tx_buffers) return;
567f0fb4cd7SMatthias Ringwald     channel->tx_write_index = 0;
568f0fb4cd7SMatthias Ringwald }
569f0fb4cd7SMatthias Ringwald static int l2cap_ertm_send_information_frame(l2cap_channel_t * channel, int index){
570f0fb4cd7SMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state = &channel->tx_packets_state[index];
571f0fb4cd7SMatthias Ringwald     hci_reserve_packet_buffer();
572f0fb4cd7SMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
573f0fb4cd7SMatthias Ringwald     uint16_t control = l2cap_encanced_control_field_for_information_frame(tx_state->tx_seq, 0, 0, L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU);
574f0fb4cd7SMatthias Ringwald     log_info("I-Frame: control 0x%04x", control);
575f0fb4cd7SMatthias Ringwald     little_endian_store_16(acl_buffer, 8, control);
576f0fb4cd7SMatthias Ringwald     memcpy(&acl_buffer[8+2], &channel->tx_packets_data[index * channel->local_mtu], tx_state->len);
577f0fb4cd7SMatthias Ringwald     // send
578f0fb4cd7SMatthias Ringwald     return l2cap_send_prepared(channel->local_cid, 2 + tx_state->len);
579f0fb4cd7SMatthias Ringwald }
580f0fb4cd7SMatthias Ringwald static int l2cap_ertm_send(l2cap_channel_t * channel, uint8_t * data, uint16_t len){
581f0fb4cd7SMatthias Ringwald     if (len > channel->remote_mtu){
582f0fb4cd7SMatthias Ringwald         log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", channel->local_cid);
583f0fb4cd7SMatthias Ringwald         return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU;
584f0fb4cd7SMatthias Ringwald     }
585f0fb4cd7SMatthias Ringwald     // TODO: check tx_transmit
586f0fb4cd7SMatthias Ringwald     // store int tx packet buffer
587f0fb4cd7SMatthias Ringwald     int index = channel->tx_write_index;
588f0fb4cd7SMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state = &channel->tx_packets_state[index];
589f0fb4cd7SMatthias Ringwald     tx_state->tx_seq = channel->next_tx_seq;
590f0fb4cd7SMatthias Ringwald     tx_state->len = len;
591f0fb4cd7SMatthias Ringwald     memcpy(&channel->tx_packets_data[index * channel->local_mtu], data, len);
592f0fb4cd7SMatthias Ringwald     // update
593f0fb4cd7SMatthias Ringwald     channel->next_tx_seq = l2cap_next_ertm_seq_nr(channel->next_tx_seq);
594f0fb4cd7SMatthias Ringwald     l2cap_ertm_next_tx_write_index(channel);
595675e6881SMatthias Ringwald     // try to send
596675e6881SMatthias Ringwald     l2cap_run();
597f0fb4cd7SMatthias Ringwald     return 0;
598f0fb4cd7SMatthias Ringwald }
59985ddcd84SMatthias Ringwald #endif
60058de5610Smatthias.ringwald 
601f511cefaSMatthias Ringwald // assumption - only on Classic connections
602ce8f182eSMatthias Ringwald int l2cap_send(uint16_t local_cid, uint8_t *data, uint16_t len){
603a35252c8S[email protected]     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
604a35252c8S[email protected]     if (!channel) {
605ce8f182eSMatthias Ringwald         log_error("l2cap_send no channel for cid 0x%02x", local_cid);
606a35252c8S[email protected]         return -1;   // TODO: define error
607a35252c8S[email protected]     }
608a35252c8S[email protected] 
609f0fb4cd7SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
610f0fb4cd7SMatthias Ringwald     // send in ERTM
611f0fb4cd7SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
612f0fb4cd7SMatthias Ringwald         return l2cap_ertm_send(channel, data, len);
613f0fb4cd7SMatthias Ringwald     }
614f0fb4cd7SMatthias Ringwald #endif
615f0fb4cd7SMatthias Ringwald 
616f0efaa57S[email protected]     if (len > channel->remote_mtu){
617ce8f182eSMatthias Ringwald         log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", local_cid);
618f0efaa57S[email protected]         return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU;
619f0efaa57S[email protected]     }
620f0efaa57S[email protected] 
621fc64f94aSMatthias Ringwald     if (!hci_can_send_acl_packet_now(channel->con_handle)){
622ce8f182eSMatthias Ringwald         log_info("l2cap_send cid 0x%02x, cannot send", local_cid);
623b1d43497Smatthias.ringwald         return BTSTACK_ACL_BUFFERS_FULL;
624b1d43497Smatthias.ringwald     }
625b1d43497Smatthias.ringwald 
6262a373862S[email protected]     hci_reserve_packet_buffer();
627facf93fdS[email protected]     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
628f0fb4cd7SMatthias Ringwald     memcpy(&acl_buffer[8], data, len);
629f0fb4cd7SMatthias Ringwald     return l2cap_send_prepared(local_cid, len);
630b1d43497Smatthias.ringwald }
631b1d43497Smatthias.ringwald 
632fc64f94aSMatthias Ringwald int l2cap_send_echo_request(hci_con_handle_t con_handle, uint8_t *data, uint16_t len){
633fc64f94aSMatthias Ringwald     return l2cap_send_signaling_packet(con_handle, ECHO_REQUEST, 0x77, len, data);
6340e37e417S[email protected] }
6350e37e417S[email protected] 
63628ca2b46S[email protected] static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
63728ca2b46S[email protected]     channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var | flag);
63828ca2b46S[email protected] }
63928ca2b46S[email protected] 
64028ca2b46S[email protected] static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
64128ca2b46S[email protected]     channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag);
64228ca2b46S[email protected] }
64309e9d05bSMatthias Ringwald #endif
64428ca2b46S[email protected] 
64528ca2b46S[email protected] 
64609e9d05bSMatthias Ringwald #ifdef ENABLE_BLE
64709e9d05bSMatthias Ringwald static int l2cap_send_le_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
64809e9d05bSMatthias Ringwald 
64909e9d05bSMatthias Ringwald     if (!hci_can_send_acl_packet_now(handle)){
65009e9d05bSMatthias Ringwald         log_info("l2cap_send_le_signaling_packet, cannot send");
65109e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
65209e9d05bSMatthias Ringwald     }
65309e9d05bSMatthias Ringwald 
65409e9d05bSMatthias Ringwald     // log_info("l2cap_send_le_signaling_packet type %u", cmd);
65509e9d05bSMatthias Ringwald     hci_reserve_packet_buffer();
65609e9d05bSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
65709e9d05bSMatthias Ringwald     va_list argptr;
65809e9d05bSMatthias Ringwald     va_start(argptr, identifier);
65909e9d05bSMatthias Ringwald     uint16_t len = l2cap_create_signaling_le(acl_buffer, handle, cmd, identifier, argptr);
66009e9d05bSMatthias Ringwald     va_end(argptr);
66109e9d05bSMatthias Ringwald     // log_info("l2cap_send_le_signaling_packet con %u!", handle);
66209e9d05bSMatthias Ringwald     return hci_send_acl_packet_buffer(len);
66309e9d05bSMatthias Ringwald }
66409e9d05bSMatthias Ringwald #endif
66509e9d05bSMatthias Ringwald 
66609e9d05bSMatthias Ringwald uint16_t l2cap_max_mtu(void){
66709e9d05bSMatthias Ringwald     return HCI_ACL_PAYLOAD_SIZE - L2CAP_HEADER_SIZE;
66809e9d05bSMatthias Ringwald }
66909e9d05bSMatthias Ringwald 
67009e9d05bSMatthias Ringwald uint16_t l2cap_max_le_mtu(void){
67109e9d05bSMatthias Ringwald     return l2cap_max_mtu();
67209e9d05bSMatthias Ringwald }
673b1d43497Smatthias.ringwald 
674450ad7ecSMatthias Ringwald static uint16_t l2cap_setup_options_mtu(l2cap_channel_t * channel, uint8_t * config_options){
675450ad7ecSMatthias Ringwald     config_options[0] = 1; // MTU
676450ad7ecSMatthias Ringwald     config_options[1] = 2; // len param
677450ad7ecSMatthias Ringwald     little_endian_store_16( (uint8_t*)&config_options, 2, channel->local_mtu);
678450ad7ecSMatthias Ringwald     return 4;
679450ad7ecSMatthias Ringwald }
680450ad7ecSMatthias Ringwald 
6816dca2a0cSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
682450ad7ecSMatthias Ringwald static uint16_t l2cap_setup_options_ertm(l2cap_channel_t * channel, uint8_t * config_options){
6836dca2a0cSMatthias Ringwald     config_options[0] = 0x04;   // RETRANSMISSION AND FLOW CONTROL OPTION
6846dca2a0cSMatthias Ringwald     config_options[1] = 9;      // length
6856dca2a0cSMatthias Ringwald     config_options[2] = (uint8_t) channel->mode;
6867b181629SMatthias Ringwald     config_options[3] = channel->num_rx_buffers;    // == TxWindows size
687bbc0a9e7SMatthias Ringwald     config_options[4] = channel->local_max_transmit;
688bbc0a9e7SMatthias Ringwald     little_endian_store_16( config_options, 5, channel->local_retransmission_timeout_ms);
689bbc0a9e7SMatthias Ringwald     little_endian_store_16( config_options, 7, channel->local_monitor_timeout_ms);
6907b181629SMatthias Ringwald     little_endian_store_16( config_options, 9, channel->local_mtu);
691450ad7ecSMatthias Ringwald     return 11;
6926dca2a0cSMatthias Ringwald }
69338f62777SMatthias Ringwald static int l2cap_ertm_send_supervisor_frame(l2cap_channel_t * channel, uint16_t control){
69438f62777SMatthias Ringwald     hci_reserve_packet_buffer();
69538f62777SMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
69638f62777SMatthias Ringwald     log_info("S-Frame: control 0x%04x", control);
69738f62777SMatthias Ringwald     little_endian_store_16(acl_buffer, 8, control);
69838f62777SMatthias Ringwald     return l2cap_send_prepared(channel->local_cid, 2);
69938f62777SMatthias Ringwald }
700450ad7ecSMatthias Ringwald #endif
701450ad7ecSMatthias Ringwald 
702450ad7ecSMatthias Ringwald static uint16_t l2cap_setup_options(l2cap_channel_t * channel, uint8_t * config_options){
703450ad7ecSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
704450ad7ecSMatthias Ringwald     // use ERTM options if supported
705450ad7ecSMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
706450ad7ecSMatthias Ringwald     if ((connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_DONE) && (connection->l2cap_state.extended_feature_mask & 0x08)){
707450ad7ecSMatthias Ringwald         return l2cap_setup_options_ertm(channel, config_options);
708450ad7ecSMatthias Ringwald 
709450ad7ecSMatthias Ringwald     }
710450ad7ecSMatthias Ringwald #endif
711450ad7ecSMatthias Ringwald     return l2cap_setup_options_mtu(channel, config_options);
7126dca2a0cSMatthias Ringwald }
7136dca2a0cSMatthias Ringwald 
7141b9cb13dSMatthias Ringwald static uint32_t l2cap_extended_features_mask(void){
7151b9cb13dSMatthias Ringwald     // extended features request supported, features: fixed channels, unicast connectionless data reception
7161b9cb13dSMatthias Ringwald     uint32_t features = 0x280;
7171b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
7181b9cb13dSMatthias Ringwald     features |= 0x0008;
7191b9cb13dSMatthias Ringwald #endif
7201b9cb13dSMatthias Ringwald     return features;
7211b9cb13dSMatthias Ringwald }
7221b9cb13dSMatthias Ringwald 
7238158c421Smatthias.ringwald // MARK: L2CAP_RUN
7242cd0be45Smatthias.ringwald // process outstanding signaling tasks
7257f02f414SMatthias Ringwald static void l2cap_run(void){
7262b83fb7dSmatthias.ringwald 
72722c29ab4SMatthias Ringwald     // log_info("l2cap_run: entered");
72822c29ab4SMatthias Ringwald 
7292b83fb7dSmatthias.ringwald     // check pending signaling responses
7302b83fb7dSmatthias.ringwald     while (signaling_responses_pending){
7312b83fb7dSmatthias.ringwald 
7322b83fb7dSmatthias.ringwald         hci_con_handle_t handle = signaling_responses[0].handle;
733a35252c8S[email protected] 
734a35252c8S[email protected]         if (!hci_can_send_acl_packet_now(handle)) break;
735a35252c8S[email protected] 
7362b83fb7dSmatthias.ringwald         uint8_t  sig_id        = signaling_responses[0].sig_id;
737e74c5f58SMatthias Ringwald         uint8_t  response_code = signaling_responses[0].code;
7382b360848Smatthias.ringwald         uint16_t infoType      = signaling_responses[0].data;  // INFORMATION_REQUEST
73963a7246aSmatthias.ringwald         uint16_t result        = signaling_responses[0].data;  // CONNECTION_REQUEST, COMMAND_REJECT
740b3264428SMatthias Ringwald #ifdef ENABLE_CLASSIC
741b3264428SMatthias Ringwald         uint16_t source_cid    = signaling_responses[0].cid;   // CONNECTION_REQUEST
742b3264428SMatthias Ringwald #endif
743f3963406SMatthias Ringwald         UNUSED(infoType);
74409e9d05bSMatthias Ringwald 
745f53da564S[email protected]         // remove first item before sending (to avoid sending response mutliple times)
746f53da564S[email protected]         signaling_responses_pending--;
747f53da564S[email protected]         int i;
748f53da564S[email protected]         for (i=0; i < signaling_responses_pending; i++){
749f53da564S[email protected]             memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t));
750f53da564S[email protected]         }
751f53da564S[email protected] 
752f53da564S[email protected]         switch (response_code){
75309e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
7542b360848Smatthias.ringwald             case CONNECTION_REQUEST:
755e74c5f58SMatthias Ringwald                 l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, source_cid, 0, result, 0);
7562bd8b7e7S[email protected]                 // also disconnect if result is 0x0003 - security blocked
7574d816277S[email protected]                 if (result == 0x0003){
7582bd8b7e7S[email protected]                     hci_disconnect_security_block(handle);
7594d816277S[email protected]                 }
7602b360848Smatthias.ringwald                 break;
7612b83fb7dSmatthias.ringwald             case ECHO_REQUEST:
7622b83fb7dSmatthias.ringwald                 l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL);
7632b83fb7dSmatthias.ringwald                 break;
7642b83fb7dSmatthias.ringwald             case INFORMATION_REQUEST:
7653b0484b3S[email protected]                 switch (infoType){
7663b0484b3S[email protected]                     case 1: { // Connectionless MTU
7673b0484b3S[email protected]                             uint16_t connectionless_mtu = hci_max_acl_data_packet_length();
7683b0484b3S[email protected]                             l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, sizeof(connectionless_mtu), &connectionless_mtu);
7693b0484b3S[email protected]                         }
770202c8a4cSMatthias Ringwald                         break;
7713b0484b3S[email protected]                     case 2: {  // Extended Features Supported
7721b9cb13dSMatthias Ringwald                             uint32_t features = l2cap_extended_features_mask();
7733b0484b3S[email protected]                             l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, sizeof(features), &features);
7743b0484b3S[email protected]                         }
775202c8a4cSMatthias Ringwald                         break;
7763b0484b3S[email protected]                     case 3: { // Fixed Channels Supported
7773b0484b3S[email protected]                             uint8_t map[8];
7783b0484b3S[email protected]                             memset(map, 0, 8);
779288636a2SMatthias Ringwald                             map[0] = 0x06;  // L2CAP Signaling Channel (0x02) + Connectionless reception (0x04)
7803b0484b3S[email protected]                             l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, sizeof(map), &map);
7813b0484b3S[email protected]                         }
782202c8a4cSMatthias Ringwald                         break;
7833b0484b3S[email protected]                     default:
7842b83fb7dSmatthias.ringwald                         // all other types are not supported
7852b83fb7dSmatthias.ringwald                         l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL);
7863b0484b3S[email protected]                         break;
7872b83fb7dSmatthias.ringwald                 }
7882b83fb7dSmatthias.ringwald                 break;
78963a7246aSmatthias.ringwald             case COMMAND_REJECT:
7905ca8d57bS[email protected]                 l2cap_send_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL);
79163f0ac45SMatthias Ringwald                 break;
79209e9d05bSMatthias Ringwald #endif
793a9a4c409SMatthias Ringwald #ifdef ENABLE_BLE
79463f0ac45SMatthias Ringwald             case LE_CREDIT_BASED_CONNECTION_REQUEST:
79563f0ac45SMatthias Ringwald                 l2cap_send_le_signaling_packet(handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, sig_id, 0, 0, 0, 0, result);
79663f0ac45SMatthias Ringwald                 break;
79770efece1S[email protected]             case COMMAND_REJECT_LE:
79870efece1S[email protected]                 l2cap_send_le_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL);
79963a7246aSmatthias.ringwald                 break;
80070efece1S[email protected] #endif
8012b83fb7dSmatthias.ringwald             default:
8022b83fb7dSmatthias.ringwald                 // should not happen
8032b83fb7dSmatthias.ringwald                 break;
8042b83fb7dSmatthias.ringwald         }
8052b83fb7dSmatthias.ringwald     }
8062b83fb7dSmatthias.ringwald 
807665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
808f3963406SMatthias Ringwald     UNUSED(it);
80909e9d05bSMatthias Ringwald 
8101b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
8111b9cb13dSMatthias Ringwald     // send l2cap information request if neccessary
8121b9cb13dSMatthias Ringwald     hci_connections_get_iterator(&it);
8131b9cb13dSMatthias Ringwald     while(btstack_linked_list_iterator_has_next(&it)){
8141b9cb13dSMatthias Ringwald         hci_connection_t * connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it);
8151b9cb13dSMatthias Ringwald         if (connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_W2_SEND_EXTENDED_FEATURE_REQUEST){
8161b9cb13dSMatthias Ringwald             connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_W4_EXTENDED_FEATURE_RESPONSE;
8171b9cb13dSMatthias Ringwald             // send information request for extended features
8181b9cb13dSMatthias Ringwald             uint8_t sig_id = l2cap_next_sig_id();
8191b9cb13dSMatthias Ringwald             uint8_t info_type = 2;
8201b9cb13dSMatthias Ringwald             l2cap_send_signaling_packet(connection->con_handle, INFORMATION_REQUEST, sig_id, info_type);
8211b9cb13dSMatthias Ringwald             return;
8221b9cb13dSMatthias Ringwald         }
8231b9cb13dSMatthias Ringwald     }
8241b9cb13dSMatthias Ringwald #endif
8251b9cb13dSMatthias Ringwald 
82609e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
82743ec931dSMatthias Ringwald     uint8_t  config_options[10];
828665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
829665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
830baf94f06S[email protected] 
831665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
83222c29ab4SMatthias Ringwald         // log_info("l2cap_run: channel %p, state %u, var 0x%02x", channel, channel->state, channel->state_var);
8332cd0be45Smatthias.ringwald         switch (channel->state){
8342cd0be45Smatthias.ringwald 
835df3354fcS[email protected]             case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE:
836ad671560S[email protected]             case L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT:
837fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
838a00031e2S[email protected]                 if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND) {
839ad671560S[email protected]                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND);
840fc64f94aSMatthias Ringwald                     l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 1, 0);
841ad671560S[email protected]                 }
842ad671560S[email protected]                 break;
843ad671560S[email protected] 
84402b22dc4Smatthias.ringwald             case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
845baf94f06S[email protected]                 if (!hci_can_send_command_packet_now()) break;
84664472d52Smatthias.ringwald                 // send connection request - set state first
84764472d52Smatthias.ringwald                 channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE;
84802b22dc4Smatthias.ringwald                 // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
8498f8108aaSmatthias.ringwald                 hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1);
85002b22dc4Smatthias.ringwald                 break;
85102b22dc4Smatthias.ringwald 
852e7ff783cSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE:
853fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
85422c29ab4SMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
855fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, channel->reason, 0);
856e7ff783cSmatthias.ringwald                 // discard channel - l2cap_finialize_channel_close without sending l2cap close event
8579dcb2fb2S[email protected]                 l2cap_stop_rtx(channel);
858665d90f2SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
859d3a9df87Smatthias.ringwald                 btstack_memory_l2cap_channel_free(channel);
860e7ff783cSmatthias.ringwald                 break;
861e7ff783cSmatthias.ringwald 
862552d92a1Smatthias.ringwald             case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT:
863fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
864fa8473a4Smatthias.ringwald                 channel->state = L2CAP_STATE_CONFIG;
86528ca2b46S[email protected]                 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
866fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0);
867552d92a1Smatthias.ringwald                 break;
868552d92a1Smatthias.ringwald 
8696fdcc387Smatthias.ringwald             case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST:
870fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
8716fdcc387Smatthias.ringwald                 // success, start l2cap handshake
872b1988dceSmatthias.ringwald                 channel->local_sig_id = l2cap_next_sig_id();
8736fdcc387Smatthias.ringwald                 channel->state = L2CAP_STATE_WAIT_CONNECT_RSP;
874fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet( channel->con_handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid);
8755932bd7cS[email protected]                 l2cap_start_rtx(channel);
8766fdcc387Smatthias.ringwald                 break;
8776fdcc387Smatthias.ringwald 
878fa8473a4Smatthias.ringwald             case L2CAP_STATE_CONFIG:
879fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
88073cf2b3dSmatthias.ringwald                 if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
88163a7246aSmatthias.ringwald                     uint16_t flags = 0;
88228ca2b46S[email protected]                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
88363a7246aSmatthias.ringwald                     if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT) {
88463a7246aSmatthias.ringwald                         flags = 1;
88563a7246aSmatthias.ringwald                     } else {
88628ca2b46S[email protected]                         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
88763a7246aSmatthias.ringwald                     }
88863a7246aSmatthias.ringwald                     if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID){
889ac8f1300SMatthias Ringwald                         channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
890fc64f94aSMatthias 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);
891ac8f1300SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
892ac8f1300SMatthias Ringwald                     } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED){
893ac8f1300SMatthias Ringwald                         channelStateVarClearFlag(channel,L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED);
894ac8f1300SMatthias Ringwald                         channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
8956dca2a0cSMatthias Ringwald                         uint16_t options_size = l2cap_setup_options(channel, config_options);
896ac8f1300SMatthias Ringwald                         l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS, options_size, &config_options);
897ac8f1300SMatthias Ringwald #endif
898ac8f1300SMatthias Ringwald                     } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU){
89963a7246aSmatthias.ringwald                         channelStateVarClearFlag(channel,L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
900ac8f1300SMatthias Ringwald                         uint16_t options_size = l2cap_setup_options(channel, config_options);
901ac8f1300SMatthias Ringwald                         l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_SUCCESS, options_size, &config_options);
90263a7246aSmatthias.ringwald                     } else {
903ac8f1300SMatthias Ringwald                         l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_SUCCESS, 0, NULL);
90463a7246aSmatthias.ringwald                     }
90563a7246aSmatthias.ringwald                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT);
906fa8473a4Smatthias.ringwald                 }
90773cf2b3dSmatthias.ringwald                 else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){
90828ca2b46S[email protected]                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
90928ca2b46S[email protected]                     channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ);
910b1988dceSmatthias.ringwald                     channel->local_sig_id = l2cap_next_sig_id();
9116dca2a0cSMatthias Ringwald                     uint16_t options_size = l2cap_setup_options(channel, config_options);
9126dca2a0cSMatthias Ringwald                     l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, options_size, &config_options);
9135932bd7cS[email protected]                     l2cap_start_rtx(channel);
914fa8473a4Smatthias.ringwald                 }
915fa8473a4Smatthias.ringwald                 if (l2cap_channel_ready_for_open(channel)){
916552d92a1Smatthias.ringwald                     channel->state = L2CAP_STATE_OPEN;
917552d92a1Smatthias.ringwald                     l2cap_emit_channel_opened(channel, 0);  // success
918fa8473a4Smatthias.ringwald                 }
919552d92a1Smatthias.ringwald                 break;
920552d92a1Smatthias.ringwald 
921e7ff783cSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
922fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
92322c29ab4SMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
924fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet( channel->con_handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);
9255932bd7cS[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 :)
926756102d3Smatthias.ringwald                 l2cap_finialize_channel_close(channel);  // -- remove from list
927e7ff783cSmatthias.ringwald                 break;
928e7ff783cSmatthias.ringwald 
929e7ff783cSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
930fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
931b1988dceSmatthias.ringwald                 channel->local_sig_id = l2cap_next_sig_id();
9322cd0be45Smatthias.ringwald                 channel->state = L2CAP_STATE_WAIT_DISCONNECT;
933fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet( channel->con_handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);
9342cd0be45Smatthias.ringwald                 break;
9352cd0be45Smatthias.ringwald             default:
9362cd0be45Smatthias.ringwald                 break;
9372cd0be45Smatthias.ringwald         }
93838f62777SMatthias Ringwald 
93938f62777SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
94038f62777SMatthias Ringwald         // send s-frame to acknowledge received packets
94138f62777SMatthias Ringwald         if (!hci_can_send_acl_packet_now(channel->con_handle)) continue;
942675e6881SMatthias Ringwald 
943675e6881SMatthias Ringwald         if (channel->tx_send_index != channel->tx_write_index){
944675e6881SMatthias Ringwald             // packet ready to send!
945675e6881SMatthias Ringwald             int index = channel->tx_send_index;
946675e6881SMatthias Ringwald             channel->tx_send_index++;
947675e6881SMatthias Ringwald             if (channel->tx_send_index >= channel->num_tx_buffers){
948675e6881SMatthias Ringwald                 channel->tx_send_index = 0;
949675e6881SMatthias Ringwald             }
950675e6881SMatthias Ringwald             l2cap_ertm_send_information_frame(channel, index);
951675e6881SMatthias Ringwald             continue;
952675e6881SMatthias Ringwald         }
953675e6881SMatthias Ringwald 
954d84e866fSMatthias Ringwald         if (channel->send_supervisor_frame_receiver_ready){
955d84e866fSMatthias Ringwald             channel->send_supervisor_frame_receiver_ready = 0;;
956d84e866fSMatthias Ringwald             log_info("Send S-Frame: RR %u", channel->req_seq);
95738f62777SMatthias Ringwald             uint16_t control = l2cap_encanced_control_field_for_supevisor_frame( L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY, 0, 0, channel->req_seq);
95838f62777SMatthias Ringwald             l2cap_ertm_send_supervisor_frame(channel, control);
959675e6881SMatthias Ringwald             continue;
96038f62777SMatthias Ringwald         }
96138f62777SMatthias Ringwald #endif
96238f62777SMatthias Ringwald 
9632cd0be45Smatthias.ringwald     }
96409e9d05bSMatthias Ringwald #endif
965da886c03S[email protected] 
966cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
967efedfb4cSMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
968efedfb4cSMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
9697f107edaSMatthias Ringwald         uint8_t  * acl_buffer;
9707f107edaSMatthias Ringwald         uint8_t  * l2cap_payload;
9717f107edaSMatthias Ringwald         uint16_t pos;
9727f107edaSMatthias Ringwald         uint16_t payload_size;
973efedfb4cSMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
974efedfb4cSMatthias Ringwald         // log_info("l2cap_run: channel %p, state %u, var 0x%02x", channel, channel->state, channel->state_var);
975efedfb4cSMatthias Ringwald         switch (channel->state){
9765cb87675SMatthias Ringwald             case L2CAP_STATE_WILL_SEND_LE_CONNECTION_REQUEST:
9775cb87675SMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
9785cb87675SMatthias Ringwald                 channel->state = L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE;
9795cb87675SMatthias Ringwald                 // le psm, source cid, mtu, mps, initial credits
9801b8b8d05SMatthias Ringwald                 channel->local_sig_id = l2cap_next_sig_id();
98163f0ac45SMatthias Ringwald                 channel->credits_incoming =  channel->new_credits_incoming;
98263f0ac45SMatthias Ringwald                 channel->new_credits_incoming = 0;
98363f0ac45SMatthias 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);
9845cb87675SMatthias Ringwald                 break;
98523017473SMatthias Ringwald             case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_ACCEPT:
98623017473SMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
98723017473SMatthias Ringwald                 // TODO: support larger MPS
98823017473SMatthias Ringwald                 channel->state = L2CAP_STATE_OPEN;
98963f0ac45SMatthias Ringwald                 channel->credits_incoming =  channel->new_credits_incoming;
99063f0ac45SMatthias Ringwald                 channel->new_credits_incoming = 0;
99163f0ac45SMatthias 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);
99264e11ca9SMatthias Ringwald                 // notify client
99344276248SMatthias Ringwald                 l2cap_emit_le_channel_opened(channel, 0);
99423017473SMatthias Ringwald                 break;
995e7d0c9aaSMatthias Ringwald             case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE:
996e7d0c9aaSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
997e7d0c9aaSMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
99863f0ac45SMatthias Ringwald                 l2cap_send_le_signaling_packet(channel->con_handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, 0, 0, channel->reason);
999e7d0c9aaSMatthias Ringwald                 // discard channel - l2cap_finialize_channel_close without sending l2cap close event
1000e7d0c9aaSMatthias Ringwald                 l2cap_stop_rtx(channel);
1001e7d0c9aaSMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1002e7d0c9aaSMatthias Ringwald                 btstack_memory_l2cap_channel_free(channel);
1003e7d0c9aaSMatthias Ringwald                 break;
10047f107edaSMatthias Ringwald             case L2CAP_STATE_OPEN:
100585aeef60SMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
100685aeef60SMatthias Ringwald 
100785aeef60SMatthias Ringwald                 // send credits
100885aeef60SMatthias Ringwald                 if (channel->new_credits_incoming){
100985aeef60SMatthias Ringwald                     log_info("l2cap: sending %u credits", channel->new_credits_incoming);
101085aeef60SMatthias Ringwald                     channel->local_sig_id = l2cap_next_sig_id();
101185aeef60SMatthias Ringwald                     uint16_t new_credits = channel->new_credits_incoming;
101285aeef60SMatthias Ringwald                     channel->new_credits_incoming = 0;
101385aeef60SMatthias Ringwald                     channel->credits_incoming += new_credits;
101485aeef60SMatthias Ringwald                     l2cap_send_le_signaling_packet(channel->con_handle, LE_FLOW_CONTROL_CREDIT, channel->local_sig_id, channel->remote_cid, new_credits);
101585aeef60SMatthias Ringwald                     break;
101685aeef60SMatthias Ringwald                 }
101785aeef60SMatthias Ringwald 
101885aeef60SMatthias Ringwald                 // send data
10197f107edaSMatthias Ringwald                 if (!channel->send_sdu_buffer) break;
10207f107edaSMatthias Ringwald                 if (!channel->credits_outgoing) break;
102185aeef60SMatthias Ringwald 
10227f107edaSMatthias Ringwald                 // send part of SDU
10237f107edaSMatthias Ringwald                 hci_reserve_packet_buffer();
10247f107edaSMatthias Ringwald                 acl_buffer = hci_get_outgoing_packet_buffer();
10257f107edaSMatthias Ringwald                 l2cap_payload = acl_buffer + 8;
10267f107edaSMatthias Ringwald                 pos = 0;
10277f107edaSMatthias Ringwald                 if (!channel->send_sdu_pos){
10287f107edaSMatthias Ringwald                     // store SDU len
10297f107edaSMatthias Ringwald                     channel->send_sdu_pos += 2;
10307f107edaSMatthias Ringwald                     little_endian_store_16(l2cap_payload, pos, channel->send_sdu_len);
10317f107edaSMatthias Ringwald                     pos += 2;
10327f107edaSMatthias Ringwald                 }
10337f107edaSMatthias Ringwald                 payload_size = btstack_min(channel->send_sdu_len + 2 - channel->send_sdu_pos, channel->remote_mps - pos);
103485aeef60SMatthias Ringwald                 log_info("len %u, pos %u => payload %u, credits %u", channel->send_sdu_len, channel->send_sdu_pos, payload_size, channel->credits_outgoing);
10357f107edaSMatthias Ringwald                 memcpy(&l2cap_payload[pos], &channel->send_sdu_buffer[channel->send_sdu_pos-2], payload_size); // -2 for virtual SDU len
10367f107edaSMatthias Ringwald                 pos += payload_size;
10377f107edaSMatthias Ringwald                 channel->send_sdu_pos += payload_size;
1038f511cefaSMatthias Ringwald                 l2cap_setup_header(acl_buffer, channel->con_handle, 0, channel->remote_cid, pos);
10397f107edaSMatthias Ringwald                 // done
10407f107edaSMatthias Ringwald 
104185aeef60SMatthias Ringwald                 channel->credits_outgoing--;
10427f107edaSMatthias Ringwald 
10437f107edaSMatthias Ringwald                 if (channel->send_sdu_pos >= channel->send_sdu_len + 2){
10447f107edaSMatthias Ringwald                     channel->send_sdu_buffer = NULL;
104544276248SMatthias Ringwald                     // send done event
104644276248SMatthias Ringwald                     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_PACKET_SENT);
104744276248SMatthias Ringwald                     // inform about can send now
104844276248SMatthias Ringwald                     l2cap_le_notify_channel_can_send(channel);
10497f107edaSMatthias Ringwald                 }
10507f107edaSMatthias Ringwald                 hci_send_acl_packet_buffer(8 + pos);
10517f107edaSMatthias Ringwald                 break;
1052828a7f7aSMatthias Ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
1053828a7f7aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1054828a7f7aSMatthias Ringwald                 channel->local_sig_id = l2cap_next_sig_id();
1055828a7f7aSMatthias Ringwald                 channel->state = L2CAP_STATE_WAIT_DISCONNECT;
1056828a7f7aSMatthias Ringwald                 l2cap_send_le_signaling_packet( channel->con_handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);
1057828a7f7aSMatthias Ringwald                 break;
1058828a7f7aSMatthias Ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
1059828a7f7aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1060828a7f7aSMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
1061828a7f7aSMatthias Ringwald                 l2cap_send_le_signaling_packet( channel->con_handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);
1062828a7f7aSMatthias Ringwald                 l2cap_le_finialize_channel_close(channel);  // -- remove from list
1063828a7f7aSMatthias Ringwald                 break;
1064efedfb4cSMatthias Ringwald             default:
1065efedfb4cSMatthias Ringwald                 break;
1066efedfb4cSMatthias Ringwald         }
1067efedfb4cSMatthias Ringwald     }
106809e9d05bSMatthias Ringwald #endif
1069efedfb4cSMatthias Ringwald 
107009e9d05bSMatthias Ringwald #ifdef ENABLE_BLE
1071da886c03S[email protected]     // send l2cap con paramter update if necessary
1072da886c03S[email protected]     hci_connections_get_iterator(&it);
1073665d90f2SMatthias Ringwald     while(btstack_linked_list_iterator_has_next(&it)){
1074665d90f2SMatthias Ringwald         hci_connection_t * connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it);
10755d14fa8fSMatthias Ringwald         if (connection->address_type != BD_ADDR_TYPE_LE_PUBLIC && connection->address_type != BD_ADDR_TYPE_LE_RANDOM) continue;
1076b68d7bc3SMatthias Ringwald         if (!hci_can_send_acl_packet_now(connection->con_handle)) continue;
1077da886c03S[email protected]         switch (connection->le_con_parameter_update_state){
1078b68d7bc3SMatthias Ringwald             case CON_PARAMETER_UPDATE_SEND_REQUEST:
1079b68d7bc3SMatthias Ringwald                 connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE;
1080b68d7bc3SMatthias Ringwald                 l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_REQUEST, connection->le_con_param_update_identifier,
1081b68d7bc3SMatthias Ringwald                                                connection->le_conn_interval_min, connection->le_conn_interval_max, connection->le_conn_latency, connection->le_supervision_timeout);
1082b68d7bc3SMatthias Ringwald                 break;
1083da886c03S[email protected]             case CON_PARAMETER_UPDATE_SEND_RESPONSE:
1084b68d7bc3SMatthias Ringwald                 connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_CHANGE_HCI_CON_PARAMETERS;
1085b68d7bc3SMatthias Ringwald                 l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 0);
1086da886c03S[email protected]                 break;
1087da886c03S[email protected]             case CON_PARAMETER_UPDATE_DENY:
1088b68d7bc3SMatthias Ringwald                 connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE;
1089b68d7bc3SMatthias Ringwald                 l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 1);
1090da886c03S[email protected]                 break;
1091da886c03S[email protected]             default:
1092da886c03S[email protected]                 break;
1093da886c03S[email protected]         }
1094da886c03S[email protected]     }
10954d7157c3S[email protected] #endif
1096da886c03S[email protected] 
109722c29ab4SMatthias Ringwald     // log_info("l2cap_run: exit");
10982cd0be45Smatthias.ringwald }
10992cd0be45Smatthias.ringwald 
110009e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1101fc64f94aSMatthias Ringwald static void l2cap_handle_connection_complete(hci_con_handle_t con_handle, l2cap_channel_t * channel){
11022df5dadcS[email protected]     if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
11035533f01eS[email protected]         log_info("l2cap_handle_connection_complete expected state");
11042df5dadcS[email protected]         // success, start l2cap handshake
1105fc64f94aSMatthias Ringwald         channel->con_handle = con_handle;
11062df5dadcS[email protected]         // check remote SSP feature first
11072df5dadcS[email protected]         channel->state = L2CAP_STATE_WAIT_REMOTE_SUPPORTED_FEATURES;
11082df5dadcS[email protected]     }
11092df5dadcS[email protected] }
11102df5dadcS[email protected] 
11111b9cb13dSMatthias Ringwald static void l2cap_ready_to_connect(l2cap_channel_t * channel){
11121b9cb13dSMatthias Ringwald 
11131b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
111427e0774aSMatthias Ringwald     // assumption: outgoing connection
11151b9cb13dSMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
11161b9cb13dSMatthias Ringwald     if (connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_IDLE){
11171b9cb13dSMatthias Ringwald         connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_W2_SEND_EXTENDED_FEATURE_REQUEST;
11181b9cb13dSMatthias Ringwald         channel->state = L2CAP_STATE_WAIT_OUTGOING_EXTENDED_FEATURES;
11191b9cb13dSMatthias Ringwald         return;
11201b9cb13dSMatthias Ringwald     }
11211b9cb13dSMatthias Ringwald #endif
11221b9cb13dSMatthias Ringwald 
11231b9cb13dSMatthias Ringwald     // fine, go ahead
11241b9cb13dSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
11251b9cb13dSMatthias Ringwald }
11261b9cb13dSMatthias Ringwald 
11272df5dadcS[email protected] static void l2cap_handle_remote_supported_features_received(l2cap_channel_t * channel){
11282df5dadcS[email protected]     if (channel->state != L2CAP_STATE_WAIT_REMOTE_SUPPORTED_FEATURES) return;
11292df5dadcS[email protected] 
11302df5dadcS[email protected]     // we have been waiting for remote supported features, if both support SSP,
1131ac301f95S[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));
1132fc64f94aSMatthias Ringwald     if (gap_ssp_supported_on_both_sides(channel->con_handle) && !l2cap_security_level_0_allowed_for_PSM(channel->psm)){
11332df5dadcS[email protected]         // request security level 2
11342df5dadcS[email protected]         channel->state = L2CAP_STATE_WAIT_OUTGOING_SECURITY_LEVEL_UPDATE;
1135fc64f94aSMatthias Ringwald         gap_request_security_level(channel->con_handle, LEVEL_2);
11362df5dadcS[email protected]         return;
11372df5dadcS[email protected]     }
11381b9cb13dSMatthias Ringwald 
11391b9cb13dSMatthias Ringwald     l2cap_ready_to_connect(channel);
11402df5dadcS[email protected] }
114109e9d05bSMatthias Ringwald #endif
11422df5dadcS[email protected] 
114309e9d05bSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
1144da144af5SMatthias 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,
1145da144af5SMatthias Ringwald     uint16_t psm, uint16_t local_mtu, gap_security_level_t security_level){
1146da144af5SMatthias Ringwald 
1147da144af5SMatthias Ringwald     l2cap_channel_t * channel = btstack_memory_l2cap_channel_get();
1148da144af5SMatthias Ringwald     if (!channel) {
1149da144af5SMatthias Ringwald         return NULL;
1150da144af5SMatthias Ringwald     }
1151da144af5SMatthias Ringwald 
1152da144af5SMatthias Ringwald      // Init memory (make valgrind happy)
1153da144af5SMatthias Ringwald     memset(channel, 0, sizeof(l2cap_channel_t));
1154da144af5SMatthias Ringwald 
1155da144af5SMatthias Ringwald     // fill in
1156da144af5SMatthias Ringwald     channel->packet_handler = packet_handler;
1157da144af5SMatthias Ringwald     bd_addr_copy(channel->address, address);
1158da144af5SMatthias Ringwald     channel->address_type = address_type;
1159da144af5SMatthias Ringwald     channel->psm = psm;
1160da144af5SMatthias Ringwald     channel->local_mtu  = local_mtu;
1161da144af5SMatthias Ringwald     channel->remote_mtu = L2CAP_MINIMAL_MTU;
1162da144af5SMatthias Ringwald     channel->required_security_level = security_level;
1163da144af5SMatthias Ringwald 
1164da144af5SMatthias Ringwald     //
1165da144af5SMatthias Ringwald     channel->local_cid = l2cap_next_local_cid();
1166da144af5SMatthias Ringwald     channel->con_handle = 0;
1167da144af5SMatthias Ringwald 
1168da144af5SMatthias Ringwald     // set initial state
1169da144af5SMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION;
1170da144af5SMatthias Ringwald     channel->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
1171da144af5SMatthias Ringwald     channel->remote_sig_id = L2CAP_SIG_ID_INVALID;
1172da144af5SMatthias Ringwald     channel->local_sig_id = L2CAP_SIG_ID_INVALID;
117338f62777SMatthias Ringwald 
1174da144af5SMatthias Ringwald     return channel;
1175da144af5SMatthias Ringwald }
117609e9d05bSMatthias Ringwald #endif
117709e9d05bSMatthias Ringwald 
117809e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1179da144af5SMatthias Ringwald 
11809077cb15SMatthias Ringwald /**
11819077cb15SMatthias Ringwald  * @brief Creates L2CAP channel to the PSM of a remote device with baseband address. A new baseband connection will be initiated if necessary.
11829077cb15SMatthias Ringwald  * @param packet_handler
11839077cb15SMatthias Ringwald  * @param address
11849077cb15SMatthias Ringwald  * @param psm
11859077cb15SMatthias Ringwald  * @param mtu
11869077cb15SMatthias Ringwald  * @param local_cid
11879077cb15SMatthias Ringwald  */
11889077cb15SMatthias Ringwald 
11899d139fbaSMatthias Ringwald uint8_t l2cap_create_channel(btstack_packet_handler_t channel_packet_handler, bd_addr_t address, uint16_t psm, uint16_t mtu, uint16_t * out_local_cid){
11909d139fbaSMatthias Ringwald     // limit MTU to the size of our outtgoing HCI buffer
11919d139fbaSMatthias Ringwald     uint16_t local_mtu = btstack_min(mtu, l2cap_max_mtu());
1192da144af5SMatthias Ringwald 
11939d139fbaSMatthias Ringwald     log_info("L2CAP_CREATE_CHANNEL addr %s psm 0x%x mtu %u -> local mtu %u", bd_addr_to_str(address), psm, mtu, local_mtu);
1194da144af5SMatthias Ringwald 
1195da144af5SMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(channel_packet_handler, address, BD_ADDR_TYPE_CLASSIC, psm, local_mtu, LEVEL_0);
1196fc64f94aSMatthias Ringwald     if (!channel) {
11979077cb15SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
11989077cb15SMatthias Ringwald     }
11999077cb15SMatthias Ringwald 
12001b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
12011b9cb13dSMatthias Ringwald     channel->mode = L2CAP_CHANNEL_MODE_BASIC;
12021b9cb13dSMatthias Ringwald #endif
12031b9cb13dSMatthias Ringwald 
12049077cb15SMatthias Ringwald     // add to connections list
1205fc64f94aSMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
12069077cb15SMatthias Ringwald 
12079077cb15SMatthias Ringwald     // store local_cid
12089077cb15SMatthias Ringwald     if (out_local_cid){
1209fc64f94aSMatthias Ringwald        *out_local_cid = channel->local_cid;
12109077cb15SMatthias Ringwald     }
12119077cb15SMatthias Ringwald 
12129077cb15SMatthias Ringwald     // check if hci connection is already usable
12139077cb15SMatthias Ringwald     hci_connection_t * conn = hci_connection_for_bd_addr_and_type(address, BD_ADDR_TYPE_CLASSIC);
12149077cb15SMatthias Ringwald     if (conn){
1215add0254bSMatthias Ringwald         log_info("l2cap_create_channel, hci connection already exists");
1216fc64f94aSMatthias Ringwald         l2cap_handle_connection_complete(conn->con_handle, channel);
12179077cb15SMatthias Ringwald         // check if remote supported fearures are already received
12189077cb15SMatthias Ringwald         if (conn->bonding_flags & BONDING_RECEIVED_REMOTE_FEATURES) {
1219fc64f94aSMatthias Ringwald             l2cap_handle_remote_supported_features_received(channel);
12209077cb15SMatthias Ringwald         }
12219077cb15SMatthias Ringwald     }
12229077cb15SMatthias Ringwald 
12239077cb15SMatthias Ringwald     l2cap_run();
12249077cb15SMatthias Ringwald 
12259077cb15SMatthias Ringwald     return 0;
12269077cb15SMatthias Ringwald }
12279077cb15SMatthias Ringwald 
12281b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
12297b181629SMatthias Ringwald 
12302b70d705SMatthias Ringwald static uint8_t l2cap_ertm_validate_local_config(uint8_t max_transmit, uint16_t retransmission_timeout_ms,
12312b70d705SMatthias Ringwald     uint16_t monitor_timeout_ms, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size){
12322b70d705SMatthias Ringwald     UNUSED(buffer);
12332b70d705SMatthias Ringwald     UNUSED(size);
12342b70d705SMatthias Ringwald 
12352b70d705SMatthias Ringwald     uint8_t result = ERROR_CODE_SUCCESS;
12362b70d705SMatthias Ringwald     if (max_transmit < 1){
12372b70d705SMatthias Ringwald         log_error("max_transmit must be >= 1");
12382b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
12392b70d705SMatthias Ringwald     }
12402b70d705SMatthias Ringwald     if (retransmission_timeout_ms < 2000){
12412b70d705SMatthias Ringwald         log_error("retransmission_timeout_ms must be >= 2000 ms");
12422b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
12432b70d705SMatthias Ringwald     }
12442b70d705SMatthias Ringwald     if (monitor_timeout_ms < 12000){
12452b70d705SMatthias Ringwald         log_error("monitor_timeout_ms must be >= 12000 ms");
12462b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
12472b70d705SMatthias Ringwald     }
12482b70d705SMatthias Ringwald     if (num_rx_buffers < 1){
12492b70d705SMatthias Ringwald         log_error("num_rx_buffers must be >= 1");
12502b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
12512b70d705SMatthias Ringwald     }
12522b70d705SMatthias Ringwald     if (num_tx_buffers < 1){
12532b70d705SMatthias Ringwald         log_error("num_rx_buffers must be >= 1");
12542b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
12552b70d705SMatthias Ringwald     }
12562b70d705SMatthias Ringwald     return result;
12572b70d705SMatthias Ringwald }
12582b70d705SMatthias Ringwald 
12597b181629SMatthias Ringwald static void l2cap_ertm_configure_channel(l2cap_channel_t * channel, int ertm_mandatory, uint8_t max_transmit,
12607b181629SMatthias Ringwald     uint16_t retransmission_timeout_ms, uint16_t monitor_timeout_ms, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size){
12617b181629SMatthias Ringwald 
12627b181629SMatthias Ringwald     channel->mode  = L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION;
12637b181629SMatthias Ringwald     channel->ertm_mandatory = ertm_mandatory;
1264bbc0a9e7SMatthias Ringwald     channel->local_max_transmit = max_transmit;
1265bbc0a9e7SMatthias Ringwald     channel->local_retransmission_timeout_ms = retransmission_timeout_ms;
1266bbc0a9e7SMatthias Ringwald     channel->local_monitor_timeout_ms = monitor_timeout_ms;
12677b181629SMatthias Ringwald     channel->num_rx_buffers = num_rx_buffers;
12687b181629SMatthias Ringwald     channel->num_tx_buffers = num_tx_buffers;
12697b181629SMatthias Ringwald 
12707b181629SMatthias Ringwald     // TODO: align buffer pointer
12717b181629SMatthias Ringwald     uint32_t pos = 0;
12727b181629SMatthias Ringwald     channel->rx_packets_state = (l2cap_ertm_rx_packet_state_t *) &buffer[pos];
12737b181629SMatthias Ringwald     pos += num_rx_buffers * sizeof(l2cap_ertm_rx_packet_state_t);
12747b181629SMatthias Ringwald     channel->tx_packets_state = (l2cap_ertm_tx_packet_state_t *) &buffer[pos];
12757b181629SMatthias Ringwald     pos += num_tx_buffers * sizeof(l2cap_ertm_tx_packet_state_t);
12767b181629SMatthias Ringwald     // calculate MTU
12777b181629SMatthias Ringwald     channel->local_mtu = (size - pos) / (num_rx_buffers + num_tx_buffers);
12787b181629SMatthias Ringwald     log_info("Local ERTM MTU: %u", channel->local_mtu);
12797b181629SMatthias Ringwald     channel->rx_packets_data = &buffer[pos];
12807b181629SMatthias Ringwald     pos += num_rx_buffers * channel->local_mtu;
12817b181629SMatthias Ringwald     channel->tx_packets_data = &buffer[pos];
12827b181629SMatthias Ringwald     log_info("RX packets %p, TX packets %p", channel->rx_packets_data, channel->tx_packets_data);
12837b181629SMatthias Ringwald }
12847b181629SMatthias Ringwald 
1285501329faSMatthias Ringwald uint8_t l2cap_create_ertm_channel(btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm,
1286501329faSMatthias Ringwald     int ertm_mandatory, uint8_t max_transmit, uint16_t retransmission_timeout_ms, uint16_t monitor_timeout_ms,
1287501329faSMatthias Ringwald     uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size, uint16_t * out_local_cid){
1288501329faSMatthias Ringwald 
12891b9cb13dSMatthias Ringwald     // limit MTU to the size of our outtgoing HCI buffer
1290501329faSMatthias Ringwald     uint16_t local_mtu = l2cap_max_mtu();
12911b9cb13dSMatthias Ringwald 
1292501329faSMatthias Ringwald     log_info("L2CAP_CREATE_CHANNEL addr %s psm 0x%x -> local mtu %u", bd_addr_to_str(address), psm, local_mtu);
12931b9cb13dSMatthias Ringwald 
12942b70d705SMatthias Ringwald     // validate local config
12952b70d705SMatthias Ringwald     uint8_t result = l2cap_ertm_validate_local_config(max_transmit, retransmission_timeout_ms, monitor_timeout_ms, num_tx_buffers, num_rx_buffers, buffer, size);
12962b70d705SMatthias Ringwald     if (result) return result;
12972b70d705SMatthias Ringwald 
1298501329faSMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(packet_handler, address, BD_ADDR_TYPE_CLASSIC, psm, local_mtu, LEVEL_0);
12991b9cb13dSMatthias Ringwald     if (!channel) {
13001b9cb13dSMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
13011b9cb13dSMatthias Ringwald     }
13021b9cb13dSMatthias Ringwald 
13037b181629SMatthias Ringwald     // configure ERTM
13047b181629SMatthias Ringwald     l2cap_ertm_configure_channel(channel, ertm_mandatory, max_transmit, retransmission_timeout_ms,
13057b181629SMatthias Ringwald         monitor_timeout_ms, num_tx_buffers, num_rx_buffers, buffer, size);
13061b9cb13dSMatthias Ringwald 
13071b9cb13dSMatthias Ringwald     // add to connections list
13081b9cb13dSMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
13091b9cb13dSMatthias Ringwald 
13101b9cb13dSMatthias Ringwald     // store local_cid
13111b9cb13dSMatthias Ringwald     if (out_local_cid){
13121b9cb13dSMatthias Ringwald        *out_local_cid = channel->local_cid;
13131b9cb13dSMatthias Ringwald     }
13141b9cb13dSMatthias Ringwald 
13151b9cb13dSMatthias Ringwald     // check if hci connection is already usable
13161b9cb13dSMatthias Ringwald     hci_connection_t * conn = hci_connection_for_bd_addr_and_type(address, BD_ADDR_TYPE_CLASSIC);
13171b9cb13dSMatthias Ringwald     if (conn){
13181b9cb13dSMatthias Ringwald         log_info("l2cap_create_channel, hci connection already exists");
13191b9cb13dSMatthias Ringwald         l2cap_handle_connection_complete(conn->con_handle, channel);
13201b9cb13dSMatthias Ringwald         // check if remote supported fearures are already received
13211b9cb13dSMatthias Ringwald         if (conn->bonding_flags & BONDING_RECEIVED_REMOTE_FEATURES) {
13221b9cb13dSMatthias Ringwald             l2cap_handle_remote_supported_features_received(channel);
13231b9cb13dSMatthias Ringwald         }
13241b9cb13dSMatthias Ringwald     }
13251b9cb13dSMatthias Ringwald 
13261b9cb13dSMatthias Ringwald     l2cap_run();
13271b9cb13dSMatthias Ringwald 
13281b9cb13dSMatthias Ringwald     return 0;
13291b9cb13dSMatthias Ringwald }
13301b9cb13dSMatthias Ringwald #endif
13311b9cb13dSMatthias Ringwald 
1332ce8f182eSMatthias Ringwald void
1333ce8f182eSMatthias Ringwald l2cap_disconnect(uint16_t local_cid, uint8_t reason){
1334e0abb8e7S[email protected]     log_info("L2CAP_DISCONNECT local_cid 0x%x reason 0x%x", local_cid, reason);
1335b35f641cSmatthias.ringwald     // find channel for local_cid
1336b35f641cSmatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
1337f62db1e3Smatthias.ringwald     if (channel) {
1338e7ff783cSmatthias.ringwald         channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
1339f62db1e3Smatthias.ringwald     }
13402cd0be45Smatthias.ringwald     // process
13412cd0be45Smatthias.ringwald     l2cap_run();
134243625864Smatthias.ringwald }
13431e6aba47Smatthias.ringwald 
1344afde0c52Smatthias.ringwald static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t status){
1345665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1346665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
1347665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1348665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1349058e3d6bSMatthias Ringwald         if ( bd_addr_cmp( channel->address, address) != 0) continue;
1350c22aecc9S[email protected]         // channel for this address found
1351c22aecc9S[email protected]         switch (channel->state){
1352c22aecc9S[email protected]             case L2CAP_STATE_WAIT_CONNECTION_COMPLETE:
1353c22aecc9S[email protected]             case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
1354afde0c52Smatthias.ringwald                 // failure, forward error code
1355afde0c52Smatthias.ringwald                 l2cap_emit_channel_opened(channel, status);
1356afde0c52Smatthias.ringwald                 // discard channel
13579dcb2fb2S[email protected]                 l2cap_stop_rtx(channel);
1358665d90f2SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1359d3a9df87Smatthias.ringwald                 btstack_memory_l2cap_channel_free(channel);
1360c22aecc9S[email protected]                 break;
1361c22aecc9S[email protected]             default:
1362c22aecc9S[email protected]                 break;
1363afde0c52Smatthias.ringwald         }
1364afde0c52Smatthias.ringwald     }
1365afde0c52Smatthias.ringwald }
1366afde0c52Smatthias.ringwald 
1367afde0c52Smatthias.ringwald static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t handle){
1368665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1369665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
1370665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1371665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1372058e3d6bSMatthias Ringwald         if ( ! bd_addr_cmp( channel->address, address) ){
13732df5dadcS[email protected]             l2cap_handle_connection_complete(handle, channel);
1374afde0c52Smatthias.ringwald         }
1375afde0c52Smatthias.ringwald     }
13766fdcc387Smatthias.ringwald     // process
13776fdcc387Smatthias.ringwald     l2cap_run();
1378afde0c52Smatthias.ringwald }
137909e9d05bSMatthias Ringwald #endif
1380b448a0e7Smatthias.ringwald 
138133c40538SMatthias Ringwald static void l2cap_notify_channel_can_send(void){
138209e9d05bSMatthias Ringwald 
138309e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
138433c40538SMatthias Ringwald     btstack_linked_list_iterator_t it;
138533c40538SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
138633c40538SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
138733c40538SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
138833c40538SMatthias Ringwald         if (!channel->waiting_for_can_send_now) continue;
1389fc64f94aSMatthias Ringwald         if (!hci_can_send_acl_packet_now(channel->con_handle)) continue;
139033c40538SMatthias Ringwald         channel->waiting_for_can_send_now = 0;
139134e7e577SMatthias Ringwald         l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid);
139233c40538SMatthias Ringwald     }
139309e9d05bSMatthias Ringwald #endif
139444276248SMatthias Ringwald 
13952125de09SMatthias Ringwald     int i;
13962125de09SMatthias Ringwald     for (i=0;i<L2CAP_FIXED_CHANNEL_TABLE_SIZE;i++){
1397773c4106SMatthias Ringwald         if (!fixed_channels[i].callback) continue;
13982125de09SMatthias Ringwald         if (!fixed_channels[i].waiting_for_can_send_now) continue;
139935454696SMatthias Ringwald         int can_send = 0;
140034e7e577SMatthias Ringwald         if (l2cap_fixed_channel_table_index_is_le(i)){
140135454696SMatthias Ringwald #ifdef ENABLE_BLE
140234e7e577SMatthias Ringwald             can_send = hci_can_send_acl_le_packet_now();
140335454696SMatthias Ringwald #endif
140434e7e577SMatthias Ringwald         } else {
140535454696SMatthias Ringwald #ifdef ENABLE_CLASSIC
140634e7e577SMatthias Ringwald             can_send = hci_can_send_acl_classic_packet_now();
140735454696SMatthias Ringwald #endif
140834e7e577SMatthias Ringwald         }
140934e7e577SMatthias Ringwald         if (!can_send) continue;
141034e7e577SMatthias Ringwald         fixed_channels[i].waiting_for_can_send_now = 0;
141134e7e577SMatthias Ringwald         l2cap_emit_can_send_now(fixed_channels[i].callback, l2cap_fixed_channel_table_channel_id_for_index(i));
14122125de09SMatthias Ringwald     }
141333c40538SMatthias Ringwald }
141433c40538SMatthias Ringwald 
1415d9a7306aSMatthias Ringwald static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *packet, uint16_t size){
1416afde0c52Smatthias.ringwald 
14179ec2630cSMatthias Ringwald     UNUSED(packet_type);
14189ec2630cSMatthias Ringwald     UNUSED(cid);
14199ec2630cSMatthias Ringwald     UNUSED(size);
14209ec2630cSMatthias Ringwald 
1421afde0c52Smatthias.ringwald     bd_addr_t address;
1422afde0c52Smatthias.ringwald     hci_con_handle_t handle;
14232d00edd4Smatthias.ringwald     int hci_con_used;
142409e9d05bSMatthias Ringwald     btstack_linked_list_iterator_t it;
142509e9d05bSMatthias Ringwald 
142609e9d05bSMatthias Ringwald     // avoid unused warnings
1427f3963406SMatthias Ringwald     UNUSED(address);
1428f3963406SMatthias Ringwald     UNUSED(hci_con_used);
1429f3963406SMatthias Ringwald     UNUSED(it);
1430f22209dfSMatthias Ringwald     UNUSED(handle);
1431afde0c52Smatthias.ringwald 
14320e2df43fSMatthias Ringwald     switch(hci_event_packet_get_type(packet)){
1433afde0c52Smatthias.ringwald 
143409e9d05bSMatthias Ringwald         // Notify channel packet handler if they can send now
143509e9d05bSMatthias Ringwald         case HCI_EVENT_TRANSPORT_PACKET_SENT:
143609e9d05bSMatthias Ringwald         case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
143709e9d05bSMatthias Ringwald             l2cap_run();    // try sending signaling packets first
143809e9d05bSMatthias Ringwald             l2cap_notify_channel_can_send();
143909e9d05bSMatthias Ringwald             break;
144009e9d05bSMatthias Ringwald 
144109e9d05bSMatthias Ringwald         case HCI_EVENT_COMMAND_STATUS:
144209e9d05bSMatthias Ringwald             l2cap_run();    // try sending signaling packets first
144309e9d05bSMatthias Ringwald             break;
144409e9d05bSMatthias Ringwald 
144509e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1446afde0c52Smatthias.ringwald         // handle connection complete events
1447afde0c52Smatthias.ringwald         case HCI_EVENT_CONNECTION_COMPLETE:
1448724d70a2SMatthias Ringwald             reverse_bd_addr(&packet[5], address);
1449afde0c52Smatthias.ringwald             if (packet[2] == 0){
1450f8fbdce0SMatthias Ringwald                 handle = little_endian_read_16(packet, 3);
1451afde0c52Smatthias.ringwald                 l2cap_handle_connection_success_for_addr(address, handle);
1452afde0c52Smatthias.ringwald             } else {
1453afde0c52Smatthias.ringwald                 l2cap_handle_connection_failed_for_addr(address, packet[2]);
1454afde0c52Smatthias.ringwald             }
1455afde0c52Smatthias.ringwald             break;
1456afde0c52Smatthias.ringwald 
1457afde0c52Smatthias.ringwald         // handle successful create connection cancel command
1458afde0c52Smatthias.ringwald         case HCI_EVENT_COMMAND_COMPLETE:
1459073bd0faSMatthias Ringwald             if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_create_connection_cancel)) {
1460afde0c52Smatthias.ringwald                 if (packet[5] == 0){
1461724d70a2SMatthias Ringwald                     reverse_bd_addr(&packet[6], address);
1462afde0c52Smatthias.ringwald                     // CONNECTION TERMINATED BY LOCAL HOST (0X16)
1463afde0c52Smatthias.ringwald                     l2cap_handle_connection_failed_for_addr(address, 0x16);
146403cfbabcSmatthias.ringwald                 }
14651e6aba47Smatthias.ringwald             }
146639d59809Smatthias.ringwald             l2cap_run();    // try sending signaling packets first
146739d59809Smatthias.ringwald             break;
146809e9d05bSMatthias Ringwald #endif
146927a923d0Smatthias.ringwald 
14701e6aba47Smatthias.ringwald         // handle disconnection complete events
1471afde0c52Smatthias.ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
1472c22aecc9S[email protected]             // send l2cap disconnect events for all channels on this handle and free them
147309e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1474d0662982SMatthias Ringwald             handle = little_endian_read_16(packet, 3);
1475665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
1476665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
1477665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1478fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
147915ec09bbSmatthias.ringwald                 l2cap_emit_channel_closed(channel);
14809dcb2fb2S[email protected]                 l2cap_stop_rtx(channel);
1481665d90f2SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1482d3a9df87Smatthias.ringwald                 btstack_memory_l2cap_channel_free(channel);
148327a923d0Smatthias.ringwald             }
148409e9d05bSMatthias Ringwald #endif
1485a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
1486d0662982SMatthias Ringwald             handle = little_endian_read_16(packet, 3);
1487991fea48SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
1488991fea48SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
1489991fea48SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1490991fea48SMatthias Ringwald                 if (channel->con_handle != handle) continue;
1491991fea48SMatthias Ringwald                 l2cap_emit_channel_closed(channel);
1492991fea48SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1493991fea48SMatthias Ringwald                 btstack_memory_l2cap_channel_free(channel);
1494991fea48SMatthias Ringwald             }
1495991fea48SMatthias Ringwald #endif
1496afde0c52Smatthias.ringwald             break;
1497fcadd0caSmatthias.ringwald 
1498ee091cf1Smatthias.ringwald         // HCI Connection Timeouts
149909e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1500afde0c52Smatthias.ringwald         case L2CAP_EVENT_TIMEOUT_CHECK:
1501f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet, 2);
1502bd04d84aSMatthias Ringwald             if (gap_get_connection_type(handle) != GAP_CONNECTION_ACL) break;
150380ca58a0Smatthias.ringwald             if (hci_authentication_active_for_handle(handle)) break;
15042d00edd4Smatthias.ringwald             hci_con_used = 0;
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;
15092d00edd4Smatthias.ringwald                 hci_con_used = 1;
1510c22aecc9S[email protected]                 break;
1511ee091cf1Smatthias.ringwald             }
15122d00edd4Smatthias.ringwald             if (hci_con_used) break;
1513d94d3cafS[email protected]             if (!hci_can_send_command_packet_now()) break;
15149edc8742Smatthias.ringwald             hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection
1515afde0c52Smatthias.ringwald             break;
1516ee091cf1Smatthias.ringwald 
1517df3354fcS[email protected]         case HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE:
1518f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet, 3);
1519665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
1520665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
1521665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1522fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
15232df5dadcS[email protected]                 l2cap_handle_remote_supported_features_received(channel);
1524df3354fcS[email protected]                 break;
1525df3354fcS[email protected]             }
1526c22aecc9S[email protected]             break;
1527df3354fcS[email protected] 
15285611a760SMatthias Ringwald         case GAP_EVENT_SECURITY_LEVEL:
1529f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet, 2);
1530bd63148eS[email protected]             log_info("l2cap - security level update");
1531665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
1532665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
1533665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1534fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
15355533f01eS[email protected] 
1536bd63148eS[email protected]                 log_info("l2cap - state %u", channel->state);
1537bd63148eS[email protected] 
1538e569dfd9SMatthias Ringwald                 gap_security_level_t actual_level = (gap_security_level_t) packet[4];
15395533f01eS[email protected]                 gap_security_level_t required_level = channel->required_security_level;
15405533f01eS[email protected] 
1541df3354fcS[email protected]                 switch (channel->state){
1542df3354fcS[email protected]                     case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE:
15435533f01eS[email protected]                         if (actual_level >= required_level){
154452606043SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
154552606043SMatthias Ringwald                             // we need to know if ERTM is supported before sending a config response
154652606043SMatthias Ringwald                             hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
154752606043SMatthias Ringwald                             connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_W2_SEND_EXTENDED_FEATURE_REQUEST;
154852606043SMatthias Ringwald                             channel->state = L2CAP_STATE_WAIT_INCOMING_EXTENDED_FEATURES;
154952606043SMatthias Ringwald #else
1550f85a9399S[email protected]                             channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
155144276248SMatthias Ringwald                             l2cap_emit_incoming_connection(channel);
155252606043SMatthias Ringwald #endif
15531eb2563eS[email protected]                         } else {
1554775ecc36SMatthias Ringwald                             channel->reason = 0x0003; // security block
15551eb2563eS[email protected]                             channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
15561eb2563eS[email protected]                         }
1557df3354fcS[email protected]                         break;
1558df3354fcS[email protected] 
1559df3354fcS[email protected]                     case L2CAP_STATE_WAIT_OUTGOING_SECURITY_LEVEL_UPDATE:
15605533f01eS[email protected]                         if (actual_level >= required_level){
15611b9cb13dSMatthias Ringwald                             l2cap_ready_to_connect(channel);
1562df3354fcS[email protected]                         } else {
1563df3354fcS[email protected]                             // disconnnect, authentication not good enough
1564df3354fcS[email protected]                             hci_disconnect_security_block(handle);
1565df3354fcS[email protected]                         }
1566df3354fcS[email protected]                         break;
1567df3354fcS[email protected] 
1568df3354fcS[email protected]                     default:
1569df3354fcS[email protected]                         break;
1570df3354fcS[email protected]                 }
1571f85a9399S[email protected]             }
1572f85a9399S[email protected]             break;
157309e9d05bSMatthias Ringwald #endif
1574f85a9399S[email protected] 
1575afde0c52Smatthias.ringwald         default:
1576afde0c52Smatthias.ringwald             break;
1577afde0c52Smatthias.ringwald     }
1578afde0c52Smatthias.ringwald 
1579bd63148eS[email protected]     l2cap_run();
15801e6aba47Smatthias.ringwald }
15811e6aba47Smatthias.ringwald 
1582e74c5f58SMatthias Ringwald static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t cid, uint16_t data){
15834cf56b4aSmatthias.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."
15842b360848Smatthias.ringwald     if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) {
15852b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].handle = handle;
15862b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].code = code;
15872b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].sig_id = sig_id;
1588e74c5f58SMatthias Ringwald         signaling_responses[signaling_responses_pending].cid = cid;
15892b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].data = data;
15902b360848Smatthias.ringwald         signaling_responses_pending++;
15912b360848Smatthias.ringwald         l2cap_run();
15922b360848Smatthias.ringwald     }
15932b360848Smatthias.ringwald }
15942b360848Smatthias.ringwald 
159509e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
159609e9d05bSMatthias Ringwald static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){
159709e9d05bSMatthias Ringwald     channel->remote_sig_id = identifier;
159809e9d05bSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
159909e9d05bSMatthias Ringwald     l2cap_run();
160009e9d05bSMatthias Ringwald }
160109e9d05bSMatthias Ringwald 
1602b35f641cSmatthias.ringwald static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){
1603645658c9Smatthias.ringwald 
16049da54300S[email protected]     // log_info("l2cap_handle_connection_request for handle %u, psm %u cid 0x%02x", handle, psm, source_cid);
1605645658c9Smatthias.ringwald     l2cap_service_t *service = l2cap_get_service(psm);
1606645658c9Smatthias.ringwald     if (!service) {
1607645658c9Smatthias.ringwald         // 0x0002 PSM not supported
1608e74c5f58SMatthias Ringwald         l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, source_cid, 0x0002);
1609645658c9Smatthias.ringwald         return;
1610645658c9Smatthias.ringwald     }
1611645658c9Smatthias.ringwald 
16125061f3afS[email protected]     hci_connection_t * hci_connection = hci_connection_for_handle( handle );
1613645658c9Smatthias.ringwald     if (!hci_connection) {
16142b360848Smatthias.ringwald         //
16159da54300S[email protected]         log_error("no hci_connection for handle %u", handle);
1616645658c9Smatthias.ringwald         return;
1617645658c9Smatthias.ringwald     }
16182bd8b7e7S[email protected] 
1619645658c9Smatthias.ringwald     // alloc structure
16209da54300S[email protected]     // log_info("l2cap_handle_connection_request register channel");
1621da144af5SMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(service->packet_handler, hci_connection->address, BD_ADDR_TYPE_CLASSIC,
1622da144af5SMatthias Ringwald     psm, service->mtu, service->required_security_level);
16232b360848Smatthias.ringwald     if (!channel){
16242b360848Smatthias.ringwald         // 0x0004 No resources available
1625e74c5f58SMatthias Ringwald         l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, source_cid, 0x0004);
16262b360848Smatthias.ringwald         return;
16272b360848Smatthias.ringwald     }
1628da144af5SMatthias Ringwald 
1629fc64f94aSMatthias Ringwald     channel->con_handle = handle;
1630b35f641cSmatthias.ringwald     channel->remote_cid = source_cid;
1631b1988dceSmatthias.ringwald     channel->remote_sig_id = sig_id;
1632645658c9Smatthias.ringwald 
1633f53da564S[email protected]     // limit local mtu to max acl packet length - l2cap header
16342985cb84Smatthias.ringwald     if (channel->local_mtu > l2cap_max_mtu()) {
16352985cb84Smatthias.ringwald         channel->local_mtu = l2cap_max_mtu();
16369775e25bSmatthias.ringwald     }
16379775e25bSmatthias.ringwald 
1638645658c9Smatthias.ringwald     // set initial state
1639df3354fcS[email protected]     channel->state =      L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE;
1640a24785d0SMatthias Ringwald     channel->state_var  = (L2CAP_CHANNEL_STATE_VAR) (L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND | L2CAP_CHANNEL_STATE_VAR_INCOMING);
1641e405ae81Smatthias.ringwald 
1642645658c9Smatthias.ringwald     // add to connections list
1643665d90f2SMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
1644645658c9Smatthias.ringwald 
1645f85a9399S[email protected]     // assert security requirements
16461eb2563eS[email protected]     gap_request_security_level(handle, channel->required_security_level);
1647e405ae81Smatthias.ringwald }
1648645658c9Smatthias.ringwald 
1649ce8f182eSMatthias Ringwald void l2cap_accept_connection(uint16_t local_cid){
1650e0abb8e7S[email protected]     log_info("L2CAP_ACCEPT_CONNECTION local_cid 0x%x", local_cid);
1651b35f641cSmatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
1652e405ae81Smatthias.ringwald     if (!channel) {
1653ce8f182eSMatthias Ringwald         log_error("l2cap_accept_connection called but local_cid 0x%x not found", local_cid);
1654e405ae81Smatthias.ringwald         return;
1655e405ae81Smatthias.ringwald     }
1656e405ae81Smatthias.ringwald 
165743ec931dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
165843ec931dSMatthias Ringwald     // configure L2CAP Basic mode
165943ec931dSMatthias Ringwald     channel->mode  = L2CAP_CHANNEL_MODE_BASIC;
166043ec931dSMatthias Ringwald #endif
166143ec931dSMatthias Ringwald 
1662552d92a1Smatthias.ringwald     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
1663e405ae81Smatthias.ringwald 
1664552d92a1Smatthias.ringwald     // process
1665552d92a1Smatthias.ringwald     l2cap_run();
1666e405ae81Smatthias.ringwald }
1667645658c9Smatthias.ringwald 
166843ec931dSMatthias Ringwald 
166943ec931dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
16702b70d705SMatthias Ringwald uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, int ertm_mandatory, uint8_t max_transmit,
1671501329faSMatthias Ringwald     uint16_t retransmission_timeout_ms, uint16_t monitor_timeout_ms, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size){
1672501329faSMatthias Ringwald 
167343ec931dSMatthias Ringwald     log_info("L2CAP_ACCEPT_ERTM_CONNECTION local_cid 0x%x", local_cid);
167443ec931dSMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
167543ec931dSMatthias Ringwald     if (!channel) {
167643ec931dSMatthias Ringwald         log_error("l2cap_accept_connection called but local_cid 0x%x not found", local_cid);
16772b70d705SMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
167843ec931dSMatthias Ringwald     }
167943ec931dSMatthias Ringwald 
16802b70d705SMatthias Ringwald     // validate local config
16812b70d705SMatthias Ringwald     uint8_t result = l2cap_ertm_validate_local_config(max_transmit, retransmission_timeout_ms, monitor_timeout_ms, num_tx_buffers, num_rx_buffers, buffer, size);
16822b70d705SMatthias Ringwald     if (result) return result;
16832b70d705SMatthias Ringwald 
168443ec931dSMatthias Ringwald     // configure L2CAP ERTM
16857b181629SMatthias Ringwald     l2cap_ertm_configure_channel(channel, ertm_mandatory, max_transmit, retransmission_timeout_ms, monitor_timeout_ms, num_tx_buffers, num_rx_buffers, buffer, size);
168643ec931dSMatthias Ringwald 
16877b181629SMatthias Ringwald     // continue
168843ec931dSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
168943ec931dSMatthias Ringwald 
169043ec931dSMatthias Ringwald     // process
169143ec931dSMatthias Ringwald     l2cap_run();
16922b70d705SMatthias Ringwald 
16932b70d705SMatthias Ringwald     return ERROR_CODE_SUCCESS;
169443ec931dSMatthias Ringwald }
169543ec931dSMatthias Ringwald #endif
169643ec931dSMatthias Ringwald 
169743ec931dSMatthias Ringwald 
16987ef6a7bbSMatthias Ringwald void l2cap_decline_connection(uint16_t local_cid){
16997ef6a7bbSMatthias Ringwald     log_info("L2CAP_DECLINE_CONNECTION local_cid 0x%x", local_cid);
1700b35f641cSmatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
1701e405ae81Smatthias.ringwald     if (!channel) {
1702ce8f182eSMatthias Ringwald         log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
1703e405ae81Smatthias.ringwald         return;
1704e405ae81Smatthias.ringwald     }
1705e7ff783cSmatthias.ringwald     channel->state  = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
17067ef6a7bbSMatthias Ringwald     channel->reason = 0x04; // no resources available
1707e7ff783cSmatthias.ringwald     l2cap_run();
1708645658c9Smatthias.ringwald }
1709645658c9Smatthias.ringwald 
17107f02f414SMatthias Ringwald static void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t *command){
1711b1988dceSmatthias.ringwald 
1712b1988dceSmatthias.ringwald     channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
1713b1988dceSmatthias.ringwald 
1714f8fbdce0SMatthias Ringwald     uint16_t flags = little_endian_read_16(command, 6);
171563a7246aSmatthias.ringwald     if (flags & 1) {
171663a7246aSmatthias.ringwald         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT);
171763a7246aSmatthias.ringwald     }
171863a7246aSmatthias.ringwald 
17192784b77dSmatthias.ringwald     // accept the other's configuration options
1720f8fbdce0SMatthias Ringwald     uint16_t end_pos = 4 + little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
17213de7c0caSmatthias.ringwald     uint16_t pos     = 8;
17223de7c0caSmatthias.ringwald     while (pos < end_pos){
172363a7246aSmatthias.ringwald         uint8_t option_hint = command[pos] >> 7;
172463a7246aSmatthias.ringwald         uint8_t option_type = command[pos] & 0x7f;
172563a7246aSmatthias.ringwald         log_info("l2cap cid %u, hint %u, type %u", channel->local_cid, option_hint, option_type);
172663a7246aSmatthias.ringwald         pos++;
17271dc511deSmatthias.ringwald         uint8_t length = command[pos++];
17281dc511deSmatthias.ringwald         // MTU { type(8): 1, len(8):2, MTU(16) }
172963a7246aSmatthias.ringwald         if (option_type == 1 && length == 2){
1730f8fbdce0SMatthias Ringwald             channel->remote_mtu = little_endian_read_16(command, pos);
17319d139fbaSMatthias Ringwald             if (channel->remote_mtu > l2cap_max_mtu()){
17329d139fbaSMatthias Ringwald                 log_info("Remote MTU %u larger than outgoing buffer, only using MTU = %u", channel->remote_mtu, l2cap_max_mtu());
17339d139fbaSMatthias Ringwald                 channel->remote_mtu = l2cap_max_mtu();
17349d139fbaSMatthias Ringwald             }
173563a7246aSmatthias.ringwald             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
173663a7246aSmatthias.ringwald         }
17370fe7a9d0S[email protected]         // Flush timeout { type(8):2, len(8): 2, Flush Timeout(16)}
17380fe7a9d0S[email protected]         if (option_type == 2 && length == 2){
1739f8fbdce0SMatthias Ringwald             channel->flush_timeout = little_endian_read_16(command, pos);
17400fe7a9d0S[email protected]         }
1741f2fa388dSMatthias Ringwald 
17426dca2a0cSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
17436dca2a0cSMatthias Ringwald         // Retransmission and Flow Control Option
17446dca2a0cSMatthias Ringwald         if (option_type == 4 && length == 9){
17453232a1c6SMatthias Ringwald             l2cap_channel_mode_t mode = (l2cap_channel_mode_t) command[pos];
1746ac8f1300SMatthias Ringwald             switch(channel->mode){
1747ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION:
174825cd60d3SMatthias Ringwald                     // Store remote config
1749bbc0a9e7SMatthias Ringwald                     channel->remote_tx_window_size = command[pos+1];
1750bbc0a9e7SMatthias Ringwald                     channel->remote_max_transmit   = command[pos+2];
1751bbc0a9e7SMatthias Ringwald                     channel->remote_retransmission_timeout_ms = little_endian_read_16(command, pos + 3);
1752bbc0a9e7SMatthias Ringwald                     channel->remote_monitor_timeout_ms = little_endian_read_16(command, pos + 5);
1753bbc0a9e7SMatthias Ringwald                     log_info("FC&C config: tx window: %u, max transmit %u, retrans timeout %u, monitor timeout %u",
1754bbc0a9e7SMatthias Ringwald                         channel->remote_tx_window_size,
1755bbc0a9e7SMatthias Ringwald                         channel->remote_max_transmit,
1756bbc0a9e7SMatthias Ringwald                         channel->remote_retransmission_timeout_ms,
1757bbc0a9e7SMatthias Ringwald                         channel->remote_monitor_timeout_ms);
1758bbc0a9e7SMatthias Ringwald                     // we store remote MPS in remote_mtu, might need to get re-evaluated
1759bbc0a9e7SMatthias Ringwald                     channel->remote_mtu = little_endian_read_16(command, pos + 7);
176025cd60d3SMatthias Ringwald                     // If ERTM mandatory, but remote doens't offer ERTM -> disconnect
176125cd60d3SMatthias Ringwald                     if (channel->ertm_mandatory && mode != L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
176225cd60d3SMatthias Ringwald                         channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
1763ac8f1300SMatthias Ringwald                     } else {
1764ac8f1300SMatthias Ringwald                         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
1765ac8f1300SMatthias Ringwald                     }
1766ac8f1300SMatthias Ringwald                     break;
1767ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_BASIC:
1768ac8f1300SMatthias Ringwald                     switch (mode){
1769ac8f1300SMatthias Ringwald                         case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION:
1770ac8f1300SMatthias Ringwald                             // remote asks for ERTM, but we want basic mode. disconnect if this happens a second time
1771ac8f1300SMatthias Ringwald                             if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_BASIC_FALLBACK_TRIED){
1772ac8f1300SMatthias Ringwald                                 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
1773ac8f1300SMatthias Ringwald                             }
1774ac8f1300SMatthias Ringwald                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_BASIC_FALLBACK_TRIED);
1775ac8f1300SMatthias Ringwald                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED);
1776ac8f1300SMatthias Ringwald                             break;
1777ac8f1300SMatthias Ringwald                         default: // case L2CAP_CHANNEL_MODE_BASIC:
1778ac8f1300SMatthias Ringwald                             // TODO store and evaluate configuration
1779ac8f1300SMatthias Ringwald                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
1780ac8f1300SMatthias Ringwald                             break;
1781ac8f1300SMatthias Ringwald                     }
1782ac8f1300SMatthias Ringwald                     break;
1783ac8f1300SMatthias Ringwald                 default:
1784ac8f1300SMatthias Ringwald                     break;
1785ac8f1300SMatthias Ringwald             }
17863232a1c6SMatthias Ringwald         }
17876dca2a0cSMatthias Ringwald #endif
178863a7246aSmatthias.ringwald         // check for unknown options
178963a7246aSmatthias.ringwald         if (option_hint == 0 && (option_type == 0 || option_type >= 0x07)){
1790c177a91cS[email protected]             log_info("l2cap cid %u, unknown options", channel->local_cid);
179163a7246aSmatthias.ringwald             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID);
17921dc511deSmatthias.ringwald         }
17931dc511deSmatthias.ringwald         pos += length;
17941dc511deSmatthias.ringwald     }
17952784b77dSmatthias.ringwald }
17962784b77dSmatthias.ringwald 
1797f2fa388dSMatthias Ringwald static void l2cap_signaling_handle_configure_response(l2cap_channel_t *channel, uint8_t result, uint8_t *command){
1798f2fa388dSMatthias Ringwald     log_info("l2cap_signaling_handle_configure_response");
17993232a1c6SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
18003232a1c6SMatthias Ringwald     uint16_t end_pos = 4 + little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
1801f2fa388dSMatthias Ringwald     uint16_t pos     = 10;
18023232a1c6SMatthias Ringwald     while (pos < end_pos){
18033232a1c6SMatthias Ringwald         uint8_t option_hint = command[pos] >> 7;
18043232a1c6SMatthias Ringwald         uint8_t option_type = command[pos] & 0x7f;
18053232a1c6SMatthias Ringwald         log_info("l2cap cid %u, hint %u, type %u", channel->local_cid, option_hint, option_type);
18063232a1c6SMatthias Ringwald         pos++;
18073232a1c6SMatthias Ringwald         uint8_t length = command[pos++];
18083232a1c6SMatthias Ringwald 
18093232a1c6SMatthias Ringwald         // Retransmission and Flow Control Option
18103232a1c6SMatthias Ringwald         if (option_type == 4 && length == 9){
1811ac8f1300SMatthias Ringwald             switch (channel->mode){
1812ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION:
1813f2fa388dSMatthias Ringwald                     if (channel->ertm_mandatory){
1814ac8f1300SMatthias Ringwald                         // ??
1815f2fa388dSMatthias Ringwald                     } else {
1816ac8f1300SMatthias Ringwald                         // On 'Reject - Unacceptable Parameters' to our optional ERTM request, fall back to BASIC mode
1817ac8f1300SMatthias Ringwald                         if (result == L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS){
1818f2fa388dSMatthias Ringwald                             channel->mode = L2CAP_CHANNEL_MODE_BASIC;
18193232a1c6SMatthias Ringwald                         }
18203232a1c6SMatthias Ringwald                     }
1821ac8f1300SMatthias Ringwald                     break;
1822ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_BASIC:
1823ac8f1300SMatthias Ringwald                     if (result == L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS){
1824ac8f1300SMatthias Ringwald                         // On 'Reject - Unacceptable Parameters' to our Basic mode request, disconnect
1825ac8f1300SMatthias Ringwald                         channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
1826ac8f1300SMatthias Ringwald                     }
1827ac8f1300SMatthias Ringwald                     break;
1828ac8f1300SMatthias Ringwald                 default:
1829ac8f1300SMatthias Ringwald                     break;
18303232a1c6SMatthias Ringwald             }
1831f2fa388dSMatthias Ringwald         }
18323232a1c6SMatthias Ringwald 
18333232a1c6SMatthias Ringwald         // check for unknown options
18343232a1c6SMatthias Ringwald         if (option_hint == 0 && (option_type == 0 || option_type >= 0x07)){
18353232a1c6SMatthias Ringwald             log_info("l2cap cid %u, unknown options", channel->local_cid);
18363232a1c6SMatthias Ringwald             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID);
18373232a1c6SMatthias Ringwald         }
18383232a1c6SMatthias Ringwald 
18393232a1c6SMatthias Ringwald         pos += length;
18403232a1c6SMatthias Ringwald     }
18413232a1c6SMatthias Ringwald #endif
18423232a1c6SMatthias Ringwald }
18433232a1c6SMatthias Ringwald 
1844fa8473a4Smatthias.ringwald static int l2cap_channel_ready_for_open(l2cap_channel_t *channel){
18459da54300S[email protected]     // log_info("l2cap_channel_ready_for_open 0x%02x", channel->state_var);
184673cf2b3dSmatthias.ringwald     if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP) == 0) return 0;
184773cf2b3dSmatthias.ringwald     if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP) == 0) return 0;
1848019f9b43SMatthias Ringwald     // addition check that fixes re-entrance issue causing l2cap event channel opened twice
1849019f9b43SMatthias Ringwald     if (channel->state == L2CAP_STATE_OPEN) return 0;
1850fa8473a4Smatthias.ringwald     return 1;
1851fa8473a4Smatthias.ringwald }
1852fa8473a4Smatthias.ringwald 
1853fa8473a4Smatthias.ringwald 
18547f02f414SMatthias Ringwald static void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){
18551e6aba47Smatthias.ringwald 
185600d93d79Smatthias.ringwald     uint8_t  code       = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
185700d93d79Smatthias.ringwald     uint8_t  identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
185838e5900eSmatthias.ringwald     uint16_t result = 0;
18591e6aba47Smatthias.ringwald 
18609da54300S[email protected]     log_info("L2CAP signaling handler code %u, state %u", code, channel->state);
1861b35f641cSmatthias.ringwald 
18629a011532Smatthias.ringwald     // handle DISCONNECT REQUESTS seperately
18639a011532Smatthias.ringwald     if (code == DISCONNECTION_REQUEST){
18649a011532Smatthias.ringwald         switch (channel->state){
1865fa8473a4Smatthias.ringwald             case L2CAP_STATE_CONFIG:
18669a011532Smatthias.ringwald             case L2CAP_STATE_OPEN:
18672b83fb7dSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
18689a011532Smatthias.ringwald             case L2CAP_STATE_WAIT_DISCONNECT:
18699a011532Smatthias.ringwald                 l2cap_handle_disconnect_request(channel, identifier);
18709a011532Smatthias.ringwald                 break;
18719a011532Smatthias.ringwald 
18729a011532Smatthias.ringwald             default:
18739a011532Smatthias.ringwald                 // ignore in other states
18749a011532Smatthias.ringwald                 break;
18759a011532Smatthias.ringwald         }
18769a011532Smatthias.ringwald         return;
18779a011532Smatthias.ringwald     }
18789a011532Smatthias.ringwald 
187956081214Smatthias.ringwald     // @STATEMACHINE(l2cap)
18801e6aba47Smatthias.ringwald     switch (channel->state) {
18811e6aba47Smatthias.ringwald 
18821e6aba47Smatthias.ringwald         case L2CAP_STATE_WAIT_CONNECT_RSP:
18831e6aba47Smatthias.ringwald             switch (code){
18841e6aba47Smatthias.ringwald                 case CONNECTION_RESPONSE:
18855932bd7cS[email protected]                     l2cap_stop_rtx(channel);
1886f8fbdce0SMatthias Ringwald                     result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
188738e5900eSmatthias.ringwald                     switch (result) {
188838e5900eSmatthias.ringwald                         case 0:
1889169f8b28Smatthias.ringwald                             // successful connection
1890f8fbdce0SMatthias Ringwald                             channel->remote_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
1891fa8473a4Smatthias.ringwald                             channel->state = L2CAP_STATE_CONFIG;
189228ca2b46S[email protected]                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
189338e5900eSmatthias.ringwald                             break;
189438e5900eSmatthias.ringwald                         case 1:
18955932bd7cS[email protected]                             // connection pending. get some coffee, but start the ERTX
18965932bd7cS[email protected]                             l2cap_start_ertx(channel);
189738e5900eSmatthias.ringwald                             break;
189838e5900eSmatthias.ringwald                         default:
1899eb920dbeSmatthias.ringwald                             // channel closed
1900eb920dbeSmatthias.ringwald                             channel->state = L2CAP_STATE_CLOSED;
1901f32b992eSmatthias.ringwald                             // map l2cap connection response result to BTstack status enumeration
190238e5900eSmatthias.ringwald                             l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result);
1903eb920dbeSmatthias.ringwald 
1904eb920dbeSmatthias.ringwald                             // drop link key if security block
1905eb920dbeSmatthias.ringwald                             if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){
190615a95bd5SMatthias Ringwald                                 gap_drop_link_key_for_bd_addr(channel->address);
1907eb920dbeSmatthias.ringwald                             }
1908eb920dbeSmatthias.ringwald 
1909eb920dbeSmatthias.ringwald                             // discard channel
1910665d90f2SMatthias Ringwald                             btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
1911d3a9df87Smatthias.ringwald                             btstack_memory_l2cap_channel_free(channel);
191238e5900eSmatthias.ringwald                             break;
19131e6aba47Smatthias.ringwald                     }
19141e6aba47Smatthias.ringwald                     break;
191538e5900eSmatthias.ringwald 
191638e5900eSmatthias.ringwald                 default:
19171e6aba47Smatthias.ringwald                     //@TODO: implement other signaling packets
191838e5900eSmatthias.ringwald                     break;
19191e6aba47Smatthias.ringwald             }
19201e6aba47Smatthias.ringwald             break;
19211e6aba47Smatthias.ringwald 
1922fa8473a4Smatthias.ringwald         case L2CAP_STATE_CONFIG:
1923f8fbdce0SMatthias Ringwald             result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
1924ae280e73Smatthias.ringwald             switch (code) {
1925ae280e73Smatthias.ringwald                 case CONFIGURE_REQUEST:
192628ca2b46S[email protected]                     channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
1927ae280e73Smatthias.ringwald                     l2cap_signaling_handle_configure_request(channel, command);
192863a7246aSmatthias.ringwald                     if (!(channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT)){
192963a7246aSmatthias.ringwald                         // only done if continuation not set
193063a7246aSmatthias.ringwald                         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
193163a7246aSmatthias.ringwald                     }
1932ae280e73Smatthias.ringwald                     break;
19331e6aba47Smatthias.ringwald                 case CONFIGURE_RESPONSE:
19345932bd7cS[email protected]                     l2cap_stop_rtx(channel);
1935f2fa388dSMatthias Ringwald                     l2cap_signaling_handle_configure_response(channel, result, command);
19365932bd7cS[email protected]                     switch (result){
19375932bd7cS[email protected]                         case 0: // success
19385932bd7cS[email protected]                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
19395932bd7cS[email protected]                             break;
19405932bd7cS[email protected]                         case 4: // pending
19415932bd7cS[email protected]                             l2cap_start_ertx(channel);
19425932bd7cS[email protected]                             break;
19435932bd7cS[email protected]                         default:
1944a32d6a03SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
1945a32d6a03SMatthias Ringwald                             if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION && channel->ertm_mandatory){
1946a32d6a03SMatthias Ringwald                                 // remote does not offer ertm but it's required
1947a32d6a03SMatthias Ringwald                                 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
1948a32d6a03SMatthias Ringwald                                 break;
1949a32d6a03SMatthias Ringwald                             }
1950a32d6a03SMatthias Ringwald #endif
1951fe9d8984S[email protected]                             // retry on negative result
1952fe9d8984S[email protected]                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
1953fe9d8984S[email protected]                             break;
1954fe9d8984S[email protected]                     }
19555a67bd4aSmatthias.ringwald                     break;
19565a67bd4aSmatthias.ringwald                 default:
19575a67bd4aSmatthias.ringwald                     break;
19581e6aba47Smatthias.ringwald             }
1959fa8473a4Smatthias.ringwald             if (l2cap_channel_ready_for_open(channel)){
1960fa8473a4Smatthias.ringwald                 // for open:
19615a67bd4aSmatthias.ringwald                 channel->state = L2CAP_STATE_OPEN;
1962fa8473a4Smatthias.ringwald                 l2cap_emit_channel_opened(channel, 0);
1963c8e4258aSmatthias.ringwald             }
1964c8e4258aSmatthias.ringwald             break;
1965f62db1e3Smatthias.ringwald 
1966f62db1e3Smatthias.ringwald         case L2CAP_STATE_WAIT_DISCONNECT:
1967f62db1e3Smatthias.ringwald             switch (code) {
1968f62db1e3Smatthias.ringwald                 case DISCONNECTION_RESPONSE:
196927a923d0Smatthias.ringwald                     l2cap_finialize_channel_close(channel);
197027a923d0Smatthias.ringwald                     break;
19715a67bd4aSmatthias.ringwald                 default:
19725a67bd4aSmatthias.ringwald                     //@TODO: implement other signaling packets
19735a67bd4aSmatthias.ringwald                     break;
197427a923d0Smatthias.ringwald             }
197527a923d0Smatthias.ringwald             break;
197684836b65Smatthias.ringwald 
197784836b65Smatthias.ringwald         case L2CAP_STATE_CLOSED:
197884836b65Smatthias.ringwald             // @TODO handle incoming requests
197984836b65Smatthias.ringwald             break;
198084836b65Smatthias.ringwald 
198184836b65Smatthias.ringwald         case L2CAP_STATE_OPEN:
198284836b65Smatthias.ringwald             //@TODO: implement other signaling packets, e.g. re-configure
198384836b65Smatthias.ringwald             break;
198410642e45Smatthias.ringwald         default:
198510642e45Smatthias.ringwald             break;
198627a923d0Smatthias.ringwald     }
19879da54300S[email protected]     // log_info("new state %u", channel->state);
198827a923d0Smatthias.ringwald }
198927a923d0Smatthias.ringwald 
199000d93d79Smatthias.ringwald 
19917f02f414SMatthias Ringwald static void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * command){
199200d93d79Smatthias.ringwald 
19931b9cb13dSMatthias Ringwald     btstack_linked_list_iterator_t it;
19941b9cb13dSMatthias Ringwald 
199500d93d79Smatthias.ringwald     // get code, signalind identifier and command len
199600d93d79Smatthias.ringwald     uint8_t code   = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
199700d93d79Smatthias.ringwald     uint8_t sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
199800d93d79Smatthias.ringwald 
19991b9cb13dSMatthias Ringwald     // not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_RESPONSE
20001b9cb13dSMatthias Ringwald     if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_RESPONSE){
2001e74c5f58SMatthias Ringwald         l2cap_register_signaling_response(handle, COMMAND_REJECT, sig_id, 0, L2CAP_REJ_CMD_UNKNOWN);
200200d93d79Smatthias.ringwald         return;
200300d93d79Smatthias.ringwald     }
200400d93d79Smatthias.ringwald 
200500d93d79Smatthias.ringwald     // general commands without an assigned channel
200600d93d79Smatthias.ringwald     switch(code) {
200700d93d79Smatthias.ringwald 
200800d93d79Smatthias.ringwald         case CONNECTION_REQUEST: {
2009f8fbdce0SMatthias Ringwald             uint16_t psm =        little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
2010f8fbdce0SMatthias Ringwald             uint16_t source_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
201100d93d79Smatthias.ringwald             l2cap_handle_connection_request(handle, sig_id, psm, source_cid);
20122b83fb7dSmatthias.ringwald             return;
201300d93d79Smatthias.ringwald         }
201400d93d79Smatthias.ringwald 
20152b360848Smatthias.ringwald         case ECHO_REQUEST:
2016e74c5f58SMatthias Ringwald             l2cap_register_signaling_response(handle, code, sig_id, 0, 0);
20172b83fb7dSmatthias.ringwald             return;
201800d93d79Smatthias.ringwald 
201900d93d79Smatthias.ringwald         case INFORMATION_REQUEST: {
2020f8fbdce0SMatthias Ringwald             uint16_t infoType = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
2021e74c5f58SMatthias Ringwald             l2cap_register_signaling_response(handle, code, sig_id, 0, infoType);
20222b83fb7dSmatthias.ringwald             return;
202300d93d79Smatthias.ringwald         }
202400d93d79Smatthias.ringwald 
20251b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
20261b9cb13dSMatthias Ringwald         case INFORMATION_RESPONSE: {
20271b9cb13dSMatthias Ringwald             hci_connection_t * connection = hci_connection_for_handle(handle);
20281b9cb13dSMatthias Ringwald             if (!connection) return;
20291b9cb13dSMatthias Ringwald             uint16_t info_type = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
20301b9cb13dSMatthias Ringwald             uint16_t result =  little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
20311b9cb13dSMatthias Ringwald             if (result != 0) return;
2032543b84e4SMatthias Ringwald             if (info_type != 0x02) return;
20331b9cb13dSMatthias Ringwald             connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_DONE;
20341b9cb13dSMatthias Ringwald             connection->l2cap_state.extended_feature_mask = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
2035543b84e4SMatthias Ringwald             log_info("extended features mask 0x%02x", connection->l2cap_state.extended_feature_mask);
20361b9cb13dSMatthias Ringwald             // trigger connection request
20371b9cb13dSMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
20381b9cb13dSMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
20391b9cb13dSMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2040543b84e4SMatthias Ringwald                 if (channel->con_handle != handle) continue;
2041543b84e4SMatthias Ringwald                 // bail if ERTM was requested but is not supported
2042543b84e4SMatthias Ringwald                 if ((channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION) && ((connection->l2cap_state.extended_feature_mask & 0x08) == 0)){
2043f073f086SMatthias Ringwald                     if (channel->ertm_mandatory){
2044543b84e4SMatthias Ringwald                         // channel closed
2045543b84e4SMatthias Ringwald                         channel->state = L2CAP_STATE_CLOSED;
2046543b84e4SMatthias Ringwald                         // map l2cap connection response result to BTstack status enumeration
2047543b84e4SMatthias Ringwald                         l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_ERTM_NOT_SUPPORTD);
2048543b84e4SMatthias Ringwald                         // discard channel
2049543b84e4SMatthias Ringwald                         btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
2050543b84e4SMatthias Ringwald                         btstack_memory_l2cap_channel_free(channel);
2051543b84e4SMatthias Ringwald                         continue;
2052f073f086SMatthias Ringwald                     } else {
2053f073f086SMatthias Ringwald                         // fallback to Basic mode
2054f073f086SMatthias Ringwald                         channel->mode = L2CAP_CHANNEL_MODE_BASIC;
2055f073f086SMatthias Ringwald                     }
2056543b84e4SMatthias Ringwald                 }
2057543b84e4SMatthias Ringwald                 // start connecting
20581b9cb13dSMatthias Ringwald                 if (channel->state == L2CAP_STATE_WAIT_OUTGOING_EXTENDED_FEATURES){
20591b9cb13dSMatthias Ringwald                     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
20601b9cb13dSMatthias Ringwald                 }
206152606043SMatthias Ringwald                 // respond to connection request
206252606043SMatthias Ringwald                 if (channel->state == L2CAP_STATE_WAIT_INCOMING_EXTENDED_FEATURES){
206352606043SMatthias Ringwald                     channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
206452606043SMatthias Ringwald                     l2cap_emit_incoming_connection(channel);
206552606043SMatthias Ringwald                 }
20661b9cb13dSMatthias Ringwald             }
20671b9cb13dSMatthias Ringwald             return;
20681b9cb13dSMatthias Ringwald         }
20691b9cb13dSMatthias Ringwald #endif
20701b9cb13dSMatthias Ringwald 
207100d93d79Smatthias.ringwald         default:
207200d93d79Smatthias.ringwald             break;
207300d93d79Smatthias.ringwald     }
207400d93d79Smatthias.ringwald 
207500d93d79Smatthias.ringwald 
207600d93d79Smatthias.ringwald     // Get potential destination CID
2077f8fbdce0SMatthias Ringwald     uint16_t dest_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
207800d93d79Smatthias.ringwald 
207900d93d79Smatthias.ringwald     // Find channel for this sig_id and connection handle
2080665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
2081665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2082665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2083fc64f94aSMatthias Ringwald         if (channel->con_handle != handle) continue;
208400d93d79Smatthias.ringwald         if (code & 1) {
2085b1988dceSmatthias.ringwald             // match odd commands (responses) by previous signaling identifier
2086b1988dceSmatthias.ringwald             if (channel->local_sig_id == sig_id) {
208700d93d79Smatthias.ringwald                 l2cap_signaling_handler_channel(channel, command);
20884e32727eSmatthias.ringwald                 break;
208900d93d79Smatthias.ringwald             }
209000d93d79Smatthias.ringwald         } else {
2091b1988dceSmatthias.ringwald             // match even commands (requests) by local channel id
209200d93d79Smatthias.ringwald             if (channel->local_cid == dest_cid) {
209300d93d79Smatthias.ringwald                 l2cap_signaling_handler_channel(channel, command);
20944e32727eSmatthias.ringwald                 break;
209500d93d79Smatthias.ringwald             }
209600d93d79Smatthias.ringwald         }
209700d93d79Smatthias.ringwald     }
209800d93d79Smatthias.ringwald }
209909e9d05bSMatthias Ringwald #endif
210000d93d79Smatthias.ringwald 
2101e7d0c9aaSMatthias Ringwald #ifdef ENABLE_BLE
210209e9d05bSMatthias Ringwald 
210309e9d05bSMatthias Ringwald static void l2cap_emit_connection_parameter_update_response(hci_con_handle_t con_handle, uint16_t result){
210409e9d05bSMatthias Ringwald     uint8_t event[6];
210509e9d05bSMatthias Ringwald     event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE;
210609e9d05bSMatthias Ringwald     event[1] = 4;
210709e9d05bSMatthias Ringwald     little_endian_store_16(event, 2, con_handle);
210809e9d05bSMatthias Ringwald     little_endian_store_16(event, 4, result);
210909e9d05bSMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
211009e9d05bSMatthias Ringwald     if (!l2cap_event_packet_handler) return;
211109e9d05bSMatthias Ringwald     (*l2cap_event_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
211209e9d05bSMatthias Ringwald }
211309e9d05bSMatthias Ringwald 
2114c48b2a2cSMatthias Ringwald // @returns valid
2115c48b2a2cSMatthias Ringwald static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t * command, uint8_t sig_id){
2116e7d0c9aaSMatthias Ringwald     hci_connection_t * connection;
2117c48b2a2cSMatthias Ringwald     uint16_t result;
2118c48b2a2cSMatthias Ringwald     uint8_t  event[10];
211983fd9c76SMatthias Ringwald 
2120cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2121a3dc965aSMatthias Ringwald     btstack_linked_list_iterator_t it;
2122a3dc965aSMatthias Ringwald     l2cap_channel_t * channel;
2123a3dc965aSMatthias Ringwald     uint16_t local_cid;
212483fd9c76SMatthias Ringwald     uint16_t le_psm;
212563f0ac45SMatthias Ringwald     uint16_t new_credits;
212663f0ac45SMatthias Ringwald     uint16_t credits_before;
2127e7d0c9aaSMatthias Ringwald     l2cap_service_t * service;
212811cae19eSMilanka Ringwald     uint16_t source_cid;
212983fd9c76SMatthias Ringwald #endif
213000d93d79Smatthias.ringwald 
21311b8b8d05SMatthias Ringwald     uint8_t code   = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
213223017473SMatthias Ringwald     log_info("l2cap_le_signaling_handler_dispatch: command 0x%02x, sig id %u", code, sig_id);
21331b8b8d05SMatthias Ringwald 
21341b8b8d05SMatthias Ringwald     switch (code){
213500d93d79Smatthias.ringwald 
2136c48b2a2cSMatthias Ringwald         case CONNECTION_PARAMETER_UPDATE_RESPONSE:
2137c48b2a2cSMatthias Ringwald             result = little_endian_read_16(command, 4);
2138ccf076adS[email protected]             l2cap_emit_connection_parameter_update_response(handle, result);
2139ccf076adS[email protected]             break;
2140da886c03S[email protected] 
2141c48b2a2cSMatthias Ringwald         case CONNECTION_PARAMETER_UPDATE_REQUEST:
2142e7d0c9aaSMatthias Ringwald             connection = hci_connection_for_handle(handle);
2143da886c03S[email protected]             if (connection){
21446d91fb6cSMatthias Ringwald                 if (connection->role != HCI_ROLE_MASTER){
21456d91fb6cSMatthias Ringwald                     // reject command without notifying upper layer when not in master role
2146c48b2a2cSMatthias Ringwald                     return 0;
21476d91fb6cSMatthias Ringwald                 }
2148da886c03S[email protected]                 int update_parameter = 1;
2149a4c06b28SMatthias Ringwald                 le_connection_parameter_range_t existing_range;
21504ced4e8cSMatthias Ringwald                 gap_get_connection_parameter_range(&existing_range);
2151c48b2a2cSMatthias Ringwald                 uint16_t le_conn_interval_min = little_endian_read_16(command,8);
2152c48b2a2cSMatthias Ringwald                 uint16_t le_conn_interval_max = little_endian_read_16(command,10);
2153c48b2a2cSMatthias Ringwald                 uint16_t le_conn_latency = little_endian_read_16(command,12);
2154c48b2a2cSMatthias Ringwald                 uint16_t le_supervision_timeout = little_endian_read_16(command,14);
2155da886c03S[email protected] 
2156da886c03S[email protected]                 if (le_conn_interval_min < existing_range.le_conn_interval_min) update_parameter = 0;
2157da886c03S[email protected]                 if (le_conn_interval_max > existing_range.le_conn_interval_max) update_parameter = 0;
2158da886c03S[email protected] 
2159da886c03S[email protected]                 if (le_conn_latency < existing_range.le_conn_latency_min) update_parameter = 0;
2160da886c03S[email protected]                 if (le_conn_latency > existing_range.le_conn_latency_max) update_parameter = 0;
2161da886c03S[email protected] 
2162da886c03S[email protected]                 if (le_supervision_timeout < existing_range.le_supervision_timeout_min) update_parameter = 0;
2163da886c03S[email protected]                 if (le_supervision_timeout > existing_range.le_supervision_timeout_max) update_parameter = 0;
2164da886c03S[email protected] 
2165da886c03S[email protected]                 if (update_parameter){
2166da886c03S[email protected]                     connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_SEND_RESPONSE;
2167da886c03S[email protected]                     connection->le_conn_interval_min = le_conn_interval_min;
2168da886c03S[email protected]                     connection->le_conn_interval_max = le_conn_interval_max;
2169da886c03S[email protected]                     connection->le_conn_latency = le_conn_latency;
2170da886c03S[email protected]                     connection->le_supervision_timeout = le_supervision_timeout;
2171da886c03S[email protected]                 } else {
2172da886c03S[email protected]                     connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_DENY;
2173da886c03S[email protected]                 }
2174c48b2a2cSMatthias Ringwald                 connection->le_con_param_update_identifier = sig_id;
2175da886c03S[email protected]             }
2176da886c03S[email protected] 
217733c40538SMatthias Ringwald             if (!l2cap_event_packet_handler) break;
2178c48b2a2cSMatthias Ringwald 
2179c48b2a2cSMatthias Ringwald             event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST;
2180c48b2a2cSMatthias Ringwald             event[1] = 8;
2181c48b2a2cSMatthias Ringwald             memcpy(&event[2], &command[4], 8);
2182c48b2a2cSMatthias Ringwald             hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
218333c40538SMatthias Ringwald             (*l2cap_event_packet_handler)( HCI_EVENT_PACKET, 0, event, sizeof(event));
2184ccf076adS[email protected]             break;
2185c48b2a2cSMatthias Ringwald 
2186a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2187a3dc965aSMatthias Ringwald 
218863f0ac45SMatthias Ringwald         case COMMAND_REJECT:
218963f0ac45SMatthias Ringwald             // Find channel for this sig_id and connection handle
219063f0ac45SMatthias Ringwald             channel = NULL;
219163f0ac45SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
219263f0ac45SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
219363f0ac45SMatthias Ringwald                 l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
219463f0ac45SMatthias Ringwald                 if (a_channel->con_handle   != handle) continue;
219563f0ac45SMatthias Ringwald                 if (a_channel->local_sig_id != sig_id) continue;
219663f0ac45SMatthias Ringwald                 channel = a_channel;
219763f0ac45SMatthias Ringwald                 break;
219863f0ac45SMatthias Ringwald             }
219963f0ac45SMatthias Ringwald             if (!channel) break;
220063f0ac45SMatthias Ringwald 
220163f0ac45SMatthias Ringwald             // if received while waiting for le connection response, assume legacy device
220263f0ac45SMatthias Ringwald             if (channel->state == L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE){
220363f0ac45SMatthias Ringwald                 channel->state = L2CAP_STATE_CLOSED;
220463f0ac45SMatthias Ringwald                 // no official value for this, use: Connection refused – LE_PSM not supported - 0x0002
220544276248SMatthias Ringwald                 l2cap_emit_le_channel_opened(channel, 0x0002);
220663f0ac45SMatthias Ringwald 
220763f0ac45SMatthias Ringwald                 // discard channel
220863f0ac45SMatthias Ringwald                 btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel);
220963f0ac45SMatthias Ringwald                 btstack_memory_l2cap_channel_free(channel);
221063f0ac45SMatthias Ringwald                 break;
221163f0ac45SMatthias Ringwald             }
221263f0ac45SMatthias Ringwald             break;
221363f0ac45SMatthias Ringwald 
2214e7d0c9aaSMatthias Ringwald         case LE_CREDIT_BASED_CONNECTION_REQUEST:
2215e7d0c9aaSMatthias Ringwald 
2216e7d0c9aaSMatthias Ringwald             // get hci connection, bail if not found (must not happen)
2217e7d0c9aaSMatthias Ringwald             connection = hci_connection_for_handle(handle);
2218e7d0c9aaSMatthias Ringwald             if (!connection) return 0;
2219e7d0c9aaSMatthias Ringwald 
2220e7d0c9aaSMatthias Ringwald             // check if service registered
2221e7d0c9aaSMatthias Ringwald             le_psm  = little_endian_read_16(command, 4);
2222e7d0c9aaSMatthias Ringwald             service = l2cap_le_get_service(le_psm);
222311cae19eSMilanka Ringwald             source_cid = little_endian_read_16(command, 6);
2224e7d0c9aaSMatthias Ringwald 
2225e7d0c9aaSMatthias Ringwald             if (service){
2226e7d0c9aaSMatthias Ringwald                 if (source_cid < 0x40){
2227e7d0c9aaSMatthias Ringwald                     // 0x0009 Connection refused - Invalid Source CID
2228e74c5f58SMatthias Ringwald                     l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0009);
2229e7d0c9aaSMatthias Ringwald                     return 1;
2230e7d0c9aaSMatthias Ringwald                 }
2231e7d0c9aaSMatthias Ringwald 
2232e7d0c9aaSMatthias Ringwald                 // go through list of channels for this ACL connection and check if we get a match
2233e7d0c9aaSMatthias Ringwald                 btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
2234e7d0c9aaSMatthias Ringwald                 while (btstack_linked_list_iterator_has_next(&it)){
22351b8b8d05SMatthias Ringwald                     l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
22361b8b8d05SMatthias Ringwald                     if (a_channel->con_handle != handle) continue;
22371b8b8d05SMatthias Ringwald                     if (a_channel->remote_cid != source_cid) continue;
2238e7d0c9aaSMatthias Ringwald                     // 0x000a Connection refused - Source CID already allocated
2239e74c5f58SMatthias Ringwald                     l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x000a);
2240e7d0c9aaSMatthias Ringwald                     return 1;
2241e7d0c9aaSMatthias Ringwald                 }
2242e7d0c9aaSMatthias Ringwald 
224383fd9c76SMatthias Ringwald                 // security: check encryption
224483fd9c76SMatthias Ringwald                 if (service->required_security_level >= LEVEL_2){
224583fd9c76SMatthias Ringwald                     if (sm_encryption_key_size(handle) == 0){
224683fd9c76SMatthias Ringwald                         // 0x0008 Connection refused - insufficient encryption
2247e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0008);
224883fd9c76SMatthias Ringwald                         return 1;
224983fd9c76SMatthias Ringwald                     }
225083fd9c76SMatthias Ringwald                     // anything less than 16 byte key size is insufficient
225183fd9c76SMatthias Ringwald                     if (sm_encryption_key_size(handle) < 16){
225283fd9c76SMatthias Ringwald                         // 0x0007 Connection refused – insufficient encryption key size
2253e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0007);
225483fd9c76SMatthias Ringwald                         return 1;
225583fd9c76SMatthias Ringwald                     }
225683fd9c76SMatthias Ringwald                 }
225783fd9c76SMatthias Ringwald 
225883fd9c76SMatthias Ringwald                 // security: check authencation
225983fd9c76SMatthias Ringwald                 if (service->required_security_level >= LEVEL_3){
226083fd9c76SMatthias Ringwald                     if (!sm_authenticated(handle)){
226183fd9c76SMatthias Ringwald                         // 0x0005 Connection refused – insufficient authentication
2262e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0005);
226383fd9c76SMatthias Ringwald                         return 1;
226483fd9c76SMatthias Ringwald                     }
226583fd9c76SMatthias Ringwald                 }
226683fd9c76SMatthias Ringwald 
226783fd9c76SMatthias Ringwald                 // security: check authorization
226883fd9c76SMatthias Ringwald                 if (service->required_security_level >= LEVEL_4){
226983fd9c76SMatthias Ringwald                     if (sm_authorization_state(handle) != AUTHORIZATION_GRANTED){
227083fd9c76SMatthias Ringwald                         // 0x0006 Connection refused – insufficient authorization
2271e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0006);
227283fd9c76SMatthias Ringwald                         return 1;
227383fd9c76SMatthias Ringwald                     }
227483fd9c76SMatthias Ringwald                 }
2275e7d0c9aaSMatthias Ringwald 
2276e7d0c9aaSMatthias Ringwald                 // allocate channel
22771b8b8d05SMatthias Ringwald                 channel = l2cap_create_channel_entry(service->packet_handler, connection->address,
2278e7d0c9aaSMatthias Ringwald                     BD_ADDR_TYPE_LE_RANDOM, le_psm, service->mtu, service->required_security_level);
2279e7d0c9aaSMatthias Ringwald                 if (!channel){
2280e7d0c9aaSMatthias Ringwald                     // 0x0004 Connection refused – no resources available
2281e74c5f58SMatthias Ringwald                     l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0004);
2282e7d0c9aaSMatthias Ringwald                     return 1;
2283e7d0c9aaSMatthias Ringwald                 }
2284e7d0c9aaSMatthias Ringwald 
2285e7d0c9aaSMatthias Ringwald                 channel->con_handle = handle;
2286e7d0c9aaSMatthias Ringwald                 channel->remote_cid = source_cid;
2287e7d0c9aaSMatthias Ringwald                 channel->remote_sig_id = sig_id;
22887f107edaSMatthias Ringwald                 channel->remote_mtu = little_endian_read_16(command, 8);
22897f107edaSMatthias Ringwald                 channel->remote_mps = little_endian_read_16(command, 10);
22907f107edaSMatthias Ringwald                 channel->credits_outgoing = little_endian_read_16(command, 12);
2291e7d0c9aaSMatthias Ringwald 
2292e7d0c9aaSMatthias Ringwald                 // set initial state
2293e7d0c9aaSMatthias Ringwald                 channel->state      = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
2294c99bb618SMatthias Ringwald                 channel->state_var |= L2CAP_CHANNEL_STATE_VAR_INCOMING;
2295e7d0c9aaSMatthias Ringwald 
2296e7d0c9aaSMatthias Ringwald                 // add to connections list
2297e7d0c9aaSMatthias Ringwald                 btstack_linked_list_add(&l2cap_le_channels, (btstack_linked_item_t *) channel);
2298e7d0c9aaSMatthias Ringwald 
2299e7d0c9aaSMatthias Ringwald                 // post connection request event
230044276248SMatthias Ringwald                 l2cap_emit_le_incoming_connection(channel);
2301e7d0c9aaSMatthias Ringwald 
2302e7d0c9aaSMatthias Ringwald             } else {
2303e7d0c9aaSMatthias Ringwald                 // Connection refused – LE_PSM not supported
2304e74c5f58SMatthias Ringwald                 l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0002);
2305e7d0c9aaSMatthias Ringwald             }
2306e7d0c9aaSMatthias Ringwald             break;
23071b8b8d05SMatthias Ringwald 
23081b8b8d05SMatthias Ringwald         case LE_CREDIT_BASED_CONNECTION_RESPONSE:
23091b8b8d05SMatthias Ringwald             // Find channel for this sig_id and connection handle
23101b8b8d05SMatthias Ringwald             channel = NULL;
23111b8b8d05SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
23121b8b8d05SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
23131b8b8d05SMatthias Ringwald                 l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
23141b8b8d05SMatthias Ringwald                 if (a_channel->con_handle   != handle) continue;
23151b8b8d05SMatthias Ringwald                 if (a_channel->local_sig_id != sig_id) continue;
23161b8b8d05SMatthias Ringwald                 channel = a_channel;
23171b8b8d05SMatthias Ringwald                 break;
23181b8b8d05SMatthias Ringwald             }
23191b8b8d05SMatthias Ringwald             if (!channel) break;
23201b8b8d05SMatthias Ringwald 
23211b8b8d05SMatthias Ringwald             // cid + 0
23221b8b8d05SMatthias Ringwald             result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+8);
23231b8b8d05SMatthias Ringwald             if (result){
23241b8b8d05SMatthias Ringwald                 channel->state = L2CAP_STATE_CLOSED;
23251b8b8d05SMatthias Ringwald                 // map l2cap connection response result to BTstack status enumeration
232644276248SMatthias Ringwald                 l2cap_emit_le_channel_opened(channel, result);
23271b8b8d05SMatthias Ringwald 
23281b8b8d05SMatthias Ringwald                 // discard channel
232963f0ac45SMatthias Ringwald                 btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel);
23301b8b8d05SMatthias Ringwald                 btstack_memory_l2cap_channel_free(channel);
23311b8b8d05SMatthias Ringwald                 break;
23321b8b8d05SMatthias Ringwald             }
23331b8b8d05SMatthias Ringwald 
23341b8b8d05SMatthias Ringwald             // success
23351b8b8d05SMatthias Ringwald             channel->remote_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0);
23361b8b8d05SMatthias Ringwald             channel->remote_mtu = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 2);
23371b8b8d05SMatthias Ringwald             channel->remote_mps = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 4);
23381b8b8d05SMatthias Ringwald             channel->credits_outgoing = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 6);
23391b8b8d05SMatthias Ringwald             channel->state = L2CAP_STATE_OPEN;
234044276248SMatthias Ringwald             l2cap_emit_le_channel_opened(channel, result);
23411b8b8d05SMatthias Ringwald             break;
23421b8b8d05SMatthias Ringwald 
234385aeef60SMatthias Ringwald         case LE_FLOW_CONTROL_CREDIT:
234485aeef60SMatthias Ringwald             // find channel
234585aeef60SMatthias Ringwald             local_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0);
234685aeef60SMatthias Ringwald             channel = l2cap_le_get_channel_for_local_cid(local_cid);
234763f0ac45SMatthias Ringwald             if (!channel) {
234863f0ac45SMatthias Ringwald                 log_error("l2cap: no channel for cid 0x%02x", local_cid);
234963f0ac45SMatthias Ringwald                 break;
235063f0ac45SMatthias Ringwald             }
235163f0ac45SMatthias Ringwald             new_credits = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 2);
235263f0ac45SMatthias Ringwald             credits_before = channel->credits_outgoing;
235363f0ac45SMatthias Ringwald             channel->credits_outgoing += new_credits;
235463f0ac45SMatthias Ringwald             // check for credit overrun
235563f0ac45SMatthias Ringwald             if (credits_before > channel->credits_outgoing){
235663f0ac45SMatthias Ringwald                 log_error("l2cap: new credits caused overrrun for cid 0x%02x, disconnecting", local_cid);
235763f0ac45SMatthias Ringwald                 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
235863f0ac45SMatthias Ringwald                 break;
235963f0ac45SMatthias Ringwald             }
236063f0ac45SMatthias Ringwald             log_info("l2cap: %u credits for 0x%02x, now %u", new_credits, local_cid, channel->credits_outgoing);
236185aeef60SMatthias Ringwald             break;
236285aeef60SMatthias Ringwald 
2363828a7f7aSMatthias Ringwald         case DISCONNECTION_REQUEST:
2364828a7f7aSMatthias Ringwald             // find channel
2365828a7f7aSMatthias Ringwald             local_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0);
2366828a7f7aSMatthias Ringwald             channel = l2cap_le_get_channel_for_local_cid(local_cid);
236763f34e00SMatthias Ringwald             if (!channel) {
236863f34e00SMatthias Ringwald                 log_error("l2cap: no channel for cid 0x%02x", local_cid);
236963f34e00SMatthias Ringwald                 break;
237063f34e00SMatthias Ringwald             }
2371828a7f7aSMatthias Ringwald             channel->remote_sig_id = sig_id;
2372828a7f7aSMatthias Ringwald             channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
2373828a7f7aSMatthias Ringwald             break;
2374828a7f7aSMatthias Ringwald 
2375a3dc965aSMatthias Ringwald #endif
2376a3dc965aSMatthias Ringwald 
237763f0ac45SMatthias Ringwald         case DISCONNECTION_RESPONSE:
237863f0ac45SMatthias Ringwald             break;
237963f0ac45SMatthias Ringwald 
2380c48b2a2cSMatthias Ringwald         default:
2381c48b2a2cSMatthias Ringwald             // command unknown -> reject command
2382c48b2a2cSMatthias Ringwald             return 0;
2383ccf076adS[email protected]     }
2384c48b2a2cSMatthias Ringwald     return 1;
2385c48b2a2cSMatthias Ringwald }
2386e7d0c9aaSMatthias Ringwald #endif
2387c48b2a2cSMatthias Ringwald 
2388c48b2a2cSMatthias Ringwald static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ){
23899ec2630cSMatthias Ringwald     UNUSED(packet_type);
23909ec2630cSMatthias Ringwald     UNUSED(channel);
2391c48b2a2cSMatthias Ringwald 
239209e9d05bSMatthias Ringwald     l2cap_channel_t * l2cap_channel;
2393f3963406SMatthias Ringwald     UNUSED(l2cap_channel);
239409e9d05bSMatthias Ringwald 
2395c48b2a2cSMatthias Ringwald     // Get Channel ID
2396c48b2a2cSMatthias Ringwald     uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
2397c48b2a2cSMatthias Ringwald     hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet);
2398c48b2a2cSMatthias Ringwald 
2399c48b2a2cSMatthias Ringwald     switch (channel_id) {
2400c48b2a2cSMatthias Ringwald 
240109e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
2402c48b2a2cSMatthias Ringwald         case L2CAP_CID_SIGNALING: {
2403c48b2a2cSMatthias Ringwald             uint16_t command_offset = 8;
2404c48b2a2cSMatthias Ringwald             while (command_offset < size) {
2405c48b2a2cSMatthias Ringwald                 // handle signaling commands
2406c48b2a2cSMatthias Ringwald                 l2cap_signaling_handler_dispatch(handle, &packet[command_offset]);
2407c48b2a2cSMatthias Ringwald 
2408c48b2a2cSMatthias Ringwald                 // increment command_offset
2409c48b2a2cSMatthias Ringwald                 command_offset += L2CAP_SIGNALING_COMMAND_DATA_OFFSET + little_endian_read_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
2410c48b2a2cSMatthias Ringwald             }
2411c48b2a2cSMatthias Ringwald             break;
2412c48b2a2cSMatthias Ringwald         }
241309e9d05bSMatthias Ringwald #endif
2414c48b2a2cSMatthias Ringwald 
2415e7d0c9aaSMatthias Ringwald #ifdef ENABLE_BLE
2416e7d0c9aaSMatthias Ringwald         case L2CAP_CID_SIGNALING_LE: {
2417e7d0c9aaSMatthias Ringwald             uint16_t sig_id = packet[COMPLETE_L2CAP_HEADER + 1];
2418e7d0c9aaSMatthias Ringwald             int      valid  = l2cap_le_signaling_handler_dispatch(handle, &packet[COMPLETE_L2CAP_HEADER], sig_id);
2419c48b2a2cSMatthias Ringwald             if (!valid){
2420e74c5f58SMatthias Ringwald                 l2cap_register_signaling_response(handle, COMMAND_REJECT_LE, sig_id, 0, L2CAP_REJ_CMD_UNKNOWN);
2421ccf076adS[email protected]             }
2422ccf076adS[email protected]             break;
2423e7d0c9aaSMatthias Ringwald         }
2424e7d0c9aaSMatthias Ringwald #endif
2425c48b2a2cSMatthias Ringwald 
2426c48b2a2cSMatthias Ringwald         case L2CAP_CID_ATTRIBUTE_PROTOCOL:
2427c48b2a2cSMatthias Ringwald             if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL].callback) {
2428c48b2a2cSMatthias Ringwald                 (*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL].callback)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
2429ccf076adS[email protected]             }
2430c48b2a2cSMatthias Ringwald             break;
2431c48b2a2cSMatthias Ringwald 
2432c48b2a2cSMatthias Ringwald         case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
2433c48b2a2cSMatthias Ringwald             if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL].callback) {
2434c48b2a2cSMatthias Ringwald                 (*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL].callback)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
2435c48b2a2cSMatthias Ringwald             }
2436c48b2a2cSMatthias Ringwald             break;
2437c48b2a2cSMatthias Ringwald 
2438c48b2a2cSMatthias Ringwald         case L2CAP_CID_CONNECTIONLESS_CHANNEL:
2439c48b2a2cSMatthias Ringwald             if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL].callback) {
2440c48b2a2cSMatthias Ringwald                 (*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL].callback)(UCD_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
2441c48b2a2cSMatthias Ringwald             }
2442c48b2a2cSMatthias Ringwald             break;
24431bbc0b23S[email protected] 
244409e9d05bSMatthias Ringwald         default:
244509e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
244600d93d79Smatthias.ringwald             // Find channel for this channel_id and connection handle
244764e11ca9SMatthias Ringwald             l2cap_channel = l2cap_get_channel_for_local_cid(channel_id);
2448d1fd2a88SMatthias Ringwald             if (l2cap_channel) {
244927e0774aSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
245027e0774aSMatthias Ringwald                 if (l2cap_channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
245127e0774aSMatthias Ringwald 
245227e0774aSMatthias Ringwald                     // verify FCS
245327e0774aSMatthias Ringwald                     uint16_t fcs_calculated = crc16_calc(&packet[4], size - (4+2));
245427e0774aSMatthias Ringwald                     uint16_t fcs_packet     = little_endian_read_16(packet, size-2);
245527e0774aSMatthias Ringwald                     log_info("Packet FCS 0x%04x, calculated FCS 0x%04x", fcs_packet, fcs_calculated);
245627e0774aSMatthias Ringwald                     if (fcs_calculated != fcs_packet){
245727e0774aSMatthias Ringwald                         log_error("FCS mismatch! Packet 0x%04x, calculated 0x%04x", fcs_packet, fcs_calculated);
245827e0774aSMatthias Ringwald                         // TODO: trigger retransmission or something like that
245927e0774aSMatthias Ringwald                         break;
246027e0774aSMatthias Ringwald                     }
246127e0774aSMatthias Ringwald 
246227e0774aSMatthias Ringwald                     // switch on packet type
246327e0774aSMatthias Ringwald                     uint16_t control = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER);
246438f62777SMatthias Ringwald                     uint8_t  req_seq = (control >> 8) & 0x3f;
246527e0774aSMatthias Ringwald                     if (control & 1){
246627e0774aSMatthias Ringwald                         // S-Frame
2467*bdbe2e49SMatthias Ringwald                         // int poll = (control >> 7) & 0x01;
2468*bdbe2e49SMatthias Ringwald                         l2cap_supervisory_function_t s = (l2cap_supervisory_function_t) ((control >> 2) & 0x03);
2469*bdbe2e49SMatthias Ringwald                         l2cap_ertm_tx_packet_state_t * tx_state;
2470*bdbe2e49SMatthias Ringwald                         switch (s){
2471*bdbe2e49SMatthias Ringwald                             case L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY:
2472*bdbe2e49SMatthias Ringwald                                 tx_state = &l2cap_channel->tx_packets_state[l2cap_channel->tx_read_index];
2473*bdbe2e49SMatthias Ringwald                                 if ( ((req_seq - 1) & 0x3f) == tx_state->tx_seq){
2474*bdbe2e49SMatthias Ringwald                                     log_info("RR seq %u == seq of oldest tx packet -> packet done", req_seq);
2475*bdbe2e49SMatthias Ringwald                                     l2cap_channel->tx_read_index++;
2476*bdbe2e49SMatthias Ringwald                                     if (l2cap_channel->tx_read_index >= l2cap_channel->num_rx_buffers){
2477*bdbe2e49SMatthias Ringwald                                         l2cap_channel->tx_read_index = 0;
2478*bdbe2e49SMatthias Ringwald                                     }
2479*bdbe2e49SMatthias Ringwald                                 } else {
2480*bdbe2e49SMatthias Ringwald                                     log_info("RR seq %u != seq of oldest tx packet %u ???", req_seq, tx_state->tx_seq);
2481*bdbe2e49SMatthias Ringwald                                 }
2482*bdbe2e49SMatthias Ringwald                                 break;
2483*bdbe2e49SMatthias Ringwald                             default:
2484*bdbe2e49SMatthias Ringwald                                 break;
2485*bdbe2e49SMatthias Ringwald                         }
248627e0774aSMatthias Ringwald                         break;
248727e0774aSMatthias Ringwald                     } else {
248827e0774aSMatthias Ringwald                         // I-Frame
248927e0774aSMatthias Ringwald                         // get control
249027e0774aSMatthias Ringwald                         l2cap_segmentation_and_reassembly_t sar = (l2cap_segmentation_and_reassembly_t) (control >> 14);
249138f62777SMatthias Ringwald                         uint8_t tx_seq = (control >> 1) & 0x3f;
249238f62777SMatthias Ringwald                         log_info("Control: 0x%04x => SAR %u, ReqSeq %02u, R?, TxSeq %02u", control, (int) sar, req_seq, tx_seq);
249338f62777SMatthias Ringwald                         log_info("SAR: pos %u", l2cap_channel->rx_packets_state->pos);
249438f62777SMatthias Ringwald                         log_info("State: expected_tx_seq %02u, req_seq %02u", l2cap_channel->expected_tx_seq, l2cap_channel->req_seq);
249538f62777SMatthias Ringwald                         // check ordering
249638f62777SMatthias Ringwald                         if (l2cap_channel->expected_tx_seq == tx_seq){
249738f62777SMatthias Ringwald                             log_info("Received expected frame with TxSeq == ExpectedTxSeq == %02u", tx_seq);
249838f62777SMatthias Ringwald                             l2cap_channel->req_seq = tx_seq;
2499d84e866fSMatthias Ringwald                             l2cap_channel->send_supervisor_frame_receiver_ready = 1;
250038f62777SMatthias Ringwald                             l2cap_channel->expected_tx_seq = l2cap_next_ertm_seq_nr(l2cap_channel->expected_tx_seq);
2501ed971c5aSMatthias Ringwald                             uint16_t sdu_length;
2502ed971c5aSMatthias Ringwald                             uint16_t segment_length;
2503ed971c5aSMatthias Ringwald                             uint16_t payload_offset;
250427e0774aSMatthias Ringwald                             switch (sar){
250527e0774aSMatthias Ringwald                                 case L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU:
2506ed971c5aSMatthias Ringwald                                     payload_offset = COMPLETE_L2CAP_HEADER+2;
2507ed971c5aSMatthias Ringwald                                     segment_length = payload_offset-2;
2508ed971c5aSMatthias Ringwald                                     l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER+2], segment_length);
250927e0774aSMatthias Ringwald                                     break;
251027e0774aSMatthias Ringwald                                 case L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU:
2511ed971c5aSMatthias Ringwald                                     // TODO: use current packet
2512ed971c5aSMatthias Ringwald                                     // TODO: check if reassembly started
2513ed971c5aSMatthias Ringwald                                     // TODO: check len against local mtu
2514ed971c5aSMatthias Ringwald                                     sdu_length = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER+2);
2515ed971c5aSMatthias Ringwald                                     payload_offset = COMPLETE_L2CAP_HEADER+4;
2516ed971c5aSMatthias Ringwald                                     segment_length = size - payload_offset-2;
2517ed971c5aSMatthias Ringwald                                     memcpy(&l2cap_channel->rx_packets_data[0], &packet[payload_offset], segment_length);
2518ed971c5aSMatthias Ringwald                                     l2cap_channel->rx_packets_state->sdu_length = sdu_length;
2519ed971c5aSMatthias Ringwald                                     l2cap_channel->rx_packets_state->pos = segment_length;
2520ed971c5aSMatthias Ringwald                                     break;
252127e0774aSMatthias Ringwald                                 case L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU:
2522ed971c5aSMatthias Ringwald                                     payload_offset = COMPLETE_L2CAP_HEADER+2;
2523ed971c5aSMatthias Ringwald                                     segment_length = size - payload_offset-2;
2524ed971c5aSMatthias Ringwald                                     memcpy(&l2cap_channel->rx_packets_data[l2cap_channel->rx_packets_state->pos], &packet[payload_offset], segment_length);
2525ed971c5aSMatthias Ringwald                                     l2cap_channel->rx_packets_state->pos += segment_length;
2526ed971c5aSMatthias Ringwald                                     l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, l2cap_channel->rx_packets_data, l2cap_channel->rx_packets_state[0].pos);
2527ed971c5aSMatthias Ringwald                                     break;
252827e0774aSMatthias Ringwald                                 case L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU:
2529ed971c5aSMatthias Ringwald                                     payload_offset = COMPLETE_L2CAP_HEADER+2;
2530ed971c5aSMatthias Ringwald                                     segment_length = size - payload_offset-2;
2531ed971c5aSMatthias Ringwald                                     memcpy(&l2cap_channel->rx_packets_data[l2cap_channel->rx_packets_state->pos], &packet[payload_offset], segment_length);
2532ed971c5aSMatthias Ringwald                                     l2cap_channel->rx_packets_state->pos += segment_length;
253327e0774aSMatthias Ringwald                                     break;
253427e0774aSMatthias Ringwald                                 }
253527e0774aSMatthias Ringwald                             }
253638f62777SMatthias Ringwald                         }
253727e0774aSMatthias Ringwald                     break;
253827e0774aSMatthias Ringwald                 }
253927e0774aSMatthias Ringwald #endif
25403d50b4baSMatthias Ringwald                 l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
254100d93d79Smatthias.ringwald             }
254209e9d05bSMatthias Ringwald #endif
2543a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
254464e11ca9SMatthias Ringwald             l2cap_channel = l2cap_le_get_channel_for_local_cid(channel_id);
254564e11ca9SMatthias Ringwald             if (l2cap_channel) {
254685aeef60SMatthias Ringwald                 // credit counting
254785aeef60SMatthias Ringwald                 if (l2cap_channel->credits_incoming == 0){
254885aeef60SMatthias Ringwald                     log_error("LE Data Channel packet received but no incoming credits");
254985aeef60SMatthias Ringwald                     l2cap_channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
255085aeef60SMatthias Ringwald                     break;
255185aeef60SMatthias Ringwald                 }
255285aeef60SMatthias Ringwald                 l2cap_channel->credits_incoming--;
255385aeef60SMatthias Ringwald 
255485aeef60SMatthias Ringwald                 // automatic credits
255585aeef60SMatthias Ringwald                 if (l2cap_channel->credits_incoming < L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_WATERMARK && l2cap_channel->automatic_credits){
255685aeef60SMatthias Ringwald                     l2cap_channel->new_credits_incoming = L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_INCREMENT;
255785aeef60SMatthias Ringwald                 }
255885aeef60SMatthias Ringwald 
2559cd529728SMatthias Ringwald                 // first fragment
2560cd529728SMatthias Ringwald                 uint16_t pos = 0;
2561cd529728SMatthias Ringwald                 if (!l2cap_channel->receive_sdu_len){
2562cd529728SMatthias Ringwald                     l2cap_channel->receive_sdu_len = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER);
2563cd529728SMatthias Ringwald                     l2cap_channel->receive_sdu_pos = 0;
2564cd529728SMatthias Ringwald                     pos  += 2;
2565cd529728SMatthias Ringwald                     size -= 2;
2566cd529728SMatthias Ringwald                 }
2567cd529728SMatthias Ringwald                 memcpy(&l2cap_channel->receive_sdu_buffer[l2cap_channel->receive_sdu_pos], &packet[COMPLETE_L2CAP_HEADER+pos], size-COMPLETE_L2CAP_HEADER);
2568cd529728SMatthias Ringwald                 l2cap_channel->receive_sdu_pos += size - COMPLETE_L2CAP_HEADER;
2569cd529728SMatthias Ringwald                 // done?
257063f0ac45SMatthias Ringwald                 log_info("le packet pos %u, len %u", l2cap_channel->receive_sdu_pos, l2cap_channel->receive_sdu_len);
2571cd529728SMatthias Ringwald                 if (l2cap_channel->receive_sdu_pos >= l2cap_channel->receive_sdu_len){
2572cd529728SMatthias Ringwald                     l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, l2cap_channel->receive_sdu_buffer, l2cap_channel->receive_sdu_len);
2573cd529728SMatthias Ringwald                     l2cap_channel->receive_sdu_len = 0;
2574cd529728SMatthias Ringwald                 }
257563f0ac45SMatthias Ringwald             } else {
257663f0ac45SMatthias Ringwald                 log_error("LE Data Channel packet received but no channel found for cid 0x%02x", channel_id);
257764e11ca9SMatthias Ringwald             }
257864e11ca9SMatthias Ringwald #endif
25795652b5ffS[email protected]             break;
25805652b5ffS[email protected]     }
258100d93d79Smatthias.ringwald 
25821eb2563eS[email protected]     l2cap_run();
25832718e2e7Smatthias.ringwald }
258400d93d79Smatthias.ringwald 
258509e9d05bSMatthias Ringwald // Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
258609e9d05bSMatthias Ringwald void l2cap_register_fixed_channel(btstack_packet_handler_t the_packet_handler, uint16_t channel_id) {
258709e9d05bSMatthias Ringwald     int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id);
258809e9d05bSMatthias Ringwald     if (index < 0) return;
258909e9d05bSMatthias Ringwald     fixed_channels[index].callback = the_packet_handler;
259009e9d05bSMatthias Ringwald }
259109e9d05bSMatthias Ringwald 
259209e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
259315ec09bbSmatthias.ringwald // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
259427a923d0Smatthias.ringwald void l2cap_finialize_channel_close(l2cap_channel_t * channel){
2595f62db1e3Smatthias.ringwald     channel->state = L2CAP_STATE_CLOSED;
2596f62db1e3Smatthias.ringwald     l2cap_emit_channel_closed(channel);
2597f62db1e3Smatthias.ringwald     // discard channel
25989dcb2fb2S[email protected]     l2cap_stop_rtx(channel);
2599665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
2600d3a9df87Smatthias.ringwald     btstack_memory_l2cap_channel_free(channel);
2601c8e4258aSmatthias.ringwald }
26021e6aba47Smatthias.ringwald 
26038f2a52f4SMatthias Ringwald static l2cap_service_t * l2cap_get_service_internal(btstack_linked_list_t * services, uint16_t psm){
2604665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
2605665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, services);
2606665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2607665d90f2SMatthias Ringwald         l2cap_service_t * service = (l2cap_service_t *) btstack_linked_list_iterator_next(&it);
26089d9bbc01Smatthias.ringwald         if ( service->psm == psm){
26099d9bbc01Smatthias.ringwald             return service;
26109d9bbc01Smatthias.ringwald         };
26119d9bbc01Smatthias.ringwald     }
26129d9bbc01Smatthias.ringwald     return NULL;
26139d9bbc01Smatthias.ringwald }
26149d9bbc01Smatthias.ringwald 
26157192e786SMatthias Ringwald static inline l2cap_service_t * l2cap_get_service(uint16_t psm){
26167192e786SMatthias Ringwald     return l2cap_get_service_internal(&l2cap_services, psm);
26177192e786SMatthias Ringwald }
26187192e786SMatthias Ringwald 
2619e0abb8e7S[email protected] 
2620be2053a6SMatthias 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){
2621be2053a6SMatthias Ringwald 
2622be2053a6SMatthias Ringwald     log_info("L2CAP_REGISTER_SERVICE psm 0x%x mtu %u", psm, mtu);
2623e0abb8e7S[email protected] 
26244bb582b6Smatthias.ringwald     // check for alread registered psm
26259d9bbc01Smatthias.ringwald     l2cap_service_t *service = l2cap_get_service(psm);
2626277abc2cSmatthias.ringwald     if (service) {
2627be2053a6SMatthias Ringwald         log_error("l2cap_register_service: PSM %u already registered", psm);
2628be2053a6SMatthias Ringwald         return L2CAP_SERVICE_ALREADY_REGISTERED;
2629277abc2cSmatthias.ringwald     }
26309d9bbc01Smatthias.ringwald 
26314bb582b6Smatthias.ringwald     // alloc structure
2632bb69aaaeS[email protected]     service = btstack_memory_l2cap_service_get();
2633277abc2cSmatthias.ringwald     if (!service) {
2634be2053a6SMatthias Ringwald         log_error("l2cap_register_service: no memory for l2cap_service_t");
2635be2053a6SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
2636277abc2cSmatthias.ringwald     }
26379d9bbc01Smatthias.ringwald 
26389d9bbc01Smatthias.ringwald     // fill in
26399d9bbc01Smatthias.ringwald     service->psm = psm;
26409d9bbc01Smatthias.ringwald     service->mtu = mtu;
264105ae8de3SMatthias Ringwald     service->packet_handler = service_packet_handler;
2642df3354fcS[email protected]     service->required_security_level = security_level;
26439d9bbc01Smatthias.ringwald 
26449d9bbc01Smatthias.ringwald     // add to services list
2645665d90f2SMatthias Ringwald     btstack_linked_list_add(&l2cap_services, (btstack_linked_item_t *) service);
2646c0e866bfSmatthias.ringwald 
2647c0e866bfSmatthias.ringwald     // enable page scan
264815a95bd5SMatthias Ringwald     gap_connectable_control(1);
26495842b6d9Smatthias.ringwald 
2650be2053a6SMatthias Ringwald     return 0;
26519d9bbc01Smatthias.ringwald }
26529d9bbc01Smatthias.ringwald 
26537e8856ebSMatthias Ringwald uint8_t l2cap_unregister_service(uint16_t psm){
2654e0abb8e7S[email protected] 
2655e0abb8e7S[email protected]     log_info("L2CAP_UNREGISTER_SERVICE psm 0x%x", psm);
2656e0abb8e7S[email protected] 
26579d9bbc01Smatthias.ringwald     l2cap_service_t *service = l2cap_get_service(psm);
26587e8856ebSMatthias Ringwald     if (!service) return L2CAP_SERVICE_DOES_NOT_EXIST;
2659665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_services, (btstack_linked_item_t *) service);
2660d3a9df87Smatthias.ringwald     btstack_memory_l2cap_service_free(service);
2661c0e866bfSmatthias.ringwald 
2662c0e866bfSmatthias.ringwald     // disable page scan when no services registered
26637e8856ebSMatthias Ringwald     if (btstack_linked_list_empty(&l2cap_services)) {
266415a95bd5SMatthias Ringwald         gap_connectable_control(0);
26659d9bbc01Smatthias.ringwald     }
26667e8856ebSMatthias Ringwald     return 0;
26677e8856ebSMatthias Ringwald }
266809e9d05bSMatthias Ringwald #endif
26699d9bbc01Smatthias.ringwald 
26707192e786SMatthias Ringwald 
2671cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
267283fd9c76SMatthias Ringwald 
267357be49d6SMatthias Ringwald static void l2cap_le_notify_channel_can_send(l2cap_channel_t *channel){
267457be49d6SMatthias Ringwald     if (!channel->waiting_for_can_send_now) return;
267557be49d6SMatthias Ringwald     if (channel->send_sdu_buffer) return;
267657be49d6SMatthias Ringwald     channel->waiting_for_can_send_now = 0;
267757be49d6SMatthias Ringwald     log_info("L2CAP_EVENT_CHANNEL_LE_CAN_SEND_NOW local_cid 0x%x", channel->local_cid);
267857be49d6SMatthias Ringwald     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_CAN_SEND_NOW);
267957be49d6SMatthias Ringwald }
268057be49d6SMatthias Ringwald 
268157be49d6SMatthias Ringwald // 1BH2222
268257be49d6SMatthias Ringwald static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel) {
268357be49d6SMatthias 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",
268457be49d6SMatthias Ringwald              channel->address_type, bd_addr_to_str(channel->address), channel->con_handle,  channel->psm, channel->local_cid, channel->remote_cid, channel->remote_mtu);
268557be49d6SMatthias Ringwald     uint8_t event[19];
268657be49d6SMatthias Ringwald     event[0] = L2CAP_EVENT_LE_INCOMING_CONNECTION;
268757be49d6SMatthias Ringwald     event[1] = sizeof(event) - 2;
268857be49d6SMatthias Ringwald     event[2] = channel->address_type;
268957be49d6SMatthias Ringwald     reverse_bd_addr(channel->address, &event[3]);
269057be49d6SMatthias Ringwald     little_endian_store_16(event,  9, channel->con_handle);
269157be49d6SMatthias Ringwald     little_endian_store_16(event, 11, channel->psm);
269257be49d6SMatthias Ringwald     little_endian_store_16(event, 13, channel->local_cid);
269357be49d6SMatthias Ringwald     little_endian_store_16(event, 15, channel->remote_cid);
269457be49d6SMatthias Ringwald     little_endian_store_16(event, 17, channel->remote_mtu);
269557be49d6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
269657be49d6SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
269757be49d6SMatthias Ringwald }
269857be49d6SMatthias Ringwald // 11BH22222
269957be49d6SMatthias Ringwald static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status) {
270057be49d6SMatthias 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",
270157be49d6SMatthias Ringwald              status, channel->address_type, bd_addr_to_str(channel->address), channel->con_handle, channel->psm,
270257be49d6SMatthias Ringwald              channel->local_cid, channel->remote_cid, channel->local_mtu, channel->remote_mtu);
2703c99bb618SMatthias Ringwald     uint8_t event[23];
270457be49d6SMatthias Ringwald     event[0] = L2CAP_EVENT_LE_CHANNEL_OPENED;
270557be49d6SMatthias Ringwald     event[1] = sizeof(event) - 2;
270657be49d6SMatthias Ringwald     event[2] = status;
270757be49d6SMatthias Ringwald     event[3] = channel->address_type;
270857be49d6SMatthias Ringwald     reverse_bd_addr(channel->address, &event[4]);
270957be49d6SMatthias Ringwald     little_endian_store_16(event, 10, channel->con_handle);
2710c99bb618SMatthias Ringwald     event[12] = channel->state_var & L2CAP_CHANNEL_STATE_VAR_INCOMING ? 1 : 0;
2711c99bb618SMatthias Ringwald     little_endian_store_16(event, 13, channel->psm);
2712c99bb618SMatthias Ringwald     little_endian_store_16(event, 15, channel->local_cid);
2713c99bb618SMatthias Ringwald     little_endian_store_16(event, 17, channel->remote_cid);
2714c99bb618SMatthias Ringwald     little_endian_store_16(event, 19, channel->local_mtu);
2715c99bb618SMatthias Ringwald     little_endian_store_16(event, 21, channel->remote_mtu);
271657be49d6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
271757be49d6SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
271857be49d6SMatthias Ringwald }
271957be49d6SMatthias Ringwald 
272057be49d6SMatthias Ringwald static l2cap_channel_t * l2cap_le_get_channel_for_local_cid(uint16_t local_cid){
272157be49d6SMatthias Ringwald     btstack_linked_list_iterator_t it;
272257be49d6SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
272357be49d6SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
272457be49d6SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
272557be49d6SMatthias Ringwald         if ( channel->local_cid == local_cid) {
272657be49d6SMatthias Ringwald             return channel;
272757be49d6SMatthias Ringwald         }
272857be49d6SMatthias Ringwald     }
272957be49d6SMatthias Ringwald     return NULL;
273057be49d6SMatthias Ringwald }
273157be49d6SMatthias Ringwald 
273257be49d6SMatthias Ringwald // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
273357be49d6SMatthias Ringwald void l2cap_le_finialize_channel_close(l2cap_channel_t * channel){
273457be49d6SMatthias Ringwald     channel->state = L2CAP_STATE_CLOSED;
273557be49d6SMatthias Ringwald     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED);
273657be49d6SMatthias Ringwald     // discard channel
273757be49d6SMatthias Ringwald     btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel);
273857be49d6SMatthias Ringwald     btstack_memory_l2cap_channel_free(channel);
273957be49d6SMatthias Ringwald }
274057be49d6SMatthias Ringwald 
2741e7d0c9aaSMatthias Ringwald static inline l2cap_service_t * l2cap_le_get_service(uint16_t le_psm){
2742e7d0c9aaSMatthias Ringwald     return l2cap_get_service_internal(&l2cap_le_services, le_psm);
27437192e786SMatthias Ringwald }
2744efedfb4cSMatthias Ringwald 
2745da144af5SMatthias Ringwald uint8_t l2cap_le_register_service(btstack_packet_handler_t packet_handler, uint16_t psm, gap_security_level_t security_level){
27467192e786SMatthias Ringwald 
2747da144af5SMatthias Ringwald     log_info("L2CAP_LE_REGISTER_SERVICE psm 0x%x", psm);
27487192e786SMatthias Ringwald 
27497192e786SMatthias Ringwald     // check for alread registered psm
27507192e786SMatthias Ringwald     l2cap_service_t *service = l2cap_le_get_service(psm);
27517192e786SMatthias Ringwald     if (service) {
2752da144af5SMatthias Ringwald         return L2CAP_SERVICE_ALREADY_REGISTERED;
27537192e786SMatthias Ringwald     }
27547192e786SMatthias Ringwald 
27557192e786SMatthias Ringwald     // alloc structure
27567192e786SMatthias Ringwald     service = btstack_memory_l2cap_service_get();
27577192e786SMatthias Ringwald     if (!service) {
27587192e786SMatthias Ringwald         log_error("l2cap_register_service_internal: no memory for l2cap_service_t");
2759da144af5SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
27607192e786SMatthias Ringwald     }
27617192e786SMatthias Ringwald 
27627192e786SMatthias Ringwald     // fill in
27637192e786SMatthias Ringwald     service->psm = psm;
2764da144af5SMatthias Ringwald     service->mtu = 0;
27657192e786SMatthias Ringwald     service->packet_handler = packet_handler;
27667192e786SMatthias Ringwald     service->required_security_level = security_level;
27677192e786SMatthias Ringwald 
27687192e786SMatthias Ringwald     // add to services list
2769665d90f2SMatthias Ringwald     btstack_linked_list_add(&l2cap_le_services, (btstack_linked_item_t *) service);
27707192e786SMatthias Ringwald 
27717192e786SMatthias Ringwald     // done
2772da144af5SMatthias Ringwald     return 0;
27737192e786SMatthias Ringwald }
27747192e786SMatthias Ringwald 
2775da144af5SMatthias Ringwald uint8_t l2cap_le_unregister_service(uint16_t psm) {
27767192e786SMatthias Ringwald     log_info("L2CAP_LE_UNREGISTER_SERVICE psm 0x%x", psm);
27777192e786SMatthias Ringwald     l2cap_service_t *service = l2cap_le_get_service(psm);
27789367f9b0SMatthias Ringwald     if (!service) return L2CAP_SERVICE_DOES_NOT_EXIST;
2779da144af5SMatthias Ringwald 
2780665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_le_services, (btstack_linked_item_t *) service);
27817192e786SMatthias Ringwald     btstack_memory_l2cap_service_free(service);
2782da144af5SMatthias Ringwald     return 0;
27837192e786SMatthias Ringwald }
2784da144af5SMatthias Ringwald 
2785da144af5SMatthias Ringwald uint8_t l2cap_le_accept_connection(uint16_t local_cid, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits){
2786e7d0c9aaSMatthias Ringwald     // get channel
2787e7d0c9aaSMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
2788e7d0c9aaSMatthias Ringwald     if (!channel) return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
2789e7d0c9aaSMatthias Ringwald 
2790e7d0c9aaSMatthias Ringwald     // validate state
2791e7d0c9aaSMatthias Ringwald     if (channel->state != L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT){
2792e7d0c9aaSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
2793e7d0c9aaSMatthias Ringwald     }
2794e7d0c9aaSMatthias Ringwald 
2795efedfb4cSMatthias Ringwald     // set state accept connection
279623017473SMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_ACCEPT;
279723017473SMatthias Ringwald     channel->receive_sdu_buffer = receive_sdu_buffer;
279823017473SMatthias Ringwald     channel->local_mtu = mtu;
279985aeef60SMatthias Ringwald     channel->new_credits_incoming = initial_credits;
280085aeef60SMatthias Ringwald     channel->automatic_credits  = initial_credits == L2CAP_LE_AUTOMATIC_CREDITS;
280185aeef60SMatthias Ringwald 
280285aeef60SMatthias Ringwald     // test
280363f0ac45SMatthias Ringwald     // channel->new_credits_incoming = 1;
2804e7d0c9aaSMatthias Ringwald 
2805e7d0c9aaSMatthias Ringwald     // go
2806e7d0c9aaSMatthias Ringwald     l2cap_run();
2807da144af5SMatthias Ringwald     return 0;
2808da144af5SMatthias Ringwald }
2809da144af5SMatthias Ringwald 
2810da144af5SMatthias Ringwald /**
2811da144af5SMatthias Ringwald  * @brief Deny incoming LE Data Channel connection due to resource constraints
2812da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
2813da144af5SMatthias Ringwald  */
2814da144af5SMatthias Ringwald 
2815da144af5SMatthias Ringwald uint8_t l2cap_le_decline_connection(uint16_t local_cid){
2816e7d0c9aaSMatthias Ringwald     // get channel
2817e7d0c9aaSMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
2818e7d0c9aaSMatthias Ringwald     if (!channel) return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
2819e7d0c9aaSMatthias Ringwald 
2820e7d0c9aaSMatthias Ringwald     // validate state
2821e7d0c9aaSMatthias Ringwald     if (channel->state != L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT){
2822e7d0c9aaSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
2823e7d0c9aaSMatthias Ringwald     }
2824e7d0c9aaSMatthias Ringwald 
2825efedfb4cSMatthias Ringwald     // set state decline connection
2826e7d0c9aaSMatthias Ringwald     channel->state  = L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE;
2827e7d0c9aaSMatthias Ringwald     channel->reason = 0x04; // no resources available
2828e7d0c9aaSMatthias Ringwald     l2cap_run();
2829da144af5SMatthias Ringwald     return 0;
2830da144af5SMatthias Ringwald }
2831da144af5SMatthias Ringwald 
28327dafa750SMatthias Ringwald uint8_t l2cap_le_create_channel(btstack_packet_handler_t packet_handler, hci_con_handle_t con_handle,
2833da144af5SMatthias Ringwald     uint16_t psm, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits, gap_security_level_t security_level,
2834efedfb4cSMatthias Ringwald     uint16_t * out_local_cid) {
2835efedfb4cSMatthias Ringwald 
28367dafa750SMatthias Ringwald     log_info("L2CAP_LE_CREATE_CHANNEL handle 0x%04x psm 0x%x mtu %u", con_handle, psm, mtu);
2837da144af5SMatthias Ringwald 
28387dafa750SMatthias Ringwald 
28397dafa750SMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(con_handle);
28407dafa750SMatthias Ringwald     if (!connection) {
28417dafa750SMatthias Ringwald         log_error("no hci_connection for handle 0x%04x", con_handle);
28427dafa750SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
28437dafa750SMatthias Ringwald     }
28447dafa750SMatthias Ringwald 
28457dafa750SMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(packet_handler, connection->address, connection->address_type, psm, mtu, security_level);
2846da144af5SMatthias Ringwald     if (!channel) {
2847da144af5SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
2848da144af5SMatthias Ringwald     }
2849e7d0c9aaSMatthias Ringwald     log_info("l2cap_le_create_channel %p", channel);
2850da144af5SMatthias Ringwald 
2851da144af5SMatthias Ringwald     // store local_cid
2852da144af5SMatthias Ringwald     if (out_local_cid){
2853da144af5SMatthias Ringwald        *out_local_cid = channel->local_cid;
2854da144af5SMatthias Ringwald     }
2855da144af5SMatthias Ringwald 
28567dafa750SMatthias Ringwald     // provide buffer
28577dafa750SMatthias Ringwald     channel->con_handle = con_handle;
2858cd529728SMatthias Ringwald     channel->receive_sdu_buffer = receive_sdu_buffer;
28597dafa750SMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_LE_CONNECTION_REQUEST;
286085aeef60SMatthias Ringwald     channel->new_credits_incoming = initial_credits;
286185aeef60SMatthias Ringwald     channel->automatic_credits    = initial_credits == L2CAP_LE_AUTOMATIC_CREDITS;
286285aeef60SMatthias Ringwald 
2863efedfb4cSMatthias Ringwald     // add to connections list
2864efedfb4cSMatthias Ringwald     btstack_linked_list_add(&l2cap_le_channels, (btstack_linked_item_t *) channel);
2865efedfb4cSMatthias Ringwald 
28667dafa750SMatthias Ringwald     // go
286763f0ac45SMatthias Ringwald     l2cap_run();
2868da144af5SMatthias Ringwald     return 0;
2869da144af5SMatthias Ringwald }
2870da144af5SMatthias Ringwald 
2871da144af5SMatthias Ringwald /**
2872da144af5SMatthias Ringwald  * @brief Provide credtis for LE Data Channel
2873da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
2874da144af5SMatthias Ringwald  * @param credits               Number additional credits for peer
2875da144af5SMatthias Ringwald  */
287664e11ca9SMatthias Ringwald uint8_t l2cap_le_provide_credits(uint16_t local_cid, uint16_t credits){
287763f0ac45SMatthias Ringwald 
287863f0ac45SMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
287963f0ac45SMatthias Ringwald     if (!channel) {
288063f0ac45SMatthias Ringwald         log_error("l2cap_le_provide_credits no channel for cid 0x%02x", local_cid);
288163f0ac45SMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
288263f0ac45SMatthias Ringwald     }
288363f0ac45SMatthias Ringwald 
2884efedfb4cSMatthias Ringwald     // check state
288563f0ac45SMatthias Ringwald     if (channel->state != L2CAP_STATE_OPEN){
288663f0ac45SMatthias Ringwald         log_error("l2cap_le_provide_credits but channel 0x%02x not open yet", local_cid);
288763f0ac45SMatthias Ringwald     }
288863f0ac45SMatthias Ringwald 
288963f0ac45SMatthias Ringwald     // assert incoming credits + credits <= 0xffff
289063f0ac45SMatthias Ringwald     uint32_t total_credits = channel->credits_incoming;
289163f0ac45SMatthias Ringwald     total_credits += channel->new_credits_incoming;
289263f0ac45SMatthias Ringwald     total_credits += credits;
289363f0ac45SMatthias Ringwald     if (total_credits > 0xffff){
289463f0ac45SMatthias Ringwald         log_error("l2cap_le_provide_credits overrun: current %u, scheduled %u, additional %u", channel->credits_incoming,
289563f0ac45SMatthias Ringwald             channel->new_credits_incoming, credits);
289663f0ac45SMatthias Ringwald     }
289763f0ac45SMatthias Ringwald 
2898efedfb4cSMatthias Ringwald     // set credits_granted
289963f0ac45SMatthias Ringwald     channel->new_credits_incoming += credits;
290063f0ac45SMatthias Ringwald 
290163f0ac45SMatthias Ringwald     // go
290263f0ac45SMatthias Ringwald     l2cap_run();
2903da144af5SMatthias Ringwald     return 0;
2904da144af5SMatthias Ringwald }
2905da144af5SMatthias Ringwald 
2906da144af5SMatthias Ringwald /**
2907da144af5SMatthias Ringwald  * @brief Check if outgoing buffer is available and that there's space on the Bluetooth module
2908da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
2909da144af5SMatthias Ringwald  */
291064e11ca9SMatthias Ringwald int l2cap_le_can_send_now(uint16_t local_cid){
291144276248SMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
291244276248SMatthias Ringwald     if (!channel) {
291344276248SMatthias Ringwald         log_error("l2cap_le_provide_credits no channel for cid 0x%02x", local_cid);
2914da144af5SMatthias Ringwald         return 0;
2915da144af5SMatthias Ringwald     }
2916da144af5SMatthias Ringwald 
291744276248SMatthias Ringwald     // check state
291844276248SMatthias Ringwald     if (channel->state != L2CAP_STATE_OPEN) return 0;
291944276248SMatthias Ringwald 
292044276248SMatthias Ringwald     // check queue
292144276248SMatthias Ringwald     if (channel->send_sdu_buffer) return 0;
292244276248SMatthias Ringwald 
292344276248SMatthias Ringwald     // fine, go ahead
292444276248SMatthias Ringwald     return 1;
292544276248SMatthias Ringwald }
292644276248SMatthias Ringwald 
2927da144af5SMatthias Ringwald /**
2928da144af5SMatthias Ringwald  * @brief Request emission of L2CAP_EVENT_CAN_SEND_NOW as soon as possible
2929da144af5SMatthias Ringwald  * @note L2CAP_EVENT_CAN_SEND_NOW might be emitted during call to this function
2930da144af5SMatthias Ringwald  *       so packet handler should be ready to handle it
2931da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
2932da144af5SMatthias Ringwald  */
293364e11ca9SMatthias Ringwald uint8_t l2cap_le_request_can_send_now_event(uint16_t local_cid){
293444276248SMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
293544276248SMatthias Ringwald     if (!channel) {
293644276248SMatthias Ringwald         log_error("l2cap_le_request_can_send_now_event no channel for cid 0x%02x", local_cid);
293744276248SMatthias Ringwald         return 0;
293844276248SMatthias Ringwald     }
293944276248SMatthias Ringwald     channel->waiting_for_can_send_now = 1;
294044276248SMatthias Ringwald     l2cap_le_notify_channel_can_send(channel);
2941da144af5SMatthias Ringwald     return 0;
2942da144af5SMatthias Ringwald }
2943da144af5SMatthias Ringwald 
2944da144af5SMatthias Ringwald /**
2945da144af5SMatthias Ringwald  * @brief Send data via LE Data Channel
2946da144af5SMatthias Ringwald  * @note Since data larger then the maximum PDU needs to be segmented into multiple PDUs, data needs to stay valid until ... event
2947da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
2948da144af5SMatthias Ringwald  * @param data                  data to send
2949da144af5SMatthias Ringwald  * @param size                  data size
2950da144af5SMatthias Ringwald  */
295164e11ca9SMatthias Ringwald uint8_t l2cap_le_send_data(uint16_t local_cid, uint8_t * data, uint16_t len){
295264e11ca9SMatthias Ringwald 
295364e11ca9SMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
295464e11ca9SMatthias Ringwald     if (!channel) {
295564e11ca9SMatthias Ringwald         log_error("l2cap_send no channel for cid 0x%02x", local_cid);
2956828a7f7aSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
295764e11ca9SMatthias Ringwald     }
295864e11ca9SMatthias Ringwald 
295964e11ca9SMatthias Ringwald     if (len > channel->remote_mtu){
296064e11ca9SMatthias Ringwald         log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", local_cid);
296164e11ca9SMatthias Ringwald         return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU;
296264e11ca9SMatthias Ringwald     }
296364e11ca9SMatthias Ringwald 
29647f107edaSMatthias Ringwald     if (channel->send_sdu_buffer){
296564e11ca9SMatthias Ringwald         log_info("l2cap_send cid 0x%02x, cannot send", local_cid);
296664e11ca9SMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
296764e11ca9SMatthias Ringwald     }
296864e11ca9SMatthias Ringwald 
29697f107edaSMatthias Ringwald     channel->send_sdu_buffer = data;
29707f107edaSMatthias Ringwald     channel->send_sdu_len    = len;
29717f107edaSMatthias Ringwald     channel->send_sdu_pos    = 0;
297264e11ca9SMatthias Ringwald 
29737f107edaSMatthias Ringwald     l2cap_run();
29747f107edaSMatthias Ringwald     return 0;
2975da144af5SMatthias Ringwald }
2976da144af5SMatthias Ringwald 
2977da144af5SMatthias Ringwald /**
2978da144af5SMatthias Ringwald  * @brief Disconnect from LE Data Channel
2979da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
2980da144af5SMatthias Ringwald  */
2981828a7f7aSMatthias Ringwald uint8_t l2cap_le_disconnect(uint16_t local_cid)
2982da144af5SMatthias Ringwald {
2983828a7f7aSMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
2984828a7f7aSMatthias Ringwald     if (!channel) {
2985828a7f7aSMatthias Ringwald         log_error("l2cap_send no channel for cid 0x%02x", local_cid);
2986828a7f7aSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
2987828a7f7aSMatthias Ringwald     }
2988828a7f7aSMatthias Ringwald 
2989828a7f7aSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
2990828a7f7aSMatthias Ringwald     l2cap_run();
2991da144af5SMatthias Ringwald     return 0;
2992da144af5SMatthias Ringwald }
2993da144af5SMatthias Ringwald 
29947f02f414SMatthias Ringwald #endif
2995