1 /****************************************************************************** 2 * 3 * Copyright 2014 Google, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 #define LOG_TAG "bt_l2cap_client" 20 21 #include "stack/include/l2cap_client.h" 22 23 #include <base/logging.h> 24 #include <string.h> 25 26 #include "osi/include/allocator.h" 27 #include "osi/include/buffer.h" 28 #include "osi/include/list.h" 29 #include "osi/include/log.h" 30 #include "osi/include/osi.h" 31 #include "stack/include/l2c_api.h" 32 33 struct l2cap_client_t { 34 l2cap_client_callbacks_t callbacks; 35 void* context; 36 37 uint16_t local_channel_id; 38 uint16_t remote_mtu; 39 bool configured_self; 40 bool configured_peer; 41 bool is_congested; 42 list_t* outbound_fragments; 43 }; 44 45 static void connect_completed_cb(uint16_t local_channel_id, 46 uint16_t error_code); 47 static void config_request_cb(uint16_t local_channel_id, 48 tL2CAP_CFG_INFO* requested_parameters); 49 static void config_completed_cb(uint16_t local_channel_id, 50 tL2CAP_CFG_INFO* negotiated_parameters); 51 static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required); 52 static void disconnect_completed_cb(uint16_t local_channel_id, 53 uint16_t error_code); 54 static void congestion_cb(uint16_t local_channel_id, bool is_congested); 55 static void read_ready_cb(uint16_t local_channel_id, BT_HDR* packet); 56 static void write_completed_cb(uint16_t local_channel_id, 57 uint16_t packets_completed); 58 59 static void fragment_packet(l2cap_client_t* client, buffer_t* packet); 60 static void dispatch_fragments(l2cap_client_t* client); 61 static l2cap_client_t* find(uint16_t local_channel_id); 62 63 // From the Bluetooth Core specification. 64 static const uint16_t L2CAP_MTU_DEFAULT = 672; 65 static const uint16_t L2CAP_MTU_MINIMUM = 48; 66 67 static const tL2CAP_APPL_INFO l2cap_callbacks = { 68 .pL2CA_ConnectCfm_Cb = connect_completed_cb, 69 .pL2CA_ConfigInd_Cb = config_request_cb, 70 .pL2CA_ConfigCfm_Cb = config_completed_cb, 71 .pL2CA_DisconnectInd_Cb = disconnect_request_cb, 72 .pL2CA_DisconnectCfm_Cb = disconnect_completed_cb, 73 .pL2CA_CongestionStatus_Cb = congestion_cb, 74 .pL2CA_DataInd_Cb = read_ready_cb, 75 .pL2CA_TxComplete_Cb = write_completed_cb, 76 }; 77 78 static list_t* 79 l2cap_clients; // A list of l2cap_client_t. Container does not own objects. 80 81 buffer_t* l2cap_buffer_new(size_t size) { 82 buffer_t* buf = buffer_new(size + L2CAP_MIN_OFFSET); 83 buffer_t* slice = NULL; 84 if (buf) slice = buffer_new_slice(buf, size); 85 buffer_free(buf); 86 return slice; 87 } 88 89 l2cap_client_t* l2cap_client_new(const l2cap_client_callbacks_t* callbacks, 90 void* context) { 91 CHECK(callbacks != NULL); 92 CHECK(callbacks->connected != NULL); 93 CHECK(callbacks->disconnected != NULL); 94 CHECK(callbacks->read_ready != NULL); 95 CHECK(callbacks->write_ready != NULL); 96 97 if (!l2cap_clients) { 98 l2cap_clients = list_new(NULL); 99 if (!l2cap_clients) { 100 LOG_ERROR(LOG_TAG, "%s unable to allocate space for L2CAP client list.", 101 __func__); 102 return NULL; 103 } 104 } 105 106 l2cap_client_t* ret = (l2cap_client_t*)osi_calloc(sizeof(l2cap_client_t)); 107 108 ret->callbacks = *callbacks; 109 ret->context = context; 110 111 ret->remote_mtu = L2CAP_MTU_DEFAULT; 112 ret->outbound_fragments = list_new(NULL); 113 114 list_append(l2cap_clients, ret); 115 116 return ret; 117 } 118 119 void l2cap_client_free(l2cap_client_t* client) { 120 if (!client) return; 121 122 list_remove(l2cap_clients, client); 123 l2cap_client_disconnect(client); 124 list_free(client->outbound_fragments); 125 osi_free(client); 126 } 127 128 bool l2cap_client_connect(l2cap_client_t* client, 129 const RawAddress& remote_bdaddr, uint16_t psm) { 130 CHECK(client != NULL); 131 CHECK(psm != 0); 132 CHECK(!remote_bdaddr.IsEmpty()); 133 CHECK(client->local_channel_id == 0); 134 CHECK(!client->configured_self); 135 CHECK(!client->configured_peer); 136 CHECK(!L2C_INVALID_PSM(psm)); 137 138 client->local_channel_id = L2CA_ConnectReq(psm, remote_bdaddr); 139 if (!client->local_channel_id) { 140 LOG_ERROR(LOG_TAG, "%s unable to create L2CAP connection.", __func__); 141 return false; 142 } 143 144 L2CA_SetConnectionCallbacks(client->local_channel_id, &l2cap_callbacks); 145 return true; 146 } 147 148 void l2cap_client_disconnect(l2cap_client_t* client) { 149 CHECK(client != NULL); 150 151 if (client->local_channel_id && !L2CA_DisconnectReq(client->local_channel_id)) 152 LOG_ERROR(LOG_TAG, "%s unable to send disconnect message for LCID 0x%04x.", 153 __func__, client->local_channel_id); 154 155 client->local_channel_id = 0; 156 client->remote_mtu = L2CAP_MTU_DEFAULT; 157 client->configured_self = false; 158 client->configured_peer = false; 159 client->is_congested = false; 160 161 for (const list_node_t* node = list_begin(client->outbound_fragments); 162 node != list_end(client->outbound_fragments); node = list_next(node)) 163 osi_free(list_node(node)); 164 165 list_clear(client->outbound_fragments); 166 } 167 168 bool l2cap_client_is_connected(const l2cap_client_t* client) { 169 CHECK(client != NULL); 170 171 return client->local_channel_id != 0 && client->configured_self && 172 client->configured_peer; 173 } 174 175 bool l2cap_client_write(l2cap_client_t* client, buffer_t* packet) { 176 CHECK(client != NULL); 177 CHECK(packet != NULL); 178 CHECK(l2cap_client_is_connected(client)); 179 180 if (client->is_congested) return false; 181 182 fragment_packet(client, packet); 183 dispatch_fragments(client); 184 return true; 185 } 186 187 static void connect_completed_cb(uint16_t local_channel_id, 188 uint16_t error_code) { 189 CHECK(local_channel_id != 0); 190 191 l2cap_client_t* client = find(local_channel_id); 192 if (!client) { 193 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client for LCID 0x%04x.", 194 __func__, local_channel_id); 195 return; 196 } 197 198 if (error_code != L2CAP_CONN_OK) { 199 LOG_ERROR(LOG_TAG, "%s error connecting L2CAP channel: %d.", __func__, 200 error_code); 201 client->callbacks.disconnected(client, client->context); 202 return; 203 } 204 205 // Use default L2CAP parameters. 206 tL2CAP_CFG_INFO desired_parameters; 207 memset(&desired_parameters, 0, sizeof(desired_parameters)); 208 if (!L2CA_ConfigReq(local_channel_id, &desired_parameters)) { 209 LOG_ERROR(LOG_TAG, "%s error sending L2CAP config parameters.", __func__); 210 client->callbacks.disconnected(client, client->context); 211 } 212 } 213 214 static void config_request_cb(uint16_t local_channel_id, 215 tL2CAP_CFG_INFO* requested_parameters) { 216 tL2CAP_CFG_INFO response; 217 l2cap_client_t* client = find(local_channel_id); 218 219 if (!client) { 220 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", 221 __func__, local_channel_id); 222 return; 223 } 224 225 memset(&response, 0, sizeof(response)); 226 response.result = L2CAP_CFG_OK; 227 228 if (requested_parameters->mtu_present) { 229 // Make sure the peer chose an MTU at least as large as the minimum L2CAP 230 // MTU defined by the Bluetooth Core spec. 231 if (requested_parameters->mtu < L2CAP_MTU_MINIMUM) { 232 response.mtu = L2CAP_MTU_MINIMUM; 233 response.mtu_present = true; 234 response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS; 235 } else { 236 client->remote_mtu = requested_parameters->mtu; 237 } 238 } 239 240 if (requested_parameters->fcr_present) { 241 if (requested_parameters->fcr.mode != L2CAP_FCR_BASIC_MODE) { 242 response.fcr_present = true; 243 response.fcr = requested_parameters->fcr; 244 response.fcr.mode = L2CAP_FCR_BASIC_MODE; 245 response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS; 246 } 247 } 248 249 if (!L2CA_ConfigRsp(local_channel_id, &response)) { 250 LOG_ERROR(LOG_TAG, "%s unable to send config response for LCID 0x%04x.", 251 __func__, local_channel_id); 252 l2cap_client_disconnect(client); 253 return; 254 } 255 256 // If we've configured both endpoints, let the listener know we've connected. 257 client->configured_peer = true; 258 if (l2cap_client_is_connected(client)) 259 client->callbacks.connected(client, client->context); 260 } 261 262 static void config_completed_cb(uint16_t local_channel_id, 263 tL2CAP_CFG_INFO* negotiated_parameters) { 264 l2cap_client_t* client = find(local_channel_id); 265 266 if (!client) { 267 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", 268 __func__, local_channel_id); 269 return; 270 } 271 272 switch (negotiated_parameters->result) { 273 // We'll get another configuration response later. 274 case L2CAP_CFG_PENDING: 275 break; 276 277 case L2CAP_CFG_UNACCEPTABLE_PARAMS: 278 // TODO: see if we can renegotiate parameters instead of dropping the 279 // connection. 280 LOG_WARN( 281 LOG_TAG, 282 "%s dropping L2CAP connection due to unacceptable config parameters.", 283 __func__); 284 l2cap_client_disconnect(client); 285 break; 286 287 case L2CAP_CFG_OK: 288 // If we've configured both endpoints, let the listener know we've 289 // connected. 290 client->configured_self = true; 291 if (l2cap_client_is_connected(client)) 292 client->callbacks.connected(client, client->context); 293 break; 294 295 // Failure, no further parameter negotiation possible. 296 default: 297 LOG_WARN(LOG_TAG, 298 "%s L2CAP parameter negotiation failed with error code %d.", 299 __func__, negotiated_parameters->result); 300 l2cap_client_disconnect(client); 301 break; 302 } 303 } 304 305 static void disconnect_request_cb(uint16_t local_channel_id, 306 bool ack_required) { 307 l2cap_client_t* client = find(local_channel_id); 308 if (!client) { 309 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", 310 __func__, local_channel_id); 311 return; 312 } 313 314 if (ack_required) L2CA_DisconnectRsp(local_channel_id); 315 316 // We already sent a disconnect response so this LCID is now invalid. 317 client->local_channel_id = 0; 318 l2cap_client_disconnect(client); 319 320 client->callbacks.disconnected(client, client->context); 321 } 322 323 static void disconnect_completed_cb(uint16_t local_channel_id, 324 UNUSED_ATTR uint16_t error_code) { 325 CHECK(local_channel_id != 0); 326 327 l2cap_client_t* client = find(local_channel_id); 328 if (!client) { 329 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", 330 __func__, local_channel_id); 331 return; 332 } 333 334 client->local_channel_id = 0; 335 l2cap_client_disconnect(client); 336 337 client->callbacks.disconnected(client, client->context); 338 } 339 340 static void congestion_cb(uint16_t local_channel_id, bool is_congested) { 341 CHECK(local_channel_id != 0); 342 343 l2cap_client_t* client = find(local_channel_id); 344 if (!client) { 345 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", 346 __func__, local_channel_id); 347 return; 348 } 349 350 client->is_congested = is_congested; 351 352 if (!is_congested) { 353 // If we just decongested, dispatch whatever we have left over in our queue. 354 // Once that's done, if we're still decongested, notify the listener so it 355 // can start writing again. 356 dispatch_fragments(client); 357 if (!client->is_congested) 358 client->callbacks.write_ready(client, client->context); 359 } 360 } 361 362 static void read_ready_cb(uint16_t local_channel_id, BT_HDR* packet) { 363 CHECK(local_channel_id != 0); 364 365 l2cap_client_t* client = find(local_channel_id); 366 if (!client) { 367 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", 368 __func__, local_channel_id); 369 return; 370 } 371 372 // TODO(sharvil): eliminate copy from BT_HDR. 373 buffer_t* buffer = buffer_new(packet->len); 374 memcpy(buffer_ptr(buffer), packet->data + packet->offset, packet->len); 375 osi_free(packet); 376 377 client->callbacks.read_ready(client, buffer, client->context); 378 buffer_free(buffer); 379 } 380 381 static void write_completed_cb(UNUSED_ATTR uint16_t local_channel_id, 382 UNUSED_ATTR uint16_t packets_completed) { 383 // Do nothing. We update congestion state based on the congestion callback 384 // and we've already removed items from outbound_fragments list so we don't 385 // really care how many packets were successfully dispatched. 386 } 387 388 static void fragment_packet(l2cap_client_t* client, buffer_t* packet) { 389 CHECK(client != NULL); 390 CHECK(packet != NULL); 391 392 // TODO(sharvil): eliminate copy into BT_HDR. 393 BT_HDR* bt_packet = static_cast<BT_HDR*>( 394 osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET + sizeof(BT_HDR))); 395 bt_packet->offset = L2CAP_MIN_OFFSET; 396 bt_packet->len = buffer_length(packet); 397 memcpy(bt_packet->data + bt_packet->offset, buffer_ptr(packet), 398 buffer_length(packet)); 399 400 for (;;) { 401 if (bt_packet->len <= client->remote_mtu) { 402 if (bt_packet->len > 0) 403 list_append(client->outbound_fragments, bt_packet); 404 else 405 osi_free(bt_packet); 406 break; 407 } 408 409 BT_HDR* fragment = static_cast<BT_HDR*>( 410 osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET + sizeof(BT_HDR))); 411 fragment->offset = L2CAP_MIN_OFFSET; 412 fragment->len = client->remote_mtu; 413 memcpy(fragment->data + fragment->offset, 414 bt_packet->data + bt_packet->offset, client->remote_mtu); 415 416 list_append(client->outbound_fragments, fragment); 417 418 bt_packet->offset += client->remote_mtu; 419 bt_packet->len -= client->remote_mtu; 420 } 421 } 422 423 static void dispatch_fragments(l2cap_client_t* client) { 424 CHECK(client != NULL); 425 CHECK(!client->is_congested); 426 427 while (!list_is_empty(client->outbound_fragments)) { 428 BT_HDR* packet = (BT_HDR*)list_front(client->outbound_fragments); 429 list_remove(client->outbound_fragments, packet); 430 431 switch (L2CA_DataWrite(client->local_channel_id, packet)) { 432 case L2CAP_DW_CONGESTED: 433 client->is_congested = true; 434 return; 435 436 case L2CAP_DW_FAILED: 437 LOG_ERROR(LOG_TAG, 438 "%s error writing data to L2CAP connection LCID 0x%04x; " 439 "disconnecting.", 440 __func__, client->local_channel_id); 441 l2cap_client_disconnect(client); 442 return; 443 444 case L2CAP_DW_SUCCESS: 445 break; 446 } 447 } 448 } 449 450 static l2cap_client_t* find(uint16_t local_channel_id) { 451 CHECK(local_channel_id != 0); 452 453 for (const list_node_t* node = list_begin(l2cap_clients); 454 node != list_end(l2cap_clients); node = list_next(node)) { 455 l2cap_client_t* client = (l2cap_client_t*)list_node(node); 456 if (client->local_channel_id == local_channel_id) return client; 457 } 458 459 return NULL; 460 } 461