1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "sdp_server.c" 39 40 /* 41 * Implementation of the Service Discovery Protocol Server 42 */ 43 44 #include <string.h> 45 46 #include "bluetooth.h" 47 #include "bluetooth_psm.h" 48 #include "bluetooth_sdp.h" 49 #include "btstack_debug.h" 50 #include "btstack_event.h" 51 #include "btstack_memory.h" 52 #include "classic/core.h" 53 #include "classic/sdp_server.h" 54 #include "classic/sdp_util.h" 55 #include "hci.h" 56 #include "hci_dump.h" 57 #include "l2cap.h" 58 59 // max number of incoming l2cap connections that can be queued instead of getting rejected 60 #ifndef SDP_WAITING_LIST_MAX_COUNT 61 #define SDP_WAITING_LIST_MAX_COUNT 8 62 #endif 63 64 // max reserved ServiceRecordHandle 65 #define maxReservedServiceRecordHandle 0xffff 66 67 // max SDP response matches L2CAP PDU -- allow to use smaller buffer 68 #ifndef SDP_RESPONSE_BUFFER_SIZE 69 #define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_PAYLOAD_SIZE-L2CAP_HEADER_SIZE) 70 #endif 71 72 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 73 74 // registered service records 75 static btstack_linked_list_t sdp_service_records = NULL; 76 77 // our handles start after the reserved range 78 static uint32_t sdp_next_service_record_handle = ((uint32_t) maxReservedServiceRecordHandle) + 2; 79 80 static uint8_t sdp_response_buffer[SDP_RESPONSE_BUFFER_SIZE]; 81 82 static uint16_t l2cap_cid = 0; 83 static uint16_t sdp_response_size = 0; 84 static uint16_t l2cap_waiting_list_cids[SDP_WAITING_LIST_MAX_COUNT]; 85 static int l2cap_waiting_list_count; 86 87 void sdp_init(void){ 88 // register with l2cap psm sevices - max MTU 89 l2cap_register_service(sdp_packet_handler, BLUETOOTH_PSM_SDP, 0xffff, LEVEL_0); 90 l2cap_waiting_list_count = 0; 91 } 92 93 uint32_t sdp_get_service_record_handle(const uint8_t * record){ 94 // TODO: make sdp_get_attribute_value_for_attribute_id accept const data to remove cast 95 uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id((uint8_t *)record, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE); 96 if (!serviceRecordHandleAttribute) return 0; 97 if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0; 98 if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0; 99 return big_endian_read_32(serviceRecordHandleAttribute, 1); 100 } 101 102 static service_record_item_t * sdp_get_record_item_for_handle(uint32_t handle){ 103 btstack_linked_item_t *it; 104 for (it = (btstack_linked_item_t *) sdp_service_records; it ; it = it->next){ 105 service_record_item_t * item = (service_record_item_t *) it; 106 if (item->service_record_handle == handle){ 107 return item; 108 } 109 } 110 return NULL; 111 } 112 113 uint8_t * sdp_get_record_for_handle(uint32_t handle){ 114 service_record_item_t * record_item = sdp_get_record_item_for_handle(handle); 115 if (!record_item) return NULL; 116 return record_item->service_record; 117 } 118 119 // get next free, unregistered service record handle 120 uint32_t sdp_create_service_record_handle(void){ 121 uint32_t handle = 0; 122 do { 123 handle = sdp_next_service_record_handle++; 124 if (sdp_get_record_item_for_handle(handle)) handle = 0; 125 } while (handle == 0); 126 return handle; 127 } 128 129 /** 130 * @brief Register Service Record with database using ServiceRecordHandle stored in record 131 * @pre AttributeIDs are in ascending order 132 * @pre ServiceRecordHandle is first attribute and valid 133 * @param record is not copied! 134 * @result status 135 */ 136 uint8_t sdp_register_service(const uint8_t * record){ 137 138 // validate service record handle. it must: exist, be in valid range, not have been already used 139 uint32_t record_handle = sdp_get_service_record_handle(record); 140 if (!record_handle) return SDP_HANDLE_INVALID; 141 if (record_handle <= maxReservedServiceRecordHandle) return SDP_HANDLE_INVALID; 142 if (sdp_get_record_item_for_handle(record_handle)) return SDP_HANDLE_ALREADY_REGISTERED; 143 144 // alloc memory for new service_record_item 145 service_record_item_t * newRecordItem = btstack_memory_service_record_item_get(); 146 if (!newRecordItem) return BTSTACK_MEMORY_ALLOC_FAILED; 147 148 // set handle and record 149 newRecordItem->service_record_handle = record_handle; 150 newRecordItem->service_record = (uint8_t*) record; 151 152 // add to linked list 153 btstack_linked_list_add(&sdp_service_records, (btstack_linked_item_t *) newRecordItem); 154 155 return 0; 156 } 157 158 // 159 // unregister service record 160 // 161 void sdp_unregister_service(uint32_t service_record_handle){ 162 service_record_item_t * record_item = sdp_get_record_item_for_handle(service_record_handle); 163 if (!record_item) return; 164 btstack_linked_list_remove(&sdp_service_records, (btstack_linked_item_t *) record_item); 165 btstack_memory_service_record_item_free(record_item); 166 } 167 168 // PDU 169 // PDU ID (1), Transaction ID (2), Param Length (2), Param 1, Param 2, .. 170 171 static int sdp_create_error_response(uint16_t transaction_id, uint16_t error_code){ 172 sdp_response_buffer[0] = SDP_ErrorResponse; 173 big_endian_store_16(sdp_response_buffer, 1, transaction_id); 174 big_endian_store_16(sdp_response_buffer, 3, 2); 175 big_endian_store_16(sdp_response_buffer, 5, error_code); // invalid syntax 176 return 7; 177 } 178 179 int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu){ 180 181 // get request details 182 uint16_t transaction_id = big_endian_read_16(packet, 1); 183 uint16_t param_len = big_endian_read_16(packet, 3); 184 uint8_t * serviceSearchPattern = &packet[5]; 185 uint16_t serviceSearchPatternLen = de_get_len_safe(serviceSearchPattern, param_len); 186 // assert service search pattern is contained 187 if (!serviceSearchPatternLen) return 0; 188 param_len -= serviceSearchPatternLen; 189 // assert max record count is contained 190 if (param_len < 2) return 0; 191 uint16_t maximumServiceRecordCount = big_endian_read_16(packet, 5 + serviceSearchPatternLen); 192 param_len -= 2; 193 // assert continuation state len is contained in param_len 194 if (param_len < 1) return 0; 195 uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2]; 196 // assert continuation state is contained in param_len 197 if ((1 + continuationState[0]) > param_len) return 0; 198 199 // calc maximumServiceRecordCount based on remote MTU 200 uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4; 201 202 // continuation state contains index of next service record to examine 203 int continuation = 0; 204 uint16_t continuation_index = 0; 205 if (continuationState[0] == 2){ 206 continuation_index = big_endian_read_16(continuationState, 1); 207 } 208 209 // get and limit total count 210 btstack_linked_item_t *it; 211 uint16_t total_service_count = 0; 212 for (it = (btstack_linked_item_t *) sdp_service_records; it ; it = it->next){ 213 service_record_item_t * item = (service_record_item_t *) it; 214 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 215 total_service_count++; 216 } 217 if (total_service_count > maximumServiceRecordCount){ 218 total_service_count = maximumServiceRecordCount; 219 } 220 221 // ServiceRecordHandleList at 9 222 uint16_t pos = 9; 223 uint16_t current_service_count = 0; 224 uint16_t current_service_index = 0; 225 uint16_t matching_service_count = 0; 226 for (it = (btstack_linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index){ 227 service_record_item_t * item = (service_record_item_t *) it; 228 229 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 230 matching_service_count++; 231 232 if (current_service_index < continuation_index) continue; 233 234 big_endian_store_32(sdp_response_buffer, pos, item->service_record_handle); 235 pos += 4; 236 current_service_count++; 237 238 if (matching_service_count >= total_service_count) break; 239 240 if (current_service_count >= maxNrServiceRecordsPerResponse){ 241 continuation = 1; 242 continuation_index = current_service_index + 1; 243 break; 244 } 245 } 246 247 // Store continuation state 248 if (continuation) { 249 sdp_response_buffer[pos++] = 2; 250 big_endian_store_16(sdp_response_buffer, pos, continuation_index); 251 pos += 2; 252 } else { 253 sdp_response_buffer[pos++] = 0; 254 } 255 256 // header 257 sdp_response_buffer[0] = SDP_ServiceSearchResponse; 258 big_endian_store_16(sdp_response_buffer, 1, transaction_id); 259 big_endian_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload 260 big_endian_store_16(sdp_response_buffer, 5, total_service_count); 261 big_endian_store_16(sdp_response_buffer, 7, current_service_count); 262 263 return pos; 264 } 265 266 int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){ 267 268 // get request details 269 uint16_t transaction_id = big_endian_read_16(packet, 1); 270 uint16_t param_len = big_endian_read_16(packet, 3); 271 // assert serviceRecordHandle and maximumAttributeByteCount are in param_len 272 if (param_len < 6) return 0; 273 uint32_t serviceRecordHandle = big_endian_read_32(packet, 5); 274 uint16_t maximumAttributeByteCount = big_endian_read_16(packet, 9); 275 param_len -= 6; 276 uint8_t * attributeIDList = &packet[11]; 277 uint16_t attributeIDListLen = de_get_len_safe(attributeIDList, param_len); 278 // assert attributeIDList are in param_len 279 if (!attributeIDListLen) return 0; 280 param_len -= attributeIDListLen; 281 // assert continuation state len is contained in param_len 282 if (param_len < 1) return 0; 283 uint8_t * continuationState = &packet[11+attributeIDListLen]; 284 // assert continuation state is contained in param_len 285 if ((1 + continuationState[0]) > param_len) return 0; 286 287 // calc maximumAttributeByteCount based on remote MTU 288 uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3); 289 if (maximumAttributeByteCount2 < maximumAttributeByteCount) { 290 maximumAttributeByteCount = maximumAttributeByteCount2; 291 } 292 293 // continuation state contains the offset into the complete response 294 uint16_t continuation_offset = 0; 295 if (continuationState[0] == 2){ 296 continuation_offset = big_endian_read_16(continuationState, 1); 297 } 298 299 // get service record 300 service_record_item_t * item = sdp_get_record_item_for_handle(serviceRecordHandle); 301 if (!item){ 302 // service record handle doesn't exist 303 return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle 304 } 305 306 307 // AttributeList - starts at offset 7 308 uint16_t pos = 7; 309 310 if (continuation_offset == 0){ 311 312 // get size of this record 313 uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList); 314 315 // store DES 316 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); 317 maximumAttributeByteCount -= 3; 318 pos += 3; 319 } 320 321 // copy maximumAttributeByteCount from record 322 uint16_t bytes_used; 323 int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); 324 pos += bytes_used; 325 326 uint16_t attributeListByteCount = pos - 7; 327 328 if (complete) { 329 sdp_response_buffer[pos++] = 0; 330 } else { 331 continuation_offset += bytes_used; 332 sdp_response_buffer[pos++] = 2; 333 big_endian_store_16(sdp_response_buffer, pos, continuation_offset); 334 pos += 2; 335 } 336 337 // header 338 sdp_response_buffer[0] = SDP_ServiceAttributeResponse; 339 big_endian_store_16(sdp_response_buffer, 1, transaction_id); 340 big_endian_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload 341 big_endian_store_16(sdp_response_buffer, 5, attributeListByteCount); 342 343 return pos; 344 } 345 346 static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){ 347 uint16_t total_response_size = 0; 348 btstack_linked_item_t *it; 349 for (it = (btstack_linked_item_t *) sdp_service_records; it ; it = it->next){ 350 service_record_item_t * item = (service_record_item_t *) it; 351 352 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 353 354 // for all service records that match 355 total_response_size += 3 + spd_get_filtered_size(item->service_record, attributeIDList); 356 } 357 return total_response_size; 358 } 359 360 int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){ 361 362 // SDP header before attribute sevice list: 7 363 // Continuation, worst case: 5 364 365 // get request details 366 uint16_t transaction_id = big_endian_read_16(packet, 1); 367 uint16_t param_len = big_endian_read_16(packet, 3); 368 uint8_t * serviceSearchPattern = &packet[5]; 369 uint16_t serviceSearchPatternLen = de_get_len_safe(serviceSearchPattern, param_len); 370 // assert serviceSearchPattern header is contained in param_len 371 if (!serviceSearchPatternLen) return 0; 372 param_len -= serviceSearchPatternLen; 373 // assert maximumAttributeByteCount contained in param_len 374 if (param_len < 2) return 0; 375 uint16_t maximumAttributeByteCount = big_endian_read_16(packet, 5 + serviceSearchPatternLen); 376 param_len -= 2; 377 uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2]; 378 uint16_t attributeIDListLen = de_get_len_safe(attributeIDList, param_len); 379 // assert attributeIDList is contained in param_len 380 if (!attributeIDListLen) return 0; 381 // assert continuation state len is contained in param_len 382 if (param_len < 1) return 0; 383 uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen]; 384 // assert continuation state is contained in param_len 385 if ((1 + continuationState[0]) > param_len) return 0; 386 387 // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block 388 uint16_t maximumAttributeByteCount2 = remote_mtu - 12; 389 if (maximumAttributeByteCount2 < maximumAttributeByteCount) { 390 maximumAttributeByteCount = maximumAttributeByteCount2; 391 } 392 393 // continuation state contains: index of next service record to examine 394 // continuation state contains: byte offset into this service record 395 uint16_t continuation_service_index = 0; 396 uint16_t continuation_offset = 0; 397 if (continuationState[0] == 4){ 398 continuation_service_index = big_endian_read_16(continuationState, 1); 399 continuation_offset = big_endian_read_16(continuationState, 3); 400 } 401 402 // log_info("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u", continuation_service_index, continuation_offset, maximumAttributeByteCount); 403 404 // AttributeLists - starts at offset 7 405 uint16_t pos = 7; 406 407 // add DES with total size for first request 408 if ((continuation_service_index == 0) && (continuation_offset == 0)){ 409 uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList); 410 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size); 411 // log_info("total response size %u", total_response_size); 412 pos += 3; 413 maximumAttributeByteCount -= 3; 414 } 415 416 // create attribute list 417 int first_answer = 1; 418 int continuation = 0; 419 uint16_t current_service_index = 0; 420 btstack_linked_item_t *it = (btstack_linked_item_t *) sdp_service_records; 421 for ( ; it ; it = it->next, ++current_service_index){ 422 service_record_item_t * item = (service_record_item_t *) it; 423 424 if (current_service_index < continuation_service_index ) continue; 425 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 426 427 if (continuation_offset == 0){ 428 429 // get size of this record 430 uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList); 431 432 // stop if complete record doesn't fits into response but we already have a partial response 433 if (((filtered_attributes_size + 3) > maximumAttributeByteCount) && !first_answer) { 434 continuation = 1; 435 break; 436 } 437 438 // store DES 439 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); 440 pos += 3; 441 maximumAttributeByteCount -= 3; 442 } 443 444 first_answer = 0; 445 446 // copy maximumAttributeByteCount from record 447 uint16_t bytes_used; 448 int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); 449 pos += bytes_used; 450 maximumAttributeByteCount -= bytes_used; 451 452 if (complete) { 453 continuation_offset = 0; 454 continue; 455 } 456 457 continuation = 1; 458 continuation_offset += bytes_used; 459 break; 460 } 461 462 uint16_t attributeListsByteCount = pos - 7; 463 464 // Continuation State 465 if (continuation){ 466 sdp_response_buffer[pos++] = 4; 467 big_endian_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index); 468 pos += 2; 469 big_endian_store_16(sdp_response_buffer, pos, continuation_offset); 470 pos += 2; 471 } else { 472 // complete 473 sdp_response_buffer[pos++] = 0; 474 } 475 476 // create SDP header 477 sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse; 478 big_endian_store_16(sdp_response_buffer, 1, transaction_id); 479 big_endian_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload 480 big_endian_store_16(sdp_response_buffer, 5, attributeListsByteCount); 481 482 return pos; 483 } 484 485 static void sdp_respond(void){ 486 if (!sdp_response_size ) return; 487 if (!l2cap_cid) return; 488 489 // update state before sending packet (avoid getting called when new l2cap credit gets emitted) 490 uint16_t size = sdp_response_size; 491 sdp_response_size = 0; 492 l2cap_send(l2cap_cid, sdp_response_buffer, size); 493 } 494 495 // @pre space in list 496 static void sdp_waiting_list_add(uint16_t cid){ 497 l2cap_waiting_list_cids[l2cap_waiting_list_count++] = cid; 498 } 499 500 // @pre at least one item in list 501 static uint16_t sdp_waiting_list_get(void){ 502 uint16_t cid = l2cap_waiting_list_cids[0]; 503 l2cap_waiting_list_count--; 504 if (l2cap_waiting_list_count){ 505 memmove(&l2cap_waiting_list_cids[0], &l2cap_waiting_list_cids[1], l2cap_waiting_list_count * sizeof(uint16_t)); 506 } 507 return cid; 508 } 509 510 // we assume that we don't get two requests in a row 511 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 512 uint16_t transaction_id; 513 SDP_PDU_ID_t pdu_id; 514 uint16_t remote_mtu; 515 uint16_t param_len; 516 517 switch (packet_type) { 518 519 case L2CAP_DATA_PACKET: 520 pdu_id = (SDP_PDU_ID_t) packet[0]; 521 transaction_id = big_endian_read_16(packet, 1); 522 param_len = big_endian_read_16(packet, 3); 523 remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel); 524 // account for our buffer 525 if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){ 526 remote_mtu = SDP_RESPONSE_BUFFER_SIZE; 527 } 528 // validate parm_len against packet size 529 if ((param_len + 5) > size) { 530 // just clear pdu_id 531 pdu_id = SDP_ErrorResponse; 532 } 533 534 // log_info("SDP Request: type %u, transaction id %u, len %u, mtu %u", pdu_id, transaction_id, param_len, remote_mtu); 535 switch (pdu_id){ 536 537 case SDP_ServiceSearchRequest: 538 sdp_response_size = sdp_handle_service_search_request(packet, remote_mtu); 539 break; 540 541 case SDP_ServiceAttributeRequest: 542 sdp_response_size = sdp_handle_service_attribute_request(packet, remote_mtu); 543 break; 544 545 case SDP_ServiceSearchAttributeRequest: 546 sdp_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu); 547 break; 548 549 default: 550 sdp_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax 551 break; 552 } 553 if (!sdp_response_size) break; 554 l2cap_request_can_send_now_event(l2cap_cid); 555 break; 556 557 case HCI_EVENT_PACKET: 558 559 switch (hci_event_packet_get_type(packet)) { 560 561 case L2CAP_EVENT_INCOMING_CONNECTION: 562 if (l2cap_cid) { 563 // try to queue up 564 if (l2cap_waiting_list_count < SDP_WAITING_LIST_MAX_COUNT){ 565 sdp_waiting_list_add(channel); 566 log_info("busy, queing incoming cid 0x%04x, now %u waiting", channel, l2cap_waiting_list_count); 567 break; 568 } 569 570 // CONNECTION REJECTED DUE TO LIMITED RESOURCES 571 l2cap_decline_connection(channel); 572 break; 573 } 574 // accept 575 l2cap_cid = channel; 576 sdp_response_size = 0; 577 l2cap_accept_connection(l2cap_cid); 578 break; 579 580 case L2CAP_EVENT_CHANNEL_OPENED: 581 if (packet[2]) { 582 // open failed -> reset 583 l2cap_cid = 0; 584 } 585 break; 586 587 case L2CAP_EVENT_CAN_SEND_NOW: 588 sdp_respond(); 589 break; 590 591 case L2CAP_EVENT_CHANNEL_CLOSED: 592 if (channel == l2cap_cid){ 593 // reset 594 l2cap_cid = 0; 595 596 // other request queued? 597 if (!l2cap_waiting_list_count) break; 598 599 // get first item 600 l2cap_cid = sdp_waiting_list_get(); 601 602 log_info("disconnect, accept queued cid 0x%04x, now %u waiting", l2cap_cid, l2cap_waiting_list_count); 603 604 // accept connection 605 sdp_response_size = 0; 606 l2cap_accept_connection(l2cap_cid); 607 } 608 break; 609 610 default: 611 // other event 612 break; 613 } 614 break; 615 616 default: 617 // other packet type 618 break; 619 } 620 } 621 622