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_util.c 40 */ 41 42 #include "classic/sdp_util.h" 43 #include "utils.h" 44 #include "btstack-config.h" 45 #include "bluetooth.h" 46 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <stdint.h> 51 #include <inttypes.h> // PRIx32 52 53 #ifdef SDP_DES_DUMP 54 // workaround for missing PRIx32 on mspgcc (16-bit MCU) 55 #ifndef PRIx32 56 #warning Using own: #define PRIx32 "lx" 57 #define PRIx32 "lx" 58 #endif 59 // date element type names 60 const char * const type_names[] = { "NIL", "UINT", "INT", "UUID", "STRING", "BOOL", "DES", "DEA", "URL"}; 61 #endif 62 63 // MARK: DataElement getter 64 de_size_t de_get_size_type(uint8_t *header){ 65 return (de_size_t) (header[0] & 7); 66 } 67 68 de_type_t de_get_element_type(uint8_t *header){ 69 return (de_type_t) (header[0] >> 3); 70 } 71 72 int de_get_header_size(uint8_t * header){ 73 de_size_t de_size = de_get_size_type(header); 74 if (de_size <= DE_SIZE_128) { 75 return 1; 76 } 77 return 1 + (1 << (de_size-DE_SIZE_VAR_8)); 78 } 79 80 int de_get_data_size(uint8_t * header){ 81 uint32_t result = 0; 82 de_type_t de_type = de_get_element_type(header); 83 de_size_t de_size = de_get_size_type(header); 84 switch (de_size){ 85 case DE_SIZE_VAR_8: 86 result = header[1]; 87 break; 88 case DE_SIZE_VAR_16: 89 result = READ_NET_16(header,1); 90 break; 91 case DE_SIZE_VAR_32: 92 result = READ_NET_32(header,1); 93 break; 94 default: 95 // case DE_SIZE_8: 96 // case DE_SIZE_16: 97 // case DE_SIZE_32: 98 // case DE_SIZE_64: 99 // case DE_SIZE_128: 100 if (de_type == DE_NIL) return 0; 101 return 1 << de_size; 102 } 103 return result; 104 } 105 106 int de_get_len(uint8_t *header){ 107 return de_get_header_size(header) + de_get_data_size(header); 108 } 109 110 // @returns OK, if UINT16 value was read 111 int de_element_get_uint16(uint8_t * element, uint16_t * value){ 112 if (de_get_size_type(element) != DE_SIZE_16) return 0; 113 *value = READ_NET_16(element, de_get_header_size(element)); 114 return 1; 115 } 116 117 // @returns: element is valid UUID 118 int de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element){ 119 de_type_t uuidType = de_get_element_type(element); 120 de_size_t uuidSize = de_get_size_type(element); 121 if (uuidType != DE_UUID) return 0; 122 uint32_t shortUUID; 123 switch (uuidSize){ 124 case DE_SIZE_16: 125 shortUUID = READ_NET_16(element, 1); 126 break; 127 case DE_SIZE_32: 128 shortUUID = READ_NET_32(element, 1); 129 break; 130 case DE_SIZE_128: 131 memcpy(uuid128, element+1, 16); 132 return 1; 133 default: 134 return 0; 135 } 136 sdp_normalize_uuid(uuid128, shortUUID); 137 return 1; 138 } 139 140 // @returns 0 if no UUID16 or UUID32 is present, and UUID32 otherwise 141 uint32_t de_get_uuid32(uint8_t * element){ 142 uint8_t uuid128[16]; 143 int validUuid128 = de_get_normalized_uuid(uuid128, element); 144 if (!validUuid128) return 0; 145 int hasBlueoothBaseUuid = sdp_has_blueooth_base_uuid(uuid128); 146 if (!hasBlueoothBaseUuid) return 0; 147 return READ_NET_32(uuid128, 0); 148 } 149 150 // functions to create record 151 static void de_store_descriptor(uint8_t * header, de_type_t type, de_size_t size){ 152 header[0] = (type << 3) | size; 153 } 154 155 void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len){ 156 header[0] = (type << 3) | size; 157 switch (size){ 158 case DE_SIZE_VAR_8: 159 header[1] = len; 160 break; 161 case DE_SIZE_VAR_16: 162 net_store_16(header, 1, len); 163 break; 164 case DE_SIZE_VAR_32: 165 net_store_32(header, 1, len); 166 break; 167 default: 168 break; 169 } 170 } 171 172 // MARK: DataElement creation 173 174 /* starts a new sequence in empty buffer - first call */ 175 void de_create_sequence(uint8_t *header){ 176 de_store_descriptor_with_len( header, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length 177 }; 178 179 /* starts a sub-sequence, @returns handle for sub-sequence */ 180 uint8_t * de_push_sequence(uint8_t *header){ 181 int element_len = de_get_len(header); 182 de_store_descriptor_with_len(header+element_len, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length 183 return header + element_len; 184 } 185 186 /* closes the current sequence and updates the parent sequence */ 187 void de_pop_sequence(uint8_t * parent, uint8_t * child){ 188 int child_len = de_get_len(child); 189 int data_size_parent = READ_NET_16(parent,1); 190 net_store_16(parent, 1, data_size_parent + child_len); 191 } 192 193 /* adds a single number value and 16+32 bit UUID to the sequence */ 194 void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value){ 195 int data_size = READ_NET_16(seq,1); 196 int element_size = 1; // e.g. for DE_TYPE_NIL 197 de_store_descriptor(seq+3+data_size, type, size); 198 switch (size){ 199 case DE_SIZE_8: 200 if (type != DE_NIL){ 201 seq[4+data_size] = value; 202 element_size = 2; 203 } 204 break; 205 case DE_SIZE_16: 206 net_store_16(seq, 4+data_size, value); 207 element_size = 3; 208 break; 209 case DE_SIZE_32: 210 net_store_32(seq, 4+data_size, value); 211 element_size = 5; 212 break; 213 default: 214 break; 215 } 216 net_store_16(seq, 1, data_size+element_size); 217 } 218 219 /* add a single block of data, e.g. as DE_STRING, DE_URL */ 220 void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data){ 221 int data_size = READ_NET_16(seq,1); 222 if (size > 0xff) { 223 // use 16-bit lengh information (3 byte header) 224 de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_16, size); 225 data_size += 3; 226 } else { 227 // use 8-bit lengh information (2 byte header) 228 de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_8, size); 229 data_size += 2; 230 } 231 memcpy( seq + 3 + data_size, data, size); 232 data_size += size; 233 net_store_16(seq, 1, data_size); 234 } 235 236 void de_add_uuid128(uint8_t * seq, uint8_t * uuid){ 237 int data_size = READ_NET_16(seq,1); 238 de_store_descriptor(seq+3+data_size, DE_UUID, DE_SIZE_128); 239 memcpy( seq + 4 + data_size, uuid, 16); 240 net_store_16(seq, 1, data_size+1+16); 241 } 242 243 // MARK: DES iterator 244 int des_iterator_init(des_iterator_t * it, uint8_t * element){ 245 de_type_t type = de_get_element_type(element); 246 if (type != DE_DES) return 0; 247 248 it->element = element; 249 it->pos = de_get_header_size(element); 250 it->length = de_get_len(element); 251 // printf("des_iterator_init current pos %d, total len %d\n", it->pos, it->length); 252 return 1; 253 } 254 255 de_type_t des_iterator_get_type (des_iterator_t * it){ 256 return de_get_element_type(&it->element[it->pos]); 257 } 258 259 uint16_t des_iterator_get_size (des_iterator_t * it){ 260 int length = de_get_len(&it->element[it->pos]); 261 int header_size = de_get_header_size(&it->element[it->pos]); 262 return length - header_size; 263 } 264 265 int des_iterator_has_more(des_iterator_t * it){ 266 return it->pos < it->length; 267 } 268 269 uint8_t * des_iterator_get_element(des_iterator_t * it){ 270 if (!des_iterator_has_more(it)) return NULL; 271 return &it->element[it->pos]; 272 } 273 274 void des_iterator_next(des_iterator_t * it){ 275 int element_len = de_get_len(&it->element[it->pos]); 276 // printf("des_iterator_next element size %d, current pos %d, total len %d\n", element_len, it->pos, it->length); 277 it->pos += element_len; 278 } 279 280 // MARK: DataElementSequence traversal 281 typedef int (*de_traversal_callback_t)(uint8_t * element, de_type_t type, de_size_t size, void *context); 282 static void de_traverse_sequence(uint8_t * element, de_traversal_callback_t handler, void *context){ 283 de_type_t type = de_get_element_type(element); 284 if (type != DE_DES) return; 285 int pos = de_get_header_size(element); 286 int end_pos = de_get_len(element); 287 while (pos < end_pos){ 288 de_type_t elemType = de_get_element_type(element + pos); 289 de_size_t elemSize = de_get_size_type(element + pos); 290 uint8_t done = (*handler)(element + pos, elemType, elemSize, context); 291 if (done) break; 292 pos += de_get_len(element + pos); 293 } 294 } 295 296 // MARK: AttributeList traversal 297 typedef int (*sdp_attribute_list_traversal_callback_t)(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *context); 298 static void sdp_attribute_list_traverse_sequence(uint8_t * element, sdp_attribute_list_traversal_callback_t handler, void *context){ 299 de_type_t type = de_get_element_type(element); 300 if (type != DE_DES) return; 301 int pos = de_get_header_size(element); 302 int end_pos = de_get_len(element); 303 while (pos < end_pos){ 304 de_type_t idType = de_get_element_type(element + pos); 305 de_size_t idSize = de_get_size_type(element + pos); 306 if (idType != DE_UINT || idSize != DE_SIZE_16) break; // wrong type 307 uint16_t attribute_id = READ_NET_16(element, pos + 1); 308 pos += 3; 309 if (pos >= end_pos) break; // array out of bounds 310 de_type_t valueType = de_get_element_type(element + pos); 311 de_size_t valueSize = de_get_size_type(element + pos); 312 uint8_t done = (*handler)(attribute_id, element + pos, valueType, valueSize, context); 313 if (done) break; 314 pos += de_get_len(element + pos); 315 } 316 } 317 318 // MARK: AttributeID in AttributeIDList 319 // attribute ID in AttributeIDList 320 // context { result, attributeID } 321 struct sdp_context_attributeID_search { 322 int result; 323 uint16_t attributeID; 324 }; 325 static int sdp_traversal_attributeID_search(uint8_t * element, de_type_t type, de_size_t size, void *my_context){ 326 struct sdp_context_attributeID_search * context = (struct sdp_context_attributeID_search *) my_context; 327 if (type != DE_UINT) return 0; 328 switch (size) { 329 case DE_SIZE_16: 330 if (READ_NET_16(element, 1) == context->attributeID) { 331 context->result = 1; 332 return 1; 333 } 334 break; 335 case DE_SIZE_32: 336 if (READ_NET_16(element, 1) <= context->attributeID 337 && context->attributeID <= READ_NET_16(element, 3)) { 338 context->result = 1; 339 return 1; 340 } 341 break; 342 default: 343 break; 344 } 345 return 0; 346 } 347 348 int sdp_attribute_list_constains_id(uint8_t *attributeIDList, uint16_t attributeID){ 349 struct sdp_context_attributeID_search attributeID_search; 350 attributeID_search.result = 0; 351 attributeID_search.attributeID = attributeID; 352 de_traverse_sequence(attributeIDList, sdp_traversal_attributeID_search, &attributeID_search); 353 return attributeID_search.result; 354 } 355 356 // MARK: Append Attributes for AttributeIDList 357 // pre: buffer contains DES with 2 byte length field 358 struct sdp_context_append_attributes { 359 uint8_t * buffer; 360 uint16_t startOffset; // offset of when to start copying 361 uint16_t maxBytes; 362 uint16_t usedBytes; 363 uint8_t *attributeIDList; 364 }; 365 366 static int sdp_traversal_append_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){ 367 struct sdp_context_append_attributes * context = (struct sdp_context_append_attributes *) my_context; 368 if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) { 369 // DES_HEADER(3) + DES_DATA + (UINT16(3) + attribute) 370 uint16_t data_size = READ_NET_16(context->buffer, 1); 371 int attribute_len = de_get_len(attributeValue); 372 if (3 + data_size + (3 + attribute_len) <= context->maxBytes) { 373 // copy Attribute 374 de_add_number(context->buffer, DE_UINT, DE_SIZE_16, attributeID); 375 data_size += 3; // 3 bytes 376 memcpy(context->buffer + 3 + data_size, attributeValue, attribute_len); 377 net_store_16(context->buffer,1,data_size+attribute_len); 378 } else { 379 // not enought space left -> continue with previous element 380 return 1; 381 } 382 } 383 return 0; 384 } 385 386 // maxBytes: maximal size of data element sequence 387 uint16_t sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer){ 388 struct sdp_context_append_attributes context; 389 context.buffer = buffer; 390 context.maxBytes = maxBytes; 391 context.usedBytes = 0; 392 context.startOffset = startOffset; 393 context.attributeIDList = attributeIDList; 394 sdp_attribute_list_traverse_sequence(record, sdp_traversal_append_attributes, &context); 395 return context.usedBytes; 396 } 397 398 // MARK: Filter attributes that match attribute list from startOffset and a max nr bytes 399 struct sdp_context_filter_attributes { 400 uint8_t * buffer; 401 uint16_t startOffset; // offset of when to start copying 402 uint16_t maxBytes; 403 uint16_t usedBytes; 404 uint8_t *attributeIDList; 405 int complete; 406 }; 407 408 // copy data with given start offset and max bytes, returns OK if all data has been copied 409 static int spd_append_range(struct sdp_context_filter_attributes* context, uint16_t len, uint8_t *data){ 410 int ok = 1; 411 uint16_t remainder_len = len - context->startOffset; 412 if (context->maxBytes < remainder_len){ 413 remainder_len = context->maxBytes; 414 ok = 0; 415 } 416 memcpy(context->buffer, &data[context->startOffset], remainder_len); 417 context->usedBytes += remainder_len; 418 context->buffer += remainder_len; 419 context->maxBytes -= remainder_len; 420 context->startOffset = 0; 421 return ok; 422 } 423 424 static int sdp_traversal_filter_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){ 425 struct sdp_context_filter_attributes * context = (struct sdp_context_filter_attributes *) my_context; 426 427 if (!sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) return 0; 428 429 // { Attribute ID (Descriptor, big endian 16-bit ID), AttributeValue (data)} 430 431 // handle Attribute ID 432 if (context->startOffset >= 3){ 433 context->startOffset -= 3; 434 } else { 435 uint8_t idBuffer[3]; 436 de_store_descriptor(idBuffer, DE_UINT, DE_SIZE_16); 437 net_store_16(idBuffer,1,attributeID); 438 439 int ok = spd_append_range(context, 3, idBuffer); 440 if (!ok) { 441 context->complete = 0; 442 return 1; 443 } 444 } 445 446 // handle Attribute Value 447 int attribute_len = de_get_len(attributeValue); 448 if (context->startOffset >= attribute_len) { 449 context->startOffset -= attribute_len; 450 return 0; 451 } 452 453 int ok = spd_append_range(context, attribute_len, attributeValue); 454 if (!ok) { 455 context->complete = 0; 456 return 1; 457 } 458 return 0; 459 } 460 461 int sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer){ 462 463 struct sdp_context_filter_attributes context; 464 context.buffer = buffer; 465 context.maxBytes = maxBytes; 466 context.usedBytes = 0; 467 context.startOffset = startOffset; 468 context.attributeIDList = attributeIDList; 469 context.complete = 1; 470 471 sdp_attribute_list_traverse_sequence(record, sdp_traversal_filter_attributes, &context); 472 473 *usedBytes = context.usedBytes; 474 return context.complete; 475 } 476 477 // MARK: Get sum of attributes matching attribute list 478 struct sdp_context_get_filtered_size { 479 uint8_t *attributeIDList; 480 uint16_t size; 481 }; 482 483 static int sdp_traversal_get_filtered_size(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){ 484 struct sdp_context_get_filtered_size * context = (struct sdp_context_get_filtered_size *) my_context; 485 if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) { 486 context->size += 3 + de_get_len(attributeValue); 487 } 488 return 0; 489 } 490 491 int spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList){ 492 struct sdp_context_get_filtered_size context; 493 context.size = 0; 494 context.attributeIDList = attributeIDList; 495 sdp_attribute_list_traverse_sequence(record, sdp_traversal_get_filtered_size, &context); 496 return context.size; 497 } 498 499 // MARK: Get AttributeValue for AttributeID 500 // find attribute (ELEMENT) by ID 501 struct sdp_context_attribute_by_id { 502 uint16_t attributeID; 503 uint8_t * attributeValue; 504 }; 505 static int sdp_traversal_attribute_by_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){ 506 struct sdp_context_attribute_by_id * context = (struct sdp_context_attribute_by_id *) my_context; 507 if (attributeID == context->attributeID) { 508 context->attributeValue = attributeValue; 509 return 1; 510 } 511 return 0; 512 } 513 514 uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID){ 515 struct sdp_context_attribute_by_id context; 516 context.attributeValue = NULL; 517 context.attributeID = attributeID; 518 sdp_attribute_list_traverse_sequence(record, sdp_traversal_attribute_by_id, &context); 519 return context.attributeValue; 520 } 521 522 // MARK: Set AttributeValue for AttributeID 523 struct sdp_context_set_attribute_for_id { 524 uint16_t attributeID; 525 uint32_t attributeValue; 526 uint8_t attributeFound; 527 }; 528 static int sdp_traversal_set_attribute_for_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){ 529 struct sdp_context_set_attribute_for_id * context = (struct sdp_context_set_attribute_for_id *) my_context; 530 if (attributeID == context->attributeID) { 531 context->attributeFound = 1; 532 switch (size){ 533 case DE_SIZE_8: 534 if (attributeType != DE_NIL){ 535 attributeValue[1] = context->attributeValue; 536 } 537 break; 538 case DE_SIZE_16: 539 net_store_16(attributeValue, 1, context->attributeValue); 540 break; 541 case DE_SIZE_32: 542 net_store_32(attributeValue, 1, context->attributeValue); 543 break; 544 // Might want to support STRINGS to, copy upto original length 545 default: 546 break; 547 } 548 return 1; 549 } 550 return 0; 551 } 552 uint8_t sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value){ 553 struct sdp_context_set_attribute_for_id context; 554 context.attributeID = attributeID; 555 context.attributeValue = value; 556 context.attributeFound = 0; 557 sdp_attribute_list_traverse_sequence(record, sdp_traversal_set_attribute_for_id, &context); 558 return context.attributeFound; 559 } 560 561 // MARK: ServiceRecord contains UUID 562 // service record contains UUID 563 // context { normalizedUUID } 564 struct sdp_context_contains_uuid128 { 565 uint8_t * uuid128; 566 int result; 567 }; 568 int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128); 569 static int sdp_traversal_contains_UUID128(uint8_t * element, de_type_t type, de_size_t size, void *my_context){ 570 struct sdp_context_contains_uuid128 * context = (struct sdp_context_contains_uuid128 *) my_context; 571 uint8_t normalizedUUID[16]; 572 if (type == DE_UUID){ 573 uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element); 574 context->result = uuidOK && memcmp(context->uuid128, normalizedUUID, 16) == 0; 575 } 576 if (type == DE_DES){ 577 context->result = sdp_record_contains_UUID128(element, context->uuid128); 578 } 579 return context->result; 580 } 581 int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128){ 582 struct sdp_context_contains_uuid128 context; 583 context.uuid128 = uuid128; 584 context.result = 0; 585 de_traverse_sequence(record, sdp_traversal_contains_UUID128, &context); 586 return context.result; 587 } 588 589 // MARK: ServiceRecord matches SearchServicePattern 590 // if UUID in searchServicePattern is not found in record => false 591 // context { result, record } 592 struct sdp_context_match_pattern { 593 uint8_t * record; 594 int result; 595 }; 596 597 int sdp_traversal_match_pattern(uint8_t * element, de_type_t attributeType, de_size_t size, void *my_context){ 598 struct sdp_context_match_pattern * context = (struct sdp_context_match_pattern *) my_context; 599 uint8_t normalizedUUID[16]; 600 uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element); 601 if (!uuidOK || !sdp_record_contains_UUID128(context->record, normalizedUUID)){ 602 context->result = 0; 603 return 1; 604 } 605 return 0; 606 } 607 int sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern){ 608 struct sdp_context_match_pattern context; 609 context.record = record; 610 context.result = 1; 611 de_traverse_sequence(serviceSearchPattern, sdp_traversal_match_pattern, &context); 612 return context.result; 613 } 614 615 // MARK: Dump DataElement 616 // context { indent } 617 #ifdef SDP_DES_DUMP 618 static int de_traversal_dump_data(uint8_t * element, de_type_t de_type, de_size_t de_size, void *my_context){ 619 int indent = *(int*) my_context; 620 int i; 621 for (i=0; i<indent;i++) printf(" "); 622 int pos = de_get_header_size(element); 623 int end_pos = de_get_len(element); 624 printf("type %5s (%u), element len %2u ", type_names[de_type], de_type, end_pos); 625 if (de_type == DE_DES) { 626 printf("\n"); 627 indent++; 628 de_traverse_sequence(element, de_traversal_dump_data, (void *)&indent); 629 } else if (de_type == DE_UUID && de_size == DE_SIZE_128) { 630 printf(", value: "); 631 printUUID128(element+1); 632 printf("\n"); 633 } else if (de_type == DE_STRING) { 634 int len = 0; 635 switch (de_size){ 636 case DE_SIZE_VAR_8: 637 len = element[1]; 638 break; 639 case DE_SIZE_VAR_16: 640 len = READ_NET_16(element, 1); 641 break; 642 default: 643 break; 644 } 645 printf("len %u (0x%02x)\n", len, len); 646 printf_hexdump(&element[pos], len); 647 } else { 648 uint32_t value = 0; 649 switch (de_size) { 650 case DE_SIZE_8: 651 if (de_type != DE_NIL){ 652 value = element[pos]; 653 } 654 break; 655 case DE_SIZE_16: 656 value = READ_NET_16(element,pos); 657 break; 658 case DE_SIZE_32: 659 value = READ_NET_32(element,pos); 660 break; 661 default: 662 break; 663 } 664 printf(", value: 0x%08" PRIx32 "\n", value); 665 } 666 return 0; 667 } 668 #endif 669 670 void de_dump_data_element(uint8_t * record){ 671 #ifdef SDP_DES_DUMP 672 int indent = 0; 673 // hack to get root DES, too. 674 de_type_t type = de_get_element_type(record); 675 de_size_t size = de_get_size_type(record); 676 de_traversal_dump_data(record, type, size, (void*) &indent); 677 #endif 678 } 679 680 void sdp_create_spp_service(uint8_t *service, uint32_t service_record_handle, int service_id, const char *name){ 681 682 uint8_t* attribute; 683 de_create_sequence(service); 684 685 // 0x0000 "Service Record Handle" 686 de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle); 687 de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle); 688 689 // 0x0001 "Service Class ID List" 690 de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList); 691 attribute = de_push_sequence(service); 692 { 693 de_add_number(attribute, DE_UUID, DE_SIZE_16, 0x1101 ); 694 } 695 de_pop_sequence(service, attribute); 696 697 // 0x0004 "Protocol Descriptor List" 698 de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList); 699 attribute = de_push_sequence(service); 700 { 701 uint8_t* l2cpProtocol = de_push_sequence(attribute); 702 { 703 de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol); 704 } 705 de_pop_sequence(attribute, l2cpProtocol); 706 707 uint8_t* rfcomm = de_push_sequence(attribute); 708 { 709 de_add_number(rfcomm, DE_UUID, DE_SIZE_16, SDP_RFCOMMProtocol); // rfcomm_service 710 de_add_number(rfcomm, DE_UINT, DE_SIZE_8, service_id); // rfcomm channel 711 } 712 de_pop_sequence(attribute, rfcomm); 713 } 714 de_pop_sequence(service, attribute); 715 716 // 0x0005 "Public Browse Group" 717 de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group 718 attribute = de_push_sequence(service); 719 { 720 de_add_number(attribute, DE_UUID, DE_SIZE_16, 0x1002 ); 721 } 722 de_pop_sequence(service, attribute); 723 724 // 0x0006 725 de_add_number(service, DE_UINT, DE_SIZE_16, SDP_LanguageBaseAttributeIDList); 726 attribute = de_push_sequence(service); 727 { 728 de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e); 729 de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a); 730 de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100); 731 } 732 de_pop_sequence(service, attribute); 733 734 // 0x0009 "Bluetooth Profile Descriptor List" 735 de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList); 736 attribute = de_push_sequence(service); 737 { 738 uint8_t *sppProfile = de_push_sequence(attribute); 739 { 740 de_add_number(sppProfile, DE_UUID, DE_SIZE_16, 0x1101); 741 de_add_number(sppProfile, DE_UINT, DE_SIZE_16, 0x0102); 742 } 743 de_pop_sequence(attribute, sppProfile); 744 } 745 de_pop_sequence(service, attribute); 746 747 // 0x0100 "ServiceName" 748 de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); 749 de_add_data(service, DE_STRING, strlen(name), (uint8_t *) name); 750 } 751