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 /* 39 * sdp_client.c 40 */ 41 42 #include "btstack_config.h" 43 #include "classic/sdp_client.h" 44 45 #include "hci_cmd.h" 46 47 #include "l2cap.h" 48 #include "classic/sdp_parser.h" 49 #include "classic/sdp_server.h" 50 #include "btstack_debug.h" 51 52 typedef enum { 53 INIT, W4_CONNECT, W2_SEND, W4_RESPONSE, QUERY_COMPLETE 54 } sdp_client_state_t; 55 56 57 void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 58 59 static uint16_t setup_service_search_attribute_request(uint8_t * data); 60 61 #ifdef ENABLE_SDP_EXTRA_QUERIES 62 static uint16_t setup_service_search_request(uint8_t * data); 63 static uint16_t setup_service_attribute_request(uint8_t * data); 64 static void parse_service_search_response(uint8_t* packet); 65 static void parse_service_attribute_response(uint8_t* packet); 66 static uint32_t serviceRecordHandle; 67 #endif 68 69 // SDP Client Query 70 static uint16_t mtu; 71 static uint16_t sdp_cid = 0x40; 72 static uint8_t * serviceSearchPattern; 73 static uint8_t * attributeIDList; 74 static uint16_t transactionID = 0; 75 static uint8_t continuationState[16]; 76 static uint8_t continuationStateLen; 77 static sdp_client_state_t sdp_client_state = INIT; 78 static SDP_PDU_ID_t PDU_ID = SDP_Invalid; 79 80 // TODO: inline if not needed (des(des)) 81 static void parse_attribute_lists(uint8_t* packet, uint16_t length){ 82 sdp_parser_handle_chunk(packet, length); 83 } 84 85 /* Queries the SDP service of the remote device given a service search pattern 86 and a list of attribute IDs. The remote data is handled by the SDP parser. The 87 SDP parser delivers attribute values and done event via a registered callback. */ 88 89 void sdp_client_query(bd_addr_t remote, uint8_t * des_serviceSearchPattern, uint8_t * des_attributeIDList){ 90 serviceSearchPattern = des_serviceSearchPattern; 91 attributeIDList = des_attributeIDList; 92 continuationStateLen = 0; 93 PDU_ID = SDP_ServiceSearchAttributeResponse; 94 95 sdp_client_state = W4_CONNECT; 96 l2cap_create_channel(sdp_packet_handler, remote, PSM_SDP, l2cap_max_mtu(), NULL); 97 } 98 99 static int can_send_now(uint16_t channel){ 100 if (sdp_client_state != W2_SEND) return 0; 101 if (!l2cap_can_send_packet_now(channel)) return 0; 102 return 1; 103 } 104 105 static void send_request(uint16_t channel){ 106 l2cap_reserve_packet_buffer(); 107 uint8_t * data = l2cap_get_outgoing_buffer(); 108 uint16_t request_len = 0; 109 110 switch (PDU_ID){ 111 #ifdef ENABLE_SDP_EXTRA_QUERIES 112 case SDP_ServiceSearchResponse: 113 request_len = setup_service_search_request(data); 114 break; 115 case SDP_ServiceAttributeResponse: 116 request_len = setup_service_attribute_request(data); 117 break; 118 #endif 119 case SDP_ServiceSearchAttributeResponse: 120 request_len = setup_service_search_attribute_request(data); 121 break; 122 default: 123 log_error("SDP Client send_request :: PDU ID invalid. %u", PDU_ID); 124 return; 125 } 126 127 // prevent re-entrance 128 sdp_client_state = W4_RESPONSE; 129 int err = l2cap_send_prepared(channel, request_len); 130 // l2cap_send_prepared shouldn't have failed as l2ap_can_send_packet_now() was true 131 switch (err){ 132 case 0: 133 log_debug("l2cap_send() -> OK"); 134 PDU_ID = SDP_Invalid; 135 break; 136 case BTSTACK_ACL_BUFFERS_FULL: 137 sdp_client_state = W2_SEND; 138 log_info("l2cap_send() ->BTSTACK_ACL_BUFFERS_FULL"); 139 break; 140 default: 141 sdp_client_state = W2_SEND; 142 log_error("l2cap_send() -> err %d", err); 143 break; 144 } 145 } 146 147 148 static void parse_service_search_attribute_response(uint8_t* packet){ 149 uint16_t offset = 3; 150 uint16_t parameterLength = big_endian_read_16(packet,offset); 151 offset+=2; 152 // AttributeListByteCount <= mtu 153 uint16_t attributeListByteCount = big_endian_read_16(packet,offset); 154 offset+=2; 155 156 if (attributeListByteCount > mtu){ 157 log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount."); 158 return; 159 } 160 161 // AttributeLists 162 parse_attribute_lists(packet+offset, attributeListByteCount); 163 offset+=attributeListByteCount; 164 165 continuationStateLen = packet[offset]; 166 offset++; 167 168 if (continuationStateLen > 16){ 169 log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in continuation state exceedes 16."); 170 return; 171 } 172 memcpy(continuationState, packet+offset, continuationStateLen); 173 offset+=continuationStateLen; 174 175 if (parameterLength != offset - 5){ 176 log_error("Error parsing ServiceSearchAttributeResponse: wrong size of parameters, number of expected bytes%u, actual number %u.", parameterLength, offset); 177 } 178 } 179 180 void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 181 // uint16_t handle; 182 if (packet_type == L2CAP_DATA_PACKET){ 183 uint16_t responseTransactionID = big_endian_read_16(packet,1); 184 if ( responseTransactionID != transactionID){ 185 log_error("Missmatching transaction ID, expected %u, found %u.", transactionID, responseTransactionID); 186 return; 187 } 188 189 if (packet[0] != SDP_ServiceSearchAttributeResponse 190 && packet[0] != SDP_ServiceSearchResponse 191 && packet[0] != SDP_ServiceAttributeResponse){ 192 log_error("Not a valid PDU ID, expected %u, %u or %u, found %u.", SDP_ServiceSearchResponse, 193 SDP_ServiceAttributeResponse, SDP_ServiceSearchAttributeResponse, packet[0]); 194 return; 195 } 196 197 PDU_ID = (SDP_PDU_ID_t)packet[0]; 198 log_info("SDP Client :: PDU ID. %u ,%u", PDU_ID, packet[0]); 199 switch (PDU_ID){ 200 #ifdef ENABLE_SDP_EXTRA_QUERIES 201 case SDP_ServiceSearchResponse: 202 parse_service_search_response(packet); 203 break; 204 case SDP_ServiceAttributeResponse: 205 parse_service_attribute_response(packet); 206 break; 207 #endif 208 case SDP_ServiceSearchAttributeResponse: 209 parse_service_search_attribute_response(packet); 210 break; 211 default: 212 log_error("SDP Client :: PDU ID invalid. %u ,%u", PDU_ID, packet[0]); 213 return; 214 } 215 216 // continuation set or DONE? 217 if (continuationStateLen == 0){ 218 log_info("SDP Client Query DONE! "); 219 sdp_client_state = QUERY_COMPLETE; 220 l2cap_disconnect(sdp_cid, 0); 221 // sdp_parser_handle_done(0); 222 return; 223 } 224 // prepare next request and send 225 sdp_client_state = W2_SEND; 226 if (can_send_now(sdp_cid)) send_request(sdp_cid); 227 return; 228 } 229 230 if (packet_type != HCI_EVENT_PACKET) return; 231 232 switch(packet[0]){ 233 case L2CAP_EVENT_TIMEOUT_CHECK: 234 log_info("sdp client: L2CAP_EVENT_TIMEOUT_CHECK"); 235 break; 236 case L2CAP_EVENT_CHANNEL_OPENED: 237 if (sdp_client_state != W4_CONNECT) break; 238 // data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16) 239 if (packet[2]) { 240 log_error("SDP Client Connection failed."); 241 sdp_parser_handle_done(packet[2]); 242 break; 243 } 244 sdp_cid = channel; 245 mtu = little_endian_read_16(packet, 17); 246 // handle = little_endian_read_16(packet, 9); 247 log_info("SDP Client Connected, cid %x, mtu %u.", sdp_cid, mtu); 248 249 sdp_client_state = W2_SEND; 250 if (can_send_now(sdp_cid)) send_request(sdp_cid); 251 252 break; 253 case L2CAP_EVENT_CAN_SEND_NOW: 254 if (can_send_now(sdp_cid)) send_request(sdp_cid); 255 break; 256 case L2CAP_EVENT_CHANNEL_CLOSED: { 257 if (sdp_cid != little_endian_read_16(packet, 2)) { 258 // log_info("Received L2CAP_EVENT_CHANNEL_CLOSED for cid %x, current cid %x\n", little_endian_read_16(packet, 2),sdp_cid); 259 break; 260 } 261 log_info("SDP Client disconnected."); 262 uint8_t status = sdp_client_state == QUERY_COMPLETE ? 0 : SDP_QUERY_INCOMPLETE; 263 sdp_client_state = INIT; 264 sdp_parser_handle_done(status); 265 break; 266 } 267 default: 268 break; 269 } 270 } 271 272 273 static uint16_t setup_service_search_attribute_request(uint8_t * data){ 274 275 uint16_t offset = 0; 276 transactionID++; 277 // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest; 278 data[offset++] = SDP_ServiceSearchAttributeRequest; 279 // uint16_t transactionID 280 big_endian_store_16(data, offset, transactionID); 281 offset += 2; 282 283 // param legnth 284 offset += 2; 285 286 // parameters: 287 // ServiceSearchPattern - DES (min 1 UUID, max 12) 288 uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern); 289 memcpy(data + offset, serviceSearchPattern, serviceSearchPatternLen); 290 offset += serviceSearchPatternLen; 291 292 // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu 293 big_endian_store_16(data, offset, mtu); 294 offset += 2; 295 296 // AttibuteIDList 297 uint16_t attributeIDListLen = de_get_len(attributeIDList); 298 memcpy(data + offset, attributeIDList, attributeIDListLen); 299 offset += attributeIDListLen; 300 301 // ContinuationState - uint8_t number of cont. bytes N<=16 302 data[offset++] = continuationStateLen; 303 // - N-bytes previous response from server 304 memcpy(data + offset, continuationState, continuationStateLen); 305 offset += continuationStateLen; 306 307 // uint16_t paramLength 308 big_endian_store_16(data, 3, offset - 5); 309 310 return offset; 311 } 312 313 #ifdef ENABLE_SDP_EXTRA_QUERIES 314 void parse_service_record_handle_list(uint8_t* packet, uint16_t total_count, uint16_t current_count){ 315 sdp_parser_handle_service_search(packet, total_count, current_count); 316 } 317 318 static uint16_t setup_service_search_request(uint8_t * data){ 319 uint16_t offset = 0; 320 transactionID++; 321 // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest; 322 data[offset++] = SDP_ServiceSearchRequest; 323 // uint16_t transactionID 324 big_endian_store_16(data, offset, transactionID); 325 offset += 2; 326 327 // param legnth 328 offset += 2; 329 330 // parameters: 331 // ServiceSearchPattern - DES (min 1 UUID, max 12) 332 uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern); 333 memcpy(data + offset, serviceSearchPattern, serviceSearchPatternLen); 334 offset += serviceSearchPatternLen; 335 336 // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu 337 big_endian_store_16(data, offset, mtu); 338 offset += 2; 339 340 // ContinuationState - uint8_t number of cont. bytes N<=16 341 data[offset++] = continuationStateLen; 342 // - N-bytes previous response from server 343 memcpy(data + offset, continuationState, continuationStateLen); 344 offset += continuationStateLen; 345 346 // uint16_t paramLength 347 big_endian_store_16(data, 3, offset - 5); 348 349 return offset; 350 } 351 352 353 static uint16_t setup_service_attribute_request(uint8_t * data){ 354 355 uint16_t offset = 0; 356 transactionID++; 357 // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest; 358 data[offset++] = SDP_ServiceAttributeRequest; 359 // uint16_t transactionID 360 big_endian_store_16(data, offset, transactionID); 361 offset += 2; 362 363 // param legnth 364 offset += 2; 365 366 // parameters: 367 // ServiceRecordHandle 368 big_endian_store_32(data, offset, serviceRecordHandle); 369 offset += 4; 370 371 // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu 372 big_endian_store_16(data, offset, mtu); 373 offset += 2; 374 375 // AttibuteIDList 376 uint16_t attributeIDListLen = de_get_len(attributeIDList); 377 memcpy(data + offset, attributeIDList, attributeIDListLen); 378 offset += attributeIDListLen; 379 380 // ContinuationState - uint8_t number of cont. bytes N<=16 381 data[offset++] = continuationStateLen; 382 // - N-bytes previous response from server 383 memcpy(data + offset, continuationState, continuationStateLen); 384 offset += continuationStateLen; 385 386 // uint16_t paramLength 387 big_endian_store_16(data, 3, offset - 5); 388 389 return offset; 390 } 391 392 static void parse_service_search_response(uint8_t* packet){ 393 uint16_t offset = 3; 394 uint16_t parameterLength = big_endian_read_16(packet,offset); 395 offset+=2; 396 397 uint16_t totalServiceRecordCount = big_endian_read_16(packet,offset); 398 offset+=2; 399 400 uint16_t currentServiceRecordCount = big_endian_read_16(packet,offset); 401 offset+=2; 402 if (currentServiceRecordCount > totalServiceRecordCount){ 403 log_error("CurrentServiceRecordCount is larger then TotalServiceRecordCount."); 404 return; 405 } 406 407 parse_service_record_handle_list(packet+offset, totalServiceRecordCount, currentServiceRecordCount); 408 offset+=(currentServiceRecordCount * 4); 409 410 continuationStateLen = packet[offset]; 411 offset++; 412 if (continuationStateLen > 16){ 413 log_error("Error parsing ServiceSearchResponse: Number of bytes in continuation state exceedes 16."); 414 return; 415 } 416 memcpy(continuationState, packet+offset, continuationStateLen); 417 offset+=continuationStateLen; 418 419 if (parameterLength != offset - 5){ 420 log_error("Error parsing ServiceSearchResponse: wrong size of parameters, number of expected bytes%u, actual number %u.", parameterLength, offset); 421 } 422 } 423 424 static void parse_service_attribute_response(uint8_t* packet){ 425 uint16_t offset = 3; 426 uint16_t parameterLength = big_endian_read_16(packet,offset); 427 offset+=2; 428 429 // AttributeListByteCount <= mtu 430 uint16_t attributeListByteCount = big_endian_read_16(packet,offset); 431 offset+=2; 432 433 if (attributeListByteCount > mtu){ 434 log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount."); 435 return; 436 } 437 438 // AttributeLists 439 parse_attribute_lists(packet+offset, attributeListByteCount); 440 offset+=attributeListByteCount; 441 442 continuationStateLen = packet[offset]; 443 offset++; 444 445 if (continuationStateLen > 16){ 446 log_error("Error parsing ServiceAttributeResponse: Number of bytes in continuation state exceedes 16."); 447 return; 448 } 449 memcpy(continuationState, packet+offset, continuationStateLen); 450 offset+=continuationStateLen; 451 452 if (parameterLength != offset - 5){ 453 log_error("Error parsing ServiceAttributeResponse: wrong size of parameters, number of expected bytes%u, actual number %u.", parameterLength, offset); 454 } 455 } 456 457 void sdp_client_service_attribute_search(bd_addr_t remote, uint32_t search_serviceRecordHandle, uint8_t * des_attributeIDList){ 458 serviceRecordHandle = search_serviceRecordHandle; 459 attributeIDList = des_attributeIDList; 460 continuationStateLen = 0; 461 PDU_ID = SDP_ServiceAttributeResponse; 462 463 sdp_client_state = W4_CONNECT; 464 l2cap_create_channel(sdp_packet_handler, remote, PSM_SDP, l2cap_max_mtu(), NULL); 465 } 466 467 void sdp_client_service_search(bd_addr_t remote, uint8_t * des_serviceSearchPattern){ 468 serviceSearchPattern = des_serviceSearchPattern; 469 continuationStateLen = 0; 470 PDU_ID = SDP_ServiceSearchResponse; 471 472 sdp_client_state = W4_CONNECT; 473 l2cap_create_channel(sdp_packet_handler, remote, PSM_SDP, l2cap_max_mtu(), NULL); 474 } 475 #endif 476 477