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