xref: /btstack/src/l2cap.c (revision c9300dca9afd5a419cbf974982f003364f6e30ec)
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
113212b6be2SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
11496646001SMatthias Ringwald static void l2cap_ertm_notify_channel_can_send(l2cap_channel_t * channel);
115212b6be2SMatthias Ringwald static int l2cap_ertm_num_unacknowledged_tx_packets(l2cap_channel_t * channel);
116*c9300dcaSMatthias Ringwald static void l2cap_ertm_monitor_timeout_callback(btstack_timer_source_t * ts);
117212b6be2SMatthias Ringwald #endif
11833c40538SMatthias Ringwald 
1195628cf69SMatthias Ringwald typedef struct l2cap_fixed_channel {
1205628cf69SMatthias Ringwald     btstack_packet_handler_t callback;
1212125de09SMatthias Ringwald     uint8_t waiting_for_can_send_now;
1225628cf69SMatthias Ringwald } l2cap_fixed_channel_t;
1235628cf69SMatthias Ringwald 
12409e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1255628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_channels;
1265628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_services;
12709e9d05bSMatthias Ringwald static uint8_t require_security_level2_for_outgoing_sdp;
12809e9d05bSMatthias Ringwald #endif
12957be49d6SMatthias Ringwald 
13057be49d6SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
1315628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_le_channels;
1325628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_le_services;
13357be49d6SMatthias Ringwald #endif
13439bda6d5Smatthias.ringwald 
13539bda6d5Smatthias.ringwald // used to cache l2cap rejects, echo, and informational requests
1362b83fb7dSmatthias.ringwald static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES];
1372b83fb7dSmatthias.ringwald static int signaling_responses_pending;
1382b83fb7dSmatthias.ringwald 
139fb37a842SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
1405628cf69SMatthias Ringwald static l2cap_fixed_channel_t fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_SIZE];
14139bda6d5Smatthias.ringwald 
142d6ed9f9cSMatthias Ringwald #ifdef ENABLE_BLE
143d6ed9f9cSMatthias Ringwald // only used for connection parameter update events
144d6ed9f9cSMatthias Ringwald static btstack_packet_handler_t l2cap_event_packet_handler;
145d6ed9f9cSMatthias Ringwald #endif
146d6ed9f9cSMatthias Ringwald 
14785ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
14885ddcd84SMatthias Ringwald 
14985ddcd84SMatthias Ringwald /*
15085ddcd84SMatthias Ringwald  * CRC lookup table for generator polynom D^16 + D^15 + D^2 + 1
15185ddcd84SMatthias Ringwald  */
15285ddcd84SMatthias Ringwald static const uint16_t crc16_table[256] = {
15385ddcd84SMatthias Ringwald     0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
15485ddcd84SMatthias Ringwald     0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
15585ddcd84SMatthias Ringwald     0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
15685ddcd84SMatthias Ringwald     0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
15785ddcd84SMatthias Ringwald     0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
15885ddcd84SMatthias Ringwald     0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
15985ddcd84SMatthias Ringwald     0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
16085ddcd84SMatthias Ringwald     0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
16185ddcd84SMatthias Ringwald     0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
16285ddcd84SMatthias Ringwald     0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
16385ddcd84SMatthias Ringwald     0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
16485ddcd84SMatthias Ringwald     0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
16585ddcd84SMatthias Ringwald     0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
16685ddcd84SMatthias Ringwald     0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
16785ddcd84SMatthias Ringwald     0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
16885ddcd84SMatthias Ringwald     0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
16985ddcd84SMatthias Ringwald };
17085ddcd84SMatthias Ringwald 
17185ddcd84SMatthias Ringwald static uint16_t crc16_calc(uint8_t * data, uint16_t len){
17285ddcd84SMatthias Ringwald     uint16_t crc = 0;   // initial value = 0
17385ddcd84SMatthias Ringwald     while (len--){
17485ddcd84SMatthias Ringwald         crc = (crc >> 8) ^ crc16_table[ (crc ^ ((uint16_t) *data++)) & 0x00FF ];
17585ddcd84SMatthias Ringwald     }
17685ddcd84SMatthias Ringwald     return crc;
17785ddcd84SMatthias Ringwald }
17885ddcd84SMatthias Ringwald 
17985ddcd84SMatthias Ringwald #endif
18085ddcd84SMatthias Ringwald 
18185ddcd84SMatthias Ringwald 
18234e7e577SMatthias Ringwald static uint16_t l2cap_fixed_channel_table_channel_id_for_index(int index){
18334e7e577SMatthias Ringwald     switch (index){
18434e7e577SMatthias Ringwald         case L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL:
18534e7e577SMatthias Ringwald             return L2CAP_CID_ATTRIBUTE_PROTOCOL;
18634e7e577SMatthias Ringwald         case L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL:
18734e7e577SMatthias Ringwald             return L2CAP_CID_SECURITY_MANAGER_PROTOCOL;
18834e7e577SMatthias Ringwald         case L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL:
18934e7e577SMatthias Ringwald             return L2CAP_CID_CONNECTIONLESS_CHANNEL;
19034e7e577SMatthias Ringwald         default:
19134e7e577SMatthias Ringwald             return 0;
19234e7e577SMatthias Ringwald     }
19334e7e577SMatthias Ringwald }
1945628cf69SMatthias Ringwald static int l2cap_fixed_channel_table_index_for_channel_id(uint16_t channel_id){
1955628cf69SMatthias Ringwald     switch (channel_id){
1965628cf69SMatthias Ringwald         case L2CAP_CID_ATTRIBUTE_PROTOCOL:
1975628cf69SMatthias Ringwald             return L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL;
1985628cf69SMatthias Ringwald         case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
1995628cf69SMatthias Ringwald             return  L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL;
2005628cf69SMatthias Ringwald         case L2CAP_CID_CONNECTIONLESS_CHANNEL:
2015628cf69SMatthias Ringwald             return  L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL;
2025628cf69SMatthias Ringwald         default:
2035628cf69SMatthias Ringwald             return -1;
2045628cf69SMatthias Ringwald         }
2055628cf69SMatthias Ringwald }
20639bda6d5Smatthias.ringwald 
20734e7e577SMatthias Ringwald static int l2cap_fixed_channel_table_index_is_le(int index){
20834e7e577SMatthias Ringwald     if (index == L2CAP_CID_CONNECTIONLESS_CHANNEL) return 0;
20934e7e577SMatthias Ringwald     return 1;
21034e7e577SMatthias Ringwald }
21134e7e577SMatthias Ringwald 
21271de195eSMatthias Ringwald void l2cap_init(void){
2132b83fb7dSmatthias.ringwald     signaling_responses_pending = 0;
214808a48abSmatthias.ringwald 
21509e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
216f5454fc6Smatthias.ringwald     l2cap_channels = NULL;
217f5454fc6Smatthias.ringwald     l2cap_services = NULL;
21809e9d05bSMatthias Ringwald     require_security_level2_for_outgoing_sdp = 0;
21909e9d05bSMatthias Ringwald #endif
220a3dc965aSMatthias Ringwald 
221a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2227192e786SMatthias Ringwald     l2cap_le_services = NULL;
2237192e786SMatthias Ringwald     l2cap_le_channels = NULL;
224a3dc965aSMatthias Ringwald #endif
225f5454fc6Smatthias.ringwald 
226d6ed9f9cSMatthias Ringwald #ifdef ENABLE_BLE
22733c40538SMatthias Ringwald     l2cap_event_packet_handler = NULL;
228d6ed9f9cSMatthias Ringwald #endif
2295628cf69SMatthias Ringwald     memset(fixed_channels, 0, sizeof(fixed_channels));
230f5454fc6Smatthias.ringwald 
231fcadd0caSmatthias.ringwald     //
2322718e2e7Smatthias.ringwald     // register callback with HCI
233fcadd0caSmatthias.ringwald     //
234d9a7306aSMatthias Ringwald     hci_event_callback_registration.callback = &l2cap_hci_event_handler;
235fb37a842SMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
236fb37a842SMatthias Ringwald 
237d9a7306aSMatthias Ringwald     hci_register_acl_packet_handler(&l2cap_acl_handler);
238fb37a842SMatthias Ringwald 
239be005ed6SMatthias Ringwald #ifdef ENABLE_CLASSIC
24015a95bd5SMatthias Ringwald     gap_connectable_control(0); // no services yet
241be005ed6SMatthias Ringwald #endif
242fcadd0caSmatthias.ringwald }
243fcadd0caSmatthias.ringwald 
244ffbf8201SMatthias Ringwald void l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
245d6ed9f9cSMatthias Ringwald #ifdef ENABLE_BLE
24633c40538SMatthias Ringwald     l2cap_event_packet_handler = handler;
247d6ed9f9cSMatthias Ringwald #else
248d6ed9f9cSMatthias Ringwald     UNUSED(handler);
249d6ed9f9cSMatthias Ringwald #endif
2501e6aba47Smatthias.ringwald }
2511e6aba47Smatthias.ringwald 
25209e9d05bSMatthias Ringwald void l2cap_request_can_send_fix_channel_now_event(hci_con_handle_t con_handle, uint16_t channel_id){
2539ec2630cSMatthias Ringwald     UNUSED(con_handle);
2549ec2630cSMatthias Ringwald 
25509e9d05bSMatthias Ringwald     int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id);
25609e9d05bSMatthias Ringwald     if (index < 0) return;
25709e9d05bSMatthias Ringwald     fixed_channels[index].waiting_for_can_send_now = 1;
25809e9d05bSMatthias Ringwald     l2cap_notify_channel_can_send();
25909e9d05bSMatthias Ringwald }
26009e9d05bSMatthias Ringwald 
26109e9d05bSMatthias Ringwald int  l2cap_can_send_fixed_channel_packet_now(hci_con_handle_t con_handle, uint16_t channel_id){
2629ec2630cSMatthias Ringwald     UNUSED(channel_id);
2639ec2630cSMatthias Ringwald 
26409e9d05bSMatthias Ringwald     return hci_can_send_acl_packet_now(con_handle);
26509e9d05bSMatthias Ringwald }
26609e9d05bSMatthias Ringwald 
26709e9d05bSMatthias Ringwald uint8_t *l2cap_get_outgoing_buffer(void){
26809e9d05bSMatthias Ringwald     return hci_get_outgoing_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
26909e9d05bSMatthias Ringwald }
27009e9d05bSMatthias Ringwald 
27109e9d05bSMatthias Ringwald int l2cap_reserve_packet_buffer(void){
27209e9d05bSMatthias Ringwald     return hci_reserve_packet_buffer();
27309e9d05bSMatthias Ringwald }
27409e9d05bSMatthias Ringwald 
27509e9d05bSMatthias Ringwald void l2cap_release_packet_buffer(void){
27609e9d05bSMatthias Ringwald     hci_release_packet_buffer();
27709e9d05bSMatthias Ringwald }
27809e9d05bSMatthias Ringwald 
279f511cefaSMatthias 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){
28009e9d05bSMatthias Ringwald     // 0 - Connection handle : PB=pb : BC=00
281f511cefaSMatthias Ringwald     little_endian_store_16(acl_buffer, 0, con_handle | (packet_boundary << 12) | (0 << 14));
28209e9d05bSMatthias Ringwald     // 2 - ACL length
28309e9d05bSMatthias Ringwald     little_endian_store_16(acl_buffer, 2,  len + 4);
28409e9d05bSMatthias Ringwald     // 4 - L2CAP packet length
28509e9d05bSMatthias Ringwald     little_endian_store_16(acl_buffer, 4,  len + 0);
28609e9d05bSMatthias Ringwald     // 6 - L2CAP channel DEST
28709e9d05bSMatthias Ringwald     little_endian_store_16(acl_buffer, 6,  remote_cid);
28809e9d05bSMatthias Ringwald }
28909e9d05bSMatthias Ringwald 
290f511cefaSMatthias Ringwald // assumption - only on LE connections
29109e9d05bSMatthias Ringwald int l2cap_send_prepared_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint16_t len){
29209e9d05bSMatthias Ringwald 
29309e9d05bSMatthias Ringwald     if (!hci_is_packet_buffer_reserved()){
29409e9d05bSMatthias Ringwald         log_error("l2cap_send_prepared_connectionless called without reserving packet first");
29509e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
29609e9d05bSMatthias Ringwald     }
29709e9d05bSMatthias Ringwald 
29809e9d05bSMatthias Ringwald     if (!hci_can_send_prepared_acl_packet_now(con_handle)){
29909e9d05bSMatthias Ringwald         log_info("l2cap_send_prepared_connectionless handle 0x%02x, cid 0x%02x, cannot send", con_handle, cid);
30009e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
30109e9d05bSMatthias Ringwald     }
30209e9d05bSMatthias Ringwald 
30309e9d05bSMatthias Ringwald     log_debug("l2cap_send_prepared_connectionless handle %u, cid 0x%02x", con_handle, cid);
30409e9d05bSMatthias Ringwald 
30509e9d05bSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
306f511cefaSMatthias Ringwald     l2cap_setup_header(acl_buffer, con_handle, 0, cid, len);
30709e9d05bSMatthias Ringwald     // send
30809e9d05bSMatthias Ringwald     return hci_send_acl_packet_buffer(len+8);
30909e9d05bSMatthias Ringwald }
31009e9d05bSMatthias Ringwald 
311f511cefaSMatthias Ringwald // assumption - only on LE connections
31209e9d05bSMatthias Ringwald int l2cap_send_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint8_t *data, uint16_t len){
31309e9d05bSMatthias Ringwald 
31409e9d05bSMatthias Ringwald     if (!hci_can_send_acl_packet_now(con_handle)){
31509e9d05bSMatthias Ringwald         log_info("l2cap_send cid 0x%02x, cannot send", cid);
31609e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
31709e9d05bSMatthias Ringwald     }
31809e9d05bSMatthias Ringwald 
31909e9d05bSMatthias Ringwald     hci_reserve_packet_buffer();
32009e9d05bSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
32109e9d05bSMatthias Ringwald 
32209e9d05bSMatthias Ringwald     memcpy(&acl_buffer[8], data, len);
32309e9d05bSMatthias Ringwald 
32409e9d05bSMatthias Ringwald     return l2cap_send_prepared_connectionless(con_handle, cid, len);
32509e9d05bSMatthias Ringwald }
32609e9d05bSMatthias Ringwald 
32709e9d05bSMatthias Ringwald static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel) {
328d9d23054SMatthias Ringwald     log_debug("L2CAP_EVENT_CHANNEL_CAN_SEND_NOW local_cid 0x%x", channel);
32909e9d05bSMatthias Ringwald     uint8_t event[4];
33009e9d05bSMatthias Ringwald     event[0] = L2CAP_EVENT_CAN_SEND_NOW;
33109e9d05bSMatthias Ringwald     event[1] = sizeof(event) - 2;
33209e9d05bSMatthias Ringwald     little_endian_store_16(event, 2, channel);
33309e9d05bSMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
33409e9d05bSMatthias Ringwald     packet_handler(HCI_EVENT_PACKET, channel, event, sizeof(event));
33509e9d05bSMatthias Ringwald }
33609e9d05bSMatthias Ringwald 
33709e9d05bSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
33817a9b554SMatthias Ringwald static void l2cap_dispatch_to_channel(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){
33958de5610Smatthias.ringwald     (* (channel->packet_handler))(type, channel->local_cid, data, size);
34058de5610Smatthias.ringwald }
34158de5610Smatthias.ringwald 
34244276248SMatthias Ringwald static void l2cap_emit_simple_event_with_cid(l2cap_channel_t * channel, uint8_t event_code){
34344276248SMatthias Ringwald     uint8_t event[4];
34444276248SMatthias Ringwald     event[0] = event_code;
34544276248SMatthias Ringwald     event[1] = sizeof(event) - 2;
34644276248SMatthias Ringwald     little_endian_store_16(event, 2, channel->local_cid);
34744276248SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
34844276248SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
34944276248SMatthias Ringwald }
35009e9d05bSMatthias Ringwald #endif
35144276248SMatthias Ringwald 
35209e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
35358de5610Smatthias.ringwald void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
354c9dc710bS[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",
355fc64f94aSMatthias Ringwald              status, bd_addr_to_str(channel->address), channel->con_handle, channel->psm,
356c9dc710bS[email protected]              channel->local_cid, channel->remote_cid, channel->local_mtu, channel->remote_mtu, channel->flush_timeout);
357bab5f4f0SMatthias Ringwald     uint8_t event[24];
35858de5610Smatthias.ringwald     event[0] = L2CAP_EVENT_CHANNEL_OPENED;
35958de5610Smatthias.ringwald     event[1] = sizeof(event) - 2;
36058de5610Smatthias.ringwald     event[2] = status;
361724d70a2SMatthias Ringwald     reverse_bd_addr(channel->address, &event[3]);
362fc64f94aSMatthias Ringwald     little_endian_store_16(event,  9, channel->con_handle);
363f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 11, channel->psm);
364f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 13, channel->local_cid);
365f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 15, channel->remote_cid);
366f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 17, channel->local_mtu);
367f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 19, channel->remote_mtu);
368f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 21, channel->flush_timeout);
369bab5f4f0SMatthias Ringwald     event[23] = channel->state_var & L2CAP_CHANNEL_STATE_VAR_INCOMING ? 1 : 0;
37058de5610Smatthias.ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
37117a9b554SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
37258de5610Smatthias.ringwald }
37358de5610Smatthias.ringwald 
37444276248SMatthias Ringwald static void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
375e0abb8e7S[email protected]     log_info("L2CAP_EVENT_CHANNEL_CLOSED local_cid 0x%x", channel->local_cid);
37644276248SMatthias Ringwald     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED);
37758de5610Smatthias.ringwald }
37858de5610Smatthias.ringwald 
37944276248SMatthias Ringwald static void l2cap_emit_incoming_connection(l2cap_channel_t *channel) {
380e0abb8e7S[email protected]     log_info("L2CAP_EVENT_INCOMING_CONNECTION addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x",
381fc64f94aSMatthias Ringwald              bd_addr_to_str(channel->address), channel->con_handle,  channel->psm, channel->local_cid, channel->remote_cid);
38258de5610Smatthias.ringwald     uint8_t event[16];
38358de5610Smatthias.ringwald     event[0] = L2CAP_EVENT_INCOMING_CONNECTION;
38458de5610Smatthias.ringwald     event[1] = sizeof(event) - 2;
385724d70a2SMatthias Ringwald     reverse_bd_addr(channel->address, &event[2]);
386fc64f94aSMatthias Ringwald     little_endian_store_16(event,  8, channel->con_handle);
387f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 10, channel->psm);
388f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 12, channel->local_cid);
389f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 14, channel->remote_cid);
39058de5610Smatthias.ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
39117a9b554SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
3920af41d30Smatthias.ringwald }
393808a48abSmatthias.ringwald 
3947f02f414SMatthias Ringwald static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
395665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
396665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
397665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
398665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
399b35f641cSmatthias.ringwald         if ( channel->local_cid == local_cid) {
400f62db1e3Smatthias.ringwald             return channel;
401f62db1e3Smatthias.ringwald         }
402f62db1e3Smatthias.ringwald     }
403f62db1e3Smatthias.ringwald     return NULL;
404f62db1e3Smatthias.ringwald }
405f62db1e3Smatthias.ringwald 
4060b9d7e78SMatthias Ringwald ///
4070b9d7e78SMatthias Ringwald 
40830725612SMatthias Ringwald void l2cap_request_can_send_now_event(uint16_t local_cid){
40930725612SMatthias Ringwald     l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
41030725612SMatthias Ringwald     if (!channel) return;
41130725612SMatthias Ringwald     channel->waiting_for_can_send_now = 1;
41296646001SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
41396646001SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
41496646001SMatthias Ringwald         l2cap_ertm_notify_channel_can_send(channel);
41596646001SMatthias Ringwald         return;
41696646001SMatthias Ringwald     }
41796646001SMatthias Ringwald #endif
41830725612SMatthias Ringwald     l2cap_notify_channel_can_send();
41930725612SMatthias Ringwald }
42030725612SMatthias Ringwald 
4210b20b13bSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
42296646001SMatthias Ringwald static int l2cap_ertm_can_store_packet_now(l2cap_channel_t * channel){
4230b20b13bSMatthias Ringwald      // get num free tx buffers
4240b20b13bSMatthias Ringwald     int num_tx_buffers_used = channel->tx_write_index - channel->tx_read_index;
4250b20b13bSMatthias Ringwald     if (num_tx_buffers_used < 0){
4260b20b13bSMatthias Ringwald         num_tx_buffers_used += channel->num_tx_buffers;
4270b20b13bSMatthias Ringwald     }
4280b20b13bSMatthias Ringwald     int num_free_tx_buffers = channel->num_tx_buffers - num_tx_buffers_used;
4290b20b13bSMatthias Ringwald     // calculate num tx buffers for remote MTU
4300b20b13bSMatthias Ringwald     int num_tx_buffers_for_max_remote_mtu;
4310b20b13bSMatthias Ringwald     if (channel->remote_mtu <= channel->remote_mps){
4320b20b13bSMatthias Ringwald         // MTU fits into single packet
4330b20b13bSMatthias Ringwald         num_tx_buffers_for_max_remote_mtu = 1;
4340b20b13bSMatthias Ringwald     } else {
4350b20b13bSMatthias Ringwald         // include SDU Length
4360b20b13bSMatthias Ringwald         num_tx_buffers_for_max_remote_mtu = (channel->remote_mtu + 2 + (channel->remote_mps - 1)) / channel->remote_mps;
4370b20b13bSMatthias Ringwald     }
4380b20b13bSMatthias Ringwald     return num_tx_buffers_for_max_remote_mtu <= num_free_tx_buffers;
4390b20b13bSMatthias Ringwald }
4400b20b13bSMatthias Ringwald #endif
44196646001SMatthias Ringwald 
44296646001SMatthias Ringwald int  l2cap_can_send_packet_now(uint16_t local_cid){
44396646001SMatthias Ringwald     l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
44496646001SMatthias Ringwald     if (!channel) return 0;
44596646001SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
44696646001SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
44796646001SMatthias Ringwald         return l2cap_ertm_can_store_packet_now(channel);
44896646001SMatthias Ringwald     }
44996646001SMatthias Ringwald #endif
4500b9d7e78SMatthias Ringwald     return hci_can_send_acl_packet_now(channel->con_handle);
4517856fb31S[email protected] }
4527856fb31S[email protected] 
45383e7cdd9SMatthias Ringwald int  l2cap_can_send_prepared_packet_now(uint16_t local_cid){
45483e7cdd9SMatthias Ringwald     l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
45583e7cdd9SMatthias Ringwald     if (!channel) return 0;
4560b20b13bSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
4570b20b13bSMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
4580b20b13bSMatthias Ringwald         return 0;
4590b20b13bSMatthias Ringwald     }
4600b20b13bSMatthias Ringwald #endif
4610b9d7e78SMatthias Ringwald     return hci_can_send_prepared_acl_packet_now(channel->con_handle);
46283e7cdd9SMatthias Ringwald }
4630b20b13bSMatthias Ringwald 
46496cbd662Smatthias.ringwald uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){
46596cbd662Smatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
46696cbd662Smatthias.ringwald     if (channel) {
46796cbd662Smatthias.ringwald         return channel->remote_mtu;
46896cbd662Smatthias.ringwald     }
46996cbd662Smatthias.ringwald     return 0;
47096cbd662Smatthias.ringwald }
47196cbd662Smatthias.ringwald 
472ec820d77SMatthias Ringwald static l2cap_channel_t * l2cap_channel_for_rtx_timer(btstack_timer_source_t * ts){
473665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
474665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
475665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
476665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
4775932bd7cS[email protected]         if ( &channel->rtx == ts) {
4785932bd7cS[email protected]             return channel;
4795932bd7cS[email protected]         }
4805932bd7cS[email protected]     }
4815932bd7cS[email protected]     return NULL;
4825932bd7cS[email protected] }
4835932bd7cS[email protected] 
484ec820d77SMatthias Ringwald static void l2cap_rtx_timeout(btstack_timer_source_t * ts){
4855932bd7cS[email protected]     l2cap_channel_t * channel = l2cap_channel_for_rtx_timer(ts);
48695d2c8f4SMatthias Ringwald     if (!channel) return;
4875932bd7cS[email protected] 
4885932bd7cS[email protected]     log_info("l2cap_rtx_timeout for local cid 0x%02x", channel->local_cid);
4895932bd7cS[email protected] 
4905932bd7cS[email protected]     // "When terminating the channel, it is not necessary to send a L2CAP_DisconnectReq
4915932bd7cS[email protected]     //  and enter WAIT_DISCONNECT state. Channels can be transitioned directly to the CLOSED state."
4925932bd7cS[email protected]     // notify client
4935932bd7cS[email protected]     l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_RTX_TIMEOUT);
4945932bd7cS[email protected] 
4955932bd7cS[email protected]     // discard channel
4969dcb2fb2S[email protected]     // no need to stop timer here, it is removed from list during timer callback
497665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
4985932bd7cS[email protected]     btstack_memory_l2cap_channel_free(channel);
4995932bd7cS[email protected] }
5005932bd7cS[email protected] 
5015932bd7cS[email protected] static void l2cap_stop_rtx(l2cap_channel_t * channel){
5025932bd7cS[email protected]     log_info("l2cap_stop_rtx for local cid 0x%02x", channel->local_cid);
503528a4a3bSMatthias Ringwald     btstack_run_loop_remove_timer(&channel->rtx);
5045932bd7cS[email protected] }
5055932bd7cS[email protected] 
5065932bd7cS[email protected] static void l2cap_start_rtx(l2cap_channel_t * channel){
5075932bd7cS[email protected]     l2cap_stop_rtx(channel);
508cb0ff06bS[email protected]     log_info("l2cap_start_rtx for local cid 0x%02x", channel->local_cid);
509528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->rtx, l2cap_rtx_timeout);
510528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer(&channel->rtx, L2CAP_RTX_TIMEOUT_MS);
511528a4a3bSMatthias Ringwald     btstack_run_loop_add_timer(&channel->rtx);
5125932bd7cS[email protected] }
5135932bd7cS[email protected] 
5145932bd7cS[email protected] static void l2cap_start_ertx(l2cap_channel_t * channel){
5155932bd7cS[email protected]     log_info("l2cap_start_ertx for local cid 0x%02x", channel->local_cid);
5165932bd7cS[email protected]     l2cap_stop_rtx(channel);
517528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->rtx, l2cap_rtx_timeout);
518528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer(&channel->rtx, L2CAP_ERTX_TIMEOUT_MS);
519528a4a3bSMatthias Ringwald     btstack_run_loop_add_timer(&channel->rtx);
5205932bd7cS[email protected] }
5215932bd7cS[email protected] 
52271de195eSMatthias Ringwald void l2cap_require_security_level_2_for_outgoing_sdp(void){
523ac301f95S[email protected]     require_security_level2_for_outgoing_sdp = 1;
524ac301f95S[email protected] }
525ac301f95S[email protected] 
526df3354fcS[email protected] static int l2cap_security_level_0_allowed_for_PSM(uint16_t psm){
527235946f1SMatthias Ringwald     return (psm == BLUETOOTH_PROTOCOL_SDP) && (!require_security_level2_for_outgoing_sdp);
528df3354fcS[email protected] }
5295932bd7cS[email protected] 
5307f02f414SMatthias Ringwald static int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
531a35252c8S[email protected]     if (!hci_can_send_acl_packet_now(handle)){
5329da54300S[email protected]         log_info("l2cap_send_signaling_packet, cannot send");
533b1d43497Smatthias.ringwald         return BTSTACK_ACL_BUFFERS_FULL;
534b1d43497Smatthias.ringwald     }
535b1d43497Smatthias.ringwald 
5369da54300S[email protected]     // log_info("l2cap_send_signaling_packet type %u", cmd);
5372a373862S[email protected]     hci_reserve_packet_buffer();
538facf93fdS[email protected]     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
53958de5610Smatthias.ringwald     va_list argptr;
54058de5610Smatthias.ringwald     va_start(argptr, identifier);
54170efece1S[email protected]     uint16_t len = l2cap_create_signaling_classic(acl_buffer, handle, cmd, identifier, argptr);
54258de5610Smatthias.ringwald     va_end(argptr);
5439da54300S[email protected]     // log_info("l2cap_send_signaling_packet con %u!", handle);
544826f7347S[email protected]     return hci_send_acl_packet_buffer(len);
54558de5610Smatthias.ringwald }
54658de5610Smatthias.ringwald 
547f511cefaSMatthias Ringwald // assumption - only on Classic connections
548b1d43497Smatthias.ringwald int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
549b1d43497Smatthias.ringwald 
550c8b9416aS[email protected]     if (!hci_is_packet_buffer_reserved()){
551c8b9416aS[email protected]         log_error("l2cap_send_prepared called without reserving packet first");
552c8b9416aS[email protected]         return BTSTACK_ACL_BUFFERS_FULL;
553c8b9416aS[email protected]     }
554c8b9416aS[email protected] 
55558de5610Smatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
556b1d43497Smatthias.ringwald     if (!channel) {
5579da54300S[email protected]         log_error("l2cap_send_prepared no channel for cid 0x%02x", local_cid);
558b1d43497Smatthias.ringwald         return -1;   // TODO: define error
5596218e6f1Smatthias.ringwald     }
5606218e6f1Smatthias.ringwald 
561fc64f94aSMatthias Ringwald     if (!hci_can_send_prepared_acl_packet_now(channel->con_handle)){
5629da54300S[email protected]         log_info("l2cap_send_prepared cid 0x%02x, cannot send", local_cid);
563a35252c8S[email protected]         return BTSTACK_ACL_BUFFERS_FULL;
564a35252c8S[email protected]     }
565a35252c8S[email protected] 
566fc64f94aSMatthias Ringwald     log_debug("l2cap_send_prepared cid 0x%02x, handle %u, 1 credit used", local_cid, channel->con_handle);
567b1d43497Smatthias.ringwald 
56885ddcd84SMatthias Ringwald     int fcs_size = 0;
56985ddcd84SMatthias Ringwald 
57085ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
57185ddcd84SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
57285ddcd84SMatthias Ringwald         fcs_size = 2;
57385ddcd84SMatthias Ringwald     }
57485ddcd84SMatthias Ringwald #endif
57585ddcd84SMatthias Ringwald 
576f511cefaSMatthias Ringwald     // set non-flushable packet boundary flag if supported on Controller
577facf93fdS[email protected]     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
578f511cefaSMatthias Ringwald     uint8_t packet_boundary_flag = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02;
57985ddcd84SMatthias Ringwald     l2cap_setup_header(acl_buffer, channel->con_handle, packet_boundary_flag, channel->remote_cid, len + fcs_size);
58085ddcd84SMatthias Ringwald 
58185ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
58285ddcd84SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
58385ddcd84SMatthias Ringwald         // calculate FCS over l2cap data
58485ddcd84SMatthias Ringwald         uint16_t fcs = crc16_calc(acl_buffer + 4, 4 + len);
58585ddcd84SMatthias Ringwald         log_info("I-Frame: fcs 0x%04x", fcs);
58685ddcd84SMatthias Ringwald         little_endian_store_16(acl_buffer, 8 + len, fcs);
58758de5610Smatthias.ringwald     }
58885ddcd84SMatthias Ringwald #endif
58985ddcd84SMatthias Ringwald 
59085ddcd84SMatthias Ringwald     // send
59185ddcd84SMatthias Ringwald     return hci_send_acl_packet_buffer(len+8+fcs_size);
59285ddcd84SMatthias Ringwald }
59385ddcd84SMatthias Ringwald 
59485ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
59585ddcd84SMatthias 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){
59685ddcd84SMatthias Ringwald     return (((uint16_t) sar) << 14) | (req_seq << 8) | (final << 7) | (tx_seq << 1) | 0;
59785ddcd84SMatthias Ringwald }
59885ddcd84SMatthias 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){
59938f62777SMatthias Ringwald     return (req_seq << 8) | (final << 7) | (poll << 4) | (((int) supervisory_function) << 2) | 1;
60085ddcd84SMatthias Ringwald }
60185ddcd84SMatthias Ringwald static int l2cap_next_ertm_seq_nr(int seq_nr){
60285ddcd84SMatthias Ringwald     return (seq_nr + 1) & 0x3f;
60385ddcd84SMatthias Ringwald }
604f0fb4cd7SMatthias Ringwald static void l2cap_ertm_next_tx_write_index(l2cap_channel_t * channel){
605f0fb4cd7SMatthias Ringwald     channel->tx_write_index++;
606f0fb4cd7SMatthias Ringwald     if (channel->tx_write_index < channel->num_tx_buffers) return;
607f0fb4cd7SMatthias Ringwald     channel->tx_write_index = 0;
608f0fb4cd7SMatthias Ringwald }
609*c9300dcaSMatthias Ringwald 
610*c9300dcaSMatthias Ringwald static void l2cap_ertm_start_monitor_timer(l2cap_channel_t * channel){
611*c9300dcaSMatthias Ringwald     btstack_run_loop_remove_timer(&channel->monitor_timer);
612*c9300dcaSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->monitor_timer, &l2cap_ertm_monitor_timeout_callback);
613*c9300dcaSMatthias Ringwald     btstack_run_loop_set_timer_context(&channel->monitor_timer, channel);
614*c9300dcaSMatthias Ringwald     btstack_run_loop_set_timer(&channel->monitor_timer, channel->local_monitor_timeout_ms);
615*c9300dcaSMatthias Ringwald     btstack_run_loop_add_timer(&channel->monitor_timer);
616*c9300dcaSMatthias Ringwald }
617*c9300dcaSMatthias Ringwald 
61820fa474dSMatthias Ringwald static void l2cap_ertm_monitor_timeout_callback(btstack_timer_source_t * ts){
61920fa474dSMatthias Ringwald     log_info("l2cap_ertm_monitor_timeout_callback");
620db55d2e9SMatthias Ringwald     l2cap_channel_t * l2cap_channel = (l2cap_channel_t *) btstack_run_loop_get_timer_context(ts);
621db55d2e9SMatthias Ringwald 
622db55d2e9SMatthias Ringwald     // TODO: we assume that it's the oldest packet
623db55d2e9SMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state;
624db55d2e9SMatthias Ringwald     tx_state = &l2cap_channel->tx_packets_state[l2cap_channel->tx_read_index];
625db55d2e9SMatthias Ringwald 
626db55d2e9SMatthias Ringwald     // check retry count
627db55d2e9SMatthias Ringwald     if (tx_state->retry_count < l2cap_channel->remote_max_transmit){
628db55d2e9SMatthias Ringwald         // increment retry count
629db55d2e9SMatthias Ringwald         tx_state->retry_count++;
630db55d2e9SMatthias Ringwald 
631*c9300dcaSMatthias Ringwald         l2cap_ertm_start_monitor_timer(l2cap_channel);
632db55d2e9SMatthias Ringwald 
633db55d2e9SMatthias Ringwald         // send RR/P=1
634db55d2e9SMatthias Ringwald         l2cap_channel->send_supervisor_frame_receiver_ready_poll = 1;
635db55d2e9SMatthias Ringwald     } else {
636db55d2e9SMatthias Ringwald         log_info("Monitor timer expired & retry count >= max transmit -> disconnect");
637db55d2e9SMatthias Ringwald         l2cap_channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
638db55d2e9SMatthias Ringwald     }
639db55d2e9SMatthias Ringwald     l2cap_run();
640db55d2e9SMatthias Ringwald }
641db55d2e9SMatthias Ringwald static void l2cap_ertm_retransmission_timeout_callback(btstack_timer_source_t * ts){
642db55d2e9SMatthias Ringwald     log_info("l2cap_ertm_retransmission_timeout_callback");
643db55d2e9SMatthias Ringwald     l2cap_channel_t * l2cap_channel = (l2cap_channel_t *) btstack_run_loop_get_timer_context(ts);
644db55d2e9SMatthias Ringwald 
645db55d2e9SMatthias Ringwald     // TODO: we assume that it's the oldest packet
646db55d2e9SMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state;
647db55d2e9SMatthias Ringwald     tx_state = &l2cap_channel->tx_packets_state[l2cap_channel->tx_read_index];
648db55d2e9SMatthias Ringwald 
649db55d2e9SMatthias Ringwald     // set retry count = 1
650db55d2e9SMatthias Ringwald     tx_state->retry_count = 1;
651db55d2e9SMatthias Ringwald 
652db55d2e9SMatthias Ringwald     // start monitor timer
653*c9300dcaSMatthias Ringwald     l2cap_ertm_start_monitor_timer(l2cap_channel);
654db55d2e9SMatthias Ringwald 
655db55d2e9SMatthias Ringwald     // send RR/P=1
656db55d2e9SMatthias Ringwald     l2cap_channel->send_supervisor_frame_receiver_ready_poll = 1;
65720fa474dSMatthias Ringwald     l2cap_run();
65820fa474dSMatthias Ringwald }
6597b7901d8SMatthias Ringwald static int l2cap_ertm_send_information_frame(l2cap_channel_t * channel, int index, int final){
660f0fb4cd7SMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state = &channel->tx_packets_state[index];
661f0fb4cd7SMatthias Ringwald     hci_reserve_packet_buffer();
662f0fb4cd7SMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
66382bb0e22SMatthias Ringwald     uint16_t control = l2cap_encanced_control_field_for_information_frame(tx_state->tx_seq, final, channel->req_seq, tx_state->sar);
664f0fb4cd7SMatthias Ringwald     log_info("I-Frame: control 0x%04x", control);
665f0fb4cd7SMatthias Ringwald     little_endian_store_16(acl_buffer, 8, control);
666f0fb4cd7SMatthias Ringwald     memcpy(&acl_buffer[8+2], &channel->tx_packets_data[index * channel->local_mtu], tx_state->len);
667f0fb4cd7SMatthias Ringwald     // send
668f0fb4cd7SMatthias Ringwald     return l2cap_send_prepared(channel->local_cid, 2 + tx_state->len);
669f0fb4cd7SMatthias Ringwald }
67082bb0e22SMatthias Ringwald 
671*c9300dcaSMatthias Ringwald static void l2cap_ertm_start_retransmission_timer(l2cap_channel_t * channel){
672*c9300dcaSMatthias Ringwald     btstack_run_loop_remove_timer(&channel->retransmission_timer);
673*c9300dcaSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->retransmission_timer, &l2cap_ertm_retransmission_timeout_callback);
674*c9300dcaSMatthias Ringwald     btstack_run_loop_set_timer_context(&channel->retransmission_timer, channel);
675*c9300dcaSMatthias Ringwald     btstack_run_loop_set_timer(&channel->retransmission_timer, channel->local_retransmission_timeout_ms);
676*c9300dcaSMatthias Ringwald     btstack_run_loop_add_timer(&channel->retransmission_timer);
677*c9300dcaSMatthias Ringwald }
678*c9300dcaSMatthias Ringwald 
6797bebc11cSMatthias Ringwald static void l2cap_ertm_store_fragment(l2cap_channel_t * channel, l2cap_segmentation_and_reassembly_t sar, uint16_t sdu_length, uint8_t * data, uint16_t len){
6807bebc11cSMatthias Ringwald     // get next index for storing packets
681f0fb4cd7SMatthias Ringwald     int index = channel->tx_write_index;
68282bb0e22SMatthias Ringwald 
683f0fb4cd7SMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state = &channel->tx_packets_state[index];
684f0fb4cd7SMatthias Ringwald     tx_state->tx_seq = channel->next_tx_seq;
685f0fb4cd7SMatthias Ringwald     tx_state->len = len;
6867bebc11cSMatthias Ringwald     tx_state->sar = sar;
687db55d2e9SMatthias Ringwald     tx_state->retry_count = 0;
68882bb0e22SMatthias Ringwald 
68982bb0e22SMatthias Ringwald     uint8_t * tx_packet = &channel->tx_packets_data[index * channel->local_mtu];
6907bebc11cSMatthias Ringwald     int pos = 0;
6917bebc11cSMatthias Ringwald     if (sar == L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU){
6927bebc11cSMatthias Ringwald         little_endian_store_16(tx_packet, 0, sdu_length);
6937bebc11cSMatthias Ringwald         pos += 2;
6947bebc11cSMatthias Ringwald     }
6957bebc11cSMatthias Ringwald     memcpy(&tx_packet[pos], data, len);
69682bb0e22SMatthias Ringwald 
697f0fb4cd7SMatthias Ringwald     // update
698f0fb4cd7SMatthias Ringwald     channel->next_tx_seq = l2cap_next_ertm_seq_nr(channel->next_tx_seq);
699f0fb4cd7SMatthias Ringwald     l2cap_ertm_next_tx_write_index(channel);
70082bb0e22SMatthias Ringwald 
701*c9300dcaSMatthias Ringwald     l2cap_ertm_start_retransmission_timer(channel);
7027bebc11cSMatthias Ringwald }
7037bebc11cSMatthias Ringwald 
7047bebc11cSMatthias Ringwald static int l2cap_ertm_send(l2cap_channel_t * channel, uint8_t * data, uint16_t len){
7057bebc11cSMatthias Ringwald     if (len > channel->remote_mtu){
7067bebc11cSMatthias Ringwald         log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", channel->local_cid);
7077bebc11cSMatthias Ringwald         return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU;
7087bebc11cSMatthias Ringwald     }
7097bebc11cSMatthias Ringwald 
7107bebc11cSMatthias Ringwald     // check if it needs to get fragmented
7117bebc11cSMatthias Ringwald     if (len > channel->remote_mps){
7127bebc11cSMatthias Ringwald         // fragmentation needed.
7137bebc11cSMatthias Ringwald         l2cap_segmentation_and_reassembly_t sar =  L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU;
7147bebc11cSMatthias Ringwald         int chunk_len;
7157bebc11cSMatthias Ringwald         while (len){
7167bebc11cSMatthias Ringwald             switch (sar){
7177bebc11cSMatthias Ringwald                 case L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU:
7187bebc11cSMatthias Ringwald                     chunk_len = channel->remote_mps - 2;    // sdu_length
7197bebc11cSMatthias Ringwald                     l2cap_ertm_store_fragment(channel, sar, len, data, chunk_len);
7207bebc11cSMatthias Ringwald                     len -= chunk_len;
7217bebc11cSMatthias Ringwald                     sar = L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU;
7227bebc11cSMatthias Ringwald                     break;
7237bebc11cSMatthias Ringwald                 case L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU:
7247bebc11cSMatthias Ringwald                     chunk_len = channel->remote_mps;
7257bebc11cSMatthias Ringwald                     if (chunk_len >= len){
7267bebc11cSMatthias Ringwald                         sar = L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU;
7277bebc11cSMatthias Ringwald                         chunk_len = len;
7287bebc11cSMatthias Ringwald                     }
7297bebc11cSMatthias Ringwald                     l2cap_ertm_store_fragment(channel, sar, len, data, chunk_len);
7307bebc11cSMatthias Ringwald                     len -= chunk_len;
7317bebc11cSMatthias Ringwald                     break;
7327bebc11cSMatthias Ringwald                 default:
7337bebc11cSMatthias Ringwald                     break;
7347bebc11cSMatthias Ringwald             }
7357bebc11cSMatthias Ringwald         }
7367bebc11cSMatthias Ringwald 
7377bebc11cSMatthias Ringwald     } else {
7387bebc11cSMatthias Ringwald         l2cap_ertm_store_fragment(channel, L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU, 0, data, len);
7397bebc11cSMatthias Ringwald     }
74082bb0e22SMatthias Ringwald 
741675e6881SMatthias Ringwald     // try to send
742675e6881SMatthias Ringwald     l2cap_run();
743f0fb4cd7SMatthias Ringwald     return 0;
744f0fb4cd7SMatthias Ringwald }
74585ddcd84SMatthias Ringwald #endif
74658de5610Smatthias.ringwald 
747f511cefaSMatthias Ringwald // assumption - only on Classic connections
748ce8f182eSMatthias Ringwald int l2cap_send(uint16_t local_cid, uint8_t *data, uint16_t len){
749a35252c8S[email protected]     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
750a35252c8S[email protected]     if (!channel) {
751ce8f182eSMatthias Ringwald         log_error("l2cap_send no channel for cid 0x%02x", local_cid);
752a35252c8S[email protected]         return -1;   // TODO: define error
753a35252c8S[email protected]     }
754a35252c8S[email protected] 
755f0fb4cd7SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
756f0fb4cd7SMatthias Ringwald     // send in ERTM
757f0fb4cd7SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
758f0fb4cd7SMatthias Ringwald         return l2cap_ertm_send(channel, data, len);
759f0fb4cd7SMatthias Ringwald     }
760f0fb4cd7SMatthias Ringwald #endif
761f0fb4cd7SMatthias Ringwald 
762f0efaa57S[email protected]     if (len > channel->remote_mtu){
763ce8f182eSMatthias Ringwald         log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", local_cid);
764f0efaa57S[email protected]         return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU;
765f0efaa57S[email protected]     }
766f0efaa57S[email protected] 
767fc64f94aSMatthias Ringwald     if (!hci_can_send_acl_packet_now(channel->con_handle)){
768ce8f182eSMatthias Ringwald         log_info("l2cap_send cid 0x%02x, cannot send", local_cid);
769b1d43497Smatthias.ringwald         return BTSTACK_ACL_BUFFERS_FULL;
770b1d43497Smatthias.ringwald     }
771b1d43497Smatthias.ringwald 
7722a373862S[email protected]     hci_reserve_packet_buffer();
773facf93fdS[email protected]     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
774f0fb4cd7SMatthias Ringwald     memcpy(&acl_buffer[8], data, len);
775f0fb4cd7SMatthias Ringwald     return l2cap_send_prepared(local_cid, len);
776b1d43497Smatthias.ringwald }
777b1d43497Smatthias.ringwald 
778fc64f94aSMatthias Ringwald int l2cap_send_echo_request(hci_con_handle_t con_handle, uint8_t *data, uint16_t len){
779fc64f94aSMatthias Ringwald     return l2cap_send_signaling_packet(con_handle, ECHO_REQUEST, 0x77, len, data);
7800e37e417S[email protected] }
7810e37e417S[email protected] 
78228ca2b46S[email protected] static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
78328ca2b46S[email protected]     channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var | flag);
78428ca2b46S[email protected] }
78528ca2b46S[email protected] 
78628ca2b46S[email protected] static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
78728ca2b46S[email protected]     channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag);
78828ca2b46S[email protected] }
78909e9d05bSMatthias Ringwald #endif
79028ca2b46S[email protected] 
79128ca2b46S[email protected] 
79209e9d05bSMatthias Ringwald #ifdef ENABLE_BLE
79309e9d05bSMatthias Ringwald static int l2cap_send_le_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
79409e9d05bSMatthias Ringwald 
79509e9d05bSMatthias Ringwald     if (!hci_can_send_acl_packet_now(handle)){
79609e9d05bSMatthias Ringwald         log_info("l2cap_send_le_signaling_packet, cannot send");
79709e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
79809e9d05bSMatthias Ringwald     }
79909e9d05bSMatthias Ringwald 
80009e9d05bSMatthias Ringwald     // log_info("l2cap_send_le_signaling_packet type %u", cmd);
80109e9d05bSMatthias Ringwald     hci_reserve_packet_buffer();
80209e9d05bSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
80309e9d05bSMatthias Ringwald     va_list argptr;
80409e9d05bSMatthias Ringwald     va_start(argptr, identifier);
80509e9d05bSMatthias Ringwald     uint16_t len = l2cap_create_signaling_le(acl_buffer, handle, cmd, identifier, argptr);
80609e9d05bSMatthias Ringwald     va_end(argptr);
80709e9d05bSMatthias Ringwald     // log_info("l2cap_send_le_signaling_packet con %u!", handle);
80809e9d05bSMatthias Ringwald     return hci_send_acl_packet_buffer(len);
80909e9d05bSMatthias Ringwald }
81009e9d05bSMatthias Ringwald #endif
81109e9d05bSMatthias Ringwald 
81209e9d05bSMatthias Ringwald uint16_t l2cap_max_mtu(void){
81309e9d05bSMatthias Ringwald     return HCI_ACL_PAYLOAD_SIZE - L2CAP_HEADER_SIZE;
81409e9d05bSMatthias Ringwald }
81509e9d05bSMatthias Ringwald 
81609e9d05bSMatthias Ringwald uint16_t l2cap_max_le_mtu(void){
81709e9d05bSMatthias Ringwald     return l2cap_max_mtu();
81809e9d05bSMatthias Ringwald }
819b1d43497Smatthias.ringwald 
8206dca2a0cSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
821450ad7ecSMatthias Ringwald static uint16_t l2cap_setup_options_ertm(l2cap_channel_t * channel, uint8_t * config_options){
8226dca2a0cSMatthias Ringwald     config_options[0] = 0x04;   // RETRANSMISSION AND FLOW CONTROL OPTION
8236dca2a0cSMatthias Ringwald     config_options[1] = 9;      // length
8246dca2a0cSMatthias Ringwald     config_options[2] = (uint8_t) channel->mode;
8257b181629SMatthias Ringwald     config_options[3] = channel->num_rx_buffers;    // == TxWindows size
826bbc0a9e7SMatthias Ringwald     config_options[4] = channel->local_max_transmit;
827bbc0a9e7SMatthias Ringwald     little_endian_store_16( config_options, 5, channel->local_retransmission_timeout_ms);
828bbc0a9e7SMatthias Ringwald     little_endian_store_16( config_options, 7, channel->local_monitor_timeout_ms);
829843bae5dSMatthias Ringwald     little_endian_store_16( config_options, 9, channel->local_mps);
830450ad7ecSMatthias Ringwald     return 11;
8316dca2a0cSMatthias Ringwald }
83238f62777SMatthias Ringwald static int l2cap_ertm_send_supervisor_frame(l2cap_channel_t * channel, uint16_t control){
83338f62777SMatthias Ringwald     hci_reserve_packet_buffer();
83438f62777SMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
83538f62777SMatthias Ringwald     log_info("S-Frame: control 0x%04x", control);
83638f62777SMatthias Ringwald     little_endian_store_16(acl_buffer, 8, control);
83738f62777SMatthias Ringwald     return l2cap_send_prepared(channel->local_cid, 2);
83838f62777SMatthias Ringwald }
839212b6be2SMatthias Ringwald static int l2cap_ertm_num_unacknowledged_tx_packets(l2cap_channel_t * channel){
840212b6be2SMatthias Ringwald     int unacknowledged_packets = channel->tx_send_index - channel->tx_read_index;
841212b6be2SMatthias Ringwald     if (unacknowledged_packets < 0){
842212b6be2SMatthias Ringwald         unacknowledged_packets += channel->num_tx_buffers;
843212b6be2SMatthias Ringwald     }
844212b6be2SMatthias Ringwald     return unacknowledged_packets;
845212b6be2SMatthias Ringwald }
846450ad7ecSMatthias Ringwald #endif
847450ad7ecSMatthias Ringwald 
848d2afdd38SMatthias Ringwald #ifdef ENABLE_CLASSIC
849d2afdd38SMatthias Ringwald 
850d2afdd38SMatthias Ringwald static uint16_t l2cap_setup_options_mtu(l2cap_channel_t * channel, uint8_t * config_options){
851d2afdd38SMatthias Ringwald     config_options[0] = 1; // MTU
852d2afdd38SMatthias Ringwald     config_options[1] = 2; // len param
853d2afdd38SMatthias Ringwald     little_endian_store_16( (uint8_t*)&config_options, 2, channel->local_mtu);
854d2afdd38SMatthias Ringwald     return 4;
855d2afdd38SMatthias Ringwald }
856d2afdd38SMatthias Ringwald 
857450ad7ecSMatthias Ringwald static uint16_t l2cap_setup_options(l2cap_channel_t * channel, uint8_t * config_options){
858450ad7ecSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
859450ad7ecSMatthias Ringwald     // use ERTM options if supported
860450ad7ecSMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
861450ad7ecSMatthias Ringwald     if ((connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_DONE) && (connection->l2cap_state.extended_feature_mask & 0x08)){
862450ad7ecSMatthias Ringwald         return l2cap_setup_options_ertm(channel, config_options);
863450ad7ecSMatthias Ringwald 
864450ad7ecSMatthias Ringwald     }
865450ad7ecSMatthias Ringwald #endif
866450ad7ecSMatthias Ringwald     return l2cap_setup_options_mtu(channel, config_options);
8676dca2a0cSMatthias Ringwald }
8686dca2a0cSMatthias Ringwald 
8691b9cb13dSMatthias Ringwald static uint32_t l2cap_extended_features_mask(void){
8701b9cb13dSMatthias Ringwald     // extended features request supported, features: fixed channels, unicast connectionless data reception
8711b9cb13dSMatthias Ringwald     uint32_t features = 0x280;
8721b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
8731b9cb13dSMatthias Ringwald     features |= 0x0008;
8741b9cb13dSMatthias Ringwald #endif
8751b9cb13dSMatthias Ringwald     return features;
8761b9cb13dSMatthias Ringwald }
877d2afdd38SMatthias Ringwald #endif
8781b9cb13dSMatthias Ringwald 
8798158c421Smatthias.ringwald // MARK: L2CAP_RUN
8802cd0be45Smatthias.ringwald // process outstanding signaling tasks
8817f02f414SMatthias Ringwald static void l2cap_run(void){
8822b83fb7dSmatthias.ringwald 
88322c29ab4SMatthias Ringwald     // log_info("l2cap_run: entered");
88422c29ab4SMatthias Ringwald 
8852b83fb7dSmatthias.ringwald     // check pending signaling responses
8862b83fb7dSmatthias.ringwald     while (signaling_responses_pending){
8872b83fb7dSmatthias.ringwald 
8882b83fb7dSmatthias.ringwald         hci_con_handle_t handle = signaling_responses[0].handle;
889a35252c8S[email protected] 
890a35252c8S[email protected]         if (!hci_can_send_acl_packet_now(handle)) break;
891a35252c8S[email protected] 
8922b83fb7dSmatthias.ringwald         uint8_t  sig_id        = signaling_responses[0].sig_id;
893e74c5f58SMatthias Ringwald         uint8_t  response_code = signaling_responses[0].code;
8942b360848Smatthias.ringwald         uint16_t infoType      = signaling_responses[0].data;  // INFORMATION_REQUEST
89563a7246aSmatthias.ringwald         uint16_t result        = signaling_responses[0].data;  // CONNECTION_REQUEST, COMMAND_REJECT
896b3264428SMatthias Ringwald #ifdef ENABLE_CLASSIC
897b3264428SMatthias Ringwald         uint16_t source_cid    = signaling_responses[0].cid;   // CONNECTION_REQUEST
898b3264428SMatthias Ringwald #endif
899f3963406SMatthias Ringwald         UNUSED(infoType);
90009e9d05bSMatthias Ringwald 
901f53da564S[email protected]         // remove first item before sending (to avoid sending response mutliple times)
902f53da564S[email protected]         signaling_responses_pending--;
903f53da564S[email protected]         int i;
904f53da564S[email protected]         for (i=0; i < signaling_responses_pending; i++){
905f53da564S[email protected]             memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t));
906f53da564S[email protected]         }
907f53da564S[email protected] 
908f53da564S[email protected]         switch (response_code){
90909e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
9102b360848Smatthias.ringwald             case CONNECTION_REQUEST:
911e74c5f58SMatthias Ringwald                 l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, source_cid, 0, result, 0);
9122bd8b7e7S[email protected]                 // also disconnect if result is 0x0003 - security blocked
9134d816277S[email protected]                 if (result == 0x0003){
9142bd8b7e7S[email protected]                     hci_disconnect_security_block(handle);
9154d816277S[email protected]                 }
9162b360848Smatthias.ringwald                 break;
9172b83fb7dSmatthias.ringwald             case ECHO_REQUEST:
9182b83fb7dSmatthias.ringwald                 l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL);
9192b83fb7dSmatthias.ringwald                 break;
9202b83fb7dSmatthias.ringwald             case INFORMATION_REQUEST:
9213b0484b3S[email protected]                 switch (infoType){
9223b0484b3S[email protected]                     case 1: { // Connectionless MTU
9233b0484b3S[email protected]                             uint16_t connectionless_mtu = hci_max_acl_data_packet_length();
9243b0484b3S[email protected]                             l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, sizeof(connectionless_mtu), &connectionless_mtu);
9253b0484b3S[email protected]                         }
926202c8a4cSMatthias Ringwald                         break;
9273b0484b3S[email protected]                     case 2: {  // Extended Features Supported
9281b9cb13dSMatthias Ringwald                             uint32_t features = l2cap_extended_features_mask();
9293b0484b3S[email protected]                             l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, sizeof(features), &features);
9303b0484b3S[email protected]                         }
931202c8a4cSMatthias Ringwald                         break;
9323b0484b3S[email protected]                     case 3: { // Fixed Channels Supported
9333b0484b3S[email protected]                             uint8_t map[8];
9343b0484b3S[email protected]                             memset(map, 0, 8);
935288636a2SMatthias Ringwald                             map[0] = 0x06;  // L2CAP Signaling Channel (0x02) + Connectionless reception (0x04)
9363b0484b3S[email protected]                             l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, sizeof(map), &map);
9373b0484b3S[email protected]                         }
938202c8a4cSMatthias Ringwald                         break;
9393b0484b3S[email protected]                     default:
9402b83fb7dSmatthias.ringwald                         // all other types are not supported
9412b83fb7dSmatthias.ringwald                         l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL);
9423b0484b3S[email protected]                         break;
9432b83fb7dSmatthias.ringwald                 }
9442b83fb7dSmatthias.ringwald                 break;
94563a7246aSmatthias.ringwald             case COMMAND_REJECT:
9465ca8d57bS[email protected]                 l2cap_send_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL);
94763f0ac45SMatthias Ringwald                 break;
94809e9d05bSMatthias Ringwald #endif
949a9a4c409SMatthias Ringwald #ifdef ENABLE_BLE
95063f0ac45SMatthias Ringwald             case LE_CREDIT_BASED_CONNECTION_REQUEST:
95163f0ac45SMatthias Ringwald                 l2cap_send_le_signaling_packet(handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, sig_id, 0, 0, 0, 0, result);
95263f0ac45SMatthias Ringwald                 break;
95370efece1S[email protected]             case COMMAND_REJECT_LE:
95470efece1S[email protected]                 l2cap_send_le_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL);
95563a7246aSmatthias.ringwald                 break;
95670efece1S[email protected] #endif
9572b83fb7dSmatthias.ringwald             default:
9582b83fb7dSmatthias.ringwald                 // should not happen
9592b83fb7dSmatthias.ringwald                 break;
9602b83fb7dSmatthias.ringwald         }
9612b83fb7dSmatthias.ringwald     }
9622b83fb7dSmatthias.ringwald 
963665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
964f3963406SMatthias Ringwald     UNUSED(it);
96509e9d05bSMatthias Ringwald 
9661b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
9671b9cb13dSMatthias Ringwald     // send l2cap information request if neccessary
9681b9cb13dSMatthias Ringwald     hci_connections_get_iterator(&it);
9691b9cb13dSMatthias Ringwald     while(btstack_linked_list_iterator_has_next(&it)){
9701b9cb13dSMatthias Ringwald         hci_connection_t * connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it);
9711b9cb13dSMatthias Ringwald         if (connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_W2_SEND_EXTENDED_FEATURE_REQUEST){
9721b9cb13dSMatthias Ringwald             connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_W4_EXTENDED_FEATURE_RESPONSE;
9731b9cb13dSMatthias Ringwald             // send information request for extended features
9741b9cb13dSMatthias Ringwald             uint8_t sig_id = l2cap_next_sig_id();
9751b9cb13dSMatthias Ringwald             uint8_t info_type = 2;
9761b9cb13dSMatthias Ringwald             l2cap_send_signaling_packet(connection->con_handle, INFORMATION_REQUEST, sig_id, info_type);
9771b9cb13dSMatthias Ringwald             return;
9781b9cb13dSMatthias Ringwald         }
9791b9cb13dSMatthias Ringwald     }
9801b9cb13dSMatthias Ringwald #endif
9811b9cb13dSMatthias Ringwald 
98209e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
98343ec931dSMatthias Ringwald     uint8_t  config_options[10];
984665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
985665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
986baf94f06S[email protected] 
987665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
98822c29ab4SMatthias Ringwald         // log_info("l2cap_run: channel %p, state %u, var 0x%02x", channel, channel->state, channel->state_var);
9892cd0be45Smatthias.ringwald         switch (channel->state){
9902cd0be45Smatthias.ringwald 
991df3354fcS[email protected]             case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE:
992ad671560S[email protected]             case L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT:
993fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
994a00031e2S[email protected]                 if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND) {
995ad671560S[email protected]                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND);
996fc64f94aSMatthias Ringwald                     l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 1, 0);
997ad671560S[email protected]                 }
998ad671560S[email protected]                 break;
999ad671560S[email protected] 
100002b22dc4Smatthias.ringwald             case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
1001baf94f06S[email protected]                 if (!hci_can_send_command_packet_now()) break;
100264472d52Smatthias.ringwald                 // send connection request - set state first
100364472d52Smatthias.ringwald                 channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE;
100402b22dc4Smatthias.ringwald                 // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
10058f8108aaSmatthias.ringwald                 hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1);
100602b22dc4Smatthias.ringwald                 break;
100702b22dc4Smatthias.ringwald 
1008e7ff783cSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE:
1009fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
101022c29ab4SMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
1011fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, channel->reason, 0);
1012e7ff783cSmatthias.ringwald                 // discard channel - l2cap_finialize_channel_close without sending l2cap close event
10139dcb2fb2S[email protected]                 l2cap_stop_rtx(channel);
1014665d90f2SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1015d3a9df87Smatthias.ringwald                 btstack_memory_l2cap_channel_free(channel);
1016e7ff783cSmatthias.ringwald                 break;
1017e7ff783cSmatthias.ringwald 
1018552d92a1Smatthias.ringwald             case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT:
1019fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1020fa8473a4Smatthias.ringwald                 channel->state = L2CAP_STATE_CONFIG;
102128ca2b46S[email protected]                 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
1022fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0);
1023552d92a1Smatthias.ringwald                 break;
1024552d92a1Smatthias.ringwald 
10256fdcc387Smatthias.ringwald             case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST:
1026fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
10276fdcc387Smatthias.ringwald                 // success, start l2cap handshake
1028b1988dceSmatthias.ringwald                 channel->local_sig_id = l2cap_next_sig_id();
10296fdcc387Smatthias.ringwald                 channel->state = L2CAP_STATE_WAIT_CONNECT_RSP;
1030fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet( channel->con_handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid);
10315932bd7cS[email protected]                 l2cap_start_rtx(channel);
10326fdcc387Smatthias.ringwald                 break;
10336fdcc387Smatthias.ringwald 
1034fa8473a4Smatthias.ringwald             case L2CAP_STATE_CONFIG:
1035fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
103673cf2b3dSmatthias.ringwald                 if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
103763a7246aSmatthias.ringwald                     uint16_t flags = 0;
103828ca2b46S[email protected]                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
103963a7246aSmatthias.ringwald                     if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT) {
104063a7246aSmatthias.ringwald                         flags = 1;
104163a7246aSmatthias.ringwald                     } else {
104228ca2b46S[email protected]                         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
104363a7246aSmatthias.ringwald                     }
104463a7246aSmatthias.ringwald                     if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID){
1045ac8f1300SMatthias Ringwald                         channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
1046fc64f94aSMatthias 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);
1047ac8f1300SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
1048ac8f1300SMatthias Ringwald                     } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED){
1049ac8f1300SMatthias Ringwald                         channelStateVarClearFlag(channel,L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED);
1050ac8f1300SMatthias Ringwald                         channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
10516dca2a0cSMatthias Ringwald                         uint16_t options_size = l2cap_setup_options(channel, config_options);
1052ac8f1300SMatthias 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);
1053ac8f1300SMatthias Ringwald #endif
1054ac8f1300SMatthias Ringwald                     } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU){
105563a7246aSmatthias.ringwald                         channelStateVarClearFlag(channel,L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
1056ac8f1300SMatthias Ringwald                         uint16_t options_size = l2cap_setup_options(channel, config_options);
1057ac8f1300SMatthias 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);
105863a7246aSmatthias.ringwald                     } else {
1059ac8f1300SMatthias Ringwald                         l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_SUCCESS, 0, NULL);
106063a7246aSmatthias.ringwald                     }
106163a7246aSmatthias.ringwald                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT);
1062fa8473a4Smatthias.ringwald                 }
106373cf2b3dSmatthias.ringwald                 else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){
106428ca2b46S[email protected]                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
106528ca2b46S[email protected]                     channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ);
1066b1988dceSmatthias.ringwald                     channel->local_sig_id = l2cap_next_sig_id();
10676dca2a0cSMatthias Ringwald                     uint16_t options_size = l2cap_setup_options(channel, config_options);
10686dca2a0cSMatthias Ringwald                     l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, options_size, &config_options);
10695932bd7cS[email protected]                     l2cap_start_rtx(channel);
1070fa8473a4Smatthias.ringwald                 }
1071fa8473a4Smatthias.ringwald                 if (l2cap_channel_ready_for_open(channel)){
1072552d92a1Smatthias.ringwald                     channel->state = L2CAP_STATE_OPEN;
1073552d92a1Smatthias.ringwald                     l2cap_emit_channel_opened(channel, 0);  // success
1074fa8473a4Smatthias.ringwald                 }
1075552d92a1Smatthias.ringwald                 break;
1076552d92a1Smatthias.ringwald 
1077e7ff783cSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
1078fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
107922c29ab4SMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
1080fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet( channel->con_handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);
10815932bd7cS[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 :)
1082756102d3Smatthias.ringwald                 l2cap_finialize_channel_close(channel);  // -- remove from list
1083e7ff783cSmatthias.ringwald                 break;
1084e7ff783cSmatthias.ringwald 
1085e7ff783cSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
1086fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1087b1988dceSmatthias.ringwald                 channel->local_sig_id = l2cap_next_sig_id();
10882cd0be45Smatthias.ringwald                 channel->state = L2CAP_STATE_WAIT_DISCONNECT;
1089fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet( channel->con_handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);
10902cd0be45Smatthias.ringwald                 break;
10912cd0be45Smatthias.ringwald             default:
10922cd0be45Smatthias.ringwald                 break;
10932cd0be45Smatthias.ringwald         }
109438f62777SMatthias Ringwald 
109538f62777SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
109638f62777SMatthias Ringwald         // send s-frame to acknowledge received packets
109738f62777SMatthias Ringwald         if (!hci_can_send_acl_packet_now(channel->con_handle)) continue;
1098675e6881SMatthias Ringwald 
1099675e6881SMatthias Ringwald         if (channel->tx_send_index != channel->tx_write_index){
1100212b6be2SMatthias Ringwald             int unacknowledged_packets = l2cap_ertm_num_unacknowledged_tx_packets(channel);
1101212b6be2SMatthias Ringwald             // check remote tx window
1102212b6be2SMatthias Ringwald             log_info("unacknowledged_packets %u, remote tx window size %u", unacknowledged_packets, channel->remote_tx_window_size);
1103212b6be2SMatthias Ringwald             if (unacknowledged_packets < channel->remote_tx_window_size){
1104675e6881SMatthias Ringwald                 int index = channel->tx_send_index;
1105675e6881SMatthias Ringwald                 channel->tx_send_index++;
1106675e6881SMatthias Ringwald                 if (channel->tx_send_index >= channel->num_tx_buffers){
1107675e6881SMatthias Ringwald                     channel->tx_send_index = 0;
1108675e6881SMatthias Ringwald                 }
11097b7901d8SMatthias Ringwald                 l2cap_ertm_send_information_frame(channel, index, 0);   // final = 0
1110675e6881SMatthias Ringwald                 continue;
1111675e6881SMatthias Ringwald             }
1112212b6be2SMatthias Ringwald         }
1113675e6881SMatthias Ringwald 
1114d84e866fSMatthias Ringwald         if (channel->send_supervisor_frame_receiver_ready){
111578cd8a22SMatthias Ringwald             channel->send_supervisor_frame_receiver_ready = 0;
1116d2afdd38SMatthias Ringwald             log_info("Send S-Frame: RR %u, final %u", channel->req_seq, channel->set_final_bit_after_packet_with_poll_bit_set);
1117d2afdd38SMatthias Ringwald             uint16_t control = l2cap_encanced_control_field_for_supevisor_frame( L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY, 0,  channel->set_final_bit_after_packet_with_poll_bit_set, channel->req_seq);
1118d2afdd38SMatthias Ringwald             channel->set_final_bit_after_packet_with_poll_bit_set = 0;
111938f62777SMatthias Ringwald             l2cap_ertm_send_supervisor_frame(channel, control);
1120675e6881SMatthias Ringwald             continue;
112138f62777SMatthias Ringwald         }
112262041d70SMatthias Ringwald         if (channel->send_supervisor_frame_receiver_ready_poll){
112378cd8a22SMatthias Ringwald             channel->send_supervisor_frame_receiver_ready_poll = 0;
112462041d70SMatthias Ringwald             log_info("Send S-Frame: RR %u with poll=1 ", channel->req_seq);
112562041d70SMatthias Ringwald             uint16_t control = l2cap_encanced_control_field_for_supevisor_frame( L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY, 1, 0, channel->req_seq);
112662041d70SMatthias Ringwald             l2cap_ertm_send_supervisor_frame(channel, control);
112762041d70SMatthias Ringwald             continue;
112862041d70SMatthias Ringwald         }
11298f1c9639SMatthias Ringwald         if (channel->send_supervisor_frame_receiver_not_ready){
113078cd8a22SMatthias Ringwald             channel->send_supervisor_frame_receiver_not_ready = 0;
11318f1c9639SMatthias Ringwald             log_info("Send S-Frame: RNR %u", channel->req_seq);
11328f1c9639SMatthias Ringwald             uint16_t control = l2cap_encanced_control_field_for_supevisor_frame( L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY, 0, 0, channel->req_seq);
11338f1c9639SMatthias Ringwald             l2cap_ertm_send_supervisor_frame(channel, control);
11348f1c9639SMatthias Ringwald             continue;
11358f1c9639SMatthias Ringwald         }
1136c7309e8dSMatthias Ringwald         if (channel->send_supervisor_frame_reject){
1137c7309e8dSMatthias Ringwald             channel->send_supervisor_frame_reject = 0;
1138c7309e8dSMatthias Ringwald             log_info("Send S-Frame: REJ %u", channel->req_seq);
1139c7309e8dSMatthias Ringwald             uint16_t control = l2cap_encanced_control_field_for_supevisor_frame( L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT, 0, 0, channel->req_seq);
1140c7309e8dSMatthias Ringwald             l2cap_ertm_send_supervisor_frame(channel, control);
1141c7309e8dSMatthias Ringwald             continue;
1142c7309e8dSMatthias Ringwald         }
1143df2191a7SMatthias Ringwald         if (channel->send_supervisor_frame_selective_reject){
1144df2191a7SMatthias Ringwald             channel->send_supervisor_frame_selective_reject = 0;
1145df2191a7SMatthias Ringwald             log_info("Send S-Frame: SREJ %u", channel->expected_tx_seq);
1146f85ade6bSMatthias Ringwald             uint16_t control = l2cap_encanced_control_field_for_supevisor_frame( L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT, 0, channel->set_final_bit_after_packet_with_poll_bit_set, channel->expected_tx_seq);
1147f85ade6bSMatthias Ringwald             channel->set_final_bit_after_packet_with_poll_bit_set = 0;
1148df2191a7SMatthias Ringwald             l2cap_ertm_send_supervisor_frame(channel, control);
1149df2191a7SMatthias Ringwald             continue;
1150df2191a7SMatthias Ringwald         }
11517b7901d8SMatthias Ringwald 
11527b7901d8SMatthias Ringwald         if (channel->srej_active){
11537b7901d8SMatthias Ringwald             int i;
11547b7901d8SMatthias Ringwald             for (i=0;i<channel->num_tx_buffers;i++){
11557b7901d8SMatthias Ringwald                 l2cap_ertm_tx_packet_state_t * tx_state = &channel->tx_packets_state[i];
11567b7901d8SMatthias Ringwald                 if (tx_state->retransmission_requested) {
11577b7901d8SMatthias Ringwald                     tx_state->retransmission_requested = 0;
1158d2afdd38SMatthias Ringwald                     uint8_t final = channel->set_final_bit_after_packet_with_poll_bit_set;
1159d2afdd38SMatthias Ringwald                     channel->set_final_bit_after_packet_with_poll_bit_set = 0;
1160d2afdd38SMatthias Ringwald                     l2cap_ertm_send_information_frame(channel, i, final);
11617b7901d8SMatthias Ringwald                     break;
11627b7901d8SMatthias Ringwald                 }
11637b7901d8SMatthias Ringwald             }
11647b7901d8SMatthias Ringwald             if (i == channel->num_tx_buffers){
11657b7901d8SMatthias Ringwald                 // no retransmission request found
11667b7901d8SMatthias Ringwald                 channel->srej_active = 0;
11677b7901d8SMatthias Ringwald             } else {
11687b7901d8SMatthias Ringwald                 // packet was sent
11697b7901d8SMatthias Ringwald                 continue;
11707b7901d8SMatthias Ringwald             }
11717b7901d8SMatthias Ringwald         }
117238f62777SMatthias Ringwald #endif
117338f62777SMatthias Ringwald 
11742cd0be45Smatthias.ringwald     }
117509e9d05bSMatthias Ringwald #endif
1176da886c03S[email protected] 
1177cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
1178efedfb4cSMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
1179efedfb4cSMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
11807f107edaSMatthias Ringwald         uint8_t  * acl_buffer;
11817f107edaSMatthias Ringwald         uint8_t  * l2cap_payload;
11827f107edaSMatthias Ringwald         uint16_t pos;
11837f107edaSMatthias Ringwald         uint16_t payload_size;
1184efedfb4cSMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1185efedfb4cSMatthias Ringwald         // log_info("l2cap_run: channel %p, state %u, var 0x%02x", channel, channel->state, channel->state_var);
1186efedfb4cSMatthias Ringwald         switch (channel->state){
11875cb87675SMatthias Ringwald             case L2CAP_STATE_WILL_SEND_LE_CONNECTION_REQUEST:
11885cb87675SMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
11895cb87675SMatthias Ringwald                 channel->state = L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE;
11905cb87675SMatthias Ringwald                 // le psm, source cid, mtu, mps, initial credits
11911b8b8d05SMatthias Ringwald                 channel->local_sig_id = l2cap_next_sig_id();
119263f0ac45SMatthias Ringwald                 channel->credits_incoming =  channel->new_credits_incoming;
119363f0ac45SMatthias Ringwald                 channel->new_credits_incoming = 0;
119463f0ac45SMatthias 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);
11955cb87675SMatthias Ringwald                 break;
119623017473SMatthias Ringwald             case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_ACCEPT:
119723017473SMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
119823017473SMatthias Ringwald                 // TODO: support larger MPS
119923017473SMatthias Ringwald                 channel->state = L2CAP_STATE_OPEN;
120063f0ac45SMatthias Ringwald                 channel->credits_incoming =  channel->new_credits_incoming;
120163f0ac45SMatthias Ringwald                 channel->new_credits_incoming = 0;
120263f0ac45SMatthias 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);
120364e11ca9SMatthias Ringwald                 // notify client
120444276248SMatthias Ringwald                 l2cap_emit_le_channel_opened(channel, 0);
120523017473SMatthias Ringwald                 break;
1206e7d0c9aaSMatthias Ringwald             case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE:
1207e7d0c9aaSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1208e7d0c9aaSMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
120963f0ac45SMatthias Ringwald                 l2cap_send_le_signaling_packet(channel->con_handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, 0, 0, channel->reason);
1210e7d0c9aaSMatthias Ringwald                 // discard channel - l2cap_finialize_channel_close without sending l2cap close event
1211e7d0c9aaSMatthias Ringwald                 l2cap_stop_rtx(channel);
1212e7d0c9aaSMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1213e7d0c9aaSMatthias Ringwald                 btstack_memory_l2cap_channel_free(channel);
1214e7d0c9aaSMatthias Ringwald                 break;
12157f107edaSMatthias Ringwald             case L2CAP_STATE_OPEN:
121685aeef60SMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
121785aeef60SMatthias Ringwald 
121885aeef60SMatthias Ringwald                 // send credits
121985aeef60SMatthias Ringwald                 if (channel->new_credits_incoming){
122085aeef60SMatthias Ringwald                     log_info("l2cap: sending %u credits", channel->new_credits_incoming);
122185aeef60SMatthias Ringwald                     channel->local_sig_id = l2cap_next_sig_id();
122285aeef60SMatthias Ringwald                     uint16_t new_credits = channel->new_credits_incoming;
122385aeef60SMatthias Ringwald                     channel->new_credits_incoming = 0;
122485aeef60SMatthias Ringwald                     channel->credits_incoming += new_credits;
122585aeef60SMatthias Ringwald                     l2cap_send_le_signaling_packet(channel->con_handle, LE_FLOW_CONTROL_CREDIT, channel->local_sig_id, channel->remote_cid, new_credits);
122685aeef60SMatthias Ringwald                     break;
122785aeef60SMatthias Ringwald                 }
122885aeef60SMatthias Ringwald 
122985aeef60SMatthias Ringwald                 // send data
12307f107edaSMatthias Ringwald                 if (!channel->send_sdu_buffer) break;
12317f107edaSMatthias Ringwald                 if (!channel->credits_outgoing) break;
123285aeef60SMatthias Ringwald 
12337f107edaSMatthias Ringwald                 // send part of SDU
12347f107edaSMatthias Ringwald                 hci_reserve_packet_buffer();
12357f107edaSMatthias Ringwald                 acl_buffer = hci_get_outgoing_packet_buffer();
12367f107edaSMatthias Ringwald                 l2cap_payload = acl_buffer + 8;
12377f107edaSMatthias Ringwald                 pos = 0;
12387f107edaSMatthias Ringwald                 if (!channel->send_sdu_pos){
12397f107edaSMatthias Ringwald                     // store SDU len
12407f107edaSMatthias Ringwald                     channel->send_sdu_pos += 2;
12417f107edaSMatthias Ringwald                     little_endian_store_16(l2cap_payload, pos, channel->send_sdu_len);
12427f107edaSMatthias Ringwald                     pos += 2;
12437f107edaSMatthias Ringwald                 }
12447f107edaSMatthias Ringwald                 payload_size = btstack_min(channel->send_sdu_len + 2 - channel->send_sdu_pos, channel->remote_mps - pos);
124585aeef60SMatthias Ringwald                 log_info("len %u, pos %u => payload %u, credits %u", channel->send_sdu_len, channel->send_sdu_pos, payload_size, channel->credits_outgoing);
12467f107edaSMatthias Ringwald                 memcpy(&l2cap_payload[pos], &channel->send_sdu_buffer[channel->send_sdu_pos-2], payload_size); // -2 for virtual SDU len
12477f107edaSMatthias Ringwald                 pos += payload_size;
12487f107edaSMatthias Ringwald                 channel->send_sdu_pos += payload_size;
1249f511cefaSMatthias Ringwald                 l2cap_setup_header(acl_buffer, channel->con_handle, 0, channel->remote_cid, pos);
12507f107edaSMatthias Ringwald                 // done
12517f107edaSMatthias Ringwald 
125285aeef60SMatthias Ringwald                 channel->credits_outgoing--;
12537f107edaSMatthias Ringwald 
12547f107edaSMatthias Ringwald                 if (channel->send_sdu_pos >= channel->send_sdu_len + 2){
12557f107edaSMatthias Ringwald                     channel->send_sdu_buffer = NULL;
125644276248SMatthias Ringwald                     // send done event
125744276248SMatthias Ringwald                     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_PACKET_SENT);
125844276248SMatthias Ringwald                     // inform about can send now
125944276248SMatthias Ringwald                     l2cap_le_notify_channel_can_send(channel);
12607f107edaSMatthias Ringwald                 }
12617f107edaSMatthias Ringwald                 hci_send_acl_packet_buffer(8 + pos);
12627f107edaSMatthias Ringwald                 break;
1263828a7f7aSMatthias Ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
1264828a7f7aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1265828a7f7aSMatthias Ringwald                 channel->local_sig_id = l2cap_next_sig_id();
1266828a7f7aSMatthias Ringwald                 channel->state = L2CAP_STATE_WAIT_DISCONNECT;
1267828a7f7aSMatthias Ringwald                 l2cap_send_le_signaling_packet( channel->con_handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);
1268828a7f7aSMatthias Ringwald                 break;
1269828a7f7aSMatthias Ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
1270828a7f7aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1271828a7f7aSMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
1272828a7f7aSMatthias Ringwald                 l2cap_send_le_signaling_packet( channel->con_handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);
1273828a7f7aSMatthias Ringwald                 l2cap_le_finialize_channel_close(channel);  // -- remove from list
1274828a7f7aSMatthias Ringwald                 break;
1275efedfb4cSMatthias Ringwald             default:
1276efedfb4cSMatthias Ringwald                 break;
1277efedfb4cSMatthias Ringwald         }
1278efedfb4cSMatthias Ringwald     }
127909e9d05bSMatthias Ringwald #endif
1280efedfb4cSMatthias Ringwald 
128109e9d05bSMatthias Ringwald #ifdef ENABLE_BLE
1282da886c03S[email protected]     // send l2cap con paramter update if necessary
1283da886c03S[email protected]     hci_connections_get_iterator(&it);
1284665d90f2SMatthias Ringwald     while(btstack_linked_list_iterator_has_next(&it)){
1285665d90f2SMatthias Ringwald         hci_connection_t * connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it);
12865d14fa8fSMatthias Ringwald         if (connection->address_type != BD_ADDR_TYPE_LE_PUBLIC && connection->address_type != BD_ADDR_TYPE_LE_RANDOM) continue;
1287b68d7bc3SMatthias Ringwald         if (!hci_can_send_acl_packet_now(connection->con_handle)) continue;
1288da886c03S[email protected]         switch (connection->le_con_parameter_update_state){
1289b68d7bc3SMatthias Ringwald             case CON_PARAMETER_UPDATE_SEND_REQUEST:
1290b68d7bc3SMatthias Ringwald                 connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE;
1291b68d7bc3SMatthias Ringwald                 l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_REQUEST, connection->le_con_param_update_identifier,
1292b68d7bc3SMatthias Ringwald                                                connection->le_conn_interval_min, connection->le_conn_interval_max, connection->le_conn_latency, connection->le_supervision_timeout);
1293b68d7bc3SMatthias Ringwald                 break;
1294da886c03S[email protected]             case CON_PARAMETER_UPDATE_SEND_RESPONSE:
1295b68d7bc3SMatthias Ringwald                 connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_CHANGE_HCI_CON_PARAMETERS;
1296b68d7bc3SMatthias Ringwald                 l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 0);
1297da886c03S[email protected]                 break;
1298da886c03S[email protected]             case CON_PARAMETER_UPDATE_DENY:
1299b68d7bc3SMatthias Ringwald                 connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE;
1300b68d7bc3SMatthias Ringwald                 l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 1);
1301da886c03S[email protected]                 break;
1302da886c03S[email protected]             default:
1303da886c03S[email protected]                 break;
1304da886c03S[email protected]         }
1305da886c03S[email protected]     }
13064d7157c3S[email protected] #endif
1307da886c03S[email protected] 
130822c29ab4SMatthias Ringwald     // log_info("l2cap_run: exit");
13092cd0be45Smatthias.ringwald }
13102cd0be45Smatthias.ringwald 
131109e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1312fc64f94aSMatthias Ringwald static void l2cap_handle_connection_complete(hci_con_handle_t con_handle, l2cap_channel_t * channel){
13132df5dadcS[email protected]     if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
13145533f01eS[email protected]         log_info("l2cap_handle_connection_complete expected state");
13152df5dadcS[email protected]         // success, start l2cap handshake
1316fc64f94aSMatthias Ringwald         channel->con_handle = con_handle;
13172df5dadcS[email protected]         // check remote SSP feature first
13182df5dadcS[email protected]         channel->state = L2CAP_STATE_WAIT_REMOTE_SUPPORTED_FEATURES;
13192df5dadcS[email protected]     }
13202df5dadcS[email protected] }
13212df5dadcS[email protected] 
13221b9cb13dSMatthias Ringwald static void l2cap_ready_to_connect(l2cap_channel_t * channel){
13231b9cb13dSMatthias Ringwald 
13241b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
132527e0774aSMatthias Ringwald     // assumption: outgoing connection
13261b9cb13dSMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
13271b9cb13dSMatthias Ringwald     if (connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_IDLE){
13281b9cb13dSMatthias Ringwald         connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_W2_SEND_EXTENDED_FEATURE_REQUEST;
13291b9cb13dSMatthias Ringwald         channel->state = L2CAP_STATE_WAIT_OUTGOING_EXTENDED_FEATURES;
13301b9cb13dSMatthias Ringwald         return;
13311b9cb13dSMatthias Ringwald     }
13321b9cb13dSMatthias Ringwald #endif
13331b9cb13dSMatthias Ringwald 
13341b9cb13dSMatthias Ringwald     // fine, go ahead
13351b9cb13dSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
13361b9cb13dSMatthias Ringwald }
13371b9cb13dSMatthias Ringwald 
13382df5dadcS[email protected] static void l2cap_handle_remote_supported_features_received(l2cap_channel_t * channel){
13392df5dadcS[email protected]     if (channel->state != L2CAP_STATE_WAIT_REMOTE_SUPPORTED_FEATURES) return;
13402df5dadcS[email protected] 
13412df5dadcS[email protected]     // we have been waiting for remote supported features, if both support SSP,
1342ac301f95S[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));
1343fc64f94aSMatthias Ringwald     if (gap_ssp_supported_on_both_sides(channel->con_handle) && !l2cap_security_level_0_allowed_for_PSM(channel->psm)){
13442df5dadcS[email protected]         // request security level 2
13452df5dadcS[email protected]         channel->state = L2CAP_STATE_WAIT_OUTGOING_SECURITY_LEVEL_UPDATE;
1346fc64f94aSMatthias Ringwald         gap_request_security_level(channel->con_handle, LEVEL_2);
13472df5dadcS[email protected]         return;
13482df5dadcS[email protected]     }
13491b9cb13dSMatthias Ringwald 
13501b9cb13dSMatthias Ringwald     l2cap_ready_to_connect(channel);
13512df5dadcS[email protected] }
135209e9d05bSMatthias Ringwald #endif
13532df5dadcS[email protected] 
135409e9d05bSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
1355da144af5SMatthias 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,
1356da144af5SMatthias Ringwald     uint16_t psm, uint16_t local_mtu, gap_security_level_t security_level){
1357da144af5SMatthias Ringwald 
1358da144af5SMatthias Ringwald     l2cap_channel_t * channel = btstack_memory_l2cap_channel_get();
1359da144af5SMatthias Ringwald     if (!channel) {
1360da144af5SMatthias Ringwald         return NULL;
1361da144af5SMatthias Ringwald     }
1362da144af5SMatthias Ringwald 
1363da144af5SMatthias Ringwald      // Init memory (make valgrind happy)
1364da144af5SMatthias Ringwald     memset(channel, 0, sizeof(l2cap_channel_t));
1365da144af5SMatthias Ringwald 
1366da144af5SMatthias Ringwald     // fill in
1367da144af5SMatthias Ringwald     channel->packet_handler = packet_handler;
1368da144af5SMatthias Ringwald     bd_addr_copy(channel->address, address);
1369da144af5SMatthias Ringwald     channel->address_type = address_type;
1370da144af5SMatthias Ringwald     channel->psm = psm;
1371da144af5SMatthias Ringwald     channel->local_mtu  = local_mtu;
1372da144af5SMatthias Ringwald     channel->remote_mtu = L2CAP_MINIMAL_MTU;
1373da144af5SMatthias Ringwald     channel->required_security_level = security_level;
1374da144af5SMatthias Ringwald 
1375da144af5SMatthias Ringwald     //
1376da144af5SMatthias Ringwald     channel->local_cid = l2cap_next_local_cid();
1377da144af5SMatthias Ringwald     channel->con_handle = 0;
1378da144af5SMatthias Ringwald 
1379da144af5SMatthias Ringwald     // set initial state
1380da144af5SMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION;
1381da144af5SMatthias Ringwald     channel->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
1382da144af5SMatthias Ringwald     channel->remote_sig_id = L2CAP_SIG_ID_INVALID;
1383da144af5SMatthias Ringwald     channel->local_sig_id = L2CAP_SIG_ID_INVALID;
138438f62777SMatthias Ringwald 
1385da144af5SMatthias Ringwald     return channel;
1386da144af5SMatthias Ringwald }
138709e9d05bSMatthias Ringwald #endif
138809e9d05bSMatthias Ringwald 
138909e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1390da144af5SMatthias Ringwald 
13919077cb15SMatthias Ringwald /**
13929077cb15SMatthias Ringwald  * @brief Creates L2CAP channel to the PSM of a remote device with baseband address. A new baseband connection will be initiated if necessary.
13939077cb15SMatthias Ringwald  * @param packet_handler
13949077cb15SMatthias Ringwald  * @param address
13959077cb15SMatthias Ringwald  * @param psm
13969077cb15SMatthias Ringwald  * @param mtu
13979077cb15SMatthias Ringwald  * @param local_cid
13989077cb15SMatthias Ringwald  */
13999077cb15SMatthias Ringwald 
14009d139fbaSMatthias 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){
14019d139fbaSMatthias Ringwald     // limit MTU to the size of our outtgoing HCI buffer
14029d139fbaSMatthias Ringwald     uint16_t local_mtu = btstack_min(mtu, l2cap_max_mtu());
1403da144af5SMatthias Ringwald 
14049d139fbaSMatthias 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);
1405da144af5SMatthias Ringwald 
1406da144af5SMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(channel_packet_handler, address, BD_ADDR_TYPE_CLASSIC, psm, local_mtu, LEVEL_0);
1407fc64f94aSMatthias Ringwald     if (!channel) {
14089077cb15SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
14099077cb15SMatthias Ringwald     }
14109077cb15SMatthias Ringwald 
14111b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
14121b9cb13dSMatthias Ringwald     channel->mode = L2CAP_CHANNEL_MODE_BASIC;
14131b9cb13dSMatthias Ringwald #endif
14141b9cb13dSMatthias Ringwald 
14159077cb15SMatthias Ringwald     // add to connections list
1416fc64f94aSMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
14179077cb15SMatthias Ringwald 
14189077cb15SMatthias Ringwald     // store local_cid
14199077cb15SMatthias Ringwald     if (out_local_cid){
1420fc64f94aSMatthias Ringwald        *out_local_cid = channel->local_cid;
14219077cb15SMatthias Ringwald     }
14229077cb15SMatthias Ringwald 
14239077cb15SMatthias Ringwald     // check if hci connection is already usable
14249077cb15SMatthias Ringwald     hci_connection_t * conn = hci_connection_for_bd_addr_and_type(address, BD_ADDR_TYPE_CLASSIC);
14259077cb15SMatthias Ringwald     if (conn){
1426add0254bSMatthias Ringwald         log_info("l2cap_create_channel, hci connection already exists");
1427fc64f94aSMatthias Ringwald         l2cap_handle_connection_complete(conn->con_handle, channel);
14289077cb15SMatthias Ringwald         // check if remote supported fearures are already received
14299077cb15SMatthias Ringwald         if (conn->bonding_flags & BONDING_RECEIVED_REMOTE_FEATURES) {
1430fc64f94aSMatthias Ringwald             l2cap_handle_remote_supported_features_received(channel);
14319077cb15SMatthias Ringwald         }
14329077cb15SMatthias Ringwald     }
14339077cb15SMatthias Ringwald 
14349077cb15SMatthias Ringwald     l2cap_run();
14359077cb15SMatthias Ringwald 
14369077cb15SMatthias Ringwald     return 0;
14379077cb15SMatthias Ringwald }
14389077cb15SMatthias Ringwald 
14391b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
14407b181629SMatthias Ringwald 
1441843bae5dSMatthias Ringwald static uint8_t l2cap_ertm_validate_local_config(uint8_t max_transmit, uint16_t retransmission_timeout_ms, uint16_t monitor_timeout_ms,
1442843bae5dSMatthias Ringwald     uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size){
1443843bae5dSMatthias Ringwald 
14442b70d705SMatthias Ringwald     UNUSED(buffer);
14452b70d705SMatthias Ringwald     UNUSED(size);
14462b70d705SMatthias Ringwald 
14472b70d705SMatthias Ringwald     uint8_t result = ERROR_CODE_SUCCESS;
14482b70d705SMatthias Ringwald     if (max_transmit < 1){
14492b70d705SMatthias Ringwald         log_error("max_transmit must be >= 1");
14502b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
14512b70d705SMatthias Ringwald     }
14522b70d705SMatthias Ringwald     if (retransmission_timeout_ms < 2000){
14532b70d705SMatthias Ringwald         log_error("retransmission_timeout_ms must be >= 2000 ms");
14542b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
14552b70d705SMatthias Ringwald     }
14562b70d705SMatthias Ringwald     if (monitor_timeout_ms < 12000){
14572b70d705SMatthias Ringwald         log_error("monitor_timeout_ms must be >= 12000 ms");
14582b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
14592b70d705SMatthias Ringwald     }
1460843bae5dSMatthias Ringwald     if (local_mtu < 48){
1461843bae5dSMatthias Ringwald         log_error("local_mtu must be >= 48");
1462843bae5dSMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
1463843bae5dSMatthias Ringwald     }
14642b70d705SMatthias Ringwald     if (num_rx_buffers < 1){
14652b70d705SMatthias Ringwald         log_error("num_rx_buffers must be >= 1");
14662b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
14672b70d705SMatthias Ringwald     }
14682b70d705SMatthias Ringwald     if (num_tx_buffers < 1){
14692b70d705SMatthias Ringwald         log_error("num_rx_buffers must be >= 1");
14702b70d705SMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
14712b70d705SMatthias Ringwald     }
14722b70d705SMatthias Ringwald     return result;
14732b70d705SMatthias Ringwald }
14742b70d705SMatthias Ringwald 
1475843bae5dSMatthias Ringwald static void l2cap_ertm_configure_channel(l2cap_channel_t * channel, int ertm_mandatory, uint8_t max_transmit, uint16_t retransmission_timeout_ms,
1476843bae5dSMatthias Ringwald     uint16_t monitor_timeout_ms, uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size){
14777b181629SMatthias Ringwald 
14787b181629SMatthias Ringwald     channel->mode  = L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION;
14797b181629SMatthias Ringwald     channel->ertm_mandatory = ertm_mandatory;
1480bbc0a9e7SMatthias Ringwald     channel->local_max_transmit = max_transmit;
1481bbc0a9e7SMatthias Ringwald     channel->local_retransmission_timeout_ms = retransmission_timeout_ms;
1482bbc0a9e7SMatthias Ringwald     channel->local_monitor_timeout_ms = monitor_timeout_ms;
1483843bae5dSMatthias Ringwald     channel->local_mtu = local_mtu;
14847b181629SMatthias Ringwald     channel->num_rx_buffers = num_rx_buffers;
14857b181629SMatthias Ringwald     channel->num_tx_buffers = num_tx_buffers;
14867b181629SMatthias Ringwald 
1487843bae5dSMatthias Ringwald     // align buffer to 16-byte boundary, just in case
1488843bae5dSMatthias Ringwald     int bytes_till_alignment = 16 - (((uintptr_t) buffer) & 0x0f);
1489843bae5dSMatthias Ringwald     buffer += bytes_till_alignment;
1490843bae5dSMatthias Ringwald     size   -= bytes_till_alignment;
1491843bae5dSMatthias Ringwald 
1492843bae5dSMatthias Ringwald     // setup state buffers
14937b181629SMatthias Ringwald     uint32_t pos = 0;
14947b181629SMatthias Ringwald     channel->rx_packets_state = (l2cap_ertm_rx_packet_state_t *) &buffer[pos];
14957b181629SMatthias Ringwald     pos += num_rx_buffers * sizeof(l2cap_ertm_rx_packet_state_t);
14967b181629SMatthias Ringwald     channel->tx_packets_state = (l2cap_ertm_tx_packet_state_t *) &buffer[pos];
14977b181629SMatthias Ringwald     pos += num_tx_buffers * sizeof(l2cap_ertm_tx_packet_state_t);
1498843bae5dSMatthias Ringwald 
1499843bae5dSMatthias Ringwald     // setup reassembly buffer
1500843bae5dSMatthias Ringwald     channel->reassembly_buffer = &buffer[pos];
1501843bae5dSMatthias Ringwald     pos += local_mtu;
1502843bae5dSMatthias Ringwald 
1503843bae5dSMatthias Ringwald     // divide rest of data equally
1504843bae5dSMatthias Ringwald     channel->local_mps = (size - pos) / (num_rx_buffers + num_tx_buffers);
1505843bae5dSMatthias Ringwald     log_info("Local MPS: %u", channel->local_mtu);
15067b181629SMatthias Ringwald     channel->rx_packets_data = &buffer[pos];
15077b181629SMatthias Ringwald     pos += num_rx_buffers * channel->local_mtu;
15087b181629SMatthias Ringwald     channel->tx_packets_data = &buffer[pos];
15097b181629SMatthias Ringwald }
15107b181629SMatthias Ringwald 
1511501329faSMatthias Ringwald uint8_t l2cap_create_ertm_channel(btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm,
1512501329faSMatthias Ringwald     int ertm_mandatory, uint8_t max_transmit, uint16_t retransmission_timeout_ms, uint16_t monitor_timeout_ms,
1513843bae5dSMatthias Ringwald     uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size, uint16_t * out_local_cid){
1514501329faSMatthias Ringwald 
1515843bae5dSMatthias Ringwald     log_info("L2CAP_CREATE_CHANNEL addr %s, psm 0x%x, local mtu %u", bd_addr_to_str(address), psm, local_mtu);
15161b9cb13dSMatthias Ringwald 
15172b70d705SMatthias Ringwald     // validate local config
1518843bae5dSMatthias Ringwald     uint8_t result = l2cap_ertm_validate_local_config(max_transmit, retransmission_timeout_ms, monitor_timeout_ms, local_mtu, num_tx_buffers, num_rx_buffers, buffer, size);
15192b70d705SMatthias Ringwald     if (result) return result;
15202b70d705SMatthias Ringwald 
1521501329faSMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(packet_handler, address, BD_ADDR_TYPE_CLASSIC, psm, local_mtu, LEVEL_0);
15221b9cb13dSMatthias Ringwald     if (!channel) {
15231b9cb13dSMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
15241b9cb13dSMatthias Ringwald     }
15251b9cb13dSMatthias Ringwald 
15267b181629SMatthias Ringwald     // configure ERTM
15277b181629SMatthias Ringwald     l2cap_ertm_configure_channel(channel, ertm_mandatory, max_transmit, retransmission_timeout_ms,
1528843bae5dSMatthias Ringwald         local_mtu, monitor_timeout_ms, num_tx_buffers, num_rx_buffers, buffer, size);
15291b9cb13dSMatthias Ringwald 
15301b9cb13dSMatthias Ringwald     // add to connections list
15311b9cb13dSMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
15321b9cb13dSMatthias Ringwald 
15331b9cb13dSMatthias Ringwald     // store local_cid
15341b9cb13dSMatthias Ringwald     if (out_local_cid){
15351b9cb13dSMatthias Ringwald        *out_local_cid = channel->local_cid;
15361b9cb13dSMatthias Ringwald     }
15371b9cb13dSMatthias Ringwald 
15381b9cb13dSMatthias Ringwald     // check if hci connection is already usable
15391b9cb13dSMatthias Ringwald     hci_connection_t * conn = hci_connection_for_bd_addr_and_type(address, BD_ADDR_TYPE_CLASSIC);
15401b9cb13dSMatthias Ringwald     if (conn){
15411b9cb13dSMatthias Ringwald         log_info("l2cap_create_channel, hci connection already exists");
15421b9cb13dSMatthias Ringwald         l2cap_handle_connection_complete(conn->con_handle, channel);
15431b9cb13dSMatthias Ringwald         // check if remote supported fearures are already received
15441b9cb13dSMatthias Ringwald         if (conn->bonding_flags & BONDING_RECEIVED_REMOTE_FEATURES) {
15451b9cb13dSMatthias Ringwald             l2cap_handle_remote_supported_features_received(channel);
15461b9cb13dSMatthias Ringwald         }
15471b9cb13dSMatthias Ringwald     }
15481b9cb13dSMatthias Ringwald 
15491b9cb13dSMatthias Ringwald     l2cap_run();
15501b9cb13dSMatthias Ringwald 
15511b9cb13dSMatthias Ringwald     return 0;
15521b9cb13dSMatthias Ringwald }
15531b9cb13dSMatthias Ringwald #endif
15541b9cb13dSMatthias Ringwald 
1555ce8f182eSMatthias Ringwald void
1556ce8f182eSMatthias Ringwald l2cap_disconnect(uint16_t local_cid, uint8_t reason){
1557e0abb8e7S[email protected]     log_info("L2CAP_DISCONNECT local_cid 0x%x reason 0x%x", local_cid, reason);
1558b35f641cSmatthias.ringwald     // find channel for local_cid
1559b35f641cSmatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
1560f62db1e3Smatthias.ringwald     if (channel) {
1561e7ff783cSmatthias.ringwald         channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
1562f62db1e3Smatthias.ringwald     }
15632cd0be45Smatthias.ringwald     // process
15642cd0be45Smatthias.ringwald     l2cap_run();
156543625864Smatthias.ringwald }
15661e6aba47Smatthias.ringwald 
1567afde0c52Smatthias.ringwald static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t status){
1568665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1569665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
1570665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1571665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1572058e3d6bSMatthias Ringwald         if ( bd_addr_cmp( channel->address, address) != 0) continue;
1573c22aecc9S[email protected]         // channel for this address found
1574c22aecc9S[email protected]         switch (channel->state){
1575c22aecc9S[email protected]             case L2CAP_STATE_WAIT_CONNECTION_COMPLETE:
1576c22aecc9S[email protected]             case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
1577afde0c52Smatthias.ringwald                 // failure, forward error code
1578afde0c52Smatthias.ringwald                 l2cap_emit_channel_opened(channel, status);
1579afde0c52Smatthias.ringwald                 // discard channel
15809dcb2fb2S[email protected]                 l2cap_stop_rtx(channel);
1581665d90f2SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1582d3a9df87Smatthias.ringwald                 btstack_memory_l2cap_channel_free(channel);
1583c22aecc9S[email protected]                 break;
1584c22aecc9S[email protected]             default:
1585c22aecc9S[email protected]                 break;
1586afde0c52Smatthias.ringwald         }
1587afde0c52Smatthias.ringwald     }
1588afde0c52Smatthias.ringwald }
1589afde0c52Smatthias.ringwald 
1590afde0c52Smatthias.ringwald static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t handle){
1591665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1592665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
1593665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1594665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1595058e3d6bSMatthias Ringwald         if ( ! bd_addr_cmp( channel->address, address) ){
15962df5dadcS[email protected]             l2cap_handle_connection_complete(handle, channel);
1597afde0c52Smatthias.ringwald         }
1598afde0c52Smatthias.ringwald     }
15996fdcc387Smatthias.ringwald     // process
16006fdcc387Smatthias.ringwald     l2cap_run();
1601afde0c52Smatthias.ringwald }
160209e9d05bSMatthias Ringwald #endif
1603b448a0e7Smatthias.ringwald 
160496646001SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
160596646001SMatthias Ringwald static void l2cap_ertm_notify_channel_can_send(l2cap_channel_t * channel){
160696646001SMatthias Ringwald     if (l2cap_ertm_can_store_packet_now(channel)){
160796646001SMatthias Ringwald         channel->waiting_for_can_send_now = 0;
160896646001SMatthias Ringwald         l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid);
160996646001SMatthias Ringwald     }
161096646001SMatthias Ringwald }
161196646001SMatthias Ringwald #endif
161296646001SMatthias Ringwald 
161333c40538SMatthias Ringwald static void l2cap_notify_channel_can_send(void){
161409e9d05bSMatthias Ringwald 
161509e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
161633c40538SMatthias Ringwald     btstack_linked_list_iterator_t it;
161733c40538SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
161833c40538SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
161933c40538SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
162033c40538SMatthias Ringwald         if (!channel->waiting_for_can_send_now) continue;
1621fc64f94aSMatthias Ringwald         if (!hci_can_send_acl_packet_now(channel->con_handle)) continue;
162233c40538SMatthias Ringwald         channel->waiting_for_can_send_now = 0;
162334e7e577SMatthias Ringwald         l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid);
162433c40538SMatthias Ringwald     }
162509e9d05bSMatthias Ringwald #endif
162644276248SMatthias Ringwald 
16272125de09SMatthias Ringwald     int i;
16282125de09SMatthias Ringwald     for (i=0;i<L2CAP_FIXED_CHANNEL_TABLE_SIZE;i++){
1629773c4106SMatthias Ringwald         if (!fixed_channels[i].callback) continue;
16302125de09SMatthias Ringwald         if (!fixed_channels[i].waiting_for_can_send_now) continue;
163135454696SMatthias Ringwald         int can_send = 0;
163234e7e577SMatthias Ringwald         if (l2cap_fixed_channel_table_index_is_le(i)){
163335454696SMatthias Ringwald #ifdef ENABLE_BLE
163434e7e577SMatthias Ringwald             can_send = hci_can_send_acl_le_packet_now();
163535454696SMatthias Ringwald #endif
163634e7e577SMatthias Ringwald         } else {
163735454696SMatthias Ringwald #ifdef ENABLE_CLASSIC
163834e7e577SMatthias Ringwald             can_send = hci_can_send_acl_classic_packet_now();
163935454696SMatthias Ringwald #endif
164034e7e577SMatthias Ringwald         }
164134e7e577SMatthias Ringwald         if (!can_send) continue;
164234e7e577SMatthias Ringwald         fixed_channels[i].waiting_for_can_send_now = 0;
164334e7e577SMatthias Ringwald         l2cap_emit_can_send_now(fixed_channels[i].callback, l2cap_fixed_channel_table_channel_id_for_index(i));
16442125de09SMatthias Ringwald     }
164533c40538SMatthias Ringwald }
164633c40538SMatthias Ringwald 
1647d9a7306aSMatthias Ringwald static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *packet, uint16_t size){
1648afde0c52Smatthias.ringwald 
16499ec2630cSMatthias Ringwald     UNUSED(packet_type);
16509ec2630cSMatthias Ringwald     UNUSED(cid);
16519ec2630cSMatthias Ringwald     UNUSED(size);
16529ec2630cSMatthias Ringwald 
1653afde0c52Smatthias.ringwald     bd_addr_t address;
1654afde0c52Smatthias.ringwald     hci_con_handle_t handle;
16552d00edd4Smatthias.ringwald     int hci_con_used;
165609e9d05bSMatthias Ringwald     btstack_linked_list_iterator_t it;
165709e9d05bSMatthias Ringwald 
165809e9d05bSMatthias Ringwald     // avoid unused warnings
1659f3963406SMatthias Ringwald     UNUSED(address);
1660f3963406SMatthias Ringwald     UNUSED(hci_con_used);
1661f3963406SMatthias Ringwald     UNUSED(it);
1662f22209dfSMatthias Ringwald     UNUSED(handle);
1663afde0c52Smatthias.ringwald 
16640e2df43fSMatthias Ringwald     switch(hci_event_packet_get_type(packet)){
1665afde0c52Smatthias.ringwald 
166609e9d05bSMatthias Ringwald         // Notify channel packet handler if they can send now
166709e9d05bSMatthias Ringwald         case HCI_EVENT_TRANSPORT_PACKET_SENT:
166809e9d05bSMatthias Ringwald         case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
166909e9d05bSMatthias Ringwald             l2cap_run();    // try sending signaling packets first
167009e9d05bSMatthias Ringwald             l2cap_notify_channel_can_send();
167109e9d05bSMatthias Ringwald             break;
167209e9d05bSMatthias Ringwald 
167309e9d05bSMatthias Ringwald         case HCI_EVENT_COMMAND_STATUS:
167409e9d05bSMatthias Ringwald             l2cap_run();    // try sending signaling packets first
167509e9d05bSMatthias Ringwald             break;
167609e9d05bSMatthias Ringwald 
167709e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1678afde0c52Smatthias.ringwald         // handle connection complete events
1679afde0c52Smatthias.ringwald         case HCI_EVENT_CONNECTION_COMPLETE:
1680724d70a2SMatthias Ringwald             reverse_bd_addr(&packet[5], address);
1681afde0c52Smatthias.ringwald             if (packet[2] == 0){
1682f8fbdce0SMatthias Ringwald                 handle = little_endian_read_16(packet, 3);
1683afde0c52Smatthias.ringwald                 l2cap_handle_connection_success_for_addr(address, handle);
1684afde0c52Smatthias.ringwald             } else {
1685afde0c52Smatthias.ringwald                 l2cap_handle_connection_failed_for_addr(address, packet[2]);
1686afde0c52Smatthias.ringwald             }
1687afde0c52Smatthias.ringwald             break;
1688afde0c52Smatthias.ringwald 
1689afde0c52Smatthias.ringwald         // handle successful create connection cancel command
1690afde0c52Smatthias.ringwald         case HCI_EVENT_COMMAND_COMPLETE:
1691073bd0faSMatthias Ringwald             if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_create_connection_cancel)) {
1692afde0c52Smatthias.ringwald                 if (packet[5] == 0){
1693724d70a2SMatthias Ringwald                     reverse_bd_addr(&packet[6], address);
1694afde0c52Smatthias.ringwald                     // CONNECTION TERMINATED BY LOCAL HOST (0X16)
1695afde0c52Smatthias.ringwald                     l2cap_handle_connection_failed_for_addr(address, 0x16);
169603cfbabcSmatthias.ringwald                 }
16971e6aba47Smatthias.ringwald             }
169839d59809Smatthias.ringwald             l2cap_run();    // try sending signaling packets first
169939d59809Smatthias.ringwald             break;
170009e9d05bSMatthias Ringwald #endif
170127a923d0Smatthias.ringwald 
17021e6aba47Smatthias.ringwald         // handle disconnection complete events
1703afde0c52Smatthias.ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
1704c22aecc9S[email protected]             // send l2cap disconnect events for all channels on this handle and free them
170509e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1706d0662982SMatthias Ringwald             handle = little_endian_read_16(packet, 3);
1707665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
1708665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
1709665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1710fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
171115ec09bbSmatthias.ringwald                 l2cap_emit_channel_closed(channel);
17129dcb2fb2S[email protected]                 l2cap_stop_rtx(channel);
1713665d90f2SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1714d3a9df87Smatthias.ringwald                 btstack_memory_l2cap_channel_free(channel);
171527a923d0Smatthias.ringwald             }
171609e9d05bSMatthias Ringwald #endif
1717a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
1718d0662982SMatthias Ringwald             handle = little_endian_read_16(packet, 3);
1719991fea48SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
1720991fea48SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
1721991fea48SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1722991fea48SMatthias Ringwald                 if (channel->con_handle != handle) continue;
1723991fea48SMatthias Ringwald                 l2cap_emit_channel_closed(channel);
1724991fea48SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1725991fea48SMatthias Ringwald                 btstack_memory_l2cap_channel_free(channel);
1726991fea48SMatthias Ringwald             }
1727991fea48SMatthias Ringwald #endif
1728afde0c52Smatthias.ringwald             break;
1729fcadd0caSmatthias.ringwald 
1730ee091cf1Smatthias.ringwald         // HCI Connection Timeouts
173109e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1732afde0c52Smatthias.ringwald         case L2CAP_EVENT_TIMEOUT_CHECK:
1733f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet, 2);
1734bd04d84aSMatthias Ringwald             if (gap_get_connection_type(handle) != GAP_CONNECTION_ACL) break;
173580ca58a0Smatthias.ringwald             if (hci_authentication_active_for_handle(handle)) break;
17362d00edd4Smatthias.ringwald             hci_con_used = 0;
1737665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
1738665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
1739665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1740fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
17412d00edd4Smatthias.ringwald                 hci_con_used = 1;
1742c22aecc9S[email protected]                 break;
1743ee091cf1Smatthias.ringwald             }
17442d00edd4Smatthias.ringwald             if (hci_con_used) break;
1745d94d3cafS[email protected]             if (!hci_can_send_command_packet_now()) break;
17469edc8742Smatthias.ringwald             hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection
1747afde0c52Smatthias.ringwald             break;
1748ee091cf1Smatthias.ringwald 
1749df3354fcS[email protected]         case HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE:
1750f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet, 3);
1751665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
1752665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
1753665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1754fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
17552df5dadcS[email protected]                 l2cap_handle_remote_supported_features_received(channel);
1756df3354fcS[email protected]                 break;
1757df3354fcS[email protected]             }
1758c22aecc9S[email protected]             break;
1759df3354fcS[email protected] 
17605611a760SMatthias Ringwald         case GAP_EVENT_SECURITY_LEVEL:
1761f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet, 2);
1762bd63148eS[email protected]             log_info("l2cap - security level update");
1763665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
1764665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
1765665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1766fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
17675533f01eS[email protected] 
1768bd63148eS[email protected]                 log_info("l2cap - state %u", channel->state);
1769bd63148eS[email protected] 
1770e569dfd9SMatthias Ringwald                 gap_security_level_t actual_level = (gap_security_level_t) packet[4];
17715533f01eS[email protected]                 gap_security_level_t required_level = channel->required_security_level;
17725533f01eS[email protected] 
1773df3354fcS[email protected]                 switch (channel->state){
1774df3354fcS[email protected]                     case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE:
17755533f01eS[email protected]                         if (actual_level >= required_level){
177652606043SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
177752606043SMatthias Ringwald                             // we need to know if ERTM is supported before sending a config response
177852606043SMatthias Ringwald                             hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
177952606043SMatthias Ringwald                             connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_W2_SEND_EXTENDED_FEATURE_REQUEST;
178052606043SMatthias Ringwald                             channel->state = L2CAP_STATE_WAIT_INCOMING_EXTENDED_FEATURES;
178152606043SMatthias Ringwald #else
1782f85a9399S[email protected]                             channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
178344276248SMatthias Ringwald                             l2cap_emit_incoming_connection(channel);
178452606043SMatthias Ringwald #endif
17851eb2563eS[email protected]                         } else {
1786775ecc36SMatthias Ringwald                             channel->reason = 0x0003; // security block
17871eb2563eS[email protected]                             channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
17881eb2563eS[email protected]                         }
1789df3354fcS[email protected]                         break;
1790df3354fcS[email protected] 
1791df3354fcS[email protected]                     case L2CAP_STATE_WAIT_OUTGOING_SECURITY_LEVEL_UPDATE:
17925533f01eS[email protected]                         if (actual_level >= required_level){
17931b9cb13dSMatthias Ringwald                             l2cap_ready_to_connect(channel);
1794df3354fcS[email protected]                         } else {
1795df3354fcS[email protected]                             // disconnnect, authentication not good enough
1796df3354fcS[email protected]                             hci_disconnect_security_block(handle);
1797df3354fcS[email protected]                         }
1798df3354fcS[email protected]                         break;
1799df3354fcS[email protected] 
1800df3354fcS[email protected]                     default:
1801df3354fcS[email protected]                         break;
1802df3354fcS[email protected]                 }
1803f85a9399S[email protected]             }
1804f85a9399S[email protected]             break;
180509e9d05bSMatthias Ringwald #endif
1806f85a9399S[email protected] 
1807afde0c52Smatthias.ringwald         default:
1808afde0c52Smatthias.ringwald             break;
1809afde0c52Smatthias.ringwald     }
1810afde0c52Smatthias.ringwald 
1811bd63148eS[email protected]     l2cap_run();
18121e6aba47Smatthias.ringwald }
18131e6aba47Smatthias.ringwald 
1814e74c5f58SMatthias 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){
18154cf56b4aSmatthias.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."
18162b360848Smatthias.ringwald     if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) {
18172b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].handle = handle;
18182b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].code = code;
18192b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].sig_id = sig_id;
1820e74c5f58SMatthias Ringwald         signaling_responses[signaling_responses_pending].cid = cid;
18212b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].data = data;
18222b360848Smatthias.ringwald         signaling_responses_pending++;
18232b360848Smatthias.ringwald         l2cap_run();
18242b360848Smatthias.ringwald     }
18252b360848Smatthias.ringwald }
18262b360848Smatthias.ringwald 
182709e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
182809e9d05bSMatthias Ringwald static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){
182909e9d05bSMatthias Ringwald     channel->remote_sig_id = identifier;
183009e9d05bSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
183109e9d05bSMatthias Ringwald     l2cap_run();
183209e9d05bSMatthias Ringwald }
183309e9d05bSMatthias Ringwald 
1834b35f641cSmatthias.ringwald static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){
1835645658c9Smatthias.ringwald 
18369da54300S[email protected]     // log_info("l2cap_handle_connection_request for handle %u, psm %u cid 0x%02x", handle, psm, source_cid);
1837645658c9Smatthias.ringwald     l2cap_service_t *service = l2cap_get_service(psm);
1838645658c9Smatthias.ringwald     if (!service) {
1839645658c9Smatthias.ringwald         // 0x0002 PSM not supported
1840e74c5f58SMatthias Ringwald         l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, source_cid, 0x0002);
1841645658c9Smatthias.ringwald         return;
1842645658c9Smatthias.ringwald     }
1843645658c9Smatthias.ringwald 
18445061f3afS[email protected]     hci_connection_t * hci_connection = hci_connection_for_handle( handle );
1845645658c9Smatthias.ringwald     if (!hci_connection) {
18462b360848Smatthias.ringwald         //
18479da54300S[email protected]         log_error("no hci_connection for handle %u", handle);
1848645658c9Smatthias.ringwald         return;
1849645658c9Smatthias.ringwald     }
18502bd8b7e7S[email protected] 
1851645658c9Smatthias.ringwald     // alloc structure
18529da54300S[email protected]     // log_info("l2cap_handle_connection_request register channel");
1853da144af5SMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(service->packet_handler, hci_connection->address, BD_ADDR_TYPE_CLASSIC,
1854da144af5SMatthias Ringwald     psm, service->mtu, service->required_security_level);
18552b360848Smatthias.ringwald     if (!channel){
18562b360848Smatthias.ringwald         // 0x0004 No resources available
1857e74c5f58SMatthias Ringwald         l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, source_cid, 0x0004);
18582b360848Smatthias.ringwald         return;
18592b360848Smatthias.ringwald     }
1860da144af5SMatthias Ringwald 
1861fc64f94aSMatthias Ringwald     channel->con_handle = handle;
1862b35f641cSmatthias.ringwald     channel->remote_cid = source_cid;
1863b1988dceSmatthias.ringwald     channel->remote_sig_id = sig_id;
1864645658c9Smatthias.ringwald 
1865f53da564S[email protected]     // limit local mtu to max acl packet length - l2cap header
18662985cb84Smatthias.ringwald     if (channel->local_mtu > l2cap_max_mtu()) {
18672985cb84Smatthias.ringwald         channel->local_mtu = l2cap_max_mtu();
18689775e25bSmatthias.ringwald     }
18699775e25bSmatthias.ringwald 
1870645658c9Smatthias.ringwald     // set initial state
1871df3354fcS[email protected]     channel->state =      L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE;
1872a24785d0SMatthias Ringwald     channel->state_var  = (L2CAP_CHANNEL_STATE_VAR) (L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND | L2CAP_CHANNEL_STATE_VAR_INCOMING);
1873e405ae81Smatthias.ringwald 
1874645658c9Smatthias.ringwald     // add to connections list
1875665d90f2SMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
1876645658c9Smatthias.ringwald 
1877f85a9399S[email protected]     // assert security requirements
18781eb2563eS[email protected]     gap_request_security_level(handle, channel->required_security_level);
1879e405ae81Smatthias.ringwald }
1880645658c9Smatthias.ringwald 
1881ce8f182eSMatthias Ringwald void l2cap_accept_connection(uint16_t local_cid){
1882e0abb8e7S[email protected]     log_info("L2CAP_ACCEPT_CONNECTION local_cid 0x%x", local_cid);
1883b35f641cSmatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
1884e405ae81Smatthias.ringwald     if (!channel) {
1885ce8f182eSMatthias Ringwald         log_error("l2cap_accept_connection called but local_cid 0x%x not found", local_cid);
1886e405ae81Smatthias.ringwald         return;
1887e405ae81Smatthias.ringwald     }
1888e405ae81Smatthias.ringwald 
188943ec931dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
189043ec931dSMatthias Ringwald     // configure L2CAP Basic mode
189143ec931dSMatthias Ringwald     channel->mode  = L2CAP_CHANNEL_MODE_BASIC;
189243ec931dSMatthias Ringwald #endif
189343ec931dSMatthias Ringwald 
1894552d92a1Smatthias.ringwald     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
1895e405ae81Smatthias.ringwald 
1896552d92a1Smatthias.ringwald     // process
1897552d92a1Smatthias.ringwald     l2cap_run();
1898e405ae81Smatthias.ringwald }
1899645658c9Smatthias.ringwald 
190043ec931dSMatthias Ringwald 
190143ec931dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
1902843bae5dSMatthias Ringwald uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, int ertm_mandatory, uint8_t max_transmit, uint16_t retransmission_timeout_ms,
1903843bae5dSMatthias Ringwald      uint16_t monitor_timeout_ms, uint16_t local_mtu, uint8_t num_tx_buffers, uint8_t num_rx_buffers, uint8_t * buffer, uint32_t size){
1904501329faSMatthias Ringwald 
190543ec931dSMatthias Ringwald     log_info("L2CAP_ACCEPT_ERTM_CONNECTION local_cid 0x%x", local_cid);
190643ec931dSMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
190743ec931dSMatthias Ringwald     if (!channel) {
190843ec931dSMatthias Ringwald         log_error("l2cap_accept_connection called but local_cid 0x%x not found", local_cid);
19092b70d705SMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
191043ec931dSMatthias Ringwald     }
191143ec931dSMatthias Ringwald 
19122b70d705SMatthias Ringwald     // validate local config
1913843bae5dSMatthias Ringwald     uint8_t result = l2cap_ertm_validate_local_config(max_transmit, retransmission_timeout_ms, monitor_timeout_ms, local_mtu, num_tx_buffers, num_rx_buffers, buffer, size);
19142b70d705SMatthias Ringwald     if (result) return result;
19152b70d705SMatthias Ringwald 
191643ec931dSMatthias Ringwald     // configure L2CAP ERTM
1917843bae5dSMatthias Ringwald     l2cap_ertm_configure_channel(channel, ertm_mandatory, max_transmit, retransmission_timeout_ms, monitor_timeout_ms, local_mtu, num_tx_buffers, num_rx_buffers, buffer, size);
191843ec931dSMatthias Ringwald 
19197b181629SMatthias Ringwald     // continue
192043ec931dSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
192143ec931dSMatthias Ringwald 
192243ec931dSMatthias Ringwald     // process
192343ec931dSMatthias Ringwald     l2cap_run();
19242b70d705SMatthias Ringwald 
19252b70d705SMatthias Ringwald     return ERROR_CODE_SUCCESS;
192643ec931dSMatthias Ringwald }
19272a424812SMatthias Ringwald 
192867a3a5b7SMatthias Ringwald uint8_t l2cap_ertm_set_busy(uint16_t local_cid){
19298f1c9639SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
19308f1c9639SMatthias Ringwald     if (!channel) {
19318f1c9639SMatthias Ringwald         log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
19328f1c9639SMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
19338f1c9639SMatthias Ringwald     }
19342bea1b8dSMatthias Ringwald     if (!channel->local_busy){
19352bea1b8dSMatthias Ringwald         channel->local_busy = 1;
19368f1c9639SMatthias Ringwald         channel->send_supervisor_frame_receiver_not_ready = 1;
19378f1c9639SMatthias Ringwald         l2cap_run();
19382bea1b8dSMatthias Ringwald     }
193967a3a5b7SMatthias Ringwald     return ERROR_CODE_SUCCESS;
194067a3a5b7SMatthias Ringwald }
194167a3a5b7SMatthias Ringwald 
194267a3a5b7SMatthias Ringwald uint8_t l2cap_ertm_set_ready(uint16_t local_cid){
19432bea1b8dSMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
19442bea1b8dSMatthias Ringwald     if (!channel) {
19452bea1b8dSMatthias Ringwald         log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
19462bea1b8dSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
19472bea1b8dSMatthias Ringwald     }
19482bea1b8dSMatthias Ringwald     if (channel->local_busy){
19492bea1b8dSMatthias Ringwald         channel->local_busy = 0;
19502bea1b8dSMatthias Ringwald         channel->send_supervisor_frame_receiver_ready_poll = 1;
19512bea1b8dSMatthias Ringwald         l2cap_run();
19522bea1b8dSMatthias Ringwald     }
195367a3a5b7SMatthias Ringwald     return ERROR_CODE_SUCCESS;
195467a3a5b7SMatthias Ringwald }
195567a3a5b7SMatthias Ringwald 
19562a424812SMatthias Ringwald static void l2cap_ertm_handle_req_seq(l2cap_channel_t * l2cap_channel, uint8_t req_seq){
195796646001SMatthias Ringwald     int num_buffers_acked = 0;
19582a424812SMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state;
1959bc4521b7SMatthias Ringwald     while (1){
19602a424812SMatthias Ringwald         tx_state = &l2cap_channel->tx_packets_state[l2cap_channel->tx_read_index];
1961bc4521b7SMatthias Ringwald         // calc delta
1962bc4521b7SMatthias Ringwald         int delta = (req_seq - tx_state->tx_seq) & 0x03f;
1963bc4521b7SMatthias Ringwald         if (delta == 0) break;  // all packets acknowledged
1964bc4521b7SMatthias Ringwald         if (delta > l2cap_channel->remote_tx_window_size) break;
1965bc4521b7SMatthias Ringwald 
196696646001SMatthias Ringwald         num_buffers_acked++;
1967bc4521b7SMatthias Ringwald         log_info("RR seq %u => packet with tx_seq %u done", req_seq, tx_state->tx_seq);
1968bc4521b7SMatthias Ringwald 
196962041d70SMatthias Ringwald         // stop retransmission timer
1970*c9300dcaSMatthias Ringwald         btstack_run_loop_remove_timer(&l2cap_channel->retransmission_timer);
19712a424812SMatthias Ringwald         l2cap_channel->tx_read_index++;
19722a424812SMatthias Ringwald         if (l2cap_channel->tx_read_index >= l2cap_channel->num_rx_buffers){
19732a424812SMatthias Ringwald             l2cap_channel->tx_read_index = 0;
19742a424812SMatthias Ringwald         }
1975bc4521b7SMatthias Ringwald 
1976bc4521b7SMatthias Ringwald         // no unack packages
1977bc4521b7SMatthias Ringwald         if (l2cap_channel->tx_read_index == l2cap_channel->tx_write_index) break;
19782a424812SMatthias Ringwald     }
197996646001SMatthias Ringwald 
198096646001SMatthias Ringwald     if (num_buffers_acked){
198196646001SMatthias Ringwald         l2cap_ertm_notify_channel_can_send(l2cap_channel);
198296646001SMatthias Ringwald     }
19832a424812SMatthias Ringwald }
198467a3a5b7SMatthias Ringwald 
19857b7901d8SMatthias Ringwald static l2cap_ertm_tx_packet_state_t * l2cap_ertm_get_tx_state(l2cap_channel_t * l2cap_channel, uint8_t tx_seq){
19867b7901d8SMatthias Ringwald     int i;
19877b7901d8SMatthias Ringwald     for (i=0;i<l2cap_channel->num_tx_buffers;i++){
19887b7901d8SMatthias Ringwald         l2cap_ertm_tx_packet_state_t * tx_state = &l2cap_channel->tx_packets_state[i];
19897b7901d8SMatthias Ringwald         if (tx_state->tx_seq == tx_seq) return tx_state;
19907b7901d8SMatthias Ringwald     }
19917b7901d8SMatthias Ringwald     return NULL;
19927b7901d8SMatthias Ringwald }
199343ec931dSMatthias Ringwald #endif
199443ec931dSMatthias Ringwald 
199543ec931dSMatthias Ringwald 
19967ef6a7bbSMatthias Ringwald void l2cap_decline_connection(uint16_t local_cid){
19977ef6a7bbSMatthias Ringwald     log_info("L2CAP_DECLINE_CONNECTION local_cid 0x%x", local_cid);
1998b35f641cSmatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
1999e405ae81Smatthias.ringwald     if (!channel) {
2000ce8f182eSMatthias Ringwald         log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
2001e405ae81Smatthias.ringwald         return;
2002e405ae81Smatthias.ringwald     }
2003e7ff783cSmatthias.ringwald     channel->state  = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
20047ef6a7bbSMatthias Ringwald     channel->reason = 0x04; // no resources available
2005e7ff783cSmatthias.ringwald     l2cap_run();
2006645658c9Smatthias.ringwald }
2007645658c9Smatthias.ringwald 
20087f02f414SMatthias Ringwald static void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t *command){
2009b1988dceSmatthias.ringwald 
2010b1988dceSmatthias.ringwald     channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
2011b1988dceSmatthias.ringwald 
2012f8fbdce0SMatthias Ringwald     uint16_t flags = little_endian_read_16(command, 6);
201363a7246aSmatthias.ringwald     if (flags & 1) {
201463a7246aSmatthias.ringwald         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT);
201563a7246aSmatthias.ringwald     }
201663a7246aSmatthias.ringwald 
20172784b77dSmatthias.ringwald     // accept the other's configuration options
2018f8fbdce0SMatthias Ringwald     uint16_t end_pos = 4 + little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
20193de7c0caSmatthias.ringwald     uint16_t pos     = 8;
20203de7c0caSmatthias.ringwald     while (pos < end_pos){
202163a7246aSmatthias.ringwald         uint8_t option_hint = command[pos] >> 7;
202263a7246aSmatthias.ringwald         uint8_t option_type = command[pos] & 0x7f;
20233844aeadSMatthias Ringwald         // log_info("l2cap cid %u, hint %u, type %u", channel->local_cid, option_hint, option_type);
202463a7246aSmatthias.ringwald         pos++;
20251dc511deSmatthias.ringwald         uint8_t length = command[pos++];
20261dc511deSmatthias.ringwald         // MTU { type(8): 1, len(8):2, MTU(16) }
202763a7246aSmatthias.ringwald         if (option_type == 1 && length == 2){
2028f8fbdce0SMatthias Ringwald             channel->remote_mtu = little_endian_read_16(command, pos);
20293844aeadSMatthias Ringwald             log_info("Remote MTU %u", channel->remote_mtu);
20309d139fbaSMatthias Ringwald             if (channel->remote_mtu > l2cap_max_mtu()){
20319d139fbaSMatthias Ringwald                 log_info("Remote MTU %u larger than outgoing buffer, only using MTU = %u", channel->remote_mtu, l2cap_max_mtu());
20329d139fbaSMatthias Ringwald                 channel->remote_mtu = l2cap_max_mtu();
20339d139fbaSMatthias Ringwald             }
203463a7246aSmatthias.ringwald             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
203563a7246aSmatthias.ringwald         }
20360fe7a9d0S[email protected]         // Flush timeout { type(8):2, len(8): 2, Flush Timeout(16)}
20370fe7a9d0S[email protected]         if (option_type == 2 && length == 2){
2038f8fbdce0SMatthias Ringwald             channel->flush_timeout = little_endian_read_16(command, pos);
20393844aeadSMatthias Ringwald             log_info("Flush timeout: %u ms", channel->flush_timeout);
20400fe7a9d0S[email protected]         }
2041f2fa388dSMatthias Ringwald 
20426dca2a0cSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
20436dca2a0cSMatthias Ringwald         // Retransmission and Flow Control Option
20446dca2a0cSMatthias Ringwald         if (option_type == 4 && length == 9){
20453232a1c6SMatthias Ringwald             l2cap_channel_mode_t mode = (l2cap_channel_mode_t) command[pos];
2046ac8f1300SMatthias Ringwald             switch(channel->mode){
2047ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION:
204825cd60d3SMatthias Ringwald                     // Store remote config
2049bbc0a9e7SMatthias Ringwald                     channel->remote_tx_window_size = command[pos+1];
2050bbc0a9e7SMatthias Ringwald                     channel->remote_max_transmit   = command[pos+2];
2051bbc0a9e7SMatthias Ringwald                     channel->remote_retransmission_timeout_ms = little_endian_read_16(command, pos + 3);
2052bbc0a9e7SMatthias Ringwald                     channel->remote_monitor_timeout_ms = little_endian_read_16(command, pos + 5);
20533844aeadSMatthias Ringwald                     channel->remote_mps = little_endian_read_16(command, pos + 7);
20543844aeadSMatthias Ringwald                     log_info("FC&C config: tx window: %u, max transmit %u, retrans timeout %u, monitor timeout %u, mps %u",
2055bbc0a9e7SMatthias Ringwald                         channel->remote_tx_window_size,
2056bbc0a9e7SMatthias Ringwald                         channel->remote_max_transmit,
2057bbc0a9e7SMatthias Ringwald                         channel->remote_retransmission_timeout_ms,
20583844aeadSMatthias Ringwald                         channel->remote_monitor_timeout_ms,
20593844aeadSMatthias Ringwald                         channel->remote_mps);
206025cd60d3SMatthias Ringwald                     // If ERTM mandatory, but remote doens't offer ERTM -> disconnect
206125cd60d3SMatthias Ringwald                     if (channel->ertm_mandatory && mode != L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
206225cd60d3SMatthias Ringwald                         channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
2063ac8f1300SMatthias Ringwald                     } else {
2064ac8f1300SMatthias Ringwald                         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
2065ac8f1300SMatthias Ringwald                     }
2066ac8f1300SMatthias Ringwald                     break;
2067ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_BASIC:
2068ac8f1300SMatthias Ringwald                     switch (mode){
2069ac8f1300SMatthias Ringwald                         case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION:
2070ac8f1300SMatthias Ringwald                             // remote asks for ERTM, but we want basic mode. disconnect if this happens a second time
2071ac8f1300SMatthias Ringwald                             if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_BASIC_FALLBACK_TRIED){
2072ac8f1300SMatthias Ringwald                                 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
2073ac8f1300SMatthias Ringwald                             }
2074ac8f1300SMatthias Ringwald                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_BASIC_FALLBACK_TRIED);
2075ac8f1300SMatthias Ringwald                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED);
2076ac8f1300SMatthias Ringwald                             break;
2077ac8f1300SMatthias Ringwald                         default: // case L2CAP_CHANNEL_MODE_BASIC:
2078ac8f1300SMatthias Ringwald                             // TODO store and evaluate configuration
2079ac8f1300SMatthias Ringwald                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
2080ac8f1300SMatthias Ringwald                             break;
2081ac8f1300SMatthias Ringwald                     }
2082ac8f1300SMatthias Ringwald                     break;
2083ac8f1300SMatthias Ringwald                 default:
2084ac8f1300SMatthias Ringwald                     break;
2085ac8f1300SMatthias Ringwald             }
20863232a1c6SMatthias Ringwald         }
20876dca2a0cSMatthias Ringwald #endif
208863a7246aSmatthias.ringwald         // check for unknown options
208963a7246aSmatthias.ringwald         if (option_hint == 0 && (option_type == 0 || option_type >= 0x07)){
2090c177a91cS[email protected]             log_info("l2cap cid %u, unknown options", channel->local_cid);
209163a7246aSmatthias.ringwald             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID);
20921dc511deSmatthias.ringwald         }
20931dc511deSmatthias.ringwald         pos += length;
20941dc511deSmatthias.ringwald     }
20952784b77dSmatthias.ringwald }
20962784b77dSmatthias.ringwald 
2097f2fa388dSMatthias Ringwald static void l2cap_signaling_handle_configure_response(l2cap_channel_t *channel, uint8_t result, uint8_t *command){
2098f2fa388dSMatthias Ringwald     log_info("l2cap_signaling_handle_configure_response");
20993232a1c6SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
21003232a1c6SMatthias Ringwald     uint16_t end_pos = 4 + little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
2101f2fa388dSMatthias Ringwald     uint16_t pos     = 10;
21023232a1c6SMatthias Ringwald     while (pos < end_pos){
21033232a1c6SMatthias Ringwald         uint8_t option_hint = command[pos] >> 7;
21043232a1c6SMatthias Ringwald         uint8_t option_type = command[pos] & 0x7f;
21053232a1c6SMatthias Ringwald         log_info("l2cap cid %u, hint %u, type %u", channel->local_cid, option_hint, option_type);
21063232a1c6SMatthias Ringwald         pos++;
21073232a1c6SMatthias Ringwald         uint8_t length = command[pos++];
21083232a1c6SMatthias Ringwald 
21093232a1c6SMatthias Ringwald         // Retransmission and Flow Control Option
21103232a1c6SMatthias Ringwald         if (option_type == 4 && length == 9){
2111ac8f1300SMatthias Ringwald             switch (channel->mode){
2112ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION:
2113f2fa388dSMatthias Ringwald                     if (channel->ertm_mandatory){
2114ac8f1300SMatthias Ringwald                         // ??
2115f2fa388dSMatthias Ringwald                     } else {
2116ac8f1300SMatthias Ringwald                         // On 'Reject - Unacceptable Parameters' to our optional ERTM request, fall back to BASIC mode
2117ac8f1300SMatthias Ringwald                         if (result == L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS){
2118f2fa388dSMatthias Ringwald                             channel->mode = L2CAP_CHANNEL_MODE_BASIC;
21193232a1c6SMatthias Ringwald                         }
21203232a1c6SMatthias Ringwald                     }
2121ac8f1300SMatthias Ringwald                     break;
2122ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_BASIC:
2123ac8f1300SMatthias Ringwald                     if (result == L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS){
2124ac8f1300SMatthias Ringwald                         // On 'Reject - Unacceptable Parameters' to our Basic mode request, disconnect
2125ac8f1300SMatthias Ringwald                         channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
2126ac8f1300SMatthias Ringwald                     }
2127ac8f1300SMatthias Ringwald                     break;
2128ac8f1300SMatthias Ringwald                 default:
2129ac8f1300SMatthias Ringwald                     break;
21303232a1c6SMatthias Ringwald             }
2131f2fa388dSMatthias Ringwald         }
21323232a1c6SMatthias Ringwald 
21333232a1c6SMatthias Ringwald         // check for unknown options
21343232a1c6SMatthias Ringwald         if (option_hint == 0 && (option_type == 0 || option_type >= 0x07)){
21353232a1c6SMatthias Ringwald             log_info("l2cap cid %u, unknown options", channel->local_cid);
21363232a1c6SMatthias Ringwald             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID);
21373232a1c6SMatthias Ringwald         }
21383232a1c6SMatthias Ringwald 
21393232a1c6SMatthias Ringwald         pos += length;
21403232a1c6SMatthias Ringwald     }
21413232a1c6SMatthias Ringwald #endif
21423232a1c6SMatthias Ringwald }
21433232a1c6SMatthias Ringwald 
2144fa8473a4Smatthias.ringwald static int l2cap_channel_ready_for_open(l2cap_channel_t *channel){
21459da54300S[email protected]     // log_info("l2cap_channel_ready_for_open 0x%02x", channel->state_var);
214673cf2b3dSmatthias.ringwald     if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP) == 0) return 0;
214773cf2b3dSmatthias.ringwald     if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP) == 0) return 0;
2148019f9b43SMatthias Ringwald     // addition check that fixes re-entrance issue causing l2cap event channel opened twice
2149019f9b43SMatthias Ringwald     if (channel->state == L2CAP_STATE_OPEN) return 0;
2150fa8473a4Smatthias.ringwald     return 1;
2151fa8473a4Smatthias.ringwald }
2152fa8473a4Smatthias.ringwald 
2153fa8473a4Smatthias.ringwald 
21547f02f414SMatthias Ringwald static void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){
21551e6aba47Smatthias.ringwald 
215600d93d79Smatthias.ringwald     uint8_t  code       = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
215700d93d79Smatthias.ringwald     uint8_t  identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
215838e5900eSmatthias.ringwald     uint16_t result = 0;
21591e6aba47Smatthias.ringwald 
21609da54300S[email protected]     log_info("L2CAP signaling handler code %u, state %u", code, channel->state);
2161b35f641cSmatthias.ringwald 
21629a011532Smatthias.ringwald     // handle DISCONNECT REQUESTS seperately
21639a011532Smatthias.ringwald     if (code == DISCONNECTION_REQUEST){
21649a011532Smatthias.ringwald         switch (channel->state){
2165fa8473a4Smatthias.ringwald             case L2CAP_STATE_CONFIG:
21669a011532Smatthias.ringwald             case L2CAP_STATE_OPEN:
21672b83fb7dSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
21689a011532Smatthias.ringwald             case L2CAP_STATE_WAIT_DISCONNECT:
21699a011532Smatthias.ringwald                 l2cap_handle_disconnect_request(channel, identifier);
21709a011532Smatthias.ringwald                 break;
21719a011532Smatthias.ringwald 
21729a011532Smatthias.ringwald             default:
21739a011532Smatthias.ringwald                 // ignore in other states
21749a011532Smatthias.ringwald                 break;
21759a011532Smatthias.ringwald         }
21769a011532Smatthias.ringwald         return;
21779a011532Smatthias.ringwald     }
21789a011532Smatthias.ringwald 
217956081214Smatthias.ringwald     // @STATEMACHINE(l2cap)
21801e6aba47Smatthias.ringwald     switch (channel->state) {
21811e6aba47Smatthias.ringwald 
21821e6aba47Smatthias.ringwald         case L2CAP_STATE_WAIT_CONNECT_RSP:
21831e6aba47Smatthias.ringwald             switch (code){
21841e6aba47Smatthias.ringwald                 case CONNECTION_RESPONSE:
21855932bd7cS[email protected]                     l2cap_stop_rtx(channel);
2186f8fbdce0SMatthias Ringwald                     result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
218738e5900eSmatthias.ringwald                     switch (result) {
218838e5900eSmatthias.ringwald                         case 0:
2189169f8b28Smatthias.ringwald                             // successful connection
2190f8fbdce0SMatthias Ringwald                             channel->remote_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
2191fa8473a4Smatthias.ringwald                             channel->state = L2CAP_STATE_CONFIG;
219228ca2b46S[email protected]                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
219338e5900eSmatthias.ringwald                             break;
219438e5900eSmatthias.ringwald                         case 1:
21955932bd7cS[email protected]                             // connection pending. get some coffee, but start the ERTX
21965932bd7cS[email protected]                             l2cap_start_ertx(channel);
219738e5900eSmatthias.ringwald                             break;
219838e5900eSmatthias.ringwald                         default:
2199eb920dbeSmatthias.ringwald                             // channel closed
2200eb920dbeSmatthias.ringwald                             channel->state = L2CAP_STATE_CLOSED;
2201f32b992eSmatthias.ringwald                             // map l2cap connection response result to BTstack status enumeration
220238e5900eSmatthias.ringwald                             l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result);
2203eb920dbeSmatthias.ringwald 
2204eb920dbeSmatthias.ringwald                             // drop link key if security block
2205eb920dbeSmatthias.ringwald                             if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){
220615a95bd5SMatthias Ringwald                                 gap_drop_link_key_for_bd_addr(channel->address);
2207eb920dbeSmatthias.ringwald                             }
2208eb920dbeSmatthias.ringwald 
2209eb920dbeSmatthias.ringwald                             // discard channel
2210665d90f2SMatthias Ringwald                             btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
2211d3a9df87Smatthias.ringwald                             btstack_memory_l2cap_channel_free(channel);
221238e5900eSmatthias.ringwald                             break;
22131e6aba47Smatthias.ringwald                     }
22141e6aba47Smatthias.ringwald                     break;
221538e5900eSmatthias.ringwald 
221638e5900eSmatthias.ringwald                 default:
22171e6aba47Smatthias.ringwald                     //@TODO: implement other signaling packets
221838e5900eSmatthias.ringwald                     break;
22191e6aba47Smatthias.ringwald             }
22201e6aba47Smatthias.ringwald             break;
22211e6aba47Smatthias.ringwald 
2222fa8473a4Smatthias.ringwald         case L2CAP_STATE_CONFIG:
2223f8fbdce0SMatthias Ringwald             result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
2224ae280e73Smatthias.ringwald             switch (code) {
2225ae280e73Smatthias.ringwald                 case CONFIGURE_REQUEST:
222628ca2b46S[email protected]                     channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
2227ae280e73Smatthias.ringwald                     l2cap_signaling_handle_configure_request(channel, command);
222863a7246aSmatthias.ringwald                     if (!(channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT)){
222963a7246aSmatthias.ringwald                         // only done if continuation not set
223063a7246aSmatthias.ringwald                         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
223163a7246aSmatthias.ringwald                     }
2232ae280e73Smatthias.ringwald                     break;
22331e6aba47Smatthias.ringwald                 case CONFIGURE_RESPONSE:
22345932bd7cS[email protected]                     l2cap_stop_rtx(channel);
2235f2fa388dSMatthias Ringwald                     l2cap_signaling_handle_configure_response(channel, result, command);
22365932bd7cS[email protected]                     switch (result){
22375932bd7cS[email protected]                         case 0: // success
22385932bd7cS[email protected]                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
22395932bd7cS[email protected]                             break;
22405932bd7cS[email protected]                         case 4: // pending
22415932bd7cS[email protected]                             l2cap_start_ertx(channel);
22425932bd7cS[email protected]                             break;
22435932bd7cS[email protected]                         default:
2244a32d6a03SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
2245a32d6a03SMatthias Ringwald                             if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION && channel->ertm_mandatory){
2246a32d6a03SMatthias Ringwald                                 // remote does not offer ertm but it's required
2247a32d6a03SMatthias Ringwald                                 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
2248a32d6a03SMatthias Ringwald                                 break;
2249a32d6a03SMatthias Ringwald                             }
2250a32d6a03SMatthias Ringwald #endif
2251fe9d8984S[email protected]                             // retry on negative result
2252fe9d8984S[email protected]                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
2253fe9d8984S[email protected]                             break;
2254fe9d8984S[email protected]                     }
22555a67bd4aSmatthias.ringwald                     break;
22565a67bd4aSmatthias.ringwald                 default:
22575a67bd4aSmatthias.ringwald                     break;
22581e6aba47Smatthias.ringwald             }
2259fa8473a4Smatthias.ringwald             if (l2cap_channel_ready_for_open(channel)){
2260fa8473a4Smatthias.ringwald                 // for open:
22615a67bd4aSmatthias.ringwald                 channel->state = L2CAP_STATE_OPEN;
2262fa8473a4Smatthias.ringwald                 l2cap_emit_channel_opened(channel, 0);
2263c8e4258aSmatthias.ringwald             }
2264c8e4258aSmatthias.ringwald             break;
2265f62db1e3Smatthias.ringwald 
2266f62db1e3Smatthias.ringwald         case L2CAP_STATE_WAIT_DISCONNECT:
2267f62db1e3Smatthias.ringwald             switch (code) {
2268f62db1e3Smatthias.ringwald                 case DISCONNECTION_RESPONSE:
226927a923d0Smatthias.ringwald                     l2cap_finialize_channel_close(channel);
227027a923d0Smatthias.ringwald                     break;
22715a67bd4aSmatthias.ringwald                 default:
22725a67bd4aSmatthias.ringwald                     //@TODO: implement other signaling packets
22735a67bd4aSmatthias.ringwald                     break;
227427a923d0Smatthias.ringwald             }
227527a923d0Smatthias.ringwald             break;
227684836b65Smatthias.ringwald 
227784836b65Smatthias.ringwald         case L2CAP_STATE_CLOSED:
227884836b65Smatthias.ringwald             // @TODO handle incoming requests
227984836b65Smatthias.ringwald             break;
228084836b65Smatthias.ringwald 
228184836b65Smatthias.ringwald         case L2CAP_STATE_OPEN:
228284836b65Smatthias.ringwald             //@TODO: implement other signaling packets, e.g. re-configure
228384836b65Smatthias.ringwald             break;
228410642e45Smatthias.ringwald         default:
228510642e45Smatthias.ringwald             break;
228627a923d0Smatthias.ringwald     }
22879da54300S[email protected]     // log_info("new state %u", channel->state);
228827a923d0Smatthias.ringwald }
228927a923d0Smatthias.ringwald 
229000d93d79Smatthias.ringwald 
22917f02f414SMatthias Ringwald static void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * command){
229200d93d79Smatthias.ringwald 
22931b9cb13dSMatthias Ringwald     btstack_linked_list_iterator_t it;
22941b9cb13dSMatthias Ringwald 
229500d93d79Smatthias.ringwald     // get code, signalind identifier and command len
229600d93d79Smatthias.ringwald     uint8_t code   = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
229700d93d79Smatthias.ringwald     uint8_t sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
229800d93d79Smatthias.ringwald 
22991b9cb13dSMatthias Ringwald     // not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_RESPONSE
23001b9cb13dSMatthias Ringwald     if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_RESPONSE){
2301e74c5f58SMatthias Ringwald         l2cap_register_signaling_response(handle, COMMAND_REJECT, sig_id, 0, L2CAP_REJ_CMD_UNKNOWN);
230200d93d79Smatthias.ringwald         return;
230300d93d79Smatthias.ringwald     }
230400d93d79Smatthias.ringwald 
230500d93d79Smatthias.ringwald     // general commands without an assigned channel
230600d93d79Smatthias.ringwald     switch(code) {
230700d93d79Smatthias.ringwald 
230800d93d79Smatthias.ringwald         case CONNECTION_REQUEST: {
2309f8fbdce0SMatthias Ringwald             uint16_t psm =        little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
2310f8fbdce0SMatthias Ringwald             uint16_t source_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
231100d93d79Smatthias.ringwald             l2cap_handle_connection_request(handle, sig_id, psm, source_cid);
23122b83fb7dSmatthias.ringwald             return;
231300d93d79Smatthias.ringwald         }
231400d93d79Smatthias.ringwald 
23152b360848Smatthias.ringwald         case ECHO_REQUEST:
2316e74c5f58SMatthias Ringwald             l2cap_register_signaling_response(handle, code, sig_id, 0, 0);
23172b83fb7dSmatthias.ringwald             return;
231800d93d79Smatthias.ringwald 
231900d93d79Smatthias.ringwald         case INFORMATION_REQUEST: {
2320f8fbdce0SMatthias Ringwald             uint16_t infoType = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
2321e74c5f58SMatthias Ringwald             l2cap_register_signaling_response(handle, code, sig_id, 0, infoType);
23222b83fb7dSmatthias.ringwald             return;
232300d93d79Smatthias.ringwald         }
232400d93d79Smatthias.ringwald 
23251b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
23261b9cb13dSMatthias Ringwald         case INFORMATION_RESPONSE: {
23271b9cb13dSMatthias Ringwald             hci_connection_t * connection = hci_connection_for_handle(handle);
23281b9cb13dSMatthias Ringwald             if (!connection) return;
23291b9cb13dSMatthias Ringwald             uint16_t info_type = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
23301b9cb13dSMatthias Ringwald             uint16_t result =  little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
23311b9cb13dSMatthias Ringwald             if (result != 0) return;
2332543b84e4SMatthias Ringwald             if (info_type != 0x02) return;
23331b9cb13dSMatthias Ringwald             connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_DONE;
23341b9cb13dSMatthias Ringwald             connection->l2cap_state.extended_feature_mask = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
2335543b84e4SMatthias Ringwald             log_info("extended features mask 0x%02x", connection->l2cap_state.extended_feature_mask);
23361b9cb13dSMatthias Ringwald             // trigger connection request
23371b9cb13dSMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
23381b9cb13dSMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
23391b9cb13dSMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2340543b84e4SMatthias Ringwald                 if (channel->con_handle != handle) continue;
2341543b84e4SMatthias Ringwald                 // bail if ERTM was requested but is not supported
2342543b84e4SMatthias Ringwald                 if ((channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION) && ((connection->l2cap_state.extended_feature_mask & 0x08) == 0)){
2343f073f086SMatthias Ringwald                     if (channel->ertm_mandatory){
2344543b84e4SMatthias Ringwald                         // channel closed
2345543b84e4SMatthias Ringwald                         channel->state = L2CAP_STATE_CLOSED;
2346543b84e4SMatthias Ringwald                         // map l2cap connection response result to BTstack status enumeration
2347543b84e4SMatthias Ringwald                         l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_ERTM_NOT_SUPPORTD);
2348543b84e4SMatthias Ringwald                         // discard channel
2349543b84e4SMatthias Ringwald                         btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
2350543b84e4SMatthias Ringwald                         btstack_memory_l2cap_channel_free(channel);
2351543b84e4SMatthias Ringwald                         continue;
2352f073f086SMatthias Ringwald                     } else {
2353f073f086SMatthias Ringwald                         // fallback to Basic mode
2354f073f086SMatthias Ringwald                         channel->mode = L2CAP_CHANNEL_MODE_BASIC;
2355f073f086SMatthias Ringwald                     }
2356543b84e4SMatthias Ringwald                 }
2357543b84e4SMatthias Ringwald                 // start connecting
23581b9cb13dSMatthias Ringwald                 if (channel->state == L2CAP_STATE_WAIT_OUTGOING_EXTENDED_FEATURES){
23591b9cb13dSMatthias Ringwald                     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
23601b9cb13dSMatthias Ringwald                 }
236152606043SMatthias Ringwald                 // respond to connection request
236252606043SMatthias Ringwald                 if (channel->state == L2CAP_STATE_WAIT_INCOMING_EXTENDED_FEATURES){
236352606043SMatthias Ringwald                     channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
236452606043SMatthias Ringwald                     l2cap_emit_incoming_connection(channel);
236552606043SMatthias Ringwald                 }
23661b9cb13dSMatthias Ringwald             }
23671b9cb13dSMatthias Ringwald             return;
23681b9cb13dSMatthias Ringwald         }
23691b9cb13dSMatthias Ringwald #endif
23701b9cb13dSMatthias Ringwald 
237100d93d79Smatthias.ringwald         default:
237200d93d79Smatthias.ringwald             break;
237300d93d79Smatthias.ringwald     }
237400d93d79Smatthias.ringwald 
237500d93d79Smatthias.ringwald 
237600d93d79Smatthias.ringwald     // Get potential destination CID
2377f8fbdce0SMatthias Ringwald     uint16_t dest_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
237800d93d79Smatthias.ringwald 
237900d93d79Smatthias.ringwald     // Find channel for this sig_id and connection handle
2380665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
2381665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2382665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2383fc64f94aSMatthias Ringwald         if (channel->con_handle != handle) continue;
238400d93d79Smatthias.ringwald         if (code & 1) {
2385b1988dceSmatthias.ringwald             // match odd commands (responses) by previous signaling identifier
2386b1988dceSmatthias.ringwald             if (channel->local_sig_id == sig_id) {
238700d93d79Smatthias.ringwald                 l2cap_signaling_handler_channel(channel, command);
23884e32727eSmatthias.ringwald                 break;
238900d93d79Smatthias.ringwald             }
239000d93d79Smatthias.ringwald         } else {
2391b1988dceSmatthias.ringwald             // match even commands (requests) by local channel id
239200d93d79Smatthias.ringwald             if (channel->local_cid == dest_cid) {
239300d93d79Smatthias.ringwald                 l2cap_signaling_handler_channel(channel, command);
23944e32727eSmatthias.ringwald                 break;
239500d93d79Smatthias.ringwald             }
239600d93d79Smatthias.ringwald         }
239700d93d79Smatthias.ringwald     }
239800d93d79Smatthias.ringwald }
239909e9d05bSMatthias Ringwald #endif
240000d93d79Smatthias.ringwald 
2401e7d0c9aaSMatthias Ringwald #ifdef ENABLE_BLE
240209e9d05bSMatthias Ringwald 
240309e9d05bSMatthias Ringwald static void l2cap_emit_connection_parameter_update_response(hci_con_handle_t con_handle, uint16_t result){
240409e9d05bSMatthias Ringwald     uint8_t event[6];
240509e9d05bSMatthias Ringwald     event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE;
240609e9d05bSMatthias Ringwald     event[1] = 4;
240709e9d05bSMatthias Ringwald     little_endian_store_16(event, 2, con_handle);
240809e9d05bSMatthias Ringwald     little_endian_store_16(event, 4, result);
240909e9d05bSMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
241009e9d05bSMatthias Ringwald     if (!l2cap_event_packet_handler) return;
241109e9d05bSMatthias Ringwald     (*l2cap_event_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
241209e9d05bSMatthias Ringwald }
241309e9d05bSMatthias Ringwald 
2414c48b2a2cSMatthias Ringwald // @returns valid
2415c48b2a2cSMatthias Ringwald static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t * command, uint8_t sig_id){
2416e7d0c9aaSMatthias Ringwald     hci_connection_t * connection;
2417c48b2a2cSMatthias Ringwald     uint16_t result;
2418c48b2a2cSMatthias Ringwald     uint8_t  event[10];
241983fd9c76SMatthias Ringwald 
2420cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2421a3dc965aSMatthias Ringwald     btstack_linked_list_iterator_t it;
2422a3dc965aSMatthias Ringwald     l2cap_channel_t * channel;
2423a3dc965aSMatthias Ringwald     uint16_t local_cid;
242483fd9c76SMatthias Ringwald     uint16_t le_psm;
242563f0ac45SMatthias Ringwald     uint16_t new_credits;
242663f0ac45SMatthias Ringwald     uint16_t credits_before;
2427e7d0c9aaSMatthias Ringwald     l2cap_service_t * service;
242811cae19eSMilanka Ringwald     uint16_t source_cid;
242983fd9c76SMatthias Ringwald #endif
243000d93d79Smatthias.ringwald 
24311b8b8d05SMatthias Ringwald     uint8_t code   = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
243223017473SMatthias Ringwald     log_info("l2cap_le_signaling_handler_dispatch: command 0x%02x, sig id %u", code, sig_id);
24331b8b8d05SMatthias Ringwald 
24341b8b8d05SMatthias Ringwald     switch (code){
243500d93d79Smatthias.ringwald 
2436c48b2a2cSMatthias Ringwald         case CONNECTION_PARAMETER_UPDATE_RESPONSE:
2437c48b2a2cSMatthias Ringwald             result = little_endian_read_16(command, 4);
2438ccf076adS[email protected]             l2cap_emit_connection_parameter_update_response(handle, result);
2439ccf076adS[email protected]             break;
2440da886c03S[email protected] 
2441c48b2a2cSMatthias Ringwald         case CONNECTION_PARAMETER_UPDATE_REQUEST:
2442e7d0c9aaSMatthias Ringwald             connection = hci_connection_for_handle(handle);
2443da886c03S[email protected]             if (connection){
24446d91fb6cSMatthias Ringwald                 if (connection->role != HCI_ROLE_MASTER){
24456d91fb6cSMatthias Ringwald                     // reject command without notifying upper layer when not in master role
2446c48b2a2cSMatthias Ringwald                     return 0;
24476d91fb6cSMatthias Ringwald                 }
2448da886c03S[email protected]                 int update_parameter = 1;
2449a4c06b28SMatthias Ringwald                 le_connection_parameter_range_t existing_range;
24504ced4e8cSMatthias Ringwald                 gap_get_connection_parameter_range(&existing_range);
2451c48b2a2cSMatthias Ringwald                 uint16_t le_conn_interval_min = little_endian_read_16(command,8);
2452c48b2a2cSMatthias Ringwald                 uint16_t le_conn_interval_max = little_endian_read_16(command,10);
2453c48b2a2cSMatthias Ringwald                 uint16_t le_conn_latency = little_endian_read_16(command,12);
2454c48b2a2cSMatthias Ringwald                 uint16_t le_supervision_timeout = little_endian_read_16(command,14);
2455da886c03S[email protected] 
2456da886c03S[email protected]                 if (le_conn_interval_min < existing_range.le_conn_interval_min) update_parameter = 0;
2457da886c03S[email protected]                 if (le_conn_interval_max > existing_range.le_conn_interval_max) update_parameter = 0;
2458da886c03S[email protected] 
2459da886c03S[email protected]                 if (le_conn_latency < existing_range.le_conn_latency_min) update_parameter = 0;
2460da886c03S[email protected]                 if (le_conn_latency > existing_range.le_conn_latency_max) update_parameter = 0;
2461da886c03S[email protected] 
2462da886c03S[email protected]                 if (le_supervision_timeout < existing_range.le_supervision_timeout_min) update_parameter = 0;
2463da886c03S[email protected]                 if (le_supervision_timeout > existing_range.le_supervision_timeout_max) update_parameter = 0;
2464da886c03S[email protected] 
2465da886c03S[email protected]                 if (update_parameter){
2466da886c03S[email protected]                     connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_SEND_RESPONSE;
2467da886c03S[email protected]                     connection->le_conn_interval_min = le_conn_interval_min;
2468da886c03S[email protected]                     connection->le_conn_interval_max = le_conn_interval_max;
2469da886c03S[email protected]                     connection->le_conn_latency = le_conn_latency;
2470da886c03S[email protected]                     connection->le_supervision_timeout = le_supervision_timeout;
2471da886c03S[email protected]                 } else {
2472da886c03S[email protected]                     connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_DENY;
2473da886c03S[email protected]                 }
2474c48b2a2cSMatthias Ringwald                 connection->le_con_param_update_identifier = sig_id;
2475da886c03S[email protected]             }
2476da886c03S[email protected] 
247733c40538SMatthias Ringwald             if (!l2cap_event_packet_handler) break;
2478c48b2a2cSMatthias Ringwald 
2479c48b2a2cSMatthias Ringwald             event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST;
2480c48b2a2cSMatthias Ringwald             event[1] = 8;
2481c48b2a2cSMatthias Ringwald             memcpy(&event[2], &command[4], 8);
2482c48b2a2cSMatthias Ringwald             hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
248333c40538SMatthias Ringwald             (*l2cap_event_packet_handler)( HCI_EVENT_PACKET, 0, event, sizeof(event));
2484ccf076adS[email protected]             break;
2485c48b2a2cSMatthias Ringwald 
2486a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2487a3dc965aSMatthias Ringwald 
248863f0ac45SMatthias Ringwald         case COMMAND_REJECT:
248963f0ac45SMatthias Ringwald             // Find channel for this sig_id and connection handle
249063f0ac45SMatthias Ringwald             channel = NULL;
249163f0ac45SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
249263f0ac45SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
249363f0ac45SMatthias Ringwald                 l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
249463f0ac45SMatthias Ringwald                 if (a_channel->con_handle   != handle) continue;
249563f0ac45SMatthias Ringwald                 if (a_channel->local_sig_id != sig_id) continue;
249663f0ac45SMatthias Ringwald                 channel = a_channel;
249763f0ac45SMatthias Ringwald                 break;
249863f0ac45SMatthias Ringwald             }
249963f0ac45SMatthias Ringwald             if (!channel) break;
250063f0ac45SMatthias Ringwald 
250163f0ac45SMatthias Ringwald             // if received while waiting for le connection response, assume legacy device
250263f0ac45SMatthias Ringwald             if (channel->state == L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE){
250363f0ac45SMatthias Ringwald                 channel->state = L2CAP_STATE_CLOSED;
250463f0ac45SMatthias Ringwald                 // no official value for this, use: Connection refused – LE_PSM not supported - 0x0002
250544276248SMatthias Ringwald                 l2cap_emit_le_channel_opened(channel, 0x0002);
250663f0ac45SMatthias Ringwald 
250763f0ac45SMatthias Ringwald                 // discard channel
250863f0ac45SMatthias Ringwald                 btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel);
250963f0ac45SMatthias Ringwald                 btstack_memory_l2cap_channel_free(channel);
251063f0ac45SMatthias Ringwald                 break;
251163f0ac45SMatthias Ringwald             }
251263f0ac45SMatthias Ringwald             break;
251363f0ac45SMatthias Ringwald 
2514e7d0c9aaSMatthias Ringwald         case LE_CREDIT_BASED_CONNECTION_REQUEST:
2515e7d0c9aaSMatthias Ringwald 
2516e7d0c9aaSMatthias Ringwald             // get hci connection, bail if not found (must not happen)
2517e7d0c9aaSMatthias Ringwald             connection = hci_connection_for_handle(handle);
2518e7d0c9aaSMatthias Ringwald             if (!connection) return 0;
2519e7d0c9aaSMatthias Ringwald 
2520e7d0c9aaSMatthias Ringwald             // check if service registered
2521e7d0c9aaSMatthias Ringwald             le_psm  = little_endian_read_16(command, 4);
2522e7d0c9aaSMatthias Ringwald             service = l2cap_le_get_service(le_psm);
252311cae19eSMilanka Ringwald             source_cid = little_endian_read_16(command, 6);
2524e7d0c9aaSMatthias Ringwald 
2525e7d0c9aaSMatthias Ringwald             if (service){
2526e7d0c9aaSMatthias Ringwald                 if (source_cid < 0x40){
2527e7d0c9aaSMatthias Ringwald                     // 0x0009 Connection refused - Invalid Source CID
2528e74c5f58SMatthias Ringwald                     l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0009);
2529e7d0c9aaSMatthias Ringwald                     return 1;
2530e7d0c9aaSMatthias Ringwald                 }
2531e7d0c9aaSMatthias Ringwald 
2532e7d0c9aaSMatthias Ringwald                 // go through list of channels for this ACL connection and check if we get a match
2533e7d0c9aaSMatthias Ringwald                 btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
2534e7d0c9aaSMatthias Ringwald                 while (btstack_linked_list_iterator_has_next(&it)){
25351b8b8d05SMatthias Ringwald                     l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
25361b8b8d05SMatthias Ringwald                     if (a_channel->con_handle != handle) continue;
25371b8b8d05SMatthias Ringwald                     if (a_channel->remote_cid != source_cid) continue;
2538e7d0c9aaSMatthias Ringwald                     // 0x000a Connection refused - Source CID already allocated
2539e74c5f58SMatthias Ringwald                     l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x000a);
2540e7d0c9aaSMatthias Ringwald                     return 1;
2541e7d0c9aaSMatthias Ringwald                 }
2542e7d0c9aaSMatthias Ringwald 
254383fd9c76SMatthias Ringwald                 // security: check encryption
254483fd9c76SMatthias Ringwald                 if (service->required_security_level >= LEVEL_2){
254583fd9c76SMatthias Ringwald                     if (sm_encryption_key_size(handle) == 0){
254683fd9c76SMatthias Ringwald                         // 0x0008 Connection refused - insufficient encryption
2547e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0008);
254883fd9c76SMatthias Ringwald                         return 1;
254983fd9c76SMatthias Ringwald                     }
255083fd9c76SMatthias Ringwald                     // anything less than 16 byte key size is insufficient
255183fd9c76SMatthias Ringwald                     if (sm_encryption_key_size(handle) < 16){
255283fd9c76SMatthias Ringwald                         // 0x0007 Connection refused – insufficient encryption key size
2553e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0007);
255483fd9c76SMatthias Ringwald                         return 1;
255583fd9c76SMatthias Ringwald                     }
255683fd9c76SMatthias Ringwald                 }
255783fd9c76SMatthias Ringwald 
255883fd9c76SMatthias Ringwald                 // security: check authencation
255983fd9c76SMatthias Ringwald                 if (service->required_security_level >= LEVEL_3){
256083fd9c76SMatthias Ringwald                     if (!sm_authenticated(handle)){
256183fd9c76SMatthias Ringwald                         // 0x0005 Connection refused – insufficient authentication
2562e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0005);
256383fd9c76SMatthias Ringwald                         return 1;
256483fd9c76SMatthias Ringwald                     }
256583fd9c76SMatthias Ringwald                 }
256683fd9c76SMatthias Ringwald 
256783fd9c76SMatthias Ringwald                 // security: check authorization
256883fd9c76SMatthias Ringwald                 if (service->required_security_level >= LEVEL_4){
256983fd9c76SMatthias Ringwald                     if (sm_authorization_state(handle) != AUTHORIZATION_GRANTED){
257083fd9c76SMatthias Ringwald                         // 0x0006 Connection refused – insufficient authorization
2571e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0006);
257283fd9c76SMatthias Ringwald                         return 1;
257383fd9c76SMatthias Ringwald                     }
257483fd9c76SMatthias Ringwald                 }
2575e7d0c9aaSMatthias Ringwald 
2576e7d0c9aaSMatthias Ringwald                 // allocate channel
25771b8b8d05SMatthias Ringwald                 channel = l2cap_create_channel_entry(service->packet_handler, connection->address,
2578e7d0c9aaSMatthias Ringwald                     BD_ADDR_TYPE_LE_RANDOM, le_psm, service->mtu, service->required_security_level);
2579e7d0c9aaSMatthias Ringwald                 if (!channel){
2580e7d0c9aaSMatthias Ringwald                     // 0x0004 Connection refused – no resources available
2581e74c5f58SMatthias Ringwald                     l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0004);
2582e7d0c9aaSMatthias Ringwald                     return 1;
2583e7d0c9aaSMatthias Ringwald                 }
2584e7d0c9aaSMatthias Ringwald 
2585e7d0c9aaSMatthias Ringwald                 channel->con_handle = handle;
2586e7d0c9aaSMatthias Ringwald                 channel->remote_cid = source_cid;
2587e7d0c9aaSMatthias Ringwald                 channel->remote_sig_id = sig_id;
25887f107edaSMatthias Ringwald                 channel->remote_mtu = little_endian_read_16(command, 8);
25897f107edaSMatthias Ringwald                 channel->remote_mps = little_endian_read_16(command, 10);
25907f107edaSMatthias Ringwald                 channel->credits_outgoing = little_endian_read_16(command, 12);
2591e7d0c9aaSMatthias Ringwald 
2592e7d0c9aaSMatthias Ringwald                 // set initial state
2593e7d0c9aaSMatthias Ringwald                 channel->state      = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
2594c99bb618SMatthias Ringwald                 channel->state_var |= L2CAP_CHANNEL_STATE_VAR_INCOMING;
2595e7d0c9aaSMatthias Ringwald 
2596e7d0c9aaSMatthias Ringwald                 // add to connections list
2597e7d0c9aaSMatthias Ringwald                 btstack_linked_list_add(&l2cap_le_channels, (btstack_linked_item_t *) channel);
2598e7d0c9aaSMatthias Ringwald 
2599e7d0c9aaSMatthias Ringwald                 // post connection request event
260044276248SMatthias Ringwald                 l2cap_emit_le_incoming_connection(channel);
2601e7d0c9aaSMatthias Ringwald 
2602e7d0c9aaSMatthias Ringwald             } else {
2603e7d0c9aaSMatthias Ringwald                 // Connection refused – LE_PSM not supported
2604e74c5f58SMatthias Ringwald                 l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0002);
2605e7d0c9aaSMatthias Ringwald             }
2606e7d0c9aaSMatthias Ringwald             break;
26071b8b8d05SMatthias Ringwald 
26081b8b8d05SMatthias Ringwald         case LE_CREDIT_BASED_CONNECTION_RESPONSE:
26091b8b8d05SMatthias Ringwald             // Find channel for this sig_id and connection handle
26101b8b8d05SMatthias Ringwald             channel = NULL;
26111b8b8d05SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
26121b8b8d05SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
26131b8b8d05SMatthias Ringwald                 l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
26141b8b8d05SMatthias Ringwald                 if (a_channel->con_handle   != handle) continue;
26151b8b8d05SMatthias Ringwald                 if (a_channel->local_sig_id != sig_id) continue;
26161b8b8d05SMatthias Ringwald                 channel = a_channel;
26171b8b8d05SMatthias Ringwald                 break;
26181b8b8d05SMatthias Ringwald             }
26191b8b8d05SMatthias Ringwald             if (!channel) break;
26201b8b8d05SMatthias Ringwald 
26211b8b8d05SMatthias Ringwald             // cid + 0
26221b8b8d05SMatthias Ringwald             result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+8);
26231b8b8d05SMatthias Ringwald             if (result){
26241b8b8d05SMatthias Ringwald                 channel->state = L2CAP_STATE_CLOSED;
26251b8b8d05SMatthias Ringwald                 // map l2cap connection response result to BTstack status enumeration
262644276248SMatthias Ringwald                 l2cap_emit_le_channel_opened(channel, result);
26271b8b8d05SMatthias Ringwald 
26281b8b8d05SMatthias Ringwald                 // discard channel
262963f0ac45SMatthias Ringwald                 btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel);
26301b8b8d05SMatthias Ringwald                 btstack_memory_l2cap_channel_free(channel);
26311b8b8d05SMatthias Ringwald                 break;
26321b8b8d05SMatthias Ringwald             }
26331b8b8d05SMatthias Ringwald 
26341b8b8d05SMatthias Ringwald             // success
26351b8b8d05SMatthias Ringwald             channel->remote_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0);
26361b8b8d05SMatthias Ringwald             channel->remote_mtu = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 2);
26371b8b8d05SMatthias Ringwald             channel->remote_mps = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 4);
26381b8b8d05SMatthias Ringwald             channel->credits_outgoing = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 6);
26391b8b8d05SMatthias Ringwald             channel->state = L2CAP_STATE_OPEN;
264044276248SMatthias Ringwald             l2cap_emit_le_channel_opened(channel, result);
26411b8b8d05SMatthias Ringwald             break;
26421b8b8d05SMatthias Ringwald 
264385aeef60SMatthias Ringwald         case LE_FLOW_CONTROL_CREDIT:
264485aeef60SMatthias Ringwald             // find channel
264585aeef60SMatthias Ringwald             local_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0);
264685aeef60SMatthias Ringwald             channel = l2cap_le_get_channel_for_local_cid(local_cid);
264763f0ac45SMatthias Ringwald             if (!channel) {
264863f0ac45SMatthias Ringwald                 log_error("l2cap: no channel for cid 0x%02x", local_cid);
264963f0ac45SMatthias Ringwald                 break;
265063f0ac45SMatthias Ringwald             }
265163f0ac45SMatthias Ringwald             new_credits = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 2);
265263f0ac45SMatthias Ringwald             credits_before = channel->credits_outgoing;
265363f0ac45SMatthias Ringwald             channel->credits_outgoing += new_credits;
265463f0ac45SMatthias Ringwald             // check for credit overrun
265563f0ac45SMatthias Ringwald             if (credits_before > channel->credits_outgoing){
265663f0ac45SMatthias Ringwald                 log_error("l2cap: new credits caused overrrun for cid 0x%02x, disconnecting", local_cid);
265763f0ac45SMatthias Ringwald                 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
265863f0ac45SMatthias Ringwald                 break;
265963f0ac45SMatthias Ringwald             }
266063f0ac45SMatthias Ringwald             log_info("l2cap: %u credits for 0x%02x, now %u", new_credits, local_cid, channel->credits_outgoing);
266185aeef60SMatthias Ringwald             break;
266285aeef60SMatthias Ringwald 
2663828a7f7aSMatthias Ringwald         case DISCONNECTION_REQUEST:
2664828a7f7aSMatthias Ringwald             // find channel
2665828a7f7aSMatthias Ringwald             local_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0);
2666828a7f7aSMatthias Ringwald             channel = l2cap_le_get_channel_for_local_cid(local_cid);
266763f34e00SMatthias Ringwald             if (!channel) {
266863f34e00SMatthias Ringwald                 log_error("l2cap: no channel for cid 0x%02x", local_cid);
266963f34e00SMatthias Ringwald                 break;
267063f34e00SMatthias Ringwald             }
2671828a7f7aSMatthias Ringwald             channel->remote_sig_id = sig_id;
2672828a7f7aSMatthias Ringwald             channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
2673828a7f7aSMatthias Ringwald             break;
2674828a7f7aSMatthias Ringwald 
2675a3dc965aSMatthias Ringwald #endif
2676a3dc965aSMatthias Ringwald 
267763f0ac45SMatthias Ringwald         case DISCONNECTION_RESPONSE:
267863f0ac45SMatthias Ringwald             break;
267963f0ac45SMatthias Ringwald 
2680c48b2a2cSMatthias Ringwald         default:
2681c48b2a2cSMatthias Ringwald             // command unknown -> reject command
2682c48b2a2cSMatthias Ringwald             return 0;
2683ccf076adS[email protected]     }
2684c48b2a2cSMatthias Ringwald     return 1;
2685c48b2a2cSMatthias Ringwald }
2686e7d0c9aaSMatthias Ringwald #endif
2687c48b2a2cSMatthias Ringwald 
2688d48432d4SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
268970734707SMatthias Ringwald 
269070734707SMatthias Ringwald // @param delta number of frames in the future, >= 1
269170734707SMatthias Ringwald static void l2cap_ertm_handle_out_of_sequence_sdu(l2cap_channel_t * l2cap_channel, l2cap_segmentation_and_reassembly_t sar, int delta, uint8_t * payload, uint16_t size){
269270734707SMatthias Ringwald     log_info("Store SDU with delta %u", delta);
269370734707SMatthias Ringwald     // get rx state for packet to store
269470734707SMatthias Ringwald     int index = l2cap_channel->rx_store_index + delta - 1;
269570734707SMatthias Ringwald     if (index > l2cap_channel->num_rx_buffers){
269670734707SMatthias Ringwald         index -= l2cap_channel->num_rx_buffers;
269770734707SMatthias Ringwald     }
269870734707SMatthias Ringwald     log_info("Index of packet to store %u", index);
269970734707SMatthias Ringwald     l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
270070734707SMatthias Ringwald     // check if buffer is free
270170734707SMatthias Ringwald     if (rx_state->valid){
270270734707SMatthias Ringwald         log_error("Packet buffer already used");
270370734707SMatthias Ringwald         return;
270470734707SMatthias Ringwald     }
270570734707SMatthias Ringwald     rx_state->valid = 1;
270670734707SMatthias Ringwald     rx_state->sar = sar;
270770734707SMatthias Ringwald     rx_state->len = size;
270870734707SMatthias Ringwald     uint8_t * rx_buffer = &l2cap_channel->rx_packets_data[index];
270970734707SMatthias Ringwald     memcpy(rx_buffer, payload, size);
271070734707SMatthias Ringwald }
271170734707SMatthias Ringwald 
2712e32be409SMatthias Ringwald static void l2cap_ertm_handle_in_sequence_sdu(l2cap_channel_t * l2cap_channel, l2cap_segmentation_and_reassembly_t sar, uint8_t * payload, uint16_t size){
2713d48432d4SMatthias Ringwald     switch (sar){
2714d48432d4SMatthias Ringwald         case L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU:
2715e32be409SMatthias Ringwald             // packet complete -> disapatch
2716e32be409SMatthias Ringwald             l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, payload, size);
2717d48432d4SMatthias Ringwald             break;
2718d48432d4SMatthias Ringwald         case L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU:
2719d48432d4SMatthias Ringwald             // TODO: check if reassembly started
2720e8e9809fSMatthias Ringwald             // TODO: check sdu_len against local mtu
2721e32be409SMatthias Ringwald             l2cap_channel->reassembly_sdu_length = little_endian_read_16(payload, 0);
2722e32be409SMatthias Ringwald             payload += 2;
2723e32be409SMatthias Ringwald             size    -= 2;
2724e32be409SMatthias Ringwald             memcpy(&l2cap_channel->reassembly_buffer[0], payload, size);
2725e32be409SMatthias Ringwald             l2cap_channel->reassembly_pos = size;
2726d48432d4SMatthias Ringwald             break;
2727d48432d4SMatthias Ringwald         case L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU:
2728e32be409SMatthias Ringwald             memcpy(&l2cap_channel->reassembly_buffer[l2cap_channel->reassembly_pos], payload, size);
2729e32be409SMatthias Ringwald             l2cap_channel->reassembly_pos += size;
2730e32be409SMatthias Ringwald             break;
2731e32be409SMatthias Ringwald         case L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU:
2732e32be409SMatthias Ringwald             memcpy(&l2cap_channel->reassembly_buffer[l2cap_channel->reassembly_pos], payload, size);
2733e32be409SMatthias Ringwald             l2cap_channel->reassembly_pos += size;
2734e32be409SMatthias Ringwald             // packet complete -> disapatch
2735e32be409SMatthias Ringwald             l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, l2cap_channel->reassembly_buffer, l2cap_channel->reassembly_pos);
2736e32be409SMatthias Ringwald             l2cap_channel->reassembly_pos = 0;
2737d48432d4SMatthias Ringwald             break;
2738d48432d4SMatthias Ringwald     }
2739d48432d4SMatthias Ringwald }
2740d48432d4SMatthias Ringwald #endif
2741d48432d4SMatthias Ringwald 
2742c48b2a2cSMatthias Ringwald static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size ){
27439ec2630cSMatthias Ringwald     UNUSED(packet_type);
27449ec2630cSMatthias Ringwald     UNUSED(channel);
2745c48b2a2cSMatthias Ringwald 
274609e9d05bSMatthias Ringwald     l2cap_channel_t * l2cap_channel;
2747f3963406SMatthias Ringwald     UNUSED(l2cap_channel);
274809e9d05bSMatthias Ringwald 
2749c48b2a2cSMatthias Ringwald     // Get Channel ID
2750c48b2a2cSMatthias Ringwald     uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
2751c48b2a2cSMatthias Ringwald     hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet);
2752c48b2a2cSMatthias Ringwald 
2753c48b2a2cSMatthias Ringwald     switch (channel_id) {
2754c48b2a2cSMatthias Ringwald 
275509e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
2756c48b2a2cSMatthias Ringwald         case L2CAP_CID_SIGNALING: {
2757c48b2a2cSMatthias Ringwald             uint16_t command_offset = 8;
2758c48b2a2cSMatthias Ringwald             while (command_offset < size) {
2759c48b2a2cSMatthias Ringwald                 // handle signaling commands
2760c48b2a2cSMatthias Ringwald                 l2cap_signaling_handler_dispatch(handle, &packet[command_offset]);
2761c48b2a2cSMatthias Ringwald 
2762c48b2a2cSMatthias Ringwald                 // increment command_offset
2763c48b2a2cSMatthias Ringwald                 command_offset += L2CAP_SIGNALING_COMMAND_DATA_OFFSET + little_endian_read_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
2764c48b2a2cSMatthias Ringwald             }
2765c48b2a2cSMatthias Ringwald             break;
2766c48b2a2cSMatthias Ringwald         }
276709e9d05bSMatthias Ringwald #endif
2768c48b2a2cSMatthias Ringwald 
2769e7d0c9aaSMatthias Ringwald #ifdef ENABLE_BLE
2770e7d0c9aaSMatthias Ringwald         case L2CAP_CID_SIGNALING_LE: {
2771e7d0c9aaSMatthias Ringwald             uint16_t sig_id = packet[COMPLETE_L2CAP_HEADER + 1];
2772e7d0c9aaSMatthias Ringwald             int      valid  = l2cap_le_signaling_handler_dispatch(handle, &packet[COMPLETE_L2CAP_HEADER], sig_id);
2773c48b2a2cSMatthias Ringwald             if (!valid){
2774e74c5f58SMatthias Ringwald                 l2cap_register_signaling_response(handle, COMMAND_REJECT_LE, sig_id, 0, L2CAP_REJ_CMD_UNKNOWN);
2775ccf076adS[email protected]             }
2776ccf076adS[email protected]             break;
2777e7d0c9aaSMatthias Ringwald         }
2778e7d0c9aaSMatthias Ringwald #endif
2779c48b2a2cSMatthias Ringwald 
2780c48b2a2cSMatthias Ringwald         case L2CAP_CID_ATTRIBUTE_PROTOCOL:
2781c48b2a2cSMatthias Ringwald             if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL].callback) {
2782c48b2a2cSMatthias Ringwald                 (*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_ATTRIBUTE_PROTOCOL].callback)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
2783ccf076adS[email protected]             }
2784c48b2a2cSMatthias Ringwald             break;
2785c48b2a2cSMatthias Ringwald 
2786c48b2a2cSMatthias Ringwald         case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
2787c48b2a2cSMatthias Ringwald             if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL].callback) {
2788c48b2a2cSMatthias Ringwald                 (*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_SECURITY_MANAGER_PROTOCOL].callback)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
2789c48b2a2cSMatthias Ringwald             }
2790c48b2a2cSMatthias Ringwald             break;
2791c48b2a2cSMatthias Ringwald 
2792c48b2a2cSMatthias Ringwald         case L2CAP_CID_CONNECTIONLESS_CHANNEL:
2793c48b2a2cSMatthias Ringwald             if (fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL].callback) {
2794c48b2a2cSMatthias Ringwald                 (*fixed_channels[L2CAP_FIXED_CHANNEL_TABLE_INDEX_CONNECTIONLESS_CHANNEL].callback)(UCD_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
2795c48b2a2cSMatthias Ringwald             }
2796c48b2a2cSMatthias Ringwald             break;
27971bbc0b23S[email protected] 
279809e9d05bSMatthias Ringwald         default:
279909e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
280000d93d79Smatthias.ringwald             // Find channel for this channel_id and connection handle
280164e11ca9SMatthias Ringwald             l2cap_channel = l2cap_get_channel_for_local_cid(channel_id);
2802d1fd2a88SMatthias Ringwald             if (l2cap_channel) {
280327e0774aSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
280427e0774aSMatthias Ringwald                 if (l2cap_channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
280527e0774aSMatthias Ringwald 
280627e0774aSMatthias Ringwald                     // verify FCS
280727e0774aSMatthias Ringwald                     uint16_t fcs_calculated = crc16_calc(&packet[4], size - (4+2));
280827e0774aSMatthias Ringwald                     uint16_t fcs_packet     = little_endian_read_16(packet, size-2);
280927e0774aSMatthias Ringwald                     log_info("Packet FCS 0x%04x, calculated FCS 0x%04x", fcs_packet, fcs_calculated);
281027e0774aSMatthias Ringwald                     if (fcs_calculated != fcs_packet){
281127e0774aSMatthias Ringwald                         log_error("FCS mismatch! Packet 0x%04x, calculated 0x%04x", fcs_packet, fcs_calculated);
281227e0774aSMatthias Ringwald                         // TODO: trigger retransmission or something like that
281327e0774aSMatthias Ringwald                         break;
281427e0774aSMatthias Ringwald                     }
281527e0774aSMatthias Ringwald 
281627e0774aSMatthias Ringwald                     // switch on packet type
281727e0774aSMatthias Ringwald                     uint16_t control = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER);
281838f62777SMatthias Ringwald                     uint8_t  req_seq = (control >> 8) & 0x3f;
28192bea1b8dSMatthias Ringwald                     int final = (control >> 7) & 0x01;
282027e0774aSMatthias Ringwald                     if (control & 1){
282127e0774aSMatthias Ringwald                         // S-Frame
282278cd8a22SMatthias Ringwald                         int poll  = (control >> 4) & 0x01;
2823bdbe2e49SMatthias Ringwald                         l2cap_supervisory_function_t s = (l2cap_supervisory_function_t) ((control >> 2) & 0x03);
28249ffcbce4SMatthias Ringwald                         log_info("Control: 0x%04x => Supervisory function %u, ReqSeq %02u", control, (int) s, req_seq);
28257b7901d8SMatthias Ringwald                         l2cap_ertm_tx_packet_state_t * tx_state;
2826bdbe2e49SMatthias Ringwald                         switch (s){
2827bdbe2e49SMatthias Ringwald                             case L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY:
28289ffcbce4SMatthias Ringwald                                 log_info("L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY");
28292a424812SMatthias Ringwald                                 l2cap_ertm_handle_req_seq(l2cap_channel, req_seq);
28303233d8abSMatthias Ringwald                                 if (poll && final){
28313233d8abSMatthias Ringwald                                     // S-frames shall not be transmitted with both the F-bit and the P-bit set to 1 at the same time.
28323233d8abSMatthias Ringwald                                     log_error("P=F=1 in S-Frame");
28333233d8abSMatthias Ringwald                                     break;
28343233d8abSMatthias Ringwald                                 }
283578cd8a22SMatthias Ringwald                                 if (poll){
2836f85ade6bSMatthias Ringwald                                     // check if we did request selective retransmission before <==> we have stored SDU segments
2837f85ade6bSMatthias Ringwald                                     int i;
2838f85ade6bSMatthias Ringwald                                     int num_stored_out_of_order_packets = 0;
2839f85ade6bSMatthias Ringwald                                     for (i=0;i<l2cap_channel->num_rx_buffers;i++){
2840f85ade6bSMatthias Ringwald                                         int index = l2cap_channel->rx_store_index + i;
2841f85ade6bSMatthias Ringwald                                         if (index >= l2cap_channel->num_rx_buffers){
2842f85ade6bSMatthias Ringwald                                             index -= l2cap_channel->num_rx_buffers;
2843f85ade6bSMatthias Ringwald                                         }
2844f85ade6bSMatthias Ringwald                                         l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
2845f85ade6bSMatthias Ringwald                                         if (!rx_state->valid) continue;
2846f85ade6bSMatthias Ringwald                                         num_stored_out_of_order_packets++;
2847f85ade6bSMatthias Ringwald                                     }
2848f85ade6bSMatthias Ringwald                                     if (num_stored_out_of_order_packets){
2849f85ade6bSMatthias Ringwald                                         l2cap_channel->send_supervisor_frame_selective_reject = 1;
2850f85ade6bSMatthias Ringwald                                     } else {
2851d2afdd38SMatthias Ringwald                                         l2cap_channel->send_supervisor_frame_receiver_ready   = 1;
285278cd8a22SMatthias Ringwald                                     }
2853f85ade6bSMatthias Ringwald                                     l2cap_channel->set_final_bit_after_packet_with_poll_bit_set = 1;
2854f85ade6bSMatthias Ringwald                                 }
28553233d8abSMatthias Ringwald                                 if (final){
28563233d8abSMatthias Ringwald                                     // final bit set <- response to RR with poll bit set. All not acknowledged packets need to be retransmitted
28573233d8abSMatthias Ringwald                                     l2cap_channel->tx_send_index = l2cap_channel->tx_read_index;
28583233d8abSMatthias Ringwald                                 }
2859bdbe2e49SMatthias Ringwald                                 break;
28609ffcbce4SMatthias Ringwald                             case L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT:
28619ffcbce4SMatthias Ringwald                                 log_info("L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT");
28629ffcbce4SMatthias Ringwald                                 l2cap_ertm_handle_req_seq(l2cap_channel, req_seq);
28639ffcbce4SMatthias Ringwald                                 // rsetart transmittion from last unacknowledted packet (earlier packets already freed in l2cap_ertm_handle_req_seq)
28649ffcbce4SMatthias Ringwald                                 l2cap_channel->tx_send_index = l2cap_channel->tx_read_index;
28659ffcbce4SMatthias Ringwald                                 break;
28669ffcbce4SMatthias Ringwald                             case L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY:
28679ffcbce4SMatthias Ringwald                                 log_error("L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY");
28689ffcbce4SMatthias Ringwald                                 break;
28699ffcbce4SMatthias Ringwald                             case L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT:
28707b7901d8SMatthias Ringwald                                 log_info("L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT");
28717b7901d8SMatthias Ringwald                                 if (poll){
28727b7901d8SMatthias Ringwald                                     l2cap_ertm_handle_req_seq(l2cap_channel, req_seq);
28737b7901d8SMatthias Ringwald                                 }
28747b7901d8SMatthias Ringwald                                 // find requested i-frame
28757b7901d8SMatthias Ringwald                                 tx_state = l2cap_ertm_get_tx_state(l2cap_channel, req_seq);
28767b7901d8SMatthias Ringwald                                 if (tx_state){
28777b7901d8SMatthias Ringwald                                     log_info("Retransmission for tx_seq %u requested", req_seq);
2878d2afdd38SMatthias Ringwald                                     l2cap_channel->set_final_bit_after_packet_with_poll_bit_set = poll;
28797b7901d8SMatthias Ringwald                                     tx_state->retransmission_requested = 1;
28807b7901d8SMatthias Ringwald                                     l2cap_channel->srej_active = 1;
28817b7901d8SMatthias Ringwald                                 }
28829ffcbce4SMatthias Ringwald                                 break;
2883bdbe2e49SMatthias Ringwald                             default:
2884bdbe2e49SMatthias Ringwald                                 break;
2885bdbe2e49SMatthias Ringwald                         }
288627e0774aSMatthias Ringwald                         break;
288727e0774aSMatthias Ringwald                     } else {
288827e0774aSMatthias Ringwald                         // I-Frame
288927e0774aSMatthias Ringwald                         // get control
289027e0774aSMatthias Ringwald                         l2cap_segmentation_and_reassembly_t sar = (l2cap_segmentation_and_reassembly_t) (control >> 14);
289138f62777SMatthias Ringwald                         uint8_t tx_seq = (control >> 1) & 0x3f;
289238f62777SMatthias Ringwald                         log_info("Control: 0x%04x => SAR %u, ReqSeq %02u, R?, TxSeq %02u", control, (int) sar, req_seq, tx_seq);
2893e8e9809fSMatthias Ringwald                         log_info("SAR: pos %u", l2cap_channel->reassembly_pos);
289438f62777SMatthias Ringwald                         log_info("State: expected_tx_seq %02u, req_seq %02u", l2cap_channel->expected_tx_seq, l2cap_channel->req_seq);
28952a424812SMatthias Ringwald                         l2cap_ertm_handle_req_seq(l2cap_channel, req_seq);
289611b576c5SMatthias Ringwald                         if (final){
289711b576c5SMatthias Ringwald                             // final bit set <- response to RR with poll bit set. All not acknowledged packets need to be retransmitted
289811b576c5SMatthias Ringwald                             l2cap_channel->tx_send_index = l2cap_channel->tx_read_index;
289911b576c5SMatthias Ringwald                         }
290038f62777SMatthias Ringwald                         // check ordering
290138f62777SMatthias Ringwald                         if (l2cap_channel->expected_tx_seq == tx_seq){
290238f62777SMatthias Ringwald                             log_info("Received expected frame with TxSeq == ExpectedTxSeq == %02u", tx_seq);
290338f62777SMatthias Ringwald                             l2cap_channel->expected_tx_seq = l2cap_next_ertm_seq_nr(l2cap_channel->expected_tx_seq);
2904f85ade6bSMatthias Ringwald                             l2cap_channel->req_seq         = l2cap_channel->expected_tx_seq;
2905d48432d4SMatthias Ringwald 
2906e32be409SMatthias Ringwald                             // process SDU
2907e32be409SMatthias Ringwald                             l2cap_ertm_handle_in_sequence_sdu(l2cap_channel, sar, &packet[COMPLETE_L2CAP_HEADER+2], size-(COMPLETE_L2CAP_HEADER+2));
2908d48432d4SMatthias Ringwald 
290970734707SMatthias Ringwald                             // process stored segments
291070734707SMatthias Ringwald                             while (1){
291170734707SMatthias Ringwald                                 int index = l2cap_channel->rx_store_index;
291270734707SMatthias Ringwald                                 l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
291370734707SMatthias Ringwald                                 if (!rx_state->valid) break;
2914f85ade6bSMatthias Ringwald 
2915f85ade6bSMatthias Ringwald                                 log_info("Processing stored frame with TxSeq == ExpectedTxSeq == %02u", l2cap_channel->expected_tx_seq);
2916f85ade6bSMatthias Ringwald                                 l2cap_channel->expected_tx_seq = l2cap_next_ertm_seq_nr(l2cap_channel->expected_tx_seq);
2917f85ade6bSMatthias Ringwald                                 l2cap_channel->req_seq         = l2cap_channel->expected_tx_seq;
2918f85ade6bSMatthias Ringwald 
291970734707SMatthias Ringwald                                 rx_state->valid = 0;
292070734707SMatthias Ringwald                                 l2cap_ertm_handle_in_sequence_sdu(l2cap_channel, rx_state->sar, &l2cap_channel->rx_packets_data[index], rx_state->len);
2921f85ade6bSMatthias Ringwald 
2922f85ade6bSMatthias Ringwald                                 // update rx store index
292370734707SMatthias Ringwald                                 index++;
292470734707SMatthias Ringwald                                 if (index >= l2cap_channel->num_rx_buffers){
292570734707SMatthias Ringwald                                     index = 0;
292670734707SMatthias Ringwald                                 }
292770734707SMatthias Ringwald                                 l2cap_channel->rx_store_index = index;
292870734707SMatthias Ringwald                             }
292970734707SMatthias Ringwald 
2930f85ade6bSMatthias Ringwald                             //
2931f85ade6bSMatthias Ringwald                             l2cap_channel->send_supervisor_frame_receiver_ready = 1;
2932f85ade6bSMatthias Ringwald 
2933c7309e8dSMatthias Ringwald                         } else {
2934df2191a7SMatthias Ringwald                             int delta = (tx_seq - l2cap_channel->expected_tx_seq) & 0x3f;
2935df2191a7SMatthias Ringwald                             if (delta < 2){
293670734707SMatthias Ringwald                                 // store segment
293770734707SMatthias Ringwald                                 l2cap_ertm_handle_out_of_sequence_sdu(l2cap_channel, sar, delta, &packet[COMPLETE_L2CAP_HEADER+2], size-(COMPLETE_L2CAP_HEADER+2));
293870734707SMatthias Ringwald 
2939df2191a7SMatthias Ringwald                                 log_info("Received unexpected frame TxSeq %u but expected %u -> send S-SREJ", tx_seq, l2cap_channel->expected_tx_seq);
2940df2191a7SMatthias Ringwald                                 l2cap_channel->send_supervisor_frame_selective_reject = 1;
2941df2191a7SMatthias Ringwald                             } else {
2942df2191a7SMatthias Ringwald                                 log_info("Received unexpected frame TxSeq %u but expected %u -> send S-REJ", tx_seq, l2cap_channel->expected_tx_seq);
2943c7309e8dSMatthias Ringwald                                 l2cap_channel->send_supervisor_frame_reject = 1;
294427e0774aSMatthias Ringwald                             }
294538f62777SMatthias Ringwald                         }
2946df2191a7SMatthias Ringwald                     }
294727e0774aSMatthias Ringwald                     break;
294827e0774aSMatthias Ringwald                 }
294927e0774aSMatthias Ringwald #endif
29503d50b4baSMatthias Ringwald                 l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
295100d93d79Smatthias.ringwald             }
295209e9d05bSMatthias Ringwald #endif
2953a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
295464e11ca9SMatthias Ringwald             l2cap_channel = l2cap_le_get_channel_for_local_cid(channel_id);
295564e11ca9SMatthias Ringwald             if (l2cap_channel) {
295685aeef60SMatthias Ringwald                 // credit counting
295785aeef60SMatthias Ringwald                 if (l2cap_channel->credits_incoming == 0){
295885aeef60SMatthias Ringwald                     log_error("LE Data Channel packet received but no incoming credits");
295985aeef60SMatthias Ringwald                     l2cap_channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
296085aeef60SMatthias Ringwald                     break;
296185aeef60SMatthias Ringwald                 }
296285aeef60SMatthias Ringwald                 l2cap_channel->credits_incoming--;
296385aeef60SMatthias Ringwald 
296485aeef60SMatthias Ringwald                 // automatic credits
296585aeef60SMatthias Ringwald                 if (l2cap_channel->credits_incoming < L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_WATERMARK && l2cap_channel->automatic_credits){
296685aeef60SMatthias Ringwald                     l2cap_channel->new_credits_incoming = L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_INCREMENT;
296785aeef60SMatthias Ringwald                 }
296885aeef60SMatthias Ringwald 
2969cd529728SMatthias Ringwald                 // first fragment
2970cd529728SMatthias Ringwald                 uint16_t pos = 0;
2971cd529728SMatthias Ringwald                 if (!l2cap_channel->receive_sdu_len){
2972cd529728SMatthias Ringwald                     l2cap_channel->receive_sdu_len = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER);
2973cd529728SMatthias Ringwald                     l2cap_channel->receive_sdu_pos = 0;
2974cd529728SMatthias Ringwald                     pos  += 2;
2975cd529728SMatthias Ringwald                     size -= 2;
2976cd529728SMatthias Ringwald                 }
2977cd529728SMatthias Ringwald                 memcpy(&l2cap_channel->receive_sdu_buffer[l2cap_channel->receive_sdu_pos], &packet[COMPLETE_L2CAP_HEADER+pos], size-COMPLETE_L2CAP_HEADER);
2978cd529728SMatthias Ringwald                 l2cap_channel->receive_sdu_pos += size - COMPLETE_L2CAP_HEADER;
2979cd529728SMatthias Ringwald                 // done?
298063f0ac45SMatthias Ringwald                 log_info("le packet pos %u, len %u", l2cap_channel->receive_sdu_pos, l2cap_channel->receive_sdu_len);
2981cd529728SMatthias Ringwald                 if (l2cap_channel->receive_sdu_pos >= l2cap_channel->receive_sdu_len){
2982cd529728SMatthias Ringwald                     l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, l2cap_channel->receive_sdu_buffer, l2cap_channel->receive_sdu_len);
2983cd529728SMatthias Ringwald                     l2cap_channel->receive_sdu_len = 0;
2984cd529728SMatthias Ringwald                 }
298563f0ac45SMatthias Ringwald             } else {
298663f0ac45SMatthias Ringwald                 log_error("LE Data Channel packet received but no channel found for cid 0x%02x", channel_id);
298764e11ca9SMatthias Ringwald             }
298864e11ca9SMatthias Ringwald #endif
29895652b5ffS[email protected]             break;
29905652b5ffS[email protected]     }
299100d93d79Smatthias.ringwald 
29921eb2563eS[email protected]     l2cap_run();
29932718e2e7Smatthias.ringwald }
299400d93d79Smatthias.ringwald 
299509e9d05bSMatthias Ringwald // Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
299609e9d05bSMatthias Ringwald void l2cap_register_fixed_channel(btstack_packet_handler_t the_packet_handler, uint16_t channel_id) {
299709e9d05bSMatthias Ringwald     int index = l2cap_fixed_channel_table_index_for_channel_id(channel_id);
299809e9d05bSMatthias Ringwald     if (index < 0) return;
299909e9d05bSMatthias Ringwald     fixed_channels[index].callback = the_packet_handler;
300009e9d05bSMatthias Ringwald }
300109e9d05bSMatthias Ringwald 
300209e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
300315ec09bbSmatthias.ringwald // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
300427a923d0Smatthias.ringwald void l2cap_finialize_channel_close(l2cap_channel_t * channel){
3005f62db1e3Smatthias.ringwald     channel->state = L2CAP_STATE_CLOSED;
3006f62db1e3Smatthias.ringwald     l2cap_emit_channel_closed(channel);
3007f62db1e3Smatthias.ringwald     // discard channel
30089dcb2fb2S[email protected]     l2cap_stop_rtx(channel);
3009665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
3010d3a9df87Smatthias.ringwald     btstack_memory_l2cap_channel_free(channel);
3011c8e4258aSmatthias.ringwald }
30121e6aba47Smatthias.ringwald 
30138f2a52f4SMatthias Ringwald static l2cap_service_t * l2cap_get_service_internal(btstack_linked_list_t * services, uint16_t psm){
3014665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
3015665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, services);
3016665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
3017665d90f2SMatthias Ringwald         l2cap_service_t * service = (l2cap_service_t *) btstack_linked_list_iterator_next(&it);
30189d9bbc01Smatthias.ringwald         if ( service->psm == psm){
30199d9bbc01Smatthias.ringwald             return service;
30209d9bbc01Smatthias.ringwald         };
30219d9bbc01Smatthias.ringwald     }
30229d9bbc01Smatthias.ringwald     return NULL;
30239d9bbc01Smatthias.ringwald }
30249d9bbc01Smatthias.ringwald 
30257192e786SMatthias Ringwald static inline l2cap_service_t * l2cap_get_service(uint16_t psm){
30267192e786SMatthias Ringwald     return l2cap_get_service_internal(&l2cap_services, psm);
30277192e786SMatthias Ringwald }
30287192e786SMatthias Ringwald 
3029e0abb8e7S[email protected] 
3030be2053a6SMatthias 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){
3031be2053a6SMatthias Ringwald 
3032be2053a6SMatthias Ringwald     log_info("L2CAP_REGISTER_SERVICE psm 0x%x mtu %u", psm, mtu);
3033e0abb8e7S[email protected] 
30344bb582b6Smatthias.ringwald     // check for alread registered psm
30359d9bbc01Smatthias.ringwald     l2cap_service_t *service = l2cap_get_service(psm);
3036277abc2cSmatthias.ringwald     if (service) {
3037be2053a6SMatthias Ringwald         log_error("l2cap_register_service: PSM %u already registered", psm);
3038be2053a6SMatthias Ringwald         return L2CAP_SERVICE_ALREADY_REGISTERED;
3039277abc2cSmatthias.ringwald     }
30409d9bbc01Smatthias.ringwald 
30414bb582b6Smatthias.ringwald     // alloc structure
3042bb69aaaeS[email protected]     service = btstack_memory_l2cap_service_get();
3043277abc2cSmatthias.ringwald     if (!service) {
3044be2053a6SMatthias Ringwald         log_error("l2cap_register_service: no memory for l2cap_service_t");
3045be2053a6SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
3046277abc2cSmatthias.ringwald     }
30479d9bbc01Smatthias.ringwald 
30489d9bbc01Smatthias.ringwald     // fill in
30499d9bbc01Smatthias.ringwald     service->psm = psm;
30509d9bbc01Smatthias.ringwald     service->mtu = mtu;
305105ae8de3SMatthias Ringwald     service->packet_handler = service_packet_handler;
3052df3354fcS[email protected]     service->required_security_level = security_level;
30539d9bbc01Smatthias.ringwald 
30549d9bbc01Smatthias.ringwald     // add to services list
3055665d90f2SMatthias Ringwald     btstack_linked_list_add(&l2cap_services, (btstack_linked_item_t *) service);
3056c0e866bfSmatthias.ringwald 
3057c0e866bfSmatthias.ringwald     // enable page scan
305815a95bd5SMatthias Ringwald     gap_connectable_control(1);
30595842b6d9Smatthias.ringwald 
3060be2053a6SMatthias Ringwald     return 0;
30619d9bbc01Smatthias.ringwald }
30629d9bbc01Smatthias.ringwald 
30637e8856ebSMatthias Ringwald uint8_t l2cap_unregister_service(uint16_t psm){
3064e0abb8e7S[email protected] 
3065e0abb8e7S[email protected]     log_info("L2CAP_UNREGISTER_SERVICE psm 0x%x", psm);
3066e0abb8e7S[email protected] 
30679d9bbc01Smatthias.ringwald     l2cap_service_t *service = l2cap_get_service(psm);
30687e8856ebSMatthias Ringwald     if (!service) return L2CAP_SERVICE_DOES_NOT_EXIST;
3069665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_services, (btstack_linked_item_t *) service);
3070d3a9df87Smatthias.ringwald     btstack_memory_l2cap_service_free(service);
3071c0e866bfSmatthias.ringwald 
3072c0e866bfSmatthias.ringwald     // disable page scan when no services registered
30737e8856ebSMatthias Ringwald     if (btstack_linked_list_empty(&l2cap_services)) {
307415a95bd5SMatthias Ringwald         gap_connectable_control(0);
30759d9bbc01Smatthias.ringwald     }
30767e8856ebSMatthias Ringwald     return 0;
30777e8856ebSMatthias Ringwald }
307809e9d05bSMatthias Ringwald #endif
30799d9bbc01Smatthias.ringwald 
30807192e786SMatthias Ringwald 
3081cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
308283fd9c76SMatthias Ringwald 
308357be49d6SMatthias Ringwald static void l2cap_le_notify_channel_can_send(l2cap_channel_t *channel){
308457be49d6SMatthias Ringwald     if (!channel->waiting_for_can_send_now) return;
308557be49d6SMatthias Ringwald     if (channel->send_sdu_buffer) return;
308657be49d6SMatthias Ringwald     channel->waiting_for_can_send_now = 0;
308757be49d6SMatthias Ringwald     log_info("L2CAP_EVENT_CHANNEL_LE_CAN_SEND_NOW local_cid 0x%x", channel->local_cid);
308857be49d6SMatthias Ringwald     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_CAN_SEND_NOW);
308957be49d6SMatthias Ringwald }
309057be49d6SMatthias Ringwald 
309157be49d6SMatthias Ringwald // 1BH2222
309257be49d6SMatthias Ringwald static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel) {
309357be49d6SMatthias 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",
309457be49d6SMatthias Ringwald              channel->address_type, bd_addr_to_str(channel->address), channel->con_handle,  channel->psm, channel->local_cid, channel->remote_cid, channel->remote_mtu);
309557be49d6SMatthias Ringwald     uint8_t event[19];
309657be49d6SMatthias Ringwald     event[0] = L2CAP_EVENT_LE_INCOMING_CONNECTION;
309757be49d6SMatthias Ringwald     event[1] = sizeof(event) - 2;
309857be49d6SMatthias Ringwald     event[2] = channel->address_type;
309957be49d6SMatthias Ringwald     reverse_bd_addr(channel->address, &event[3]);
310057be49d6SMatthias Ringwald     little_endian_store_16(event,  9, channel->con_handle);
310157be49d6SMatthias Ringwald     little_endian_store_16(event, 11, channel->psm);
310257be49d6SMatthias Ringwald     little_endian_store_16(event, 13, channel->local_cid);
310357be49d6SMatthias Ringwald     little_endian_store_16(event, 15, channel->remote_cid);
310457be49d6SMatthias Ringwald     little_endian_store_16(event, 17, channel->remote_mtu);
310557be49d6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
310657be49d6SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
310757be49d6SMatthias Ringwald }
310857be49d6SMatthias Ringwald // 11BH22222
310957be49d6SMatthias Ringwald static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status) {
311057be49d6SMatthias 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",
311157be49d6SMatthias Ringwald              status, channel->address_type, bd_addr_to_str(channel->address), channel->con_handle, channel->psm,
311257be49d6SMatthias Ringwald              channel->local_cid, channel->remote_cid, channel->local_mtu, channel->remote_mtu);
3113c99bb618SMatthias Ringwald     uint8_t event[23];
311457be49d6SMatthias Ringwald     event[0] = L2CAP_EVENT_LE_CHANNEL_OPENED;
311557be49d6SMatthias Ringwald     event[1] = sizeof(event) - 2;
311657be49d6SMatthias Ringwald     event[2] = status;
311757be49d6SMatthias Ringwald     event[3] = channel->address_type;
311857be49d6SMatthias Ringwald     reverse_bd_addr(channel->address, &event[4]);
311957be49d6SMatthias Ringwald     little_endian_store_16(event, 10, channel->con_handle);
3120c99bb618SMatthias Ringwald     event[12] = channel->state_var & L2CAP_CHANNEL_STATE_VAR_INCOMING ? 1 : 0;
3121c99bb618SMatthias Ringwald     little_endian_store_16(event, 13, channel->psm);
3122c99bb618SMatthias Ringwald     little_endian_store_16(event, 15, channel->local_cid);
3123c99bb618SMatthias Ringwald     little_endian_store_16(event, 17, channel->remote_cid);
3124c99bb618SMatthias Ringwald     little_endian_store_16(event, 19, channel->local_mtu);
3125c99bb618SMatthias Ringwald     little_endian_store_16(event, 21, channel->remote_mtu);
312657be49d6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
312757be49d6SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
312857be49d6SMatthias Ringwald }
312957be49d6SMatthias Ringwald 
313057be49d6SMatthias Ringwald static l2cap_channel_t * l2cap_le_get_channel_for_local_cid(uint16_t local_cid){
313157be49d6SMatthias Ringwald     btstack_linked_list_iterator_t it;
313257be49d6SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_le_channels);
313357be49d6SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
313457be49d6SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
313557be49d6SMatthias Ringwald         if ( channel->local_cid == local_cid) {
313657be49d6SMatthias Ringwald             return channel;
313757be49d6SMatthias Ringwald         }
313857be49d6SMatthias Ringwald     }
313957be49d6SMatthias Ringwald     return NULL;
314057be49d6SMatthias Ringwald }
314157be49d6SMatthias Ringwald 
314257be49d6SMatthias Ringwald // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
314357be49d6SMatthias Ringwald void l2cap_le_finialize_channel_close(l2cap_channel_t * channel){
314457be49d6SMatthias Ringwald     channel->state = L2CAP_STATE_CLOSED;
314557be49d6SMatthias Ringwald     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED);
314657be49d6SMatthias Ringwald     // discard channel
314757be49d6SMatthias Ringwald     btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel);
314857be49d6SMatthias Ringwald     btstack_memory_l2cap_channel_free(channel);
314957be49d6SMatthias Ringwald }
315057be49d6SMatthias Ringwald 
3151e7d0c9aaSMatthias Ringwald static inline l2cap_service_t * l2cap_le_get_service(uint16_t le_psm){
3152e7d0c9aaSMatthias Ringwald     return l2cap_get_service_internal(&l2cap_le_services, le_psm);
31537192e786SMatthias Ringwald }
3154efedfb4cSMatthias Ringwald 
3155da144af5SMatthias Ringwald uint8_t l2cap_le_register_service(btstack_packet_handler_t packet_handler, uint16_t psm, gap_security_level_t security_level){
31567192e786SMatthias Ringwald 
3157da144af5SMatthias Ringwald     log_info("L2CAP_LE_REGISTER_SERVICE psm 0x%x", psm);
31587192e786SMatthias Ringwald 
31597192e786SMatthias Ringwald     // check for alread registered psm
31607192e786SMatthias Ringwald     l2cap_service_t *service = l2cap_le_get_service(psm);
31617192e786SMatthias Ringwald     if (service) {
3162da144af5SMatthias Ringwald         return L2CAP_SERVICE_ALREADY_REGISTERED;
31637192e786SMatthias Ringwald     }
31647192e786SMatthias Ringwald 
31657192e786SMatthias Ringwald     // alloc structure
31667192e786SMatthias Ringwald     service = btstack_memory_l2cap_service_get();
31677192e786SMatthias Ringwald     if (!service) {
31687192e786SMatthias Ringwald         log_error("l2cap_register_service_internal: no memory for l2cap_service_t");
3169da144af5SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
31707192e786SMatthias Ringwald     }
31717192e786SMatthias Ringwald 
31727192e786SMatthias Ringwald     // fill in
31737192e786SMatthias Ringwald     service->psm = psm;
3174da144af5SMatthias Ringwald     service->mtu = 0;
31757192e786SMatthias Ringwald     service->packet_handler = packet_handler;
31767192e786SMatthias Ringwald     service->required_security_level = security_level;
31777192e786SMatthias Ringwald 
31787192e786SMatthias Ringwald     // add to services list
3179665d90f2SMatthias Ringwald     btstack_linked_list_add(&l2cap_le_services, (btstack_linked_item_t *) service);
31807192e786SMatthias Ringwald 
31817192e786SMatthias Ringwald     // done
3182da144af5SMatthias Ringwald     return 0;
31837192e786SMatthias Ringwald }
31847192e786SMatthias Ringwald 
3185da144af5SMatthias Ringwald uint8_t l2cap_le_unregister_service(uint16_t psm) {
31867192e786SMatthias Ringwald     log_info("L2CAP_LE_UNREGISTER_SERVICE psm 0x%x", psm);
31877192e786SMatthias Ringwald     l2cap_service_t *service = l2cap_le_get_service(psm);
31889367f9b0SMatthias Ringwald     if (!service) return L2CAP_SERVICE_DOES_NOT_EXIST;
3189da144af5SMatthias Ringwald 
3190665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_le_services, (btstack_linked_item_t *) service);
31917192e786SMatthias Ringwald     btstack_memory_l2cap_service_free(service);
3192da144af5SMatthias Ringwald     return 0;
31937192e786SMatthias Ringwald }
3194da144af5SMatthias Ringwald 
3195da144af5SMatthias Ringwald uint8_t l2cap_le_accept_connection(uint16_t local_cid, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits){
3196e7d0c9aaSMatthias Ringwald     // get channel
3197e7d0c9aaSMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
3198e7d0c9aaSMatthias Ringwald     if (!channel) return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
3199e7d0c9aaSMatthias Ringwald 
3200e7d0c9aaSMatthias Ringwald     // validate state
3201e7d0c9aaSMatthias Ringwald     if (channel->state != L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT){
3202e7d0c9aaSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
3203e7d0c9aaSMatthias Ringwald     }
3204e7d0c9aaSMatthias Ringwald 
3205efedfb4cSMatthias Ringwald     // set state accept connection
320623017473SMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_ACCEPT;
320723017473SMatthias Ringwald     channel->receive_sdu_buffer = receive_sdu_buffer;
320823017473SMatthias Ringwald     channel->local_mtu = mtu;
320985aeef60SMatthias Ringwald     channel->new_credits_incoming = initial_credits;
321085aeef60SMatthias Ringwald     channel->automatic_credits  = initial_credits == L2CAP_LE_AUTOMATIC_CREDITS;
321185aeef60SMatthias Ringwald 
321285aeef60SMatthias Ringwald     // test
321363f0ac45SMatthias Ringwald     // channel->new_credits_incoming = 1;
3214e7d0c9aaSMatthias Ringwald 
3215e7d0c9aaSMatthias Ringwald     // go
3216e7d0c9aaSMatthias Ringwald     l2cap_run();
3217da144af5SMatthias Ringwald     return 0;
3218da144af5SMatthias Ringwald }
3219da144af5SMatthias Ringwald 
3220da144af5SMatthias Ringwald /**
3221da144af5SMatthias Ringwald  * @brief Deny incoming LE Data Channel connection due to resource constraints
3222da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3223da144af5SMatthias Ringwald  */
3224da144af5SMatthias Ringwald 
3225da144af5SMatthias Ringwald uint8_t l2cap_le_decline_connection(uint16_t local_cid){
3226e7d0c9aaSMatthias Ringwald     // get channel
3227e7d0c9aaSMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
3228e7d0c9aaSMatthias Ringwald     if (!channel) return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
3229e7d0c9aaSMatthias Ringwald 
3230e7d0c9aaSMatthias Ringwald     // validate state
3231e7d0c9aaSMatthias Ringwald     if (channel->state != L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT){
3232e7d0c9aaSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
3233e7d0c9aaSMatthias Ringwald     }
3234e7d0c9aaSMatthias Ringwald 
3235efedfb4cSMatthias Ringwald     // set state decline connection
3236e7d0c9aaSMatthias Ringwald     channel->state  = L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE;
3237e7d0c9aaSMatthias Ringwald     channel->reason = 0x04; // no resources available
3238e7d0c9aaSMatthias Ringwald     l2cap_run();
3239da144af5SMatthias Ringwald     return 0;
3240da144af5SMatthias Ringwald }
3241da144af5SMatthias Ringwald 
32427dafa750SMatthias Ringwald uint8_t l2cap_le_create_channel(btstack_packet_handler_t packet_handler, hci_con_handle_t con_handle,
3243da144af5SMatthias Ringwald     uint16_t psm, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits, gap_security_level_t security_level,
3244efedfb4cSMatthias Ringwald     uint16_t * out_local_cid) {
3245efedfb4cSMatthias Ringwald 
32467dafa750SMatthias Ringwald     log_info("L2CAP_LE_CREATE_CHANNEL handle 0x%04x psm 0x%x mtu %u", con_handle, psm, mtu);
3247da144af5SMatthias Ringwald 
32487dafa750SMatthias Ringwald 
32497dafa750SMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(con_handle);
32507dafa750SMatthias Ringwald     if (!connection) {
32517dafa750SMatthias Ringwald         log_error("no hci_connection for handle 0x%04x", con_handle);
32527dafa750SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
32537dafa750SMatthias Ringwald     }
32547dafa750SMatthias Ringwald 
32557dafa750SMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(packet_handler, connection->address, connection->address_type, psm, mtu, security_level);
3256da144af5SMatthias Ringwald     if (!channel) {
3257da144af5SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
3258da144af5SMatthias Ringwald     }
3259e7d0c9aaSMatthias Ringwald     log_info("l2cap_le_create_channel %p", channel);
3260da144af5SMatthias Ringwald 
3261da144af5SMatthias Ringwald     // store local_cid
3262da144af5SMatthias Ringwald     if (out_local_cid){
3263da144af5SMatthias Ringwald        *out_local_cid = channel->local_cid;
3264da144af5SMatthias Ringwald     }
3265da144af5SMatthias Ringwald 
32667dafa750SMatthias Ringwald     // provide buffer
32677dafa750SMatthias Ringwald     channel->con_handle = con_handle;
3268cd529728SMatthias Ringwald     channel->receive_sdu_buffer = receive_sdu_buffer;
32697dafa750SMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_LE_CONNECTION_REQUEST;
327085aeef60SMatthias Ringwald     channel->new_credits_incoming = initial_credits;
327185aeef60SMatthias Ringwald     channel->automatic_credits    = initial_credits == L2CAP_LE_AUTOMATIC_CREDITS;
327285aeef60SMatthias Ringwald 
3273efedfb4cSMatthias Ringwald     // add to connections list
3274efedfb4cSMatthias Ringwald     btstack_linked_list_add(&l2cap_le_channels, (btstack_linked_item_t *) channel);
3275efedfb4cSMatthias Ringwald 
32767dafa750SMatthias Ringwald     // go
327763f0ac45SMatthias Ringwald     l2cap_run();
3278da144af5SMatthias Ringwald     return 0;
3279da144af5SMatthias Ringwald }
3280da144af5SMatthias Ringwald 
3281da144af5SMatthias Ringwald /**
3282da144af5SMatthias Ringwald  * @brief Provide credtis for LE Data Channel
3283da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3284da144af5SMatthias Ringwald  * @param credits               Number additional credits for peer
3285da144af5SMatthias Ringwald  */
328664e11ca9SMatthias Ringwald uint8_t l2cap_le_provide_credits(uint16_t local_cid, uint16_t credits){
328763f0ac45SMatthias Ringwald 
328863f0ac45SMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
328963f0ac45SMatthias Ringwald     if (!channel) {
329063f0ac45SMatthias Ringwald         log_error("l2cap_le_provide_credits no channel for cid 0x%02x", local_cid);
329163f0ac45SMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
329263f0ac45SMatthias Ringwald     }
329363f0ac45SMatthias Ringwald 
3294efedfb4cSMatthias Ringwald     // check state
329563f0ac45SMatthias Ringwald     if (channel->state != L2CAP_STATE_OPEN){
329663f0ac45SMatthias Ringwald         log_error("l2cap_le_provide_credits but channel 0x%02x not open yet", local_cid);
329763f0ac45SMatthias Ringwald     }
329863f0ac45SMatthias Ringwald 
329963f0ac45SMatthias Ringwald     // assert incoming credits + credits <= 0xffff
330063f0ac45SMatthias Ringwald     uint32_t total_credits = channel->credits_incoming;
330163f0ac45SMatthias Ringwald     total_credits += channel->new_credits_incoming;
330263f0ac45SMatthias Ringwald     total_credits += credits;
330363f0ac45SMatthias Ringwald     if (total_credits > 0xffff){
330463f0ac45SMatthias Ringwald         log_error("l2cap_le_provide_credits overrun: current %u, scheduled %u, additional %u", channel->credits_incoming,
330563f0ac45SMatthias Ringwald             channel->new_credits_incoming, credits);
330663f0ac45SMatthias Ringwald     }
330763f0ac45SMatthias Ringwald 
3308efedfb4cSMatthias Ringwald     // set credits_granted
330963f0ac45SMatthias Ringwald     channel->new_credits_incoming += credits;
331063f0ac45SMatthias Ringwald 
331163f0ac45SMatthias Ringwald     // go
331263f0ac45SMatthias Ringwald     l2cap_run();
3313da144af5SMatthias Ringwald     return 0;
3314da144af5SMatthias Ringwald }
3315da144af5SMatthias Ringwald 
3316da144af5SMatthias Ringwald /**
3317da144af5SMatthias Ringwald  * @brief Check if outgoing buffer is available and that there's space on the Bluetooth module
3318da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3319da144af5SMatthias Ringwald  */
332064e11ca9SMatthias Ringwald int l2cap_le_can_send_now(uint16_t local_cid){
332144276248SMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
332244276248SMatthias Ringwald     if (!channel) {
332344276248SMatthias Ringwald         log_error("l2cap_le_provide_credits no channel for cid 0x%02x", local_cid);
3324da144af5SMatthias Ringwald         return 0;
3325da144af5SMatthias Ringwald     }
3326da144af5SMatthias Ringwald 
332744276248SMatthias Ringwald     // check state
332844276248SMatthias Ringwald     if (channel->state != L2CAP_STATE_OPEN) return 0;
332944276248SMatthias Ringwald 
333044276248SMatthias Ringwald     // check queue
333144276248SMatthias Ringwald     if (channel->send_sdu_buffer) return 0;
333244276248SMatthias Ringwald 
333344276248SMatthias Ringwald     // fine, go ahead
333444276248SMatthias Ringwald     return 1;
333544276248SMatthias Ringwald }
333644276248SMatthias Ringwald 
3337da144af5SMatthias Ringwald /**
3338da144af5SMatthias Ringwald  * @brief Request emission of L2CAP_EVENT_CAN_SEND_NOW as soon as possible
3339da144af5SMatthias Ringwald  * @note L2CAP_EVENT_CAN_SEND_NOW might be emitted during call to this function
3340da144af5SMatthias Ringwald  *       so packet handler should be ready to handle it
3341da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3342da144af5SMatthias Ringwald  */
334364e11ca9SMatthias Ringwald uint8_t l2cap_le_request_can_send_now_event(uint16_t local_cid){
334444276248SMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
334544276248SMatthias Ringwald     if (!channel) {
334644276248SMatthias Ringwald         log_error("l2cap_le_request_can_send_now_event no channel for cid 0x%02x", local_cid);
334744276248SMatthias Ringwald         return 0;
334844276248SMatthias Ringwald     }
334944276248SMatthias Ringwald     channel->waiting_for_can_send_now = 1;
335044276248SMatthias Ringwald     l2cap_le_notify_channel_can_send(channel);
3351da144af5SMatthias Ringwald     return 0;
3352da144af5SMatthias Ringwald }
3353da144af5SMatthias Ringwald 
3354da144af5SMatthias Ringwald /**
3355da144af5SMatthias Ringwald  * @brief Send data via LE Data Channel
3356da144af5SMatthias Ringwald  * @note Since data larger then the maximum PDU needs to be segmented into multiple PDUs, data needs to stay valid until ... event
3357da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3358da144af5SMatthias Ringwald  * @param data                  data to send
3359da144af5SMatthias Ringwald  * @param size                  data size
3360da144af5SMatthias Ringwald  */
336164e11ca9SMatthias Ringwald uint8_t l2cap_le_send_data(uint16_t local_cid, uint8_t * data, uint16_t len){
336264e11ca9SMatthias Ringwald 
336364e11ca9SMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
336464e11ca9SMatthias Ringwald     if (!channel) {
336564e11ca9SMatthias Ringwald         log_error("l2cap_send no channel for cid 0x%02x", local_cid);
3366828a7f7aSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
336764e11ca9SMatthias Ringwald     }
336864e11ca9SMatthias Ringwald 
336964e11ca9SMatthias Ringwald     if (len > channel->remote_mtu){
337064e11ca9SMatthias Ringwald         log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", local_cid);
337164e11ca9SMatthias Ringwald         return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU;
337264e11ca9SMatthias Ringwald     }
337364e11ca9SMatthias Ringwald 
33747f107edaSMatthias Ringwald     if (channel->send_sdu_buffer){
337564e11ca9SMatthias Ringwald         log_info("l2cap_send cid 0x%02x, cannot send", local_cid);
337664e11ca9SMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
337764e11ca9SMatthias Ringwald     }
337864e11ca9SMatthias Ringwald 
33797f107edaSMatthias Ringwald     channel->send_sdu_buffer = data;
33807f107edaSMatthias Ringwald     channel->send_sdu_len    = len;
33817f107edaSMatthias Ringwald     channel->send_sdu_pos    = 0;
338264e11ca9SMatthias Ringwald 
33837f107edaSMatthias Ringwald     l2cap_run();
33847f107edaSMatthias Ringwald     return 0;
3385da144af5SMatthias Ringwald }
3386da144af5SMatthias Ringwald 
3387da144af5SMatthias Ringwald /**
3388da144af5SMatthias Ringwald  * @brief Disconnect from LE Data Channel
3389da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3390da144af5SMatthias Ringwald  */
3391828a7f7aSMatthias Ringwald uint8_t l2cap_le_disconnect(uint16_t local_cid)
3392da144af5SMatthias Ringwald {
3393828a7f7aSMatthias Ringwald     l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
3394828a7f7aSMatthias Ringwald     if (!channel) {
3395828a7f7aSMatthias Ringwald         log_error("l2cap_send no channel for cid 0x%02x", local_cid);
3396828a7f7aSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
3397828a7f7aSMatthias Ringwald     }
3398828a7f7aSMatthias Ringwald 
3399828a7f7aSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
3400828a7f7aSMatthias Ringwald     l2cap_run();
3401da144af5SMatthias Ringwald     return 0;
3402da144af5SMatthias Ringwald }
3403da144af5SMatthias Ringwald 
34047f02f414SMatthias Ringwald #endif
3405