xref: /btstack/src/l2cap.c (revision 6774d5c927ebbccf5c4db4e49165a7a21209cbad)
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 
38e501bae0SMatthias 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"
5284e3541eSMilanka Ringwald #include "bluetooth_psm.h"
5316ece135SMatthias Ringwald #include "btstack_debug.h"
540e2df43fSMatthias Ringwald #include "btstack_event.h"
55d3a9df87Smatthias.ringwald #include "btstack_memory.h"
5643625864Smatthias.ringwald 
5743625864Smatthias.ringwald #include <stdarg.h>
5843625864Smatthias.ringwald #include <string.h>
5943625864Smatthias.ringwald 
6043625864Smatthias.ringwald #include <stdio.h>
6143625864Smatthias.ringwald 
62a6e314f1SMatthias Ringwald /*
63a6e314f1SMatthias Ringwald  * @brief L2CAP Supervisory function in S-Frames
64a6e314f1SMatthias Ringwald  */
65a6e314f1SMatthias Ringwald typedef enum {
66a6e314f1SMatthias Ringwald     L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY = 0,
67a6e314f1SMatthias Ringwald     L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT,
68a6e314f1SMatthias Ringwald     L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY,
69a6e314f1SMatthias Ringwald     L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT
70a6e314f1SMatthias Ringwald } l2cap_supervisory_function_t;
71a6e314f1SMatthias Ringwald 
72a6e314f1SMatthias Ringwald /**
73a6e314f1SMatthias Ringwald  * @brief L2CAP Information Types used in Information Request & Response
74a6e314f1SMatthias Ringwald  */
75a6e314f1SMatthias Ringwald typedef enum {
76a6e314f1SMatthias Ringwald   L2CAP_INFO_TYPE_CONNECTIONLESS_MTU = 1,
77a6e314f1SMatthias Ringwald   L2CAP_INFO_TYPE_EXTENDED_FEATURES_SUPPORTED,
78a6e314f1SMatthias Ringwald   L2CAP_INFO_TYPE_FIXED_CHANNELS_SUPPORTED,
79a6e314f1SMatthias Ringwald } l2cap_info_type_t;
80a6e314f1SMatthias Ringwald 
81a6e314f1SMatthias Ringwald /**
82a6e314f1SMatthias Ringwald  * @brief L2CAP Configuration Option Types used in Configurateion Request & Response
83a6e314f1SMatthias Ringwald  */
84a6e314f1SMatthias Ringwald typedef enum {
85a6e314f1SMatthias Ringwald   L2CAP_CONFIG_OPTION_TYPE_MAX_TRANSMISSION_UNIT = 1,
86a6e314f1SMatthias Ringwald   L2CAP_CONFIG_OPTION_TYPE_FLUSH_TIMEOUT,
87a6e314f1SMatthias Ringwald   L2CAP_CONFIG_OPTION_TYPE_QUALITY_OF_SERVICE,
88a6e314f1SMatthias Ringwald   L2CAP_CONFIG_OPTION_TYPE_RETRANSMISSION_AND_FLOW_CONTROL,
89a6e314f1SMatthias Ringwald   L2CAP_CONFIG_OPTION_TYPE_FRAME_CHECK_SEQUENCE,
90a6e314f1SMatthias Ringwald   L2CAP_CONFIG_OPTION_TYPE_EXTENDED_FLOW_SPECIFICATION,
91a6e314f1SMatthias Ringwald   L2CAP_CONFIG_OPTION_TYPE_EXTENDED_WINDOW_SIZE,
92a6e314f1SMatthias Ringwald } l2cap_config_option_type_t;
93a6e314f1SMatthias Ringwald 
94a6e314f1SMatthias Ringwald 
95a6e314f1SMatthias Ringwald #define L2CAP_SIG_ID_INVALID 0
96a6e314f1SMatthias Ringwald 
97a6e314f1SMatthias Ringwald // size of HCI ACL + L2CAP Header for regular data packets (8)
98a6e314f1SMatthias Ringwald #define COMPLETE_L2CAP_HEADER (HCI_ACL_HEADER_SIZE + L2CAP_HEADER_SIZE)
99a6e314f1SMatthias Ringwald 
100a6e314f1SMatthias Ringwald // L2CAP Configuration Result Codes
101a6e314f1SMatthias Ringwald #define L2CAP_CONF_RESULT_SUCCESS                  0x0000
102a6e314f1SMatthias Ringwald #define L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS  0x0001
103a6e314f1SMatthias Ringwald #define L2CAP_CONF_RESULT_REJECT                   0x0002
104a6e314f1SMatthias Ringwald #define L2CAP_CONF_RESULT_UNKNOWN_OPTIONS          0x0003
105a6e314f1SMatthias Ringwald #define L2CAP_CONF_RESULT_PENDING                  0x0004
106a6e314f1SMatthias Ringwald #define L2CAP_CONF_RESULT_FLOW_SPEC_REJECTED       0x0005
107a6e314f1SMatthias Ringwald 
108a6e314f1SMatthias Ringwald // L2CAP Reject Result Codes
109a6e314f1SMatthias Ringwald #define L2CAP_REJ_CMD_UNKNOWN                      0x0000
110a6e314f1SMatthias Ringwald 
111a6e314f1SMatthias Ringwald // Response Timeout eXpired
112a6e314f1SMatthias Ringwald #define L2CAP_RTX_TIMEOUT_MS   10000
113a6e314f1SMatthias Ringwald 
114a6e314f1SMatthias Ringwald // Extended Response Timeout eXpired
115a6e314f1SMatthias Ringwald #define L2CAP_ERTX_TIMEOUT_MS 120000
116a6e314f1SMatthias Ringwald 
1174c744e21Smatthias.ringwald // nr of buffered acl packets in outgoing queue to get max performance
1184c744e21Smatthias.ringwald #define NR_BUFFERED_ACL_PACKETS 3
1194c744e21Smatthias.ringwald 
12039bda6d5Smatthias.ringwald // used to cache l2cap rejects, echo, and informational requests
121e16a9cacSmatthias.ringwald #define NR_PENDING_SIGNALING_RESPONSES 3
12239bda6d5Smatthias.ringwald 
12385aeef60SMatthias Ringwald // nr of credits provided to remote if credits fall below watermark
12485aeef60SMatthias Ringwald #define L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_WATERMARK 5
12585aeef60SMatthias Ringwald #define L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_INCREMENT 5
12685aeef60SMatthias Ringwald 
12700d93d79Smatthias.ringwald // offsets for L2CAP SIGNALING COMMANDS
12800d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_CODE_OFFSET   0
12900d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_SIGID_OFFSET  1
13000d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2
13100d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_DATA_OFFSET   4
13200d93d79Smatthias.ringwald 
13309e9d05bSMatthias Ringwald #if defined(ENABLE_LE_DATA_CHANNELS) || defined(ENABLE_CLASSIC)
13409e9d05bSMatthias Ringwald #define L2CAP_USES_CHANNELS
13509e9d05bSMatthias Ringwald #endif
13609e9d05bSMatthias Ringwald 
13733c40538SMatthias Ringwald // prototypes
138675e6881SMatthias Ringwald static void l2cap_run(void);
13933c40538SMatthias Ringwald static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
1403d50b4baSMatthias Ringwald static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size );
14130725612SMatthias Ringwald static void l2cap_notify_channel_can_send(void);
14209e9d05bSMatthias Ringwald static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel);
1436ddef68dSMilanka Ringwald static uint8_t  l2cap_next_sig_id(void);
1447740e150SMatthias Ringwald static l2cap_fixed_channel_t * l2cap_fixed_channel_for_channel_id(uint16_t local_cid);
14509e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
146474f5c3fSMatthias Ringwald static void l2cap_handle_remote_supported_features_received(l2cap_channel_t * channel);
147474f5c3fSMatthias Ringwald static void l2cap_handle_connection_complete(hci_con_handle_t con_handle, l2cap_channel_t * channel);
14809e9d05bSMatthias Ringwald static void l2cap_finialize_channel_close(l2cap_channel_t *channel);
14909e9d05bSMatthias Ringwald static inline l2cap_service_t * l2cap_get_service(uint16_t psm);
15009e9d05bSMatthias Ringwald static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status);
15109e9d05bSMatthias Ringwald static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
15209e9d05bSMatthias Ringwald static void l2cap_emit_incoming_connection(l2cap_channel_t *channel);
15309e9d05bSMatthias Ringwald static int  l2cap_channel_ready_for_open(l2cap_channel_t *channel);
15409e9d05bSMatthias Ringwald #endif
155cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
15657be49d6SMatthias Ringwald static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status);
15787050a0bSMatthias Ringwald static void l2cap_emit_le_channel_closed(l2cap_channel_t * channel);
15857be49d6SMatthias Ringwald static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel);
15944276248SMatthias Ringwald static void l2cap_le_notify_channel_can_send(l2cap_channel_t *channel);
160828a7f7aSMatthias Ringwald static void l2cap_le_finialize_channel_close(l2cap_channel_t *channel);
161*6774d5c9SMatthias Ringwald static void l2cap_le_send_pdu(l2cap_channel_t *channel);
162e7d0c9aaSMatthias Ringwald static inline l2cap_service_t * l2cap_le_get_service(uint16_t psm);
163e7d0c9aaSMatthias Ringwald #endif
164474f5c3fSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
1656a5ffed8SMatthias Ringwald static uint16_t l2cap_next_local_cid(void);
1666a5ffed8SMatthias Ringwald static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid);
167836ae835SMatthias Ringwald static void l2cap_emit_simple_event_with_cid(l2cap_channel_t * channel, uint8_t event_code);
168474f5c3fSMatthias Ringwald static void l2cap_dispatch_to_channel(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size);
169474f5c3fSMatthias Ringwald static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid);
1705d18f623SMatthias Ringwald static l2cap_channel_t * l2cap_create_channel_entry(btstack_packet_handler_t packet_handler, l2cap_channel_type_t channel_type, bd_addr_t address, bd_addr_type_t address_type,
171474f5c3fSMatthias Ringwald         uint16_t psm, uint16_t local_mtu, gap_security_level_t security_level);
172c45d6b2cSMatthias Ringwald static void l2cap_free_channel_entry(l2cap_channel_t * channel);
173474f5c3fSMatthias Ringwald #endif
174212b6be2SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
17596646001SMatthias Ringwald static void l2cap_ertm_notify_channel_can_send(l2cap_channel_t * channel);
176c9300dcaSMatthias Ringwald static void l2cap_ertm_monitor_timeout_callback(btstack_timer_source_t * ts);
1778a700052SMatthias Ringwald static void l2cap_ertm_retransmission_timeout_callback(btstack_timer_source_t * ts);
178212b6be2SMatthias Ringwald #endif
17933c40538SMatthias Ringwald 
180fad84cafSMatthias Ringwald // l2cap_fixed_channel_t entries
18124eb964eSMatthias Ringwald #ifdef ENABLE_BLE
182fad84cafSMatthias Ringwald static l2cap_fixed_channel_t l2cap_fixed_channel_att;
183fad84cafSMatthias Ringwald static l2cap_fixed_channel_t l2cap_fixed_channel_sm;
18424eb964eSMatthias Ringwald #endif
18524eb964eSMatthias Ringwald #ifdef ENABLE_CLASSIC
186fad84cafSMatthias Ringwald static l2cap_fixed_channel_t l2cap_fixed_channel_connectionless;
18724eb964eSMatthias Ringwald #endif
1885628cf69SMatthias Ringwald 
18909e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1905628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_services;
19109e9d05bSMatthias Ringwald static uint8_t require_security_level2_for_outgoing_sdp;
192ece97caeSMatthias Ringwald static bd_addr_t l2cap_outgoing_classic_addr;
19309e9d05bSMatthias Ringwald #endif
19457be49d6SMatthias Ringwald 
19557be49d6SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
1965628cf69SMatthias Ringwald static btstack_linked_list_t l2cap_le_services;
19757be49d6SMatthias Ringwald #endif
19839bda6d5Smatthias.ringwald 
199fad84cafSMatthias Ringwald // single list of channels for Classic Channels, LE Data Channels, Classic Connectionless, ATT, and SM
200421cb104SMatthias Ringwald static btstack_linked_list_t l2cap_channels;
2016a5ffed8SMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
2026ddef68dSMilanka Ringwald // next channel id for new connections
2036ddef68dSMilanka Ringwald static uint16_t  local_source_cid  = 0x40;
2046a5ffed8SMatthias Ringwald #endif
2056ddef68dSMilanka Ringwald // next signaling sequence number
2066ddef68dSMilanka Ringwald static uint8_t   sig_seq_nr  = 0xff;
207421cb104SMatthias Ringwald 
20839bda6d5Smatthias.ringwald // used to cache l2cap rejects, echo, and informational requests
2092b83fb7dSmatthias.ringwald static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES];
2102b83fb7dSmatthias.ringwald static int signaling_responses_pending;
211fb37a842SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
21239bda6d5Smatthias.ringwald 
213d6ed9f9cSMatthias Ringwald #ifdef ENABLE_BLE
214d6ed9f9cSMatthias Ringwald // only used for connection parameter update events
215d6ed9f9cSMatthias Ringwald static btstack_packet_handler_t l2cap_event_packet_handler;
21625818320SMatthias Ringwald static uint16_t l2cap_le_custom_max_mtu;
217d6ed9f9cSMatthias Ringwald #endif
218d6ed9f9cSMatthias Ringwald 
21985ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
22085ddcd84SMatthias Ringwald 
221e288be62SMatthias Ringwald // enable for testing
222e288be62SMatthias Ringwald // #define L2CAP_ERTM_SIMULATE_FCS_ERROR_INTERVAL 16
223e288be62SMatthias Ringwald 
22485ddcd84SMatthias Ringwald /*
22585ddcd84SMatthias Ringwald  * CRC lookup table for generator polynom D^16 + D^15 + D^2 + 1
22685ddcd84SMatthias Ringwald  */
22785ddcd84SMatthias Ringwald static const uint16_t crc16_table[256] = {
22885ddcd84SMatthias Ringwald     0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
22985ddcd84SMatthias Ringwald     0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
23085ddcd84SMatthias Ringwald     0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
23185ddcd84SMatthias Ringwald     0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
23285ddcd84SMatthias Ringwald     0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
23385ddcd84SMatthias Ringwald     0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
23485ddcd84SMatthias Ringwald     0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
23585ddcd84SMatthias Ringwald     0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
23685ddcd84SMatthias Ringwald     0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
23785ddcd84SMatthias Ringwald     0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
23885ddcd84SMatthias Ringwald     0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
23985ddcd84SMatthias Ringwald     0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
24085ddcd84SMatthias Ringwald     0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
24185ddcd84SMatthias Ringwald     0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
24285ddcd84SMatthias Ringwald     0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
24385ddcd84SMatthias Ringwald     0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
24485ddcd84SMatthias Ringwald };
24585ddcd84SMatthias Ringwald 
24685ddcd84SMatthias Ringwald static uint16_t crc16_calc(uint8_t * data, uint16_t len){
24785ddcd84SMatthias Ringwald     uint16_t crc = 0;   // initial value = 0
24885ddcd84SMatthias Ringwald     while (len--){
24985ddcd84SMatthias Ringwald         crc = (crc >> 8) ^ crc16_table[ (crc ^ ((uint16_t) *data++)) & 0x00FF ];
25085ddcd84SMatthias Ringwald     }
25185ddcd84SMatthias Ringwald     return crc;
25285ddcd84SMatthias Ringwald }
25385ddcd84SMatthias Ringwald 
254474f5c3fSMatthias 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){
255474f5c3fSMatthias Ringwald     return (((uint16_t) sar) << 14) | (req_seq << 8) | (final << 7) | (tx_seq << 1) | 0;
256474f5c3fSMatthias Ringwald }
257474f5c3fSMatthias Ringwald 
258474f5c3fSMatthias 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){
259474f5c3fSMatthias Ringwald     return (req_seq << 8) | (final << 7) | (poll << 4) | (((int) supervisory_function) << 2) | 1;
260474f5c3fSMatthias Ringwald }
261474f5c3fSMatthias Ringwald 
262474f5c3fSMatthias Ringwald static int l2cap_next_ertm_seq_nr(int seq_nr){
263474f5c3fSMatthias Ringwald     return (seq_nr + 1) & 0x3f;
264474f5c3fSMatthias Ringwald }
265474f5c3fSMatthias Ringwald 
266474f5c3fSMatthias Ringwald static int l2cap_ertm_can_store_packet_now(l2cap_channel_t * channel){
267474f5c3fSMatthias Ringwald     // get num free tx buffers
268a8409e80SMatthias Ringwald     int num_free_tx_buffers = channel->num_tx_buffers - channel->num_stored_tx_frames;
269474f5c3fSMatthias Ringwald     // calculate num tx buffers for remote MTU
270474f5c3fSMatthias Ringwald     int num_tx_buffers_for_max_remote_mtu;
271b90eac91SMatthias Ringwald     uint16_t effective_mps = btstack_min(channel->remote_mps, channel->local_mps);
272b90eac91SMatthias Ringwald     if (channel->remote_mtu <= effective_mps){
273474f5c3fSMatthias Ringwald         // MTU fits into single packet
274474f5c3fSMatthias Ringwald         num_tx_buffers_for_max_remote_mtu = 1;
275474f5c3fSMatthias Ringwald     } else {
276474f5c3fSMatthias Ringwald         // include SDU Length
277b90eac91SMatthias Ringwald         num_tx_buffers_for_max_remote_mtu = (channel->remote_mtu + 2 + (effective_mps - 1)) / effective_mps;
278474f5c3fSMatthias Ringwald     }
279a8409e80SMatthias Ringwald     log_debug("num_free_tx_buffers %u, num_tx_buffers_for_max_remote_mtu %u", num_free_tx_buffers, num_tx_buffers_for_max_remote_mtu);
280474f5c3fSMatthias Ringwald     return num_tx_buffers_for_max_remote_mtu <= num_free_tx_buffers;
281474f5c3fSMatthias Ringwald }
282474f5c3fSMatthias Ringwald 
283ef2faf56SMatthias Ringwald static void l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel_t * l2cap_channel){
284ef2faf56SMatthias Ringwald     log_info("Retransmit unacknowleged frames");
285ef2faf56SMatthias Ringwald     l2cap_channel->unacked_frames = 0;;
286ef2faf56SMatthias Ringwald     l2cap_channel->tx_send_index  = l2cap_channel->tx_read_index;
287ef2faf56SMatthias Ringwald }
288ef2faf56SMatthias Ringwald 
289474f5c3fSMatthias Ringwald static void l2cap_ertm_next_tx_write_index(l2cap_channel_t * channel){
290474f5c3fSMatthias Ringwald     channel->tx_write_index++;
291474f5c3fSMatthias Ringwald     if (channel->tx_write_index < channel->num_tx_buffers) return;
292474f5c3fSMatthias Ringwald     channel->tx_write_index = 0;
293474f5c3fSMatthias Ringwald }
294474f5c3fSMatthias Ringwald 
295474f5c3fSMatthias Ringwald static void l2cap_ertm_start_monitor_timer(l2cap_channel_t * channel){
296550189ffSMatthias Ringwald     log_info("Start Monitor timer");
297474f5c3fSMatthias Ringwald     btstack_run_loop_remove_timer(&channel->monitor_timer);
298474f5c3fSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->monitor_timer, &l2cap_ertm_monitor_timeout_callback);
299474f5c3fSMatthias Ringwald     btstack_run_loop_set_timer_context(&channel->monitor_timer, channel);
300474f5c3fSMatthias Ringwald     btstack_run_loop_set_timer(&channel->monitor_timer, channel->local_monitor_timeout_ms);
301474f5c3fSMatthias Ringwald     btstack_run_loop_add_timer(&channel->monitor_timer);
302474f5c3fSMatthias Ringwald }
303474f5c3fSMatthias Ringwald 
304550189ffSMatthias Ringwald static void l2cap_ertm_stop_monitor_timer(l2cap_channel_t * channel){
305550189ffSMatthias Ringwald     log_info("Stop Monitor timer");
306550189ffSMatthias Ringwald     btstack_run_loop_remove_timer(&channel->monitor_timer);
307550189ffSMatthias Ringwald }
308474f5c3fSMatthias Ringwald 
309474f5c3fSMatthias Ringwald static void l2cap_ertm_start_retransmission_timer(l2cap_channel_t * channel){
310550189ffSMatthias Ringwald     log_info("Start Retransmission timer");
311474f5c3fSMatthias Ringwald     btstack_run_loop_remove_timer(&channel->retransmission_timer);
312474f5c3fSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->retransmission_timer, &l2cap_ertm_retransmission_timeout_callback);
313474f5c3fSMatthias Ringwald     btstack_run_loop_set_timer_context(&channel->retransmission_timer, channel);
314474f5c3fSMatthias Ringwald     btstack_run_loop_set_timer(&channel->retransmission_timer, channel->local_retransmission_timeout_ms);
315474f5c3fSMatthias Ringwald     btstack_run_loop_add_timer(&channel->retransmission_timer);
316474f5c3fSMatthias Ringwald }
317474f5c3fSMatthias Ringwald 
318474f5c3fSMatthias Ringwald static void l2cap_ertm_stop_retransmission_timer(l2cap_channel_t * l2cap_channel){
319550189ffSMatthias Ringwald     log_info("Stop Retransmission timer");
320474f5c3fSMatthias Ringwald     btstack_run_loop_remove_timer(&l2cap_channel->retransmission_timer);
321474f5c3fSMatthias Ringwald }
322474f5c3fSMatthias Ringwald 
323474f5c3fSMatthias Ringwald static void l2cap_ertm_monitor_timeout_callback(btstack_timer_source_t * ts){
324550189ffSMatthias Ringwald     log_info("Monitor timeout");
325474f5c3fSMatthias Ringwald     l2cap_channel_t * l2cap_channel = (l2cap_channel_t *) btstack_run_loop_get_timer_context(ts);
326474f5c3fSMatthias Ringwald 
327474f5c3fSMatthias Ringwald     // TODO: we assume that it's the oldest packet
328474f5c3fSMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state;
329474f5c3fSMatthias Ringwald     tx_state = &l2cap_channel->tx_packets_state[l2cap_channel->tx_read_index];
330474f5c3fSMatthias Ringwald 
331474f5c3fSMatthias Ringwald     // check retry count
332474f5c3fSMatthias Ringwald     if (tx_state->retry_count < l2cap_channel->remote_max_transmit){
333474f5c3fSMatthias Ringwald         // increment retry count
334474f5c3fSMatthias Ringwald         tx_state->retry_count++;
335474f5c3fSMatthias Ringwald 
336ef2faf56SMatthias Ringwald         // start retransmit
337ef2faf56SMatthias Ringwald         l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
338ef2faf56SMatthias Ringwald 
339ef2faf56SMatthias Ringwald         // start monitor timer
340474f5c3fSMatthias Ringwald         l2cap_ertm_start_monitor_timer(l2cap_channel);
341474f5c3fSMatthias Ringwald 
342474f5c3fSMatthias Ringwald         // send RR/P=1
343474f5c3fSMatthias Ringwald         l2cap_channel->send_supervisor_frame_receiver_ready_poll = 1;
344474f5c3fSMatthias Ringwald     } else {
345474f5c3fSMatthias Ringwald         log_info("Monitor timer expired & retry count >= max transmit -> disconnect");
346474f5c3fSMatthias Ringwald         l2cap_channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
347474f5c3fSMatthias Ringwald     }
348474f5c3fSMatthias Ringwald     l2cap_run();
349474f5c3fSMatthias Ringwald }
350474f5c3fSMatthias Ringwald 
351474f5c3fSMatthias Ringwald static void l2cap_ertm_retransmission_timeout_callback(btstack_timer_source_t * ts){
352550189ffSMatthias Ringwald     log_info("Retransmission timeout");
353474f5c3fSMatthias Ringwald     l2cap_channel_t * l2cap_channel = (l2cap_channel_t *) btstack_run_loop_get_timer_context(ts);
354474f5c3fSMatthias Ringwald 
355474f5c3fSMatthias Ringwald     // TODO: we assume that it's the oldest packet
356474f5c3fSMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state;
357474f5c3fSMatthias Ringwald     tx_state = &l2cap_channel->tx_packets_state[l2cap_channel->tx_read_index];
358474f5c3fSMatthias Ringwald 
359474f5c3fSMatthias Ringwald     // set retry count = 1
360474f5c3fSMatthias Ringwald     tx_state->retry_count = 1;
361474f5c3fSMatthias Ringwald 
362ef2faf56SMatthias Ringwald     // start retransmit
363ef2faf56SMatthias Ringwald     l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
364ef2faf56SMatthias Ringwald 
365474f5c3fSMatthias Ringwald     // start monitor timer
366474f5c3fSMatthias Ringwald     l2cap_ertm_start_monitor_timer(l2cap_channel);
367474f5c3fSMatthias Ringwald 
368474f5c3fSMatthias Ringwald     // send RR/P=1
369474f5c3fSMatthias Ringwald     l2cap_channel->send_supervisor_frame_receiver_ready_poll = 1;
370474f5c3fSMatthias Ringwald     l2cap_run();
371474f5c3fSMatthias Ringwald }
372474f5c3fSMatthias Ringwald 
373474f5c3fSMatthias Ringwald static int l2cap_ertm_send_information_frame(l2cap_channel_t * channel, int index, int final){
374474f5c3fSMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state = &channel->tx_packets_state[index];
375474f5c3fSMatthias Ringwald     hci_reserve_packet_buffer();
376474f5c3fSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
377474f5c3fSMatthias Ringwald     uint16_t control = l2cap_encanced_control_field_for_information_frame(tx_state->tx_seq, final, channel->req_seq, tx_state->sar);
378474f5c3fSMatthias Ringwald     log_info("I-Frame: control 0x%04x", control);
379474f5c3fSMatthias Ringwald     little_endian_store_16(acl_buffer, 8, control);
3803b81f0d3SMatthias Ringwald     memcpy(&acl_buffer[8+2], &channel->tx_packets_data[index * channel->local_mps], tx_state->len);
3811e1a46bbSMatthias Ringwald     // (re-)start retransmission timer on
3821e1a46bbSMatthias Ringwald     l2cap_ertm_start_retransmission_timer(channel);
383474f5c3fSMatthias Ringwald     // send
384474f5c3fSMatthias Ringwald     return l2cap_send_prepared(channel->local_cid, 2 + tx_state->len);
385474f5c3fSMatthias Ringwald }
386474f5c3fSMatthias Ringwald 
387474f5c3fSMatthias 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){
388474f5c3fSMatthias Ringwald     // get next index for storing packets
389474f5c3fSMatthias Ringwald     int index = channel->tx_write_index;
390474f5c3fSMatthias Ringwald 
391474f5c3fSMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state = &channel->tx_packets_state[index];
392474f5c3fSMatthias Ringwald     tx_state->tx_seq = channel->next_tx_seq;
393474f5c3fSMatthias Ringwald     tx_state->sar = sar;
394474f5c3fSMatthias Ringwald     tx_state->retry_count = 0;
395474f5c3fSMatthias Ringwald 
3963b81f0d3SMatthias Ringwald     uint8_t * tx_packet = &channel->tx_packets_data[index * channel->local_mps];
397b90eac91SMatthias Ringwald     log_debug("index %u, local mps %u, remote mps %u, packet tx %p, len %u", index, channel->local_mps, channel->remote_mps, tx_packet, len);
398474f5c3fSMatthias Ringwald     int pos = 0;
399474f5c3fSMatthias Ringwald     if (sar == L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU){
400474f5c3fSMatthias Ringwald         little_endian_store_16(tx_packet, 0, sdu_length);
401474f5c3fSMatthias Ringwald         pos += 2;
402474f5c3fSMatthias Ringwald     }
403474f5c3fSMatthias Ringwald     memcpy(&tx_packet[pos], data, len);
404b90eac91SMatthias Ringwald     tx_state->len = pos + len;
405474f5c3fSMatthias Ringwald 
406474f5c3fSMatthias Ringwald     // update
407a8409e80SMatthias Ringwald     channel->num_stored_tx_frames++;
408474f5c3fSMatthias Ringwald     channel->next_tx_seq = l2cap_next_ertm_seq_nr(channel->next_tx_seq);
409474f5c3fSMatthias Ringwald     l2cap_ertm_next_tx_write_index(channel);
41094301352SMatthias Ringwald 
411a8409e80SMatthias Ringwald     log_info("l2cap_ertm_store_fragment: tx_read_index %u, tx_write_index %u, num stored %u", channel->tx_read_index, channel->tx_write_index, channel->num_stored_tx_frames);
41294301352SMatthias Ringwald 
413474f5c3fSMatthias Ringwald }
414474f5c3fSMatthias Ringwald 
415474f5c3fSMatthias Ringwald static int l2cap_ertm_send(l2cap_channel_t * channel, uint8_t * data, uint16_t len){
416474f5c3fSMatthias Ringwald     if (len > channel->remote_mtu){
417a8409e80SMatthias Ringwald         log_error("l2cap_ertm_send cid 0x%02x, data length exceeds remote MTU.", channel->local_cid);
418474f5c3fSMatthias Ringwald         return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU;
419474f5c3fSMatthias Ringwald     }
420474f5c3fSMatthias Ringwald 
421a8409e80SMatthias Ringwald     if (!l2cap_ertm_can_store_packet_now(channel)){
422a8409e80SMatthias Ringwald         log_error("l2cap_ertm_send cid 0x%02x, fragment store full", channel->local_cid);
423a8409e80SMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
424a8409e80SMatthias Ringwald     }
425a8409e80SMatthias Ringwald 
426474f5c3fSMatthias Ringwald     // check if it needs to get fragmented
427b90eac91SMatthias Ringwald     uint16_t effective_mps = btstack_min(channel->remote_mps, channel->local_mps);
428b90eac91SMatthias Ringwald     if (len > effective_mps){
429474f5c3fSMatthias Ringwald         // fragmentation needed.
430474f5c3fSMatthias Ringwald         l2cap_segmentation_and_reassembly_t sar =  L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU;
431474f5c3fSMatthias Ringwald         int chunk_len;
432474f5c3fSMatthias Ringwald         while (len){
433474f5c3fSMatthias Ringwald             switch (sar){
434474f5c3fSMatthias Ringwald                 case L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU:
435b90eac91SMatthias Ringwald                     chunk_len = effective_mps - 2;    // sdu_length
436474f5c3fSMatthias Ringwald                     l2cap_ertm_store_fragment(channel, sar, len, data, chunk_len);
437474f5c3fSMatthias Ringwald                     len -= chunk_len;
438474f5c3fSMatthias Ringwald                     sar = L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU;
439474f5c3fSMatthias Ringwald                     break;
440474f5c3fSMatthias Ringwald                 case L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU:
441b90eac91SMatthias Ringwald                     chunk_len = effective_mps;
442474f5c3fSMatthias Ringwald                     if (chunk_len >= len){
443474f5c3fSMatthias Ringwald                         sar = L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU;
444474f5c3fSMatthias Ringwald                         chunk_len = len;
445474f5c3fSMatthias Ringwald                     }
446474f5c3fSMatthias Ringwald                     l2cap_ertm_store_fragment(channel, sar, len, data, chunk_len);
447474f5c3fSMatthias Ringwald                     len -= chunk_len;
448474f5c3fSMatthias Ringwald                     break;
449474f5c3fSMatthias Ringwald                 default:
450474f5c3fSMatthias Ringwald                     break;
451474f5c3fSMatthias Ringwald             }
452474f5c3fSMatthias Ringwald         }
453474f5c3fSMatthias Ringwald 
454474f5c3fSMatthias Ringwald     } else {
455474f5c3fSMatthias Ringwald         l2cap_ertm_store_fragment(channel, L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU, 0, data, len);
456474f5c3fSMatthias Ringwald     }
457474f5c3fSMatthias Ringwald 
458474f5c3fSMatthias Ringwald     // try to send
459474f5c3fSMatthias Ringwald     l2cap_run();
460474f5c3fSMatthias Ringwald     return 0;
461474f5c3fSMatthias Ringwald }
462474f5c3fSMatthias Ringwald 
4637cbe539fSMatthias Ringwald static uint16_t l2cap_setup_options_ertm_request(l2cap_channel_t * channel, uint8_t * config_options){
464fcb125edSMatthias Ringwald     int pos = 0;
465fcb125edSMatthias Ringwald     config_options[pos++] = L2CAP_CONFIG_OPTION_TYPE_RETRANSMISSION_AND_FLOW_CONTROL;
466fcb125edSMatthias Ringwald     config_options[pos++] = 9;      // length
467fcb125edSMatthias Ringwald     config_options[pos++] = (uint8_t) channel->mode;
468fcb125edSMatthias Ringwald     config_options[pos++] = channel->num_rx_buffers;    // == TxWindows size
469fcb125edSMatthias Ringwald     config_options[pos++] = channel->local_max_transmit;
470fcb125edSMatthias Ringwald     little_endian_store_16( config_options, pos, channel->local_retransmission_timeout_ms);
471fcb125edSMatthias Ringwald     pos += 2;
472fcb125edSMatthias Ringwald     little_endian_store_16( config_options, pos, channel->local_monitor_timeout_ms);
473fcb125edSMatthias Ringwald     pos += 2;
474fcb125edSMatthias Ringwald     little_endian_store_16( config_options, pos, channel->local_mps);
475fcb125edSMatthias Ringwald     pos += 2;
4766574158aSMatthias Ringwald     //
477fcb125edSMatthias Ringwald     config_options[pos++] = L2CAP_CONFIG_OPTION_TYPE_MAX_TRANSMISSION_UNIT;
478fcb125edSMatthias Ringwald     config_options[pos++] = 2;     // length
479fcb125edSMatthias Ringwald     little_endian_store_16(config_options, pos, channel->local_mtu);
480fcb125edSMatthias Ringwald     pos += 2;
481c425ea4aSMatthias Ringwald 
482c425ea4aSMatthias Ringwald     // Issue: iOS (e.g. 10.2) uses "No FCS" as default while Core 5.0 specifies "FCS" as default
483c425ea4aSMatthias Ringwald     // Workaround: try to actively negotiate FCS option
484fcb125edSMatthias Ringwald     config_options[pos++] = L2CAP_CONFIG_OPTION_TYPE_FRAME_CHECK_SEQUENCE;
485fcb125edSMatthias Ringwald     config_options[pos++] = 1;     // length
486fcb125edSMatthias Ringwald     config_options[pos++] = channel->fcs_option;
487f2c70799Sandryblack     return pos; // 11+4+3=18
488474f5c3fSMatthias Ringwald }
489474f5c3fSMatthias Ringwald 
4907cbe539fSMatthias Ringwald static uint16_t l2cap_setup_options_ertm_response(l2cap_channel_t * channel, uint8_t * config_options){
491fcb125edSMatthias Ringwald     int pos = 0;
492fcb125edSMatthias Ringwald     config_options[pos++] = L2CAP_CONFIG_OPTION_TYPE_RETRANSMISSION_AND_FLOW_CONTROL;
493fcb125edSMatthias Ringwald     config_options[pos++] = 9;      // length
494fcb125edSMatthias Ringwald     config_options[pos++] = (uint8_t) channel->mode;
4957cbe539fSMatthias Ringwald     // less or equal to remote tx window size
496fcb125edSMatthias Ringwald     config_options[pos++] = btstack_min(channel->num_tx_buffers, channel->remote_tx_window_size);
4977cbe539fSMatthias Ringwald     // max transmit in response shall be ignored -> use sender values
498fcb125edSMatthias Ringwald     config_options[pos++] = channel->remote_max_transmit;
4997cbe539fSMatthias Ringwald     // A value for the Retransmission time-out shall be sent in a positive Configuration Response
5007cbe539fSMatthias Ringwald     // and indicates the value that will be used by the sender of the Configuration Response -> use our value
501fcb125edSMatthias Ringwald     little_endian_store_16( config_options, pos, channel->local_retransmission_timeout_ms);
502fcb125edSMatthias Ringwald     pos += 2;
5037cbe539fSMatthias Ringwald     // A value for the Monitor time-out shall be sent in a positive Configuration Response
5047cbe539fSMatthias Ringwald     // and indicates the value that will be used by the sender of the Configuration Response -> use our value
505fcb125edSMatthias Ringwald     little_endian_store_16( config_options, pos, channel->local_monitor_timeout_ms);
506fcb125edSMatthias Ringwald     pos += 2;
5077cbe539fSMatthias Ringwald     // less or equal to remote mps
508b90eac91SMatthias Ringwald     uint16_t effective_mps = btstack_min(channel->remote_mps, channel->local_mps);
509b90eac91SMatthias Ringwald     little_endian_store_16( config_options, pos, effective_mps);
510fcb125edSMatthias Ringwald     pos += 2;
5116574158aSMatthias Ringwald     //
512fcb125edSMatthias Ringwald     config_options[pos++] = L2CAP_CONFIG_OPTION_TYPE_MAX_TRANSMISSION_UNIT; // MTU
513fcb125edSMatthias Ringwald     config_options[pos++] = 2;     // length
514fcb125edSMatthias Ringwald     little_endian_store_16(config_options, pos, channel->remote_mtu);
515fcb125edSMatthias Ringwald     pos += 2;
516fcb125edSMatthias Ringwald #if 0
517d64e9771SMatthias Ringwald     //
518fcb125edSMatthias Ringwald     config_options[pos++] = L2CAP_CONFIG_OPTION_TYPE_FRAME_CHECK_SEQUENCE;
519fcb125edSMatthias Ringwald     config_options[pos++] = 1;     // length
520fcb125edSMatthias Ringwald     config_options[pos++] = channel->fcs_option;
521fcb125edSMatthias Ringwald #endif
522f2c70799Sandryblack     return pos; // 11+4=15
5237cbe539fSMatthias Ringwald }
5247cbe539fSMatthias Ringwald 
525474f5c3fSMatthias Ringwald static int l2cap_ertm_send_supervisor_frame(l2cap_channel_t * channel, uint16_t control){
526474f5c3fSMatthias Ringwald     hci_reserve_packet_buffer();
527474f5c3fSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
528474f5c3fSMatthias Ringwald     log_info("S-Frame: control 0x%04x", control);
529474f5c3fSMatthias Ringwald     little_endian_store_16(acl_buffer, 8, control);
530474f5c3fSMatthias Ringwald     return l2cap_send_prepared(channel->local_cid, 2);
531474f5c3fSMatthias Ringwald }
532474f5c3fSMatthias Ringwald 
5335774a392SMatthias Ringwald static uint8_t l2cap_ertm_validate_local_config(l2cap_ertm_config_t * ertm_config){
534474f5c3fSMatthias Ringwald 
535474f5c3fSMatthias Ringwald     uint8_t result = ERROR_CODE_SUCCESS;
5369c0e62d3SMatthias Ringwald     if (ertm_config->max_transmit < 1){
537474f5c3fSMatthias Ringwald         log_error("max_transmit must be >= 1");
538474f5c3fSMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
539474f5c3fSMatthias Ringwald     }
5409c0e62d3SMatthias Ringwald     if (ertm_config->retransmission_timeout_ms < 2000){
541474f5c3fSMatthias Ringwald         log_error("retransmission_timeout_ms must be >= 2000 ms");
542474f5c3fSMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
543474f5c3fSMatthias Ringwald     }
5449c0e62d3SMatthias Ringwald     if (ertm_config->monitor_timeout_ms < 12000){
545474f5c3fSMatthias Ringwald         log_error("monitor_timeout_ms must be >= 12000 ms");
546474f5c3fSMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
547474f5c3fSMatthias Ringwald     }
5489c0e62d3SMatthias Ringwald     if (ertm_config->local_mtu < 48){
549474f5c3fSMatthias Ringwald         log_error("local_mtu must be >= 48");
550474f5c3fSMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
551474f5c3fSMatthias Ringwald     }
5529c0e62d3SMatthias Ringwald     if (ertm_config->num_rx_buffers < 1){
553474f5c3fSMatthias Ringwald         log_error("num_rx_buffers must be >= 1");
554474f5c3fSMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
555474f5c3fSMatthias Ringwald     }
5569c0e62d3SMatthias Ringwald     if (ertm_config->num_tx_buffers < 1){
557474f5c3fSMatthias Ringwald         log_error("num_rx_buffers must be >= 1");
558474f5c3fSMatthias Ringwald         result = ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS;
559474f5c3fSMatthias Ringwald     }
560474f5c3fSMatthias Ringwald     return result;
561474f5c3fSMatthias Ringwald }
562474f5c3fSMatthias Ringwald 
5639c0e62d3SMatthias Ringwald static void l2cap_ertm_configure_channel(l2cap_channel_t * channel, l2cap_ertm_config_t * ertm_config, uint8_t * buffer, uint32_t size){
564474f5c3fSMatthias Ringwald 
565474f5c3fSMatthias Ringwald     channel->mode  = L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION;
5669c0e62d3SMatthias Ringwald     channel->ertm_mandatory = ertm_config->ertm_mandatory;
5679c0e62d3SMatthias Ringwald     channel->local_max_transmit = ertm_config->max_transmit;
5689c0e62d3SMatthias Ringwald     channel->local_retransmission_timeout_ms = ertm_config->retransmission_timeout_ms;
5699c0e62d3SMatthias Ringwald     channel->local_monitor_timeout_ms = ertm_config->monitor_timeout_ms;
5709c0e62d3SMatthias Ringwald     channel->local_mtu = ertm_config->local_mtu;
5719c0e62d3SMatthias Ringwald     channel->num_rx_buffers = ertm_config->num_rx_buffers;
5729c0e62d3SMatthias Ringwald     channel->num_tx_buffers = ertm_config->num_tx_buffers;
573474f5c3fSMatthias Ringwald 
574c342091bSMatthias Ringwald     // align buffer to 16-byte boundary to assert l2cap_ertm_rx_packet_state_t is aligned
575474f5c3fSMatthias Ringwald     int bytes_till_alignment = 16 - (((uintptr_t) buffer) & 0x0f);
576474f5c3fSMatthias Ringwald     buffer += bytes_till_alignment;
577474f5c3fSMatthias Ringwald     size   -= bytes_till_alignment;
578474f5c3fSMatthias Ringwald 
579c342091bSMatthias Ringwald     // setup state buffers - use void cast to avoid -Wcast-align warning
580474f5c3fSMatthias Ringwald     uint32_t pos = 0;
581c342091bSMatthias Ringwald     channel->rx_packets_state = (l2cap_ertm_rx_packet_state_t *) (void *) &buffer[pos];
5829c0e62d3SMatthias Ringwald     pos += ertm_config->num_rx_buffers * sizeof(l2cap_ertm_rx_packet_state_t);
583c342091bSMatthias Ringwald     channel->tx_packets_state = (l2cap_ertm_tx_packet_state_t *) (void *) &buffer[pos];
5849c0e62d3SMatthias Ringwald     pos += ertm_config->num_tx_buffers * sizeof(l2cap_ertm_tx_packet_state_t);
585474f5c3fSMatthias Ringwald 
586474f5c3fSMatthias Ringwald     // setup reassembly buffer
587474f5c3fSMatthias Ringwald     channel->reassembly_buffer = &buffer[pos];
5889c0e62d3SMatthias Ringwald     pos += ertm_config->local_mtu;
589474f5c3fSMatthias Ringwald 
590474f5c3fSMatthias Ringwald     // divide rest of data equally
5919c0e62d3SMatthias Ringwald     channel->local_mps = (size - pos) / (ertm_config->num_rx_buffers + ertm_config->num_tx_buffers);
5920d3ee2efSMatthias Ringwald     log_info("Local MPS: %u", channel->local_mps);
593474f5c3fSMatthias Ringwald     channel->rx_packets_data = &buffer[pos];
5940d3ee2efSMatthias Ringwald     pos += ertm_config->num_rx_buffers * channel->local_mps;
595474f5c3fSMatthias Ringwald     channel->tx_packets_data = &buffer[pos];
5966574158aSMatthias Ringwald 
597c425ea4aSMatthias Ringwald     channel->fcs_option = ertm_config->fcs_option;
598474f5c3fSMatthias Ringwald }
599474f5c3fSMatthias Ringwald 
600474f5c3fSMatthias Ringwald uint8_t l2cap_create_ertm_channel(btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm,
6019c0e62d3SMatthias Ringwald     l2cap_ertm_config_t * ertm_config, uint8_t * buffer, uint32_t size, uint16_t * out_local_cid){
602474f5c3fSMatthias Ringwald 
6039c0e62d3SMatthias Ringwald     log_info("L2CAP_CREATE_ERTM_CHANNEL addr %s, psm 0x%x, local mtu %u", bd_addr_to_str(address), psm, ertm_config->local_mtu);
604474f5c3fSMatthias Ringwald 
605474f5c3fSMatthias Ringwald     // validate local config
6065774a392SMatthias Ringwald     uint8_t result = l2cap_ertm_validate_local_config(ertm_config);
607474f5c3fSMatthias Ringwald     if (result) return result;
608474f5c3fSMatthias Ringwald 
609f16129ceSMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(packet_handler, L2CAP_CHANNEL_TYPE_CLASSIC, address, BD_ADDR_TYPE_ACL, psm, ertm_config->local_mtu, LEVEL_0);
610474f5c3fSMatthias Ringwald     if (!channel) {
611474f5c3fSMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
612474f5c3fSMatthias Ringwald     }
613474f5c3fSMatthias Ringwald 
614474f5c3fSMatthias Ringwald     // configure ERTM
6159c0e62d3SMatthias Ringwald     l2cap_ertm_configure_channel(channel, ertm_config, buffer, size);
616474f5c3fSMatthias Ringwald 
617474f5c3fSMatthias Ringwald     // add to connections list
618474f5c3fSMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
619474f5c3fSMatthias Ringwald 
620474f5c3fSMatthias Ringwald     // store local_cid
621474f5c3fSMatthias Ringwald     if (out_local_cid){
622474f5c3fSMatthias Ringwald        *out_local_cid = channel->local_cid;
623474f5c3fSMatthias Ringwald     }
624474f5c3fSMatthias Ringwald 
625474f5c3fSMatthias Ringwald     // check if hci connection is already usable
626f16129ceSMatthias Ringwald     hci_connection_t * conn = hci_connection_for_bd_addr_and_type(address, BD_ADDR_TYPE_ACL);
627474f5c3fSMatthias Ringwald     if (conn){
628474f5c3fSMatthias Ringwald         log_info("l2cap_create_channel, hci connection already exists");
629474f5c3fSMatthias Ringwald         l2cap_handle_connection_complete(conn->con_handle, channel);
630474f5c3fSMatthias Ringwald         // check if remote supported fearures are already received
631474f5c3fSMatthias Ringwald         if (conn->bonding_flags & BONDING_RECEIVED_REMOTE_FEATURES) {
632474f5c3fSMatthias Ringwald             l2cap_handle_remote_supported_features_received(channel);
633474f5c3fSMatthias Ringwald         }
634474f5c3fSMatthias Ringwald     }
635474f5c3fSMatthias Ringwald 
636474f5c3fSMatthias Ringwald     l2cap_run();
637474f5c3fSMatthias Ringwald 
638474f5c3fSMatthias Ringwald     return 0;
639474f5c3fSMatthias Ringwald }
640474f5c3fSMatthias Ringwald 
641474f5c3fSMatthias Ringwald static void l2cap_ertm_notify_channel_can_send(l2cap_channel_t * channel){
642474f5c3fSMatthias Ringwald     if (l2cap_ertm_can_store_packet_now(channel)){
643474f5c3fSMatthias Ringwald         channel->waiting_for_can_send_now = 0;
644474f5c3fSMatthias Ringwald         l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid);
645474f5c3fSMatthias Ringwald     }
646474f5c3fSMatthias Ringwald }
647474f5c3fSMatthias Ringwald 
6489c0e62d3SMatthias Ringwald uint8_t l2cap_accept_ertm_connection(uint16_t local_cid, l2cap_ertm_config_t * ertm_config, uint8_t * buffer, uint32_t size){
649474f5c3fSMatthias Ringwald 
650474f5c3fSMatthias Ringwald     log_info("L2CAP_ACCEPT_ERTM_CONNECTION local_cid 0x%x", local_cid);
651f68b21d7SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
652474f5c3fSMatthias Ringwald     if (!channel) {
653474f5c3fSMatthias Ringwald         log_error("l2cap_accept_connection called but local_cid 0x%x not found", local_cid);
654474f5c3fSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
655474f5c3fSMatthias Ringwald     }
656474f5c3fSMatthias Ringwald 
657474f5c3fSMatthias Ringwald     // validate local config
6585774a392SMatthias Ringwald     uint8_t result = l2cap_ertm_validate_local_config(ertm_config);
659474f5c3fSMatthias Ringwald     if (result) return result;
660474f5c3fSMatthias Ringwald 
661474f5c3fSMatthias Ringwald     // configure L2CAP ERTM
6629c0e62d3SMatthias Ringwald     l2cap_ertm_configure_channel(channel, ertm_config, buffer, size);
663474f5c3fSMatthias Ringwald 
664836ae835SMatthias Ringwald     // default: continue
665474f5c3fSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
666474f5c3fSMatthias Ringwald 
6678b7155e0SMatthias Ringwald     // verify remote ERTM support
668836ae835SMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
669836ae835SMatthias Ringwald     if (connection == NULL) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
670836ae835SMatthias Ringwald 
671836ae835SMatthias Ringwald     if ((channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION) && ((connection->l2cap_state.extended_feature_mask & 0x08) == 0)){
6728b7155e0SMatthias Ringwald         // ERTM not possible, select basic mode and release buffer
6738b7155e0SMatthias Ringwald         channel->mode = L2CAP_CHANNEL_MODE_BASIC;
6748b7155e0SMatthias Ringwald         l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_ERTM_BUFFER_RELEASED);
675836ae835SMatthias Ringwald 
6768b7155e0SMatthias Ringwald         // bail if ERTM is mandatory
677836ae835SMatthias Ringwald         if (channel->ertm_mandatory){
678836ae835SMatthias Ringwald             // We chose 'no resources available' for "ERTM mandatory but you don't even know ERTM exists"
6798b7155e0SMatthias Ringwald             log_info("ERTM mandatory -> reject connection");
680836ae835SMatthias Ringwald             channel->state  = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
681836ae835SMatthias Ringwald             channel->reason = 0x04; // no resources available
6828b7155e0SMatthias Ringwald         }  else {
6838b7155e0SMatthias Ringwald             log_info("ERTM not supported by remote -> use Basic mode");
684836ae835SMatthias Ringwald         }
685836ae835SMatthias Ringwald     }
686836ae835SMatthias Ringwald 
687474f5c3fSMatthias Ringwald     // process
688474f5c3fSMatthias Ringwald     l2cap_run();
689474f5c3fSMatthias Ringwald 
690474f5c3fSMatthias Ringwald     return ERROR_CODE_SUCCESS;
691474f5c3fSMatthias Ringwald }
692474f5c3fSMatthias Ringwald 
693474f5c3fSMatthias Ringwald uint8_t l2cap_ertm_set_busy(uint16_t local_cid){
694f68b21d7SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
695474f5c3fSMatthias Ringwald     if (!channel) {
696474f5c3fSMatthias Ringwald         log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
697474f5c3fSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
698474f5c3fSMatthias Ringwald     }
699474f5c3fSMatthias Ringwald     if (!channel->local_busy){
700474f5c3fSMatthias Ringwald         channel->local_busy = 1;
701474f5c3fSMatthias Ringwald         channel->send_supervisor_frame_receiver_not_ready = 1;
702474f5c3fSMatthias Ringwald         l2cap_run();
703474f5c3fSMatthias Ringwald     }
704474f5c3fSMatthias Ringwald     return ERROR_CODE_SUCCESS;
705474f5c3fSMatthias Ringwald }
706474f5c3fSMatthias Ringwald 
707474f5c3fSMatthias Ringwald uint8_t l2cap_ertm_set_ready(uint16_t local_cid){
708f68b21d7SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
709474f5c3fSMatthias Ringwald     if (!channel) {
710474f5c3fSMatthias Ringwald         log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
711474f5c3fSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
712474f5c3fSMatthias Ringwald     }
713474f5c3fSMatthias Ringwald     if (channel->local_busy){
714474f5c3fSMatthias Ringwald         channel->local_busy = 0;
715474f5c3fSMatthias Ringwald         channel->send_supervisor_frame_receiver_ready_poll = 1;
716474f5c3fSMatthias Ringwald         l2cap_run();
717474f5c3fSMatthias Ringwald     }
718474f5c3fSMatthias Ringwald     return ERROR_CODE_SUCCESS;
719474f5c3fSMatthias Ringwald }
720474f5c3fSMatthias Ringwald 
7211e1a46bbSMatthias Ringwald // Process-ReqSeq
7221e1a46bbSMatthias Ringwald static void l2cap_ertm_process_req_seq(l2cap_channel_t * l2cap_channel, uint8_t req_seq){
723474f5c3fSMatthias Ringwald     int num_buffers_acked = 0;
724474f5c3fSMatthias Ringwald     l2cap_ertm_tx_packet_state_t * tx_state;
72594301352SMatthias Ringwald     log_info("l2cap_ertm_process_req_seq: tx_read_index %u, tx_write_index %u, req_seq %u", l2cap_channel->tx_read_index, l2cap_channel->tx_write_index, req_seq);
726474f5c3fSMatthias Ringwald     while (1){
7271e1a46bbSMatthias Ringwald 
72894301352SMatthias Ringwald         // no unack packets left
72994301352SMatthias Ringwald         if (l2cap_channel->unacked_frames == 0) {
7301e1a46bbSMatthias Ringwald             // stop retransmission timer
7311e1a46bbSMatthias Ringwald             l2cap_ertm_stop_retransmission_timer(l2cap_channel);
7321e1a46bbSMatthias Ringwald             break;
7331e1a46bbSMatthias Ringwald         }
7341e1a46bbSMatthias Ringwald 
735474f5c3fSMatthias Ringwald         tx_state = &l2cap_channel->tx_packets_state[l2cap_channel->tx_read_index];
736474f5c3fSMatthias Ringwald         // calc delta
737474f5c3fSMatthias Ringwald         int delta = (req_seq - tx_state->tx_seq) & 0x03f;
738474f5c3fSMatthias Ringwald         if (delta == 0) break;  // all packets acknowledged
739474f5c3fSMatthias Ringwald         if (delta > l2cap_channel->remote_tx_window_size) break;
740474f5c3fSMatthias Ringwald 
741474f5c3fSMatthias Ringwald         num_buffers_acked++;
742a8409e80SMatthias Ringwald         l2cap_channel->num_stored_tx_frames--;
74394301352SMatthias Ringwald         l2cap_channel->unacked_frames--;
744474f5c3fSMatthias Ringwald         log_info("RR seq %u => packet with tx_seq %u done", req_seq, tx_state->tx_seq);
745474f5c3fSMatthias Ringwald 
746474f5c3fSMatthias Ringwald         l2cap_channel->tx_read_index++;
747474f5c3fSMatthias Ringwald         if (l2cap_channel->tx_read_index >= l2cap_channel->num_rx_buffers){
748474f5c3fSMatthias Ringwald             l2cap_channel->tx_read_index = 0;
749474f5c3fSMatthias Ringwald         }
750474f5c3fSMatthias Ringwald     }
751474f5c3fSMatthias Ringwald     if (num_buffers_acked){
752a8409e80SMatthias Ringwald         log_info("num_buffers_acked %u", num_buffers_acked);
753474f5c3fSMatthias Ringwald     l2cap_ertm_notify_channel_can_send(l2cap_channel);
754474f5c3fSMatthias Ringwald }
755474f5c3fSMatthias Ringwald }
756474f5c3fSMatthias Ringwald 
757474f5c3fSMatthias Ringwald static l2cap_ertm_tx_packet_state_t * l2cap_ertm_get_tx_state(l2cap_channel_t * l2cap_channel, uint8_t tx_seq){
758474f5c3fSMatthias Ringwald     int i;
759474f5c3fSMatthias Ringwald     for (i=0;i<l2cap_channel->num_tx_buffers;i++){
760474f5c3fSMatthias Ringwald         l2cap_ertm_tx_packet_state_t * tx_state = &l2cap_channel->tx_packets_state[i];
761474f5c3fSMatthias Ringwald         if (tx_state->tx_seq == tx_seq) return tx_state;
762474f5c3fSMatthias Ringwald     }
763474f5c3fSMatthias Ringwald     return NULL;
764474f5c3fSMatthias Ringwald }
765474f5c3fSMatthias Ringwald 
766474f5c3fSMatthias Ringwald // @param delta number of frames in the future, >= 1
767122c2b05SMatthias Ringwald // @assumption size <= l2cap_channel->local_mps (checked in l2cap_acl_classic_handler)
7683d244bfaSMatthias Ringwald static void l2cap_ertm_handle_out_of_sequence_sdu(l2cap_channel_t * l2cap_channel, l2cap_segmentation_and_reassembly_t sar, int delta, const uint8_t * payload, uint16_t size){
769474f5c3fSMatthias Ringwald     log_info("Store SDU with delta %u", delta);
770474f5c3fSMatthias Ringwald     // get rx state for packet to store
771474f5c3fSMatthias Ringwald     int index = l2cap_channel->rx_store_index + delta - 1;
772474f5c3fSMatthias Ringwald     if (index > l2cap_channel->num_rx_buffers){
773474f5c3fSMatthias Ringwald         index -= l2cap_channel->num_rx_buffers;
774474f5c3fSMatthias Ringwald     }
775474f5c3fSMatthias Ringwald     log_info("Index of packet to store %u", index);
776474f5c3fSMatthias Ringwald     l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
777474f5c3fSMatthias Ringwald     // check if buffer is free
778474f5c3fSMatthias Ringwald     if (rx_state->valid){
779474f5c3fSMatthias Ringwald         log_error("Packet buffer already used");
780474f5c3fSMatthias Ringwald         return;
781474f5c3fSMatthias Ringwald     }
782474f5c3fSMatthias Ringwald     rx_state->valid = 1;
783474f5c3fSMatthias Ringwald     rx_state->sar = sar;
784474f5c3fSMatthias Ringwald     rx_state->len = size;
785474f5c3fSMatthias Ringwald     uint8_t * rx_buffer = &l2cap_channel->rx_packets_data[index];
786474f5c3fSMatthias Ringwald     memcpy(rx_buffer, payload, size);
787474f5c3fSMatthias Ringwald }
788474f5c3fSMatthias Ringwald 
789122c2b05SMatthias Ringwald // @assumption size <= l2cap_channel->local_mps (checked in l2cap_acl_classic_handler)
7903d244bfaSMatthias Ringwald static void l2cap_ertm_handle_in_sequence_sdu(l2cap_channel_t * l2cap_channel, l2cap_segmentation_and_reassembly_t sar, const uint8_t * payload, uint16_t size){
791122c2b05SMatthias Ringwald     uint16_t reassembly_sdu_length;
792474f5c3fSMatthias Ringwald     switch (sar){
793474f5c3fSMatthias Ringwald         case L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU:
794122c2b05SMatthias Ringwald             // assert total packet size <= our mtu
795122c2b05SMatthias Ringwald             if (size > l2cap_channel->local_mtu) break;
796474f5c3fSMatthias Ringwald             // packet complete -> disapatch
7973d244bfaSMatthias Ringwald             l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, (uint8_t*) payload, size);
798474f5c3fSMatthias Ringwald             break;
799474f5c3fSMatthias Ringwald         case L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU:
800122c2b05SMatthias Ringwald             // read SDU len
801122c2b05SMatthias Ringwald             reassembly_sdu_length = little_endian_read_16(payload, 0);
802474f5c3fSMatthias Ringwald             payload += 2;
803474f5c3fSMatthias Ringwald             size    -= 2;
804122c2b05SMatthias Ringwald             // assert reassembled size <= our mtu
805122c2b05SMatthias Ringwald             if (reassembly_sdu_length > l2cap_channel->local_mtu) break;
806122c2b05SMatthias Ringwald             // store start segment
807122c2b05SMatthias Ringwald             l2cap_channel->reassembly_sdu_length = reassembly_sdu_length;
808474f5c3fSMatthias Ringwald             memcpy(&l2cap_channel->reassembly_buffer[0], payload, size);
809474f5c3fSMatthias Ringwald             l2cap_channel->reassembly_pos = size;
810474f5c3fSMatthias Ringwald             break;
811474f5c3fSMatthias Ringwald         case L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU:
812122c2b05SMatthias Ringwald             // assert size of reassembled data <= our mtu
813122c2b05SMatthias Ringwald             if (l2cap_channel->reassembly_pos + size > l2cap_channel->local_mtu) break;
814122c2b05SMatthias Ringwald             // store continuation segment
815474f5c3fSMatthias Ringwald             memcpy(&l2cap_channel->reassembly_buffer[l2cap_channel->reassembly_pos], payload, size);
816474f5c3fSMatthias Ringwald             l2cap_channel->reassembly_pos += size;
817474f5c3fSMatthias Ringwald             break;
818474f5c3fSMatthias Ringwald         case L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU:
819122c2b05SMatthias Ringwald             // assert size of reassembled data <= our mtu
820122c2b05SMatthias Ringwald             if (l2cap_channel->reassembly_pos + size > l2cap_channel->local_mtu) break;
821122c2b05SMatthias Ringwald             // store continuation segment
822474f5c3fSMatthias Ringwald             memcpy(&l2cap_channel->reassembly_buffer[l2cap_channel->reassembly_pos], payload, size);
823474f5c3fSMatthias Ringwald             l2cap_channel->reassembly_pos += size;
824122c2b05SMatthias Ringwald             // assert size of reassembled data matches announced sdu length
825122c2b05SMatthias Ringwald             if (l2cap_channel->reassembly_pos != l2cap_channel->reassembly_sdu_length) break;
826474f5c3fSMatthias Ringwald             // packet complete -> disapatch
827474f5c3fSMatthias Ringwald             l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, l2cap_channel->reassembly_buffer, l2cap_channel->reassembly_pos);
828474f5c3fSMatthias Ringwald             l2cap_channel->reassembly_pos = 0;
829474f5c3fSMatthias Ringwald             break;
830474f5c3fSMatthias Ringwald     }
831474f5c3fSMatthias Ringwald }
832474f5c3fSMatthias Ringwald 
83385ddcd84SMatthias Ringwald #endif
83485ddcd84SMatthias Ringwald 
8356a5ffed8SMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
8366ddef68dSMilanka Ringwald static uint16_t l2cap_next_local_cid(void){
8376268fbfeSMilanka Ringwald     do {
8386268fbfeSMilanka Ringwald         if (local_source_cid == 0xffff) {
8396268fbfeSMilanka Ringwald             local_source_cid = 0x40;
8406268fbfeSMilanka Ringwald         } else {
8416268fbfeSMilanka Ringwald             local_source_cid++;
8426268fbfeSMilanka Ringwald         }
8436268fbfeSMilanka Ringwald     } while (l2cap_get_channel_for_local_cid(local_source_cid) != NULL);
8446268fbfeSMilanka Ringwald     return local_source_cid;
8456ddef68dSMilanka Ringwald }
8466a5ffed8SMatthias Ringwald #endif
8476ddef68dSMilanka Ringwald 
8486ddef68dSMilanka Ringwald static uint8_t l2cap_next_sig_id(void){
8496ddef68dSMilanka Ringwald     if (sig_seq_nr == 0xff) {
8506ddef68dSMilanka Ringwald         sig_seq_nr = 1;
8516ddef68dSMilanka Ringwald     } else {
8526ddef68dSMilanka Ringwald         sig_seq_nr++;
8536ddef68dSMilanka Ringwald     }
8546ddef68dSMilanka Ringwald     return sig_seq_nr;
8556ddef68dSMilanka Ringwald }
8566ddef68dSMilanka Ringwald 
85771de195eSMatthias Ringwald void l2cap_init(void){
8582b83fb7dSmatthias.ringwald     signaling_responses_pending = 0;
859808a48abSmatthias.ringwald 
860f5454fc6Smatthias.ringwald     l2cap_channels = NULL;
861fad84cafSMatthias Ringwald 
862fad84cafSMatthias Ringwald #ifdef ENABLE_CLASSIC
863f5454fc6Smatthias.ringwald     l2cap_services = NULL;
86409e9d05bSMatthias Ringwald     require_security_level2_for_outgoing_sdp = 0;
865fad84cafSMatthias Ringwald 
866fad84cafSMatthias Ringwald     // Setup Connectionless Channel
867fad84cafSMatthias Ringwald     l2cap_fixed_channel_connectionless.local_cid     = L2CAP_CID_CONNECTIONLESS_CHANNEL;
8687740e150SMatthias Ringwald     l2cap_fixed_channel_connectionless.channel_type  = L2CAP_CHANNEL_TYPE_CONNECTIONLESS;
869fad84cafSMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) &l2cap_fixed_channel_connectionless);
87009e9d05bSMatthias Ringwald #endif
871a3dc965aSMatthias Ringwald 
872a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
8737192e786SMatthias Ringwald     l2cap_le_services = NULL;
874a3dc965aSMatthias Ringwald #endif
875f5454fc6Smatthias.ringwald 
876d6ed9f9cSMatthias Ringwald #ifdef ENABLE_BLE
87733c40538SMatthias Ringwald     l2cap_event_packet_handler = NULL;
87825818320SMatthias Ringwald     l2cap_le_custom_max_mtu = 0;
879fad84cafSMatthias Ringwald 
880fad84cafSMatthias Ringwald     // Setup fixed ATT Channel
881fad84cafSMatthias Ringwald     l2cap_fixed_channel_att.local_cid    = L2CAP_CID_ATTRIBUTE_PROTOCOL;
8827740e150SMatthias Ringwald     l2cap_fixed_channel_att.channel_type = L2CAP_CHANNEL_TYPE_LE_FIXED;
883fad84cafSMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) &l2cap_fixed_channel_att);
884fad84cafSMatthias Ringwald 
885fad84cafSMatthias Ringwald     // Setup fixed SM Channel
886fad84cafSMatthias Ringwald     l2cap_fixed_channel_sm.local_cid     = L2CAP_CID_SECURITY_MANAGER_PROTOCOL;
8877740e150SMatthias Ringwald     l2cap_fixed_channel_sm.channel_type  = L2CAP_CHANNEL_TYPE_LE_FIXED;
888fad84cafSMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) &l2cap_fixed_channel_sm);
889d6ed9f9cSMatthias Ringwald #endif
890f5454fc6Smatthias.ringwald 
891fcadd0caSmatthias.ringwald     //
8922718e2e7Smatthias.ringwald     // register callback with HCI
893fcadd0caSmatthias.ringwald     //
894d9a7306aSMatthias Ringwald     hci_event_callback_registration.callback = &l2cap_hci_event_handler;
895fb37a842SMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
896fb37a842SMatthias Ringwald 
897d9a7306aSMatthias Ringwald     hci_register_acl_packet_handler(&l2cap_acl_handler);
898fb37a842SMatthias Ringwald 
899be005ed6SMatthias Ringwald #ifdef ENABLE_CLASSIC
90015a95bd5SMatthias Ringwald     gap_connectable_control(0); // no services yet
901be005ed6SMatthias Ringwald #endif
902fcadd0caSmatthias.ringwald }
903fcadd0caSmatthias.ringwald 
904ffbf8201SMatthias Ringwald void l2cap_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
905d6ed9f9cSMatthias Ringwald #ifdef ENABLE_BLE
90633c40538SMatthias Ringwald     l2cap_event_packet_handler = handler;
907d6ed9f9cSMatthias Ringwald #else
9085774a392SMatthias Ringwald     UNUSED(handler);    // ok: no code
909d6ed9f9cSMatthias Ringwald #endif
9101e6aba47Smatthias.ringwald }
9111e6aba47Smatthias.ringwald 
91209e9d05bSMatthias Ringwald void l2cap_request_can_send_fix_channel_now_event(hci_con_handle_t con_handle, uint16_t channel_id){
913fad84cafSMatthias Ringwald     UNUSED(con_handle);  // ok: there is no con handle
9149ec2630cSMatthias Ringwald 
915f68b21d7SMatthias Ringwald     l2cap_fixed_channel_t * channel = l2cap_fixed_channel_for_channel_id(channel_id);
916fad84cafSMatthias Ringwald     if (!channel) return;
917fad84cafSMatthias Ringwald     channel->waiting_for_can_send_now = 1;
91809e9d05bSMatthias Ringwald     l2cap_notify_channel_can_send();
91909e9d05bSMatthias Ringwald }
92009e9d05bSMatthias Ringwald 
92109e9d05bSMatthias Ringwald int  l2cap_can_send_fixed_channel_packet_now(hci_con_handle_t con_handle, uint16_t channel_id){
9225774a392SMatthias Ringwald     UNUSED(channel_id); // ok: only depends on Controller LE buffers
9239ec2630cSMatthias Ringwald 
92409e9d05bSMatthias Ringwald     return hci_can_send_acl_packet_now(con_handle);
92509e9d05bSMatthias Ringwald }
92609e9d05bSMatthias Ringwald 
92709e9d05bSMatthias Ringwald uint8_t *l2cap_get_outgoing_buffer(void){
92809e9d05bSMatthias Ringwald     return hci_get_outgoing_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
92909e9d05bSMatthias Ringwald }
93009e9d05bSMatthias Ringwald 
9314e6fa3a2SMatthias Ringwald // only for L2CAP Basic Channels
93209e9d05bSMatthias Ringwald int l2cap_reserve_packet_buffer(void){
93309e9d05bSMatthias Ringwald     return hci_reserve_packet_buffer();
93409e9d05bSMatthias Ringwald }
93509e9d05bSMatthias Ringwald 
9364e6fa3a2SMatthias Ringwald // only for L2CAP Basic Channels
93709e9d05bSMatthias Ringwald void l2cap_release_packet_buffer(void){
93809e9d05bSMatthias Ringwald     hci_release_packet_buffer();
93909e9d05bSMatthias Ringwald }
94009e9d05bSMatthias Ringwald 
941f511cefaSMatthias 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){
94209e9d05bSMatthias Ringwald     // 0 - Connection handle : PB=pb : BC=00
943f511cefaSMatthias Ringwald     little_endian_store_16(acl_buffer, 0, con_handle | (packet_boundary << 12) | (0 << 14));
94409e9d05bSMatthias Ringwald     // 2 - ACL length
94509e9d05bSMatthias Ringwald     little_endian_store_16(acl_buffer, 2,  len + 4);
94609e9d05bSMatthias Ringwald     // 4 - L2CAP packet length
94709e9d05bSMatthias Ringwald     little_endian_store_16(acl_buffer, 4,  len + 0);
94809e9d05bSMatthias Ringwald     // 6 - L2CAP channel DEST
94909e9d05bSMatthias Ringwald     little_endian_store_16(acl_buffer, 6,  remote_cid);
95009e9d05bSMatthias Ringwald }
95109e9d05bSMatthias Ringwald 
952f511cefaSMatthias Ringwald // assumption - only on LE connections
95309e9d05bSMatthias Ringwald int l2cap_send_prepared_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint16_t len){
95409e9d05bSMatthias Ringwald 
95509e9d05bSMatthias Ringwald     if (!hci_is_packet_buffer_reserved()){
95609e9d05bSMatthias Ringwald         log_error("l2cap_send_prepared_connectionless called without reserving packet first");
95709e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
95809e9d05bSMatthias Ringwald     }
95909e9d05bSMatthias Ringwald 
96009e9d05bSMatthias Ringwald     if (!hci_can_send_prepared_acl_packet_now(con_handle)){
96109e9d05bSMatthias Ringwald         log_info("l2cap_send_prepared_connectionless handle 0x%02x, cid 0x%02x, cannot send", con_handle, cid);
96209e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
96309e9d05bSMatthias Ringwald     }
96409e9d05bSMatthias Ringwald 
96509e9d05bSMatthias Ringwald     log_debug("l2cap_send_prepared_connectionless handle %u, cid 0x%02x", con_handle, cid);
96609e9d05bSMatthias Ringwald 
96709e9d05bSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
968f511cefaSMatthias Ringwald     l2cap_setup_header(acl_buffer, con_handle, 0, cid, len);
96909e9d05bSMatthias Ringwald     // send
97009e9d05bSMatthias Ringwald     return hci_send_acl_packet_buffer(len+8);
97109e9d05bSMatthias Ringwald }
97209e9d05bSMatthias Ringwald 
973f511cefaSMatthias Ringwald // assumption - only on LE connections
97409e9d05bSMatthias Ringwald int l2cap_send_connectionless(hci_con_handle_t con_handle, uint16_t cid, uint8_t *data, uint16_t len){
97509e9d05bSMatthias Ringwald 
97609e9d05bSMatthias Ringwald     if (!hci_can_send_acl_packet_now(con_handle)){
97709e9d05bSMatthias Ringwald         log_info("l2cap_send cid 0x%02x, cannot send", cid);
97809e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
97909e9d05bSMatthias Ringwald     }
98009e9d05bSMatthias Ringwald 
98109e9d05bSMatthias Ringwald     hci_reserve_packet_buffer();
98209e9d05bSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
98309e9d05bSMatthias Ringwald 
98409e9d05bSMatthias Ringwald     memcpy(&acl_buffer[8], data, len);
98509e9d05bSMatthias Ringwald 
98609e9d05bSMatthias Ringwald     return l2cap_send_prepared_connectionless(con_handle, cid, len);
98709e9d05bSMatthias Ringwald }
98809e9d05bSMatthias Ringwald 
98909e9d05bSMatthias Ringwald static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel) {
990d9d23054SMatthias Ringwald     log_debug("L2CAP_EVENT_CHANNEL_CAN_SEND_NOW local_cid 0x%x", channel);
99109e9d05bSMatthias Ringwald     uint8_t event[4];
99209e9d05bSMatthias Ringwald     event[0] = L2CAP_EVENT_CAN_SEND_NOW;
99309e9d05bSMatthias Ringwald     event[1] = sizeof(event) - 2;
99409e9d05bSMatthias Ringwald     little_endian_store_16(event, 2, channel);
99509e9d05bSMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
99609e9d05bSMatthias Ringwald     packet_handler(HCI_EVENT_PACKET, channel, event, sizeof(event));
99709e9d05bSMatthias Ringwald }
99809e9d05bSMatthias Ringwald 
99909e9d05bSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
100017a9b554SMatthias Ringwald static void l2cap_dispatch_to_channel(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){
100158de5610Smatthias.ringwald     (* (channel->packet_handler))(type, channel->local_cid, data, size);
100258de5610Smatthias.ringwald }
100358de5610Smatthias.ringwald 
100444276248SMatthias Ringwald static void l2cap_emit_simple_event_with_cid(l2cap_channel_t * channel, uint8_t event_code){
100544276248SMatthias Ringwald     uint8_t event[4];
100644276248SMatthias Ringwald     event[0] = event_code;
100744276248SMatthias Ringwald     event[1] = sizeof(event) - 2;
100844276248SMatthias Ringwald     little_endian_store_16(event, 2, channel->local_cid);
100944276248SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
101044276248SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
101144276248SMatthias Ringwald }
101209e9d05bSMatthias Ringwald #endif
101344276248SMatthias Ringwald 
101409e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
101558de5610Smatthias.ringwald void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
1016c9dc710bS[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",
1017fc64f94aSMatthias Ringwald              status, bd_addr_to_str(channel->address), channel->con_handle, channel->psm,
1018c9dc710bS[email protected]              channel->local_cid, channel->remote_cid, channel->local_mtu, channel->remote_mtu, channel->flush_timeout);
10197f1690cfSMatthias Ringwald     uint8_t event[26];
102058de5610Smatthias.ringwald     event[0] = L2CAP_EVENT_CHANNEL_OPENED;
102158de5610Smatthias.ringwald     event[1] = sizeof(event) - 2;
102258de5610Smatthias.ringwald     event[2] = status;
1023724d70a2SMatthias Ringwald     reverse_bd_addr(channel->address, &event[3]);
1024fc64f94aSMatthias Ringwald     little_endian_store_16(event,  9, channel->con_handle);
1025f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 11, channel->psm);
1026f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 13, channel->local_cid);
1027f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 15, channel->remote_cid);
1028f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 17, channel->local_mtu);
1029f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 19, channel->remote_mtu);
1030f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 21, channel->flush_timeout);
1031bab5f4f0SMatthias Ringwald     event[23] = channel->state_var & L2CAP_CHANNEL_STATE_VAR_INCOMING ? 1 : 0;
10327f1690cfSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
10337f1690cfSMatthias Ringwald     log_info("ERTM mode %u, fcs enabled %u", channel->mode, channel->fcs_option);
10347f1690cfSMatthias Ringwald     event[24] = channel->mode;
10357f1690cfSMatthias Ringwald     event[25] = channel->fcs_option;
10367f1690cfSMatthias Ringwald 
10377f1690cfSMatthias Ringwald #else
10387f1690cfSMatthias Ringwald     event[24] = L2CAP_CHANNEL_MODE_BASIC;
10397f1690cfSMatthias Ringwald     event[25] = 0;
10407f1690cfSMatthias Ringwald #endif
104158de5610Smatthias.ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
104217a9b554SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
104358de5610Smatthias.ringwald }
104458de5610Smatthias.ringwald 
104544276248SMatthias Ringwald static void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
1046e0abb8e7S[email protected]     log_info("L2CAP_EVENT_CHANNEL_CLOSED local_cid 0x%x", channel->local_cid);
104744276248SMatthias Ringwald     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED);
104858de5610Smatthias.ringwald }
104958de5610Smatthias.ringwald 
105044276248SMatthias Ringwald static void l2cap_emit_incoming_connection(l2cap_channel_t *channel) {
1051e0abb8e7S[email protected]     log_info("L2CAP_EVENT_INCOMING_CONNECTION addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x",
1052fc64f94aSMatthias Ringwald              bd_addr_to_str(channel->address), channel->con_handle,  channel->psm, channel->local_cid, channel->remote_cid);
105358de5610Smatthias.ringwald     uint8_t event[16];
105458de5610Smatthias.ringwald     event[0] = L2CAP_EVENT_INCOMING_CONNECTION;
105558de5610Smatthias.ringwald     event[1] = sizeof(event) - 2;
1056724d70a2SMatthias Ringwald     reverse_bd_addr(channel->address, &event[2]);
1057fc64f94aSMatthias Ringwald     little_endian_store_16(event,  8, channel->con_handle);
1058f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 10, channel->psm);
1059f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 12, channel->local_cid);
1060f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 14, channel->remote_cid);
106158de5610Smatthias.ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
106217a9b554SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
10630af41d30Smatthias.ringwald }
1064f62db1e3Smatthias.ringwald 
106566a72640SMatthias Ringwald static void l2cap_handle_channel_open_failed(l2cap_channel_t * channel, uint8_t status){
106666a72640SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
106766a72640SMatthias Ringwald     // emit ertm buffer released, as it's not needed. if in basic mode, it was either not allocated or already released
106866a72640SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
106966a72640SMatthias Ringwald         l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_ERTM_BUFFER_RELEASED);
107066a72640SMatthias Ringwald     }
107166a72640SMatthias Ringwald #endif
1072624873c3SMatthias Ringwald     l2cap_emit_channel_opened(channel, status);
1073624873c3SMatthias Ringwald }
1074624873c3SMatthias Ringwald 
107566a72640SMatthias Ringwald static void l2cap_handle_channel_closed(l2cap_channel_t * channel){
107666a72640SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
107766a72640SMatthias Ringwald     // emit ertm buffer released, as it's not needed anymore. if in basic mode, it was either not allocated or already released
107866a72640SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
107966a72640SMatthias Ringwald         l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_ERTM_BUFFER_RELEASED);
108066a72640SMatthias Ringwald     }
108166a72640SMatthias Ringwald #endif
108266a72640SMatthias Ringwald     l2cap_emit_channel_closed(channel);
108366a72640SMatthias Ringwald }
1084dd3bf36fSMatthias Ringwald #endif
1085dd3bf36fSMatthias Ringwald 
1086dd3bf36fSMatthias Ringwald static l2cap_fixed_channel_t * l2cap_channel_item_by_cid(uint16_t cid){
1087dd3bf36fSMatthias Ringwald     btstack_linked_list_iterator_t it;
1088dd3bf36fSMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
1089dd3bf36fSMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1090dd3bf36fSMatthias Ringwald         l2cap_fixed_channel_t * channel = (l2cap_fixed_channel_t*) btstack_linked_list_iterator_next(&it);
1091dd3bf36fSMatthias Ringwald         if (channel->local_cid == cid) {
1092dd3bf36fSMatthias Ringwald             return channel;
1093dd3bf36fSMatthias Ringwald         }
1094dd3bf36fSMatthias Ringwald     }
1095dd3bf36fSMatthias Ringwald     return NULL;
1096dd3bf36fSMatthias Ringwald }
109766a72640SMatthias Ringwald 
1098fad84cafSMatthias Ringwald // used for fixed channels in LE (ATT/SM) and Classic (Connectionless Channel). CID < 0x04
1099fad84cafSMatthias Ringwald static l2cap_fixed_channel_t * l2cap_fixed_channel_for_channel_id(uint16_t local_cid){
1100fad84cafSMatthias Ringwald     if (local_cid >= 0x40) return NULL;
1101fad84cafSMatthias Ringwald     return (l2cap_fixed_channel_t*) l2cap_channel_item_by_cid(local_cid);
1102fad84cafSMatthias Ringwald }
110324eb964eSMatthias Ringwald 
110424eb964eSMatthias Ringwald // used for Classic Channels + LE Data Channels. local_cid >= 0x40
110524eb964eSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
110624eb964eSMatthias Ringwald static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
110724eb964eSMatthias Ringwald     if (local_cid < 0x40) return NULL;
110824eb964eSMatthias Ringwald     return (l2cap_channel_t*) l2cap_channel_item_by_cid(local_cid);
110924eb964eSMatthias Ringwald }
11100b9d7e78SMatthias Ringwald 
111130725612SMatthias Ringwald void l2cap_request_can_send_now_event(uint16_t local_cid){
111230725612SMatthias Ringwald     l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
111330725612SMatthias Ringwald     if (!channel) return;
111430725612SMatthias Ringwald     channel->waiting_for_can_send_now = 1;
111596646001SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
111696646001SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
111796646001SMatthias Ringwald         l2cap_ertm_notify_channel_can_send(channel);
111896646001SMatthias Ringwald         return;
111996646001SMatthias Ringwald     }
112096646001SMatthias Ringwald #endif
112130725612SMatthias Ringwald     l2cap_notify_channel_can_send();
112230725612SMatthias Ringwald }
112330725612SMatthias Ringwald 
112496646001SMatthias Ringwald int  l2cap_can_send_packet_now(uint16_t local_cid){
112596646001SMatthias Ringwald     l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
112696646001SMatthias Ringwald     if (!channel) return 0;
112796646001SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
112896646001SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
112996646001SMatthias Ringwald         return l2cap_ertm_can_store_packet_now(channel);
113096646001SMatthias Ringwald     }
113196646001SMatthias Ringwald #endif
11320b9d7e78SMatthias Ringwald     return hci_can_send_acl_packet_now(channel->con_handle);
11337856fb31S[email protected] }
11347856fb31S[email protected] 
113583e7cdd9SMatthias Ringwald int  l2cap_can_send_prepared_packet_now(uint16_t local_cid){
113683e7cdd9SMatthias Ringwald     l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
113783e7cdd9SMatthias Ringwald     if (!channel) return 0;
11380b20b13bSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
11390b20b13bSMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
11400b20b13bSMatthias Ringwald         return 0;
11410b20b13bSMatthias Ringwald     }
11420b20b13bSMatthias Ringwald #endif
11430b9d7e78SMatthias Ringwald     return hci_can_send_prepared_acl_packet_now(channel->con_handle);
114483e7cdd9SMatthias Ringwald }
11450b20b13bSMatthias Ringwald 
114696cbd662Smatthias.ringwald uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){
114796cbd662Smatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
114896cbd662Smatthias.ringwald     if (channel) {
114996cbd662Smatthias.ringwald         return channel->remote_mtu;
115096cbd662Smatthias.ringwald     }
115196cbd662Smatthias.ringwald     return 0;
115296cbd662Smatthias.ringwald }
115324eb964eSMatthias Ringwald #endif
115496cbd662Smatthias.ringwald 
115524eb964eSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
1156fad84cafSMatthias Ringwald static int l2cap_is_dynamic_channel_type(l2cap_channel_type_t channel_type){
1157fad84cafSMatthias Ringwald     switch (channel_type){
1158fad84cafSMatthias Ringwald         case L2CAP_CHANNEL_TYPE_CLASSIC:
1159fad84cafSMatthias Ringwald         case L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL:
1160fad84cafSMatthias Ringwald             return 1;
1161fad84cafSMatthias Ringwald         default:
1162fad84cafSMatthias Ringwald             return 0;
1163fad84cafSMatthias Ringwald     }
1164fad84cafSMatthias Ringwald }
116524eb964eSMatthias Ringwald #endif
1166fad84cafSMatthias Ringwald 
116724eb964eSMatthias Ringwald #ifdef ENABLE_CLASSIC
1168fad84cafSMatthias Ringwald // RTX Timer only exist for dynamic channels
1169ec820d77SMatthias Ringwald static l2cap_channel_t * l2cap_channel_for_rtx_timer(btstack_timer_source_t * ts){
1170665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
1171665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
1172665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1173665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1174fad84cafSMatthias Ringwald         if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
11755932bd7cS[email protected]         if (&channel->rtx == ts) {
11765932bd7cS[email protected]             return channel;
11775932bd7cS[email protected]         }
11785932bd7cS[email protected]     }
11795932bd7cS[email protected]     return NULL;
11805932bd7cS[email protected] }
11815932bd7cS[email protected] 
1182ec820d77SMatthias Ringwald static void l2cap_rtx_timeout(btstack_timer_source_t * ts){
11835932bd7cS[email protected]     l2cap_channel_t * channel = l2cap_channel_for_rtx_timer(ts);
118495d2c8f4SMatthias Ringwald     if (!channel) return;
11855932bd7cS[email protected] 
11865932bd7cS[email protected]     log_info("l2cap_rtx_timeout for local cid 0x%02x", channel->local_cid);
11875932bd7cS[email protected] 
11885932bd7cS[email protected]     // "When terminating the channel, it is not necessary to send a L2CAP_DisconnectReq
11895932bd7cS[email protected]     //  and enter WAIT_DISCONNECT state. Channels can be transitioned directly to the CLOSED state."
11905932bd7cS[email protected]     // notify client
119166a72640SMatthias Ringwald     l2cap_handle_channel_open_failed(channel, L2CAP_CONNECTION_RESPONSE_RESULT_RTX_TIMEOUT);
11925932bd7cS[email protected] 
11935932bd7cS[email protected]     // discard channel
1194665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
1195c45d6b2cSMatthias Ringwald     l2cap_free_channel_entry(channel);
11965932bd7cS[email protected] }
11975932bd7cS[email protected] 
119813aa3e4bSMatthias Ringwald #endif
119913aa3e4bSMatthias Ringwald 
120013aa3e4bSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
12015932bd7cS[email protected] static void l2cap_stop_rtx(l2cap_channel_t * channel){
12025932bd7cS[email protected]     log_info("l2cap_stop_rtx for local cid 0x%02x", channel->local_cid);
1203528a4a3bSMatthias Ringwald     btstack_run_loop_remove_timer(&channel->rtx);
12045932bd7cS[email protected] }
120513aa3e4bSMatthias Ringwald #endif
120613aa3e4bSMatthias Ringwald 
120713aa3e4bSMatthias Ringwald #ifdef ENABLE_CLASSIC
12085932bd7cS[email protected] 
12095932bd7cS[email protected] static void l2cap_start_rtx(l2cap_channel_t * channel){
12105932bd7cS[email protected]     l2cap_stop_rtx(channel);
1211cb0ff06bS[email protected]     log_info("l2cap_start_rtx for local cid 0x%02x", channel->local_cid);
1212528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->rtx, l2cap_rtx_timeout);
1213528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer(&channel->rtx, L2CAP_RTX_TIMEOUT_MS);
1214528a4a3bSMatthias Ringwald     btstack_run_loop_add_timer(&channel->rtx);
12155932bd7cS[email protected] }
12165932bd7cS[email protected] 
12175932bd7cS[email protected] static void l2cap_start_ertx(l2cap_channel_t * channel){
12185932bd7cS[email protected]     log_info("l2cap_start_ertx for local cid 0x%02x", channel->local_cid);
12195932bd7cS[email protected]     l2cap_stop_rtx(channel);
1220528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->rtx, l2cap_rtx_timeout);
1221528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer(&channel->rtx, L2CAP_ERTX_TIMEOUT_MS);
1222528a4a3bSMatthias Ringwald     btstack_run_loop_add_timer(&channel->rtx);
12235932bd7cS[email protected] }
12245932bd7cS[email protected] 
122571de195eSMatthias Ringwald void l2cap_require_security_level_2_for_outgoing_sdp(void){
1226ac301f95S[email protected]     require_security_level2_for_outgoing_sdp = 1;
1227ac301f95S[email protected] }
1228ac301f95S[email protected] 
1229df3354fcS[email protected] static int l2cap_security_level_0_allowed_for_PSM(uint16_t psm){
123084e3541eSMilanka Ringwald     return (psm == BLUETOOTH_PSM_SDP) && (!require_security_level2_for_outgoing_sdp);
1231df3354fcS[email protected] }
12325932bd7cS[email protected] 
123363854e74SMatthias Ringwald static int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, int identifier, ...){
1234a35252c8S[email protected]     if (!hci_can_send_acl_packet_now(handle)){
12359da54300S[email protected]         log_info("l2cap_send_signaling_packet, cannot send");
1236b1d43497Smatthias.ringwald         return BTSTACK_ACL_BUFFERS_FULL;
1237b1d43497Smatthias.ringwald     }
1238b1d43497Smatthias.ringwald 
12399da54300S[email protected]     // log_info("l2cap_send_signaling_packet type %u", cmd);
12402a373862S[email protected]     hci_reserve_packet_buffer();
1241facf93fdS[email protected]     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
124258de5610Smatthias.ringwald     va_list argptr;
124358de5610Smatthias.ringwald     va_start(argptr, identifier);
124470efece1S[email protected]     uint16_t len = l2cap_create_signaling_classic(acl_buffer, handle, cmd, identifier, argptr);
124558de5610Smatthias.ringwald     va_end(argptr);
12469da54300S[email protected]     // log_info("l2cap_send_signaling_packet con %u!", handle);
1247826f7347S[email protected]     return hci_send_acl_packet_buffer(len);
124858de5610Smatthias.ringwald }
124958de5610Smatthias.ringwald 
1250f511cefaSMatthias Ringwald // assumption - only on Classic connections
12514e6fa3a2SMatthias Ringwald // cannot be used for L2CAP ERTM
1252b1d43497Smatthias.ringwald int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
1253b1d43497Smatthias.ringwald 
1254c8b9416aS[email protected]     if (!hci_is_packet_buffer_reserved()){
1255c8b9416aS[email protected]         log_error("l2cap_send_prepared called without reserving packet first");
1256c8b9416aS[email protected]         return BTSTACK_ACL_BUFFERS_FULL;
1257c8b9416aS[email protected]     }
1258c8b9416aS[email protected] 
125958de5610Smatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
1260b1d43497Smatthias.ringwald     if (!channel) {
12619da54300S[email protected]         log_error("l2cap_send_prepared no channel for cid 0x%02x", local_cid);
1262b1d43497Smatthias.ringwald         return -1;   // TODO: define error
12636218e6f1Smatthias.ringwald     }
12646218e6f1Smatthias.ringwald 
1265fc64f94aSMatthias Ringwald     if (!hci_can_send_prepared_acl_packet_now(channel->con_handle)){
12669da54300S[email protected]         log_info("l2cap_send_prepared cid 0x%02x, cannot send", local_cid);
1267a35252c8S[email protected]         return BTSTACK_ACL_BUFFERS_FULL;
1268a35252c8S[email protected]     }
1269a35252c8S[email protected] 
1270fc64f94aSMatthias Ringwald     log_debug("l2cap_send_prepared cid 0x%02x, handle %u, 1 credit used", local_cid, channel->con_handle);
1271b1d43497Smatthias.ringwald 
127285ddcd84SMatthias Ringwald     int fcs_size = 0;
127385ddcd84SMatthias Ringwald 
127485ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
12756574158aSMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION && channel->fcs_option){
127685ddcd84SMatthias Ringwald         fcs_size = 2;
127785ddcd84SMatthias Ringwald     }
127885ddcd84SMatthias Ringwald #endif
127985ddcd84SMatthias Ringwald 
1280f511cefaSMatthias Ringwald     // set non-flushable packet boundary flag if supported on Controller
1281facf93fdS[email protected]     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
1282f511cefaSMatthias Ringwald     uint8_t packet_boundary_flag = hci_non_flushable_packet_boundary_flag_supported() ? 0x00 : 0x02;
128385ddcd84SMatthias Ringwald     l2cap_setup_header(acl_buffer, channel->con_handle, packet_boundary_flag, channel->remote_cid, len + fcs_size);
128485ddcd84SMatthias Ringwald 
128585ddcd84SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
1286b72f6906SMatthias Ringwald     if (fcs_size){
128785ddcd84SMatthias Ringwald         // calculate FCS over l2cap data
128885ddcd84SMatthias Ringwald         uint16_t fcs = crc16_calc(acl_buffer + 4, 4 + len);
128985ddcd84SMatthias Ringwald         log_info("I-Frame: fcs 0x%04x", fcs);
129085ddcd84SMatthias Ringwald         little_endian_store_16(acl_buffer, 8 + len, fcs);
129158de5610Smatthias.ringwald     }
129285ddcd84SMatthias Ringwald #endif
129385ddcd84SMatthias Ringwald 
129485ddcd84SMatthias Ringwald     // send
129585ddcd84SMatthias Ringwald     return hci_send_acl_packet_buffer(len+8+fcs_size);
129685ddcd84SMatthias Ringwald }
129785ddcd84SMatthias Ringwald 
1298f511cefaSMatthias Ringwald // assumption - only on Classic connections
1299ce8f182eSMatthias Ringwald int l2cap_send(uint16_t local_cid, uint8_t *data, uint16_t len){
1300a35252c8S[email protected]     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
1301a35252c8S[email protected]     if (!channel) {
1302ce8f182eSMatthias Ringwald         log_error("l2cap_send no channel for cid 0x%02x", local_cid);
1303a35252c8S[email protected]         return -1;   // TODO: define error
1304a35252c8S[email protected]     }
1305a35252c8S[email protected] 
1306f0fb4cd7SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
1307f0fb4cd7SMatthias Ringwald     // send in ERTM
1308f0fb4cd7SMatthias Ringwald     if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
1309f0fb4cd7SMatthias Ringwald         return l2cap_ertm_send(channel, data, len);
1310f0fb4cd7SMatthias Ringwald     }
1311f0fb4cd7SMatthias Ringwald #endif
1312f0fb4cd7SMatthias Ringwald 
1313f0efaa57S[email protected]     if (len > channel->remote_mtu){
1314ce8f182eSMatthias Ringwald         log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", local_cid);
1315f0efaa57S[email protected]         return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU;
1316f0efaa57S[email protected]     }
1317f0efaa57S[email protected] 
1318fc64f94aSMatthias Ringwald     if (!hci_can_send_acl_packet_now(channel->con_handle)){
1319ce8f182eSMatthias Ringwald         log_info("l2cap_send cid 0x%02x, cannot send", local_cid);
1320b1d43497Smatthias.ringwald         return BTSTACK_ACL_BUFFERS_FULL;
1321b1d43497Smatthias.ringwald     }
1322b1d43497Smatthias.ringwald 
13232a373862S[email protected]     hci_reserve_packet_buffer();
1324facf93fdS[email protected]     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
1325f0fb4cd7SMatthias Ringwald     memcpy(&acl_buffer[8], data, len);
1326f0fb4cd7SMatthias Ringwald     return l2cap_send_prepared(local_cid, len);
1327b1d43497Smatthias.ringwald }
1328b1d43497Smatthias.ringwald 
1329fc64f94aSMatthias Ringwald int l2cap_send_echo_request(hci_con_handle_t con_handle, uint8_t *data, uint16_t len){
1330fc64f94aSMatthias Ringwald     return l2cap_send_signaling_packet(con_handle, ECHO_REQUEST, 0x77, len, data);
13310e37e417S[email protected] }
13320e37e417S[email protected] 
133328ca2b46S[email protected] static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
133428ca2b46S[email protected]     channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var | flag);
133528ca2b46S[email protected] }
133628ca2b46S[email protected] 
133728ca2b46S[email protected] static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
133828ca2b46S[email protected]     channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag);
133928ca2b46S[email protected] }
134009e9d05bSMatthias Ringwald #endif
134128ca2b46S[email protected] 
134228ca2b46S[email protected] 
134309e9d05bSMatthias Ringwald #ifdef ENABLE_BLE
134463854e74SMatthias Ringwald static int l2cap_send_le_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, int identifier, ...){
134509e9d05bSMatthias Ringwald 
134609e9d05bSMatthias Ringwald     if (!hci_can_send_acl_packet_now(handle)){
134709e9d05bSMatthias Ringwald         log_info("l2cap_send_le_signaling_packet, cannot send");
134809e9d05bSMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
134909e9d05bSMatthias Ringwald     }
135009e9d05bSMatthias Ringwald 
135109e9d05bSMatthias Ringwald     // log_info("l2cap_send_le_signaling_packet type %u", cmd);
135209e9d05bSMatthias Ringwald     hci_reserve_packet_buffer();
135309e9d05bSMatthias Ringwald     uint8_t *acl_buffer = hci_get_outgoing_packet_buffer();
135409e9d05bSMatthias Ringwald     va_list argptr;
135509e9d05bSMatthias Ringwald     va_start(argptr, identifier);
135609e9d05bSMatthias Ringwald     uint16_t len = l2cap_create_signaling_le(acl_buffer, handle, cmd, identifier, argptr);
135709e9d05bSMatthias Ringwald     va_end(argptr);
135809e9d05bSMatthias Ringwald     // log_info("l2cap_send_le_signaling_packet con %u!", handle);
135909e9d05bSMatthias Ringwald     return hci_send_acl_packet_buffer(len);
136009e9d05bSMatthias Ringwald }
136109e9d05bSMatthias Ringwald #endif
136209e9d05bSMatthias Ringwald 
136309e9d05bSMatthias Ringwald uint16_t l2cap_max_mtu(void){
136409e9d05bSMatthias Ringwald     return HCI_ACL_PAYLOAD_SIZE - L2CAP_HEADER_SIZE;
136509e9d05bSMatthias Ringwald }
136609e9d05bSMatthias Ringwald 
13673e329ddfSandryblack #ifdef ENABLE_BLE
136809e9d05bSMatthias Ringwald uint16_t l2cap_max_le_mtu(void){
136925818320SMatthias Ringwald     if (l2cap_le_custom_max_mtu != 0) return l2cap_le_custom_max_mtu;
137009e9d05bSMatthias Ringwald     return l2cap_max_mtu();
137109e9d05bSMatthias Ringwald }
1372b1d43497Smatthias.ringwald 
137325818320SMatthias Ringwald void l2cap_set_max_le_mtu(uint16_t max_mtu){
137425818320SMatthias Ringwald     if (max_mtu < l2cap_max_mtu()){
137525818320SMatthias Ringwald         l2cap_le_custom_max_mtu = max_mtu;
137625818320SMatthias Ringwald     }
137725818320SMatthias Ringwald }
13783e329ddfSandryblack #endif
137925818320SMatthias Ringwald 
1380d2afdd38SMatthias Ringwald #ifdef ENABLE_CLASSIC
1381d2afdd38SMatthias Ringwald 
13826b99230fSMatthias Ringwald static uint16_t l2cap_setup_options_mtu(uint8_t * config_options, uint16_t mtu){
1383d64e9771SMatthias Ringwald     config_options[0] = L2CAP_CONFIG_OPTION_TYPE_MAX_TRANSMISSION_UNIT; // MTU
1384d2afdd38SMatthias Ringwald     config_options[1] = 2; // len param
13856b99230fSMatthias Ringwald     little_endian_store_16(config_options, 2, mtu);
1386d2afdd38SMatthias Ringwald     return 4;
1387d2afdd38SMatthias Ringwald }
1388d2afdd38SMatthias Ringwald 
1389450ad7ecSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
13906b99230fSMatthias Ringwald static int l2cap_ertm_mode(l2cap_channel_t * channel){
1391450ad7ecSMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
13926b99230fSMatthias Ringwald     return ((connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_DONE)
13936b99230fSMatthias Ringwald         &&  (connection->l2cap_state.extended_feature_mask & 0x08));
1394450ad7ecSMatthias Ringwald }
1395450ad7ecSMatthias Ringwald #endif
13966b99230fSMatthias Ringwald 
13976b99230fSMatthias Ringwald static uint16_t l2cap_setup_options_request(l2cap_channel_t * channel, uint8_t * config_options){
13986b99230fSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
1399313d3a26SMatthias Ringwald     // use ERTM options if supported by remote and channel ready to use it
1400313d3a26SMatthias Ringwald     if (l2cap_ertm_mode(channel) && channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
14017cbe539fSMatthias Ringwald         return l2cap_setup_options_ertm_request(channel, config_options);
14026b99230fSMatthias Ringwald     }
14036b99230fSMatthias Ringwald #endif
14046b99230fSMatthias Ringwald     uint16_t mtu = channel->local_mtu;
14056b99230fSMatthias Ringwald     return l2cap_setup_options_mtu(config_options, mtu);
14066b99230fSMatthias Ringwald }
14076b99230fSMatthias Ringwald 
1408b8134563SMatthias Ringwald static uint16_t l2cap_setup_options_mtu_response(l2cap_channel_t * channel, uint8_t * config_options){
140932717978SMatthias Ringwald     uint16_t mtu = btstack_min(channel->local_mtu, channel->remote_mtu);
14106b99230fSMatthias Ringwald     return l2cap_setup_options_mtu(config_options, mtu);
14116dca2a0cSMatthias Ringwald }
14126dca2a0cSMatthias Ringwald 
14131b9cb13dSMatthias Ringwald static uint32_t l2cap_extended_features_mask(void){
14141b9cb13dSMatthias Ringwald     // extended features request supported, features: fixed channels, unicast connectionless data reception
14151b9cb13dSMatthias Ringwald     uint32_t features = 0x280;
14161b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
141754901195SMatthias Ringwald     features |= 0x0028;
14181b9cb13dSMatthias Ringwald #endif
14191b9cb13dSMatthias Ringwald     return features;
14201b9cb13dSMatthias Ringwald }
1421d2afdd38SMatthias Ringwald #endif
14221b9cb13dSMatthias Ringwald 
14238158c421Smatthias.ringwald // MARK: L2CAP_RUN
14242cd0be45Smatthias.ringwald // process outstanding signaling tasks
14257f02f414SMatthias Ringwald static void l2cap_run(void){
14262b83fb7dSmatthias.ringwald 
142722c29ab4SMatthias Ringwald     // log_info("l2cap_run: entered");
142822c29ab4SMatthias Ringwald 
14292b83fb7dSmatthias.ringwald     // check pending signaling responses
14302b83fb7dSmatthias.ringwald     while (signaling_responses_pending){
14312b83fb7dSmatthias.ringwald 
14322b83fb7dSmatthias.ringwald         hci_con_handle_t handle = signaling_responses[0].handle;
1433a35252c8S[email protected] 
1434a35252c8S[email protected]         if (!hci_can_send_acl_packet_now(handle)) break;
1435a35252c8S[email protected] 
14362b83fb7dSmatthias.ringwald         uint8_t  sig_id        = signaling_responses[0].sig_id;
1437e74c5f58SMatthias Ringwald         uint8_t  response_code = signaling_responses[0].code;
143863a7246aSmatthias.ringwald         uint16_t result        = signaling_responses[0].data;  // CONNECTION_REQUEST, COMMAND_REJECT
1439b3264428SMatthias Ringwald #ifdef ENABLE_CLASSIC
14405774a392SMatthias Ringwald         uint16_t info_type     = signaling_responses[0].data;  // INFORMATION_REQUEST
1441b3264428SMatthias Ringwald         uint16_t source_cid    = signaling_responses[0].cid;   // CONNECTION_REQUEST
1442b3264428SMatthias Ringwald #endif
144309e9d05bSMatthias Ringwald 
1444f53da564S[email protected]         // remove first item before sending (to avoid sending response mutliple times)
1445f53da564S[email protected]         signaling_responses_pending--;
1446f53da564S[email protected]         int i;
1447f53da564S[email protected]         for (i=0; i < signaling_responses_pending; i++){
1448f53da564S[email protected]             memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t));
1449f53da564S[email protected]         }
1450f53da564S[email protected] 
1451f53da564S[email protected]         switch (response_code){
145209e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
14532b360848Smatthias.ringwald             case CONNECTION_REQUEST:
1454e74c5f58SMatthias Ringwald                 l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, source_cid, 0, result, 0);
14552bd8b7e7S[email protected]                 // also disconnect if result is 0x0003 - security blocked
14564d816277S[email protected]                 if (result == 0x0003){
14572bd8b7e7S[email protected]                     hci_disconnect_security_block(handle);
14584d816277S[email protected]                 }
14592b360848Smatthias.ringwald                 break;
14602b83fb7dSmatthias.ringwald             case ECHO_REQUEST:
14612b83fb7dSmatthias.ringwald                 l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL);
14622b83fb7dSmatthias.ringwald                 break;
14632b83fb7dSmatthias.ringwald             case INFORMATION_REQUEST:
14643e64cb44SMatthias Ringwald                 switch (info_type){
14653e64cb44SMatthias Ringwald                     case L2CAP_INFO_TYPE_CONNECTIONLESS_MTU: {
14663b0484b3S[email protected]                             uint16_t connectionless_mtu = hci_max_acl_data_packet_length();
14673e64cb44SMatthias Ringwald                             l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, info_type, 0, sizeof(connectionless_mtu), &connectionless_mtu);
14683b0484b3S[email protected]                         }
1469202c8a4cSMatthias Ringwald                         break;
14703e64cb44SMatthias Ringwald                     case L2CAP_INFO_TYPE_EXTENDED_FEATURES_SUPPORTED: {
14711b9cb13dSMatthias Ringwald                             uint32_t features = l2cap_extended_features_mask();
14723e64cb44SMatthias Ringwald                             l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, info_type, 0, sizeof(features), &features);
14733b0484b3S[email protected]                         }
1474202c8a4cSMatthias Ringwald                         break;
14753e64cb44SMatthias Ringwald                     case L2CAP_INFO_TYPE_FIXED_CHANNELS_SUPPORTED: {
14763b0484b3S[email protected]                             uint8_t map[8];
14773b0484b3S[email protected]                             memset(map, 0, 8);
1478288636a2SMatthias Ringwald                             map[0] = 0x06;  // L2CAP Signaling Channel (0x02) + Connectionless reception (0x04)
14793e64cb44SMatthias Ringwald                             l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, info_type, 0, sizeof(map), &map);
14803b0484b3S[email protected]                         }
1481202c8a4cSMatthias Ringwald                         break;
14823b0484b3S[email protected]                     default:
14832b83fb7dSmatthias.ringwald                         // all other types are not supported
14843e64cb44SMatthias Ringwald                         l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, info_type, 1, 0, NULL);
14853b0484b3S[email protected]                         break;
14862b83fb7dSmatthias.ringwald                 }
14872b83fb7dSmatthias.ringwald                 break;
148863a7246aSmatthias.ringwald             case COMMAND_REJECT:
14895ca8d57bS[email protected]                 l2cap_send_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL);
149063f0ac45SMatthias Ringwald                 break;
149109e9d05bSMatthias Ringwald #endif
1492a9a4c409SMatthias Ringwald #ifdef ENABLE_BLE
149363f0ac45SMatthias Ringwald             case LE_CREDIT_BASED_CONNECTION_REQUEST:
149463f0ac45SMatthias Ringwald                 l2cap_send_le_signaling_packet(handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, sig_id, 0, 0, 0, 0, result);
149563f0ac45SMatthias Ringwald                 break;
149670efece1S[email protected]             case COMMAND_REJECT_LE:
149770efece1S[email protected]                 l2cap_send_le_signaling_packet(handle, COMMAND_REJECT, sig_id, result, 0, NULL);
149863a7246aSmatthias.ringwald                 break;
149970efece1S[email protected] #endif
15002b83fb7dSmatthias.ringwald             default:
15012b83fb7dSmatthias.ringwald                 // should not happen
15022b83fb7dSmatthias.ringwald                 break;
15032b83fb7dSmatthias.ringwald         }
15042b83fb7dSmatthias.ringwald     }
15052b83fb7dSmatthias.ringwald 
1506959f646aSMatthias Ringwald #if defined(ENABLE_CLASSIC) || defined(ENABLE_BLE)
1507665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
15085774a392SMatthias Ringwald #endif
150909e9d05bSMatthias Ringwald 
15101b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
15111b9cb13dSMatthias Ringwald     // send l2cap information request if neccessary
15121b9cb13dSMatthias Ringwald     hci_connections_get_iterator(&it);
15131b9cb13dSMatthias Ringwald     while(btstack_linked_list_iterator_has_next(&it)){
15141b9cb13dSMatthias Ringwald         hci_connection_t * connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it);
15151b9cb13dSMatthias Ringwald         if (connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_W2_SEND_EXTENDED_FEATURE_REQUEST){
151693d791b2SMatthias Ringwald             if (!hci_can_send_acl_packet_now(connection->con_handle)) break;
15171b9cb13dSMatthias Ringwald             connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_W4_EXTENDED_FEATURE_RESPONSE;
15181b9cb13dSMatthias Ringwald             uint8_t sig_id = l2cap_next_sig_id();
15193e64cb44SMatthias Ringwald             uint8_t info_type = L2CAP_INFO_TYPE_EXTENDED_FEATURES_SUPPORTED;
15201b9cb13dSMatthias Ringwald             l2cap_send_signaling_packet(connection->con_handle, INFORMATION_REQUEST, sig_id, info_type);
15211b9cb13dSMatthias Ringwald             return;
15221b9cb13dSMatthias Ringwald         }
15231b9cb13dSMatthias Ringwald     }
15241b9cb13dSMatthias Ringwald #endif
15251b9cb13dSMatthias Ringwald 
152609e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1527f2c70799Sandryblack #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
1528f2c70799Sandryblack     uint8_t  config_options[18];
1529f2c70799Sandryblack #else
153043ec931dSMatthias Ringwald     uint8_t  config_options[10];
1531f2c70799Sandryblack #endif
1532665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
1533665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1534baf94f06S[email protected] 
1535665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1536421cb104SMatthias Ringwald 
1537421cb104SMatthias Ringwald         if (channel->channel_type != L2CAP_CHANNEL_TYPE_CLASSIC) continue;
1538421cb104SMatthias Ringwald 
153922c29ab4SMatthias Ringwald         // log_info("l2cap_run: channel %p, state %u, var 0x%02x", channel, channel->state, channel->state_var);
15402cd0be45Smatthias.ringwald         switch (channel->state){
15412cd0be45Smatthias.ringwald 
1542df3354fcS[email protected]             case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE:
1543ad671560S[email protected]             case L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT:
1544fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1545a00031e2S[email protected]                 if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND) {
1546ad671560S[email protected]                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND);
1547fc64f94aSMatthias Ringwald                     l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 1, 0);
1548ad671560S[email protected]                 }
1549ad671560S[email protected]                 break;
1550ad671560S[email protected] 
155102b22dc4Smatthias.ringwald             case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
1552baf94f06S[email protected]                 if (!hci_can_send_command_packet_now()) break;
155364472d52Smatthias.ringwald                 // send connection request - set state first
155464472d52Smatthias.ringwald                 channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE;
155502b22dc4Smatthias.ringwald                 // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
1556ece97caeSMatthias Ringwald                 memcpy(l2cap_outgoing_classic_addr, channel->address, 6);
15578f8108aaSmatthias.ringwald                 hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1);
155802b22dc4Smatthias.ringwald                 break;
155902b22dc4Smatthias.ringwald 
1560e7ff783cSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE:
1561fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
156222c29ab4SMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
1563fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, channel->reason, 0);
1564e7ff783cSmatthias.ringwald                 // discard channel - l2cap_finialize_channel_close without sending l2cap close event
1565665d90f2SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1566c45d6b2cSMatthias Ringwald                 l2cap_free_channel_entry(channel);
1567e7ff783cSmatthias.ringwald                 break;
1568e7ff783cSmatthias.ringwald 
1569552d92a1Smatthias.ringwald             case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT:
1570fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1571fa8473a4Smatthias.ringwald                 channel->state = L2CAP_STATE_CONFIG;
157228ca2b46S[email protected]                 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
1573fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet(channel->con_handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0);
1574552d92a1Smatthias.ringwald                 break;
1575552d92a1Smatthias.ringwald 
15766fdcc387Smatthias.ringwald             case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST:
1577fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
15786fdcc387Smatthias.ringwald                 // success, start l2cap handshake
1579b1988dceSmatthias.ringwald                 channel->local_sig_id = l2cap_next_sig_id();
15806fdcc387Smatthias.ringwald                 channel->state = L2CAP_STATE_WAIT_CONNECT_RSP;
1581fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet( channel->con_handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid);
15825932bd7cS[email protected]                 l2cap_start_rtx(channel);
15836fdcc387Smatthias.ringwald                 break;
15846fdcc387Smatthias.ringwald 
1585fa8473a4Smatthias.ringwald             case L2CAP_STATE_CONFIG:
1586fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
158761c3f6deSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
158861c3f6deSMatthias Ringwald                     // fallback to basic mode if ERTM requested but not not supported by remote
158961c3f6deSMatthias Ringwald                      if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
159061c3f6deSMatthias Ringwald                         if (!l2cap_ertm_mode(channel)){
159161c3f6deSMatthias Ringwald                             l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_ERTM_BUFFER_RELEASED);
159261c3f6deSMatthias Ringwald                             channel->mode = L2CAP_CHANNEL_MODE_BASIC;
159361c3f6deSMatthias Ringwald                         }
159461c3f6deSMatthias Ringwald                     }
159561c3f6deSMatthias Ringwald #endif
159673cf2b3dSmatthias.ringwald                 if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
159763a7246aSmatthias.ringwald                     uint16_t flags = 0;
159828ca2b46S[email protected]                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
159963a7246aSmatthias.ringwald                     if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT) {
160063a7246aSmatthias.ringwald                         flags = 1;
160163a7246aSmatthias.ringwald                     } else {
160228ca2b46S[email protected]                         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
160363a7246aSmatthias.ringwald                     }
160463a7246aSmatthias.ringwald                     if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID){
1605ac8f1300SMatthias Ringwald                         channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
1606fc64f94aSMatthias 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);
1607ac8f1300SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
1608ac8f1300SMatthias Ringwald                     } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED){
1609ac8f1300SMatthias Ringwald                         channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED);
1610ac8f1300SMatthias Ringwald                         channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
1611b8134563SMatthias Ringwald                         uint16_t options_size = l2cap_setup_options_ertm_response(channel, config_options);
1612ac8f1300SMatthias 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);
1613b8134563SMatthias Ringwald                     } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_ERTM){
1614b8134563SMatthias Ringwald                         channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_ERTM);
1615b8134563SMatthias Ringwald                         channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
1616b8134563SMatthias Ringwald                         uint16_t options_size = l2cap_setup_options_ertm_response(channel, config_options);
1617b8134563SMatthias 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);
1618ac8f1300SMatthias Ringwald #endif
1619ac8f1300SMatthias Ringwald                     } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU){
162063a7246aSmatthias.ringwald                         channelStateVarClearFlag(channel,L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
1621b8134563SMatthias Ringwald                         uint16_t options_size = l2cap_setup_options_mtu_response(channel, config_options);
1622ac8f1300SMatthias 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);
162363a7246aSmatthias.ringwald                     } else {
1624ac8f1300SMatthias Ringwald                         l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_SUCCESS, 0, NULL);
162563a7246aSmatthias.ringwald                     }
162663a7246aSmatthias.ringwald                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT);
1627fa8473a4Smatthias.ringwald                 }
162873cf2b3dSmatthias.ringwald                 else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){
162928ca2b46S[email protected]                     channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
163028ca2b46S[email protected]                     channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ);
1631b1988dceSmatthias.ringwald                     channel->local_sig_id = l2cap_next_sig_id();
16326b99230fSMatthias Ringwald                     uint16_t options_size = l2cap_setup_options_request(channel, config_options);
16336dca2a0cSMatthias Ringwald                     l2cap_send_signaling_packet(channel->con_handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, options_size, &config_options);
16345932bd7cS[email protected]                     l2cap_start_rtx(channel);
1635fa8473a4Smatthias.ringwald                 }
1636fa8473a4Smatthias.ringwald                 if (l2cap_channel_ready_for_open(channel)){
1637552d92a1Smatthias.ringwald                     channel->state = L2CAP_STATE_OPEN;
1638552d92a1Smatthias.ringwald                     l2cap_emit_channel_opened(channel, 0);  // success
1639fa8473a4Smatthias.ringwald                 }
1640552d92a1Smatthias.ringwald                 break;
1641552d92a1Smatthias.ringwald 
1642e7ff783cSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
1643fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
164422c29ab4SMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
1645fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet( channel->con_handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);
16465932bd7cS[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 :)
1647756102d3Smatthias.ringwald                 l2cap_finialize_channel_close(channel);  // -- remove from list
164864cb054cSMatthias Ringwald                 channel = NULL;
1649e7ff783cSmatthias.ringwald                 break;
1650e7ff783cSmatthias.ringwald 
1651e7ff783cSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
1652fc64f94aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1653b1988dceSmatthias.ringwald                 channel->local_sig_id = l2cap_next_sig_id();
16542cd0be45Smatthias.ringwald                 channel->state = L2CAP_STATE_WAIT_DISCONNECT;
1655fc64f94aSMatthias Ringwald                 l2cap_send_signaling_packet( channel->con_handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);
16562cd0be45Smatthias.ringwald                 break;
16572cd0be45Smatthias.ringwald             default:
16582cd0be45Smatthias.ringwald                 break;
16592cd0be45Smatthias.ringwald         }
166038f62777SMatthias Ringwald 
16619700d53bSMilanka Ringwald 
166238f62777SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
166364cb054cSMatthias Ringwald 
16649700d53bSMilanka Ringwald         // handle channel finalize on L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE
166564cb054cSMatthias Ringwald         if (!channel) continue;
16669700d53bSMilanka Ringwald 
16679700d53bSMilanka Ringwald         // ERTM mode
16689700d53bSMilanka Ringwald         if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
16699700d53bSMilanka Ringwald 
16709700d53bSMilanka Ringwald             // check if we can still send
1671e0780573SMatthias Ringwald             if (channel->con_handle == HCI_CON_HANDLE_INVALID) continue;
167238f62777SMatthias Ringwald             if (!hci_can_send_acl_packet_now(channel->con_handle)) continue;
1673675e6881SMatthias Ringwald 
167423f7c1d6SMatthias Ringwald             // send if we have more data and remote windows isn't full yet
16759700d53bSMilanka Ringwald             log_debug("unacked_frames %u < min( stored frames %u, remote tx window size %u)?", channel->unacked_frames, channel->num_stored_tx_frames, channel->remote_tx_window_size);
167623f7c1d6SMatthias Ringwald             if (channel->unacked_frames < btstack_min(channel->num_stored_tx_frames, channel->remote_tx_window_size)){
167794301352SMatthias Ringwald                 channel->unacked_frames++;
1678675e6881SMatthias Ringwald                 int index = channel->tx_send_index;
1679675e6881SMatthias Ringwald                 channel->tx_send_index++;
1680675e6881SMatthias Ringwald                 if (channel->tx_send_index >= channel->num_tx_buffers){
1681675e6881SMatthias Ringwald                     channel->tx_send_index = 0;
1682675e6881SMatthias Ringwald                 }
16837b7901d8SMatthias Ringwald                 l2cap_ertm_send_information_frame(channel, index, 0);   // final = 0
1684675e6881SMatthias Ringwald                 continue;
1685675e6881SMatthias Ringwald             }
1686675e6881SMatthias Ringwald 
1687d84e866fSMatthias Ringwald             if (channel->send_supervisor_frame_receiver_ready){
168878cd8a22SMatthias Ringwald                 channel->send_supervisor_frame_receiver_ready = 0;
1689d2afdd38SMatthias Ringwald                 log_info("Send S-Frame: RR %u, final %u", channel->req_seq, channel->set_final_bit_after_packet_with_poll_bit_set);
1690d2afdd38SMatthias 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);
1691d2afdd38SMatthias Ringwald                 channel->set_final_bit_after_packet_with_poll_bit_set = 0;
169238f62777SMatthias Ringwald                 l2cap_ertm_send_supervisor_frame(channel, control);
1693675e6881SMatthias Ringwald                 continue;
169438f62777SMatthias Ringwald             }
169562041d70SMatthias Ringwald             if (channel->send_supervisor_frame_receiver_ready_poll){
169678cd8a22SMatthias Ringwald                 channel->send_supervisor_frame_receiver_ready_poll = 0;
169762041d70SMatthias Ringwald                 log_info("Send S-Frame: RR %u with poll=1 ", channel->req_seq);
169862041d70SMatthias Ringwald                 uint16_t control = l2cap_encanced_control_field_for_supevisor_frame( L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY, 1, 0, channel->req_seq);
169962041d70SMatthias Ringwald                 l2cap_ertm_send_supervisor_frame(channel, control);
170062041d70SMatthias Ringwald                 continue;
170162041d70SMatthias Ringwald             }
17028f1c9639SMatthias Ringwald             if (channel->send_supervisor_frame_receiver_not_ready){
170378cd8a22SMatthias Ringwald                 channel->send_supervisor_frame_receiver_not_ready = 0;
17048f1c9639SMatthias Ringwald                 log_info("Send S-Frame: RNR %u", channel->req_seq);
17058f1c9639SMatthias Ringwald                 uint16_t control = l2cap_encanced_control_field_for_supevisor_frame( L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY, 0, 0, channel->req_seq);
17068f1c9639SMatthias Ringwald                 l2cap_ertm_send_supervisor_frame(channel, control);
17078f1c9639SMatthias Ringwald                 continue;
17088f1c9639SMatthias Ringwald             }
1709c7309e8dSMatthias Ringwald             if (channel->send_supervisor_frame_reject){
1710c7309e8dSMatthias Ringwald                 channel->send_supervisor_frame_reject = 0;
1711c7309e8dSMatthias Ringwald                 log_info("Send S-Frame: REJ %u", channel->req_seq);
1712c7309e8dSMatthias Ringwald                 uint16_t control = l2cap_encanced_control_field_for_supevisor_frame( L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT, 0, 0, channel->req_seq);
1713c7309e8dSMatthias Ringwald                 l2cap_ertm_send_supervisor_frame(channel, control);
1714c7309e8dSMatthias Ringwald                 continue;
1715c7309e8dSMatthias Ringwald             }
1716df2191a7SMatthias Ringwald             if (channel->send_supervisor_frame_selective_reject){
1717df2191a7SMatthias Ringwald                 channel->send_supervisor_frame_selective_reject = 0;
1718df2191a7SMatthias Ringwald                 log_info("Send S-Frame: SREJ %u", channel->expected_tx_seq);
1719f85ade6bSMatthias 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);
1720f85ade6bSMatthias Ringwald                 channel->set_final_bit_after_packet_with_poll_bit_set = 0;
1721df2191a7SMatthias Ringwald                 l2cap_ertm_send_supervisor_frame(channel, control);
1722df2191a7SMatthias Ringwald                 continue;
1723df2191a7SMatthias Ringwald             }
17247b7901d8SMatthias Ringwald 
17257b7901d8SMatthias Ringwald             if (channel->srej_active){
17267b7901d8SMatthias Ringwald                 int i;
17277b7901d8SMatthias Ringwald                 for (i=0;i<channel->num_tx_buffers;i++){
17287b7901d8SMatthias Ringwald                     l2cap_ertm_tx_packet_state_t * tx_state = &channel->tx_packets_state[i];
17297b7901d8SMatthias Ringwald                     if (tx_state->retransmission_requested) {
17307b7901d8SMatthias Ringwald                         tx_state->retransmission_requested = 0;
1731d2afdd38SMatthias Ringwald                         uint8_t final = channel->set_final_bit_after_packet_with_poll_bit_set;
1732d2afdd38SMatthias Ringwald                         channel->set_final_bit_after_packet_with_poll_bit_set = 0;
1733d2afdd38SMatthias Ringwald                         l2cap_ertm_send_information_frame(channel, i, final);
17347b7901d8SMatthias Ringwald                         break;
17357b7901d8SMatthias Ringwald                     }
17367b7901d8SMatthias Ringwald                 }
17377b7901d8SMatthias Ringwald                 if (i == channel->num_tx_buffers){
17387b7901d8SMatthias Ringwald                     // no retransmission request found
17397b7901d8SMatthias Ringwald                     channel->srej_active = 0;
17407b7901d8SMatthias Ringwald                 } else {
17417b7901d8SMatthias Ringwald                     // packet was sent
17427b7901d8SMatthias Ringwald                     continue;
17437b7901d8SMatthias Ringwald                 }
17447b7901d8SMatthias Ringwald             }
17459700d53bSMilanka Ringwald         }
174638f62777SMatthias Ringwald #endif
174738f62777SMatthias Ringwald 
17482cd0be45Smatthias.ringwald     }
174909e9d05bSMatthias Ringwald #endif
1750da886c03S[email protected] 
1751cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
1752421cb104SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
1753efedfb4cSMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1754b5803aafSMatthias Ringwald         uint16_t mps;
1755efedfb4cSMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
1756421cb104SMatthias Ringwald 
1757421cb104SMatthias Ringwald         if (channel->channel_type != L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL) continue;
1758421cb104SMatthias Ringwald 
1759efedfb4cSMatthias Ringwald         // log_info("l2cap_run: channel %p, state %u, var 0x%02x", channel, channel->state, channel->state_var);
1760efedfb4cSMatthias Ringwald         switch (channel->state){
17615cb87675SMatthias Ringwald             case L2CAP_STATE_WILL_SEND_LE_CONNECTION_REQUEST:
17625cb87675SMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
17635cb87675SMatthias Ringwald                 channel->state = L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE;
17645cb87675SMatthias Ringwald                 // le psm, source cid, mtu, mps, initial credits
17651b8b8d05SMatthias Ringwald                 channel->local_sig_id = l2cap_next_sig_id();
176663f0ac45SMatthias Ringwald                 channel->credits_incoming =  channel->new_credits_incoming;
176763f0ac45SMatthias Ringwald                 channel->new_credits_incoming = 0;
1768b5803aafSMatthias Ringwald                 mps = btstack_min(l2cap_max_le_mtu(), channel->local_mtu);
1769b5803aafSMatthias 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, mps, channel->credits_incoming);
17705cb87675SMatthias Ringwald                 break;
177123017473SMatthias Ringwald             case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_ACCEPT:
177223017473SMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
177323017473SMatthias Ringwald                 // TODO: support larger MPS
177423017473SMatthias Ringwald                 channel->state = L2CAP_STATE_OPEN;
177563f0ac45SMatthias Ringwald                 channel->credits_incoming =  channel->new_credits_incoming;
177663f0ac45SMatthias Ringwald                 channel->new_credits_incoming = 0;
1777b5803aafSMatthias Ringwald                 mps = btstack_min(l2cap_max_le_mtu(), channel->local_mtu);
1778b5803aafSMatthias Ringwald                 l2cap_send_le_signaling_packet(channel->con_handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->local_mtu, mps, channel->credits_incoming, 0);
177964e11ca9SMatthias Ringwald                 // notify client
178044276248SMatthias Ringwald                 l2cap_emit_le_channel_opened(channel, 0);
178123017473SMatthias Ringwald                 break;
1782e7d0c9aaSMatthias Ringwald             case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE:
1783e7d0c9aaSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1784e7d0c9aaSMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
178563f0ac45SMatthias Ringwald                 l2cap_send_le_signaling_packet(channel->con_handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, 0, 0, channel->reason);
1786e7d0c9aaSMatthias Ringwald                 // discard channel - l2cap_finialize_channel_close without sending l2cap close event
1787e7d0c9aaSMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
1788c45d6b2cSMatthias Ringwald                 l2cap_free_channel_entry(channel);
1789e7d0c9aaSMatthias Ringwald                 break;
17907f107edaSMatthias Ringwald             case L2CAP_STATE_OPEN:
179185aeef60SMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
179285aeef60SMatthias Ringwald 
179385aeef60SMatthias Ringwald                 // send credits
179485aeef60SMatthias Ringwald                 if (channel->new_credits_incoming){
179585aeef60SMatthias Ringwald                     log_info("l2cap: sending %u credits", channel->new_credits_incoming);
179685aeef60SMatthias Ringwald                     channel->local_sig_id = l2cap_next_sig_id();
179785aeef60SMatthias Ringwald                     uint16_t new_credits = channel->new_credits_incoming;
179885aeef60SMatthias Ringwald                     channel->new_credits_incoming = 0;
179985aeef60SMatthias Ringwald                     channel->credits_incoming += new_credits;
180085aeef60SMatthias Ringwald                     l2cap_send_le_signaling_packet(channel->con_handle, LE_FLOW_CONTROL_CREDIT, channel->local_sig_id, channel->remote_cid, new_credits);
1801*6774d5c9SMatthias Ringwald                 }
180285aeef60SMatthias Ringwald                 break;
180385aeef60SMatthias Ringwald 
1804828a7f7aSMatthias Ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
1805828a7f7aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1806828a7f7aSMatthias Ringwald                 channel->local_sig_id = l2cap_next_sig_id();
1807828a7f7aSMatthias Ringwald                 channel->state = L2CAP_STATE_WAIT_DISCONNECT;
1808828a7f7aSMatthias Ringwald                 l2cap_send_le_signaling_packet( channel->con_handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);
1809828a7f7aSMatthias Ringwald                 break;
1810828a7f7aSMatthias Ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
1811828a7f7aSMatthias Ringwald                 if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
1812828a7f7aSMatthias Ringwald                 channel->state = L2CAP_STATE_INVALID;
1813828a7f7aSMatthias Ringwald                 l2cap_send_le_signaling_packet( channel->con_handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);
1814828a7f7aSMatthias Ringwald                 l2cap_le_finialize_channel_close(channel);  // -- remove from list
1815828a7f7aSMatthias Ringwald                 break;
1816efedfb4cSMatthias Ringwald             default:
1817efedfb4cSMatthias Ringwald                 break;
1818efedfb4cSMatthias Ringwald         }
1819efedfb4cSMatthias Ringwald     }
182009e9d05bSMatthias Ringwald #endif
1821efedfb4cSMatthias Ringwald 
182209e9d05bSMatthias Ringwald #ifdef ENABLE_BLE
1823da886c03S[email protected]     // send l2cap con paramter update if necessary
1824da886c03S[email protected]     hci_connections_get_iterator(&it);
1825665d90f2SMatthias Ringwald     while(btstack_linked_list_iterator_has_next(&it)){
1826665d90f2SMatthias Ringwald         hci_connection_t * connection = (hci_connection_t *) btstack_linked_list_iterator_next(&it);
18275d14fa8fSMatthias Ringwald         if (connection->address_type != BD_ADDR_TYPE_LE_PUBLIC && connection->address_type != BD_ADDR_TYPE_LE_RANDOM) continue;
1828b68d7bc3SMatthias Ringwald         if (!hci_can_send_acl_packet_now(connection->con_handle)) continue;
1829da886c03S[email protected]         switch (connection->le_con_parameter_update_state){
1830b68d7bc3SMatthias Ringwald             case CON_PARAMETER_UPDATE_SEND_REQUEST:
1831b68d7bc3SMatthias Ringwald                 connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE;
1832fe8aebe6SMatthias Ringwald                 l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_REQUEST, l2cap_next_sig_id(),
1833b68d7bc3SMatthias Ringwald                                                connection->le_conn_interval_min, connection->le_conn_interval_max, connection->le_conn_latency, connection->le_supervision_timeout);
1834b68d7bc3SMatthias Ringwald                 break;
1835da886c03S[email protected]             case CON_PARAMETER_UPDATE_SEND_RESPONSE:
1836b68d7bc3SMatthias Ringwald                 connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_CHANGE_HCI_CON_PARAMETERS;
1837b68d7bc3SMatthias Ringwald                 l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 0);
1838da886c03S[email protected]                 break;
1839da886c03S[email protected]             case CON_PARAMETER_UPDATE_DENY:
1840b68d7bc3SMatthias Ringwald                 connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_NONE;
1841b68d7bc3SMatthias Ringwald                 l2cap_send_le_signaling_packet(connection->con_handle, CONNECTION_PARAMETER_UPDATE_RESPONSE, connection->le_con_param_update_identifier, 1);
1842da886c03S[email protected]                 break;
1843da886c03S[email protected]             default:
1844da886c03S[email protected]                 break;
1845da886c03S[email protected]         }
1846da886c03S[email protected]     }
18474d7157c3S[email protected] #endif
1848da886c03S[email protected] 
184922c29ab4SMatthias Ringwald     // log_info("l2cap_run: exit");
18502cd0be45Smatthias.ringwald }
18512cd0be45Smatthias.ringwald 
185209e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1853fc64f94aSMatthias Ringwald static void l2cap_handle_connection_complete(hci_con_handle_t con_handle, l2cap_channel_t * channel){
18542df5dadcS[email protected]     if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
1855e5ac0afcSMatthias Ringwald         log_info("connection complete con_handle %04x - for channel %p cid 0x%04x", (int) con_handle, channel, channel->local_cid);
18562df5dadcS[email protected]         // success, start l2cap handshake
1857fc64f94aSMatthias Ringwald         channel->con_handle = con_handle;
18582df5dadcS[email protected]         // check remote SSP feature first
18592df5dadcS[email protected]         channel->state = L2CAP_STATE_WAIT_REMOTE_SUPPORTED_FEATURES;
18602df5dadcS[email protected]     }
18612df5dadcS[email protected] }
18622df5dadcS[email protected] 
18631b9cb13dSMatthias Ringwald static void l2cap_ready_to_connect(l2cap_channel_t * channel){
18641b9cb13dSMatthias Ringwald 
18651b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
186627e0774aSMatthias Ringwald     // assumption: outgoing connection
18671b9cb13dSMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
18681b9cb13dSMatthias Ringwald     if (connection->l2cap_state.information_state == L2CAP_INFORMATION_STATE_IDLE){
18691b9cb13dSMatthias Ringwald         connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_W2_SEND_EXTENDED_FEATURE_REQUEST;
18701b9cb13dSMatthias Ringwald         channel->state = L2CAP_STATE_WAIT_OUTGOING_EXTENDED_FEATURES;
18711b9cb13dSMatthias Ringwald         return;
18721b9cb13dSMatthias Ringwald     }
18731b9cb13dSMatthias Ringwald #endif
18741b9cb13dSMatthias Ringwald 
18751b9cb13dSMatthias Ringwald     // fine, go ahead
18761b9cb13dSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
18771b9cb13dSMatthias Ringwald }
18781b9cb13dSMatthias Ringwald 
18792df5dadcS[email protected] static void l2cap_handle_remote_supported_features_received(l2cap_channel_t * channel){
18802df5dadcS[email protected]     if (channel->state != L2CAP_STATE_WAIT_REMOTE_SUPPORTED_FEATURES) return;
18812df5dadcS[email protected] 
18822df5dadcS[email protected]     // we have been waiting for remote supported features, if both support SSP,
1883ac301f95S[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));
1884fc64f94aSMatthias Ringwald     if (gap_ssp_supported_on_both_sides(channel->con_handle) && !l2cap_security_level_0_allowed_for_PSM(channel->psm)){
18852df5dadcS[email protected]         // request security level 2
18862df5dadcS[email protected]         channel->state = L2CAP_STATE_WAIT_OUTGOING_SECURITY_LEVEL_UPDATE;
1887dfce2622SMilanka Ringwald         channel->required_security_level = LEVEL_2;
1888fc64f94aSMatthias Ringwald         gap_request_security_level(channel->con_handle, LEVEL_2);
18892df5dadcS[email protected]         return;
18902df5dadcS[email protected]     }
18911b9cb13dSMatthias Ringwald 
18921b9cb13dSMatthias Ringwald     l2cap_ready_to_connect(channel);
18932df5dadcS[email protected] }
189409e9d05bSMatthias Ringwald #endif
18952df5dadcS[email protected] 
189609e9d05bSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
18975d18f623SMatthias Ringwald static l2cap_channel_t * l2cap_create_channel_entry(btstack_packet_handler_t packet_handler, l2cap_channel_type_t channel_type, bd_addr_t address, bd_addr_type_t address_type,
1898da144af5SMatthias Ringwald     uint16_t psm, uint16_t local_mtu, gap_security_level_t security_level){
1899da144af5SMatthias Ringwald 
1900da144af5SMatthias Ringwald     l2cap_channel_t * channel = btstack_memory_l2cap_channel_get();
1901da144af5SMatthias Ringwald     if (!channel) {
1902da144af5SMatthias Ringwald         return NULL;
1903da144af5SMatthias Ringwald     }
1904da144af5SMatthias Ringwald 
1905da144af5SMatthias Ringwald     // fill in
1906da144af5SMatthias Ringwald     channel->packet_handler = packet_handler;
19075d18f623SMatthias Ringwald     channel->channel_type   = channel_type;
1908da144af5SMatthias Ringwald     bd_addr_copy(channel->address, address);
1909da144af5SMatthias Ringwald     channel->address_type = address_type;
1910da144af5SMatthias Ringwald     channel->psm = psm;
1911da144af5SMatthias Ringwald     channel->local_mtu  = local_mtu;
1912b37a9357SMatthias Ringwald     channel->remote_mtu = L2CAP_DEFAULT_MTU;
1913da144af5SMatthias Ringwald     channel->required_security_level = security_level;
1914da144af5SMatthias Ringwald 
1915da144af5SMatthias Ringwald     //
1916da144af5SMatthias Ringwald     channel->local_cid = l2cap_next_local_cid();
1917e0780573SMatthias Ringwald     channel->con_handle = HCI_CON_HANDLE_INVALID;
1918da144af5SMatthias Ringwald 
1919da144af5SMatthias Ringwald     // set initial state
1920da144af5SMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION;
1921da144af5SMatthias Ringwald     channel->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
1922da144af5SMatthias Ringwald     channel->remote_sig_id = L2CAP_SIG_ID_INVALID;
1923da144af5SMatthias Ringwald     channel->local_sig_id = L2CAP_SIG_ID_INVALID;
192438f62777SMatthias Ringwald 
1925c45d6b2cSMatthias Ringwald     log_info("create channel %p, local_cid 0x%04x", channel, channel->local_cid);
1926e5ac0afcSMatthias Ringwald 
1927da144af5SMatthias Ringwald     return channel;
1928da144af5SMatthias Ringwald }
1929c45d6b2cSMatthias Ringwald 
1930c45d6b2cSMatthias Ringwald static void l2cap_free_channel_entry(l2cap_channel_t * channel){
1931c45d6b2cSMatthias Ringwald     log_info("free channel %p, local_cid 0x%04x", channel, channel->local_cid);
19328f4dd6c1SMatthias Ringwald     // assert all timers are stopped
1933b5bab9c8SMatthias Ringwald     l2cap_stop_rtx(channel);
19348f4dd6c1SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
19358f4dd6c1SMatthias Ringwald     l2cap_ertm_stop_retransmission_timer(channel);
19368f4dd6c1SMatthias Ringwald     l2cap_ertm_stop_monitor_timer(channel);
19378f4dd6c1SMatthias Ringwald #endif
1938b5bab9c8SMatthias Ringwald     // free  memory
1939c45d6b2cSMatthias Ringwald     btstack_memory_l2cap_channel_free(channel);
1940c45d6b2cSMatthias Ringwald }
194109e9d05bSMatthias Ringwald #endif
194209e9d05bSMatthias Ringwald 
194309e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
1944da144af5SMatthias Ringwald 
19459077cb15SMatthias Ringwald /**
19469077cb15SMatthias Ringwald  * @brief Creates L2CAP channel to the PSM of a remote device with baseband address. A new baseband connection will be initiated if necessary.
19479077cb15SMatthias Ringwald  * @param packet_handler
19489077cb15SMatthias Ringwald  * @param address
19499077cb15SMatthias Ringwald  * @param psm
19509077cb15SMatthias Ringwald  * @param mtu
19519077cb15SMatthias Ringwald  * @param local_cid
19529077cb15SMatthias Ringwald  */
19539077cb15SMatthias Ringwald 
19549d139fbaSMatthias 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){
19559d139fbaSMatthias Ringwald     // limit MTU to the size of our outtgoing HCI buffer
19569d139fbaSMatthias Ringwald     uint16_t local_mtu = btstack_min(mtu, l2cap_max_mtu());
1957da144af5SMatthias Ringwald 
19589d139fbaSMatthias 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);
1959da144af5SMatthias Ringwald 
1960f16129ceSMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(channel_packet_handler, L2CAP_CHANNEL_TYPE_CLASSIC, address, BD_ADDR_TYPE_ACL, psm, local_mtu, LEVEL_0);
1961fc64f94aSMatthias Ringwald     if (!channel) {
19629077cb15SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
19639077cb15SMatthias Ringwald     }
19649077cb15SMatthias Ringwald 
19651b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
19661b9cb13dSMatthias Ringwald     channel->mode = L2CAP_CHANNEL_MODE_BASIC;
19671b9cb13dSMatthias Ringwald #endif
19681b9cb13dSMatthias Ringwald 
19699077cb15SMatthias Ringwald     // add to connections list
1970fc64f94aSMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
19719077cb15SMatthias Ringwald 
19729077cb15SMatthias Ringwald     // store local_cid
19739077cb15SMatthias Ringwald     if (out_local_cid){
1974fc64f94aSMatthias Ringwald        *out_local_cid = channel->local_cid;
19759077cb15SMatthias Ringwald     }
19769077cb15SMatthias Ringwald 
19779077cb15SMatthias Ringwald     // check if hci connection is already usable
1978f16129ceSMatthias Ringwald     hci_connection_t * conn = hci_connection_for_bd_addr_and_type(address, BD_ADDR_TYPE_ACL);
19799077cb15SMatthias Ringwald     if (conn){
1980e5ac0afcSMatthias Ringwald         log_info("l2cap_create_channel, hci connection 0x%04x already exists", conn->con_handle);
1981fc64f94aSMatthias Ringwald         l2cap_handle_connection_complete(conn->con_handle, channel);
19829077cb15SMatthias Ringwald         // check if remote supported fearures are already received
19839077cb15SMatthias Ringwald         if (conn->bonding_flags & BONDING_RECEIVED_REMOTE_FEATURES) {
1984fc64f94aSMatthias Ringwald             l2cap_handle_remote_supported_features_received(channel);
19859077cb15SMatthias Ringwald         }
19869077cb15SMatthias Ringwald     }
19879077cb15SMatthias Ringwald 
19889077cb15SMatthias Ringwald     l2cap_run();
19899077cb15SMatthias Ringwald 
19909077cb15SMatthias Ringwald     return 0;
19919077cb15SMatthias Ringwald }
19929077cb15SMatthias Ringwald 
19931ea99aafSMilanka Ringwald void l2cap_disconnect(uint16_t local_cid, uint8_t reason){
1994e0abb8e7S[email protected]     log_info("L2CAP_DISCONNECT local_cid 0x%x reason 0x%x", local_cid, reason);
1995b35f641cSmatthias.ringwald     // find channel for local_cid
1996b35f641cSmatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
1997f62db1e3Smatthias.ringwald     if (channel) {
1998e7ff783cSmatthias.ringwald         channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
1999f62db1e3Smatthias.ringwald     }
20002cd0be45Smatthias.ringwald     // process
20012cd0be45Smatthias.ringwald     l2cap_run();
200243625864Smatthias.ringwald }
20031e6aba47Smatthias.ringwald 
2004afde0c52Smatthias.ringwald static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t status){
2005ceec418aSMatthias Ringwald     // mark all channels before emitting open events as these could trigger new connetion requests to the same device
2006665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
2007665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
2008665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2009665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2010fad84cafSMatthias Ringwald         if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
2011058e3d6bSMatthias Ringwald         if (bd_addr_cmp( channel->address, address) != 0) continue;
2012c22aecc9S[email protected]         // channel for this address found
2013c22aecc9S[email protected]         switch (channel->state){
2014c22aecc9S[email protected]             case L2CAP_STATE_WAIT_CONNECTION_COMPLETE:
2015c22aecc9S[email protected]             case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
2016ceec418aSMatthias Ringwald                 channel->state = L2CAP_STATE_EMIT_OPEN_FAILED_AND_DISCARD;
2017c22aecc9S[email protected]                 break;
2018c22aecc9S[email protected]             default:
2019c22aecc9S[email protected]                 break;
2020afde0c52Smatthias.ringwald         }
2021afde0c52Smatthias.ringwald     }
2022ceec418aSMatthias Ringwald     // emit and free marked entries. restart loop to deal with list changes
2023ceec418aSMatthias Ringwald     int done = 0;
2024ceec418aSMatthias Ringwald     while (!done) {
2025ceec418aSMatthias Ringwald         done = 1;
2026ceec418aSMatthias Ringwald         btstack_linked_list_iterator_init(&it, &l2cap_channels);
2027ceec418aSMatthias Ringwald         while (btstack_linked_list_iterator_has_next(&it)){
2028ceec418aSMatthias Ringwald             l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2029fad84cafSMatthias Ringwald             if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
2030ceec418aSMatthias Ringwald             if (channel->state == L2CAP_STATE_EMIT_OPEN_FAILED_AND_DISCARD){
2031ceec418aSMatthias Ringwald                 done = 0;
2032ceec418aSMatthias Ringwald                 // failure, forward error code
203366a72640SMatthias Ringwald                 l2cap_handle_channel_open_failed(channel, status);
2034ceec418aSMatthias Ringwald                 // discard channel
2035ceec418aSMatthias Ringwald                 btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
2036c45d6b2cSMatthias Ringwald                 l2cap_free_channel_entry(channel);
2037ceec418aSMatthias Ringwald                 break;
2038ceec418aSMatthias Ringwald             }
2039ceec418aSMatthias Ringwald         }
2040ceec418aSMatthias Ringwald     }
2041ceec418aSMatthias Ringwald 
2042afde0c52Smatthias.ringwald }
2043afde0c52Smatthias.ringwald 
2044afde0c52Smatthias.ringwald static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t handle){
2045665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
2046665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
2047665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2048665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2049fad84cafSMatthias Ringwald         if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
2050058e3d6bSMatthias Ringwald         if ( ! bd_addr_cmp( channel->address, address) ){
20512df5dadcS[email protected]             l2cap_handle_connection_complete(handle, channel);
2052afde0c52Smatthias.ringwald         }
2053afde0c52Smatthias.ringwald     }
20546fdcc387Smatthias.ringwald     // process
20556fdcc387Smatthias.ringwald     l2cap_run();
2056afde0c52Smatthias.ringwald }
205709e9d05bSMatthias Ringwald #endif
2058b448a0e7Smatthias.ringwald 
2059*6774d5c9SMatthias Ringwald static bool l2cap_channel_ready_to_send(l2cap_channel_t * channel){
2060*6774d5c9SMatthias Ringwald     switch (channel->channel_type){
2061*6774d5c9SMatthias Ringwald #ifdef ENABLE_CLASSIC
2062*6774d5c9SMatthias Ringwald         case L2CAP_CHANNEL_TYPE_CLASSIC:
2063*6774d5c9SMatthias Ringwald             if (!channel->waiting_for_can_send_now) return false;
2064*6774d5c9SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
2065*6774d5c9SMatthias Ringwald             // skip ertm channels as they only depend on free buffers in storage
2066*6774d5c9SMatthias Ringwald             if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION) return false;
2067*6774d5c9SMatthias Ringwald #endif /* ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE */
2068*6774d5c9SMatthias Ringwald             return hci_can_send_acl_classic_packet_now() != 0;
2069*6774d5c9SMatthias Ringwald         case L2CAP_CHANNEL_TYPE_CONNECTIONLESS:
2070*6774d5c9SMatthias Ringwald             if (!channel->waiting_for_can_send_now) return false;
2071*6774d5c9SMatthias Ringwald             return hci_can_send_acl_classic_packet_now() != 0;
2072*6774d5c9SMatthias Ringwald #endif
2073*6774d5c9SMatthias Ringwald #ifdef ENABLE_BLE
2074*6774d5c9SMatthias Ringwald         case L2CAP_CHANNEL_TYPE_LE_FIXED:
2075*6774d5c9SMatthias Ringwald             if (!channel->waiting_for_can_send_now) return false;
2076*6774d5c9SMatthias Ringwald             return hci_can_send_acl_le_packet_now() != 0;
2077*6774d5c9SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2078*6774d5c9SMatthias Ringwald         case L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL:
2079*6774d5c9SMatthias Ringwald             if (channel->send_sdu_buffer == NULL) return false;
2080*6774d5c9SMatthias Ringwald             if (channel->credits_outgoing == 0) return false;
2081*6774d5c9SMatthias Ringwald             return hci_can_send_acl_le_packet_now() != 0;
2082*6774d5c9SMatthias Ringwald #endif
2083*6774d5c9SMatthias Ringwald #endif
2084*6774d5c9SMatthias Ringwald         default:
2085*6774d5c9SMatthias Ringwald             return false;
2086*6774d5c9SMatthias Ringwald     }
2087*6774d5c9SMatthias Ringwald }
2088*6774d5c9SMatthias Ringwald 
2089*6774d5c9SMatthias Ringwald static void l2cap_channel_trigger_send(l2cap_channel_t * channel){
2090*6774d5c9SMatthias Ringwald     switch (channel->channel_type){
2091*6774d5c9SMatthias Ringwald #ifdef ENABLE_BLE
2092*6774d5c9SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2093*6774d5c9SMatthias Ringwald         case L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL:
2094*6774d5c9SMatthias Ringwald             l2cap_le_send_pdu(channel);
2095*6774d5c9SMatthias Ringwald             break;
2096*6774d5c9SMatthias Ringwald #endif
2097*6774d5c9SMatthias Ringwald #endif
2098*6774d5c9SMatthias Ringwald         default:
2099*6774d5c9SMatthias Ringwald             // emit can send
2100*6774d5c9SMatthias Ringwald             channel->waiting_for_can_send_now = 0;
2101*6774d5c9SMatthias Ringwald             l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid);
2102*6774d5c9SMatthias Ringwald             break;
2103*6774d5c9SMatthias Ringwald     }
2104*6774d5c9SMatthias Ringwald }
2105*6774d5c9SMatthias Ringwald 
210633c40538SMatthias Ringwald static void l2cap_notify_channel_can_send(void){
2107*6774d5c9SMatthias Ringwald     bool done = false;
21087740e150SMatthias Ringwald     while (!done){
2109*6774d5c9SMatthias Ringwald         done = true;
211033c40538SMatthias Ringwald         btstack_linked_list_iterator_t it;
211133c40538SMatthias Ringwald         btstack_linked_list_iterator_init(&it, &l2cap_channels);
211233c40538SMatthias Ringwald         while (btstack_linked_list_iterator_has_next(&it)){
211333c40538SMatthias Ringwald             l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2114*6774d5c9SMatthias Ringwald             bool ready = l2cap_channel_ready_to_send(channel);
2115*6774d5c9SMatthias Ringwald             if (!ready) continue;
2116*6774d5c9SMatthias Ringwald 
2117*6774d5c9SMatthias Ringwald             // requeue channel for fairness
21187740e150SMatthias Ringwald             btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
21197740e150SMatthias Ringwald             btstack_linked_list_add_tail(&l2cap_channels, (btstack_linked_item_t *) channel);
2120*6774d5c9SMatthias Ringwald 
2121*6774d5c9SMatthias Ringwald             // trigger sending
2122*6774d5c9SMatthias Ringwald             l2cap_channel_trigger_send(channel);
2123*6774d5c9SMatthias Ringwald 
21247740e150SMatthias Ringwald             // exit inner loop as we just broke the iterator, but try again
2125*6774d5c9SMatthias Ringwald             done = false;
21267740e150SMatthias Ringwald             break;
21277740e150SMatthias Ringwald         }
212833c40538SMatthias Ringwald     }
212933c40538SMatthias Ringwald }
213033c40538SMatthias Ringwald 
21312053036dSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
21322053036dSMatthias Ringwald 
21332053036dSMatthias Ringwald static int l2cap_send_open_failed_on_hci_disconnect(l2cap_channel_t * channel){
21342053036dSMatthias Ringwald     // open cannot fail for for incoming connections
21352053036dSMatthias Ringwald     if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_INCOMING) return 0;
21362053036dSMatthias Ringwald 
21372053036dSMatthias Ringwald     // check state
21382053036dSMatthias Ringwald     switch (channel->state){
21392053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
21402053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_CONNECTION_COMPLETE:
21412053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_REMOTE_SUPPORTED_FEATURES:
21422053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_OUTGOING_SECURITY_LEVEL_UPDATE:
21432053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT:
21442053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_OUTGOING_EXTENDED_FEATURES:
21452053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_CONNECT_RSP:
21462053036dSMatthias Ringwald         case L2CAP_STATE_CONFIG:
21472053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST:
21482053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_LE_CONNECTION_REQUEST:
21492053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE:
2150ceec418aSMatthias Ringwald         case L2CAP_STATE_EMIT_OPEN_FAILED_AND_DISCARD:
21512053036dSMatthias Ringwald             return 1;
21522053036dSMatthias Ringwald 
21532053036dSMatthias Ringwald         case L2CAP_STATE_OPEN:
21542053036dSMatthias Ringwald         case L2CAP_STATE_CLOSED:
21552053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_INCOMING_EXTENDED_FEATURES:
21562053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_DISCONNECT:
21572053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_INSUFFICIENT_SECURITY:
21582053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE:
21592053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT:
21602053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
21612053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
21622053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE:
21632053036dSMatthias Ringwald         case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_ACCEPT:
21642053036dSMatthias Ringwald         case L2CAP_STATE_INVALID:
21652053036dSMatthias Ringwald         case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE:
21662053036dSMatthias Ringwald             return 0;
21676aa7d794SMatthias Ringwald         // no default here, to get a warning about new states
21682053036dSMatthias Ringwald     }
21696aa7d794SMatthias Ringwald     // still, the compiler insists on a return value
21706aa7d794SMatthias Ringwald     return 0;
21712053036dSMatthias Ringwald }
217213aa3e4bSMatthias Ringwald #endif
21732053036dSMatthias Ringwald 
217413aa3e4bSMatthias Ringwald #ifdef ENABLE_CLASSIC
21752053036dSMatthias Ringwald static void l2cap_handle_hci_disconnect_event(l2cap_channel_t * channel){
21762053036dSMatthias Ringwald     if (l2cap_send_open_failed_on_hci_disconnect(channel)){
217766a72640SMatthias Ringwald         l2cap_handle_channel_open_failed(channel, L2CAP_CONNECTION_BASEBAND_DISCONNECT);
21782053036dSMatthias Ringwald     } else {
217966a72640SMatthias Ringwald         l2cap_handle_channel_closed(channel);
21802053036dSMatthias Ringwald     }
2181c45d6b2cSMatthias Ringwald     l2cap_free_channel_entry(channel);
21822053036dSMatthias Ringwald }
21832053036dSMatthias Ringwald #endif
21842053036dSMatthias Ringwald 
21852cf36df7SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
21862cf36df7SMatthias Ringwald static void l2cap_handle_hci_le_disconnect_event(l2cap_channel_t * channel){
21872cf36df7SMatthias Ringwald     if (l2cap_send_open_failed_on_hci_disconnect(channel)){
21882cf36df7SMatthias Ringwald         l2cap_emit_le_channel_opened(channel, L2CAP_CONNECTION_BASEBAND_DISCONNECT);
21892cf36df7SMatthias Ringwald     } else {
21902cf36df7SMatthias Ringwald         l2cap_emit_le_channel_closed(channel);
21912cf36df7SMatthias Ringwald     }
2192c45d6b2cSMatthias Ringwald     l2cap_free_channel_entry(channel);
21932cf36df7SMatthias Ringwald }
21942cf36df7SMatthias Ringwald #endif
21952053036dSMatthias Ringwald 
2196d9a7306aSMatthias Ringwald static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *packet, uint16_t size){
2197afde0c52Smatthias.ringwald 
21985774a392SMatthias Ringwald     UNUSED(packet_type); // ok: registered with hci_event_callback_registration
21995774a392SMatthias Ringwald     UNUSED(cid);         // ok: there is no channel
22005774a392SMatthias Ringwald     UNUSED(size);        // ok: fixed format events read from HCI buffer
22019ec2630cSMatthias Ringwald 
22025774a392SMatthias Ringwald #ifdef ENABLE_CLASSIC
2203afde0c52Smatthias.ringwald     bd_addr_t address;
22042d00edd4Smatthias.ringwald     int hci_con_used;
22055774a392SMatthias Ringwald #endif
22065774a392SMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
22075774a392SMatthias Ringwald     hci_con_handle_t handle;
220809e9d05bSMatthias Ringwald     btstack_linked_list_iterator_t it;
22095774a392SMatthias Ringwald #endif
2210afde0c52Smatthias.ringwald 
22110e2df43fSMatthias Ringwald     switch(hci_event_packet_get_type(packet)){
2212afde0c52Smatthias.ringwald 
221309e9d05bSMatthias Ringwald         // Notify channel packet handler if they can send now
221409e9d05bSMatthias Ringwald         case HCI_EVENT_TRANSPORT_PACKET_SENT:
221509e9d05bSMatthias Ringwald         case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
2216eea99214SMatthias Ringwald         case BTSTACK_EVENT_NR_CONNECTIONS_CHANGED:
221709e9d05bSMatthias Ringwald             l2cap_run();    // try sending signaling packets first
221809e9d05bSMatthias Ringwald             l2cap_notify_channel_can_send();
221909e9d05bSMatthias Ringwald             break;
222009e9d05bSMatthias Ringwald 
222109e9d05bSMatthias Ringwald         case HCI_EVENT_COMMAND_STATUS:
2222ece97caeSMatthias Ringwald #ifdef ENABLE_CLASSIC
2223ece97caeSMatthias Ringwald             // check command status for create connection for errors
2224ece97caeSMatthias Ringwald             if (HCI_EVENT_IS_COMMAND_STATUS(packet, hci_create_connection)){
2225ece97caeSMatthias Ringwald                 // cache outgoing address and reset
2226ece97caeSMatthias Ringwald                 memcpy(address, l2cap_outgoing_classic_addr, 6);
2227ece97caeSMatthias Ringwald                 memset(l2cap_outgoing_classic_addr, 0, 6);
2228ece97caeSMatthias Ringwald                 // error => outgoing connection failed
2229ece97caeSMatthias Ringwald                 uint8_t status = hci_event_command_status_get_status(packet);
2230ece97caeSMatthias Ringwald                 if (status){
2231ece97caeSMatthias Ringwald                     l2cap_handle_connection_failed_for_addr(address, status);
2232ece97caeSMatthias Ringwald                 }
2233ece97caeSMatthias Ringwald             }
2234ece97caeSMatthias Ringwald #endif
223509e9d05bSMatthias Ringwald             l2cap_run();    // try sending signaling packets first
223609e9d05bSMatthias Ringwald             break;
223709e9d05bSMatthias Ringwald 
223809e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
2239afde0c52Smatthias.ringwald         // handle connection complete events
2240afde0c52Smatthias.ringwald         case HCI_EVENT_CONNECTION_COMPLETE:
2241724d70a2SMatthias Ringwald             reverse_bd_addr(&packet[5], address);
2242afde0c52Smatthias.ringwald             if (packet[2] == 0){
2243f8fbdce0SMatthias Ringwald                 handle = little_endian_read_16(packet, 3);
2244afde0c52Smatthias.ringwald                 l2cap_handle_connection_success_for_addr(address, handle);
2245afde0c52Smatthias.ringwald             } else {
2246afde0c52Smatthias.ringwald                 l2cap_handle_connection_failed_for_addr(address, packet[2]);
2247afde0c52Smatthias.ringwald             }
2248afde0c52Smatthias.ringwald             break;
2249afde0c52Smatthias.ringwald 
2250afde0c52Smatthias.ringwald         // handle successful create connection cancel command
2251afde0c52Smatthias.ringwald         case HCI_EVENT_COMMAND_COMPLETE:
2252073bd0faSMatthias Ringwald             if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_create_connection_cancel)) {
2253afde0c52Smatthias.ringwald                 if (packet[5] == 0){
2254724d70a2SMatthias Ringwald                     reverse_bd_addr(&packet[6], address);
2255afde0c52Smatthias.ringwald                     // CONNECTION TERMINATED BY LOCAL HOST (0X16)
2256afde0c52Smatthias.ringwald                     l2cap_handle_connection_failed_for_addr(address, 0x16);
225703cfbabcSmatthias.ringwald                 }
22581e6aba47Smatthias.ringwald             }
225939d59809Smatthias.ringwald             l2cap_run();    // try sending signaling packets first
226039d59809Smatthias.ringwald             break;
226109e9d05bSMatthias Ringwald #endif
226227a923d0Smatthias.ringwald 
22632053036dSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
22641e6aba47Smatthias.ringwald         // handle disconnection complete events
2265afde0c52Smatthias.ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
2266d0662982SMatthias Ringwald             handle = little_endian_read_16(packet, 3);
22672053036dSMatthias Ringwald             // send l2cap open failed or closed events for all channels on this handle and free them
2268665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
2269665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
2270665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2271fad84cafSMatthias Ringwald                 if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
2272fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
2273665d90f2SMatthias Ringwald                 btstack_linked_list_iterator_remove(&it);
2274421cb104SMatthias Ringwald                 switch(channel->channel_type){
2275421cb104SMatthias Ringwald #ifdef ENABLE_CLASSIC
2276421cb104SMatthias Ringwald                     case L2CAP_CHANNEL_TYPE_CLASSIC:
22772053036dSMatthias Ringwald                         l2cap_handle_hci_disconnect_event(channel);
2278421cb104SMatthias Ringwald                         break;
227909e9d05bSMatthias Ringwald #endif
2280a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2281421cb104SMatthias Ringwald                     case L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL:
22822cf36df7SMatthias Ringwald                         l2cap_handle_hci_le_disconnect_event(channel);
2283afde0c52Smatthias.ringwald                         break;
22842053036dSMatthias Ringwald #endif
2285421cb104SMatthias Ringwald                     default:
2286421cb104SMatthias Ringwald                         break;
2287421cb104SMatthias Ringwald                 }
2288421cb104SMatthias Ringwald             }
22899909e5e4SMatthias Ringwald             break;
2290421cb104SMatthias Ringwald #endif
2291fcadd0caSmatthias.ringwald 
22929909e5e4SMatthias Ringwald 
2293ee091cf1Smatthias.ringwald         // HCI Connection Timeouts
229409e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
2295afde0c52Smatthias.ringwald         case L2CAP_EVENT_TIMEOUT_CHECK:
2296f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet, 2);
2297bd04d84aSMatthias Ringwald             if (gap_get_connection_type(handle) != GAP_CONNECTION_ACL) break;
229880ca58a0Smatthias.ringwald             if (hci_authentication_active_for_handle(handle)) break;
22992d00edd4Smatthias.ringwald             hci_con_used = 0;
2300665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
2301665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
2302665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2303fad84cafSMatthias Ringwald                 if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
2304fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
23052d00edd4Smatthias.ringwald                 hci_con_used = 1;
2306c22aecc9S[email protected]                 break;
2307ee091cf1Smatthias.ringwald             }
23082d00edd4Smatthias.ringwald             if (hci_con_used) break;
2309d94d3cafS[email protected]             if (!hci_can_send_command_packet_now()) break;
23109edc8742Smatthias.ringwald             hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection
2311afde0c52Smatthias.ringwald             break;
2312ee091cf1Smatthias.ringwald 
2313df3354fcS[email protected]         case HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE:
2314f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet, 3);
2315665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
2316665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
2317665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2318fad84cafSMatthias Ringwald                 if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
2319fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
2320e5ac0afcSMatthias Ringwald                 log_info("remote supported features, channel %p, cid %04x - state %u", channel, channel->local_cid, channel->state);
23212df5dadcS[email protected]                 l2cap_handle_remote_supported_features_received(channel);
2322df3354fcS[email protected]             }
2323c22aecc9S[email protected]             break;
2324df3354fcS[email protected] 
23255611a760SMatthias Ringwald         case GAP_EVENT_SECURITY_LEVEL:
2326f8fbdce0SMatthias Ringwald             handle = little_endian_read_16(packet, 2);
2327e5ac0afcSMatthias Ringwald             log_info("l2cap - security level update for handle 0x%04x", handle);
2328665d90f2SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
2329665d90f2SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
2330665d90f2SMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2331fad84cafSMatthias Ringwald                 if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
2332fc64f94aSMatthias Ringwald                 if (channel->con_handle != handle) continue;
23335533f01eS[email protected] 
2334e569dfd9SMatthias Ringwald                 gap_security_level_t actual_level = (gap_security_level_t) packet[4];
23355533f01eS[email protected]                 gap_security_level_t required_level = channel->required_security_level;
23365533f01eS[email protected] 
2337e5ac0afcSMatthias Ringwald                 log_info("channel %p, cid %04x - state %u: actual %u >= required %u?", channel, channel->local_cid, channel->state, actual_level, required_level);
2338dfce2622SMilanka Ringwald 
2339df3354fcS[email protected]                 switch (channel->state){
2340df3354fcS[email protected]                     case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE:
23415533f01eS[email protected]                         if (actual_level >= required_level){
234252606043SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
234352606043SMatthias Ringwald                             // we need to know if ERTM is supported before sending a config response
234452606043SMatthias Ringwald                             hci_connection_t * connection = hci_connection_for_handle(channel->con_handle);
234552606043SMatthias Ringwald                             connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_W2_SEND_EXTENDED_FEATURE_REQUEST;
234652606043SMatthias Ringwald                             channel->state = L2CAP_STATE_WAIT_INCOMING_EXTENDED_FEATURES;
234752606043SMatthias Ringwald #else
2348f85a9399S[email protected]                             channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
234944276248SMatthias Ringwald                             l2cap_emit_incoming_connection(channel);
235052606043SMatthias Ringwald #endif
23511eb2563eS[email protected]                         } else {
2352775ecc36SMatthias Ringwald                             channel->reason = 0x0003; // security block
23531eb2563eS[email protected]                             channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
23541eb2563eS[email protected]                         }
2355df3354fcS[email protected]                         break;
2356df3354fcS[email protected] 
2357df3354fcS[email protected]                     case L2CAP_STATE_WAIT_OUTGOING_SECURITY_LEVEL_UPDATE:
23585533f01eS[email protected]                         if (actual_level >= required_level){
23591b9cb13dSMatthias Ringwald                             l2cap_ready_to_connect(channel);
2360df3354fcS[email protected]                         } else {
2361df3354fcS[email protected]                             // disconnnect, authentication not good enough
2362df3354fcS[email protected]                             hci_disconnect_security_block(handle);
2363df3354fcS[email protected]                         }
2364df3354fcS[email protected]                         break;
2365df3354fcS[email protected] 
2366df3354fcS[email protected]                     default:
2367df3354fcS[email protected]                         break;
2368df3354fcS[email protected]                 }
2369f85a9399S[email protected]             }
2370f85a9399S[email protected]             break;
237109e9d05bSMatthias Ringwald #endif
2372f85a9399S[email protected] 
2373afde0c52Smatthias.ringwald         default:
2374afde0c52Smatthias.ringwald             break;
2375afde0c52Smatthias.ringwald     }
2376afde0c52Smatthias.ringwald 
2377bd63148eS[email protected]     l2cap_run();
23781e6aba47Smatthias.ringwald }
23791e6aba47Smatthias.ringwald 
2380e74c5f58SMatthias 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){
23814cf56b4aSmatthias.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."
23822b360848Smatthias.ringwald     if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) {
23832b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].handle = handle;
23842b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].code = code;
23852b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].sig_id = sig_id;
2386e74c5f58SMatthias Ringwald         signaling_responses[signaling_responses_pending].cid = cid;
23872b360848Smatthias.ringwald         signaling_responses[signaling_responses_pending].data = data;
23882b360848Smatthias.ringwald         signaling_responses_pending++;
23892b360848Smatthias.ringwald         l2cap_run();
23902b360848Smatthias.ringwald     }
23912b360848Smatthias.ringwald }
23922b360848Smatthias.ringwald 
239309e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
239409e9d05bSMatthias Ringwald static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){
239509e9d05bSMatthias Ringwald     channel->remote_sig_id = identifier;
239609e9d05bSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
239709e9d05bSMatthias Ringwald     l2cap_run();
239809e9d05bSMatthias Ringwald }
239909e9d05bSMatthias Ringwald 
2400b35f641cSmatthias.ringwald static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){
2401645658c9Smatthias.ringwald 
24029da54300S[email protected]     // log_info("l2cap_handle_connection_request for handle %u, psm %u cid 0x%02x", handle, psm, source_cid);
2403645658c9Smatthias.ringwald     l2cap_service_t *service = l2cap_get_service(psm);
2404645658c9Smatthias.ringwald     if (!service) {
2405645658c9Smatthias.ringwald         // 0x0002 PSM not supported
2406e74c5f58SMatthias Ringwald         l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, source_cid, 0x0002);
2407645658c9Smatthias.ringwald         return;
2408645658c9Smatthias.ringwald     }
2409645658c9Smatthias.ringwald 
24105061f3afS[email protected]     hci_connection_t * hci_connection = hci_connection_for_handle( handle );
2411645658c9Smatthias.ringwald     if (!hci_connection) {
24122b360848Smatthias.ringwald         //
24139da54300S[email protected]         log_error("no hci_connection for handle %u", handle);
2414645658c9Smatthias.ringwald         return;
2415645658c9Smatthias.ringwald     }
24162bd8b7e7S[email protected] 
2417645658c9Smatthias.ringwald     // alloc structure
24189da54300S[email protected]     // log_info("l2cap_handle_connection_request register channel");
2419f16129ceSMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(service->packet_handler, L2CAP_CHANNEL_TYPE_CLASSIC, hci_connection->address, BD_ADDR_TYPE_ACL,
2420da144af5SMatthias Ringwald     psm, service->mtu, service->required_security_level);
24212b360848Smatthias.ringwald     if (!channel){
24222b360848Smatthias.ringwald         // 0x0004 No resources available
2423e74c5f58SMatthias Ringwald         l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, source_cid, 0x0004);
24242b360848Smatthias.ringwald         return;
24252b360848Smatthias.ringwald     }
2426da144af5SMatthias Ringwald 
2427fc64f94aSMatthias Ringwald     channel->con_handle = handle;
2428b35f641cSmatthias.ringwald     channel->remote_cid = source_cid;
2429b1988dceSmatthias.ringwald     channel->remote_sig_id = sig_id;
2430645658c9Smatthias.ringwald 
2431f53da564S[email protected]     // limit local mtu to max acl packet length - l2cap header
24322985cb84Smatthias.ringwald     if (channel->local_mtu > l2cap_max_mtu()) {
24332985cb84Smatthias.ringwald         channel->local_mtu = l2cap_max_mtu();
24349775e25bSmatthias.ringwald     }
24359775e25bSmatthias.ringwald 
2436645658c9Smatthias.ringwald     // set initial state
2437df3354fcS[email protected]     channel->state =      L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE;
2438a24785d0SMatthias Ringwald     channel->state_var  = (L2CAP_CHANNEL_STATE_VAR) (L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND | L2CAP_CHANNEL_STATE_VAR_INCOMING);
2439e405ae81Smatthias.ringwald 
2440645658c9Smatthias.ringwald     // add to connections list
2441665d90f2SMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
2442645658c9Smatthias.ringwald 
2443f85a9399S[email protected]     // assert security requirements
24441eb2563eS[email protected]     gap_request_security_level(handle, channel->required_security_level);
2445e405ae81Smatthias.ringwald }
2446645658c9Smatthias.ringwald 
2447ce8f182eSMatthias Ringwald void l2cap_accept_connection(uint16_t local_cid){
2448e0abb8e7S[email protected]     log_info("L2CAP_ACCEPT_CONNECTION local_cid 0x%x", local_cid);
2449b35f641cSmatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
2450e405ae81Smatthias.ringwald     if (!channel) {
2451ce8f182eSMatthias Ringwald         log_error("l2cap_accept_connection called but local_cid 0x%x not found", local_cid);
2452e405ae81Smatthias.ringwald         return;
2453e405ae81Smatthias.ringwald     }
2454e405ae81Smatthias.ringwald 
245543ec931dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
245643ec931dSMatthias Ringwald     // configure L2CAP Basic mode
245743ec931dSMatthias Ringwald     channel->mode  = L2CAP_CHANNEL_MODE_BASIC;
245843ec931dSMatthias Ringwald #endif
245943ec931dSMatthias Ringwald 
2460552d92a1Smatthias.ringwald     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
2461e405ae81Smatthias.ringwald 
2462552d92a1Smatthias.ringwald     // process
2463552d92a1Smatthias.ringwald     l2cap_run();
2464e405ae81Smatthias.ringwald }
2465645658c9Smatthias.ringwald 
24667ef6a7bbSMatthias Ringwald void l2cap_decline_connection(uint16_t local_cid){
24677ef6a7bbSMatthias Ringwald     log_info("L2CAP_DECLINE_CONNECTION local_cid 0x%x", local_cid);
2468b35f641cSmatthias.ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
2469e405ae81Smatthias.ringwald     if (!channel) {
2470ce8f182eSMatthias Ringwald         log_error( "l2cap_decline_connection called but local_cid 0x%x not found", local_cid);
2471e405ae81Smatthias.ringwald         return;
2472e405ae81Smatthias.ringwald     }
2473e7ff783cSmatthias.ringwald     channel->state  = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
24747ef6a7bbSMatthias Ringwald     channel->reason = 0x04; // no resources available
2475e7ff783cSmatthias.ringwald     l2cap_run();
2476645658c9Smatthias.ringwald }
2477645658c9Smatthias.ringwald 
2478e9cfb251SMatthias Ringwald // @pre command len is valid, see check in l2cap_signaling_handler_channel
24797f02f414SMatthias Ringwald static void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t *command){
2480b1988dceSmatthias.ringwald 
2481fcb125edSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
2482fcb125edSMatthias Ringwald     uint8_t use_fcs = 1;
2483fcb125edSMatthias Ringwald #endif
2484fcb125edSMatthias Ringwald 
2485b1988dceSmatthias.ringwald     channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
2486b1988dceSmatthias.ringwald 
2487f8fbdce0SMatthias Ringwald     uint16_t flags = little_endian_read_16(command, 6);
248863a7246aSmatthias.ringwald     if (flags & 1) {
248963a7246aSmatthias.ringwald         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT);
249063a7246aSmatthias.ringwald     }
249163a7246aSmatthias.ringwald 
24922784b77dSmatthias.ringwald     // accept the other's configuration options
2493f8fbdce0SMatthias Ringwald     uint16_t end_pos = 4 + little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
24943de7c0caSmatthias.ringwald     uint16_t pos     = 8;
24953de7c0caSmatthias.ringwald     while (pos < end_pos){
249663a7246aSmatthias.ringwald         uint8_t option_hint = command[pos] >> 7;
249763a7246aSmatthias.ringwald         uint8_t option_type = command[pos] & 0x7f;
24983844aeadSMatthias Ringwald         // log_info("l2cap cid %u, hint %u, type %u", channel->local_cid, option_hint, option_type);
249963a7246aSmatthias.ringwald         pos++;
25001dc511deSmatthias.ringwald         uint8_t length = command[pos++];
25011dc511deSmatthias.ringwald         // MTU { type(8): 1, len(8):2, MTU(16) }
2502671fb338SMatthias Ringwald         if (option_type == L2CAP_CONFIG_OPTION_TYPE_MAX_TRANSMISSION_UNIT && length == 2){
2503f8fbdce0SMatthias Ringwald             channel->remote_mtu = little_endian_read_16(command, pos);
25043844aeadSMatthias Ringwald             log_info("Remote MTU %u", channel->remote_mtu);
25059d139fbaSMatthias Ringwald             if (channel->remote_mtu > l2cap_max_mtu()){
25069d139fbaSMatthias Ringwald                 log_info("Remote MTU %u larger than outgoing buffer, only using MTU = %u", channel->remote_mtu, l2cap_max_mtu());
25079d139fbaSMatthias Ringwald                 channel->remote_mtu = l2cap_max_mtu();
25089d139fbaSMatthias Ringwald             }
250963a7246aSmatthias.ringwald             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
251063a7246aSmatthias.ringwald         }
25110fe7a9d0S[email protected]         // Flush timeout { type(8):2, len(8): 2, Flush Timeout(16)}
2512671fb338SMatthias Ringwald         if (option_type == L2CAP_CONFIG_OPTION_TYPE_FLUSH_TIMEOUT && length == 2){
2513f8fbdce0SMatthias Ringwald             channel->flush_timeout = little_endian_read_16(command, pos);
25143844aeadSMatthias Ringwald             log_info("Flush timeout: %u ms", channel->flush_timeout);
25150fe7a9d0S[email protected]         }
2516f2fa388dSMatthias Ringwald 
25176dca2a0cSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
25186dca2a0cSMatthias Ringwald         // Retransmission and Flow Control Option
2519671fb338SMatthias Ringwald         if (option_type == L2CAP_CONFIG_OPTION_TYPE_RETRANSMISSION_AND_FLOW_CONTROL && length == 9){
25203232a1c6SMatthias Ringwald             l2cap_channel_mode_t mode = (l2cap_channel_mode_t) command[pos];
2521ac8f1300SMatthias Ringwald             switch(channel->mode){
2522ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION:
252325cd60d3SMatthias Ringwald                     // Store remote config
2524bbc0a9e7SMatthias Ringwald                     channel->remote_tx_window_size = command[pos+1];
2525bbc0a9e7SMatthias Ringwald                     channel->remote_max_transmit   = command[pos+2];
2526bbc0a9e7SMatthias Ringwald                     channel->remote_retransmission_timeout_ms = little_endian_read_16(command, pos + 3);
2527bbc0a9e7SMatthias Ringwald                     channel->remote_monitor_timeout_ms = little_endian_read_16(command, pos + 5);
25283844aeadSMatthias Ringwald                     channel->remote_mps = little_endian_read_16(command, pos + 7);
25293844aeadSMatthias Ringwald                     log_info("FC&C config: tx window: %u, max transmit %u, retrans timeout %u, monitor timeout %u, mps %u",
2530bbc0a9e7SMatthias Ringwald                         channel->remote_tx_window_size,
2531bbc0a9e7SMatthias Ringwald                         channel->remote_max_transmit,
2532bbc0a9e7SMatthias Ringwald                         channel->remote_retransmission_timeout_ms,
25333844aeadSMatthias Ringwald                         channel->remote_monitor_timeout_ms,
25343844aeadSMatthias Ringwald                         channel->remote_mps);
253525cd60d3SMatthias Ringwald                     // If ERTM mandatory, but remote doens't offer ERTM -> disconnect
253625cd60d3SMatthias Ringwald                     if (channel->ertm_mandatory && mode != L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
253725cd60d3SMatthias Ringwald                         channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
2538ac8f1300SMatthias Ringwald                     } else {
2539b8134563SMatthias Ringwald                         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_ERTM);
2540ac8f1300SMatthias Ringwald                     }
2541ac8f1300SMatthias Ringwald                     break;
2542ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_BASIC:
2543ac8f1300SMatthias Ringwald                     switch (mode){
2544ac8f1300SMatthias Ringwald                         case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION:
2545ac8f1300SMatthias Ringwald                             // remote asks for ERTM, but we want basic mode. disconnect if this happens a second time
2546ac8f1300SMatthias Ringwald                             if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_BASIC_FALLBACK_TRIED){
2547ac8f1300SMatthias Ringwald                                 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
2548ac8f1300SMatthias Ringwald                             }
2549ac8f1300SMatthias Ringwald                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_BASIC_FALLBACK_TRIED);
2550ac8f1300SMatthias Ringwald                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_REJECTED);
2551ac8f1300SMatthias Ringwald                             break;
2552ac8f1300SMatthias Ringwald                         default: // case L2CAP_CHANNEL_MODE_BASIC:
2553ac8f1300SMatthias Ringwald                             // TODO store and evaluate configuration
2554b8134563SMatthias Ringwald                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_ERTM);
2555ac8f1300SMatthias Ringwald                             break;
2556ac8f1300SMatthias Ringwald                     }
2557ac8f1300SMatthias Ringwald                     break;
2558ac8f1300SMatthias Ringwald                 default:
2559ac8f1300SMatthias Ringwald                     break;
2560ac8f1300SMatthias Ringwald             }
25613232a1c6SMatthias Ringwald         }
25626574158aSMatthias Ringwald         if (option_type == L2CAP_CONFIG_OPTION_TYPE_FRAME_CHECK_SEQUENCE && length == 1){
2563fcb125edSMatthias Ringwald             use_fcs = command[pos];
25646574158aSMatthias Ringwald         }
25656dca2a0cSMatthias Ringwald #endif
256663a7246aSmatthias.ringwald         // check for unknown options
2567671fb338SMatthias Ringwald         if (option_hint == 0 && (option_type < L2CAP_CONFIG_OPTION_TYPE_MAX_TRANSMISSION_UNIT || option_type > L2CAP_CONFIG_OPTION_TYPE_EXTENDED_WINDOW_SIZE)){
2568c177a91cS[email protected]             log_info("l2cap cid %u, unknown options", channel->local_cid);
256963a7246aSmatthias.ringwald             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID);
25701dc511deSmatthias.ringwald         }
25711dc511deSmatthias.ringwald         pos += length;
25721dc511deSmatthias.ringwald     }
2573fcb125edSMatthias Ringwald 
2574fcb125edSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
2575fcb125edSMatthias Ringwald         // "FCS" has precedence over "No FCS"
2576fcb125edSMatthias Ringwald         uint8_t update = channel->fcs_option || use_fcs;
2577fcb125edSMatthias Ringwald         log_info("local fcs: %u, remote fcs: %u -> %u", channel->fcs_option, use_fcs, update);
2578fcb125edSMatthias Ringwald         channel->fcs_option = update;
257967f8f607SMatthias Ringwald         // If ERTM mandatory, but remote didn't send Retransmission and Flowcontrol options -> disconnect
258067f8f607SMatthias Ringwald         if (((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_ERTM) == 0) & (channel->ertm_mandatory)){
258167f8f607SMatthias Ringwald             channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
258267f8f607SMatthias Ringwald         }
2583fcb125edSMatthias Ringwald #endif
25842784b77dSmatthias.ringwald }
25852784b77dSmatthias.ringwald 
2586e9cfb251SMatthias Ringwald // @pre command len is valid, see check in l2cap_signaling_handler_channel
2587f2fa388dSMatthias Ringwald static void l2cap_signaling_handle_configure_response(l2cap_channel_t *channel, uint8_t result, uint8_t *command){
2588f2fa388dSMatthias Ringwald     log_info("l2cap_signaling_handle_configure_response");
25893232a1c6SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
25903232a1c6SMatthias Ringwald     uint16_t end_pos = 4 + little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
2591f2fa388dSMatthias Ringwald     uint16_t pos     = 10;
25923232a1c6SMatthias Ringwald     while (pos < end_pos){
25933232a1c6SMatthias Ringwald         uint8_t option_hint = command[pos] >> 7;
25943232a1c6SMatthias Ringwald         uint8_t option_type = command[pos] & 0x7f;
2595fcb125edSMatthias Ringwald         // log_info("l2cap cid %u, hint %u, type %u", channel->local_cid, option_hint, option_type);
25963232a1c6SMatthias Ringwald         pos++;
25973232a1c6SMatthias Ringwald         uint8_t length = command[pos++];
25983232a1c6SMatthias Ringwald 
25993232a1c6SMatthias Ringwald         // Retransmission and Flow Control Option
2600671fb338SMatthias Ringwald         if (option_type == L2CAP_CONFIG_OPTION_TYPE_RETRANSMISSION_AND_FLOW_CONTROL && length == 9){
2601ac8f1300SMatthias Ringwald             switch (channel->mode){
2602ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION:
2603f2fa388dSMatthias Ringwald                     if (channel->ertm_mandatory){
2604ac8f1300SMatthias Ringwald                         // ??
2605f2fa388dSMatthias Ringwald                     } else {
2606ac8f1300SMatthias Ringwald                         // On 'Reject - Unacceptable Parameters' to our optional ERTM request, fall back to BASIC mode
2607ac8f1300SMatthias Ringwald                         if (result == L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS){
260866a72640SMatthias Ringwald                             l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_ERTM_BUFFER_RELEASED);
2609f2fa388dSMatthias Ringwald                             channel->mode = L2CAP_CHANNEL_MODE_BASIC;
26103232a1c6SMatthias Ringwald                         }
26113232a1c6SMatthias Ringwald                     }
2612ac8f1300SMatthias Ringwald                     break;
2613ac8f1300SMatthias Ringwald                 case L2CAP_CHANNEL_MODE_BASIC:
2614ac8f1300SMatthias Ringwald                     if (result == L2CAP_CONF_RESULT_UNACCEPTABLE_PARAMETERS){
2615ac8f1300SMatthias Ringwald                         // On 'Reject - Unacceptable Parameters' to our Basic mode request, disconnect
2616ac8f1300SMatthias Ringwald                         channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
2617ac8f1300SMatthias Ringwald                     }
2618ac8f1300SMatthias Ringwald                     break;
2619ac8f1300SMatthias Ringwald                 default:
2620ac8f1300SMatthias Ringwald                     break;
26213232a1c6SMatthias Ringwald             }
2622f2fa388dSMatthias Ringwald         }
26233232a1c6SMatthias Ringwald 
26243232a1c6SMatthias Ringwald         // check for unknown options
2625671fb338SMatthias Ringwald         if (option_hint == 0 && (option_type < L2CAP_CONFIG_OPTION_TYPE_MAX_TRANSMISSION_UNIT || option_type > L2CAP_CONFIG_OPTION_TYPE_EXTENDED_WINDOW_SIZE)){
26263232a1c6SMatthias Ringwald             log_info("l2cap cid %u, unknown options", channel->local_cid);
26273232a1c6SMatthias Ringwald             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID);
26283232a1c6SMatthias Ringwald         }
26293232a1c6SMatthias Ringwald 
26303232a1c6SMatthias Ringwald         pos += length;
26313232a1c6SMatthias Ringwald     }
2632688f9764SMatthias Ringwald #else
26335774a392SMatthias Ringwald     UNUSED(channel);  // ok: no code
26345774a392SMatthias Ringwald     UNUSED(result);   // ok: no code
26355774a392SMatthias Ringwald     UNUSED(command);  // ok: no code
26363232a1c6SMatthias Ringwald #endif
26373232a1c6SMatthias Ringwald }
26383232a1c6SMatthias Ringwald 
2639fa8473a4Smatthias.ringwald static int l2cap_channel_ready_for_open(l2cap_channel_t *channel){
26409da54300S[email protected]     // log_info("l2cap_channel_ready_for_open 0x%02x", channel->state_var);
264173cf2b3dSmatthias.ringwald     if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP) == 0) return 0;
264273cf2b3dSmatthias.ringwald     if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP) == 0) return 0;
2643019f9b43SMatthias Ringwald     // addition check that fixes re-entrance issue causing l2cap event channel opened twice
2644019f9b43SMatthias Ringwald     if (channel->state == L2CAP_STATE_OPEN) return 0;
2645fa8473a4Smatthias.ringwald     return 1;
2646fa8473a4Smatthias.ringwald }
2647fa8473a4Smatthias.ringwald 
2648fa8473a4Smatthias.ringwald 
2649e9cfb251SMatthias Ringwald // @pre command len is valid, see check in l2cap_signaling_handler_dispatch
26507f02f414SMatthias Ringwald static void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){
26511e6aba47Smatthias.ringwald 
265200d93d79Smatthias.ringwald     uint8_t  code       = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
265300d93d79Smatthias.ringwald     uint8_t  identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
2654e9cfb251SMatthias Ringwald     uint16_t cmd_len    = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
265538e5900eSmatthias.ringwald     uint16_t result = 0;
26561e6aba47Smatthias.ringwald 
26579da54300S[email protected]     log_info("L2CAP signaling handler code %u, state %u", code, channel->state);
2658b35f641cSmatthias.ringwald 
26599a011532Smatthias.ringwald     // handle DISCONNECT REQUESTS seperately
26609a011532Smatthias.ringwald     if (code == DISCONNECTION_REQUEST){
26619a011532Smatthias.ringwald         switch (channel->state){
2662fa8473a4Smatthias.ringwald             case L2CAP_STATE_CONFIG:
26639a011532Smatthias.ringwald             case L2CAP_STATE_OPEN:
26642b83fb7dSmatthias.ringwald             case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
26659a011532Smatthias.ringwald             case L2CAP_STATE_WAIT_DISCONNECT:
26669a011532Smatthias.ringwald                 l2cap_handle_disconnect_request(channel, identifier);
26679a011532Smatthias.ringwald                 break;
26689a011532Smatthias.ringwald 
26699a011532Smatthias.ringwald             default:
26709a011532Smatthias.ringwald                 // ignore in other states
26719a011532Smatthias.ringwald                 break;
26729a011532Smatthias.ringwald         }
26739a011532Smatthias.ringwald         return;
26749a011532Smatthias.ringwald     }
26759a011532Smatthias.ringwald 
267656081214Smatthias.ringwald     // @STATEMACHINE(l2cap)
26771e6aba47Smatthias.ringwald     switch (channel->state) {
26781e6aba47Smatthias.ringwald 
26791e6aba47Smatthias.ringwald         case L2CAP_STATE_WAIT_CONNECT_RSP:
26801e6aba47Smatthias.ringwald             switch (code){
26811e6aba47Smatthias.ringwald                 case CONNECTION_RESPONSE:
2682e9cfb251SMatthias Ringwald                     if (cmd_len < 8){
2683e9cfb251SMatthias Ringwald                         // command imcomplete
2684e9cfb251SMatthias Ringwald                         l2cap_register_signaling_response(channel->con_handle, COMMAND_REJECT, identifier, 0, L2CAP_REJ_CMD_UNKNOWN);
2685e9cfb251SMatthias Ringwald                         break;
2686e9cfb251SMatthias Ringwald                     }
26875932bd7cS[email protected]                     l2cap_stop_rtx(channel);
2688f8fbdce0SMatthias Ringwald                     result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
268938e5900eSmatthias.ringwald                     switch (result) {
269038e5900eSmatthias.ringwald                         case 0:
2691169f8b28Smatthias.ringwald                             // successful connection
2692f8fbdce0SMatthias Ringwald                             channel->remote_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
2693fa8473a4Smatthias.ringwald                             channel->state = L2CAP_STATE_CONFIG;
269428ca2b46S[email protected]                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
269538e5900eSmatthias.ringwald                             break;
269638e5900eSmatthias.ringwald                         case 1:
26975932bd7cS[email protected]                             // connection pending. get some coffee, but start the ERTX
26985932bd7cS[email protected]                             l2cap_start_ertx(channel);
269938e5900eSmatthias.ringwald                             break;
270038e5900eSmatthias.ringwald                         default:
2701eb920dbeSmatthias.ringwald                             // channel closed
2702eb920dbeSmatthias.ringwald                             channel->state = L2CAP_STATE_CLOSED;
2703f32b992eSmatthias.ringwald                             // map l2cap connection response result to BTstack status enumeration
270466a72640SMatthias Ringwald                             l2cap_handle_channel_open_failed(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result);
2705eb920dbeSmatthias.ringwald 
2706eb920dbeSmatthias.ringwald                             // drop link key if security block
2707eb920dbeSmatthias.ringwald                             if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){
270815a95bd5SMatthias Ringwald                                 gap_drop_link_key_for_bd_addr(channel->address);
2709eb920dbeSmatthias.ringwald                             }
2710eb920dbeSmatthias.ringwald 
2711eb920dbeSmatthias.ringwald                             // discard channel
2712665d90f2SMatthias Ringwald                             btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
2713c45d6b2cSMatthias Ringwald                             l2cap_free_channel_entry(channel);
271438e5900eSmatthias.ringwald                             break;
27151e6aba47Smatthias.ringwald                     }
27161e6aba47Smatthias.ringwald                     break;
271738e5900eSmatthias.ringwald 
271838e5900eSmatthias.ringwald                 default:
27191e6aba47Smatthias.ringwald                     //@TODO: implement other signaling packets
272038e5900eSmatthias.ringwald                     break;
27211e6aba47Smatthias.ringwald             }
27221e6aba47Smatthias.ringwald             break;
27231e6aba47Smatthias.ringwald 
2724fa8473a4Smatthias.ringwald         case L2CAP_STATE_CONFIG:
2725ae280e73Smatthias.ringwald             switch (code) {
2726ae280e73Smatthias.ringwald                 case CONFIGURE_REQUEST:
2727e9cfb251SMatthias Ringwald                     if (cmd_len < 4){
2728e9cfb251SMatthias Ringwald                         // command incomplete
2729e9cfb251SMatthias Ringwald                         l2cap_register_signaling_response(channel->con_handle, COMMAND_REJECT, identifier, 0, L2CAP_REJ_CMD_UNKNOWN);
2730e9cfb251SMatthias Ringwald                         break;
2731e9cfb251SMatthias Ringwald                     }
273228ca2b46S[email protected]                     channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
2733ae280e73Smatthias.ringwald                     l2cap_signaling_handle_configure_request(channel, command);
273463a7246aSmatthias.ringwald                     if (!(channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT)){
273563a7246aSmatthias.ringwald                         // only done if continuation not set
273663a7246aSmatthias.ringwald                         channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
273763a7246aSmatthias.ringwald                     }
2738ae280e73Smatthias.ringwald                     break;
27391e6aba47Smatthias.ringwald                 case CONFIGURE_RESPONSE:
2740e9cfb251SMatthias Ringwald                     if (cmd_len < 6){
2741e9cfb251SMatthias Ringwald                         // command incomplete
2742e9cfb251SMatthias Ringwald                         l2cap_register_signaling_response(channel->con_handle, COMMAND_REJECT, identifier, 0, L2CAP_REJ_CMD_UNKNOWN);
2743e9cfb251SMatthias Ringwald                         break;
2744e9cfb251SMatthias Ringwald                     }
2745e9cfb251SMatthias Ringwald                     result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
27465932bd7cS[email protected]                     l2cap_stop_rtx(channel);
2747f2fa388dSMatthias Ringwald                     l2cap_signaling_handle_configure_response(channel, result, command);
27485932bd7cS[email protected]                     switch (result){
27495932bd7cS[email protected]                         case 0: // success
27505932bd7cS[email protected]                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
27515932bd7cS[email protected]                             break;
27525932bd7cS[email protected]                         case 4: // pending
27535932bd7cS[email protected]                             l2cap_start_ertx(channel);
27545932bd7cS[email protected]                             break;
27555932bd7cS[email protected]                         default:
2756a32d6a03SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
2757a32d6a03SMatthias Ringwald                             if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION && channel->ertm_mandatory){
2758a32d6a03SMatthias Ringwald                                 // remote does not offer ertm but it's required
2759a32d6a03SMatthias Ringwald                                 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
2760a32d6a03SMatthias Ringwald                                 break;
2761a32d6a03SMatthias Ringwald                             }
2762a32d6a03SMatthias Ringwald #endif
2763fe9d8984S[email protected]                             // retry on negative result
2764fe9d8984S[email protected]                             channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
2765fe9d8984S[email protected]                             break;
2766fe9d8984S[email protected]                     }
27675a67bd4aSmatthias.ringwald                     break;
27685a67bd4aSmatthias.ringwald                 default:
27695a67bd4aSmatthias.ringwald                     break;
27701e6aba47Smatthias.ringwald             }
2771fa8473a4Smatthias.ringwald             if (l2cap_channel_ready_for_open(channel)){
27722e4c1850SMatthias Ringwald 
27732e4c1850SMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
27742e4c1850SMatthias Ringwald                 // assert that packet can be stored in fragment buffers in ertm
27752e4c1850SMatthias Ringwald                 if (channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
27762e4c1850SMatthias Ringwald                     uint16_t effective_mps = btstack_min(channel->remote_mps, channel->local_mps);
27772e4c1850SMatthias Ringwald                     uint16_t usable_mtu = channel->num_tx_buffers == 1 ? effective_mps : channel->num_tx_buffers * effective_mps - 2;
27782e4c1850SMatthias Ringwald                     if (usable_mtu < channel->remote_mtu){
27792e4c1850SMatthias Ringwald                         log_info("Remote MTU %u > max storable ERTM packet, only using MTU = %u", channel->remote_mtu, usable_mtu);
27802e4c1850SMatthias Ringwald                         channel->remote_mtu = usable_mtu;
27812e4c1850SMatthias Ringwald                     }
27822e4c1850SMatthias Ringwald                 }
27832e4c1850SMatthias Ringwald #endif
2784fa8473a4Smatthias.ringwald                 // for open:
27855a67bd4aSmatthias.ringwald                 channel->state = L2CAP_STATE_OPEN;
2786fa8473a4Smatthias.ringwald                 l2cap_emit_channel_opened(channel, 0);
2787c8e4258aSmatthias.ringwald             }
2788c8e4258aSmatthias.ringwald             break;
2789f62db1e3Smatthias.ringwald 
2790f62db1e3Smatthias.ringwald         case L2CAP_STATE_WAIT_DISCONNECT:
2791f62db1e3Smatthias.ringwald             switch (code) {
2792f62db1e3Smatthias.ringwald                 case DISCONNECTION_RESPONSE:
279327a923d0Smatthias.ringwald                     l2cap_finialize_channel_close(channel);
279427a923d0Smatthias.ringwald                     break;
27955a67bd4aSmatthias.ringwald                 default:
27965a67bd4aSmatthias.ringwald                     //@TODO: implement other signaling packets
27975a67bd4aSmatthias.ringwald                     break;
279827a923d0Smatthias.ringwald             }
279927a923d0Smatthias.ringwald             break;
280084836b65Smatthias.ringwald 
280184836b65Smatthias.ringwald         case L2CAP_STATE_CLOSED:
280284836b65Smatthias.ringwald             // @TODO handle incoming requests
280384836b65Smatthias.ringwald             break;
280484836b65Smatthias.ringwald 
280584836b65Smatthias.ringwald         case L2CAP_STATE_OPEN:
280684836b65Smatthias.ringwald             //@TODO: implement other signaling packets, e.g. re-configure
280784836b65Smatthias.ringwald             break;
280810642e45Smatthias.ringwald         default:
280910642e45Smatthias.ringwald             break;
281027a923d0Smatthias.ringwald     }
28119da54300S[email protected]     // log_info("new state %u", channel->state);
281227a923d0Smatthias.ringwald }
281327a923d0Smatthias.ringwald 
281400d93d79Smatthias.ringwald 
2815ed2ed8e1SMatthias Ringwald // @pre command len is valid, see check in l2cap_acl_classic_handler
28167f02f414SMatthias Ringwald static void l2cap_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t * command){
281700d93d79Smatthias.ringwald 
28181b9cb13dSMatthias Ringwald     btstack_linked_list_iterator_t it;
28191b9cb13dSMatthias Ringwald 
282000d93d79Smatthias.ringwald     // get code, signalind identifier and command len
282100d93d79Smatthias.ringwald     uint8_t code     = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
282200d93d79Smatthias.ringwald     uint8_t sig_id   = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
28230493bf3aSMatthias Ringwald     uint16_t cmd_len = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
282400d93d79Smatthias.ringwald 
28251b9cb13dSMatthias Ringwald     // not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_RESPONSE
28261b9cb13dSMatthias Ringwald     if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_RESPONSE){
2827e74c5f58SMatthias Ringwald         l2cap_register_signaling_response(handle, COMMAND_REJECT, sig_id, 0, L2CAP_REJ_CMD_UNKNOWN);
282800d93d79Smatthias.ringwald         return;
282900d93d79Smatthias.ringwald     }
283000d93d79Smatthias.ringwald 
283100d93d79Smatthias.ringwald     // general commands without an assigned channel
283200d93d79Smatthias.ringwald     switch(code) {
283300d93d79Smatthias.ringwald 
28340493bf3aSMatthias Ringwald         case CONNECTION_REQUEST:
28350493bf3aSMatthias Ringwald             if (cmd_len == 4){
2836f8fbdce0SMatthias Ringwald                 uint16_t psm =        little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
2837f8fbdce0SMatthias Ringwald                 uint16_t source_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
283800d93d79Smatthias.ringwald                 l2cap_handle_connection_request(handle, sig_id, psm, source_cid);
28390493bf3aSMatthias Ringwald             } else {
28400493bf3aSMatthias Ringwald                 l2cap_register_signaling_response(handle, COMMAND_REJECT, sig_id, 0, L2CAP_REJ_CMD_UNKNOWN);
284100d93d79Smatthias.ringwald             }
28420493bf3aSMatthias Ringwald             return;
284300d93d79Smatthias.ringwald 
28442b360848Smatthias.ringwald         case ECHO_REQUEST:
2845e74c5f58SMatthias Ringwald             l2cap_register_signaling_response(handle, code, sig_id, 0, 0);
28462b83fb7dSmatthias.ringwald             return;
284700d93d79Smatthias.ringwald 
28480493bf3aSMatthias Ringwald         case INFORMATION_REQUEST:
28490493bf3aSMatthias Ringwald             if (cmd_len == 2) {
28503e64cb44SMatthias Ringwald                 uint16_t info_type = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
28513e64cb44SMatthias Ringwald                 l2cap_register_signaling_response(handle, code, sig_id, 0, info_type);
28520493bf3aSMatthias Ringwald             } else {
28530493bf3aSMatthias Ringwald                 l2cap_register_signaling_response(handle, COMMAND_REJECT, sig_id, 0, L2CAP_REJ_CMD_UNKNOWN);
285400d93d79Smatthias.ringwald             }
28550493bf3aSMatthias Ringwald             return;
285600d93d79Smatthias.ringwald 
28571b9cb13dSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
28581b9cb13dSMatthias Ringwald         case INFORMATION_RESPONSE: {
28591b9cb13dSMatthias Ringwald             hci_connection_t * connection = hci_connection_for_handle(handle);
28601b9cb13dSMatthias Ringwald             if (!connection) return;
28610defadfbSMatthias Ringwald             if (connection->l2cap_state.information_state != L2CAP_INFORMATION_STATE_W4_EXTENDED_FEATURE_RESPONSE) return;
28620defadfbSMatthias Ringwald 
28630defadfbSMatthias Ringwald             // get extended features from response if valid
28640defadfbSMatthias Ringwald             connection->l2cap_state.extended_feature_mask = 0;
28650defadfbSMatthias Ringwald             if (cmd_len >= 6) {
28661b9cb13dSMatthias Ringwald                 uint16_t info_type = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
28671b9cb13dSMatthias Ringwald                 uint16_t result    = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
28680defadfbSMatthias Ringwald                 if (result == 0 && info_type == L2CAP_INFO_TYPE_EXTENDED_FEATURES_SUPPORTED) {
28691b9cb13dSMatthias Ringwald                     connection->l2cap_state.extended_feature_mask = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
28700defadfbSMatthias Ringwald                 }
28710defadfbSMatthias Ringwald             }
28720defadfbSMatthias Ringwald             connection->l2cap_state.information_state = L2CAP_INFORMATION_STATE_DONE;
2873543b84e4SMatthias Ringwald             log_info("extended features mask 0x%02x", connection->l2cap_state.extended_feature_mask);
28740defadfbSMatthias Ringwald 
28751b9cb13dSMatthias Ringwald             // trigger connection request
28761b9cb13dSMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
28771b9cb13dSMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
28781b9cb13dSMatthias Ringwald                 l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2879fad84cafSMatthias Ringwald                 if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
2880543b84e4SMatthias Ringwald                 if (channel->con_handle != handle) continue;
2881f8ecb114SMatthias Ringwald 
2882f8ecb114SMatthias Ringwald                 // incoming connection: ask user for channel configuration, esp. if ertm will be mandatory
2883f8ecb114SMatthias Ringwald                 if (channel->state == L2CAP_STATE_WAIT_INCOMING_EXTENDED_FEATURES){
2884f8ecb114SMatthias Ringwald                     channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
2885f8ecb114SMatthias Ringwald                     l2cap_emit_incoming_connection(channel);
2886f8ecb114SMatthias Ringwald                     continue;
2887f8ecb114SMatthias Ringwald                 }
2888f8ecb114SMatthias Ringwald 
2889f8ecb114SMatthias Ringwald                 // outgoing connection
2890f8ecb114SMatthias Ringwald                 if (channel->state == L2CAP_STATE_WAIT_OUTGOING_EXTENDED_FEATURES){
2891f8ecb114SMatthias Ringwald 
2892dae3b2abSMatthias Ringwald                     // if ERTM was requested, but is not listed in extended feature mask:
2893543b84e4SMatthias Ringwald                     if ((channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION) && ((connection->l2cap_state.extended_feature_mask & 0x08) == 0)){
2894dae3b2abSMatthias Ringwald 
2895f073f086SMatthias Ringwald                         if (channel->ertm_mandatory){
2896dae3b2abSMatthias Ringwald                             // bail if ERTM is mandatory
2897543b84e4SMatthias Ringwald                             channel->state = L2CAP_STATE_CLOSED;
2898543b84e4SMatthias Ringwald                             // map l2cap connection response result to BTstack status enumeration
289966a72640SMatthias Ringwald                             l2cap_handle_channel_open_failed(channel, L2CAP_CONNECTION_RESPONSE_RESULT_ERTM_NOT_SUPPORTED);
2900543b84e4SMatthias Ringwald                             // discard channel
2901543b84e4SMatthias Ringwald                             btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
2902c45d6b2cSMatthias Ringwald                             l2cap_free_channel_entry(channel);
2903543b84e4SMatthias Ringwald                             continue;
2904dae3b2abSMatthias Ringwald 
2905f073f086SMatthias Ringwald                         } else {
2906f073f086SMatthias Ringwald                             // fallback to Basic mode
290766a72640SMatthias Ringwald                             l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_ERTM_BUFFER_RELEASED);
2908f073f086SMatthias Ringwald                             channel->mode = L2CAP_CHANNEL_MODE_BASIC;
2909f073f086SMatthias Ringwald                         }
2910dae3b2abSMatthias Ringwald                     }
2911f8ecb114SMatthias Ringwald 
291252606043SMatthias Ringwald                     // respond to connection request
2913f8ecb114SMatthias Ringwald                     channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
2914f8ecb114SMatthias Ringwald                     continue;
291552606043SMatthias Ringwald                 }
29161b9cb13dSMatthias Ringwald             }
29171b9cb13dSMatthias Ringwald             return;
29181b9cb13dSMatthias Ringwald         }
29191b9cb13dSMatthias Ringwald #endif
29201b9cb13dSMatthias Ringwald 
292100d93d79Smatthias.ringwald         default:
292200d93d79Smatthias.ringwald             break;
292300d93d79Smatthias.ringwald     }
292400d93d79Smatthias.ringwald 
292500d93d79Smatthias.ringwald     // Get potential destination CID
2926f8fbdce0SMatthias Ringwald     uint16_t dest_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
292700d93d79Smatthias.ringwald 
292800d93d79Smatthias.ringwald     // Find channel for this sig_id and connection handle
2929665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &l2cap_channels);
2930665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2931665d90f2SMatthias Ringwald         l2cap_channel_t * channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
2932fad84cafSMatthias Ringwald         if (!l2cap_is_dynamic_channel_type(channel->channel_type)) continue;
2933fc64f94aSMatthias Ringwald         if (channel->con_handle != handle) continue;
293400d93d79Smatthias.ringwald         if (code & 1) {
2935b1988dceSmatthias.ringwald             // match odd commands (responses) by previous signaling identifier
2936b1988dceSmatthias.ringwald             if (channel->local_sig_id == sig_id) {
293700d93d79Smatthias.ringwald                 l2cap_signaling_handler_channel(channel, command);
29384e32727eSmatthias.ringwald                 break;
293900d93d79Smatthias.ringwald             }
294000d93d79Smatthias.ringwald         } else {
2941b1988dceSmatthias.ringwald             // match even commands (requests) by local channel id
294200d93d79Smatthias.ringwald             if (channel->local_cid == dest_cid) {
294300d93d79Smatthias.ringwald                 l2cap_signaling_handler_channel(channel, command);
29444e32727eSmatthias.ringwald                 break;
294500d93d79Smatthias.ringwald             }
294600d93d79Smatthias.ringwald         }
294700d93d79Smatthias.ringwald     }
294800d93d79Smatthias.ringwald }
294909e9d05bSMatthias Ringwald #endif
295000d93d79Smatthias.ringwald 
2951e7d0c9aaSMatthias Ringwald #ifdef ENABLE_BLE
295209e9d05bSMatthias Ringwald 
295309e9d05bSMatthias Ringwald static void l2cap_emit_connection_parameter_update_response(hci_con_handle_t con_handle, uint16_t result){
295409e9d05bSMatthias Ringwald     uint8_t event[6];
295509e9d05bSMatthias Ringwald     event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE;
295609e9d05bSMatthias Ringwald     event[1] = 4;
295709e9d05bSMatthias Ringwald     little_endian_store_16(event, 2, con_handle);
295809e9d05bSMatthias Ringwald     little_endian_store_16(event, 4, result);
295909e9d05bSMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
296009e9d05bSMatthias Ringwald     if (!l2cap_event_packet_handler) return;
296109e9d05bSMatthias Ringwald     (*l2cap_event_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
296209e9d05bSMatthias Ringwald }
296309e9d05bSMatthias Ringwald 
2964c48b2a2cSMatthias Ringwald // @returns valid
2965c48b2a2cSMatthias Ringwald static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t * command, uint8_t sig_id){
2966e7d0c9aaSMatthias Ringwald     hci_connection_t * connection;
2967c48b2a2cSMatthias Ringwald     uint16_t result;
2968f299206dSMatthias Ringwald     uint8_t  event[12];
296983fd9c76SMatthias Ringwald 
2970cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
2971a3dc965aSMatthias Ringwald     btstack_linked_list_iterator_t it;
2972a3dc965aSMatthias Ringwald     l2cap_channel_t * channel;
2973a3dc965aSMatthias Ringwald     uint16_t local_cid;
297483fd9c76SMatthias Ringwald     uint16_t le_psm;
297563f0ac45SMatthias Ringwald     uint16_t new_credits;
297663f0ac45SMatthias Ringwald     uint16_t credits_before;
2977e7d0c9aaSMatthias Ringwald     l2cap_service_t * service;
297811cae19eSMilanka Ringwald     uint16_t source_cid;
297983fd9c76SMatthias Ringwald #endif
298000d93d79Smatthias.ringwald 
29811b8b8d05SMatthias Ringwald     uint8_t code   = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
2982adcfabadSMatthias Ringwald     uint16_t len   = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
29831fcd10b7SMatthias Ringwald     log_info("l2cap_le_signaling_handler_dispatch: command 0x%02x, sig id %u, len %u", code, sig_id, len);
29841b8b8d05SMatthias Ringwald 
29851b8b8d05SMatthias Ringwald     switch (code){
298600d93d79Smatthias.ringwald 
2987c48b2a2cSMatthias Ringwald         case CONNECTION_PARAMETER_UPDATE_REQUEST:
2988adcfabadSMatthias Ringwald             // check size
29891fcd10b7SMatthias Ringwald             if (len < 8) return 0;
2990e7d0c9aaSMatthias Ringwald             connection = hci_connection_for_handle(handle);
2991da886c03S[email protected]             if (connection){
29926d91fb6cSMatthias Ringwald                 if (connection->role != HCI_ROLE_MASTER){
29936d91fb6cSMatthias Ringwald                     // reject command without notifying upper layer when not in master role
2994c48b2a2cSMatthias Ringwald                     return 0;
29956d91fb6cSMatthias Ringwald                 }
2996a4c06b28SMatthias Ringwald                 le_connection_parameter_range_t existing_range;
29974ced4e8cSMatthias Ringwald                 gap_get_connection_parameter_range(&existing_range);
2998d5e694a3SMatthias Ringwald                 uint16_t le_conn_interval_min   = little_endian_read_16(command,L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
2999d5e694a3SMatthias Ringwald                 uint16_t le_conn_interval_max   = little_endian_read_16(command,L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
3000d5e694a3SMatthias Ringwald                 uint16_t le_conn_latency        = little_endian_read_16(command,L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
3001d5e694a3SMatthias Ringwald                 uint16_t le_supervision_timeout = little_endian_read_16(command,L2CAP_SIGNALING_COMMAND_DATA_OFFSET+6);
3002da886c03S[email protected] 
300373cd8a2aSMatthias Ringwald                 int update_parameter = gap_connection_parameter_range_included(&existing_range, le_conn_interval_min, le_conn_interval_max, le_conn_latency, le_supervision_timeout);
3004da886c03S[email protected]                 if (update_parameter){
3005da886c03S[email protected]                     connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_SEND_RESPONSE;
3006da886c03S[email protected]                     connection->le_conn_interval_min = le_conn_interval_min;
3007da886c03S[email protected]                     connection->le_conn_interval_max = le_conn_interval_max;
3008da886c03S[email protected]                     connection->le_conn_latency = le_conn_latency;
3009da886c03S[email protected]                     connection->le_supervision_timeout = le_supervision_timeout;
3010da886c03S[email protected]                 } else {
3011da886c03S[email protected]                     connection->le_con_parameter_update_state = CON_PARAMETER_UPDATE_DENY;
3012da886c03S[email protected]                 }
3013c48b2a2cSMatthias Ringwald                 connection->le_con_param_update_identifier = sig_id;
3014da886c03S[email protected]             }
3015da886c03S[email protected] 
301633c40538SMatthias Ringwald             if (!l2cap_event_packet_handler) break;
3017c48b2a2cSMatthias Ringwald 
3018c48b2a2cSMatthias Ringwald             event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_REQUEST;
3019c48b2a2cSMatthias Ringwald             event[1] = 8;
3020f299206dSMatthias Ringwald             little_endian_store_16(event, 2, handle);
3021f299206dSMatthias Ringwald             memcpy(&event[4], &command[4], 8);
3022c48b2a2cSMatthias Ringwald             hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
302333c40538SMatthias Ringwald             (*l2cap_event_packet_handler)( HCI_EVENT_PACKET, 0, event, sizeof(event));
3024ccf076adS[email protected]             break;
3025c48b2a2cSMatthias Ringwald 
30261fcd10b7SMatthias Ringwald         case CONNECTION_PARAMETER_UPDATE_RESPONSE:
30271fcd10b7SMatthias Ringwald             // check size
30281fcd10b7SMatthias Ringwald             if (len < 2) return 0;
30291fcd10b7SMatthias Ringwald             result = little_endian_read_16(command, 4);
30301fcd10b7SMatthias Ringwald             l2cap_emit_connection_parameter_update_response(handle, result);
30311fcd10b7SMatthias Ringwald             break;
30321fcd10b7SMatthias Ringwald 
3033a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
3034a3dc965aSMatthias Ringwald 
303563f0ac45SMatthias Ringwald         case COMMAND_REJECT:
303663f0ac45SMatthias Ringwald             // Find channel for this sig_id and connection handle
303763f0ac45SMatthias Ringwald             channel = NULL;
3038421cb104SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
303963f0ac45SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
304063f0ac45SMatthias Ringwald                 l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
3041fad84cafSMatthias Ringwald                 if (!l2cap_is_dynamic_channel_type(a_channel->channel_type)) continue;
304263f0ac45SMatthias Ringwald                 if (a_channel->con_handle   != handle) continue;
304363f0ac45SMatthias Ringwald                 if (a_channel->local_sig_id != sig_id) continue;
304463f0ac45SMatthias Ringwald                 channel = a_channel;
304563f0ac45SMatthias Ringwald                 break;
304663f0ac45SMatthias Ringwald             }
304763f0ac45SMatthias Ringwald             if (!channel) break;
304863f0ac45SMatthias Ringwald 
304963f0ac45SMatthias Ringwald             // if received while waiting for le connection response, assume legacy device
305063f0ac45SMatthias Ringwald             if (channel->state == L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE){
305163f0ac45SMatthias Ringwald                 channel->state = L2CAP_STATE_CLOSED;
305263f0ac45SMatthias Ringwald                 // no official value for this, use: Connection refused – LE_PSM not supported - 0x0002
305344276248SMatthias Ringwald                 l2cap_emit_le_channel_opened(channel, 0x0002);
305463f0ac45SMatthias Ringwald 
305563f0ac45SMatthias Ringwald                 // discard channel
3056421cb104SMatthias Ringwald                 btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
3057c45d6b2cSMatthias Ringwald                 l2cap_free_channel_entry(channel);
305863f0ac45SMatthias Ringwald                 break;
305963f0ac45SMatthias Ringwald             }
306063f0ac45SMatthias Ringwald             break;
306163f0ac45SMatthias Ringwald 
3062e7d0c9aaSMatthias Ringwald         case LE_CREDIT_BASED_CONNECTION_REQUEST:
3063adcfabadSMatthias Ringwald             // check size
3064adcfabadSMatthias Ringwald             if (len < 10) return 0;
3065e7d0c9aaSMatthias Ringwald 
3066e7d0c9aaSMatthias Ringwald             // get hci connection, bail if not found (must not happen)
3067e7d0c9aaSMatthias Ringwald             connection = hci_connection_for_handle(handle);
3068e7d0c9aaSMatthias Ringwald             if (!connection) return 0;
3069e7d0c9aaSMatthias Ringwald 
3070e7d0c9aaSMatthias Ringwald             // check if service registered
3071e7d0c9aaSMatthias Ringwald             le_psm  = little_endian_read_16(command, 4);
3072e7d0c9aaSMatthias Ringwald             service = l2cap_le_get_service(le_psm);
307311cae19eSMilanka Ringwald             source_cid = little_endian_read_16(command, 6);
3074e7d0c9aaSMatthias Ringwald 
3075e7d0c9aaSMatthias Ringwald             if (service){
3076e7d0c9aaSMatthias Ringwald                 if (source_cid < 0x40){
3077e7d0c9aaSMatthias Ringwald                     // 0x0009 Connection refused - Invalid Source CID
3078e74c5f58SMatthias Ringwald                     l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0009);
3079e7d0c9aaSMatthias Ringwald                     return 1;
3080e7d0c9aaSMatthias Ringwald                 }
3081e7d0c9aaSMatthias Ringwald 
3082e7d0c9aaSMatthias Ringwald                 // go through list of channels for this ACL connection and check if we get a match
3083421cb104SMatthias Ringwald                 btstack_linked_list_iterator_init(&it, &l2cap_channels);
3084e7d0c9aaSMatthias Ringwald                 while (btstack_linked_list_iterator_has_next(&it)){
30851b8b8d05SMatthias Ringwald                     l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
3086fad84cafSMatthias Ringwald                     if (!l2cap_is_dynamic_channel_type(a_channel->channel_type)) continue;
30871b8b8d05SMatthias Ringwald                     if (a_channel->con_handle != handle) continue;
30881b8b8d05SMatthias Ringwald                     if (a_channel->remote_cid != source_cid) continue;
3089e7d0c9aaSMatthias Ringwald                     // 0x000a Connection refused - Source CID already allocated
3090e74c5f58SMatthias Ringwald                     l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x000a);
3091e7d0c9aaSMatthias Ringwald                     return 1;
3092e7d0c9aaSMatthias Ringwald                 }
3093e7d0c9aaSMatthias Ringwald 
309483fd9c76SMatthias Ringwald                 // security: check encryption
309583fd9c76SMatthias Ringwald                 if (service->required_security_level >= LEVEL_2){
30969c6e867eSMatthias Ringwald                     if (gap_encryption_key_size(handle) == 0){
309783fd9c76SMatthias Ringwald                         // 0x0008 Connection refused - insufficient encryption
3098e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0008);
309983fd9c76SMatthias Ringwald                         return 1;
310083fd9c76SMatthias Ringwald                     }
310183fd9c76SMatthias Ringwald                     // anything less than 16 byte key size is insufficient
31029c6e867eSMatthias Ringwald                     if (gap_encryption_key_size(handle) < 16){
310383fd9c76SMatthias Ringwald                         // 0x0007 Connection refused – insufficient encryption key size
3104e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0007);
310583fd9c76SMatthias Ringwald                         return 1;
310683fd9c76SMatthias Ringwald                     }
310783fd9c76SMatthias Ringwald                 }
310883fd9c76SMatthias Ringwald 
310983fd9c76SMatthias Ringwald                 // security: check authencation
311083fd9c76SMatthias Ringwald                 if (service->required_security_level >= LEVEL_3){
31119c6e867eSMatthias Ringwald                     if (!gap_authenticated(handle)){
311283fd9c76SMatthias Ringwald                         // 0x0005 Connection refused – insufficient authentication
3113e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0005);
311483fd9c76SMatthias Ringwald                         return 1;
311583fd9c76SMatthias Ringwald                     }
311683fd9c76SMatthias Ringwald                 }
311783fd9c76SMatthias Ringwald 
311883fd9c76SMatthias Ringwald                 // security: check authorization
311983fd9c76SMatthias Ringwald                 if (service->required_security_level >= LEVEL_4){
31209c6e867eSMatthias Ringwald                     if (gap_authorization_state(handle) != AUTHORIZATION_GRANTED){
312183fd9c76SMatthias Ringwald                         // 0x0006 Connection refused – insufficient authorization
3122e74c5f58SMatthias Ringwald                         l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0006);
312383fd9c76SMatthias Ringwald                         return 1;
312483fd9c76SMatthias Ringwald                     }
312583fd9c76SMatthias Ringwald                 }
3126e7d0c9aaSMatthias Ringwald 
3127e7d0c9aaSMatthias Ringwald                 // allocate channel
31285d18f623SMatthias Ringwald                 channel = l2cap_create_channel_entry(service->packet_handler, L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL, connection->address,
3129e7d0c9aaSMatthias Ringwald                     BD_ADDR_TYPE_LE_RANDOM, le_psm, service->mtu, service->required_security_level);
3130e7d0c9aaSMatthias Ringwald                 if (!channel){
3131e7d0c9aaSMatthias Ringwald                     // 0x0004 Connection refused – no resources available
3132e74c5f58SMatthias Ringwald                     l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0004);
3133e7d0c9aaSMatthias Ringwald                     return 1;
3134e7d0c9aaSMatthias Ringwald                 }
3135e7d0c9aaSMatthias Ringwald 
3136e7d0c9aaSMatthias Ringwald                 channel->con_handle = handle;
3137e7d0c9aaSMatthias Ringwald                 channel->remote_cid = source_cid;
3138e7d0c9aaSMatthias Ringwald                 channel->remote_sig_id = sig_id;
31397f107edaSMatthias Ringwald                 channel->remote_mtu = little_endian_read_16(command, 8);
31407f107edaSMatthias Ringwald                 channel->remote_mps = little_endian_read_16(command, 10);
31417f107edaSMatthias Ringwald                 channel->credits_outgoing = little_endian_read_16(command, 12);
3142e7d0c9aaSMatthias Ringwald 
3143e7d0c9aaSMatthias Ringwald                 // set initial state
3144e7d0c9aaSMatthias Ringwald                 channel->state      = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
3145c99bb618SMatthias Ringwald                 channel->state_var |= L2CAP_CHANNEL_STATE_VAR_INCOMING;
3146e7d0c9aaSMatthias Ringwald 
3147e7d0c9aaSMatthias Ringwald                 // add to connections list
3148421cb104SMatthias Ringwald                 btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
3149e7d0c9aaSMatthias Ringwald 
3150e7d0c9aaSMatthias Ringwald                 // post connection request event
315144276248SMatthias Ringwald                 l2cap_emit_le_incoming_connection(channel);
3152e7d0c9aaSMatthias Ringwald 
3153e7d0c9aaSMatthias Ringwald             } else {
3154e7d0c9aaSMatthias Ringwald                 // Connection refused – LE_PSM not supported
3155e74c5f58SMatthias Ringwald                 l2cap_register_signaling_response(handle, LE_CREDIT_BASED_CONNECTION_REQUEST, sig_id, source_cid, 0x0002);
3156e7d0c9aaSMatthias Ringwald             }
3157e7d0c9aaSMatthias Ringwald             break;
31581b8b8d05SMatthias Ringwald 
31591b8b8d05SMatthias Ringwald         case LE_CREDIT_BASED_CONNECTION_RESPONSE:
3160adcfabadSMatthias Ringwald             // check size
3161adcfabadSMatthias Ringwald             if (len < 10) return 0;
3162adcfabadSMatthias Ringwald 
31631b8b8d05SMatthias Ringwald             // Find channel for this sig_id and connection handle
31641b8b8d05SMatthias Ringwald             channel = NULL;
3165421cb104SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &l2cap_channels);
31661b8b8d05SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it)){
31671b8b8d05SMatthias Ringwald                 l2cap_channel_t * a_channel = (l2cap_channel_t *) btstack_linked_list_iterator_next(&it);
3168fad84cafSMatthias Ringwald                 if (!l2cap_is_dynamic_channel_type(a_channel->channel_type)) continue;
31691b8b8d05SMatthias Ringwald                 if (a_channel->con_handle   != handle) continue;
31701b8b8d05SMatthias Ringwald                 if (a_channel->local_sig_id != sig_id) continue;
31711b8b8d05SMatthias Ringwald                 channel = a_channel;
31721b8b8d05SMatthias Ringwald                 break;
31731b8b8d05SMatthias Ringwald             }
31741b8b8d05SMatthias Ringwald             if (!channel) break;
31751b8b8d05SMatthias Ringwald 
31761b8b8d05SMatthias Ringwald             // cid + 0
31771b8b8d05SMatthias Ringwald             result = little_endian_read_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+8);
31781b8b8d05SMatthias Ringwald             if (result){
31791b8b8d05SMatthias Ringwald                 channel->state = L2CAP_STATE_CLOSED;
31801b8b8d05SMatthias Ringwald                 // map l2cap connection response result to BTstack status enumeration
318144276248SMatthias Ringwald                 l2cap_emit_le_channel_opened(channel, result);
31821b8b8d05SMatthias Ringwald 
31831b8b8d05SMatthias Ringwald                 // discard channel
3184421cb104SMatthias Ringwald                 btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
3185c45d6b2cSMatthias Ringwald                 l2cap_free_channel_entry(channel);
31861b8b8d05SMatthias Ringwald                 break;
31871b8b8d05SMatthias Ringwald             }
31881b8b8d05SMatthias Ringwald 
31891b8b8d05SMatthias Ringwald             // success
31901b8b8d05SMatthias Ringwald             channel->remote_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0);
31911b8b8d05SMatthias Ringwald             channel->remote_mtu = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 2);
31921b8b8d05SMatthias Ringwald             channel->remote_mps = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 4);
31931b8b8d05SMatthias Ringwald             channel->credits_outgoing = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 6);
31941b8b8d05SMatthias Ringwald             channel->state = L2CAP_STATE_OPEN;
319544276248SMatthias Ringwald             l2cap_emit_le_channel_opened(channel, result);
31961b8b8d05SMatthias Ringwald             break;
31971b8b8d05SMatthias Ringwald 
319885aeef60SMatthias Ringwald         case LE_FLOW_CONTROL_CREDIT:
3199adcfabadSMatthias Ringwald             // check size
3200adcfabadSMatthias Ringwald             if (len < 4) return 0;
3201adcfabadSMatthias Ringwald 
320285aeef60SMatthias Ringwald             // find channel
320385aeef60SMatthias Ringwald             local_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0);
3204421cb104SMatthias Ringwald             channel = l2cap_get_channel_for_local_cid(local_cid);
320563f0ac45SMatthias Ringwald             if (!channel) {
320663f0ac45SMatthias Ringwald                 log_error("l2cap: no channel for cid 0x%02x", local_cid);
320763f0ac45SMatthias Ringwald                 break;
320863f0ac45SMatthias Ringwald             }
320963f0ac45SMatthias Ringwald             new_credits = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 2);
321063f0ac45SMatthias Ringwald             credits_before = channel->credits_outgoing;
321163f0ac45SMatthias Ringwald             channel->credits_outgoing += new_credits;
321263f0ac45SMatthias Ringwald             // check for credit overrun
321363f0ac45SMatthias Ringwald             if (credits_before > channel->credits_outgoing){
321463f0ac45SMatthias Ringwald                 log_error("l2cap: new credits caused overrrun for cid 0x%02x, disconnecting", local_cid);
321563f0ac45SMatthias Ringwald                 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
321663f0ac45SMatthias Ringwald                 break;
321763f0ac45SMatthias Ringwald             }
321863f0ac45SMatthias Ringwald             log_info("l2cap: %u credits for 0x%02x, now %u", new_credits, local_cid, channel->credits_outgoing);
321985aeef60SMatthias Ringwald             break;
322085aeef60SMatthias Ringwald 
3221828a7f7aSMatthias Ringwald         case DISCONNECTION_REQUEST:
3222adcfabadSMatthias Ringwald 
3223adcfabadSMatthias Ringwald             // check size
3224adcfabadSMatthias Ringwald             if (len < 4) return 0;
3225adcfabadSMatthias Ringwald 
3226828a7f7aSMatthias Ringwald             // find channel
3227828a7f7aSMatthias Ringwald             local_cid = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 0);
3228421cb104SMatthias Ringwald             channel = l2cap_get_channel_for_local_cid(local_cid);
322963f34e00SMatthias Ringwald             if (!channel) {
323063f34e00SMatthias Ringwald                 log_error("l2cap: no channel for cid 0x%02x", local_cid);
323163f34e00SMatthias Ringwald                 break;
323263f34e00SMatthias Ringwald             }
3233828a7f7aSMatthias Ringwald             channel->remote_sig_id = sig_id;
3234828a7f7aSMatthias Ringwald             channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
3235828a7f7aSMatthias Ringwald             break;
3236828a7f7aSMatthias Ringwald 
3237a3dc965aSMatthias Ringwald #endif
3238a3dc965aSMatthias Ringwald 
323963f0ac45SMatthias Ringwald         case DISCONNECTION_RESPONSE:
324063f0ac45SMatthias Ringwald             break;
324163f0ac45SMatthias Ringwald 
3242c48b2a2cSMatthias Ringwald         default:
3243c48b2a2cSMatthias Ringwald             // command unknown -> reject command
3244c48b2a2cSMatthias Ringwald             return 0;
3245ccf076adS[email protected]     }
3246c48b2a2cSMatthias Ringwald     return 1;
3247c48b2a2cSMatthias Ringwald }
3248e7d0c9aaSMatthias Ringwald #endif
3249c48b2a2cSMatthias Ringwald 
3250bb0a72a6SMatthias Ringwald static void l2cap_acl_classic_handler(hci_con_handle_t handle, uint8_t *packet, uint16_t size){
3251bb0a72a6SMatthias Ringwald #ifdef ENABLE_CLASSIC
325209e9d05bSMatthias Ringwald     l2cap_channel_t * l2cap_channel;
3253fad84cafSMatthias Ringwald     l2cap_fixed_channel_t * l2cap_fixed_channel;
325409e9d05bSMatthias Ringwald 
3255c48b2a2cSMatthias Ringwald     uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
3256c48b2a2cSMatthias Ringwald     switch (channel_id) {
3257c48b2a2cSMatthias Ringwald 
3258c48b2a2cSMatthias Ringwald         case L2CAP_CID_SIGNALING: {
3259eaeabfdaSMatthias Ringwald             uint32_t command_offset = 8;
3260eaeabfdaSMatthias Ringwald             while ((command_offset + L2CAP_SIGNALING_COMMAND_DATA_OFFSET) < size) {
3261ed2ed8e1SMatthias Ringwald                 // assert signaling command is fully inside packet
3262ed2ed8e1SMatthias Ringwald                 uint16_t data_len = little_endian_read_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
3263eaeabfdaSMatthias Ringwald                 uint32_t next_command_offset = command_offset + L2CAP_SIGNALING_COMMAND_DATA_OFFSET + data_len;
3264ed2ed8e1SMatthias Ringwald                 if (next_command_offset > size){
3265ed2ed8e1SMatthias Ringwald                     log_error("l2cap signaling command len invalid -> drop");
3266ed2ed8e1SMatthias Ringwald                     break;
3267ed2ed8e1SMatthias Ringwald                 }
3268ed2ed8e1SMatthias Ringwald                 // handle signaling command
3269c48b2a2cSMatthias Ringwald                 l2cap_signaling_handler_dispatch(handle, &packet[command_offset]);
3270ed2ed8e1SMatthias Ringwald                 // go to next command
3271eaeabfdaSMatthias Ringwald                 command_offset = next_command_offset;
3272c48b2a2cSMatthias Ringwald             }
3273c48b2a2cSMatthias Ringwald             break;
3274c48b2a2cSMatthias Ringwald         }
3275c48b2a2cSMatthias Ringwald         case L2CAP_CID_CONNECTIONLESS_CHANNEL:
3276fad84cafSMatthias Ringwald             l2cap_fixed_channel = l2cap_fixed_channel_for_channel_id(L2CAP_CID_CONNECTIONLESS_CHANNEL);
3277fad84cafSMatthias Ringwald             if (!l2cap_fixed_channel) break;
3278fad84cafSMatthias Ringwald             if (!l2cap_fixed_channel->packet_handler) break;
3279fad84cafSMatthias Ringwald             (*l2cap_fixed_channel->packet_handler)(UCD_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
3280c48b2a2cSMatthias Ringwald             break;
32811bbc0b23S[email protected] 
328209e9d05bSMatthias Ringwald         default:
328300d93d79Smatthias.ringwald             // Find channel for this channel_id and connection handle
328464e11ca9SMatthias Ringwald             l2cap_channel = l2cap_get_channel_for_local_cid(channel_id);
3285d1fd2a88SMatthias Ringwald             if (l2cap_channel) {
328627e0774aSMatthias Ringwald #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
328727e0774aSMatthias Ringwald                 if (l2cap_channel->mode == L2CAP_CHANNEL_MODE_ENHANCED_RETRANSMISSION){
328827e0774aSMatthias Ringwald 
32896574158aSMatthias Ringwald                     int fcs_size = l2cap_channel->fcs_option ? 2 : 0;
329007c7de86SMatthias Ringwald 
32916574158aSMatthias Ringwald                     // assert control + FCS fields are inside
32926574158aSMatthias Ringwald                     if (size < COMPLETE_L2CAP_HEADER+2+fcs_size) break;
32936574158aSMatthias Ringwald 
32946574158aSMatthias Ringwald                     if (l2cap_channel->fcs_option){
3295fcb125edSMatthias Ringwald                         // verify FCS (required if one side requested it)
329627e0774aSMatthias Ringwald                         uint16_t fcs_calculated = crc16_calc(&packet[4], size - (4+2));
329727e0774aSMatthias Ringwald                         uint16_t fcs_packet     = little_endian_read_16(packet, size-2);
3298e288be62SMatthias Ringwald 
3299e288be62SMatthias Ringwald #ifdef L2CAP_ERTM_SIMULATE_FCS_ERROR_INTERVAL
3300e288be62SMatthias Ringwald                         // simulate fcs error
3301e288be62SMatthias Ringwald                         static int counter = 0;
3302e288be62SMatthias Ringwald                         if (++counter == L2CAP_ERTM_SIMULATE_FCS_ERROR_INTERVAL) {
3303e288be62SMatthias Ringwald                             log_info("Simulate fcs error");
3304e288be62SMatthias Ringwald                             fcs_calculated++;
3305e288be62SMatthias Ringwald                             counter = 0;
3306e288be62SMatthias Ringwald                         }
3307e288be62SMatthias Ringwald #endif
3308e288be62SMatthias Ringwald 
33096574158aSMatthias Ringwald                         if (fcs_calculated == fcs_packet){
33106574158aSMatthias Ringwald                             log_info("Packet FCS 0x%04x verified", fcs_packet);
33116574158aSMatthias Ringwald                         } else {
331227e0774aSMatthias Ringwald                             log_error("FCS mismatch! Packet 0x%04x, calculated 0x%04x", fcs_packet, fcs_calculated);
3313ef2faf56SMatthias Ringwald                             // ERTM State Machine in Bluetooth Spec does not handle 'I-Frame with invalid FCS'
331427e0774aSMatthias Ringwald                             break;
331527e0774aSMatthias Ringwald                         }
33166574158aSMatthias Ringwald                     }
331727e0774aSMatthias Ringwald 
331827e0774aSMatthias Ringwald                     // switch on packet type
331927e0774aSMatthias Ringwald                     uint16_t control = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER);
332038f62777SMatthias Ringwald                     uint8_t  req_seq = (control >> 8) & 0x3f;
33212bea1b8dSMatthias Ringwald                     int final = (control >> 7) & 0x01;
332227e0774aSMatthias Ringwald                     if (control & 1){
332327e0774aSMatthias Ringwald                         // S-Frame
332478cd8a22SMatthias Ringwald                         int poll  = (control >> 4) & 0x01;
3325bdbe2e49SMatthias Ringwald                         l2cap_supervisory_function_t s = (l2cap_supervisory_function_t) ((control >> 2) & 0x03);
33269ffcbce4SMatthias Ringwald                         log_info("Control: 0x%04x => Supervisory function %u, ReqSeq %02u", control, (int) s, req_seq);
33277b7901d8SMatthias Ringwald                         l2cap_ertm_tx_packet_state_t * tx_state;
3328bdbe2e49SMatthias Ringwald                         switch (s){
3329bdbe2e49SMatthias Ringwald                             case L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY:
33309ffcbce4SMatthias Ringwald                                 log_info("L2CAP_SUPERVISORY_FUNCTION_RR_RECEIVER_READY");
33311e1a46bbSMatthias Ringwald                                 l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
33323233d8abSMatthias Ringwald                                 if (poll && final){
33333233d8abSMatthias Ringwald                                     // S-frames shall not be transmitted with both the F-bit and the P-bit set to 1 at the same time.
33343233d8abSMatthias Ringwald                                     log_error("P=F=1 in S-Frame");
33353233d8abSMatthias Ringwald                                     break;
33363233d8abSMatthias Ringwald                                 }
333778cd8a22SMatthias Ringwald                                 if (poll){
3338f85ade6bSMatthias Ringwald                                     // check if we did request selective retransmission before <==> we have stored SDU segments
3339f85ade6bSMatthias Ringwald                                     int i;
3340f85ade6bSMatthias Ringwald                                     int num_stored_out_of_order_packets = 0;
3341f85ade6bSMatthias Ringwald                                     for (i=0;i<l2cap_channel->num_rx_buffers;i++){
3342f85ade6bSMatthias Ringwald                                         int index = l2cap_channel->rx_store_index + i;
3343f85ade6bSMatthias Ringwald                                         if (index >= l2cap_channel->num_rx_buffers){
3344f85ade6bSMatthias Ringwald                                             index -= l2cap_channel->num_rx_buffers;
3345f85ade6bSMatthias Ringwald                                         }
3346f85ade6bSMatthias Ringwald                                         l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
3347f85ade6bSMatthias Ringwald                                         if (!rx_state->valid) continue;
3348f85ade6bSMatthias Ringwald                                         num_stored_out_of_order_packets++;
3349f85ade6bSMatthias Ringwald                                     }
3350f85ade6bSMatthias Ringwald                                     if (num_stored_out_of_order_packets){
3351f85ade6bSMatthias Ringwald                                         l2cap_channel->send_supervisor_frame_selective_reject = 1;
3352f85ade6bSMatthias Ringwald                                     } else {
3353d2afdd38SMatthias Ringwald                                         l2cap_channel->send_supervisor_frame_receiver_ready   = 1;
335478cd8a22SMatthias Ringwald                                     }
3355f85ade6bSMatthias Ringwald                                     l2cap_channel->set_final_bit_after_packet_with_poll_bit_set = 1;
3356f85ade6bSMatthias Ringwald                                 }
33573233d8abSMatthias Ringwald                                 if (final){
3358550189ffSMatthias Ringwald                                     // Stop-MonitorTimer
3359550189ffSMatthias Ringwald                                     l2cap_ertm_stop_monitor_timer(l2cap_channel);
3360550189ffSMatthias Ringwald                                     // If UnackedFrames > 0 then Start-RetransTimer
336194301352SMatthias Ringwald                                     if (l2cap_channel->unacked_frames){
3362550189ffSMatthias Ringwald                                         l2cap_ertm_start_retransmission_timer(l2cap_channel);
3363550189ffSMatthias Ringwald                                     }
33643233d8abSMatthias Ringwald                                     // final bit set <- response to RR with poll bit set. All not acknowledged packets need to be retransmitted
3365ef2faf56SMatthias Ringwald                                     l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
33663233d8abSMatthias Ringwald                                 }
3367bdbe2e49SMatthias Ringwald                                 break;
33689ffcbce4SMatthias Ringwald                             case L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT:
33699ffcbce4SMatthias Ringwald                                 log_info("L2CAP_SUPERVISORY_FUNCTION_REJ_REJECT");
33701e1a46bbSMatthias Ringwald                                 l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
3371600cf12dSMatthias Ringwald                                 // restart transmittion from last unacknowledted packet (earlier packets already freed in l2cap_ertm_process_req_seq)
3372ef2faf56SMatthias Ringwald                                 l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
33739ffcbce4SMatthias Ringwald                                 break;
33749ffcbce4SMatthias Ringwald                             case L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY:
33759ffcbce4SMatthias Ringwald                                 log_error("L2CAP_SUPERVISORY_FUNCTION_RNR_RECEIVER_NOT_READY");
33769ffcbce4SMatthias Ringwald                                 break;
33779ffcbce4SMatthias Ringwald                             case L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT:
33787b7901d8SMatthias Ringwald                                 log_info("L2CAP_SUPERVISORY_FUNCTION_SREJ_SELECTIVE_REJECT");
33797b7901d8SMatthias Ringwald                                 if (poll){
33801e1a46bbSMatthias Ringwald                                     l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
33817b7901d8SMatthias Ringwald                                 }
33827b7901d8SMatthias Ringwald                                 // find requested i-frame
33837b7901d8SMatthias Ringwald                                 tx_state = l2cap_ertm_get_tx_state(l2cap_channel, req_seq);
33847b7901d8SMatthias Ringwald                                 if (tx_state){
33857b7901d8SMatthias Ringwald                                     log_info("Retransmission for tx_seq %u requested", req_seq);
3386d2afdd38SMatthias Ringwald                                     l2cap_channel->set_final_bit_after_packet_with_poll_bit_set = poll;
33877b7901d8SMatthias Ringwald                                     tx_state->retransmission_requested = 1;
33887b7901d8SMatthias Ringwald                                     l2cap_channel->srej_active = 1;
33897b7901d8SMatthias Ringwald                                 }
33909ffcbce4SMatthias Ringwald                                 break;
3391bdbe2e49SMatthias Ringwald                             default:
3392bdbe2e49SMatthias Ringwald                                 break;
3393bdbe2e49SMatthias Ringwald                         }
339427e0774aSMatthias Ringwald                         break;
339527e0774aSMatthias Ringwald                     } else {
339627e0774aSMatthias Ringwald                         // I-Frame
339727e0774aSMatthias Ringwald                         // get control
339827e0774aSMatthias Ringwald                         l2cap_segmentation_and_reassembly_t sar = (l2cap_segmentation_and_reassembly_t) (control >> 14);
339938f62777SMatthias Ringwald                         uint8_t tx_seq = (control >> 1) & 0x3f;
340038f62777SMatthias Ringwald                         log_info("Control: 0x%04x => SAR %u, ReqSeq %02u, R?, TxSeq %02u", control, (int) sar, req_seq, tx_seq);
3401e8e9809fSMatthias Ringwald                         log_info("SAR: pos %u", l2cap_channel->reassembly_pos);
340238f62777SMatthias Ringwald                         log_info("State: expected_tx_seq %02u, req_seq %02u", l2cap_channel->expected_tx_seq, l2cap_channel->req_seq);
34031e1a46bbSMatthias Ringwald                         l2cap_ertm_process_req_seq(l2cap_channel, req_seq);
340411b576c5SMatthias Ringwald                         if (final){
340511b576c5SMatthias Ringwald                             // final bit set <- response to RR with poll bit set. All not acknowledged packets need to be retransmitted
3406ef2faf56SMatthias Ringwald                             l2cap_ertm_retransmit_unacknowleded_frames(l2cap_channel);
340711b576c5SMatthias Ringwald                         }
340807c7de86SMatthias Ringwald 
340907c7de86SMatthias Ringwald                         // get SDU
3410826c39d0SMatthias Ringwald                         const uint8_t * payload_data = &packet[COMPLETE_L2CAP_HEADER+2];
3411826c39d0SMatthias Ringwald                         uint16_t        payload_len  = size-(COMPLETE_L2CAP_HEADER+2+fcs_size);
341207c7de86SMatthias Ringwald 
341307c7de86SMatthias Ringwald                         // assert SDU size is smaller or equal to our buffers
3414826c39d0SMatthias Ringwald                         uint16_t max_payload_size = 0;
3415826c39d0SMatthias Ringwald                         switch (sar){
3416826c39d0SMatthias Ringwald                             case L2CAP_SEGMENTATION_AND_REASSEMBLY_UNSEGMENTED_L2CAP_SDU:
3417826c39d0SMatthias Ringwald                             case L2CAP_SEGMENTATION_AND_REASSEMBLY_START_OF_L2CAP_SDU:
3418826c39d0SMatthias Ringwald                                 // SDU Length + MPS
3419826c39d0SMatthias Ringwald                                 max_payload_size = l2cap_channel->local_mps + 2;
3420826c39d0SMatthias Ringwald                                 break;
3421826c39d0SMatthias Ringwald                             case L2CAP_SEGMENTATION_AND_REASSEMBLY_CONTINUATION_OF_L2CAP_SDU:
3422826c39d0SMatthias Ringwald                             case L2CAP_SEGMENTATION_AND_REASSEMBLY_END_OF_L2CAP_SDU:
3423826c39d0SMatthias Ringwald                                 max_payload_size = l2cap_channel->local_mps;
3424826c39d0SMatthias Ringwald                                 break;
3425826c39d0SMatthias Ringwald                         }
3426826c39d0SMatthias Ringwald                         if (payload_len > max_payload_size){
3427826c39d0SMatthias Ringwald                             log_info("payload len %u > max payload %u -> drop packet", payload_len, max_payload_size);
3428826c39d0SMatthias Ringwald                             break;
3429826c39d0SMatthias Ringwald                         }
343007c7de86SMatthias Ringwald 
343138f62777SMatthias Ringwald                         // check ordering
343238f62777SMatthias Ringwald                         if (l2cap_channel->expected_tx_seq == tx_seq){
343338f62777SMatthias Ringwald                             log_info("Received expected frame with TxSeq == ExpectedTxSeq == %02u", tx_seq);
343438f62777SMatthias Ringwald                             l2cap_channel->expected_tx_seq = l2cap_next_ertm_seq_nr(l2cap_channel->expected_tx_seq);
3435f85ade6bSMatthias Ringwald                             l2cap_channel->req_seq         = l2cap_channel->expected_tx_seq;
3436d48432d4SMatthias Ringwald 
3437e32be409SMatthias Ringwald                             // process SDU
3438826c39d0SMatthias Ringwald                             l2cap_ertm_handle_in_sequence_sdu(l2cap_channel, sar, payload_data, payload_len);
3439d48432d4SMatthias Ringwald 
344070734707SMatthias Ringwald                             // process stored segments
344170734707SMatthias Ringwald                             while (1){
344270734707SMatthias Ringwald                                 int index = l2cap_channel->rx_store_index;
344370734707SMatthias Ringwald                                 l2cap_ertm_rx_packet_state_t * rx_state = &l2cap_channel->rx_packets_state[index];
344470734707SMatthias Ringwald                                 if (!rx_state->valid) break;
3445f85ade6bSMatthias Ringwald 
3446f85ade6bSMatthias Ringwald                                 log_info("Processing stored frame with TxSeq == ExpectedTxSeq == %02u", l2cap_channel->expected_tx_seq);
3447f85ade6bSMatthias Ringwald                                 l2cap_channel->expected_tx_seq = l2cap_next_ertm_seq_nr(l2cap_channel->expected_tx_seq);
3448f85ade6bSMatthias Ringwald                                 l2cap_channel->req_seq         = l2cap_channel->expected_tx_seq;
3449f85ade6bSMatthias Ringwald 
345070734707SMatthias Ringwald                                 rx_state->valid = 0;
345170734707SMatthias Ringwald                                 l2cap_ertm_handle_in_sequence_sdu(l2cap_channel, rx_state->sar, &l2cap_channel->rx_packets_data[index], rx_state->len);
3452f85ade6bSMatthias Ringwald 
3453f85ade6bSMatthias Ringwald                                 // update rx store index
345470734707SMatthias Ringwald                                 index++;
345570734707SMatthias Ringwald                                 if (index >= l2cap_channel->num_rx_buffers){
345670734707SMatthias Ringwald                                     index = 0;
345770734707SMatthias Ringwald                                 }
345870734707SMatthias Ringwald                                 l2cap_channel->rx_store_index = index;
345970734707SMatthias Ringwald                             }
346070734707SMatthias Ringwald 
3461f85ade6bSMatthias Ringwald                             //
3462f85ade6bSMatthias Ringwald                             l2cap_channel->send_supervisor_frame_receiver_ready = 1;
3463f85ade6bSMatthias Ringwald 
3464c7309e8dSMatthias Ringwald                         } else {
3465df2191a7SMatthias Ringwald                             int delta = (tx_seq - l2cap_channel->expected_tx_seq) & 0x3f;
3466df2191a7SMatthias Ringwald                             if (delta < 2){
346770734707SMatthias Ringwald                                 // store segment
3468826c39d0SMatthias Ringwald                                 l2cap_ertm_handle_out_of_sequence_sdu(l2cap_channel, sar, delta, payload_data, payload_len);
346970734707SMatthias Ringwald 
3470df2191a7SMatthias Ringwald                                 log_info("Received unexpected frame TxSeq %u but expected %u -> send S-SREJ", tx_seq, l2cap_channel->expected_tx_seq);
3471df2191a7SMatthias Ringwald                                 l2cap_channel->send_supervisor_frame_selective_reject = 1;
3472df2191a7SMatthias Ringwald                             } else {
3473df2191a7SMatthias Ringwald                                 log_info("Received unexpected frame TxSeq %u but expected %u -> send S-REJ", tx_seq, l2cap_channel->expected_tx_seq);
3474c7309e8dSMatthias Ringwald                                 l2cap_channel->send_supervisor_frame_reject = 1;
347527e0774aSMatthias Ringwald                             }
347638f62777SMatthias Ringwald                         }
3477df2191a7SMatthias Ringwald                     }
347827e0774aSMatthias Ringwald                     break;
347927e0774aSMatthias Ringwald                 }
348027e0774aSMatthias Ringwald #endif
34813d50b4baSMatthias Ringwald                 l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
348200d93d79Smatthias.ringwald             }
3483bb0a72a6SMatthias Ringwald             break;
3484bb0a72a6SMatthias Ringwald     }
3485bb0a72a6SMatthias Ringwald #else
3486bb0a72a6SMatthias Ringwald     UNUSED(handle); // ok: no code
3487bb0a72a6SMatthias Ringwald     UNUSED(packet); // ok: no code
3488bb0a72a6SMatthias Ringwald     UNUSED(size);   // ok: no code
348909e9d05bSMatthias Ringwald #endif
3490bb0a72a6SMatthias Ringwald }
3491bb0a72a6SMatthias Ringwald 
3492bb0a72a6SMatthias Ringwald static void l2cap_acl_le_handler(hci_con_handle_t handle, uint8_t *packet, uint16_t size){
3493bb0a72a6SMatthias Ringwald #ifdef ENABLE_BLE
3494bb0a72a6SMatthias Ringwald 
3495fad84cafSMatthias Ringwald     l2cap_fixed_channel_t * l2cap_fixed_channel;
3496fad84cafSMatthias Ringwald 
3497bb0a72a6SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
3498bb0a72a6SMatthias Ringwald     l2cap_channel_t * l2cap_channel;
3499bb0a72a6SMatthias Ringwald #endif
3500bb0a72a6SMatthias Ringwald     uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
3501bb0a72a6SMatthias Ringwald     switch (channel_id) {
3502bb0a72a6SMatthias Ringwald 
3503bb0a72a6SMatthias Ringwald         case L2CAP_CID_SIGNALING_LE: {
3504bb0a72a6SMatthias Ringwald             uint16_t sig_id = packet[COMPLETE_L2CAP_HEADER + 1];
3505adcfabadSMatthias Ringwald             uint16_t len = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER + 2);
3506adcfabadSMatthias Ringwald             if (COMPLETE_L2CAP_HEADER + 4 + len > size) break;
3507bb0a72a6SMatthias Ringwald             int      valid  = l2cap_le_signaling_handler_dispatch(handle, &packet[COMPLETE_L2CAP_HEADER], sig_id);
3508bb0a72a6SMatthias Ringwald             if (!valid){
3509bb0a72a6SMatthias Ringwald                 l2cap_register_signaling_response(handle, COMMAND_REJECT_LE, sig_id, 0, L2CAP_REJ_CMD_UNKNOWN);
3510bb0a72a6SMatthias Ringwald             }
3511bb0a72a6SMatthias Ringwald             break;
3512bb0a72a6SMatthias Ringwald         }
3513bb0a72a6SMatthias Ringwald 
3514bb0a72a6SMatthias Ringwald         case L2CAP_CID_ATTRIBUTE_PROTOCOL:
3515fad84cafSMatthias Ringwald             l2cap_fixed_channel = l2cap_fixed_channel_for_channel_id(L2CAP_CID_ATTRIBUTE_PROTOCOL);
3516fad84cafSMatthias Ringwald             if (!l2cap_fixed_channel) break;
3517fad84cafSMatthias Ringwald             if (!l2cap_fixed_channel->packet_handler) break;
3518fad84cafSMatthias Ringwald             (*l2cap_fixed_channel->packet_handler)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
3519bb0a72a6SMatthias Ringwald             break;
3520bb0a72a6SMatthias Ringwald 
3521bb0a72a6SMatthias Ringwald         case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
3522fad84cafSMatthias Ringwald             l2cap_fixed_channel = l2cap_fixed_channel_for_channel_id(L2CAP_CID_SECURITY_MANAGER_PROTOCOL);
3523fad84cafSMatthias Ringwald             if (!l2cap_fixed_channel) break;
3524fad84cafSMatthias Ringwald             if (!l2cap_fixed_channel->packet_handler) break;
3525fad84cafSMatthias Ringwald             (*l2cap_fixed_channel->packet_handler)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
3526bb0a72a6SMatthias Ringwald             break;
3527bb0a72a6SMatthias Ringwald 
3528bb0a72a6SMatthias Ringwald         default:
3529bb0a72a6SMatthias Ringwald 
3530a3dc965aSMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
3531421cb104SMatthias Ringwald             l2cap_channel = l2cap_get_channel_for_local_cid(channel_id);
353264e11ca9SMatthias Ringwald             if (l2cap_channel) {
353385aeef60SMatthias Ringwald                 // credit counting
353485aeef60SMatthias Ringwald                 if (l2cap_channel->credits_incoming == 0){
353585aeef60SMatthias Ringwald                     log_error("LE Data Channel packet received but no incoming credits");
353685aeef60SMatthias Ringwald                     l2cap_channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
353785aeef60SMatthias Ringwald                     break;
353885aeef60SMatthias Ringwald                 }
353985aeef60SMatthias Ringwald                 l2cap_channel->credits_incoming--;
354085aeef60SMatthias Ringwald 
354185aeef60SMatthias Ringwald                 // automatic credits
354285aeef60SMatthias Ringwald                 if (l2cap_channel->credits_incoming < L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_WATERMARK && l2cap_channel->automatic_credits){
354385aeef60SMatthias Ringwald                     l2cap_channel->new_credits_incoming = L2CAP_LE_DATA_CHANNELS_AUTOMATIC_CREDITS_INCREMENT;
354485aeef60SMatthias Ringwald                 }
354585aeef60SMatthias Ringwald 
3546cd529728SMatthias Ringwald                 // first fragment
3547cd529728SMatthias Ringwald                 uint16_t pos = 0;
3548cd529728SMatthias Ringwald                 if (!l2cap_channel->receive_sdu_len){
3549bb98c113SMatthias Ringwald                     uint16_t sdu_len = little_endian_read_16(packet, COMPLETE_L2CAP_HEADER);
3550bb98c113SMatthias Ringwald                     if(sdu_len > l2cap_channel->local_mtu) break;   // SDU would be larger than our buffer
3551bb98c113SMatthias Ringwald                     l2cap_channel->receive_sdu_len = sdu_len;
3552cd529728SMatthias Ringwald                     l2cap_channel->receive_sdu_pos = 0;
3553cd529728SMatthias Ringwald                     pos  += 2;
3554cd529728SMatthias Ringwald                     size -= 2;
3555cd529728SMatthias Ringwald                 }
3556bb98c113SMatthias Ringwald                 uint16_t fragment_size   = size-COMPLETE_L2CAP_HEADER;
3557bb98c113SMatthias Ringwald                 uint16_t remaining_space = l2cap_channel->local_mtu - l2cap_channel->receive_sdu_pos;
3558bb98c113SMatthias Ringwald                 if (fragment_size > remaining_space) break;         // SDU would cause buffer overrun
3559bb98c113SMatthias Ringwald                 memcpy(&l2cap_channel->receive_sdu_buffer[l2cap_channel->receive_sdu_pos], &packet[COMPLETE_L2CAP_HEADER+pos], fragment_size);
3560cd529728SMatthias Ringwald                 l2cap_channel->receive_sdu_pos += size - COMPLETE_L2CAP_HEADER;
3561cd529728SMatthias Ringwald                 // done?
3562895ff4a5SMatthias Ringwald                 log_debug("le packet pos %u, len %u", l2cap_channel->receive_sdu_pos, l2cap_channel->receive_sdu_len);
3563cd529728SMatthias Ringwald                 if (l2cap_channel->receive_sdu_pos >= l2cap_channel->receive_sdu_len){
3564cd529728SMatthias Ringwald                     l2cap_dispatch_to_channel(l2cap_channel, L2CAP_DATA_PACKET, l2cap_channel->receive_sdu_buffer, l2cap_channel->receive_sdu_len);
3565cd529728SMatthias Ringwald                     l2cap_channel->receive_sdu_len = 0;
3566cd529728SMatthias Ringwald                 }
356763f0ac45SMatthias Ringwald             } else {
356863f0ac45SMatthias Ringwald                 log_error("LE Data Channel packet received but no channel found for cid 0x%02x", channel_id);
356964e11ca9SMatthias Ringwald             }
357064e11ca9SMatthias Ringwald #endif
35715652b5ffS[email protected]             break;
35725652b5ffS[email protected]     }
3573bb0a72a6SMatthias Ringwald #else
3574bb0a72a6SMatthias Ringwald     UNUSED(handle); // ok: no code
3575bb0a72a6SMatthias Ringwald     UNUSED(packet); // ok: no code
3576bb0a72a6SMatthias Ringwald     UNUSED(size);   // ok: no code
3577bb0a72a6SMatthias Ringwald #endif
3578bb0a72a6SMatthias Ringwald }
3579bb0a72a6SMatthias Ringwald 
3580bb0a72a6SMatthias Ringwald static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
3581bb0a72a6SMatthias Ringwald     UNUSED(packet_type);    // ok: registered with hci_register_acl_packet_handler
3582bb0a72a6SMatthias Ringwald     UNUSED(channel);        // ok: there is no channel
3583bb0a72a6SMatthias Ringwald 
3584adcfabadSMatthias Ringwald     // Assert full L2CAP header present
3585adcfabadSMatthias Ringwald     if (size < COMPLETE_L2CAP_HEADER) return;
3586adcfabadSMatthias Ringwald 
3587f16129ceSMatthias Ringwald     // Dispatch to Classic or LE handler (SCO packets are not dispatched to L2CAP)
3588bb0a72a6SMatthias Ringwald     hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet);
3589bb0a72a6SMatthias Ringwald     hci_connection_t *conn = hci_connection_for_handle(handle);
3590bb0a72a6SMatthias Ringwald     if (!conn) return;
3591f16129ceSMatthias Ringwald     if (conn->address_type == BD_ADDR_TYPE_ACL){
3592bb0a72a6SMatthias Ringwald         l2cap_acl_classic_handler(handle, packet, size);
3593bb0a72a6SMatthias Ringwald     } else {
3594bb0a72a6SMatthias Ringwald         l2cap_acl_le_handler(handle, packet, size);
3595bb0a72a6SMatthias Ringwald     }
359600d93d79Smatthias.ringwald 
35971eb2563eS[email protected]     l2cap_run();
35982718e2e7Smatthias.ringwald }
359900d93d79Smatthias.ringwald 
360009e9d05bSMatthias Ringwald // Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
360109e9d05bSMatthias Ringwald void l2cap_register_fixed_channel(btstack_packet_handler_t the_packet_handler, uint16_t channel_id) {
3602fad84cafSMatthias Ringwald     l2cap_fixed_channel_t * channel = l2cap_fixed_channel_for_channel_id(channel_id);
3603fad84cafSMatthias Ringwald     if (!channel) return;
3604fad84cafSMatthias Ringwald     channel->packet_handler = the_packet_handler;
360509e9d05bSMatthias Ringwald }
360609e9d05bSMatthias Ringwald 
360709e9d05bSMatthias Ringwald #ifdef ENABLE_CLASSIC
360815ec09bbSmatthias.ringwald // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
360927a923d0Smatthias.ringwald void l2cap_finialize_channel_close(l2cap_channel_t * channel){
3610f62db1e3Smatthias.ringwald     channel->state = L2CAP_STATE_CLOSED;
361166a72640SMatthias Ringwald     l2cap_handle_channel_closed(channel);
3612f62db1e3Smatthias.ringwald     // discard channel
3613665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
3614c45d6b2cSMatthias Ringwald     l2cap_free_channel_entry(channel);
3615c8e4258aSmatthias.ringwald }
361613aa3e4bSMatthias Ringwald #endif
36171e6aba47Smatthias.ringwald 
361813aa3e4bSMatthias Ringwald #ifdef L2CAP_USES_CHANNELS
36198f2a52f4SMatthias Ringwald static l2cap_service_t * l2cap_get_service_internal(btstack_linked_list_t * services, uint16_t psm){
3620665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
3621665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, services);
3622665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
3623665d90f2SMatthias Ringwald         l2cap_service_t * service = (l2cap_service_t *) btstack_linked_list_iterator_next(&it);
36249d9bbc01Smatthias.ringwald         if ( service->psm == psm){
36259d9bbc01Smatthias.ringwald             return service;
36269d9bbc01Smatthias.ringwald         };
36279d9bbc01Smatthias.ringwald     }
36289d9bbc01Smatthias.ringwald     return NULL;
36299d9bbc01Smatthias.ringwald }
363013aa3e4bSMatthias Ringwald #endif
36319d9bbc01Smatthias.ringwald 
363213aa3e4bSMatthias Ringwald #ifdef ENABLE_CLASSIC
36337192e786SMatthias Ringwald static inline l2cap_service_t * l2cap_get_service(uint16_t psm){
36347192e786SMatthias Ringwald     return l2cap_get_service_internal(&l2cap_services, psm);
36357192e786SMatthias Ringwald }
36367192e786SMatthias Ringwald 
3637be2053a6SMatthias 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){
3638be2053a6SMatthias Ringwald 
3639be2053a6SMatthias Ringwald     log_info("L2CAP_REGISTER_SERVICE psm 0x%x mtu %u", psm, mtu);
3640e0abb8e7S[email protected] 
36414bb582b6Smatthias.ringwald     // check for alread registered psm
36429d9bbc01Smatthias.ringwald     l2cap_service_t *service = l2cap_get_service(psm);
3643277abc2cSmatthias.ringwald     if (service) {
3644be2053a6SMatthias Ringwald         log_error("l2cap_register_service: PSM %u already registered", psm);
3645be2053a6SMatthias Ringwald         return L2CAP_SERVICE_ALREADY_REGISTERED;
3646277abc2cSmatthias.ringwald     }
36479d9bbc01Smatthias.ringwald 
36484bb582b6Smatthias.ringwald     // alloc structure
3649bb69aaaeS[email protected]     service = btstack_memory_l2cap_service_get();
3650277abc2cSmatthias.ringwald     if (!service) {
3651be2053a6SMatthias Ringwald         log_error("l2cap_register_service: no memory for l2cap_service_t");
3652be2053a6SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
3653277abc2cSmatthias.ringwald     }
36549d9bbc01Smatthias.ringwald 
36559d9bbc01Smatthias.ringwald     // fill in
36569d9bbc01Smatthias.ringwald     service->psm = psm;
36579d9bbc01Smatthias.ringwald     service->mtu = mtu;
365805ae8de3SMatthias Ringwald     service->packet_handler = service_packet_handler;
3659df3354fcS[email protected]     service->required_security_level = security_level;
36609d9bbc01Smatthias.ringwald 
36619d9bbc01Smatthias.ringwald     // add to services list
3662665d90f2SMatthias Ringwald     btstack_linked_list_add(&l2cap_services, (btstack_linked_item_t *) service);
3663c0e866bfSmatthias.ringwald 
3664c0e866bfSmatthias.ringwald     // enable page scan
366515a95bd5SMatthias Ringwald     gap_connectable_control(1);
36665842b6d9Smatthias.ringwald 
3667be2053a6SMatthias Ringwald     return 0;
36689d9bbc01Smatthias.ringwald }
36699d9bbc01Smatthias.ringwald 
36707e8856ebSMatthias Ringwald uint8_t l2cap_unregister_service(uint16_t psm){
3671e0abb8e7S[email protected] 
3672e0abb8e7S[email protected]     log_info("L2CAP_UNREGISTER_SERVICE psm 0x%x", psm);
3673e0abb8e7S[email protected] 
36749d9bbc01Smatthias.ringwald     l2cap_service_t *service = l2cap_get_service(psm);
36757e8856ebSMatthias Ringwald     if (!service) return L2CAP_SERVICE_DOES_NOT_EXIST;
3676665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_services, (btstack_linked_item_t *) service);
3677d3a9df87Smatthias.ringwald     btstack_memory_l2cap_service_free(service);
3678c0e866bfSmatthias.ringwald 
3679c0e866bfSmatthias.ringwald     // disable page scan when no services registered
36807e8856ebSMatthias Ringwald     if (btstack_linked_list_empty(&l2cap_services)) {
368115a95bd5SMatthias Ringwald         gap_connectable_control(0);
36829d9bbc01Smatthias.ringwald     }
36837e8856ebSMatthias Ringwald     return 0;
36847e8856ebSMatthias Ringwald }
368509e9d05bSMatthias Ringwald #endif
36869d9bbc01Smatthias.ringwald 
36877192e786SMatthias Ringwald 
3688cab29d48SMatthias Ringwald #ifdef ENABLE_LE_DATA_CHANNELS
368983fd9c76SMatthias Ringwald 
369057be49d6SMatthias Ringwald static void l2cap_le_notify_channel_can_send(l2cap_channel_t *channel){
369157be49d6SMatthias Ringwald     if (!channel->waiting_for_can_send_now) return;
369257be49d6SMatthias Ringwald     if (channel->send_sdu_buffer) return;
369357be49d6SMatthias Ringwald     channel->waiting_for_can_send_now = 0;
3694895ff4a5SMatthias Ringwald     log_debug("L2CAP_EVENT_CHANNEL_LE_CAN_SEND_NOW local_cid 0x%x", channel->local_cid);
369557be49d6SMatthias Ringwald     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_CAN_SEND_NOW);
369657be49d6SMatthias Ringwald }
369757be49d6SMatthias Ringwald 
369857be49d6SMatthias Ringwald // 1BH2222
369957be49d6SMatthias Ringwald static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel) {
370057be49d6SMatthias 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",
370157be49d6SMatthias Ringwald              channel->address_type, bd_addr_to_str(channel->address), channel->con_handle,  channel->psm, channel->local_cid, channel->remote_cid, channel->remote_mtu);
370257be49d6SMatthias Ringwald     uint8_t event[19];
370357be49d6SMatthias Ringwald     event[0] = L2CAP_EVENT_LE_INCOMING_CONNECTION;
370457be49d6SMatthias Ringwald     event[1] = sizeof(event) - 2;
370557be49d6SMatthias Ringwald     event[2] = channel->address_type;
370657be49d6SMatthias Ringwald     reverse_bd_addr(channel->address, &event[3]);
370757be49d6SMatthias Ringwald     little_endian_store_16(event,  9, channel->con_handle);
370857be49d6SMatthias Ringwald     little_endian_store_16(event, 11, channel->psm);
370957be49d6SMatthias Ringwald     little_endian_store_16(event, 13, channel->local_cid);
371057be49d6SMatthias Ringwald     little_endian_store_16(event, 15, channel->remote_cid);
371157be49d6SMatthias Ringwald     little_endian_store_16(event, 17, channel->remote_mtu);
371257be49d6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
371357be49d6SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
371457be49d6SMatthias Ringwald }
371557be49d6SMatthias Ringwald // 11BH22222
371657be49d6SMatthias Ringwald static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status) {
371757be49d6SMatthias 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",
371857be49d6SMatthias Ringwald              status, channel->address_type, bd_addr_to_str(channel->address), channel->con_handle, channel->psm,
371957be49d6SMatthias Ringwald              channel->local_cid, channel->remote_cid, channel->local_mtu, channel->remote_mtu);
3720c99bb618SMatthias Ringwald     uint8_t event[23];
372157be49d6SMatthias Ringwald     event[0] = L2CAP_EVENT_LE_CHANNEL_OPENED;
372257be49d6SMatthias Ringwald     event[1] = sizeof(event) - 2;
372357be49d6SMatthias Ringwald     event[2] = status;
372457be49d6SMatthias Ringwald     event[3] = channel->address_type;
372557be49d6SMatthias Ringwald     reverse_bd_addr(channel->address, &event[4]);
372657be49d6SMatthias Ringwald     little_endian_store_16(event, 10, channel->con_handle);
3727c99bb618SMatthias Ringwald     event[12] = channel->state_var & L2CAP_CHANNEL_STATE_VAR_INCOMING ? 1 : 0;
3728c99bb618SMatthias Ringwald     little_endian_store_16(event, 13, channel->psm);
3729c99bb618SMatthias Ringwald     little_endian_store_16(event, 15, channel->local_cid);
3730c99bb618SMatthias Ringwald     little_endian_store_16(event, 17, channel->remote_cid);
3731c99bb618SMatthias Ringwald     little_endian_store_16(event, 19, channel->local_mtu);
3732c99bb618SMatthias Ringwald     little_endian_store_16(event, 21, channel->remote_mtu);
373357be49d6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
373457be49d6SMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
373557be49d6SMatthias Ringwald }
373687050a0bSMatthias Ringwald // 2
373787050a0bSMatthias Ringwald static void l2cap_emit_le_channel_closed(l2cap_channel_t * channel){
373887050a0bSMatthias Ringwald     log_info("L2CAP_EVENT_LE_CHANNEL_CLOSED local_cid 0x%x", channel->local_cid);
373987050a0bSMatthias Ringwald     uint8_t event[4];
374087050a0bSMatthias Ringwald     event[0] = L2CAP_EVENT_LE_CHANNEL_CLOSED;
374187050a0bSMatthias Ringwald     event[1] = sizeof(event) - 2;
374287050a0bSMatthias Ringwald     little_endian_store_16(event, 2, channel->local_cid);
374387050a0bSMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
374487050a0bSMatthias Ringwald     l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
374587050a0bSMatthias Ringwald }
374687050a0bSMatthias Ringwald 
3747*6774d5c9SMatthias Ringwald static void l2cap_le_send_pdu(l2cap_channel_t *channel){
3748*6774d5c9SMatthias Ringwald     btstack_assert(channel != NULL);
3749*6774d5c9SMatthias Ringwald     btstack_assert(channel->send_pdu_buffer != NULL);
3750*6774d5c9SMatthias Ringwald     btstack_assert(channel->credits_outgoing > 0);
3751*6774d5c9SMatthias Ringwald 
3752*6774d5c9SMatthias Ringwald     // send part of SDU
3753*6774d5c9SMatthias Ringwald     hci_reserve_packet_buffer();
3754*6774d5c9SMatthias Ringwald     uint8_t * acl_buffer = hci_get_outgoing_packet_buffer();
3755*6774d5c9SMatthias Ringwald     uint8_t * l2cap_payload = acl_buffer + 8;
3756*6774d5c9SMatthias Ringwald     uint16_t pos = 0;
3757*6774d5c9SMatthias Ringwald     if (!channel->send_sdu_pos){
3758*6774d5c9SMatthias Ringwald         // store SDU len
3759*6774d5c9SMatthias Ringwald         channel->send_sdu_pos += 2;
3760*6774d5c9SMatthias Ringwald         little_endian_store_16(l2cap_payload, pos, channel->send_sdu_len);
3761*6774d5c9SMatthias Ringwald         pos += 2;
3762*6774d5c9SMatthias Ringwald     }
3763*6774d5c9SMatthias Ringwald     uint16_t payload_size = btstack_min(channel->send_sdu_len + 2 - channel->send_sdu_pos, channel->remote_mps - pos);
3764*6774d5c9SMatthias Ringwald     log_info("len %u, pos %u => payload %u, credits %u", channel->send_sdu_len, channel->send_sdu_pos, payload_size, channel->credits_outgoing);
3765*6774d5c9SMatthias Ringwald     memcpy(&l2cap_payload[pos], &channel->send_sdu_buffer[channel->send_sdu_pos-2], payload_size); // -2 for virtual SDU len
3766*6774d5c9SMatthias Ringwald     pos += payload_size;
3767*6774d5c9SMatthias Ringwald     channel->send_sdu_pos += payload_size;
3768*6774d5c9SMatthias Ringwald     l2cap_setup_header(acl_buffer, channel->con_handle, 0, channel->remote_cid, pos);
3769*6774d5c9SMatthias Ringwald 
3770*6774d5c9SMatthias Ringwald     channel->credits_outgoing--;
3771*6774d5c9SMatthias Ringwald 
3772*6774d5c9SMatthias Ringwald     hci_send_acl_packet_buffer(8 + pos);
3773*6774d5c9SMatthias Ringwald 
3774*6774d5c9SMatthias Ringwald     if (channel->send_sdu_pos >= channel->send_sdu_len + 2){
3775*6774d5c9SMatthias Ringwald         channel->send_sdu_buffer = NULL;
3776*6774d5c9SMatthias Ringwald         // send done event
3777*6774d5c9SMatthias Ringwald         l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_PACKET_SENT);
3778*6774d5c9SMatthias Ringwald         // inform about can send now
3779*6774d5c9SMatthias Ringwald         l2cap_le_notify_channel_can_send(channel);
3780*6774d5c9SMatthias Ringwald     }
3781*6774d5c9SMatthias Ringwald }
3782*6774d5c9SMatthias Ringwald 
378357be49d6SMatthias Ringwald // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
378457be49d6SMatthias Ringwald void l2cap_le_finialize_channel_close(l2cap_channel_t * channel){
378557be49d6SMatthias Ringwald     channel->state = L2CAP_STATE_CLOSED;
378657be49d6SMatthias Ringwald     l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED);
378757be49d6SMatthias Ringwald     // discard channel
3788421cb104SMatthias Ringwald     btstack_linked_list_remove(&l2cap_channels, (btstack_linked_item_t *) channel);
3789c45d6b2cSMatthias Ringwald     l2cap_free_channel_entry(channel);
379057be49d6SMatthias Ringwald }
379157be49d6SMatthias Ringwald 
3792e7d0c9aaSMatthias Ringwald static inline l2cap_service_t * l2cap_le_get_service(uint16_t le_psm){
3793e7d0c9aaSMatthias Ringwald     return l2cap_get_service_internal(&l2cap_le_services, le_psm);
37947192e786SMatthias Ringwald }
3795efedfb4cSMatthias Ringwald 
3796da144af5SMatthias Ringwald uint8_t l2cap_le_register_service(btstack_packet_handler_t packet_handler, uint16_t psm, gap_security_level_t security_level){
37977192e786SMatthias Ringwald 
3798da144af5SMatthias Ringwald     log_info("L2CAP_LE_REGISTER_SERVICE psm 0x%x", psm);
37997192e786SMatthias Ringwald 
38007192e786SMatthias Ringwald     // check for alread registered psm
38017192e786SMatthias Ringwald     l2cap_service_t *service = l2cap_le_get_service(psm);
38027192e786SMatthias Ringwald     if (service) {
3803da144af5SMatthias Ringwald         return L2CAP_SERVICE_ALREADY_REGISTERED;
38047192e786SMatthias Ringwald     }
38057192e786SMatthias Ringwald 
38067192e786SMatthias Ringwald     // alloc structure
38077192e786SMatthias Ringwald     service = btstack_memory_l2cap_service_get();
38087192e786SMatthias Ringwald     if (!service) {
38097192e786SMatthias Ringwald         log_error("l2cap_register_service_internal: no memory for l2cap_service_t");
3810da144af5SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
38117192e786SMatthias Ringwald     }
38127192e786SMatthias Ringwald 
38137192e786SMatthias Ringwald     // fill in
38147192e786SMatthias Ringwald     service->psm = psm;
3815da144af5SMatthias Ringwald     service->mtu = 0;
38167192e786SMatthias Ringwald     service->packet_handler = packet_handler;
38177192e786SMatthias Ringwald     service->required_security_level = security_level;
38187192e786SMatthias Ringwald 
38197192e786SMatthias Ringwald     // add to services list
3820665d90f2SMatthias Ringwald     btstack_linked_list_add(&l2cap_le_services, (btstack_linked_item_t *) service);
38217192e786SMatthias Ringwald 
38227192e786SMatthias Ringwald     // done
3823da144af5SMatthias Ringwald     return 0;
38247192e786SMatthias Ringwald }
38257192e786SMatthias Ringwald 
3826da144af5SMatthias Ringwald uint8_t l2cap_le_unregister_service(uint16_t psm) {
38277192e786SMatthias Ringwald     log_info("L2CAP_LE_UNREGISTER_SERVICE psm 0x%x", psm);
38287192e786SMatthias Ringwald     l2cap_service_t *service = l2cap_le_get_service(psm);
38299367f9b0SMatthias Ringwald     if (!service) return L2CAP_SERVICE_DOES_NOT_EXIST;
3830da144af5SMatthias Ringwald 
3831665d90f2SMatthias Ringwald     btstack_linked_list_remove(&l2cap_le_services, (btstack_linked_item_t *) service);
38327192e786SMatthias Ringwald     btstack_memory_l2cap_service_free(service);
3833da144af5SMatthias Ringwald     return 0;
38347192e786SMatthias Ringwald }
3835da144af5SMatthias Ringwald 
3836da144af5SMatthias Ringwald uint8_t l2cap_le_accept_connection(uint16_t local_cid, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits){
3837e7d0c9aaSMatthias Ringwald     // get channel
3838421cb104SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
3839e7d0c9aaSMatthias Ringwald     if (!channel) return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
3840e7d0c9aaSMatthias Ringwald 
3841e7d0c9aaSMatthias Ringwald     // validate state
3842e7d0c9aaSMatthias Ringwald     if (channel->state != L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT){
3843e7d0c9aaSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
3844e7d0c9aaSMatthias Ringwald     }
3845e7d0c9aaSMatthias Ringwald 
3846efedfb4cSMatthias Ringwald     // set state accept connection
384723017473SMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_ACCEPT;
384823017473SMatthias Ringwald     channel->receive_sdu_buffer = receive_sdu_buffer;
384923017473SMatthias Ringwald     channel->local_mtu = mtu;
385085aeef60SMatthias Ringwald     channel->new_credits_incoming = initial_credits;
385185aeef60SMatthias Ringwald     channel->automatic_credits  = initial_credits == L2CAP_LE_AUTOMATIC_CREDITS;
385285aeef60SMatthias Ringwald 
385385aeef60SMatthias Ringwald     // test
385463f0ac45SMatthias Ringwald     // channel->new_credits_incoming = 1;
3855e7d0c9aaSMatthias Ringwald 
3856e7d0c9aaSMatthias Ringwald     // go
3857e7d0c9aaSMatthias Ringwald     l2cap_run();
3858da144af5SMatthias Ringwald     return 0;
3859da144af5SMatthias Ringwald }
3860da144af5SMatthias Ringwald 
3861da144af5SMatthias Ringwald /**
3862da144af5SMatthias Ringwald  * @brief Deny incoming LE Data Channel connection due to resource constraints
3863da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3864da144af5SMatthias Ringwald  */
3865da144af5SMatthias Ringwald 
3866da144af5SMatthias Ringwald uint8_t l2cap_le_decline_connection(uint16_t local_cid){
3867e7d0c9aaSMatthias Ringwald     // get channel
3868421cb104SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
3869e7d0c9aaSMatthias Ringwald     if (!channel) return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
3870e7d0c9aaSMatthias Ringwald 
3871e7d0c9aaSMatthias Ringwald     // validate state
3872e7d0c9aaSMatthias Ringwald     if (channel->state != L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT){
3873e7d0c9aaSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
3874e7d0c9aaSMatthias Ringwald     }
3875e7d0c9aaSMatthias Ringwald 
3876efedfb4cSMatthias Ringwald     // set state decline connection
3877e7d0c9aaSMatthias Ringwald     channel->state  = L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE;
3878e7d0c9aaSMatthias Ringwald     channel->reason = 0x04; // no resources available
3879e7d0c9aaSMatthias Ringwald     l2cap_run();
3880da144af5SMatthias Ringwald     return 0;
3881da144af5SMatthias Ringwald }
3882da144af5SMatthias Ringwald 
38837dafa750SMatthias Ringwald uint8_t l2cap_le_create_channel(btstack_packet_handler_t packet_handler, hci_con_handle_t con_handle,
3884da144af5SMatthias Ringwald     uint16_t psm, uint8_t * receive_sdu_buffer, uint16_t mtu, uint16_t initial_credits, gap_security_level_t security_level,
3885efedfb4cSMatthias Ringwald     uint16_t * out_local_cid) {
3886efedfb4cSMatthias Ringwald 
38877dafa750SMatthias Ringwald     log_info("L2CAP_LE_CREATE_CHANNEL handle 0x%04x psm 0x%x mtu %u", con_handle, psm, mtu);
3888da144af5SMatthias Ringwald 
38897dafa750SMatthias Ringwald 
38907dafa750SMatthias Ringwald     hci_connection_t * connection = hci_connection_for_handle(con_handle);
38917dafa750SMatthias Ringwald     if (!connection) {
38927dafa750SMatthias Ringwald         log_error("no hci_connection for handle 0x%04x", con_handle);
38937dafa750SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
38947dafa750SMatthias Ringwald     }
38957dafa750SMatthias Ringwald 
38965d18f623SMatthias Ringwald     l2cap_channel_t * channel = l2cap_create_channel_entry(packet_handler, L2CAP_CHANNEL_TYPE_LE_DATA_CHANNEL, connection->address, connection->address_type, psm, mtu, security_level);
3897da144af5SMatthias Ringwald     if (!channel) {
3898da144af5SMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
3899da144af5SMatthias Ringwald     }
3900e7d0c9aaSMatthias Ringwald     log_info("l2cap_le_create_channel %p", channel);
3901da144af5SMatthias Ringwald 
3902da144af5SMatthias Ringwald     // store local_cid
3903da144af5SMatthias Ringwald     if (out_local_cid){
3904da144af5SMatthias Ringwald        *out_local_cid = channel->local_cid;
3905da144af5SMatthias Ringwald     }
3906da144af5SMatthias Ringwald 
39077dafa750SMatthias Ringwald     // provide buffer
39087dafa750SMatthias Ringwald     channel->con_handle = con_handle;
3909cd529728SMatthias Ringwald     channel->receive_sdu_buffer = receive_sdu_buffer;
39107dafa750SMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_LE_CONNECTION_REQUEST;
391185aeef60SMatthias Ringwald     channel->new_credits_incoming = initial_credits;
391285aeef60SMatthias Ringwald     channel->automatic_credits    = initial_credits == L2CAP_LE_AUTOMATIC_CREDITS;
391385aeef60SMatthias Ringwald 
3914efedfb4cSMatthias Ringwald     // add to connections list
3915421cb104SMatthias Ringwald     btstack_linked_list_add(&l2cap_channels, (btstack_linked_item_t *) channel);
3916efedfb4cSMatthias Ringwald 
39177dafa750SMatthias Ringwald     // go
391863f0ac45SMatthias Ringwald     l2cap_run();
3919da144af5SMatthias Ringwald     return 0;
3920da144af5SMatthias Ringwald }
3921da144af5SMatthias Ringwald 
3922da144af5SMatthias Ringwald /**
3923da144af5SMatthias Ringwald  * @brief Provide credtis for LE Data Channel
3924da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3925da144af5SMatthias Ringwald  * @param credits               Number additional credits for peer
3926da144af5SMatthias Ringwald  */
392764e11ca9SMatthias Ringwald uint8_t l2cap_le_provide_credits(uint16_t local_cid, uint16_t credits){
392863f0ac45SMatthias Ringwald 
3929421cb104SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
393063f0ac45SMatthias Ringwald     if (!channel) {
393163f0ac45SMatthias Ringwald         log_error("l2cap_le_provide_credits no channel for cid 0x%02x", local_cid);
393263f0ac45SMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
393363f0ac45SMatthias Ringwald     }
393463f0ac45SMatthias Ringwald 
3935efedfb4cSMatthias Ringwald     // check state
393663f0ac45SMatthias Ringwald     if (channel->state != L2CAP_STATE_OPEN){
393763f0ac45SMatthias Ringwald         log_error("l2cap_le_provide_credits but channel 0x%02x not open yet", local_cid);
393863f0ac45SMatthias Ringwald     }
393963f0ac45SMatthias Ringwald 
394063f0ac45SMatthias Ringwald     // assert incoming credits + credits <= 0xffff
394163f0ac45SMatthias Ringwald     uint32_t total_credits = channel->credits_incoming;
394263f0ac45SMatthias Ringwald     total_credits += channel->new_credits_incoming;
394363f0ac45SMatthias Ringwald     total_credits += credits;
394463f0ac45SMatthias Ringwald     if (total_credits > 0xffff){
394563f0ac45SMatthias Ringwald         log_error("l2cap_le_provide_credits overrun: current %u, scheduled %u, additional %u", channel->credits_incoming,
394663f0ac45SMatthias Ringwald             channel->new_credits_incoming, credits);
394763f0ac45SMatthias Ringwald     }
394863f0ac45SMatthias Ringwald 
3949efedfb4cSMatthias Ringwald     // set credits_granted
395063f0ac45SMatthias Ringwald     channel->new_credits_incoming += credits;
395163f0ac45SMatthias Ringwald 
395263f0ac45SMatthias Ringwald     // go
395363f0ac45SMatthias Ringwald     l2cap_run();
3954da144af5SMatthias Ringwald     return 0;
3955da144af5SMatthias Ringwald }
3956da144af5SMatthias Ringwald 
3957da144af5SMatthias Ringwald /**
3958da144af5SMatthias Ringwald  * @brief Check if outgoing buffer is available and that there's space on the Bluetooth module
3959da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3960da144af5SMatthias Ringwald  */
396164e11ca9SMatthias Ringwald int l2cap_le_can_send_now(uint16_t local_cid){
3962421cb104SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
396344276248SMatthias Ringwald     if (!channel) {
396444276248SMatthias Ringwald         log_error("l2cap_le_provide_credits no channel for cid 0x%02x", local_cid);
3965da144af5SMatthias Ringwald         return 0;
3966da144af5SMatthias Ringwald     }
3967da144af5SMatthias Ringwald 
396844276248SMatthias Ringwald     // check state
396944276248SMatthias Ringwald     if (channel->state != L2CAP_STATE_OPEN) return 0;
397044276248SMatthias Ringwald 
397144276248SMatthias Ringwald     // check queue
397244276248SMatthias Ringwald     if (channel->send_sdu_buffer) return 0;
397344276248SMatthias Ringwald 
397444276248SMatthias Ringwald     // fine, go ahead
397544276248SMatthias Ringwald     return 1;
397644276248SMatthias Ringwald }
397744276248SMatthias Ringwald 
3978da144af5SMatthias Ringwald /**
3979da144af5SMatthias Ringwald  * @brief Request emission of L2CAP_EVENT_CAN_SEND_NOW as soon as possible
3980da144af5SMatthias Ringwald  * @note L2CAP_EVENT_CAN_SEND_NOW might be emitted during call to this function
3981da144af5SMatthias Ringwald  *       so packet handler should be ready to handle it
3982da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3983da144af5SMatthias Ringwald  */
398464e11ca9SMatthias Ringwald uint8_t l2cap_le_request_can_send_now_event(uint16_t local_cid){
3985421cb104SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
398644276248SMatthias Ringwald     if (!channel) {
398744276248SMatthias Ringwald         log_error("l2cap_le_request_can_send_now_event no channel for cid 0x%02x", local_cid);
398844276248SMatthias Ringwald         return 0;
398944276248SMatthias Ringwald     }
399044276248SMatthias Ringwald     channel->waiting_for_can_send_now = 1;
399144276248SMatthias Ringwald     l2cap_le_notify_channel_can_send(channel);
3992da144af5SMatthias Ringwald     return 0;
3993da144af5SMatthias Ringwald }
3994da144af5SMatthias Ringwald 
3995da144af5SMatthias Ringwald /**
3996da144af5SMatthias Ringwald  * @brief Send data via LE Data Channel
3997da144af5SMatthias Ringwald  * @note Since data larger then the maximum PDU needs to be segmented into multiple PDUs, data needs to stay valid until ... event
3998da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
3999da144af5SMatthias Ringwald  * @param data                  data to send
4000da144af5SMatthias Ringwald  * @param size                  data size
4001da144af5SMatthias Ringwald  */
400264e11ca9SMatthias Ringwald uint8_t l2cap_le_send_data(uint16_t local_cid, uint8_t * data, uint16_t len){
400364e11ca9SMatthias Ringwald 
4004421cb104SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
400564e11ca9SMatthias Ringwald     if (!channel) {
400664e11ca9SMatthias Ringwald         log_error("l2cap_send no channel for cid 0x%02x", local_cid);
4007828a7f7aSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
400864e11ca9SMatthias Ringwald     }
400964e11ca9SMatthias Ringwald 
401064e11ca9SMatthias Ringwald     if (len > channel->remote_mtu){
401164e11ca9SMatthias Ringwald         log_error("l2cap_send cid 0x%02x, data length exceeds remote MTU.", local_cid);
401264e11ca9SMatthias Ringwald         return L2CAP_DATA_LEN_EXCEEDS_REMOTE_MTU;
401364e11ca9SMatthias Ringwald     }
401464e11ca9SMatthias Ringwald 
40157f107edaSMatthias Ringwald     if (channel->send_sdu_buffer){
401664e11ca9SMatthias Ringwald         log_info("l2cap_send cid 0x%02x, cannot send", local_cid);
401764e11ca9SMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
401864e11ca9SMatthias Ringwald     }
401964e11ca9SMatthias Ringwald 
40207f107edaSMatthias Ringwald     channel->send_sdu_buffer = data;
40217f107edaSMatthias Ringwald     channel->send_sdu_len    = len;
40227f107edaSMatthias Ringwald     channel->send_sdu_pos    = 0;
402364e11ca9SMatthias Ringwald 
4024*6774d5c9SMatthias Ringwald     l2cap_notify_channel_can_send();
40257f107edaSMatthias Ringwald     return 0;
4026da144af5SMatthias Ringwald }
4027da144af5SMatthias Ringwald 
4028da144af5SMatthias Ringwald /**
4029da144af5SMatthias Ringwald  * @brief Disconnect from LE Data Channel
4030da144af5SMatthias Ringwald  * @param local_cid             L2CAP LE Data Channel Identifier
4031da144af5SMatthias Ringwald  */
4032828a7f7aSMatthias Ringwald uint8_t l2cap_le_disconnect(uint16_t local_cid)
4033da144af5SMatthias Ringwald {
4034421cb104SMatthias Ringwald     l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
4035828a7f7aSMatthias Ringwald     if (!channel) {
4036828a7f7aSMatthias Ringwald         log_error("l2cap_send no channel for cid 0x%02x", local_cid);
4037828a7f7aSMatthias Ringwald         return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
4038828a7f7aSMatthias Ringwald     }
4039828a7f7aSMatthias Ringwald 
4040828a7f7aSMatthias Ringwald     channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
4041828a7f7aSMatthias Ringwald     l2cap_run();
4042da144af5SMatthias Ringwald     return 0;
4043da144af5SMatthias Ringwald }
4044da144af5SMatthias Ringwald 
40457f02f414SMatthias Ringwald #endif
4046