143625864Smatthias.ringwald /* 21713bceaSmatthias.ringwald * Copyright (C) 2009 by Matthias Ringwald 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. 161713bceaSmatthias.ringwald * 171713bceaSmatthias.ringwald * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS 181713bceaSmatthias.ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 191713bceaSmatthias.ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 201713bceaSmatthias.ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 211713bceaSmatthias.ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 221713bceaSmatthias.ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 231713bceaSmatthias.ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 241713bceaSmatthias.ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 251713bceaSmatthias.ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 261713bceaSmatthias.ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 271713bceaSmatthias.ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 281713bceaSmatthias.ringwald * SUCH DAMAGE. 291713bceaSmatthias.ringwald * 301713bceaSmatthias.ringwald */ 311713bceaSmatthias.ringwald 321713bceaSmatthias.ringwald /* 3343625864Smatthias.ringwald * l2cap.c 3443625864Smatthias.ringwald * 3543625864Smatthias.ringwald * Logical Link Control and Adaption Protocl (L2CAP) 3643625864Smatthias.ringwald * 3743625864Smatthias.ringwald * Created by Matthias Ringwald on 5/16/09. 3843625864Smatthias.ringwald */ 3943625864Smatthias.ringwald 4043625864Smatthias.ringwald #include "l2cap.h" 41645658c9Smatthias.ringwald #include "hci.h" 422b3c6c9bSmatthias.ringwald #include "hci_dump.h" 436218e6f1Smatthias.ringwald #include "debug.h" 44d3a9df87Smatthias.ringwald #include "btstack_memory.h" 4543625864Smatthias.ringwald 4643625864Smatthias.ringwald #include <stdarg.h> 4743625864Smatthias.ringwald #include <string.h> 4843625864Smatthias.ringwald 4943625864Smatthias.ringwald #include <stdio.h> 5043625864Smatthias.ringwald 514c744e21Smatthias.ringwald // nr of buffered acl packets in outgoing queue to get max performance 524c744e21Smatthias.ringwald #define NR_BUFFERED_ACL_PACKETS 3 534c744e21Smatthias.ringwald 5439bda6d5Smatthias.ringwald // used to cache l2cap rejects, echo, and informational requests 55e16a9cacSmatthias.ringwald #define NR_PENDING_SIGNALING_RESPONSES 3 5639bda6d5Smatthias.ringwald 5700d93d79Smatthias.ringwald // offsets for L2CAP SIGNALING COMMANDS 5800d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_CODE_OFFSET 0 5900d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_SIGID_OFFSET 1 6000d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2 6100d93d79Smatthias.ringwald #define L2CAP_SIGNALING_COMMAND_DATA_OFFSET 4 6200d93d79Smatthias.ringwald 6339bda6d5Smatthias.ringwald static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 6439bda6d5Smatthias.ringwald static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size); 6539bda6d5Smatthias.ringwald 6639bda6d5Smatthias.ringwald // used to cache l2cap rejects, echo, and informational requests 672b83fb7dSmatthias.ringwald static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES]; 682b83fb7dSmatthias.ringwald static int signaling_responses_pending; 692b83fb7dSmatthias.ringwald 701e6aba47Smatthias.ringwald static linked_list_t l2cap_channels = NULL; 719d9bbc01Smatthias.ringwald static linked_list_t l2cap_services = NULL; 7236944dffSmatthias.ringwald static void (*packet_handler) (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) = null_packet_handler; 73808a48abSmatthias.ringwald static int new_credits_blocked = 0; 741e6aba47Smatthias.ringwald 75*5652b5ffS[email protected] static btstack_packet_handler_t attribute_protocol_packet_handler = NULL; 76*5652b5ffS[email protected] static btstack_packet_handler_t security_protocol_packet_handler = NULL; 77*5652b5ffS[email protected] 7839bda6d5Smatthias.ringwald // prototypes 79fa8473a4Smatthias.ringwald static void l2cap_finialize_channel_close(l2cap_channel_t *channel); 80fa8473a4Smatthias.ringwald static l2cap_service_t * l2cap_get_service(uint16_t psm); 81fa8473a4Smatthias.ringwald static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status); 82fa8473a4Smatthias.ringwald static void l2cap_emit_channel_closed(l2cap_channel_t *channel); 83fa8473a4Smatthias.ringwald static void l2cap_emit_connection_request(l2cap_channel_t *channel); 84fa8473a4Smatthias.ringwald static int l2cap_channel_ready_for_open(l2cap_channel_t *channel); 8539bda6d5Smatthias.ringwald 8639bda6d5Smatthias.ringwald 871e6aba47Smatthias.ringwald void l2cap_init(){ 88808a48abSmatthias.ringwald new_credits_blocked = 0; 892b83fb7dSmatthias.ringwald signaling_responses_pending = 0; 90808a48abSmatthias.ringwald 91f5454fc6Smatthias.ringwald l2cap_channels = NULL; 92f5454fc6Smatthias.ringwald l2cap_services = NULL; 93f5454fc6Smatthias.ringwald 94f5454fc6Smatthias.ringwald packet_handler = null_packet_handler; 95f5454fc6Smatthias.ringwald 96fcadd0caSmatthias.ringwald // 972718e2e7Smatthias.ringwald // register callback with HCI 98fcadd0caSmatthias.ringwald // 992718e2e7Smatthias.ringwald hci_register_packet_handler(&l2cap_packet_handler); 100c0e866bfSmatthias.ringwald hci_connectable_control(0); // no services yet 101fcadd0caSmatthias.ringwald } 102fcadd0caSmatthias.ringwald 103fcadd0caSmatthias.ringwald 104fcadd0caSmatthias.ringwald /** Register L2CAP packet handlers */ 10536944dffSmatthias.ringwald static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 106fcadd0caSmatthias.ringwald } 10736944dffSmatthias.ringwald void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){ 108b502e1b0Smatthias.ringwald packet_handler = handler; 1091e6aba47Smatthias.ringwald } 1101e6aba47Smatthias.ringwald 11158de5610Smatthias.ringwald // notify client/protocol handler 11258de5610Smatthias.ringwald void l2cap_dispatch(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){ 11358de5610Smatthias.ringwald if (channel->packet_handler) { 11458de5610Smatthias.ringwald (* (channel->packet_handler))(type, channel->local_cid, data, size); 11558de5610Smatthias.ringwald } else { 11636944dffSmatthias.ringwald (*packet_handler)(channel->connection, type, channel->local_cid, data, size); 11758de5610Smatthias.ringwald } 11858de5610Smatthias.ringwald } 11958de5610Smatthias.ringwald 12058de5610Smatthias.ringwald void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) { 1219893b714Smatthias.ringwald uint8_t event[21]; 12258de5610Smatthias.ringwald event[0] = L2CAP_EVENT_CHANNEL_OPENED; 12358de5610Smatthias.ringwald event[1] = sizeof(event) - 2; 12458de5610Smatthias.ringwald event[2] = status; 12558de5610Smatthias.ringwald bt_flip_addr(&event[3], channel->address); 12658de5610Smatthias.ringwald bt_store_16(event, 9, channel->handle); 12758de5610Smatthias.ringwald bt_store_16(event, 11, channel->psm); 12858de5610Smatthias.ringwald bt_store_16(event, 13, channel->local_cid); 12958de5610Smatthias.ringwald bt_store_16(event, 15, channel->remote_cid); 1304c98aa43Smatthias.ringwald bt_store_16(event, 17, channel->local_mtu); 1314c98aa43Smatthias.ringwald bt_store_16(event, 19, channel->remote_mtu); 13258de5610Smatthias.ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 13358de5610Smatthias.ringwald l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event)); 13458de5610Smatthias.ringwald } 13558de5610Smatthias.ringwald 13658de5610Smatthias.ringwald void l2cap_emit_channel_closed(l2cap_channel_t *channel) { 13758de5610Smatthias.ringwald uint8_t event[4]; 13858de5610Smatthias.ringwald event[0] = L2CAP_EVENT_CHANNEL_CLOSED; 13958de5610Smatthias.ringwald event[1] = sizeof(event) - 2; 14058de5610Smatthias.ringwald bt_store_16(event, 2, channel->local_cid); 14158de5610Smatthias.ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 14258de5610Smatthias.ringwald l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event)); 14358de5610Smatthias.ringwald } 14458de5610Smatthias.ringwald 14558de5610Smatthias.ringwald void l2cap_emit_connection_request(l2cap_channel_t *channel) { 14658de5610Smatthias.ringwald uint8_t event[16]; 14758de5610Smatthias.ringwald event[0] = L2CAP_EVENT_INCOMING_CONNECTION; 14858de5610Smatthias.ringwald event[1] = sizeof(event) - 2; 14958de5610Smatthias.ringwald bt_flip_addr(&event[2], channel->address); 15058de5610Smatthias.ringwald bt_store_16(event, 8, channel->handle); 15158de5610Smatthias.ringwald bt_store_16(event, 10, channel->psm); 15258de5610Smatthias.ringwald bt_store_16(event, 12, channel->local_cid); 15358de5610Smatthias.ringwald bt_store_16(event, 14, channel->remote_cid); 15458de5610Smatthias.ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 15558de5610Smatthias.ringwald l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event)); 1560af41d30Smatthias.ringwald } 157808a48abSmatthias.ringwald 1585842b6d9Smatthias.ringwald static void l2cap_emit_service_registered(void *connection, uint8_t status, uint16_t psm){ 1595842b6d9Smatthias.ringwald uint8_t event[5]; 1605842b6d9Smatthias.ringwald event[0] = L2CAP_EVENT_SERVICE_REGISTERED; 1615842b6d9Smatthias.ringwald event[1] = sizeof(event) - 2; 1625842b6d9Smatthias.ringwald event[2] = status; 1635842b6d9Smatthias.ringwald bt_store_16(event, 3, psm); 1645842b6d9Smatthias.ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 1655842b6d9Smatthias.ringwald (*packet_handler)(connection, HCI_EVENT_PACKET, 0, event, sizeof(event)); 1665842b6d9Smatthias.ringwald } 1675842b6d9Smatthias.ringwald 1686218e6f1Smatthias.ringwald void l2cap_emit_credits(l2cap_channel_t *channel, uint8_t credits) { 1696218e6f1Smatthias.ringwald // track credits 1706218e6f1Smatthias.ringwald channel->packets_granted += credits; 1717b5fbe1fSmatthias.ringwald // log_info("l2cap_emit_credits for cid %u, credits given: %u (+%u)\n", channel->local_cid, channel->packets_granted, credits); 1726218e6f1Smatthias.ringwald 1736218e6f1Smatthias.ringwald uint8_t event[5]; 1746218e6f1Smatthias.ringwald event[0] = L2CAP_EVENT_CREDITS; 1756218e6f1Smatthias.ringwald event[1] = sizeof(event) - 2; 1766218e6f1Smatthias.ringwald bt_store_16(event, 2, channel->local_cid); 1776218e6f1Smatthias.ringwald event[4] = credits; 1786218e6f1Smatthias.ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 1796218e6f1Smatthias.ringwald l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event)); 1806218e6f1Smatthias.ringwald } 1816218e6f1Smatthias.ringwald 182808a48abSmatthias.ringwald void l2cap_block_new_credits(uint8_t blocked){ 183808a48abSmatthias.ringwald new_credits_blocked = blocked; 184808a48abSmatthias.ringwald } 185808a48abSmatthias.ringwald 18640d1c7a4Smatthias.ringwald void l2cap_hand_out_credits(void){ 187808a48abSmatthias.ringwald 188808a48abSmatthias.ringwald if (new_credits_blocked) return; // we're told not to. used by daemon 189808a48abSmatthias.ringwald 1908d371091Smatthias.ringwald linked_item_t *it; 1918d371091Smatthias.ringwald for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ 1928d371091Smatthias.ringwald if (!hci_number_free_acl_slots()) return; 1938d371091Smatthias.ringwald l2cap_channel_t * channel = (l2cap_channel_t *) it; 1940e7bc007Smatthias.ringwald if (channel->state != L2CAP_STATE_OPEN) continue; 1954c744e21Smatthias.ringwald if (hci_number_outgoing_packets(channel->handle) < NR_BUFFERED_ACL_PACKETS && channel->packets_granted == 0) { 1968d371091Smatthias.ringwald l2cap_emit_credits(channel, 1); 1978d371091Smatthias.ringwald } 1988d371091Smatthias.ringwald } 1998d371091Smatthias.ringwald } 2008d371091Smatthias.ringwald 201b35f641cSmatthias.ringwald l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){ 202f62db1e3Smatthias.ringwald linked_item_t *it; 203f62db1e3Smatthias.ringwald for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ 2048d371091Smatthias.ringwald l2cap_channel_t * channel = (l2cap_channel_t *) it; 205b35f641cSmatthias.ringwald if ( channel->local_cid == local_cid) { 206f62db1e3Smatthias.ringwald return channel; 207f62db1e3Smatthias.ringwald } 208f62db1e3Smatthias.ringwald } 209f62db1e3Smatthias.ringwald return NULL; 210f62db1e3Smatthias.ringwald } 211f62db1e3Smatthias.ringwald 2126b1fde37Smatthias.ringwald int l2cap_can_send_packet_now(uint16_t local_cid){ 2136b1fde37Smatthias.ringwald l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid); 2146b1fde37Smatthias.ringwald if (!channel) return 0; 2156b1fde37Smatthias.ringwald if (!channel->packets_granted) return 0; 2166b1fde37Smatthias.ringwald return hci_can_send_packet_now(HCI_ACL_DATA_PACKET); 2176b1fde37Smatthias.ringwald } 2186b1fde37Smatthias.ringwald 21996cbd662Smatthias.ringwald uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){ 22096cbd662Smatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); 22196cbd662Smatthias.ringwald if (channel) { 22296cbd662Smatthias.ringwald return channel->remote_mtu; 22396cbd662Smatthias.ringwald } 22496cbd662Smatthias.ringwald return 0; 22596cbd662Smatthias.ringwald } 22696cbd662Smatthias.ringwald 22758de5610Smatthias.ringwald int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){ 228b1d43497Smatthias.ringwald 229b1d43497Smatthias.ringwald if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){ 230b1d43497Smatthias.ringwald log_info("l2cap_send_signaling_packet, cannot send\n"); 231b1d43497Smatthias.ringwald return BTSTACK_ACL_BUFFERS_FULL; 232b1d43497Smatthias.ringwald } 233b1d43497Smatthias.ringwald 2347b5fbe1fSmatthias.ringwald // log_info("l2cap_send_signaling_packet type %u\n", cmd); 235b1d43497Smatthias.ringwald uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer(); 23658de5610Smatthias.ringwald va_list argptr; 23758de5610Smatthias.ringwald va_start(argptr, identifier); 238816c0598Smatthias.ringwald uint16_t len = l2cap_create_signaling_internal(acl_buffer, handle, cmd, identifier, argptr); 23958de5610Smatthias.ringwald va_end(argptr); 2407b5fbe1fSmatthias.ringwald // log_info("l2cap_send_signaling_packet con %u!\n", handle); 241816c0598Smatthias.ringwald return hci_send_acl_packet(acl_buffer, len); 24258de5610Smatthias.ringwald } 24358de5610Smatthias.ringwald 244b1d43497Smatthias.ringwald uint8_t *l2cap_get_outgoing_buffer(void){ 245b1d43497Smatthias.ringwald return hci_get_outgoing_acl_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes 246b1d43497Smatthias.ringwald } 2476218e6f1Smatthias.ringwald 248b1d43497Smatthias.ringwald int l2cap_send_prepared(uint16_t local_cid, uint16_t len){ 249b1d43497Smatthias.ringwald 250b1d43497Smatthias.ringwald if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){ 251b1d43497Smatthias.ringwald log_info("l2cap_send_internal cid %u, cannot send\n", local_cid); 252808a48abSmatthias.ringwald return BTSTACK_ACL_BUFFERS_FULL; 2538ea03fa5Smatthias.ringwald } 2546218e6f1Smatthias.ringwald 25558de5610Smatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); 256b1d43497Smatthias.ringwald if (!channel) { 257b1d43497Smatthias.ringwald log_error("l2cap_send_internal no channel for cid %u\n", local_cid); 258b1d43497Smatthias.ringwald return -1; // TODO: define error 2596218e6f1Smatthias.ringwald } 2606218e6f1Smatthias.ringwald 261b1d43497Smatthias.ringwald if (channel->packets_granted == 0){ 262b1d43497Smatthias.ringwald log_error("l2cap_send_internal cid %u, no credits!\n", local_cid); 263b1d43497Smatthias.ringwald return -1; // TODO: define error 264b1d43497Smatthias.ringwald } 265b1d43497Smatthias.ringwald 266b1d43497Smatthias.ringwald --channel->packets_granted; 267b1d43497Smatthias.ringwald 268b1d43497Smatthias.ringwald log_debug("l2cap_send_internal cid %u, handle %u, 1 credit used, credits left %u;\n", 269b1d43497Smatthias.ringwald local_cid, channel->handle, channel->packets_granted); 270b1d43497Smatthias.ringwald 271b1d43497Smatthias.ringwald uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer(); 272b1d43497Smatthias.ringwald 27358de5610Smatthias.ringwald // 0 - Connection handle : PB=10 : BC=00 27458de5610Smatthias.ringwald bt_store_16(acl_buffer, 0, channel->handle | (2 << 12) | (0 << 14)); 27558de5610Smatthias.ringwald // 2 - ACL length 27658de5610Smatthias.ringwald bt_store_16(acl_buffer, 2, len + 4); 27758de5610Smatthias.ringwald // 4 - L2CAP packet length 27858de5610Smatthias.ringwald bt_store_16(acl_buffer, 4, len + 0); 27958de5610Smatthias.ringwald // 6 - L2CAP channel DEST 28058de5610Smatthias.ringwald bt_store_16(acl_buffer, 6, channel->remote_cid); 28158de5610Smatthias.ringwald // send 282b1d43497Smatthias.ringwald int err = hci_send_acl_packet(acl_buffer, len+8); 28391b99603Smatthias.ringwald 28491b99603Smatthias.ringwald l2cap_hand_out_credits(); 28591b99603Smatthias.ringwald 2866218e6f1Smatthias.ringwald return err; 28758de5610Smatthias.ringwald } 28858de5610Smatthias.ringwald 289b1d43497Smatthias.ringwald int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len){ 290b1d43497Smatthias.ringwald 291b1d43497Smatthias.ringwald if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){ 292b1d43497Smatthias.ringwald log_info("l2cap_send_internal cid %u, cannot send\n", local_cid); 293b1d43497Smatthias.ringwald return BTSTACK_ACL_BUFFERS_FULL; 294b1d43497Smatthias.ringwald } 295b1d43497Smatthias.ringwald 296b1d43497Smatthias.ringwald uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer(); 297b1d43497Smatthias.ringwald 298b1d43497Smatthias.ringwald memcpy(&acl_buffer[8], data, len); 299b1d43497Smatthias.ringwald 300b1d43497Smatthias.ringwald return l2cap_send_prepared(local_cid, len); 301b1d43497Smatthias.ringwald } 302b1d43497Smatthias.ringwald 30328ca2b46S[email protected] static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){ 30428ca2b46S[email protected] channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var | flag); 30528ca2b46S[email protected] } 30628ca2b46S[email protected] 30728ca2b46S[email protected] static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){ 30828ca2b46S[email protected] channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag); 30928ca2b46S[email protected] } 31028ca2b46S[email protected] 31128ca2b46S[email protected] 312b1d43497Smatthias.ringwald 3138158c421Smatthias.ringwald // MARK: L2CAP_RUN 3142cd0be45Smatthias.ringwald // process outstanding signaling tasks 3152cd0be45Smatthias.ringwald void l2cap_run(void){ 3162b83fb7dSmatthias.ringwald 3172b83fb7dSmatthias.ringwald // check pending signaling responses 3182b83fb7dSmatthias.ringwald while (signaling_responses_pending){ 3192b83fb7dSmatthias.ringwald 32002b22dc4Smatthias.ringwald if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break; 3212b83fb7dSmatthias.ringwald 3222b83fb7dSmatthias.ringwald hci_con_handle_t handle = signaling_responses[0].handle; 3232b83fb7dSmatthias.ringwald uint8_t sig_id = signaling_responses[0].sig_id; 3242b360848Smatthias.ringwald uint16_t infoType = signaling_responses[0].data; // INFORMATION_REQUEST 3252b360848Smatthias.ringwald uint16_t result = signaling_responses[0].data; // CONNECTION_REQUEST 3262b83fb7dSmatthias.ringwald 3272b83fb7dSmatthias.ringwald switch (signaling_responses[0].code){ 3282b360848Smatthias.ringwald case CONNECTION_REQUEST: 3292b360848Smatthias.ringwald l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, 0, 0, result, 0); 3302b360848Smatthias.ringwald break; 3312b83fb7dSmatthias.ringwald case ECHO_REQUEST: 3322b83fb7dSmatthias.ringwald l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL); 3332b83fb7dSmatthias.ringwald break; 3342b83fb7dSmatthias.ringwald case INFORMATION_REQUEST: 3352b83fb7dSmatthias.ringwald if (infoType == 2) { 3362b83fb7dSmatthias.ringwald uint32_t features = 0; 3372b83fb7dSmatthias.ringwald // extended features request supported, however no features present 3382b83fb7dSmatthias.ringwald l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, 4, &features); 3392b83fb7dSmatthias.ringwald } else { 3402b83fb7dSmatthias.ringwald // all other types are not supported 3412b83fb7dSmatthias.ringwald l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL); 3422b83fb7dSmatthias.ringwald } 3432b83fb7dSmatthias.ringwald break; 3442b83fb7dSmatthias.ringwald default: 3452b83fb7dSmatthias.ringwald // should not happen 3462b83fb7dSmatthias.ringwald break; 3472b83fb7dSmatthias.ringwald } 3482b83fb7dSmatthias.ringwald 3492b83fb7dSmatthias.ringwald // remove first item 3502b83fb7dSmatthias.ringwald signaling_responses_pending--; 3512b83fb7dSmatthias.ringwald int i; 3522b83fb7dSmatthias.ringwald for (i=0; i < signaling_responses_pending; i++){ 35376115249S[email protected] memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t)); 3542b83fb7dSmatthias.ringwald } 3552b83fb7dSmatthias.ringwald } 3562b83fb7dSmatthias.ringwald 357ae280e73Smatthias.ringwald uint8_t config_options[4]; 3582cd0be45Smatthias.ringwald linked_item_t *it; 359756102d3Smatthias.ringwald linked_item_t *next; 360756102d3Smatthias.ringwald for (it = (linked_item_t *) l2cap_channels; it ; it = next){ 361756102d3Smatthias.ringwald next = it->next; // cache next item as current item might get freed 3622cd0be45Smatthias.ringwald 36302b22dc4Smatthias.ringwald if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break; 36402b22dc4Smatthias.ringwald if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break; 3652cd0be45Smatthias.ringwald 3662cd0be45Smatthias.ringwald l2cap_channel_t * channel = (l2cap_channel_t *) it; 3676e6710ebSmatthias.ringwald 3687b5fbe1fSmatthias.ringwald // log_info("l2cap_run: state %u, var 0x%02x\n", channel->state, channel->state_var); 3696e6710ebSmatthias.ringwald 37056081214Smatthias.ringwald 3712cd0be45Smatthias.ringwald switch (channel->state){ 3722cd0be45Smatthias.ringwald 37302b22dc4Smatthias.ringwald case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION: 37464472d52Smatthias.ringwald // send connection request - set state first 37564472d52Smatthias.ringwald channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE; 37602b22dc4Smatthias.ringwald // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch 3778f8108aaSmatthias.ringwald hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1); 37802b22dc4Smatthias.ringwald break; 37902b22dc4Smatthias.ringwald 380e7ff783cSmatthias.ringwald case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE: 381b1988dceSmatthias.ringwald l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, channel->reason, 0); 382e7ff783cSmatthias.ringwald // discard channel - l2cap_finialize_channel_close without sending l2cap close event 383756102d3Smatthias.ringwald linked_list_remove(&l2cap_channels, (linked_item_t *) channel); // -- remove from list 384d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 385e7ff783cSmatthias.ringwald break; 386e7ff783cSmatthias.ringwald 387552d92a1Smatthias.ringwald case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT: 388fa8473a4Smatthias.ringwald channel->state = L2CAP_STATE_CONFIG; 38928ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ); 3902a544672Smatthias.ringwald l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0); 391552d92a1Smatthias.ringwald break; 392552d92a1Smatthias.ringwald 3936fdcc387Smatthias.ringwald case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST: 3946fdcc387Smatthias.ringwald // success, start l2cap handshake 395b1988dceSmatthias.ringwald channel->local_sig_id = l2cap_next_sig_id(); 3966fdcc387Smatthias.ringwald channel->state = L2CAP_STATE_WAIT_CONNECT_RSP; 3972a544672Smatthias.ringwald l2cap_send_signaling_packet( channel->handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid); 3986fdcc387Smatthias.ringwald break; 3996fdcc387Smatthias.ringwald 400fa8473a4Smatthias.ringwald case L2CAP_STATE_CONFIG: 40173cf2b3dSmatthias.ringwald if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){ 40228ca2b46S[email protected] channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP); 40328ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP); 404fa8473a4Smatthias.ringwald l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, 0, 0, 0, NULL); 405fa8473a4Smatthias.ringwald } 40673cf2b3dSmatthias.ringwald else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){ 40728ca2b46S[email protected] channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ); 40828ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ); 409b1988dceSmatthias.ringwald channel->local_sig_id = l2cap_next_sig_id(); 410ae280e73Smatthias.ringwald config_options[0] = 1; // MTU 411ae280e73Smatthias.ringwald config_options[1] = 2; // len param 412ae280e73Smatthias.ringwald bt_store_16( (uint8_t*)&config_options, 2, channel->local_mtu); 413b1988dceSmatthias.ringwald l2cap_send_signaling_packet(channel->handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, 4, &config_options); 414fa8473a4Smatthias.ringwald } 415fa8473a4Smatthias.ringwald if (l2cap_channel_ready_for_open(channel)){ 416552d92a1Smatthias.ringwald channel->state = L2CAP_STATE_OPEN; 417552d92a1Smatthias.ringwald l2cap_emit_channel_opened(channel, 0); // success 418552d92a1Smatthias.ringwald l2cap_emit_credits(channel, 1); 419fa8473a4Smatthias.ringwald } 420552d92a1Smatthias.ringwald break; 421552d92a1Smatthias.ringwald 422e7ff783cSmatthias.ringwald case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE: 423b1988dceSmatthias.ringwald l2cap_send_signaling_packet( channel->handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid); 424756102d3Smatthias.ringwald l2cap_finialize_channel_close(channel); // -- remove from list 425e7ff783cSmatthias.ringwald break; 426e7ff783cSmatthias.ringwald 427e7ff783cSmatthias.ringwald case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST: 428b1988dceSmatthias.ringwald channel->local_sig_id = l2cap_next_sig_id(); 4292cd0be45Smatthias.ringwald channel->state = L2CAP_STATE_WAIT_DISCONNECT; 4302a544672Smatthias.ringwald l2cap_send_signaling_packet( channel->handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid); 4312cd0be45Smatthias.ringwald break; 4322cd0be45Smatthias.ringwald default: 4332cd0be45Smatthias.ringwald break; 4342cd0be45Smatthias.ringwald } 4352cd0be45Smatthias.ringwald } 4362cd0be45Smatthias.ringwald } 4372cd0be45Smatthias.ringwald 4384aa9e837Smatthias.ringwald uint16_t l2cap_max_mtu(void){ 439816c0598Smatthias.ringwald return hci_max_acl_data_packet_length() - L2CAP_HEADER_SIZE; 440fa8c92f6Smatthias.ringwald } 441fa8c92f6Smatthias.ringwald 4421e6aba47Smatthias.ringwald // open outgoing L2CAP channel 44315470d27Smatthias.ringwald void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler, 44415470d27Smatthias.ringwald bd_addr_t address, uint16_t psm, uint16_t mtu){ 4451e6aba47Smatthias.ringwald 4461e6aba47Smatthias.ringwald // alloc structure 44728ca2b46S[email protected] l2cap_channel_t * chan = (l2cap_channel_t*) btstack_memory_l2cap_channel_get(); 4482b360848Smatthias.ringwald if (!chan) { 4492b360848Smatthias.ringwald // emit error event 4502b360848Smatthias.ringwald l2cap_channel_t dummy_channel; 4512b360848Smatthias.ringwald BD_ADDR_COPY(dummy_channel.address, address); 4522b360848Smatthias.ringwald dummy_channel.psm = psm; 4532b360848Smatthias.ringwald l2cap_emit_channel_opened(&dummy_channel, BTSTACK_MEMORY_ALLOC_FAILED); 4542b360848Smatthias.ringwald return; 4552b360848Smatthias.ringwald } 4561d279b20Smatthias.ringwald // limit local mtu to max acl packet length 4572985cb84Smatthias.ringwald if (mtu > l2cap_max_mtu()) { 4582985cb84Smatthias.ringwald mtu = l2cap_max_mtu(); 4599775e25bSmatthias.ringwald } 4609775e25bSmatthias.ringwald 4611e6aba47Smatthias.ringwald // fill in 4621e6aba47Smatthias.ringwald BD_ADDR_COPY(chan->address, address); 4631e6aba47Smatthias.ringwald chan->psm = psm; 4641e6aba47Smatthias.ringwald chan->handle = 0; 4651e6aba47Smatthias.ringwald chan->connection = connection; 4666b296a27Smatthias.ringwald chan->packet_handler = packet_handler; 4672784b77dSmatthias.ringwald chan->remote_mtu = L2CAP_MINIMAL_MTU; 46815470d27Smatthias.ringwald chan->local_mtu = mtu; 4696218e6f1Smatthias.ringwald chan->packets_granted = 0; 4706218e6f1Smatthias.ringwald 4711e6aba47Smatthias.ringwald // set initial state 47202b22dc4Smatthias.ringwald chan->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION; 47373cf2b3dSmatthias.ringwald chan->state_var = L2CAP_CHANNEL_STATE_VAR_NONE; 474b1988dceSmatthias.ringwald chan->remote_sig_id = L2CAP_SIG_ID_INVALID; 475b1988dceSmatthias.ringwald chan->local_sig_id = L2CAP_SIG_ID_INVALID; 4761e6aba47Smatthias.ringwald 4771e6aba47Smatthias.ringwald // add to connections list 4781e6aba47Smatthias.ringwald linked_list_add(&l2cap_channels, (linked_item_t *) chan); 4791e6aba47Smatthias.ringwald 48002b22dc4Smatthias.ringwald l2cap_run(); 48143625864Smatthias.ringwald } 48243625864Smatthias.ringwald 483b35f641cSmatthias.ringwald void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason){ 484b35f641cSmatthias.ringwald // find channel for local_cid 485b35f641cSmatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); 486f62db1e3Smatthias.ringwald if (channel) { 487e7ff783cSmatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; 488f62db1e3Smatthias.ringwald } 4892cd0be45Smatthias.ringwald // process 4902cd0be45Smatthias.ringwald l2cap_run(); 49143625864Smatthias.ringwald } 4921e6aba47Smatthias.ringwald 493afde0c52Smatthias.ringwald static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t status){ 49415ec09bbSmatthias.ringwald linked_item_t *it = (linked_item_t *) &l2cap_channels; 49515ec09bbSmatthias.ringwald while (it->next){ 49615ec09bbSmatthias.ringwald l2cap_channel_t * channel = (l2cap_channel_t *) it->next; 497b448a0e7Smatthias.ringwald if ( ! BD_ADDR_CMP( channel->address, address) ){ 49802b22dc4Smatthias.ringwald if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) { 499afde0c52Smatthias.ringwald // failure, forward error code 500afde0c52Smatthias.ringwald l2cap_emit_channel_opened(channel, status); 501afde0c52Smatthias.ringwald // discard channel 50215ec09bbSmatthias.ringwald it->next = it->next->next; 503d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 504afde0c52Smatthias.ringwald } 50515ec09bbSmatthias.ringwald } else { 50615ec09bbSmatthias.ringwald it = it->next; 507afde0c52Smatthias.ringwald } 508afde0c52Smatthias.ringwald } 509afde0c52Smatthias.ringwald } 510afde0c52Smatthias.ringwald 511afde0c52Smatthias.ringwald static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t handle){ 512afde0c52Smatthias.ringwald linked_item_t *it; 513afde0c52Smatthias.ringwald for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ 514afde0c52Smatthias.ringwald l2cap_channel_t * channel = (l2cap_channel_t *) it; 515afde0c52Smatthias.ringwald if ( ! BD_ADDR_CMP( channel->address, address) ){ 51602b22dc4Smatthias.ringwald if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) { 517b448a0e7Smatthias.ringwald // success, start l2cap handshake 5186fdcc387Smatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST; 519afde0c52Smatthias.ringwald channel->handle = handle; 520b35f641cSmatthias.ringwald channel->local_cid = l2cap_next_local_cid(); 521afde0c52Smatthias.ringwald } 522afde0c52Smatthias.ringwald } 523afde0c52Smatthias.ringwald } 5246fdcc387Smatthias.ringwald // process 5256fdcc387Smatthias.ringwald l2cap_run(); 526afde0c52Smatthias.ringwald } 527b448a0e7Smatthias.ringwald 528afde0c52Smatthias.ringwald void l2cap_event_handler( uint8_t *packet, uint16_t size ){ 529afde0c52Smatthias.ringwald 530afde0c52Smatthias.ringwald bd_addr_t address; 531afde0c52Smatthias.ringwald hci_con_handle_t handle; 5326e6710ebSmatthias.ringwald l2cap_channel_t * channel; 53336944dffSmatthias.ringwald linked_item_t *it; 5342d00edd4Smatthias.ringwald int hci_con_used; 535afde0c52Smatthias.ringwald 536afde0c52Smatthias.ringwald switch(packet[0]){ 537afde0c52Smatthias.ringwald 538afde0c52Smatthias.ringwald // handle connection complete events 539afde0c52Smatthias.ringwald case HCI_EVENT_CONNECTION_COMPLETE: 540afde0c52Smatthias.ringwald bt_flip_addr(address, &packet[5]); 541afde0c52Smatthias.ringwald if (packet[2] == 0){ 542afde0c52Smatthias.ringwald handle = READ_BT_16(packet, 3); 543afde0c52Smatthias.ringwald l2cap_handle_connection_success_for_addr(address, handle); 544afde0c52Smatthias.ringwald } else { 545afde0c52Smatthias.ringwald l2cap_handle_connection_failed_for_addr(address, packet[2]); 546afde0c52Smatthias.ringwald } 547afde0c52Smatthias.ringwald break; 548afde0c52Smatthias.ringwald 549afde0c52Smatthias.ringwald // handle successful create connection cancel command 550afde0c52Smatthias.ringwald case HCI_EVENT_COMMAND_COMPLETE: 551afde0c52Smatthias.ringwald if ( COMMAND_COMPLETE_EVENT(packet, hci_create_connection_cancel) ) { 552afde0c52Smatthias.ringwald if (packet[5] == 0){ 553afde0c52Smatthias.ringwald bt_flip_addr(address, &packet[6]); 554afde0c52Smatthias.ringwald // CONNECTION TERMINATED BY LOCAL HOST (0X16) 555afde0c52Smatthias.ringwald l2cap_handle_connection_failed_for_addr(address, 0x16); 55603cfbabcSmatthias.ringwald } 5571e6aba47Smatthias.ringwald } 55839d59809Smatthias.ringwald l2cap_run(); // try sending signaling packets first 55939d59809Smatthias.ringwald break; 56039d59809Smatthias.ringwald 56139d59809Smatthias.ringwald case HCI_EVENT_COMMAND_STATUS: 56239d59809Smatthias.ringwald l2cap_run(); // try sending signaling packets first 563afde0c52Smatthias.ringwald break; 56427a923d0Smatthias.ringwald 5651e6aba47Smatthias.ringwald // handle disconnection complete events 566afde0c52Smatthias.ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 56727a923d0Smatthias.ringwald // send l2cap disconnect events for all channels on this handle 568afde0c52Smatthias.ringwald handle = READ_BT_16(packet, 3); 56915ec09bbSmatthias.ringwald it = (linked_item_t *) &l2cap_channels; 57015ec09bbSmatthias.ringwald while (it->next){ 57139ce35a7Smatthias.ringwald l2cap_channel_t * channel = (l2cap_channel_t *) it->next; 57227a923d0Smatthias.ringwald if ( channel->handle == handle ){ 57315ec09bbSmatthias.ringwald // update prev item before free'ing next element - don't call l2cap_finalize_channel_close 5742060cf14Smatthias.ringwald it->next = it->next->next; 57515ec09bbSmatthias.ringwald l2cap_emit_channel_closed(channel); 576d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 57715ec09bbSmatthias.ringwald } else { 57815ec09bbSmatthias.ringwald it = it->next; 57927a923d0Smatthias.ringwald } 58027a923d0Smatthias.ringwald } 581afde0c52Smatthias.ringwald break; 582fcadd0caSmatthias.ringwald 5836218e6f1Smatthias.ringwald case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS: 58402b22dc4Smatthias.ringwald l2cap_run(); // try sending signaling packets first 5858d371091Smatthias.ringwald l2cap_hand_out_credits(); 5866218e6f1Smatthias.ringwald break; 5876218e6f1Smatthias.ringwald 588ee091cf1Smatthias.ringwald // HCI Connection Timeouts 589afde0c52Smatthias.ringwald case L2CAP_EVENT_TIMEOUT_CHECK: 59036944dffSmatthias.ringwald handle = READ_BT_16(packet, 2); 59180ca58a0Smatthias.ringwald if (hci_authentication_active_for_handle(handle)) break; 5922d00edd4Smatthias.ringwald hci_con_used = 0; 593ee091cf1Smatthias.ringwald for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ 594ee091cf1Smatthias.ringwald channel = (l2cap_channel_t *) it; 595ee091cf1Smatthias.ringwald if (channel->handle == handle) { 5962d00edd4Smatthias.ringwald hci_con_used = 1; 597ee091cf1Smatthias.ringwald } 598ee091cf1Smatthias.ringwald } 5992d00edd4Smatthias.ringwald if (hci_con_used) break; 60032ab9390Smatthias.ringwald if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break; 6019edc8742Smatthias.ringwald hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection 602afde0c52Smatthias.ringwald break; 603ee091cf1Smatthias.ringwald 6046e6710ebSmatthias.ringwald case DAEMON_EVENT_HCI_PACKET_SENT: 6056e6710ebSmatthias.ringwald for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ 6066e6710ebSmatthias.ringwald channel = (l2cap_channel_t *) it; 6076e6710ebSmatthias.ringwald if (channel->packet_handler) { 6086e6710ebSmatthias.ringwald (* (channel->packet_handler))(HCI_EVENT_PACKET, channel->local_cid, packet, size); 6096e6710ebSmatthias.ringwald } 6106e6710ebSmatthias.ringwald } 611*5652b5ffS[email protected] if (attribute_protocol_packet_handler) { 612*5652b5ffS[email protected] (*attribute_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size); 613*5652b5ffS[email protected] } 614*5652b5ffS[email protected] if (security_protocol_packet_handler) { 615*5652b5ffS[email protected] (*security_protocol_packet_handler)(SM_DATA_PACKET, 0, packet, size); 616*5652b5ffS[email protected] } 6176e6710ebSmatthias.ringwald break; 6186e6710ebSmatthias.ringwald 619afde0c52Smatthias.ringwald default: 620afde0c52Smatthias.ringwald break; 621afde0c52Smatthias.ringwald } 622afde0c52Smatthias.ringwald 623afde0c52Smatthias.ringwald // pass on 624b502e1b0Smatthias.ringwald (*packet_handler)(NULL, HCI_EVENT_PACKET, 0, packet, size); 6251e6aba47Smatthias.ringwald } 6261e6aba47Smatthias.ringwald 627afde0c52Smatthias.ringwald static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){ 628b1988dceSmatthias.ringwald channel->remote_sig_id = identifier; 629e7ff783cSmatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE; 630e7ff783cSmatthias.ringwald l2cap_run(); 63184836b65Smatthias.ringwald } 63284836b65Smatthias.ringwald 6332b360848Smatthias.ringwald static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){ 6342b360848Smatthias.ringwald if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) { 6352b360848Smatthias.ringwald signaling_responses[signaling_responses_pending].handle = handle; 6362b360848Smatthias.ringwald signaling_responses[signaling_responses_pending].code = code; 6372b360848Smatthias.ringwald signaling_responses[signaling_responses_pending].sig_id = sig_id; 6382b360848Smatthias.ringwald signaling_responses[signaling_responses_pending].data = data; 6392b360848Smatthias.ringwald signaling_responses_pending++; 6402b360848Smatthias.ringwald l2cap_run(); 6412b360848Smatthias.ringwald } 6422b360848Smatthias.ringwald } 6432b360848Smatthias.ringwald 644b35f641cSmatthias.ringwald static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){ 645645658c9Smatthias.ringwald 6467b5fbe1fSmatthias.ringwald // log_info("l2cap_handle_connection_request for handle %u, psm %u cid %u\n", handle, psm, source_cid); 647645658c9Smatthias.ringwald l2cap_service_t *service = l2cap_get_service(psm); 648645658c9Smatthias.ringwald if (!service) { 649645658c9Smatthias.ringwald // 0x0002 PSM not supported 6502b360848Smatthias.ringwald l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0002); 651645658c9Smatthias.ringwald return; 652645658c9Smatthias.ringwald } 653645658c9Smatthias.ringwald 654645658c9Smatthias.ringwald hci_connection_t * hci_connection = connection_for_handle( handle ); 655645658c9Smatthias.ringwald if (!hci_connection) { 6562b360848Smatthias.ringwald // 6577d67539fSmatthias.ringwald log_error("no hci_connection for handle %u\n", handle); 658645658c9Smatthias.ringwald return; 659645658c9Smatthias.ringwald } 660645658c9Smatthias.ringwald // alloc structure 6617b5fbe1fSmatthias.ringwald // log_info("l2cap_handle_connection_request register channel\n"); 66228ca2b46S[email protected] l2cap_channel_t * channel = (l2cap_channel_t*) btstack_memory_l2cap_channel_get(); 6632b360848Smatthias.ringwald if (!channel){ 6642b360848Smatthias.ringwald // 0x0004 No resources available 6652b360848Smatthias.ringwald l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0004); 6662b360848Smatthias.ringwald return; 6672b360848Smatthias.ringwald } 668645658c9Smatthias.ringwald 669645658c9Smatthias.ringwald // fill in 670169f8b28Smatthias.ringwald BD_ADDR_COPY(channel->address, hci_connection->address); 671169f8b28Smatthias.ringwald channel->psm = psm; 672169f8b28Smatthias.ringwald channel->handle = handle; 673169f8b28Smatthias.ringwald channel->connection = service->connection; 674f8dd2f72Smatthias.ringwald channel->packet_handler = service->packet_handler; 675b35f641cSmatthias.ringwald channel->local_cid = l2cap_next_local_cid(); 676b35f641cSmatthias.ringwald channel->remote_cid = source_cid; 677fa2b2627Smatthias.ringwald channel->local_mtu = service->mtu; 6780a18a8e9Smatthias.ringwald channel->remote_mtu = L2CAP_DEFAULT_MTU; 679761b0451Smatthias.ringwald channel->packets_granted = 0; 680b1988dceSmatthias.ringwald channel->remote_sig_id = sig_id; 681645658c9Smatthias.ringwald 6821d279b20Smatthias.ringwald // limit local mtu to max acl packet length 6832985cb84Smatthias.ringwald if (channel->local_mtu > l2cap_max_mtu()) { 6842985cb84Smatthias.ringwald channel->local_mtu = l2cap_max_mtu(); 6859775e25bSmatthias.ringwald } 6869775e25bSmatthias.ringwald 687645658c9Smatthias.ringwald // set initial state 688e405ae81Smatthias.ringwald channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT; 68973cf2b3dSmatthias.ringwald channel->state_var = L2CAP_CHANNEL_STATE_VAR_NONE; 690e405ae81Smatthias.ringwald 691645658c9Smatthias.ringwald // add to connections list 692169f8b28Smatthias.ringwald linked_list_add(&l2cap_channels, (linked_item_t *) channel); 693645658c9Smatthias.ringwald 694e405ae81Smatthias.ringwald // emit incoming connection request 695e405ae81Smatthias.ringwald l2cap_emit_connection_request(channel); 696e405ae81Smatthias.ringwald } 697645658c9Smatthias.ringwald 698b35f641cSmatthias.ringwald void l2cap_accept_connection_internal(uint16_t local_cid){ 699b35f641cSmatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); 700e405ae81Smatthias.ringwald if (!channel) { 7017d67539fSmatthias.ringwald log_error("l2cap_accept_connection_internal called but local_cid 0x%x not found", local_cid); 702e405ae81Smatthias.ringwald return; 703e405ae81Smatthias.ringwald } 704e405ae81Smatthias.ringwald 705552d92a1Smatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT; 706e405ae81Smatthias.ringwald 707552d92a1Smatthias.ringwald // process 708552d92a1Smatthias.ringwald l2cap_run(); 709e405ae81Smatthias.ringwald } 710645658c9Smatthias.ringwald 711b35f641cSmatthias.ringwald void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason){ 712b35f641cSmatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid); 713e405ae81Smatthias.ringwald if (!channel) { 7147d67539fSmatthias.ringwald log_error( "l2cap_decline_connection_internal called but local_cid 0x%x not found", local_cid); 715e405ae81Smatthias.ringwald return; 716e405ae81Smatthias.ringwald } 717e7ff783cSmatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE; 718e7ff783cSmatthias.ringwald channel->reason = reason; 719e7ff783cSmatthias.ringwald l2cap_run(); 720645658c9Smatthias.ringwald } 721645658c9Smatthias.ringwald 7222784b77dSmatthias.ringwald void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t *command){ 723b1988dceSmatthias.ringwald 724b1988dceSmatthias.ringwald channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET]; 725b1988dceSmatthias.ringwald 7262784b77dSmatthias.ringwald // accept the other's configuration options 7273de7c0caSmatthias.ringwald uint16_t end_pos = 4 + READ_BT_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET); 7283de7c0caSmatthias.ringwald uint16_t pos = 8; 7293de7c0caSmatthias.ringwald while (pos < end_pos){ 7301dc511deSmatthias.ringwald uint8_t type = command[pos++]; 7311dc511deSmatthias.ringwald uint8_t length = command[pos++]; 7321dc511deSmatthias.ringwald // MTU { type(8): 1, len(8):2, MTU(16) } 7331dc511deSmatthias.ringwald if ((type & 0x7f) == 1 && length == 2){ 7341dc511deSmatthias.ringwald channel->remote_mtu = READ_BT_16(command, pos); 7357b5fbe1fSmatthias.ringwald // log_info("l2cap cid %u, remote mtu %u\n", channel->local_cid, channel->remote_mtu); 7361dc511deSmatthias.ringwald } 7371dc511deSmatthias.ringwald pos += length; 7381dc511deSmatthias.ringwald } 7392784b77dSmatthias.ringwald } 7402784b77dSmatthias.ringwald 741fa8473a4Smatthias.ringwald static int l2cap_channel_ready_for_open(l2cap_channel_t *channel){ 7427b5fbe1fSmatthias.ringwald // log_info("l2cap_channel_ready_for_open 0x%02x\n", channel->state_var); 74373cf2b3dSmatthias.ringwald if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP) == 0) return 0; 74473cf2b3dSmatthias.ringwald if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP) == 0) return 0; 745fa8473a4Smatthias.ringwald return 1; 746fa8473a4Smatthias.ringwald } 747fa8473a4Smatthias.ringwald 748fa8473a4Smatthias.ringwald 74900d93d79Smatthias.ringwald void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){ 7501e6aba47Smatthias.ringwald 75100d93d79Smatthias.ringwald uint8_t code = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET]; 75200d93d79Smatthias.ringwald uint8_t identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET]; 75338e5900eSmatthias.ringwald uint16_t result = 0; 7541e6aba47Smatthias.ringwald 7555842b6d9Smatthias.ringwald log_info("L2CAP signaling handler code %u, state %u\n", code, channel->state); 756b35f641cSmatthias.ringwald 7579a011532Smatthias.ringwald // handle DISCONNECT REQUESTS seperately 7589a011532Smatthias.ringwald if (code == DISCONNECTION_REQUEST){ 7599a011532Smatthias.ringwald switch (channel->state){ 760fa8473a4Smatthias.ringwald case L2CAP_STATE_CONFIG: 7619a011532Smatthias.ringwald case L2CAP_STATE_OPEN: 7622b83fb7dSmatthias.ringwald case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST: 7639a011532Smatthias.ringwald case L2CAP_STATE_WAIT_DISCONNECT: 7649a011532Smatthias.ringwald l2cap_handle_disconnect_request(channel, identifier); 7659a011532Smatthias.ringwald break; 7669a011532Smatthias.ringwald 7679a011532Smatthias.ringwald default: 7689a011532Smatthias.ringwald // ignore in other states 7699a011532Smatthias.ringwald break; 7709a011532Smatthias.ringwald } 7719a011532Smatthias.ringwald return; 7729a011532Smatthias.ringwald } 7739a011532Smatthias.ringwald 77456081214Smatthias.ringwald // @STATEMACHINE(l2cap) 7751e6aba47Smatthias.ringwald switch (channel->state) { 7761e6aba47Smatthias.ringwald 7771e6aba47Smatthias.ringwald case L2CAP_STATE_WAIT_CONNECT_RSP: 7781e6aba47Smatthias.ringwald switch (code){ 7791e6aba47Smatthias.ringwald case CONNECTION_RESPONSE: 78000d93d79Smatthias.ringwald result = READ_BT_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4); 78138e5900eSmatthias.ringwald switch (result) { 78238e5900eSmatthias.ringwald case 0: 783169f8b28Smatthias.ringwald // successful connection 78400d93d79Smatthias.ringwald channel->remote_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET); 785fa8473a4Smatthias.ringwald channel->state = L2CAP_STATE_CONFIG; 78628ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ); 78738e5900eSmatthias.ringwald break; 78838e5900eSmatthias.ringwald case 1: 78938e5900eSmatthias.ringwald // connection pending. get some coffee 79038e5900eSmatthias.ringwald break; 79138e5900eSmatthias.ringwald default: 792eb920dbeSmatthias.ringwald // channel closed 793eb920dbeSmatthias.ringwald channel->state = L2CAP_STATE_CLOSED; 794eb920dbeSmatthias.ringwald 795f32b992eSmatthias.ringwald // map l2cap connection response result to BTstack status enumeration 79638e5900eSmatthias.ringwald l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result); 797eb920dbeSmatthias.ringwald 798eb920dbeSmatthias.ringwald // drop link key if security block 799eb920dbeSmatthias.ringwald if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){ 800eb920dbeSmatthias.ringwald hci_drop_link_key_for_bd_addr(&channel->address); 801eb920dbeSmatthias.ringwald } 802eb920dbeSmatthias.ringwald 803eb920dbeSmatthias.ringwald // discard channel 804eb920dbeSmatthias.ringwald linked_list_remove(&l2cap_channels, (linked_item_t *) channel); 805d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 80638e5900eSmatthias.ringwald break; 8071e6aba47Smatthias.ringwald } 8081e6aba47Smatthias.ringwald break; 80938e5900eSmatthias.ringwald 81038e5900eSmatthias.ringwald default: 8111e6aba47Smatthias.ringwald //@TODO: implement other signaling packets 81238e5900eSmatthias.ringwald break; 8131e6aba47Smatthias.ringwald } 8141e6aba47Smatthias.ringwald break; 8151e6aba47Smatthias.ringwald 816fa8473a4Smatthias.ringwald case L2CAP_STATE_CONFIG: 817ae280e73Smatthias.ringwald switch (code) { 818ae280e73Smatthias.ringwald case CONFIGURE_REQUEST: 81928ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ); 82028ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP); 821ae280e73Smatthias.ringwald l2cap_signaling_handle_configure_request(channel, command); 822ae280e73Smatthias.ringwald break; 8231e6aba47Smatthias.ringwald case CONFIGURE_RESPONSE: 82428ca2b46S[email protected] channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP); 8255a67bd4aSmatthias.ringwald break; 8265a67bd4aSmatthias.ringwald default: 8275a67bd4aSmatthias.ringwald break; 8281e6aba47Smatthias.ringwald } 829fa8473a4Smatthias.ringwald if (l2cap_channel_ready_for_open(channel)){ 830fa8473a4Smatthias.ringwald // for open: 8315a67bd4aSmatthias.ringwald channel->state = L2CAP_STATE_OPEN; 832fa8473a4Smatthias.ringwald l2cap_emit_channel_opened(channel, 0); 8336218e6f1Smatthias.ringwald l2cap_emit_credits(channel, 1); 834c8e4258aSmatthias.ringwald } 835c8e4258aSmatthias.ringwald break; 836f62db1e3Smatthias.ringwald 837f62db1e3Smatthias.ringwald case L2CAP_STATE_WAIT_DISCONNECT: 838f62db1e3Smatthias.ringwald switch (code) { 839f62db1e3Smatthias.ringwald case DISCONNECTION_RESPONSE: 84027a923d0Smatthias.ringwald l2cap_finialize_channel_close(channel); 84127a923d0Smatthias.ringwald break; 8425a67bd4aSmatthias.ringwald default: 8435a67bd4aSmatthias.ringwald //@TODO: implement other signaling packets 8445a67bd4aSmatthias.ringwald break; 84527a923d0Smatthias.ringwald } 84627a923d0Smatthias.ringwald break; 84784836b65Smatthias.ringwald 84884836b65Smatthias.ringwald case L2CAP_STATE_CLOSED: 84984836b65Smatthias.ringwald // @TODO handle incoming requests 85084836b65Smatthias.ringwald break; 85184836b65Smatthias.ringwald 85284836b65Smatthias.ringwald case L2CAP_STATE_OPEN: 85384836b65Smatthias.ringwald //@TODO: implement other signaling packets, e.g. re-configure 85484836b65Smatthias.ringwald break; 85510642e45Smatthias.ringwald default: 85610642e45Smatthias.ringwald break; 85727a923d0Smatthias.ringwald } 8587b5fbe1fSmatthias.ringwald // log_info("new state %u\n", channel->state); 85927a923d0Smatthias.ringwald } 86027a923d0Smatthias.ringwald 86100d93d79Smatthias.ringwald 86200d93d79Smatthias.ringwald void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * command){ 86300d93d79Smatthias.ringwald 86400d93d79Smatthias.ringwald // get code, signalind identifier and command len 86500d93d79Smatthias.ringwald uint8_t code = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET]; 86600d93d79Smatthias.ringwald uint8_t sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET]; 86700d93d79Smatthias.ringwald 86800d93d79Smatthias.ringwald // not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_REQUEST 86900d93d79Smatthias.ringwald if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_REQUEST){ 87000d93d79Smatthias.ringwald return; 87100d93d79Smatthias.ringwald } 87200d93d79Smatthias.ringwald 87300d93d79Smatthias.ringwald // general commands without an assigned channel 87400d93d79Smatthias.ringwald switch(code) { 87500d93d79Smatthias.ringwald 87600d93d79Smatthias.ringwald case CONNECTION_REQUEST: { 87700d93d79Smatthias.ringwald uint16_t psm = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET); 87800d93d79Smatthias.ringwald uint16_t source_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2); 87900d93d79Smatthias.ringwald l2cap_handle_connection_request(handle, sig_id, psm, source_cid); 8802b83fb7dSmatthias.ringwald return; 88100d93d79Smatthias.ringwald } 88200d93d79Smatthias.ringwald 8832b360848Smatthias.ringwald case ECHO_REQUEST: 8842b360848Smatthias.ringwald l2cap_register_signaling_response(handle, code, sig_id, 0); 8852b83fb7dSmatthias.ringwald return; 88600d93d79Smatthias.ringwald 88700d93d79Smatthias.ringwald case INFORMATION_REQUEST: { 88800d93d79Smatthias.ringwald uint16_t infoType = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET); 8892b360848Smatthias.ringwald l2cap_register_signaling_response(handle, code, sig_id, infoType); 8902b83fb7dSmatthias.ringwald return; 89100d93d79Smatthias.ringwald } 89200d93d79Smatthias.ringwald 89300d93d79Smatthias.ringwald default: 89400d93d79Smatthias.ringwald break; 89500d93d79Smatthias.ringwald } 89600d93d79Smatthias.ringwald 89700d93d79Smatthias.ringwald 89800d93d79Smatthias.ringwald // Get potential destination CID 89900d93d79Smatthias.ringwald uint16_t dest_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET); 90000d93d79Smatthias.ringwald 90100d93d79Smatthias.ringwald // Find channel for this sig_id and connection handle 90200d93d79Smatthias.ringwald linked_item_t *it; 90300d93d79Smatthias.ringwald for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ 90400d93d79Smatthias.ringwald l2cap_channel_t * channel = (l2cap_channel_t *) it; 90500d93d79Smatthias.ringwald if (channel->handle == handle) { 90600d93d79Smatthias.ringwald if (code & 1) { 907b1988dceSmatthias.ringwald // match odd commands (responses) by previous signaling identifier 908b1988dceSmatthias.ringwald if (channel->local_sig_id == sig_id) { 90900d93d79Smatthias.ringwald l2cap_signaling_handler_channel(channel, command); 9104e32727eSmatthias.ringwald break; 91100d93d79Smatthias.ringwald } 91200d93d79Smatthias.ringwald } else { 913b1988dceSmatthias.ringwald // match even commands (requests) by local channel id 91400d93d79Smatthias.ringwald if (channel->local_cid == dest_cid) { 91500d93d79Smatthias.ringwald l2cap_signaling_handler_channel(channel, command); 9164e32727eSmatthias.ringwald break; 91700d93d79Smatthias.ringwald } 91800d93d79Smatthias.ringwald } 91900d93d79Smatthias.ringwald } 92000d93d79Smatthias.ringwald } 92100d93d79Smatthias.ringwald } 92200d93d79Smatthias.ringwald 92300d93d79Smatthias.ringwald void l2cap_acl_handler( uint8_t *packet, uint16_t size ){ 92400d93d79Smatthias.ringwald 92500d93d79Smatthias.ringwald // Get Channel ID 92600d93d79Smatthias.ringwald uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); 92700d93d79Smatthias.ringwald hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet); 92800d93d79Smatthias.ringwald 929*5652b5ffS[email protected] switch (channel_id) { 930*5652b5ffS[email protected] 931*5652b5ffS[email protected] case L2CAP_CID_SIGNALING: { 932*5652b5ffS[email protected] 93300d93d79Smatthias.ringwald uint16_t command_offset = 8; 93400d93d79Smatthias.ringwald while (command_offset < size) { 93500d93d79Smatthias.ringwald 93600d93d79Smatthias.ringwald // handle signaling commands 93700d93d79Smatthias.ringwald l2cap_signaling_handler_dispatch(handle, &packet[command_offset]); 93800d93d79Smatthias.ringwald 93900d93d79Smatthias.ringwald // increment command_offset 94000d93d79Smatthias.ringwald command_offset += L2CAP_SIGNALING_COMMAND_DATA_OFFSET + READ_BT_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET); 94100d93d79Smatthias.ringwald } 942*5652b5ffS[email protected] break; 94300d93d79Smatthias.ringwald } 94400d93d79Smatthias.ringwald 945*5652b5ffS[email protected] case L2CAP_CID_ATTRIBUTE_PROTOCOL: 946*5652b5ffS[email protected] if (attribute_protocol_packet_handler) { 947*5652b5ffS[email protected] (*attribute_protocol_packet_handler)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); 948*5652b5ffS[email protected] } 949*5652b5ffS[email protected] break; 950*5652b5ffS[email protected] 951*5652b5ffS[email protected] case L2CAP_CID_SECURITY_MANAGER_PROTOCOL: 952*5652b5ffS[email protected] if (security_protocol_packet_handler) { 953*5652b5ffS[email protected] (*security_protocol_packet_handler)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); 954*5652b5ffS[email protected] } 955*5652b5ffS[email protected] break; 956*5652b5ffS[email protected] 957*5652b5ffS[email protected] default: { 95800d93d79Smatthias.ringwald // Find channel for this channel_id and connection handle 95900d93d79Smatthias.ringwald l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(channel_id); 96000d93d79Smatthias.ringwald if (channel) { 96158de5610Smatthias.ringwald l2cap_dispatch(channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); 96200d93d79Smatthias.ringwald } 963*5652b5ffS[email protected] break; 964*5652b5ffS[email protected] } 965*5652b5ffS[email protected] } 966*5652b5ffS[email protected] 967*5652b5ffS[email protected] l2cap_run(); 96800d93d79Smatthias.ringwald } 96900d93d79Smatthias.ringwald 9702718e2e7Smatthias.ringwald static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){ 9712718e2e7Smatthias.ringwald switch (packet_type) { 9722718e2e7Smatthias.ringwald case HCI_EVENT_PACKET: 9732718e2e7Smatthias.ringwald l2cap_event_handler(packet, size); 9742718e2e7Smatthias.ringwald break; 9752718e2e7Smatthias.ringwald case HCI_ACL_DATA_PACKET: 9762718e2e7Smatthias.ringwald l2cap_acl_handler(packet, size); 9772718e2e7Smatthias.ringwald break; 9782718e2e7Smatthias.ringwald default: 9792718e2e7Smatthias.ringwald break; 9802718e2e7Smatthias.ringwald } 9812718e2e7Smatthias.ringwald } 98200d93d79Smatthias.ringwald 98315ec09bbSmatthias.ringwald // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE 98427a923d0Smatthias.ringwald void l2cap_finialize_channel_close(l2cap_channel_t *channel){ 985f62db1e3Smatthias.ringwald channel->state = L2CAP_STATE_CLOSED; 986f62db1e3Smatthias.ringwald l2cap_emit_channel_closed(channel); 987f62db1e3Smatthias.ringwald // discard channel 988f62db1e3Smatthias.ringwald linked_list_remove(&l2cap_channels, (linked_item_t *) channel); 989d3a9df87Smatthias.ringwald btstack_memory_l2cap_channel_free(channel); 990c8e4258aSmatthias.ringwald } 9911e6aba47Smatthias.ringwald 9929d9bbc01Smatthias.ringwald l2cap_service_t * l2cap_get_service(uint16_t psm){ 993c52bf64dSmatthias.ringwald linked_item_t *it; 9949d9bbc01Smatthias.ringwald 9959d9bbc01Smatthias.ringwald // close open channels 9969d9bbc01Smatthias.ringwald for (it = (linked_item_t *) l2cap_services; it ; it = it->next){ 9979d9bbc01Smatthias.ringwald l2cap_service_t * service = ((l2cap_service_t *) it); 9989d9bbc01Smatthias.ringwald if ( service->psm == psm){ 9999d9bbc01Smatthias.ringwald return service; 10009d9bbc01Smatthias.ringwald }; 10019d9bbc01Smatthias.ringwald } 10029d9bbc01Smatthias.ringwald return NULL; 10039d9bbc01Smatthias.ringwald } 10049d9bbc01Smatthias.ringwald 100536944dffSmatthias.ringwald void l2cap_register_service_internal(void *connection, btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t mtu){ 10064bb582b6Smatthias.ringwald // check for alread registered psm 10074bb582b6Smatthias.ringwald // TODO: emit error event 10089d9bbc01Smatthias.ringwald l2cap_service_t *service = l2cap_get_service(psm); 1009277abc2cSmatthias.ringwald if (service) { 1010277abc2cSmatthias.ringwald log_error("l2cap_register_service_internal: PSM %u already registered\n", psm); 101181476041Smatthias.ringwald l2cap_emit_service_registered(connection, L2CAP_SERVICE_ALREADY_REGISTERED, psm); 1012277abc2cSmatthias.ringwald return; 1013277abc2cSmatthias.ringwald } 10149d9bbc01Smatthias.ringwald 10154bb582b6Smatthias.ringwald // alloc structure 10164bb582b6Smatthias.ringwald // TODO: emit error event 101728ca2b46S[email protected] service = (l2cap_service_t *) btstack_memory_l2cap_service_get(); 1018277abc2cSmatthias.ringwald if (!service) { 1019277abc2cSmatthias.ringwald log_error("l2cap_register_service_internal: no memory for l2cap_service_t\n"); 10205842b6d9Smatthias.ringwald l2cap_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, psm); 1021277abc2cSmatthias.ringwald return; 1022277abc2cSmatthias.ringwald } 10239d9bbc01Smatthias.ringwald 10249d9bbc01Smatthias.ringwald // fill in 10259d9bbc01Smatthias.ringwald service->psm = psm; 10269d9bbc01Smatthias.ringwald service->mtu = mtu; 10279d9bbc01Smatthias.ringwald service->connection = connection; 1028d8497f19Smatthias.ringwald service->packet_handler = packet_handler; 10299d9bbc01Smatthias.ringwald 10309d9bbc01Smatthias.ringwald // add to services list 10319d9bbc01Smatthias.ringwald linked_list_add(&l2cap_services, (linked_item_t *) service); 1032c0e866bfSmatthias.ringwald 1033c0e866bfSmatthias.ringwald // enable page scan 1034c0e866bfSmatthias.ringwald hci_connectable_control(1); 10355842b6d9Smatthias.ringwald 10365842b6d9Smatthias.ringwald // done 10375842b6d9Smatthias.ringwald l2cap_emit_service_registered(connection, 0, psm); 10389d9bbc01Smatthias.ringwald } 10399d9bbc01Smatthias.ringwald 104036944dffSmatthias.ringwald void l2cap_unregister_service_internal(void *connection, uint16_t psm){ 10419d9bbc01Smatthias.ringwald l2cap_service_t *service = l2cap_get_service(psm); 1042037d6e48Smatthias.ringwald if (!service) return; 10439d9bbc01Smatthias.ringwald linked_list_remove(&l2cap_services, (linked_item_t *) service); 1044d3a9df87Smatthias.ringwald btstack_memory_l2cap_service_free(service); 1045c0e866bfSmatthias.ringwald 1046c0e866bfSmatthias.ringwald // disable page scan when no services registered 1047c0e866bfSmatthias.ringwald if (!linked_list_empty(&l2cap_services)) return; 1048c0e866bfSmatthias.ringwald hci_connectable_control(0); 10499d9bbc01Smatthias.ringwald } 10509d9bbc01Smatthias.ringwald 10519d9bbc01Smatthias.ringwald // 105236944dffSmatthias.ringwald void l2cap_close_connection(void *connection){ 10539d9bbc01Smatthias.ringwald linked_item_t *it; 10549d9bbc01Smatthias.ringwald 10553a9e0a58Smatthias.ringwald // close open channels - note to myself: no channel is freed, so no new for fancy iterator tricks 1056c52bf64dSmatthias.ringwald l2cap_channel_t * channel; 1057c52bf64dSmatthias.ringwald for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ 1058c52bf64dSmatthias.ringwald channel = (l2cap_channel_t *) it; 1059c52bf64dSmatthias.ringwald if (channel->connection == connection) { 1060cb8eb7e6Smatthias.ringwald channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; 1061c52bf64dSmatthias.ringwald } 1062c52bf64dSmatthias.ringwald } 10639d9bbc01Smatthias.ringwald 1064645658c9Smatthias.ringwald // unregister services 106569025de8Smatthias.ringwald it = (linked_item_t *) &l2cap_services; 106669025de8Smatthias.ringwald while (it->next) { 106769025de8Smatthias.ringwald l2cap_service_t * service = (l2cap_service_t *) it->next; 1068645658c9Smatthias.ringwald if (service->connection == connection){ 106969025de8Smatthias.ringwald it->next = it->next->next; 1070d3a9df87Smatthias.ringwald btstack_memory_l2cap_service_free(service); 10718149d2c7Smatthias.ringwald } else { 10728149d2c7Smatthias.ringwald it = it->next; 1073645658c9Smatthias.ringwald } 1074645658c9Smatthias.ringwald } 1075cb8eb7e6Smatthias.ringwald 1076cb8eb7e6Smatthias.ringwald // process 1077cb8eb7e6Smatthias.ringwald l2cap_run(); 1078c52bf64dSmatthias.ringwald } 1079*5652b5ffS[email protected] 1080*5652b5ffS[email protected] // Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol 1081*5652b5ffS[email protected] void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint16_t channel_id) { 1082*5652b5ffS[email protected] switch(channel_id){ 1083*5652b5ffS[email protected] case L2CAP_CID_ATTRIBUTE_PROTOCOL: 1084*5652b5ffS[email protected] attribute_protocol_packet_handler = packet_handler; 1085*5652b5ffS[email protected] break; 1086*5652b5ffS[email protected] case L2CAP_CID_SECURITY_MANAGER_PROTOCOL: 1087*5652b5ffS[email protected] security_protocol_packet_handler = packet_handler; 1088*5652b5ffS[email protected] break; 1089*5652b5ffS[email protected] } 1090*5652b5ffS[email protected] } 1091*5652b5ffS[email protected] 1092