Norimasa Okamoto
/
BTstack
BTstack Bluetooth stack
Embed:
(wiki syntax)
Show/hide line numbers
sdp.c
00001 /* 00002 * Copyright (C) 2009-2012 by Matthias Ringwald 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holders nor the names of 00014 * contributors may be used to endorse or promote products derived 00015 * from this software without specific prior written permission. 00016 * 4. Any redistribution, use, or modification is done solely for 00017 * personal benefit and not for any commercial purpose or for 00018 * monetary gain. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS 00021 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00023 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 00024 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00025 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00026 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 00027 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 00028 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00029 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 00030 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00031 * SUCH DAMAGE. 00032 * 00033 * Please inquire about commercial licensing options at btstack@ringwald.ch 00034 * 00035 */ 00036 00037 /* 00038 * Implementation of the Service Discovery Protocol Server 00039 */ 00040 00041 #include "sdp.h" 00042 00043 00044 #include <stdio.h> 00045 #include <string.h> 00046 00047 #include <btstack/sdp_util.h> 00048 00049 #include "hci_dump.h" 00050 #include "l2cap.h" 00051 00052 #include "debug.h" 00053 00054 // max reserved ServiceRecordHandle 00055 #define maxReservedServiceRecordHandle 0xffff 00056 00057 // max SDP response 00058 #define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_BUFFER_SIZE-HCI_ACL_HEADER_SIZE) 00059 00060 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 00061 00062 // registered service records 00063 static linked_list_t sdp_service_records = NULL; 00064 00065 // our handles start after the reserved range 00066 static uint32_t sdp_next_service_record_handle = maxReservedServiceRecordHandle + 2; 00067 00068 static uint8_t sdp_response_buffer[SDP_RESPONSE_BUFFER_SIZE]; 00069 00070 static void (*app_packet_handler)(void * connection, uint8_t packet_type, 00071 uint16_t channel, uint8_t *packet, uint16_t size) = NULL; 00072 00073 static uint16_t l2cap_cid = 0; 00074 static uint16_t sdp_response_size = 0; 00075 00076 void sdp_init(){ 00077 // register with l2cap psm sevices - max MTU 00078 l2cap_register_service_internal(NULL, sdp_packet_handler, PSM_SDP, 0xffff); 00079 } 00080 00081 // register packet handler 00082 void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, 00083 uint16_t channel, uint8_t *packet, uint16_t size)){ 00084 app_packet_handler = handler; 00085 l2cap_cid = 0; 00086 } 00087 00088 uint32_t sdp_get_service_record_handle(uint8_t * record){ 00089 uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle); 00090 if (!serviceRecordHandleAttribute) return 0; 00091 if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0; 00092 if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0; 00093 return READ_NET_32(serviceRecordHandleAttribute, 1); 00094 } 00095 00096 // data: event(8), len(8), status(8), service_record_handle(32) 00097 static void sdp_emit_service_registered(void *connection, uint32_t handle, uint8_t status) { 00098 if (!app_packet_handler) return; 00099 uint8_t event[7]; 00100 event[0] = SDP_SERVICE_REGISTERED; 00101 event[1] = sizeof(event) - 2; 00102 event[2] = status; 00103 bt_store_32(event, 3, handle); 00104 hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event)); 00105 (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event)); 00106 } 00107 00108 service_record_item_t * sdp_get_record_for_handle(uint32_t handle){ 00109 linked_item_t *it; 00110 for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){ 00111 service_record_item_t * item = (service_record_item_t *) it; 00112 if (item->service_record_handle == handle){ 00113 return item; 00114 } 00115 } 00116 return NULL; 00117 } 00118 00119 // get next free, unregistered service record handle 00120 uint32_t sdp_create_service_record_handle(void){ 00121 uint32_t handle = 0; 00122 do { 00123 handle = sdp_next_service_record_handle++; 00124 if (sdp_get_record_for_handle(handle)) handle = 0; 00125 } while (handle == 0); 00126 return handle; 00127 } 00128 00129 #ifdef EMBEDDED 00130 00131 // register service record internally - this special version doesn't copy the record, it should not be freeed 00132 // pre: AttributeIDs are in ascending order 00133 // pre: ServiceRecordHandle is first attribute and valid 00134 // pre: record 00135 // @returns ServiceRecordHandle or 0 if registration failed 00136 uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item){ 00137 // get user record handle 00138 uint32_t record_handle = record_item->service_record_handle; 00139 // get actual record 00140 uint8_t *record = record_item->service_record; 00141 00142 // check for ServiceRecordHandle attribute, returns pointer or null 00143 uint8_t * req_record_handle = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle); 00144 if (!req_record_handle) { 00145 log_error("SDP Error - record does not contain ServiceRecordHandle attribute\n"); 00146 return 0; 00147 } 00148 00149 // validate service record handle is not in reserved range 00150 if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0; 00151 00152 // check if already in use 00153 if (record_handle) { 00154 if (sdp_get_record_for_handle(record_handle)) { 00155 record_handle = 0; 00156 } 00157 } 00158 00159 // create new handle if needed 00160 if (!record_handle){ 00161 record_handle = sdp_create_service_record_handle(); 00162 // Write the handle back into the record too 00163 record_item->service_record_handle = record_handle; 00164 sdp_set_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle, record_handle); 00165 } 00166 00167 // add to linked list 00168 linked_list_add(&sdp_service_records, (linked_item_t *) record_item); 00169 00170 sdp_emit_service_registered(connection, 0, record_item->service_record_handle); 00171 00172 return record_handle; 00173 } 00174 00175 #else 00176 00177 // AttributeIDList used to remove ServiceRecordHandle 00178 static const uint8_t removeServiceRecordHandleAttributeIDList[] = { 0x36, 0x00, 0x05, 0x0A, 0x00, 0x01, 0xFF, 0xFF }; 00179 00180 // register service record internally - the normal version creates a copy of the record 00181 // pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present 00182 // @returns ServiceRecordHandle or 0 if registration failed 00183 uint32_t sdp_register_service_internal(void *connection, uint8_t * record){ 00184 00185 // dump for now 00186 // printf("Register service record\n"); 00187 // de_dump_data_element(record); 00188 00189 // get user record handle 00190 uint32_t record_handle = sdp_get_service_record_handle(record); 00191 00192 // validate service record handle is not in reserved range 00193 if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0; 00194 00195 // check if already in use 00196 if (record_handle) { 00197 if (sdp_get_record_for_handle(record_handle)) { 00198 record_handle = 0; 00199 } 00200 } 00201 00202 // create new handle if needed 00203 if (!record_handle){ 00204 record_handle = sdp_create_service_record_handle(); 00205 } 00206 00207 // calculate size of new service record: DES (2 byte len) 00208 // + ServiceRecordHandle attribute (UINT16 UINT32) + size of existing attributes 00209 uint16_t recordSize = 3 + (3 + 5) + de_get_data_size(record); 00210 00211 // alloc memory for new service_record_item 00212 service_record_item_t * newRecordItem = (service_record_item_t *) malloc(recordSize + sizeof(service_record_item_t)); 00213 if (!newRecordItem) { 00214 sdp_emit_service_registered(connection, 0, BTSTACK_MEMORY_ALLOC_FAILED); 00215 return 0; 00216 } 00217 // link new service item to client connection 00218 newRecordItem->connection = connection; 00219 00220 // set new handle 00221 newRecordItem->service_record_handle = record_handle; 00222 00223 // create updated service record 00224 uint8_t * newRecord = (uint8_t *) &(newRecordItem->service_record); 00225 00226 // create DES for new record 00227 de_create_sequence(newRecord); 00228 00229 // set service record handle 00230 de_add_number(newRecord, DE_UINT, DE_SIZE_16, 0); 00231 de_add_number(newRecord, DE_UINT, DE_SIZE_32, record_handle); 00232 00233 // add other attributes 00234 sdp_append_attributes_in_attributeIDList(record, (uint8_t *) removeServiceRecordHandleAttributeIDList, 0, recordSize, newRecord); 00235 00236 // dump for now 00237 // de_dump_data_element(newRecord); 00238 // printf("reserved size %u, actual size %u\n", recordSize, de_get_len(newRecord)); 00239 00240 // add to linked list 00241 linked_list_add(&sdp_service_records, (linked_item_t *) newRecordItem); 00242 00243 sdp_emit_service_registered(connection, 0, newRecordItem->service_record_handle); 00244 00245 return record_handle; 00246 } 00247 00248 #endif 00249 00250 // unregister service record internally 00251 // 00252 // makes sure one client cannot remove service records of other clients 00253 // 00254 void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle){ 00255 service_record_item_t * record_item = sdp_get_record_for_handle(service_record_handle); 00256 if (record_item && record_item->connection == connection) { 00257 linked_list_remove(&sdp_service_records, (linked_item_t *) record_item); 00258 } 00259 } 00260 00261 // remove all service record for a client connection 00262 void sdp_unregister_services_for_connection(void *connection){ 00263 linked_item_t *it = (linked_item_t *) &sdp_service_records; 00264 while (it->next){ 00265 service_record_item_t *record_item = (service_record_item_t *) it->next; 00266 if (record_item->connection == connection){ 00267 it->next = it->next->next; 00268 #ifndef EMBEDDED 00269 free(record_item); 00270 #endif 00271 } else { 00272 it = it->next; 00273 } 00274 } 00275 } 00276 00277 // PDU 00278 // PDU ID (1), Transaction ID (2), Param Length (2), Param 1, Param 2, .. 00279 00280 int sdp_create_error_response(uint16_t transaction_id, uint16_t error_code){ 00281 sdp_response_buffer[0] = SDP_ErrorResponse; 00282 net_store_16(sdp_response_buffer, 1, transaction_id); 00283 net_store_16(sdp_response_buffer, 3, 2); 00284 net_store_16(sdp_response_buffer, 5, error_code); // invalid syntax 00285 return 7; 00286 } 00287 00288 int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu){ 00289 00290 // get request details 00291 uint16_t transaction_id = READ_NET_16(packet, 1); 00292 // not used yet - uint16_t param_len = READ_NET_16(packet, 3); 00293 uint8_t * serviceSearchPattern = &packet[5]; 00294 uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern); 00295 uint16_t maximumServiceRecordCount = READ_NET_16(packet, 5 + serviceSearchPatternLen); 00296 uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2]; 00297 00298 // calc maxumumServiceRecordCount based on remote MTU 00299 uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4; 00300 00301 // continuation state contains index of next service record to examine 00302 int continuation = 0; 00303 uint16_t continuation_index = 0; 00304 if (continuationState[0] == 2){ 00305 continuation_index = READ_NET_16(continuationState, 1); 00306 } 00307 00308 // get and limit total count 00309 linked_item_t *it; 00310 uint16_t total_service_count = 0; 00311 for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){ 00312 service_record_item_t * item = (service_record_item_t *) it; 00313 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 00314 total_service_count++; 00315 } 00316 if (total_service_count > maximumServiceRecordCount){ 00317 total_service_count = maximumServiceRecordCount; 00318 } 00319 00320 // ServiceRecordHandleList at 9 00321 uint16_t pos = 9; 00322 uint16_t current_service_count = 0; 00323 uint16_t current_service_index = 0; 00324 uint16_t matching_service_count = 0; 00325 for (it = (linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index){ 00326 service_record_item_t * item = (service_record_item_t *) it; 00327 00328 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 00329 matching_service_count++; 00330 00331 if (current_service_index < continuation_index) continue; 00332 00333 net_store_32(sdp_response_buffer, pos, item->service_record_handle); 00334 pos += 4; 00335 current_service_count++; 00336 00337 if (matching_service_count >= total_service_count) break; 00338 00339 if (current_service_count >= maxNrServiceRecordsPerResponse){ 00340 continuation = 1; 00341 continuation_index = current_service_index + 1; 00342 break; 00343 } 00344 } 00345 00346 // Store continuation state 00347 if (continuation) { 00348 sdp_response_buffer[pos++] = 2; 00349 net_store_16(sdp_response_buffer, pos, continuation_index); 00350 pos += 2; 00351 } else { 00352 sdp_response_buffer[pos++] = 0; 00353 } 00354 00355 // header 00356 sdp_response_buffer[0] = SDP_ServiceSearchResponse; 00357 net_store_16(sdp_response_buffer, 1, transaction_id); 00358 net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload 00359 net_store_16(sdp_response_buffer, 5, total_service_count); 00360 net_store_16(sdp_response_buffer, 7, current_service_count); 00361 00362 return pos; 00363 } 00364 00365 int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){ 00366 00367 // get request details 00368 uint16_t transaction_id = READ_NET_16(packet, 1); 00369 // not used yet - uint16_t param_len = READ_NET_16(packet, 3); 00370 uint32_t serviceRecordHandle = READ_NET_32(packet, 5); 00371 uint16_t maximumAttributeByteCount = READ_NET_16(packet, 9); 00372 uint8_t * attributeIDList = &packet[11]; 00373 uint16_t attributeIDListLen = de_get_len(attributeIDList); 00374 uint8_t * continuationState = &packet[11+attributeIDListLen]; 00375 00376 // calc maximumAttributeByteCount based on remote MTU 00377 uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3); 00378 if (maximumAttributeByteCount2 < maximumAttributeByteCount) { 00379 maximumAttributeByteCount = maximumAttributeByteCount2; 00380 } 00381 00382 // continuation state contains the offset into the complete response 00383 uint16_t continuation_offset = 0; 00384 if (continuationState[0] == 2){ 00385 continuation_offset = READ_NET_16(continuationState, 1); 00386 } 00387 00388 // get service record 00389 service_record_item_t * item = sdp_get_record_for_handle(serviceRecordHandle); 00390 if (!item){ 00391 // service record handle doesn't exist 00392 return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle 00393 } 00394 00395 00396 // AttributeList - starts at offset 7 00397 uint16_t pos = 7; 00398 00399 if (continuation_offset == 0){ 00400 00401 // get size of this record 00402 uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList); 00403 00404 // store DES 00405 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); 00406 maximumAttributeByteCount -= 3; 00407 pos += 3; 00408 } 00409 00410 // copy maximumAttributeByteCount from record 00411 uint16_t bytes_used; 00412 int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); 00413 pos += bytes_used; 00414 00415 uint16_t attributeListByteCount = pos - 7; 00416 00417 if (complete) { 00418 sdp_response_buffer[pos++] = 0; 00419 } else { 00420 continuation_offset += bytes_used; 00421 sdp_response_buffer[pos++] = 2; 00422 net_store_16(sdp_response_buffer, pos, continuation_offset); 00423 pos += 2; 00424 } 00425 00426 // header 00427 sdp_response_buffer[0] = SDP_ServiceAttributeResponse; 00428 net_store_16(sdp_response_buffer, 1, transaction_id); 00429 net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload 00430 net_store_16(sdp_response_buffer, 5, attributeListByteCount); 00431 00432 return pos; 00433 } 00434 00435 static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){ 00436 uint16_t total_response_size = 0; 00437 linked_item_t *it; 00438 for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){ 00439 service_record_item_t * item = (service_record_item_t *) it; 00440 00441 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 00442 00443 // for all service records that match 00444 total_response_size += 3 + spd_get_filtered_size(item->service_record, attributeIDList); 00445 } 00446 return total_response_size; 00447 } 00448 00449 int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){ 00450 00451 // SDP header before attribute sevice list: 7 00452 // Continuation, worst case: 5 00453 00454 // get request details 00455 uint16_t transaction_id = READ_NET_16(packet, 1); 00456 // not used yet - uint16_t param_len = READ_NET_16(packet, 3); 00457 uint8_t * serviceSearchPattern = &packet[5]; 00458 uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern); 00459 uint16_t maximumAttributeByteCount = READ_NET_16(packet, 5 + serviceSearchPatternLen); 00460 uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2]; 00461 uint16_t attributeIDListLen = de_get_len(attributeIDList); 00462 uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen]; 00463 00464 // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block 00465 uint16_t maximumAttributeByteCount2 = remote_mtu - 12; 00466 if (maximumAttributeByteCount2 < maximumAttributeByteCount) { 00467 maximumAttributeByteCount = maximumAttributeByteCount2; 00468 } 00469 00470 // continuation state contains: index of next service record to examine 00471 // continuation state contains: byte offset into this service record 00472 uint16_t continuation_service_index = 0; 00473 uint16_t continuation_offset = 0; 00474 if (continuationState[0] == 4){ 00475 continuation_service_index = READ_NET_16(continuationState, 1); 00476 continuation_offset = READ_NET_16(continuationState, 3); 00477 } 00478 00479 // printf("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u\n", continuation_service_index, continuation_offset, maximumAttributeByteCount); 00480 00481 // AttributeLists - starts at offset 7 00482 uint16_t pos = 7; 00483 00484 // add DES with total size for first request 00485 if (continuation_service_index == 0 && continuation_offset == 0){ 00486 uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList); 00487 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size); 00488 // log_info("total response size %u\n", total_response_size); 00489 pos += 3; 00490 maximumAttributeByteCount -= 3; 00491 } 00492 00493 // create attribute list 00494 int first_answer = 1; 00495 int continuation = 0; 00496 uint16_t current_service_index = 0; 00497 linked_item_t *it = (linked_item_t *) sdp_service_records; 00498 for ( ; it ; it = it->next, ++current_service_index){ 00499 service_record_item_t * item = (service_record_item_t *) it; 00500 00501 if (current_service_index < continuation_service_index ) continue; 00502 if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; 00503 00504 if (continuation_offset == 0){ 00505 00506 // get size of this record 00507 uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList); 00508 00509 // stop if complete record doesn't fits into response but we already have a partial response 00510 if ((filtered_attributes_size + 3 > maximumAttributeByteCount) && !first_answer) { 00511 continuation = 1; 00512 break; 00513 } 00514 00515 // store DES 00516 de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); 00517 pos += 3; 00518 maximumAttributeByteCount -= 3; 00519 } 00520 00521 first_answer = 0; 00522 00523 // copy maximumAttributeByteCount from record 00524 uint16_t bytes_used; 00525 int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); 00526 pos += bytes_used; 00527 maximumAttributeByteCount -= bytes_used; 00528 00529 if (complete) { 00530 continuation_offset = 0; 00531 continue; 00532 } 00533 00534 continuation = 1; 00535 continuation_offset += bytes_used; 00536 break; 00537 } 00538 00539 uint16_t attributeListsByteCount = pos - 7; 00540 00541 // Continuation State 00542 if (continuation){ 00543 sdp_response_buffer[pos++] = 4; 00544 net_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index); 00545 pos += 2; 00546 net_store_16(sdp_response_buffer, pos, continuation_offset); 00547 pos += 2; 00548 } else { 00549 // complete 00550 sdp_response_buffer[pos++] = 0; 00551 } 00552 00553 // create SDP header 00554 sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse; 00555 net_store_16(sdp_response_buffer, 1, transaction_id); 00556 net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload 00557 net_store_16(sdp_response_buffer, 5, attributeListsByteCount); 00558 00559 return pos; 00560 } 00561 00562 static void sdp_try_respond(void){ 00563 if (!sdp_response_size ) return; 00564 if (!l2cap_cid) return; 00565 if (!l2cap_can_send_packet_now(l2cap_cid)) return; 00566 00567 // update state before sending packet (avoid getting called when new l2cap credit gets emitted) 00568 uint16_t size = sdp_response_size; 00569 sdp_response_size = 0; 00570 l2cap_send_internal(l2cap_cid, sdp_response_buffer, size); 00571 } 00572 00573 // we assume that we don't get two requests in a row 00574 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 00575 uint16_t transaction_id; 00576 SDP_PDU_ID_t pdu_id; 00577 uint16_t remote_mtu; 00578 // uint16_t param_len; 00579 00580 switch (packet_type) { 00581 00582 case L2CAP_DATA_PACKET: 00583 pdu_id = (SDP_PDU_ID_t) packet[0]; 00584 transaction_id = READ_NET_16(packet, 1); 00585 // param_len = READ_NET_16(packet, 3); 00586 remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel); 00587 // account for our buffer 00588 if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){ 00589 remote_mtu = SDP_RESPONSE_BUFFER_SIZE; 00590 } 00591 00592 // printf("SDP Request: type %u, transaction id %u, len %u, mtu %u\n", pdu_id, transaction_id, param_len, remote_mtu); 00593 switch (pdu_id){ 00594 00595 case SDP_ServiceSearchRequest: 00596 sdp_response_size = sdp_handle_service_search_request(packet, remote_mtu); 00597 break; 00598 00599 case SDP_ServiceAttributeRequest: 00600 sdp_response_size = sdp_handle_service_attribute_request(packet, remote_mtu); 00601 break; 00602 00603 case SDP_ServiceSearchAttributeRequest: 00604 sdp_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu); 00605 break; 00606 00607 default: 00608 sdp_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax 00609 break; 00610 } 00611 00612 sdp_try_respond(); 00613 00614 break; 00615 00616 case HCI_EVENT_PACKET: 00617 00618 switch (packet[0]) { 00619 00620 case L2CAP_EVENT_INCOMING_CONNECTION: 00621 if (l2cap_cid) { 00622 // CONNECTION REJECTED DUE TO LIMITED RESOURCES 00623 l2cap_decline_connection_internal(channel, 0x0d); 00624 break; 00625 } 00626 // accept 00627 l2cap_cid = channel; 00628 sdp_response_size = 0; 00629 l2cap_accept_connection_internal(channel); 00630 break; 00631 00632 case L2CAP_EVENT_CHANNEL_OPENED: 00633 if (packet[2]) { 00634 // open failed -> reset 00635 l2cap_cid = 0; 00636 } 00637 break; 00638 00639 case L2CAP_EVENT_CREDITS: 00640 case DAEMON_EVENT_HCI_PACKET_SENT: 00641 sdp_try_respond(); 00642 break; 00643 00644 case L2CAP_EVENT_CHANNEL_CLOSED: 00645 if (channel == l2cap_cid){ 00646 // reset 00647 l2cap_cid = 0; 00648 } 00649 break; 00650 00651 default: 00652 // other event 00653 break; 00654 } 00655 break; 00656 00657 default: 00658 // other packet type 00659 break; 00660 } 00661 } 00662
Generated on Tue Jul 12 2022 15:55:29 by 1.7.2