Junichi Katsu / Mbed 2 deprecated BLEControl

Dependencies:   FatFileSystem TB6612FNG2 mbed

Committer:
mbed_Cookbook_SE
Date:
Mon Nov 30 09:32:15 2015 +0000
Revision:
0:de03cbbcd0ff
??

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_Cookbook_SE 0:de03cbbcd0ff 1 /*
mbed_Cookbook_SE 0:de03cbbcd0ff 2 * Copyright (C) 2009-2012 by Matthias Ringwald
mbed_Cookbook_SE 0:de03cbbcd0ff 3 *
mbed_Cookbook_SE 0:de03cbbcd0ff 4 * Redistribution and use in source and binary forms, with or without
mbed_Cookbook_SE 0:de03cbbcd0ff 5 * modification, are permitted provided that the following conditions
mbed_Cookbook_SE 0:de03cbbcd0ff 6 * are met:
mbed_Cookbook_SE 0:de03cbbcd0ff 7 *
mbed_Cookbook_SE 0:de03cbbcd0ff 8 * 1. Redistributions of source code must retain the above copyright
mbed_Cookbook_SE 0:de03cbbcd0ff 9 * notice, this list of conditions and the following disclaimer.
mbed_Cookbook_SE 0:de03cbbcd0ff 10 * 2. Redistributions in binary form must reproduce the above copyright
mbed_Cookbook_SE 0:de03cbbcd0ff 11 * notice, this list of conditions and the following disclaimer in the
mbed_Cookbook_SE 0:de03cbbcd0ff 12 * documentation and/or other materials provided with the distribution.
mbed_Cookbook_SE 0:de03cbbcd0ff 13 * 3. Neither the name of the copyright holders nor the names of
mbed_Cookbook_SE 0:de03cbbcd0ff 14 * contributors may be used to endorse or promote products derived
mbed_Cookbook_SE 0:de03cbbcd0ff 15 * from this software without specific prior written permission.
mbed_Cookbook_SE 0:de03cbbcd0ff 16 * 4. Any redistribution, use, or modification is done solely for
mbed_Cookbook_SE 0:de03cbbcd0ff 17 * personal benefit and not for any commercial purpose or for
mbed_Cookbook_SE 0:de03cbbcd0ff 18 * monetary gain.
mbed_Cookbook_SE 0:de03cbbcd0ff 19 *
mbed_Cookbook_SE 0:de03cbbcd0ff 20 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
mbed_Cookbook_SE 0:de03cbbcd0ff 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
mbed_Cookbook_SE 0:de03cbbcd0ff 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
mbed_Cookbook_SE 0:de03cbbcd0ff 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
mbed_Cookbook_SE 0:de03cbbcd0ff 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
mbed_Cookbook_SE 0:de03cbbcd0ff 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
mbed_Cookbook_SE 0:de03cbbcd0ff 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
mbed_Cookbook_SE 0:de03cbbcd0ff 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
mbed_Cookbook_SE 0:de03cbbcd0ff 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
mbed_Cookbook_SE 0:de03cbbcd0ff 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
mbed_Cookbook_SE 0:de03cbbcd0ff 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
mbed_Cookbook_SE 0:de03cbbcd0ff 31 * SUCH DAMAGE.
mbed_Cookbook_SE 0:de03cbbcd0ff 32 *
mbed_Cookbook_SE 0:de03cbbcd0ff 33 * Please inquire about commercial licensing options at btstack@ringwald.ch
mbed_Cookbook_SE 0:de03cbbcd0ff 34 *
mbed_Cookbook_SE 0:de03cbbcd0ff 35 */
mbed_Cookbook_SE 0:de03cbbcd0ff 36
mbed_Cookbook_SE 0:de03cbbcd0ff 37 /*
mbed_Cookbook_SE 0:de03cbbcd0ff 38 * l2cap.c
mbed_Cookbook_SE 0:de03cbbcd0ff 39 *
mbed_Cookbook_SE 0:de03cbbcd0ff 40 * Logical Link Control and Adaption Protocl (L2CAP)
mbed_Cookbook_SE 0:de03cbbcd0ff 41 *
mbed_Cookbook_SE 0:de03cbbcd0ff 42 * Created by Matthias Ringwald on 5/16/09.
mbed_Cookbook_SE 0:de03cbbcd0ff 43 */
mbed_Cookbook_SE 0:de03cbbcd0ff 44
mbed_Cookbook_SE 0:de03cbbcd0ff 45 #include "l2cap.h"
mbed_Cookbook_SE 0:de03cbbcd0ff 46 #include "hci.h"
mbed_Cookbook_SE 0:de03cbbcd0ff 47 #include "hci_dump.h"
mbed_Cookbook_SE 0:de03cbbcd0ff 48 #include "debug.h"
mbed_Cookbook_SE 0:de03cbbcd0ff 49 #include "btstack_memory.h"
mbed_Cookbook_SE 0:de03cbbcd0ff 50
mbed_Cookbook_SE 0:de03cbbcd0ff 51 #include <stdarg.h>
mbed_Cookbook_SE 0:de03cbbcd0ff 52 #include <string.h>
mbed_Cookbook_SE 0:de03cbbcd0ff 53
mbed_Cookbook_SE 0:de03cbbcd0ff 54 #include <stdio.h>
mbed_Cookbook_SE 0:de03cbbcd0ff 55
mbed_Cookbook_SE 0:de03cbbcd0ff 56 // nr of buffered acl packets in outgoing queue to get max performance
mbed_Cookbook_SE 0:de03cbbcd0ff 57 #define NR_BUFFERED_ACL_PACKETS 3
mbed_Cookbook_SE 0:de03cbbcd0ff 58
mbed_Cookbook_SE 0:de03cbbcd0ff 59 // used to cache l2cap rejects, echo, and informational requests
mbed_Cookbook_SE 0:de03cbbcd0ff 60 #define NR_PENDING_SIGNALING_RESPONSES 3
mbed_Cookbook_SE 0:de03cbbcd0ff 61
mbed_Cookbook_SE 0:de03cbbcd0ff 62 // offsets for L2CAP SIGNALING COMMANDS
mbed_Cookbook_SE 0:de03cbbcd0ff 63 #define L2CAP_SIGNALING_COMMAND_CODE_OFFSET 0
mbed_Cookbook_SE 0:de03cbbcd0ff 64 #define L2CAP_SIGNALING_COMMAND_SIGID_OFFSET 1
mbed_Cookbook_SE 0:de03cbbcd0ff 65 #define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2
mbed_Cookbook_SE 0:de03cbbcd0ff 66 #define L2CAP_SIGNALING_COMMAND_DATA_OFFSET 4
mbed_Cookbook_SE 0:de03cbbcd0ff 67
mbed_Cookbook_SE 0:de03cbbcd0ff 68 static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
mbed_Cookbook_SE 0:de03cbbcd0ff 69 static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
mbed_Cookbook_SE 0:de03cbbcd0ff 70
mbed_Cookbook_SE 0:de03cbbcd0ff 71 // used to cache l2cap rejects, echo, and informational requests
mbed_Cookbook_SE 0:de03cbbcd0ff 72 static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES];
mbed_Cookbook_SE 0:de03cbbcd0ff 73 static int signaling_responses_pending;
mbed_Cookbook_SE 0:de03cbbcd0ff 74
mbed_Cookbook_SE 0:de03cbbcd0ff 75 static linked_list_t l2cap_channels = NULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 76 static linked_list_t l2cap_services = NULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 77 static void (*packet_handler) (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) = null_packet_handler;
mbed_Cookbook_SE 0:de03cbbcd0ff 78 static int new_credits_blocked = 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 79
mbed_Cookbook_SE 0:de03cbbcd0ff 80 static btstack_packet_handler_t attribute_protocol_packet_handler = NULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 81 static btstack_packet_handler_t security_protocol_packet_handler = NULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 82
mbed_Cookbook_SE 0:de03cbbcd0ff 83 // prototypes
mbed_Cookbook_SE 0:de03cbbcd0ff 84 static void l2cap_finialize_channel_close(l2cap_channel_t *channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 85 static l2cap_service_t * l2cap_get_service(uint16_t psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 86 static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status);
mbed_Cookbook_SE 0:de03cbbcd0ff 87 static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 88 static void l2cap_emit_connection_request(l2cap_channel_t *channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 89 static int l2cap_channel_ready_for_open(l2cap_channel_t *channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 90
mbed_Cookbook_SE 0:de03cbbcd0ff 91
mbed_Cookbook_SE 0:de03cbbcd0ff 92 void l2cap_init(){
mbed_Cookbook_SE 0:de03cbbcd0ff 93 new_credits_blocked = 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 94 signaling_responses_pending = 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 95
mbed_Cookbook_SE 0:de03cbbcd0ff 96 l2cap_channels = NULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 97 l2cap_services = NULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 98
mbed_Cookbook_SE 0:de03cbbcd0ff 99 packet_handler = null_packet_handler;
mbed_Cookbook_SE 0:de03cbbcd0ff 100
mbed_Cookbook_SE 0:de03cbbcd0ff 101 //
mbed_Cookbook_SE 0:de03cbbcd0ff 102 // register callback with HCI
mbed_Cookbook_SE 0:de03cbbcd0ff 103 //
mbed_Cookbook_SE 0:de03cbbcd0ff 104 hci_register_packet_handler(&l2cap_packet_handler);
mbed_Cookbook_SE 0:de03cbbcd0ff 105 hci_connectable_control(0); // no services yet
mbed_Cookbook_SE 0:de03cbbcd0ff 106 }
mbed_Cookbook_SE 0:de03cbbcd0ff 107
mbed_Cookbook_SE 0:de03cbbcd0ff 108
mbed_Cookbook_SE 0:de03cbbcd0ff 109 /** Register L2CAP packet handlers */
mbed_Cookbook_SE 0:de03cbbcd0ff 110 static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
mbed_Cookbook_SE 0:de03cbbcd0ff 111 }
mbed_Cookbook_SE 0:de03cbbcd0ff 112 void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
mbed_Cookbook_SE 0:de03cbbcd0ff 113 packet_handler = handler;
mbed_Cookbook_SE 0:de03cbbcd0ff 114 }
mbed_Cookbook_SE 0:de03cbbcd0ff 115
mbed_Cookbook_SE 0:de03cbbcd0ff 116 // notify client/protocol handler
mbed_Cookbook_SE 0:de03cbbcd0ff 117 void l2cap_dispatch(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){
mbed_Cookbook_SE 0:de03cbbcd0ff 118 if (channel->packet_handler) {
mbed_Cookbook_SE 0:de03cbbcd0ff 119 (* (channel->packet_handler))(type, channel->local_cid, data, size);
mbed_Cookbook_SE 0:de03cbbcd0ff 120 } else {
mbed_Cookbook_SE 0:de03cbbcd0ff 121 (*packet_handler)(channel->connection, type, channel->local_cid, data, size);
mbed_Cookbook_SE 0:de03cbbcd0ff 122 }
mbed_Cookbook_SE 0:de03cbbcd0ff 123 }
mbed_Cookbook_SE 0:de03cbbcd0ff 124
mbed_Cookbook_SE 0:de03cbbcd0ff 125 void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
mbed_Cookbook_SE 0:de03cbbcd0ff 126 uint8_t event[21];
mbed_Cookbook_SE 0:de03cbbcd0ff 127 event[0] = L2CAP_EVENT_CHANNEL_OPENED;
mbed_Cookbook_SE 0:de03cbbcd0ff 128 event[1] = sizeof(event) - 2;
mbed_Cookbook_SE 0:de03cbbcd0ff 129 event[2] = status;
mbed_Cookbook_SE 0:de03cbbcd0ff 130 bt_flip_addr(&event[3], channel->address);
mbed_Cookbook_SE 0:de03cbbcd0ff 131 bt_store_16(event, 9, channel->handle);
mbed_Cookbook_SE 0:de03cbbcd0ff 132 bt_store_16(event, 11, channel->psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 133 bt_store_16(event, 13, channel->local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 134 bt_store_16(event, 15, channel->remote_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 135 bt_store_16(event, 17, channel->local_mtu);
mbed_Cookbook_SE 0:de03cbbcd0ff 136 bt_store_16(event, 19, channel->remote_mtu);
mbed_Cookbook_SE 0:de03cbbcd0ff 137 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 138 l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 139 }
mbed_Cookbook_SE 0:de03cbbcd0ff 140
mbed_Cookbook_SE 0:de03cbbcd0ff 141 void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
mbed_Cookbook_SE 0:de03cbbcd0ff 142 uint8_t event[4];
mbed_Cookbook_SE 0:de03cbbcd0ff 143 event[0] = L2CAP_EVENT_CHANNEL_CLOSED;
mbed_Cookbook_SE 0:de03cbbcd0ff 144 event[1] = sizeof(event) - 2;
mbed_Cookbook_SE 0:de03cbbcd0ff 145 bt_store_16(event, 2, channel->local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 146 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 147 l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 148 }
mbed_Cookbook_SE 0:de03cbbcd0ff 149
mbed_Cookbook_SE 0:de03cbbcd0ff 150 void l2cap_emit_connection_request(l2cap_channel_t *channel) {
mbed_Cookbook_SE 0:de03cbbcd0ff 151 uint8_t event[16];
mbed_Cookbook_SE 0:de03cbbcd0ff 152 event[0] = L2CAP_EVENT_INCOMING_CONNECTION;
mbed_Cookbook_SE 0:de03cbbcd0ff 153 event[1] = sizeof(event) - 2;
mbed_Cookbook_SE 0:de03cbbcd0ff 154 bt_flip_addr(&event[2], channel->address);
mbed_Cookbook_SE 0:de03cbbcd0ff 155 bt_store_16(event, 8, channel->handle);
mbed_Cookbook_SE 0:de03cbbcd0ff 156 bt_store_16(event, 10, channel->psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 157 bt_store_16(event, 12, channel->local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 158 bt_store_16(event, 14, channel->remote_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 159 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 160 l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 161 }
mbed_Cookbook_SE 0:de03cbbcd0ff 162
mbed_Cookbook_SE 0:de03cbbcd0ff 163 static void l2cap_emit_service_registered(void *connection, uint8_t status, uint16_t psm){
mbed_Cookbook_SE 0:de03cbbcd0ff 164 uint8_t event[5];
mbed_Cookbook_SE 0:de03cbbcd0ff 165 event[0] = L2CAP_EVENT_SERVICE_REGISTERED;
mbed_Cookbook_SE 0:de03cbbcd0ff 166 event[1] = sizeof(event) - 2;
mbed_Cookbook_SE 0:de03cbbcd0ff 167 event[2] = status;
mbed_Cookbook_SE 0:de03cbbcd0ff 168 bt_store_16(event, 3, psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 169 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 170 (*packet_handler)(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 171 }
mbed_Cookbook_SE 0:de03cbbcd0ff 172
mbed_Cookbook_SE 0:de03cbbcd0ff 173 void l2cap_emit_credits(l2cap_channel_t *channel, uint8_t credits) {
mbed_Cookbook_SE 0:de03cbbcd0ff 174 // track credits
mbed_Cookbook_SE 0:de03cbbcd0ff 175 channel->packets_granted += credits;
mbed_Cookbook_SE 0:de03cbbcd0ff 176 // log_info("l2cap_emit_credits for cid %u, credits given: %u (+%u)\n", channel->local_cid, channel->packets_granted, credits);
mbed_Cookbook_SE 0:de03cbbcd0ff 177
mbed_Cookbook_SE 0:de03cbbcd0ff 178 uint8_t event[5];
mbed_Cookbook_SE 0:de03cbbcd0ff 179 event[0] = L2CAP_EVENT_CREDITS;
mbed_Cookbook_SE 0:de03cbbcd0ff 180 event[1] = sizeof(event) - 2;
mbed_Cookbook_SE 0:de03cbbcd0ff 181 bt_store_16(event, 2, channel->local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 182 event[4] = credits;
mbed_Cookbook_SE 0:de03cbbcd0ff 183 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 184 l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
mbed_Cookbook_SE 0:de03cbbcd0ff 185 }
mbed_Cookbook_SE 0:de03cbbcd0ff 186
mbed_Cookbook_SE 0:de03cbbcd0ff 187 void l2cap_block_new_credits(uint8_t blocked){
mbed_Cookbook_SE 0:de03cbbcd0ff 188 new_credits_blocked = blocked;
mbed_Cookbook_SE 0:de03cbbcd0ff 189 }
mbed_Cookbook_SE 0:de03cbbcd0ff 190
mbed_Cookbook_SE 0:de03cbbcd0ff 191 void l2cap_hand_out_credits(void){
mbed_Cookbook_SE 0:de03cbbcd0ff 192
mbed_Cookbook_SE 0:de03cbbcd0ff 193 if (new_credits_blocked) return; // we're told not to. used by daemon
mbed_Cookbook_SE 0:de03cbbcd0ff 194
mbed_Cookbook_SE 0:de03cbbcd0ff 195 linked_item_t *it;
mbed_Cookbook_SE 0:de03cbbcd0ff 196 for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 197 if (!hci_number_free_acl_slots()) return;
mbed_Cookbook_SE 0:de03cbbcd0ff 198 l2cap_channel_t * channel = (l2cap_channel_t *) it;
mbed_Cookbook_SE 0:de03cbbcd0ff 199 if (channel->state != L2CAP_STATE_OPEN) continue;
mbed_Cookbook_SE 0:de03cbbcd0ff 200 if (hci_number_outgoing_packets(channel->handle) < NR_BUFFERED_ACL_PACKETS && channel->packets_granted == 0) {
mbed_Cookbook_SE 0:de03cbbcd0ff 201 l2cap_emit_credits(channel, 1);
mbed_Cookbook_SE 0:de03cbbcd0ff 202 }
mbed_Cookbook_SE 0:de03cbbcd0ff 203 }
mbed_Cookbook_SE 0:de03cbbcd0ff 204 }
mbed_Cookbook_SE 0:de03cbbcd0ff 205
mbed_Cookbook_SE 0:de03cbbcd0ff 206 l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
mbed_Cookbook_SE 0:de03cbbcd0ff 207 linked_item_t *it;
mbed_Cookbook_SE 0:de03cbbcd0ff 208 for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 209 l2cap_channel_t * channel = (l2cap_channel_t *) it;
mbed_Cookbook_SE 0:de03cbbcd0ff 210 if ( channel->local_cid == local_cid) {
mbed_Cookbook_SE 0:de03cbbcd0ff 211 return channel;
mbed_Cookbook_SE 0:de03cbbcd0ff 212 }
mbed_Cookbook_SE 0:de03cbbcd0ff 213 }
mbed_Cookbook_SE 0:de03cbbcd0ff 214 return NULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 215 }
mbed_Cookbook_SE 0:de03cbbcd0ff 216
mbed_Cookbook_SE 0:de03cbbcd0ff 217 int l2cap_can_send_packet_now(uint16_t local_cid){
mbed_Cookbook_SE 0:de03cbbcd0ff 218 l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 219 if (!channel) return 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 220 if (!channel->packets_granted) return 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 221 return hci_can_send_packet_now(HCI_ACL_DATA_PACKET);
mbed_Cookbook_SE 0:de03cbbcd0ff 222 }
mbed_Cookbook_SE 0:de03cbbcd0ff 223
mbed_Cookbook_SE 0:de03cbbcd0ff 224 uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){
mbed_Cookbook_SE 0:de03cbbcd0ff 225 l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 226 if (channel) {
mbed_Cookbook_SE 0:de03cbbcd0ff 227 return channel->remote_mtu;
mbed_Cookbook_SE 0:de03cbbcd0ff 228 }
mbed_Cookbook_SE 0:de03cbbcd0ff 229 return 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 230 }
mbed_Cookbook_SE 0:de03cbbcd0ff 231
mbed_Cookbook_SE 0:de03cbbcd0ff 232 int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
mbed_Cookbook_SE 0:de03cbbcd0ff 233
mbed_Cookbook_SE 0:de03cbbcd0ff 234 if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
mbed_Cookbook_SE 0:de03cbbcd0ff 235 log_info("l2cap_send_signaling_packet, cannot send\n");
mbed_Cookbook_SE 0:de03cbbcd0ff 236 return BTSTACK_ACL_BUFFERS_FULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 237 }
mbed_Cookbook_SE 0:de03cbbcd0ff 238
mbed_Cookbook_SE 0:de03cbbcd0ff 239 // log_info("l2cap_send_signaling_packet type %u\n", cmd);
mbed_Cookbook_SE 0:de03cbbcd0ff 240 uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
mbed_Cookbook_SE 0:de03cbbcd0ff 241 va_list argptr;
mbed_Cookbook_SE 0:de03cbbcd0ff 242 va_start(argptr, identifier);
mbed_Cookbook_SE 0:de03cbbcd0ff 243 uint16_t len = l2cap_create_signaling_internal(acl_buffer, handle, cmd, identifier, argptr);
mbed_Cookbook_SE 0:de03cbbcd0ff 244 va_end(argptr);
mbed_Cookbook_SE 0:de03cbbcd0ff 245 // log_info("l2cap_send_signaling_packet con %u!\n", handle);
mbed_Cookbook_SE 0:de03cbbcd0ff 246 return hci_send_acl_packet(acl_buffer, len);
mbed_Cookbook_SE 0:de03cbbcd0ff 247 }
mbed_Cookbook_SE 0:de03cbbcd0ff 248
mbed_Cookbook_SE 0:de03cbbcd0ff 249 uint8_t *l2cap_get_outgoing_buffer(void){
mbed_Cookbook_SE 0:de03cbbcd0ff 250 return hci_get_outgoing_acl_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
mbed_Cookbook_SE 0:de03cbbcd0ff 251 }
mbed_Cookbook_SE 0:de03cbbcd0ff 252
mbed_Cookbook_SE 0:de03cbbcd0ff 253 int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
mbed_Cookbook_SE 0:de03cbbcd0ff 254
mbed_Cookbook_SE 0:de03cbbcd0ff 255 if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
mbed_Cookbook_SE 0:de03cbbcd0ff 256 log_info("l2cap_send_internal cid %u, cannot send\n", local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 257 return BTSTACK_ACL_BUFFERS_FULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 258 }
mbed_Cookbook_SE 0:de03cbbcd0ff 259
mbed_Cookbook_SE 0:de03cbbcd0ff 260 l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 261 if (!channel) {
mbed_Cookbook_SE 0:de03cbbcd0ff 262 log_error("l2cap_send_internal no channel for cid %u\n", local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 263 return -1; // TODO: define error
mbed_Cookbook_SE 0:de03cbbcd0ff 264 }
mbed_Cookbook_SE 0:de03cbbcd0ff 265
mbed_Cookbook_SE 0:de03cbbcd0ff 266 if (channel->packets_granted == 0){
mbed_Cookbook_SE 0:de03cbbcd0ff 267 log_error("l2cap_send_internal cid %u, no credits!\n", local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 268 return -1; // TODO: define error
mbed_Cookbook_SE 0:de03cbbcd0ff 269 }
mbed_Cookbook_SE 0:de03cbbcd0ff 270
mbed_Cookbook_SE 0:de03cbbcd0ff 271 --channel->packets_granted;
mbed_Cookbook_SE 0:de03cbbcd0ff 272
mbed_Cookbook_SE 0:de03cbbcd0ff 273 log_debug("l2cap_send_internal cid %u, handle %u, 1 credit used, credits left %u;\n",
mbed_Cookbook_SE 0:de03cbbcd0ff 274 local_cid, channel->handle, channel->packets_granted);
mbed_Cookbook_SE 0:de03cbbcd0ff 275
mbed_Cookbook_SE 0:de03cbbcd0ff 276 uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
mbed_Cookbook_SE 0:de03cbbcd0ff 277
mbed_Cookbook_SE 0:de03cbbcd0ff 278 // 0 - Connection handle : PB=10 : BC=00
mbed_Cookbook_SE 0:de03cbbcd0ff 279 bt_store_16(acl_buffer, 0, channel->handle | (2 << 12) | (0 << 14));
mbed_Cookbook_SE 0:de03cbbcd0ff 280 // 2 - ACL length
mbed_Cookbook_SE 0:de03cbbcd0ff 281 bt_store_16(acl_buffer, 2, len + 4);
mbed_Cookbook_SE 0:de03cbbcd0ff 282 // 4 - L2CAP packet length
mbed_Cookbook_SE 0:de03cbbcd0ff 283 bt_store_16(acl_buffer, 4, len + 0);
mbed_Cookbook_SE 0:de03cbbcd0ff 284 // 6 - L2CAP channel DEST
mbed_Cookbook_SE 0:de03cbbcd0ff 285 bt_store_16(acl_buffer, 6, channel->remote_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 286 // send
mbed_Cookbook_SE 0:de03cbbcd0ff 287 int err = hci_send_acl_packet(acl_buffer, len+8);
mbed_Cookbook_SE 0:de03cbbcd0ff 288
mbed_Cookbook_SE 0:de03cbbcd0ff 289 l2cap_hand_out_credits();
mbed_Cookbook_SE 0:de03cbbcd0ff 290
mbed_Cookbook_SE 0:de03cbbcd0ff 291 return err;
mbed_Cookbook_SE 0:de03cbbcd0ff 292 }
mbed_Cookbook_SE 0:de03cbbcd0ff 293
mbed_Cookbook_SE 0:de03cbbcd0ff 294 int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len){
mbed_Cookbook_SE 0:de03cbbcd0ff 295
mbed_Cookbook_SE 0:de03cbbcd0ff 296 if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
mbed_Cookbook_SE 0:de03cbbcd0ff 297 log_info("l2cap_send_prepared_to_handle cid %u, cannot send\n", cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 298 return BTSTACK_ACL_BUFFERS_FULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 299 }
mbed_Cookbook_SE 0:de03cbbcd0ff 300
mbed_Cookbook_SE 0:de03cbbcd0ff 301 log_debug("l2cap_send_prepared_to_handle cid %u, handle %u\n", cid, handle);
mbed_Cookbook_SE 0:de03cbbcd0ff 302
mbed_Cookbook_SE 0:de03cbbcd0ff 303 uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
mbed_Cookbook_SE 0:de03cbbcd0ff 304
mbed_Cookbook_SE 0:de03cbbcd0ff 305 // 0 - Connection handle : PB=10 : BC=00
mbed_Cookbook_SE 0:de03cbbcd0ff 306 bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14));
mbed_Cookbook_SE 0:de03cbbcd0ff 307 // 2 - ACL length
mbed_Cookbook_SE 0:de03cbbcd0ff 308 bt_store_16(acl_buffer, 2, len + 4);
mbed_Cookbook_SE 0:de03cbbcd0ff 309 // 4 - L2CAP packet length
mbed_Cookbook_SE 0:de03cbbcd0ff 310 bt_store_16(acl_buffer, 4, len + 0);
mbed_Cookbook_SE 0:de03cbbcd0ff 311 // 6 - L2CAP channel DEST
mbed_Cookbook_SE 0:de03cbbcd0ff 312 bt_store_16(acl_buffer, 6, cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 313 // send
mbed_Cookbook_SE 0:de03cbbcd0ff 314 int err = hci_send_acl_packet(acl_buffer, len+8);
mbed_Cookbook_SE 0:de03cbbcd0ff 315
mbed_Cookbook_SE 0:de03cbbcd0ff 316 l2cap_hand_out_credits();
mbed_Cookbook_SE 0:de03cbbcd0ff 317
mbed_Cookbook_SE 0:de03cbbcd0ff 318 return err;
mbed_Cookbook_SE 0:de03cbbcd0ff 319 }
mbed_Cookbook_SE 0:de03cbbcd0ff 320
mbed_Cookbook_SE 0:de03cbbcd0ff 321 int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len){
mbed_Cookbook_SE 0:de03cbbcd0ff 322
mbed_Cookbook_SE 0:de03cbbcd0ff 323 if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
mbed_Cookbook_SE 0:de03cbbcd0ff 324 log_info("l2cap_send_internal cid %u, cannot send\n", local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 325 return BTSTACK_ACL_BUFFERS_FULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 326 }
mbed_Cookbook_SE 0:de03cbbcd0ff 327
mbed_Cookbook_SE 0:de03cbbcd0ff 328 uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
mbed_Cookbook_SE 0:de03cbbcd0ff 329
mbed_Cookbook_SE 0:de03cbbcd0ff 330 memcpy(&acl_buffer[8], data, len);
mbed_Cookbook_SE 0:de03cbbcd0ff 331
mbed_Cookbook_SE 0:de03cbbcd0ff 332 return l2cap_send_prepared(local_cid, len);
mbed_Cookbook_SE 0:de03cbbcd0ff 333 }
mbed_Cookbook_SE 0:de03cbbcd0ff 334
mbed_Cookbook_SE 0:de03cbbcd0ff 335 int l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len){
mbed_Cookbook_SE 0:de03cbbcd0ff 336
mbed_Cookbook_SE 0:de03cbbcd0ff 337 if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
mbed_Cookbook_SE 0:de03cbbcd0ff 338 log_info("l2cap_send_internal cid %u, cannot send\n", cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 339 return BTSTACK_ACL_BUFFERS_FULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 340 }
mbed_Cookbook_SE 0:de03cbbcd0ff 341
mbed_Cookbook_SE 0:de03cbbcd0ff 342 uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
mbed_Cookbook_SE 0:de03cbbcd0ff 343
mbed_Cookbook_SE 0:de03cbbcd0ff 344 memcpy(&acl_buffer[8], data, len);
mbed_Cookbook_SE 0:de03cbbcd0ff 345
mbed_Cookbook_SE 0:de03cbbcd0ff 346 return l2cap_send_prepared_connectionless(handle, cid, len);
mbed_Cookbook_SE 0:de03cbbcd0ff 347 }
mbed_Cookbook_SE 0:de03cbbcd0ff 348
mbed_Cookbook_SE 0:de03cbbcd0ff 349 static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
mbed_Cookbook_SE 0:de03cbbcd0ff 350 channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var | flag);
mbed_Cookbook_SE 0:de03cbbcd0ff 351 }
mbed_Cookbook_SE 0:de03cbbcd0ff 352
mbed_Cookbook_SE 0:de03cbbcd0ff 353 static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
mbed_Cookbook_SE 0:de03cbbcd0ff 354 channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag);
mbed_Cookbook_SE 0:de03cbbcd0ff 355 }
mbed_Cookbook_SE 0:de03cbbcd0ff 356
mbed_Cookbook_SE 0:de03cbbcd0ff 357
mbed_Cookbook_SE 0:de03cbbcd0ff 358
mbed_Cookbook_SE 0:de03cbbcd0ff 359 // MARK: L2CAP_RUN
mbed_Cookbook_SE 0:de03cbbcd0ff 360 // process outstanding signaling tasks
mbed_Cookbook_SE 0:de03cbbcd0ff 361 void l2cap_run(void){
mbed_Cookbook_SE 0:de03cbbcd0ff 362
mbed_Cookbook_SE 0:de03cbbcd0ff 363 // check pending signaling responses
mbed_Cookbook_SE 0:de03cbbcd0ff 364 while (signaling_responses_pending){
mbed_Cookbook_SE 0:de03cbbcd0ff 365
mbed_Cookbook_SE 0:de03cbbcd0ff 366 if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break;
mbed_Cookbook_SE 0:de03cbbcd0ff 367
mbed_Cookbook_SE 0:de03cbbcd0ff 368 hci_con_handle_t handle = signaling_responses[0].handle;
mbed_Cookbook_SE 0:de03cbbcd0ff 369 uint8_t sig_id = signaling_responses[0].sig_id;
mbed_Cookbook_SE 0:de03cbbcd0ff 370 uint16_t infoType = signaling_responses[0].data; // INFORMATION_REQUEST
mbed_Cookbook_SE 0:de03cbbcd0ff 371 uint16_t result = signaling_responses[0].data; // CONNECTION_REQUEST
mbed_Cookbook_SE 0:de03cbbcd0ff 372
mbed_Cookbook_SE 0:de03cbbcd0ff 373 switch (signaling_responses[0].code){
mbed_Cookbook_SE 0:de03cbbcd0ff 374 case CONNECTION_REQUEST:
mbed_Cookbook_SE 0:de03cbbcd0ff 375 l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, 0, 0, result, 0);
mbed_Cookbook_SE 0:de03cbbcd0ff 376 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 377 case ECHO_REQUEST:
mbed_Cookbook_SE 0:de03cbbcd0ff 378 l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL);
mbed_Cookbook_SE 0:de03cbbcd0ff 379 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 380 case INFORMATION_REQUEST:
mbed_Cookbook_SE 0:de03cbbcd0ff 381 if (infoType == 2) {
mbed_Cookbook_SE 0:de03cbbcd0ff 382 uint32_t features = 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 383 // extended features request supported, however no features present
mbed_Cookbook_SE 0:de03cbbcd0ff 384 l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, 4, &features);
mbed_Cookbook_SE 0:de03cbbcd0ff 385 } else {
mbed_Cookbook_SE 0:de03cbbcd0ff 386 // all other types are not supported
mbed_Cookbook_SE 0:de03cbbcd0ff 387 l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL);
mbed_Cookbook_SE 0:de03cbbcd0ff 388 }
mbed_Cookbook_SE 0:de03cbbcd0ff 389 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 390 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 391 // should not happen
mbed_Cookbook_SE 0:de03cbbcd0ff 392 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 393 }
mbed_Cookbook_SE 0:de03cbbcd0ff 394
mbed_Cookbook_SE 0:de03cbbcd0ff 395 // remove first item
mbed_Cookbook_SE 0:de03cbbcd0ff 396 signaling_responses_pending--;
mbed_Cookbook_SE 0:de03cbbcd0ff 397 int i;
mbed_Cookbook_SE 0:de03cbbcd0ff 398 for (i=0; i < signaling_responses_pending; i++){
mbed_Cookbook_SE 0:de03cbbcd0ff 399 memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t));
mbed_Cookbook_SE 0:de03cbbcd0ff 400 }
mbed_Cookbook_SE 0:de03cbbcd0ff 401 }
mbed_Cookbook_SE 0:de03cbbcd0ff 402
mbed_Cookbook_SE 0:de03cbbcd0ff 403 uint8_t config_options[4];
mbed_Cookbook_SE 0:de03cbbcd0ff 404 linked_item_t *it;
mbed_Cookbook_SE 0:de03cbbcd0ff 405 linked_item_t *next;
mbed_Cookbook_SE 0:de03cbbcd0ff 406 for (it = (linked_item_t *) l2cap_channels; it ; it = next){
mbed_Cookbook_SE 0:de03cbbcd0ff 407 next = it->next; // cache next item as current item might get freed
mbed_Cookbook_SE 0:de03cbbcd0ff 408
mbed_Cookbook_SE 0:de03cbbcd0ff 409 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break;
mbed_Cookbook_SE 0:de03cbbcd0ff 410 if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break;
mbed_Cookbook_SE 0:de03cbbcd0ff 411
mbed_Cookbook_SE 0:de03cbbcd0ff 412 l2cap_channel_t * channel = (l2cap_channel_t *) it;
mbed_Cookbook_SE 0:de03cbbcd0ff 413
mbed_Cookbook_SE 0:de03cbbcd0ff 414 // log_info("l2cap_run: state %u, var 0x%02x\n", channel->state, channel->state_var);
mbed_Cookbook_SE 0:de03cbbcd0ff 415
mbed_Cookbook_SE 0:de03cbbcd0ff 416
mbed_Cookbook_SE 0:de03cbbcd0ff 417 switch (channel->state){
mbed_Cookbook_SE 0:de03cbbcd0ff 418
mbed_Cookbook_SE 0:de03cbbcd0ff 419 case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
mbed_Cookbook_SE 0:de03cbbcd0ff 420 // send connection request - set state first
mbed_Cookbook_SE 0:de03cbbcd0ff 421 channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE;
mbed_Cookbook_SE 0:de03cbbcd0ff 422 // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
mbed_Cookbook_SE 0:de03cbbcd0ff 423 hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1);
mbed_Cookbook_SE 0:de03cbbcd0ff 424 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 425
mbed_Cookbook_SE 0:de03cbbcd0ff 426 case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE:
mbed_Cookbook_SE 0:de03cbbcd0ff 427 l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, channel->reason, 0);
mbed_Cookbook_SE 0:de03cbbcd0ff 428 // discard channel - l2cap_finialize_channel_close without sending l2cap close event
mbed_Cookbook_SE 0:de03cbbcd0ff 429 linked_list_remove(&l2cap_channels, (linked_item_t *) channel); // -- remove from list
mbed_Cookbook_SE 0:de03cbbcd0ff 430 btstack_memory_l2cap_channel_free(channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 431 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 432
mbed_Cookbook_SE 0:de03cbbcd0ff 433 case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT:
mbed_Cookbook_SE 0:de03cbbcd0ff 434 channel->state = L2CAP_STATE_CONFIG;
mbed_Cookbook_SE 0:de03cbbcd0ff 435 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
mbed_Cookbook_SE 0:de03cbbcd0ff 436 l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0);
mbed_Cookbook_SE 0:de03cbbcd0ff 437 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 438
mbed_Cookbook_SE 0:de03cbbcd0ff 439 case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST:
mbed_Cookbook_SE 0:de03cbbcd0ff 440 // success, start l2cap handshake
mbed_Cookbook_SE 0:de03cbbcd0ff 441 channel->local_sig_id = l2cap_next_sig_id();
mbed_Cookbook_SE 0:de03cbbcd0ff 442 channel->state = L2CAP_STATE_WAIT_CONNECT_RSP;
mbed_Cookbook_SE 0:de03cbbcd0ff 443 l2cap_send_signaling_packet( channel->handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 444 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 445
mbed_Cookbook_SE 0:de03cbbcd0ff 446 case L2CAP_STATE_CONFIG:
mbed_Cookbook_SE 0:de03cbbcd0ff 447 if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
mbed_Cookbook_SE 0:de03cbbcd0ff 448 channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
mbed_Cookbook_SE 0:de03cbbcd0ff 449 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
mbed_Cookbook_SE 0:de03cbbcd0ff 450 l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, 0, 0, 0, NULL);
mbed_Cookbook_SE 0:de03cbbcd0ff 451 }
mbed_Cookbook_SE 0:de03cbbcd0ff 452 else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){
mbed_Cookbook_SE 0:de03cbbcd0ff 453 channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
mbed_Cookbook_SE 0:de03cbbcd0ff 454 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ);
mbed_Cookbook_SE 0:de03cbbcd0ff 455 channel->local_sig_id = l2cap_next_sig_id();
mbed_Cookbook_SE 0:de03cbbcd0ff 456 config_options[0] = 1; // MTU
mbed_Cookbook_SE 0:de03cbbcd0ff 457 config_options[1] = 2; // len param
mbed_Cookbook_SE 0:de03cbbcd0ff 458 bt_store_16( (uint8_t*)&config_options, 2, channel->local_mtu);
mbed_Cookbook_SE 0:de03cbbcd0ff 459 l2cap_send_signaling_packet(channel->handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, 4, &config_options);
mbed_Cookbook_SE 0:de03cbbcd0ff 460 }
mbed_Cookbook_SE 0:de03cbbcd0ff 461 if (l2cap_channel_ready_for_open(channel)){
mbed_Cookbook_SE 0:de03cbbcd0ff 462 channel->state = L2CAP_STATE_OPEN;
mbed_Cookbook_SE 0:de03cbbcd0ff 463 l2cap_emit_channel_opened(channel, 0); // success
mbed_Cookbook_SE 0:de03cbbcd0ff 464 l2cap_emit_credits(channel, 1);
mbed_Cookbook_SE 0:de03cbbcd0ff 465 }
mbed_Cookbook_SE 0:de03cbbcd0ff 466 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 467
mbed_Cookbook_SE 0:de03cbbcd0ff 468 case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
mbed_Cookbook_SE 0:de03cbbcd0ff 469 l2cap_send_signaling_packet( channel->handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 470 l2cap_finialize_channel_close(channel); // -- remove from list
mbed_Cookbook_SE 0:de03cbbcd0ff 471 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 472
mbed_Cookbook_SE 0:de03cbbcd0ff 473 case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
mbed_Cookbook_SE 0:de03cbbcd0ff 474 channel->local_sig_id = l2cap_next_sig_id();
mbed_Cookbook_SE 0:de03cbbcd0ff 475 channel->state = L2CAP_STATE_WAIT_DISCONNECT;
mbed_Cookbook_SE 0:de03cbbcd0ff 476 l2cap_send_signaling_packet( channel->handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 477 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 478 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 479 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 480 }
mbed_Cookbook_SE 0:de03cbbcd0ff 481 }
mbed_Cookbook_SE 0:de03cbbcd0ff 482 }
mbed_Cookbook_SE 0:de03cbbcd0ff 483
mbed_Cookbook_SE 0:de03cbbcd0ff 484 uint16_t l2cap_max_mtu(void){
mbed_Cookbook_SE 0:de03cbbcd0ff 485 return hci_max_acl_data_packet_length() - L2CAP_HEADER_SIZE;
mbed_Cookbook_SE 0:de03cbbcd0ff 486 }
mbed_Cookbook_SE 0:de03cbbcd0ff 487
mbed_Cookbook_SE 0:de03cbbcd0ff 488 // open outgoing L2CAP channel
mbed_Cookbook_SE 0:de03cbbcd0ff 489 void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler,
mbed_Cookbook_SE 0:de03cbbcd0ff 490 bd_addr_t address, uint16_t psm, uint16_t mtu){
mbed_Cookbook_SE 0:de03cbbcd0ff 491
mbed_Cookbook_SE 0:de03cbbcd0ff 492 // alloc structure
mbed_Cookbook_SE 0:de03cbbcd0ff 493 l2cap_channel_t * chan = (l2cap_channel_t*) btstack_memory_l2cap_channel_get();
mbed_Cookbook_SE 0:de03cbbcd0ff 494 if (!chan) {
mbed_Cookbook_SE 0:de03cbbcd0ff 495 // emit error event
mbed_Cookbook_SE 0:de03cbbcd0ff 496 l2cap_channel_t dummy_channel;
mbed_Cookbook_SE 0:de03cbbcd0ff 497 BD_ADDR_COPY(dummy_channel.address, address);
mbed_Cookbook_SE 0:de03cbbcd0ff 498 dummy_channel.psm = psm;
mbed_Cookbook_SE 0:de03cbbcd0ff 499 l2cap_emit_channel_opened(&dummy_channel, BTSTACK_MEMORY_ALLOC_FAILED);
mbed_Cookbook_SE 0:de03cbbcd0ff 500 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 501 }
mbed_Cookbook_SE 0:de03cbbcd0ff 502 // limit local mtu to max acl packet length
mbed_Cookbook_SE 0:de03cbbcd0ff 503 if (mtu > l2cap_max_mtu()) {
mbed_Cookbook_SE 0:de03cbbcd0ff 504 mtu = l2cap_max_mtu();
mbed_Cookbook_SE 0:de03cbbcd0ff 505 }
mbed_Cookbook_SE 0:de03cbbcd0ff 506
mbed_Cookbook_SE 0:de03cbbcd0ff 507 // fill in
mbed_Cookbook_SE 0:de03cbbcd0ff 508 BD_ADDR_COPY(chan->address, address);
mbed_Cookbook_SE 0:de03cbbcd0ff 509 chan->psm = psm;
mbed_Cookbook_SE 0:de03cbbcd0ff 510 chan->handle = 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 511 chan->connection = connection;
mbed_Cookbook_SE 0:de03cbbcd0ff 512 chan->packet_handler = packet_handler;
mbed_Cookbook_SE 0:de03cbbcd0ff 513 chan->remote_mtu = L2CAP_MINIMAL_MTU;
mbed_Cookbook_SE 0:de03cbbcd0ff 514 chan->local_mtu = mtu;
mbed_Cookbook_SE 0:de03cbbcd0ff 515 chan->packets_granted = 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 516
mbed_Cookbook_SE 0:de03cbbcd0ff 517 // set initial state
mbed_Cookbook_SE 0:de03cbbcd0ff 518 chan->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION;
mbed_Cookbook_SE 0:de03cbbcd0ff 519 chan->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
mbed_Cookbook_SE 0:de03cbbcd0ff 520 chan->remote_sig_id = L2CAP_SIG_ID_INVALID;
mbed_Cookbook_SE 0:de03cbbcd0ff 521 chan->local_sig_id = L2CAP_SIG_ID_INVALID;
mbed_Cookbook_SE 0:de03cbbcd0ff 522
mbed_Cookbook_SE 0:de03cbbcd0ff 523 // add to connections list
mbed_Cookbook_SE 0:de03cbbcd0ff 524 linked_list_add(&l2cap_channels, (linked_item_t *) chan);
mbed_Cookbook_SE 0:de03cbbcd0ff 525
mbed_Cookbook_SE 0:de03cbbcd0ff 526 l2cap_run();
mbed_Cookbook_SE 0:de03cbbcd0ff 527 }
mbed_Cookbook_SE 0:de03cbbcd0ff 528
mbed_Cookbook_SE 0:de03cbbcd0ff 529 void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason){
mbed_Cookbook_SE 0:de03cbbcd0ff 530 // find channel for local_cid
mbed_Cookbook_SE 0:de03cbbcd0ff 531 l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 532 if (channel) {
mbed_Cookbook_SE 0:de03cbbcd0ff 533 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
mbed_Cookbook_SE 0:de03cbbcd0ff 534 }
mbed_Cookbook_SE 0:de03cbbcd0ff 535 // process
mbed_Cookbook_SE 0:de03cbbcd0ff 536 l2cap_run();
mbed_Cookbook_SE 0:de03cbbcd0ff 537 }
mbed_Cookbook_SE 0:de03cbbcd0ff 538
mbed_Cookbook_SE 0:de03cbbcd0ff 539 static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t status){
mbed_Cookbook_SE 0:de03cbbcd0ff 540 linked_item_t *it = (linked_item_t *) &l2cap_channels;
mbed_Cookbook_SE 0:de03cbbcd0ff 541 while (it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 542 l2cap_channel_t * channel = (l2cap_channel_t *) it->next;
mbed_Cookbook_SE 0:de03cbbcd0ff 543 if ( ! BD_ADDR_CMP( channel->address, address) ){
mbed_Cookbook_SE 0:de03cbbcd0ff 544 if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
mbed_Cookbook_SE 0:de03cbbcd0ff 545 // failure, forward error code
mbed_Cookbook_SE 0:de03cbbcd0ff 546 l2cap_emit_channel_opened(channel, status);
mbed_Cookbook_SE 0:de03cbbcd0ff 547 // discard channel
mbed_Cookbook_SE 0:de03cbbcd0ff 548 it->next = it->next->next;
mbed_Cookbook_SE 0:de03cbbcd0ff 549 btstack_memory_l2cap_channel_free(channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 550 }
mbed_Cookbook_SE 0:de03cbbcd0ff 551 } else {
mbed_Cookbook_SE 0:de03cbbcd0ff 552 it = it->next;
mbed_Cookbook_SE 0:de03cbbcd0ff 553 }
mbed_Cookbook_SE 0:de03cbbcd0ff 554 }
mbed_Cookbook_SE 0:de03cbbcd0ff 555 }
mbed_Cookbook_SE 0:de03cbbcd0ff 556
mbed_Cookbook_SE 0:de03cbbcd0ff 557 static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t handle){
mbed_Cookbook_SE 0:de03cbbcd0ff 558 linked_item_t *it;
mbed_Cookbook_SE 0:de03cbbcd0ff 559 for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 560 l2cap_channel_t * channel = (l2cap_channel_t *) it;
mbed_Cookbook_SE 0:de03cbbcd0ff 561 if ( ! BD_ADDR_CMP( channel->address, address) ){
mbed_Cookbook_SE 0:de03cbbcd0ff 562 if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
mbed_Cookbook_SE 0:de03cbbcd0ff 563 // success, start l2cap handshake
mbed_Cookbook_SE 0:de03cbbcd0ff 564 channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
mbed_Cookbook_SE 0:de03cbbcd0ff 565 channel->handle = handle;
mbed_Cookbook_SE 0:de03cbbcd0ff 566 channel->local_cid = l2cap_next_local_cid();
mbed_Cookbook_SE 0:de03cbbcd0ff 567 }
mbed_Cookbook_SE 0:de03cbbcd0ff 568 }
mbed_Cookbook_SE 0:de03cbbcd0ff 569 }
mbed_Cookbook_SE 0:de03cbbcd0ff 570 // process
mbed_Cookbook_SE 0:de03cbbcd0ff 571 l2cap_run();
mbed_Cookbook_SE 0:de03cbbcd0ff 572 }
mbed_Cookbook_SE 0:de03cbbcd0ff 573
mbed_Cookbook_SE 0:de03cbbcd0ff 574 void l2cap_event_handler( uint8_t *packet, uint16_t size ){
mbed_Cookbook_SE 0:de03cbbcd0ff 575
mbed_Cookbook_SE 0:de03cbbcd0ff 576 bd_addr_t address;
mbed_Cookbook_SE 0:de03cbbcd0ff 577 hci_con_handle_t handle;
mbed_Cookbook_SE 0:de03cbbcd0ff 578 l2cap_channel_t * channel;
mbed_Cookbook_SE 0:de03cbbcd0ff 579 linked_item_t *it;
mbed_Cookbook_SE 0:de03cbbcd0ff 580 int hci_con_used;
mbed_Cookbook_SE 0:de03cbbcd0ff 581
mbed_Cookbook_SE 0:de03cbbcd0ff 582 switch(packet[0]){
mbed_Cookbook_SE 0:de03cbbcd0ff 583
mbed_Cookbook_SE 0:de03cbbcd0ff 584 // handle connection complete events
mbed_Cookbook_SE 0:de03cbbcd0ff 585 case HCI_EVENT_CONNECTION_COMPLETE:
mbed_Cookbook_SE 0:de03cbbcd0ff 586 bt_flip_addr(address, &packet[5]);
mbed_Cookbook_SE 0:de03cbbcd0ff 587 if (packet[2] == 0){
mbed_Cookbook_SE 0:de03cbbcd0ff 588 handle = READ_BT_16(packet, 3);
mbed_Cookbook_SE 0:de03cbbcd0ff 589 l2cap_handle_connection_success_for_addr(address, handle);
mbed_Cookbook_SE 0:de03cbbcd0ff 590 } else {
mbed_Cookbook_SE 0:de03cbbcd0ff 591 l2cap_handle_connection_failed_for_addr(address, packet[2]);
mbed_Cookbook_SE 0:de03cbbcd0ff 592 }
mbed_Cookbook_SE 0:de03cbbcd0ff 593 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 594
mbed_Cookbook_SE 0:de03cbbcd0ff 595 // handle successful create connection cancel command
mbed_Cookbook_SE 0:de03cbbcd0ff 596 case HCI_EVENT_COMMAND_COMPLETE:
mbed_Cookbook_SE 0:de03cbbcd0ff 597 if ( COMMAND_COMPLETE_EVENT(packet, hci_create_connection_cancel) ) {
mbed_Cookbook_SE 0:de03cbbcd0ff 598 if (packet[5] == 0){
mbed_Cookbook_SE 0:de03cbbcd0ff 599 bt_flip_addr(address, &packet[6]);
mbed_Cookbook_SE 0:de03cbbcd0ff 600 // CONNECTION TERMINATED BY LOCAL HOST (0X16)
mbed_Cookbook_SE 0:de03cbbcd0ff 601 l2cap_handle_connection_failed_for_addr(address, 0x16);
mbed_Cookbook_SE 0:de03cbbcd0ff 602 }
mbed_Cookbook_SE 0:de03cbbcd0ff 603 }
mbed_Cookbook_SE 0:de03cbbcd0ff 604 l2cap_run(); // try sending signaling packets first
mbed_Cookbook_SE 0:de03cbbcd0ff 605 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 606
mbed_Cookbook_SE 0:de03cbbcd0ff 607 case HCI_EVENT_COMMAND_STATUS:
mbed_Cookbook_SE 0:de03cbbcd0ff 608 l2cap_run(); // try sending signaling packets first
mbed_Cookbook_SE 0:de03cbbcd0ff 609 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 610
mbed_Cookbook_SE 0:de03cbbcd0ff 611 // handle disconnection complete events
mbed_Cookbook_SE 0:de03cbbcd0ff 612 case HCI_EVENT_DISCONNECTION_COMPLETE:
mbed_Cookbook_SE 0:de03cbbcd0ff 613 // send l2cap disconnect events for all channels on this handle
mbed_Cookbook_SE 0:de03cbbcd0ff 614 handle = READ_BT_16(packet, 3);
mbed_Cookbook_SE 0:de03cbbcd0ff 615 it = (linked_item_t *) &l2cap_channels;
mbed_Cookbook_SE 0:de03cbbcd0ff 616 while (it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 617 l2cap_channel_t * channel = (l2cap_channel_t *) it->next;
mbed_Cookbook_SE 0:de03cbbcd0ff 618 if ( channel->handle == handle ){
mbed_Cookbook_SE 0:de03cbbcd0ff 619 // update prev item before free'ing next element - don't call l2cap_finalize_channel_close
mbed_Cookbook_SE 0:de03cbbcd0ff 620 it->next = it->next->next;
mbed_Cookbook_SE 0:de03cbbcd0ff 621 l2cap_emit_channel_closed(channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 622 btstack_memory_l2cap_channel_free(channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 623 } else {
mbed_Cookbook_SE 0:de03cbbcd0ff 624 it = it->next;
mbed_Cookbook_SE 0:de03cbbcd0ff 625 }
mbed_Cookbook_SE 0:de03cbbcd0ff 626 }
mbed_Cookbook_SE 0:de03cbbcd0ff 627 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 628
mbed_Cookbook_SE 0:de03cbbcd0ff 629 case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
mbed_Cookbook_SE 0:de03cbbcd0ff 630 l2cap_run(); // try sending signaling packets first
mbed_Cookbook_SE 0:de03cbbcd0ff 631 l2cap_hand_out_credits();
mbed_Cookbook_SE 0:de03cbbcd0ff 632 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 633
mbed_Cookbook_SE 0:de03cbbcd0ff 634 // HCI Connection Timeouts
mbed_Cookbook_SE 0:de03cbbcd0ff 635 case L2CAP_EVENT_TIMEOUT_CHECK:
mbed_Cookbook_SE 0:de03cbbcd0ff 636 handle = READ_BT_16(packet, 2);
mbed_Cookbook_SE 0:de03cbbcd0ff 637 if (hci_authentication_active_for_handle(handle)) break;
mbed_Cookbook_SE 0:de03cbbcd0ff 638 hci_con_used = 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 639 for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 640 channel = (l2cap_channel_t *) it;
mbed_Cookbook_SE 0:de03cbbcd0ff 641 if (channel->handle == handle) {
mbed_Cookbook_SE 0:de03cbbcd0ff 642 hci_con_used = 1;
mbed_Cookbook_SE 0:de03cbbcd0ff 643 }
mbed_Cookbook_SE 0:de03cbbcd0ff 644 }
mbed_Cookbook_SE 0:de03cbbcd0ff 645 if (hci_con_used) break;
mbed_Cookbook_SE 0:de03cbbcd0ff 646 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break;
mbed_Cookbook_SE 0:de03cbbcd0ff 647 hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection
mbed_Cookbook_SE 0:de03cbbcd0ff 648 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 649
mbed_Cookbook_SE 0:de03cbbcd0ff 650 case DAEMON_EVENT_HCI_PACKET_SENT:
mbed_Cookbook_SE 0:de03cbbcd0ff 651 for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 652 channel = (l2cap_channel_t *) it;
mbed_Cookbook_SE 0:de03cbbcd0ff 653 if (channel->packet_handler) {
mbed_Cookbook_SE 0:de03cbbcd0ff 654 (* (channel->packet_handler))(HCI_EVENT_PACKET, channel->local_cid, packet, size);
mbed_Cookbook_SE 0:de03cbbcd0ff 655 }
mbed_Cookbook_SE 0:de03cbbcd0ff 656 }
mbed_Cookbook_SE 0:de03cbbcd0ff 657 if (attribute_protocol_packet_handler) {
mbed_Cookbook_SE 0:de03cbbcd0ff 658 (*attribute_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size);
mbed_Cookbook_SE 0:de03cbbcd0ff 659 }
mbed_Cookbook_SE 0:de03cbbcd0ff 660 if (security_protocol_packet_handler) {
mbed_Cookbook_SE 0:de03cbbcd0ff 661 (*security_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size);
mbed_Cookbook_SE 0:de03cbbcd0ff 662 }
mbed_Cookbook_SE 0:de03cbbcd0ff 663 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 664
mbed_Cookbook_SE 0:de03cbbcd0ff 665 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 666 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 667 }
mbed_Cookbook_SE 0:de03cbbcd0ff 668
mbed_Cookbook_SE 0:de03cbbcd0ff 669 // pass on
mbed_Cookbook_SE 0:de03cbbcd0ff 670 (*packet_handler)(NULL, HCI_EVENT_PACKET, 0, packet, size);
mbed_Cookbook_SE 0:de03cbbcd0ff 671 }
mbed_Cookbook_SE 0:de03cbbcd0ff 672
mbed_Cookbook_SE 0:de03cbbcd0ff 673 static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){
mbed_Cookbook_SE 0:de03cbbcd0ff 674 channel->remote_sig_id = identifier;
mbed_Cookbook_SE 0:de03cbbcd0ff 675 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
mbed_Cookbook_SE 0:de03cbbcd0ff 676 l2cap_run();
mbed_Cookbook_SE 0:de03cbbcd0ff 677 }
mbed_Cookbook_SE 0:de03cbbcd0ff 678
mbed_Cookbook_SE 0:de03cbbcd0ff 679 static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){
mbed_Cookbook_SE 0:de03cbbcd0ff 680 // Vol 3, Part A, 4.3: "The DCID and SCID fields shall be ignored when the result field indi- cates the connection was refused."
mbed_Cookbook_SE 0:de03cbbcd0ff 681 if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) {
mbed_Cookbook_SE 0:de03cbbcd0ff 682 signaling_responses[signaling_responses_pending].handle = handle;
mbed_Cookbook_SE 0:de03cbbcd0ff 683 signaling_responses[signaling_responses_pending].code = code;
mbed_Cookbook_SE 0:de03cbbcd0ff 684 signaling_responses[signaling_responses_pending].sig_id = sig_id;
mbed_Cookbook_SE 0:de03cbbcd0ff 685 signaling_responses[signaling_responses_pending].data = data;
mbed_Cookbook_SE 0:de03cbbcd0ff 686 signaling_responses_pending++;
mbed_Cookbook_SE 0:de03cbbcd0ff 687 l2cap_run();
mbed_Cookbook_SE 0:de03cbbcd0ff 688 }
mbed_Cookbook_SE 0:de03cbbcd0ff 689 }
mbed_Cookbook_SE 0:de03cbbcd0ff 690
mbed_Cookbook_SE 0:de03cbbcd0ff 691 static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){
mbed_Cookbook_SE 0:de03cbbcd0ff 692
mbed_Cookbook_SE 0:de03cbbcd0ff 693 // log_info("l2cap_handle_connection_request for handle %u, psm %u cid %u\n", handle, psm, source_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 694 l2cap_service_t *service = l2cap_get_service(psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 695 if (!service) {
mbed_Cookbook_SE 0:de03cbbcd0ff 696 // 0x0002 PSM not supported
mbed_Cookbook_SE 0:de03cbbcd0ff 697 l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0002);
mbed_Cookbook_SE 0:de03cbbcd0ff 698 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 699 }
mbed_Cookbook_SE 0:de03cbbcd0ff 700
mbed_Cookbook_SE 0:de03cbbcd0ff 701 hci_connection_t * hci_connection = connection_for_handle( handle );
mbed_Cookbook_SE 0:de03cbbcd0ff 702 if (!hci_connection) {
mbed_Cookbook_SE 0:de03cbbcd0ff 703 //
mbed_Cookbook_SE 0:de03cbbcd0ff 704 log_error("no hci_connection for handle %u\n", handle);
mbed_Cookbook_SE 0:de03cbbcd0ff 705 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 706 }
mbed_Cookbook_SE 0:de03cbbcd0ff 707 // alloc structure
mbed_Cookbook_SE 0:de03cbbcd0ff 708 // log_info("l2cap_handle_connection_request register channel\n");
mbed_Cookbook_SE 0:de03cbbcd0ff 709 l2cap_channel_t * channel = (l2cap_channel_t*) btstack_memory_l2cap_channel_get();
mbed_Cookbook_SE 0:de03cbbcd0ff 710 if (!channel){
mbed_Cookbook_SE 0:de03cbbcd0ff 711 // 0x0004 No resources available
mbed_Cookbook_SE 0:de03cbbcd0ff 712 l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0004);
mbed_Cookbook_SE 0:de03cbbcd0ff 713 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 714 }
mbed_Cookbook_SE 0:de03cbbcd0ff 715
mbed_Cookbook_SE 0:de03cbbcd0ff 716 // fill in
mbed_Cookbook_SE 0:de03cbbcd0ff 717 BD_ADDR_COPY(channel->address, hci_connection->address);
mbed_Cookbook_SE 0:de03cbbcd0ff 718 channel->psm = psm;
mbed_Cookbook_SE 0:de03cbbcd0ff 719 channel->handle = handle;
mbed_Cookbook_SE 0:de03cbbcd0ff 720 channel->connection = service->connection;
mbed_Cookbook_SE 0:de03cbbcd0ff 721 channel->packet_handler = service->packet_handler;
mbed_Cookbook_SE 0:de03cbbcd0ff 722 channel->local_cid = l2cap_next_local_cid();
mbed_Cookbook_SE 0:de03cbbcd0ff 723 channel->remote_cid = source_cid;
mbed_Cookbook_SE 0:de03cbbcd0ff 724 channel->local_mtu = service->mtu;
mbed_Cookbook_SE 0:de03cbbcd0ff 725 channel->remote_mtu = L2CAP_DEFAULT_MTU;
mbed_Cookbook_SE 0:de03cbbcd0ff 726 channel->packets_granted = 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 727 channel->remote_sig_id = sig_id;
mbed_Cookbook_SE 0:de03cbbcd0ff 728
mbed_Cookbook_SE 0:de03cbbcd0ff 729 // limit local mtu to max acl packet length
mbed_Cookbook_SE 0:de03cbbcd0ff 730 if (channel->local_mtu > l2cap_max_mtu()) {
mbed_Cookbook_SE 0:de03cbbcd0ff 731 channel->local_mtu = l2cap_max_mtu();
mbed_Cookbook_SE 0:de03cbbcd0ff 732 }
mbed_Cookbook_SE 0:de03cbbcd0ff 733
mbed_Cookbook_SE 0:de03cbbcd0ff 734 // set initial state
mbed_Cookbook_SE 0:de03cbbcd0ff 735 channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
mbed_Cookbook_SE 0:de03cbbcd0ff 736 channel->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
mbed_Cookbook_SE 0:de03cbbcd0ff 737
mbed_Cookbook_SE 0:de03cbbcd0ff 738 // add to connections list
mbed_Cookbook_SE 0:de03cbbcd0ff 739 linked_list_add(&l2cap_channels, (linked_item_t *) channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 740
mbed_Cookbook_SE 0:de03cbbcd0ff 741 // emit incoming connection request
mbed_Cookbook_SE 0:de03cbbcd0ff 742 l2cap_emit_connection_request(channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 743 }
mbed_Cookbook_SE 0:de03cbbcd0ff 744
mbed_Cookbook_SE 0:de03cbbcd0ff 745 void l2cap_accept_connection_internal(uint16_t local_cid){
mbed_Cookbook_SE 0:de03cbbcd0ff 746 l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 747 if (!channel) {
mbed_Cookbook_SE 0:de03cbbcd0ff 748 log_error("l2cap_accept_connection_internal called but local_cid 0x%x not found", local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 749 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 750 }
mbed_Cookbook_SE 0:de03cbbcd0ff 751
mbed_Cookbook_SE 0:de03cbbcd0ff 752 channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
mbed_Cookbook_SE 0:de03cbbcd0ff 753
mbed_Cookbook_SE 0:de03cbbcd0ff 754 // process
mbed_Cookbook_SE 0:de03cbbcd0ff 755 l2cap_run();
mbed_Cookbook_SE 0:de03cbbcd0ff 756 }
mbed_Cookbook_SE 0:de03cbbcd0ff 757
mbed_Cookbook_SE 0:de03cbbcd0ff 758 void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason){
mbed_Cookbook_SE 0:de03cbbcd0ff 759 l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 760 if (!channel) {
mbed_Cookbook_SE 0:de03cbbcd0ff 761 log_error( "l2cap_decline_connection_internal called but local_cid 0x%x not found", local_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 762 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 763 }
mbed_Cookbook_SE 0:de03cbbcd0ff 764 channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
mbed_Cookbook_SE 0:de03cbbcd0ff 765 channel->reason = reason;
mbed_Cookbook_SE 0:de03cbbcd0ff 766 l2cap_run();
mbed_Cookbook_SE 0:de03cbbcd0ff 767 }
mbed_Cookbook_SE 0:de03cbbcd0ff 768
mbed_Cookbook_SE 0:de03cbbcd0ff 769 void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t *command){
mbed_Cookbook_SE 0:de03cbbcd0ff 770
mbed_Cookbook_SE 0:de03cbbcd0ff 771 channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
mbed_Cookbook_SE 0:de03cbbcd0ff 772
mbed_Cookbook_SE 0:de03cbbcd0ff 773 // accept the other's configuration options
mbed_Cookbook_SE 0:de03cbbcd0ff 774 uint16_t end_pos = 4 + READ_BT_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
mbed_Cookbook_SE 0:de03cbbcd0ff 775 uint16_t pos = 8;
mbed_Cookbook_SE 0:de03cbbcd0ff 776 while (pos < end_pos){
mbed_Cookbook_SE 0:de03cbbcd0ff 777 uint8_t type = command[pos++];
mbed_Cookbook_SE 0:de03cbbcd0ff 778 uint8_t length = command[pos++];
mbed_Cookbook_SE 0:de03cbbcd0ff 779 // MTU { type(8): 1, len(8):2, MTU(16) }
mbed_Cookbook_SE 0:de03cbbcd0ff 780 if ((type & 0x7f) == 1 && length == 2){
mbed_Cookbook_SE 0:de03cbbcd0ff 781 channel->remote_mtu = READ_BT_16(command, pos);
mbed_Cookbook_SE 0:de03cbbcd0ff 782 // log_info("l2cap cid %u, remote mtu %u\n", channel->local_cid, channel->remote_mtu);
mbed_Cookbook_SE 0:de03cbbcd0ff 783 }
mbed_Cookbook_SE 0:de03cbbcd0ff 784 pos += length;
mbed_Cookbook_SE 0:de03cbbcd0ff 785 }
mbed_Cookbook_SE 0:de03cbbcd0ff 786 }
mbed_Cookbook_SE 0:de03cbbcd0ff 787
mbed_Cookbook_SE 0:de03cbbcd0ff 788 static int l2cap_channel_ready_for_open(l2cap_channel_t *channel){
mbed_Cookbook_SE 0:de03cbbcd0ff 789 // log_info("l2cap_channel_ready_for_open 0x%02x\n", channel->state_var);
mbed_Cookbook_SE 0:de03cbbcd0ff 790 if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP) == 0) return 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 791 if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP) == 0) return 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 792 return 1;
mbed_Cookbook_SE 0:de03cbbcd0ff 793 }
mbed_Cookbook_SE 0:de03cbbcd0ff 794
mbed_Cookbook_SE 0:de03cbbcd0ff 795
mbed_Cookbook_SE 0:de03cbbcd0ff 796 void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){
mbed_Cookbook_SE 0:de03cbbcd0ff 797
mbed_Cookbook_SE 0:de03cbbcd0ff 798 uint8_t code = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
mbed_Cookbook_SE 0:de03cbbcd0ff 799 uint8_t identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
mbed_Cookbook_SE 0:de03cbbcd0ff 800 uint16_t result = 0;
mbed_Cookbook_SE 0:de03cbbcd0ff 801
mbed_Cookbook_SE 0:de03cbbcd0ff 802 log_info("L2CAP signaling handler code %u, state %u\n", code, channel->state);
mbed_Cookbook_SE 0:de03cbbcd0ff 803
mbed_Cookbook_SE 0:de03cbbcd0ff 804 // handle DISCONNECT REQUESTS seperately
mbed_Cookbook_SE 0:de03cbbcd0ff 805 if (code == DISCONNECTION_REQUEST){
mbed_Cookbook_SE 0:de03cbbcd0ff 806 switch (channel->state){
mbed_Cookbook_SE 0:de03cbbcd0ff 807 case L2CAP_STATE_CONFIG:
mbed_Cookbook_SE 0:de03cbbcd0ff 808 case L2CAP_STATE_OPEN:
mbed_Cookbook_SE 0:de03cbbcd0ff 809 case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
mbed_Cookbook_SE 0:de03cbbcd0ff 810 case L2CAP_STATE_WAIT_DISCONNECT:
mbed_Cookbook_SE 0:de03cbbcd0ff 811 l2cap_handle_disconnect_request(channel, identifier);
mbed_Cookbook_SE 0:de03cbbcd0ff 812 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 813
mbed_Cookbook_SE 0:de03cbbcd0ff 814 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 815 // ignore in other states
mbed_Cookbook_SE 0:de03cbbcd0ff 816 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 817 }
mbed_Cookbook_SE 0:de03cbbcd0ff 818 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 819 }
mbed_Cookbook_SE 0:de03cbbcd0ff 820
mbed_Cookbook_SE 0:de03cbbcd0ff 821 // @STATEMACHINE(l2cap)
mbed_Cookbook_SE 0:de03cbbcd0ff 822 switch (channel->state) {
mbed_Cookbook_SE 0:de03cbbcd0ff 823
mbed_Cookbook_SE 0:de03cbbcd0ff 824 case L2CAP_STATE_WAIT_CONNECT_RSP:
mbed_Cookbook_SE 0:de03cbbcd0ff 825 switch (code){
mbed_Cookbook_SE 0:de03cbbcd0ff 826 case CONNECTION_RESPONSE:
mbed_Cookbook_SE 0:de03cbbcd0ff 827 result = READ_BT_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
mbed_Cookbook_SE 0:de03cbbcd0ff 828 switch (result) {
mbed_Cookbook_SE 0:de03cbbcd0ff 829 case 0:
mbed_Cookbook_SE 0:de03cbbcd0ff 830 // successful connection
mbed_Cookbook_SE 0:de03cbbcd0ff 831 channel->remote_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
mbed_Cookbook_SE 0:de03cbbcd0ff 832 channel->state = L2CAP_STATE_CONFIG;
mbed_Cookbook_SE 0:de03cbbcd0ff 833 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
mbed_Cookbook_SE 0:de03cbbcd0ff 834 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 835 case 1:
mbed_Cookbook_SE 0:de03cbbcd0ff 836 // connection pending. get some coffee
mbed_Cookbook_SE 0:de03cbbcd0ff 837 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 838 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 839 // channel closed
mbed_Cookbook_SE 0:de03cbbcd0ff 840 channel->state = L2CAP_STATE_CLOSED;
mbed_Cookbook_SE 0:de03cbbcd0ff 841
mbed_Cookbook_SE 0:de03cbbcd0ff 842 // map l2cap connection response result to BTstack status enumeration
mbed_Cookbook_SE 0:de03cbbcd0ff 843 l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result);
mbed_Cookbook_SE 0:de03cbbcd0ff 844
mbed_Cookbook_SE 0:de03cbbcd0ff 845 // drop link key if security block
mbed_Cookbook_SE 0:de03cbbcd0ff 846 if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){
mbed_Cookbook_SE 0:de03cbbcd0ff 847 hci_drop_link_key_for_bd_addr(&channel->address);
mbed_Cookbook_SE 0:de03cbbcd0ff 848 }
mbed_Cookbook_SE 0:de03cbbcd0ff 849
mbed_Cookbook_SE 0:de03cbbcd0ff 850 // discard channel
mbed_Cookbook_SE 0:de03cbbcd0ff 851 linked_list_remove(&l2cap_channels, (linked_item_t *) channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 852 btstack_memory_l2cap_channel_free(channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 853 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 854 }
mbed_Cookbook_SE 0:de03cbbcd0ff 855 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 856
mbed_Cookbook_SE 0:de03cbbcd0ff 857 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 858 //@TODO: implement other signaling packets
mbed_Cookbook_SE 0:de03cbbcd0ff 859 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 860 }
mbed_Cookbook_SE 0:de03cbbcd0ff 861 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 862
mbed_Cookbook_SE 0:de03cbbcd0ff 863 case L2CAP_STATE_CONFIG:
mbed_Cookbook_SE 0:de03cbbcd0ff 864 switch (code) {
mbed_Cookbook_SE 0:de03cbbcd0ff 865 case CONFIGURE_REQUEST:
mbed_Cookbook_SE 0:de03cbbcd0ff 866 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
mbed_Cookbook_SE 0:de03cbbcd0ff 867 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
mbed_Cookbook_SE 0:de03cbbcd0ff 868 l2cap_signaling_handle_configure_request(channel, command);
mbed_Cookbook_SE 0:de03cbbcd0ff 869 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 870 case CONFIGURE_RESPONSE:
mbed_Cookbook_SE 0:de03cbbcd0ff 871 channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
mbed_Cookbook_SE 0:de03cbbcd0ff 872 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 873 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 874 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 875 }
mbed_Cookbook_SE 0:de03cbbcd0ff 876 if (l2cap_channel_ready_for_open(channel)){
mbed_Cookbook_SE 0:de03cbbcd0ff 877 // for open:
mbed_Cookbook_SE 0:de03cbbcd0ff 878 channel->state = L2CAP_STATE_OPEN;
mbed_Cookbook_SE 0:de03cbbcd0ff 879 l2cap_emit_channel_opened(channel, 0);
mbed_Cookbook_SE 0:de03cbbcd0ff 880 l2cap_emit_credits(channel, 1);
mbed_Cookbook_SE 0:de03cbbcd0ff 881 }
mbed_Cookbook_SE 0:de03cbbcd0ff 882 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 883
mbed_Cookbook_SE 0:de03cbbcd0ff 884 case L2CAP_STATE_WAIT_DISCONNECT:
mbed_Cookbook_SE 0:de03cbbcd0ff 885 switch (code) {
mbed_Cookbook_SE 0:de03cbbcd0ff 886 case DISCONNECTION_RESPONSE:
mbed_Cookbook_SE 0:de03cbbcd0ff 887 l2cap_finialize_channel_close(channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 888 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 889 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 890 //@TODO: implement other signaling packets
mbed_Cookbook_SE 0:de03cbbcd0ff 891 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 892 }
mbed_Cookbook_SE 0:de03cbbcd0ff 893 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 894
mbed_Cookbook_SE 0:de03cbbcd0ff 895 case L2CAP_STATE_CLOSED:
mbed_Cookbook_SE 0:de03cbbcd0ff 896 // @TODO handle incoming requests
mbed_Cookbook_SE 0:de03cbbcd0ff 897 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 898
mbed_Cookbook_SE 0:de03cbbcd0ff 899 case L2CAP_STATE_OPEN:
mbed_Cookbook_SE 0:de03cbbcd0ff 900 //@TODO: implement other signaling packets, e.g. re-configure
mbed_Cookbook_SE 0:de03cbbcd0ff 901 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 902 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 903 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 904 }
mbed_Cookbook_SE 0:de03cbbcd0ff 905 // log_info("new state %u\n", channel->state);
mbed_Cookbook_SE 0:de03cbbcd0ff 906 }
mbed_Cookbook_SE 0:de03cbbcd0ff 907
mbed_Cookbook_SE 0:de03cbbcd0ff 908
mbed_Cookbook_SE 0:de03cbbcd0ff 909 void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * command){
mbed_Cookbook_SE 0:de03cbbcd0ff 910
mbed_Cookbook_SE 0:de03cbbcd0ff 911 // get code, signalind identifier and command len
mbed_Cookbook_SE 0:de03cbbcd0ff 912 uint8_t code = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
mbed_Cookbook_SE 0:de03cbbcd0ff 913 uint8_t sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
mbed_Cookbook_SE 0:de03cbbcd0ff 914
mbed_Cookbook_SE 0:de03cbbcd0ff 915 // not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_REQUEST
mbed_Cookbook_SE 0:de03cbbcd0ff 916 if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_REQUEST){
mbed_Cookbook_SE 0:de03cbbcd0ff 917 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 918 }
mbed_Cookbook_SE 0:de03cbbcd0ff 919
mbed_Cookbook_SE 0:de03cbbcd0ff 920 // general commands without an assigned channel
mbed_Cookbook_SE 0:de03cbbcd0ff 921 switch(code) {
mbed_Cookbook_SE 0:de03cbbcd0ff 922
mbed_Cookbook_SE 0:de03cbbcd0ff 923 case CONNECTION_REQUEST: {
mbed_Cookbook_SE 0:de03cbbcd0ff 924 uint16_t psm = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
mbed_Cookbook_SE 0:de03cbbcd0ff 925 uint16_t source_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
mbed_Cookbook_SE 0:de03cbbcd0ff 926 l2cap_handle_connection_request(handle, sig_id, psm, source_cid);
mbed_Cookbook_SE 0:de03cbbcd0ff 927 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 928 }
mbed_Cookbook_SE 0:de03cbbcd0ff 929
mbed_Cookbook_SE 0:de03cbbcd0ff 930 case ECHO_REQUEST:
mbed_Cookbook_SE 0:de03cbbcd0ff 931 l2cap_register_signaling_response(handle, code, sig_id, 0);
mbed_Cookbook_SE 0:de03cbbcd0ff 932 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 933
mbed_Cookbook_SE 0:de03cbbcd0ff 934 case INFORMATION_REQUEST: {
mbed_Cookbook_SE 0:de03cbbcd0ff 935 uint16_t infoType = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
mbed_Cookbook_SE 0:de03cbbcd0ff 936 l2cap_register_signaling_response(handle, code, sig_id, infoType);
mbed_Cookbook_SE 0:de03cbbcd0ff 937 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 938 }
mbed_Cookbook_SE 0:de03cbbcd0ff 939
mbed_Cookbook_SE 0:de03cbbcd0ff 940 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 941 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 942 }
mbed_Cookbook_SE 0:de03cbbcd0ff 943
mbed_Cookbook_SE 0:de03cbbcd0ff 944
mbed_Cookbook_SE 0:de03cbbcd0ff 945 // Get potential destination CID
mbed_Cookbook_SE 0:de03cbbcd0ff 946 uint16_t dest_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
mbed_Cookbook_SE 0:de03cbbcd0ff 947
mbed_Cookbook_SE 0:de03cbbcd0ff 948 // Find channel for this sig_id and connection handle
mbed_Cookbook_SE 0:de03cbbcd0ff 949 linked_item_t *it;
mbed_Cookbook_SE 0:de03cbbcd0ff 950 for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 951 l2cap_channel_t * channel = (l2cap_channel_t *) it;
mbed_Cookbook_SE 0:de03cbbcd0ff 952 if (channel->handle == handle) {
mbed_Cookbook_SE 0:de03cbbcd0ff 953 if (code & 1) {
mbed_Cookbook_SE 0:de03cbbcd0ff 954 // match odd commands (responses) by previous signaling identifier
mbed_Cookbook_SE 0:de03cbbcd0ff 955 if (channel->local_sig_id == sig_id) {
mbed_Cookbook_SE 0:de03cbbcd0ff 956 l2cap_signaling_handler_channel(channel, command);
mbed_Cookbook_SE 0:de03cbbcd0ff 957 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 958 }
mbed_Cookbook_SE 0:de03cbbcd0ff 959 } else {
mbed_Cookbook_SE 0:de03cbbcd0ff 960 // match even commands (requests) by local channel id
mbed_Cookbook_SE 0:de03cbbcd0ff 961 if (channel->local_cid == dest_cid) {
mbed_Cookbook_SE 0:de03cbbcd0ff 962 l2cap_signaling_handler_channel(channel, command);
mbed_Cookbook_SE 0:de03cbbcd0ff 963 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 964 }
mbed_Cookbook_SE 0:de03cbbcd0ff 965 }
mbed_Cookbook_SE 0:de03cbbcd0ff 966 }
mbed_Cookbook_SE 0:de03cbbcd0ff 967 }
mbed_Cookbook_SE 0:de03cbbcd0ff 968 }
mbed_Cookbook_SE 0:de03cbbcd0ff 969
mbed_Cookbook_SE 0:de03cbbcd0ff 970 void l2cap_acl_handler( uint8_t *packet, uint16_t size ){
mbed_Cookbook_SE 0:de03cbbcd0ff 971
mbed_Cookbook_SE 0:de03cbbcd0ff 972 // Get Channel ID
mbed_Cookbook_SE 0:de03cbbcd0ff 973 uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
mbed_Cookbook_SE 0:de03cbbcd0ff 974 hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet);
mbed_Cookbook_SE 0:de03cbbcd0ff 975
mbed_Cookbook_SE 0:de03cbbcd0ff 976 switch (channel_id) {
mbed_Cookbook_SE 0:de03cbbcd0ff 977
mbed_Cookbook_SE 0:de03cbbcd0ff 978 case L2CAP_CID_SIGNALING: {
mbed_Cookbook_SE 0:de03cbbcd0ff 979
mbed_Cookbook_SE 0:de03cbbcd0ff 980 uint16_t command_offset = 8;
mbed_Cookbook_SE 0:de03cbbcd0ff 981 while (command_offset < size) {
mbed_Cookbook_SE 0:de03cbbcd0ff 982
mbed_Cookbook_SE 0:de03cbbcd0ff 983 // handle signaling commands
mbed_Cookbook_SE 0:de03cbbcd0ff 984 l2cap_signaling_handler_dispatch(handle, &packet[command_offset]);
mbed_Cookbook_SE 0:de03cbbcd0ff 985
mbed_Cookbook_SE 0:de03cbbcd0ff 986 // increment command_offset
mbed_Cookbook_SE 0:de03cbbcd0ff 987 command_offset += L2CAP_SIGNALING_COMMAND_DATA_OFFSET + READ_BT_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
mbed_Cookbook_SE 0:de03cbbcd0ff 988 }
mbed_Cookbook_SE 0:de03cbbcd0ff 989 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 990 }
mbed_Cookbook_SE 0:de03cbbcd0ff 991
mbed_Cookbook_SE 0:de03cbbcd0ff 992 case L2CAP_CID_ATTRIBUTE_PROTOCOL:
mbed_Cookbook_SE 0:de03cbbcd0ff 993 if (attribute_protocol_packet_handler) {
mbed_Cookbook_SE 0:de03cbbcd0ff 994 (*attribute_protocol_packet_handler)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
mbed_Cookbook_SE 0:de03cbbcd0ff 995 }
mbed_Cookbook_SE 0:de03cbbcd0ff 996 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 997
mbed_Cookbook_SE 0:de03cbbcd0ff 998 case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
mbed_Cookbook_SE 0:de03cbbcd0ff 999 if (security_protocol_packet_handler) {
mbed_Cookbook_SE 0:de03cbbcd0ff 1000 (*security_protocol_packet_handler)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
mbed_Cookbook_SE 0:de03cbbcd0ff 1001 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1002 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 1003
mbed_Cookbook_SE 0:de03cbbcd0ff 1004 default: {
mbed_Cookbook_SE 0:de03cbbcd0ff 1005 // Find channel for this channel_id and connection handle
mbed_Cookbook_SE 0:de03cbbcd0ff 1006 l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(channel_id);
mbed_Cookbook_SE 0:de03cbbcd0ff 1007 if (channel) {
mbed_Cookbook_SE 0:de03cbbcd0ff 1008 l2cap_dispatch(channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
mbed_Cookbook_SE 0:de03cbbcd0ff 1009 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1010 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 1011 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1012 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1013
mbed_Cookbook_SE 0:de03cbbcd0ff 1014 l2cap_run();
mbed_Cookbook_SE 0:de03cbbcd0ff 1015 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1016
mbed_Cookbook_SE 0:de03cbbcd0ff 1017 static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
mbed_Cookbook_SE 0:de03cbbcd0ff 1018 switch (packet_type) {
mbed_Cookbook_SE 0:de03cbbcd0ff 1019 case HCI_EVENT_PACKET:
mbed_Cookbook_SE 0:de03cbbcd0ff 1020 l2cap_event_handler(packet, size);
mbed_Cookbook_SE 0:de03cbbcd0ff 1021 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 1022 case HCI_ACL_DATA_PACKET:
mbed_Cookbook_SE 0:de03cbbcd0ff 1023 l2cap_acl_handler(packet, size);
mbed_Cookbook_SE 0:de03cbbcd0ff 1024 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 1025 default:
mbed_Cookbook_SE 0:de03cbbcd0ff 1026 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 1027 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1028 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1029
mbed_Cookbook_SE 0:de03cbbcd0ff 1030 // finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
mbed_Cookbook_SE 0:de03cbbcd0ff 1031 void l2cap_finialize_channel_close(l2cap_channel_t *channel){
mbed_Cookbook_SE 0:de03cbbcd0ff 1032 channel->state = L2CAP_STATE_CLOSED;
mbed_Cookbook_SE 0:de03cbbcd0ff 1033 l2cap_emit_channel_closed(channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 1034 // discard channel
mbed_Cookbook_SE 0:de03cbbcd0ff 1035 linked_list_remove(&l2cap_channels, (linked_item_t *) channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 1036 btstack_memory_l2cap_channel_free(channel);
mbed_Cookbook_SE 0:de03cbbcd0ff 1037 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1038
mbed_Cookbook_SE 0:de03cbbcd0ff 1039 l2cap_service_t * l2cap_get_service(uint16_t psm){
mbed_Cookbook_SE 0:de03cbbcd0ff 1040 linked_item_t *it;
mbed_Cookbook_SE 0:de03cbbcd0ff 1041
mbed_Cookbook_SE 0:de03cbbcd0ff 1042 // close open channels
mbed_Cookbook_SE 0:de03cbbcd0ff 1043 for (it = (linked_item_t *) l2cap_services; it ; it = it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 1044 l2cap_service_t * service = ((l2cap_service_t *) it);
mbed_Cookbook_SE 0:de03cbbcd0ff 1045 if ( service->psm == psm){
mbed_Cookbook_SE 0:de03cbbcd0ff 1046 return service;
mbed_Cookbook_SE 0:de03cbbcd0ff 1047 };
mbed_Cookbook_SE 0:de03cbbcd0ff 1048 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1049 return NULL;
mbed_Cookbook_SE 0:de03cbbcd0ff 1050 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1051
mbed_Cookbook_SE 0:de03cbbcd0ff 1052 void l2cap_register_service_internal(void *connection, btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t mtu){
mbed_Cookbook_SE 0:de03cbbcd0ff 1053 // check for alread registered psm
mbed_Cookbook_SE 0:de03cbbcd0ff 1054 // TODO: emit error event
mbed_Cookbook_SE 0:de03cbbcd0ff 1055 l2cap_service_t *service = l2cap_get_service(psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 1056 if (service) {
mbed_Cookbook_SE 0:de03cbbcd0ff 1057 log_error("l2cap_register_service_internal: PSM %u already registered\n", psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 1058 l2cap_emit_service_registered(connection, L2CAP_SERVICE_ALREADY_REGISTERED, psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 1059 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 1060 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1061
mbed_Cookbook_SE 0:de03cbbcd0ff 1062 // alloc structure
mbed_Cookbook_SE 0:de03cbbcd0ff 1063 // TODO: emit error event
mbed_Cookbook_SE 0:de03cbbcd0ff 1064 service = (l2cap_service_t *) btstack_memory_l2cap_service_get();
mbed_Cookbook_SE 0:de03cbbcd0ff 1065 if (!service) {
mbed_Cookbook_SE 0:de03cbbcd0ff 1066 log_error("l2cap_register_service_internal: no memory for l2cap_service_t\n");
mbed_Cookbook_SE 0:de03cbbcd0ff 1067 l2cap_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 1068 return;
mbed_Cookbook_SE 0:de03cbbcd0ff 1069 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1070
mbed_Cookbook_SE 0:de03cbbcd0ff 1071 // fill in
mbed_Cookbook_SE 0:de03cbbcd0ff 1072 service->psm = psm;
mbed_Cookbook_SE 0:de03cbbcd0ff 1073 service->mtu = mtu;
mbed_Cookbook_SE 0:de03cbbcd0ff 1074 service->connection = connection;
mbed_Cookbook_SE 0:de03cbbcd0ff 1075 service->packet_handler = packet_handler;
mbed_Cookbook_SE 0:de03cbbcd0ff 1076
mbed_Cookbook_SE 0:de03cbbcd0ff 1077 // add to services list
mbed_Cookbook_SE 0:de03cbbcd0ff 1078 linked_list_add(&l2cap_services, (linked_item_t *) service);
mbed_Cookbook_SE 0:de03cbbcd0ff 1079
mbed_Cookbook_SE 0:de03cbbcd0ff 1080 // enable page scan
mbed_Cookbook_SE 0:de03cbbcd0ff 1081 hci_connectable_control(1);
mbed_Cookbook_SE 0:de03cbbcd0ff 1082
mbed_Cookbook_SE 0:de03cbbcd0ff 1083 // done
mbed_Cookbook_SE 0:de03cbbcd0ff 1084 l2cap_emit_service_registered(connection, 0, psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 1085 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1086
mbed_Cookbook_SE 0:de03cbbcd0ff 1087 void l2cap_unregister_service_internal(void *connection, uint16_t psm){
mbed_Cookbook_SE 0:de03cbbcd0ff 1088 l2cap_service_t *service = l2cap_get_service(psm);
mbed_Cookbook_SE 0:de03cbbcd0ff 1089 if (!service) return;
mbed_Cookbook_SE 0:de03cbbcd0ff 1090 linked_list_remove(&l2cap_services, (linked_item_t *) service);
mbed_Cookbook_SE 0:de03cbbcd0ff 1091 btstack_memory_l2cap_service_free(service);
mbed_Cookbook_SE 0:de03cbbcd0ff 1092
mbed_Cookbook_SE 0:de03cbbcd0ff 1093 // disable page scan when no services registered
mbed_Cookbook_SE 0:de03cbbcd0ff 1094 if (!linked_list_empty(&l2cap_services)) return;
mbed_Cookbook_SE 0:de03cbbcd0ff 1095 hci_connectable_control(0);
mbed_Cookbook_SE 0:de03cbbcd0ff 1096 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1097
mbed_Cookbook_SE 0:de03cbbcd0ff 1098 //
mbed_Cookbook_SE 0:de03cbbcd0ff 1099 void l2cap_close_connection(void *connection){
mbed_Cookbook_SE 0:de03cbbcd0ff 1100 linked_item_t *it;
mbed_Cookbook_SE 0:de03cbbcd0ff 1101
mbed_Cookbook_SE 0:de03cbbcd0ff 1102 // close open channels - note to myself: no channel is freed, so no new for fancy iterator tricks
mbed_Cookbook_SE 0:de03cbbcd0ff 1103 l2cap_channel_t * channel;
mbed_Cookbook_SE 0:de03cbbcd0ff 1104 for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
mbed_Cookbook_SE 0:de03cbbcd0ff 1105 channel = (l2cap_channel_t *) it;
mbed_Cookbook_SE 0:de03cbbcd0ff 1106 if (channel->connection == connection) {
mbed_Cookbook_SE 0:de03cbbcd0ff 1107 channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
mbed_Cookbook_SE 0:de03cbbcd0ff 1108 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1109 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1110
mbed_Cookbook_SE 0:de03cbbcd0ff 1111 // unregister services
mbed_Cookbook_SE 0:de03cbbcd0ff 1112 it = (linked_item_t *) &l2cap_services;
mbed_Cookbook_SE 0:de03cbbcd0ff 1113 while (it->next) {
mbed_Cookbook_SE 0:de03cbbcd0ff 1114 l2cap_service_t * service = (l2cap_service_t *) it->next;
mbed_Cookbook_SE 0:de03cbbcd0ff 1115 if (service->connection == connection){
mbed_Cookbook_SE 0:de03cbbcd0ff 1116 it->next = it->next->next;
mbed_Cookbook_SE 0:de03cbbcd0ff 1117 btstack_memory_l2cap_service_free(service);
mbed_Cookbook_SE 0:de03cbbcd0ff 1118 } else {
mbed_Cookbook_SE 0:de03cbbcd0ff 1119 it = it->next;
mbed_Cookbook_SE 0:de03cbbcd0ff 1120 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1121 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1122
mbed_Cookbook_SE 0:de03cbbcd0ff 1123 // process
mbed_Cookbook_SE 0:de03cbbcd0ff 1124 l2cap_run();
mbed_Cookbook_SE 0:de03cbbcd0ff 1125 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1126
mbed_Cookbook_SE 0:de03cbbcd0ff 1127 // Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
mbed_Cookbook_SE 0:de03cbbcd0ff 1128 void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint16_t channel_id) {
mbed_Cookbook_SE 0:de03cbbcd0ff 1129 switch(channel_id){
mbed_Cookbook_SE 0:de03cbbcd0ff 1130 case L2CAP_CID_ATTRIBUTE_PROTOCOL:
mbed_Cookbook_SE 0:de03cbbcd0ff 1131 attribute_protocol_packet_handler = packet_handler;
mbed_Cookbook_SE 0:de03cbbcd0ff 1132 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 1133 case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
mbed_Cookbook_SE 0:de03cbbcd0ff 1134 security_protocol_packet_handler = packet_handler;
mbed_Cookbook_SE 0:de03cbbcd0ff 1135 break;
mbed_Cookbook_SE 0:de03cbbcd0ff 1136 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1137 }
mbed_Cookbook_SE 0:de03cbbcd0ff 1138