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 if (!sdp_attribute_list_valid(attributeIDList) == false){ 286 return sdp_create_error_response(transaction_id, 0x0003); /// invalid request syntax 287 } 288 // assert attributeIDList are in param_len 289 if (!attributeIDListLen) return 0; 290 param_len -= attributeIDListLen; 291 // assert continuation state len is contained in param_len 292 if (param_len < 1) return 0; 293 uint8_t * continuationState = &packet[11+attributeIDListLen]; 294 // assert continuation state is contained in param_len 295 if ((1 + continuationState[0]) > param_len) return 0; 296 297 // calc maximumAttributeByteCount based on remote MTU 298 uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3); 299 if (maximumAttributeByteCount2 < maximumAttributeByteCount) { 300 maximumAttributeByteCount = maximumAttributeByteCount2; 301 } 302 303 // continuation state contains the offset into the complete response 304 uint16_t continuation_offset = 0; 305 if (continuationState[0] == 2){ 306 continuation_offset = big_endian_read_16(continuationState, 1); 307 } 308 309 // get service record 310 service_record_item_t * item = sdp_get_record_item_for_handle(serviceRecordHandle); 311 if (!item){ 312 // service record handle doesn't exist 313 return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle 314 } 315 316 317 // AttributeList - starts at offset 7 318 uint16_t pos = 7; 319 320 if (continuation_offset == 0){ 321 322 // get size of this record 323 uint16_t filtered_attributes_size = sdp_get_filtered_size(item->service_record, attributeIDList); 324 325 // store DES 326 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); 327 maximumAttributeByteCount -= 3; 328 pos += 3; 329 } 330 331 // copy maximumAttributeByteCount from record 332 uint16_t bytes_used; 333 int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); 334 pos += bytes_used; 335 336 uint16_t attributeListByteCount = pos - 7; 337 338 if (complete) { 339 sdp_response_buffer[pos++] = 0; 340 } else { 341 continuation_offset += bytes_used; 342 sdp_response_buffer[pos++] = 2; 343 big_endian_store_16(sdp_response_buffer, pos, continuation_offset); 344 pos += 2; 345 } 346 347 // header 348 sdp_response_buffer[0] = SDP_ServiceAttributeResponse; 349 big_endian_store_16(sdp_response_buffer, 1, transaction_id); 350 big_endian_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload 351 big_endian_store_16(sdp_response_buffer, 5, attributeListByteCount); 352 353 return pos; 354 } 355 356 static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){ 357 uint16_t total_response_size = 0; 358 btstack_linked_item_t *it; 359 for (it = (btstack_linked_item_t *) sdp_server_service_records; it ; it = it->next){ 360 service_record_item_t * item = (service_record_item_t *) it; 361 362 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 363 364 // for all service records that match 365 total_response_size += 3 + sdp_get_filtered_size(item->service_record, attributeIDList); 366 } 367 return total_response_size; 368 } 369 370 int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){ 371 372 // SDP header before attribute sevice list: 7 373 // Continuation, worst case: 5 374 375 // get request details 376 uint16_t transaction_id = big_endian_read_16(packet, 1); 377 uint16_t param_len = big_endian_read_16(packet, 3); 378 uint8_t * serviceSearchPattern = &packet[5]; 379 uint16_t serviceSearchPatternLen = de_get_len_safe(serviceSearchPattern, param_len); 380 // assert serviceSearchPattern header is contained in param_len 381 if (!serviceSearchPatternLen) return 0; 382 param_len -= serviceSearchPatternLen; 383 // assert maximumAttributeByteCount contained in param_len 384 if (param_len < 2) return 0; 385 uint16_t maximumAttributeByteCount = big_endian_read_16(packet, 5 + serviceSearchPatternLen); 386 param_len -= 2; 387 uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2]; 388 uint16_t attributeIDListLen = de_get_len_safe(attributeIDList, param_len); 389 if (!sdp_attribute_list_valid(attributeIDList) == false){ 390 return sdp_create_error_response(transaction_id, 0x0003); /// invalid request syntax 391 } 392 // assert attributeIDList is contained in param_len 393 if (!attributeIDListLen) return 0; 394 // assert continuation state len is contained in param_len 395 if (param_len < 1) return 0; 396 uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen]; 397 // assert continuation state is contained in param_len 398 if ((1 + continuationState[0]) > param_len) return 0; 399 400 // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block 401 uint16_t maximumAttributeByteCount2 = remote_mtu - 12; 402 if (maximumAttributeByteCount2 < maximumAttributeByteCount) { 403 maximumAttributeByteCount = maximumAttributeByteCount2; 404 } 405 406 // continuation state contains: index of next service record to examine 407 // continuation state contains: byte offset into this service record 408 uint16_t continuation_service_index = 0; 409 uint16_t continuation_offset = 0; 410 if (continuationState[0] == 4){ 411 continuation_service_index = big_endian_read_16(continuationState, 1); 412 continuation_offset = big_endian_read_16(continuationState, 3); 413 } 414 415 // log_info("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u", continuation_service_index, continuation_offset, maximumAttributeByteCount); 416 417 // AttributeLists - starts at offset 7 418 uint16_t pos = 7; 419 420 // add DES with total size for first request 421 if ((continuation_service_index == 0) && (continuation_offset == 0)){ 422 uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList); 423 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size); 424 // log_info("total response size %u", total_response_size); 425 pos += 3; 426 maximumAttributeByteCount -= 3; 427 } 428 429 // create attribute list 430 int first_answer = 1; 431 int continuation = 0; 432 uint16_t current_service_index = 0; 433 btstack_linked_item_t *it = (btstack_linked_item_t *) sdp_server_service_records; 434 for ( ; it ; it = it->next, ++current_service_index){ 435 service_record_item_t * item = (service_record_item_t *) it; 436 437 if (current_service_index < continuation_service_index ) continue; 438 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 439 440 if (continuation_offset == 0){ 441 442 // get size of this record 443 uint16_t filtered_attributes_size = sdp_get_filtered_size(item->service_record, attributeIDList); 444 445 // stop if complete record doesn't fits into response but we already have a partial response 446 if (((filtered_attributes_size + 3) > maximumAttributeByteCount) && !first_answer) { 447 continuation = 1; 448 break; 449 } 450 451 // store DES 452 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); 453 pos += 3; 454 maximumAttributeByteCount -= 3; 455 } 456 457 first_answer = 0; 458 459 // copy maximumAttributeByteCount from record 460 uint16_t bytes_used; 461 int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); 462 pos += bytes_used; 463 maximumAttributeByteCount -= bytes_used; 464 465 if (complete) { 466 continuation_offset = 0; 467 continue; 468 } 469 470 continuation = 1; 471 continuation_offset += bytes_used; 472 break; 473 } 474 475 uint16_t attributeListsByteCount = pos - 7; 476 477 // Continuation State 478 if (continuation){ 479 sdp_response_buffer[pos++] = 4; 480 big_endian_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index); 481 pos += 2; 482 big_endian_store_16(sdp_response_buffer, pos, continuation_offset); 483 pos += 2; 484 } else { 485 // complete 486 sdp_response_buffer[pos++] = 0; 487 } 488 489 // create SDP header 490 sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse; 491 big_endian_store_16(sdp_response_buffer, 1, transaction_id); 492 big_endian_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload 493 big_endian_store_16(sdp_response_buffer, 5, attributeListsByteCount); 494 495 return pos; 496 } 497 498 static void sdp_respond(void){ 499 if (!sdp_server_response_size ) return; 500 if (!sdp_server_l2cap_cid) return; 501 502 // update state before sending packet (avoid getting called when new l2cap credit gets emitted) 503 uint16_t size = sdp_server_response_size; 504 sdp_server_response_size = 0; 505 l2cap_send(sdp_server_l2cap_cid, sdp_response_buffer, size); 506 } 507 508 // @pre space in list 509 static void sdp_waiting_list_add(uint16_t cid){ 510 sdp_server_l2cap_waiting_list_cids[sdp_server_l2cap_waiting_list_count++] = cid; 511 } 512 513 // @pre at least one item in list 514 static uint16_t sdp_waiting_list_get(void){ 515 uint16_t cid = sdp_server_l2cap_waiting_list_cids[0]; 516 sdp_server_l2cap_waiting_list_count--; 517 if (sdp_server_l2cap_waiting_list_count){ 518 memmove(&sdp_server_l2cap_waiting_list_cids[0], &sdp_server_l2cap_waiting_list_cids[1], sdp_server_l2cap_waiting_list_count * sizeof(uint16_t)); 519 } 520 return cid; 521 } 522 523 // we assume that we don't get two requests in a row 524 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 525 uint16_t transaction_id; 526 sdp_pdu_id_t pdu_id; 527 uint16_t remote_mtu; 528 uint16_t param_len; 529 530 switch (packet_type) { 531 532 case L2CAP_DATA_PACKET: 533 pdu_id = (sdp_pdu_id_t) packet[0]; 534 transaction_id = big_endian_read_16(packet, 1); 535 param_len = big_endian_read_16(packet, 3); 536 remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel); 537 // account for our buffer 538 if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){ 539 remote_mtu = SDP_RESPONSE_BUFFER_SIZE; 540 } 541 // validate parm_len against packet size 542 if ((param_len + 5) > size) { 543 // just clear pdu_id 544 pdu_id = SDP_ErrorResponse; 545 } 546 547 // log_info("SDP Request: type %u, transaction id %u, len %u, mtu %u", pdu_id, transaction_id, param_len, remote_mtu); 548 switch (pdu_id){ 549 550 case SDP_ServiceSearchRequest: 551 sdp_server_response_size = sdp_handle_service_search_request(packet, remote_mtu); 552 break; 553 554 case SDP_ServiceAttributeRequest: 555 sdp_server_response_size = sdp_handle_service_attribute_request(packet, remote_mtu); 556 break; 557 558 case SDP_ServiceSearchAttributeRequest: 559 sdp_server_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu); 560 break; 561 562 default: 563 sdp_server_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax 564 break; 565 } 566 if (!sdp_server_response_size) break; 567 l2cap_request_can_send_now_event(sdp_server_l2cap_cid); 568 break; 569 570 case HCI_EVENT_PACKET: 571 572 switch (hci_event_packet_get_type(packet)) { 573 574 case L2CAP_EVENT_INCOMING_CONNECTION: 575 if (sdp_server_l2cap_cid) { 576 // try to queue up 577 if (sdp_server_l2cap_waiting_list_count < SDP_WAITING_LIST_MAX_COUNT){ 578 sdp_waiting_list_add(channel); 579 log_info("busy, queing incoming cid 0x%04x, now %u waiting", channel, sdp_server_l2cap_waiting_list_count); 580 break; 581 } 582 583 // CONNECTION REJECTED DUE TO LIMITED RESOURCES 584 l2cap_decline_connection(channel); 585 break; 586 } 587 // accept 588 sdp_server_l2cap_cid = channel; 589 sdp_server_response_size = 0; 590 l2cap_accept_connection(sdp_server_l2cap_cid); 591 break; 592 593 case L2CAP_EVENT_CHANNEL_OPENED: 594 if (packet[2]) { 595 // open failed -> reset 596 sdp_server_l2cap_cid = 0; 597 } 598 break; 599 600 case L2CAP_EVENT_CAN_SEND_NOW: 601 sdp_respond(); 602 break; 603 604 case L2CAP_EVENT_CHANNEL_CLOSED: 605 if (channel == sdp_server_l2cap_cid){ 606 // reset 607 sdp_server_l2cap_cid = 0; 608 609 // other request queued? 610 if (!sdp_server_l2cap_waiting_list_count) break; 611 612 // get first item 613 sdp_server_l2cap_cid = sdp_waiting_list_get(); 614 615 log_info("disconnect, accept queued cid 0x%04x, now %u waiting", sdp_server_l2cap_cid, sdp_server_l2cap_waiting_list_count); 616 617 // accept connection 618 sdp_server_response_size = 0; 619 l2cap_accept_connection(sdp_server_l2cap_cid); 620 } 621 break; 622 623 default: 624 // other event 625 break; 626 } 627 break; 628 629 default: 630 // other packet type 631 break; 632 } 633 } 634 635