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