1 /* $NetBSD: sdp.c,v 1.1 2006/09/10 15:45:56 plunky Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Itronix Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of Itronix Inc. may not be used to endorse 16 * or promote products derived from this software without specific 17 * prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * SUCH DAMAGE. 55 */ 56 57 #include <sys/cdefs.h> 58 __RCSID("$NetBSD: sdp.c,v 1.1 2006/09/10 15:45:56 plunky Exp $"); 59 60 #include <sys/types.h> 61 62 #include <dev/bluetooth/btdev.h> 63 #include <dev/bluetooth/bthidev.h> 64 #include <dev/bluetooth/btsco.h> 65 #include <dev/usb/usb.h> 66 #include <dev/usb/usbhid.h> 67 68 #include <prop/proplib.h> 69 70 #include <bluetooth.h> 71 #include <err.h> 72 #include <errno.h> 73 #include <sdp.h> 74 #include <stdlib.h> 75 #include <usbhid.h> 76 77 #include "btdevctl.h" 78 79 static int32_t parse_l2cap_psm(sdp_attr_t *); 80 static int32_t parse_rfcomm_channel(sdp_attr_t *); 81 static int32_t parse_hid_descriptor(sdp_attr_t *); 82 static int32_t parse_boolean(sdp_attr_t *); 83 84 static int config_hid(prop_dictionary_t); 85 static int config_hset(prop_dictionary_t); 86 static int config_hf(prop_dictionary_t); 87 88 uint16_t hid_services[] = { 89 SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE 90 }; 91 92 uint32_t hid_attrs[] = { 93 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 94 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), 95 SDP_ATTR_RANGE( SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS, 96 SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS), 97 SDP_ATTR_RANGE( 0x0205, /* HIDReconnectInitiate */ 98 0x0206), /* HIDDescriptorList */ 99 SDP_ATTR_RANGE( 0x0209, /* HIDBatteryPower */ 100 0x0209), 101 SDP_ATTR_RANGE( 0x020d, /* HIDNormallyConnectable */ 102 0x020d) 103 }; 104 105 uint16_t hset_services[] = { 106 SDP_SERVICE_CLASS_HEADSET 107 }; 108 109 uint32_t hset_attrs[] = { 110 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 111 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), 112 }; 113 114 uint16_t hf_services[] = { 115 SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY 116 }; 117 118 uint32_t hf_attrs[] = { 119 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 120 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), 121 }; 122 123 #define NUM(v) (sizeof(v) / sizeof(v[0])) 124 125 static struct { 126 const char *name; 127 int (*handler)(prop_dictionary_t); 128 const char *description; 129 uint16_t *services; 130 int nservices; 131 uint32_t *attrs; 132 int nattrs; 133 } cfgtype[] = { 134 { 135 "HID", config_hid, "Human Interface Device", 136 hid_services, NUM(hid_services), 137 hid_attrs, NUM(hid_attrs), 138 }, 139 { 140 "HSET", config_hset, "Headset", 141 hset_services, NUM(hset_services), 142 hset_attrs, NUM(hset_attrs), 143 }, 144 { 145 "HF", config_hf, "Handsfree", 146 hf_services, NUM(hf_services), 147 hf_attrs, NUM(hf_attrs), 148 }, 149 }; 150 151 static sdp_attr_t values[8]; 152 static uint8_t buffer[NUM(values)][512]; 153 154 prop_dictionary_t 155 cfg_query(bdaddr_t *laddr, bdaddr_t *raddr, const char *service) 156 { 157 prop_dictionary_t dict; 158 void *ss; 159 int rv, i; 160 161 dict = prop_dictionary_create(); 162 if (dict == NULL) 163 return NULL; 164 165 for (i = 0 ; i < NUM(values) ; i++) { 166 values[i].flags = SDP_ATTR_INVALID; 167 values[i].attr = 0; 168 values[i].vlen = sizeof(buffer[i]); 169 values[i].value = buffer[i]; 170 } 171 172 for (i = 0 ; i < NUM(cfgtype) ; i++) { 173 if (strcasecmp(service, cfgtype[i].name) == 0) { 174 ss = sdp_open(laddr, raddr); 175 176 if (ss == NULL || (errno = sdp_error(ss)) != 0) 177 return NULL; 178 179 rv = sdp_search(ss, 180 cfgtype[i].nservices, cfgtype[i].services, 181 cfgtype[i].nattrs, cfgtype[i].attrs, 182 NUM(values), values); 183 184 if (rv != 0) { 185 errno = sdp_error(ss); 186 return NULL; 187 } 188 sdp_close(ss); 189 190 rv = (*cfgtype[i].handler)(dict); 191 if (rv != 0) 192 return NULL; 193 194 return dict; 195 } 196 } 197 198 printf("Known config types:\n"); 199 for (i = 0 ; i < NUM(cfgtype) ; i++) 200 printf("\t%s\t%s\n", cfgtype[i].name, cfgtype[i].description); 201 202 exit(EXIT_FAILURE); 203 } 204 205 /* 206 * Configure HID results 207 */ 208 static int 209 config_hid(prop_dictionary_t dict) 210 { 211 prop_object_t obj; 212 int32_t control_psm, interrupt_psm, 213 reconnect_initiate, battery_power, 214 normally_connectable, hid_length; 215 uint8_t *hid_descriptor; 216 int i; 217 218 control_psm = -1; 219 interrupt_psm = -1; 220 reconnect_initiate = -1; 221 normally_connectable = 0; 222 battery_power = 0; 223 hid_descriptor = NULL; 224 hid_length = -1; 225 226 for (i = 0; i < NUM(values) ; i++) { 227 if (values[i].flags != SDP_ATTR_OK) 228 continue; 229 230 switch (values[i].attr) { 231 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: 232 control_psm = parse_l2cap_psm(&values[i]); 233 break; 234 235 case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: 236 interrupt_psm = parse_l2cap_psm(&values[i]); 237 break; 238 239 case 0x0205: /* HIDReconnectInitiate */ 240 reconnect_initiate = parse_boolean(&values[i]); 241 break; 242 243 case 0x0206: /* HIDDescriptorList */ 244 if (parse_hid_descriptor(&values[i]) == 0) { 245 hid_descriptor = values[i].value; 246 hid_length = values[i].vlen; 247 } 248 break; 249 250 case 0x0209: /* HIDBatteryPower */ 251 battery_power = parse_boolean(&values[i]); 252 break; 253 254 case 0x020d: /* HIDNormallyConnectable */ 255 normally_connectable = parse_boolean(&values[i]); 256 break; 257 } 258 } 259 260 if (control_psm == -1 261 || interrupt_psm == -1 262 || reconnect_initiate == -1 263 || hid_descriptor == NULL 264 || hid_length == -1) 265 return ENOATTR; 266 267 obj = prop_string_create_cstring_nocopy("bthidev"); 268 if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj)) 269 return errno; 270 271 obj = prop_number_create_integer(control_psm); 272 if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVcontrolpsm, obj)) 273 return errno; 274 275 obj = prop_number_create_integer(interrupt_psm); 276 if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVinterruptpsm, obj)) 277 return errno; 278 279 obj = prop_data_create_data(hid_descriptor, hid_length); 280 if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVdescriptor, obj)) 281 return errno; 282 283 if (!reconnect_initiate) { 284 obj = prop_bool_create(TRUE); 285 if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVreconnect, obj)) 286 return errno; 287 } 288 289 return 0; 290 } 291 292 /* 293 * Configure HSET results 294 */ 295 static int 296 config_hset(prop_dictionary_t dict) 297 { 298 prop_object_t obj; 299 uint32_t channel; 300 int i; 301 302 channel = -1; 303 304 for (i = 0; i < NUM(values) ; i++) { 305 if (values[i].flags != SDP_ATTR_OK) 306 continue; 307 308 switch (values[i].attr) { 309 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: 310 channel = parse_rfcomm_channel(&values[i]); 311 break; 312 } 313 } 314 315 if (channel == -1) 316 return ENOATTR; 317 318 obj = prop_string_create_cstring_nocopy("btsco"); 319 if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj)) 320 return errno; 321 322 obj = prop_number_create_integer(channel); 323 if (obj == NULL || !prop_dictionary_set(dict, BTSCOchannel, obj)) 324 return errno; 325 326 return 0; 327 } 328 329 /* 330 * Configure HF results 331 */ 332 static int 333 config_hf(prop_dictionary_t dict) 334 { 335 prop_object_t obj; 336 uint32_t channel; 337 int i; 338 339 channel = -1; 340 341 for (i = 0 ; i < NUM(values) ; i++) { 342 if (values[i].flags != SDP_ATTR_OK) 343 continue; 344 345 switch (values[i].attr) { 346 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: 347 channel = parse_rfcomm_channel(&values[i]); 348 break; 349 } 350 } 351 352 if (channel == -1) 353 return ENOATTR; 354 355 obj = prop_string_create_cstring_nocopy("btsco"); 356 if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj)) 357 return errno; 358 359 obj = prop_bool_create(TRUE); 360 if (obj == NULL || !prop_dictionary_set(dict, BTSCOlisten, obj)) 361 return errno; 362 363 obj = prop_number_create_integer(channel); 364 if (obj == NULL || !prop_dictionary_set(dict, BTSCOchannel, obj)) 365 return errno; 366 367 return 0; 368 } 369 370 /* 371 * Parse [additional] protocol descriptor list for L2CAP PSM 372 * 373 * seq8 len8 2 374 * seq8 len8 2 375 * uuid16 value16 3 L2CAP 376 * uint16 value16 3 PSM 377 * seq8 len8 2 378 * uuid16 value16 3 HID Protocol 379 * === 380 * 15 381 */ 382 383 static int32_t 384 parse_l2cap_psm(sdp_attr_t *a) 385 { 386 uint8_t *ptr = a->value; 387 uint8_t *end = a->value + a->vlen; 388 int32_t type, len, uuid, psm; 389 390 if (end - ptr < 15) 391 return (-1); 392 393 if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) { 394 SDP_GET8(type, ptr); 395 switch (type) { 396 case SDP_DATA_SEQ8: 397 SDP_GET8(len, ptr); 398 break; 399 400 case SDP_DATA_SEQ16: 401 SDP_GET16(len, ptr); 402 break; 403 404 case SDP_DATA_SEQ32: 405 SDP_GET32(len, ptr); 406 break; 407 408 default: 409 return (-1); 410 } 411 if (ptr + len > end) 412 return (-1); 413 } 414 415 SDP_GET8(type, ptr); 416 switch (type) { 417 case SDP_DATA_SEQ8: 418 SDP_GET8(len, ptr); 419 break; 420 421 case SDP_DATA_SEQ16: 422 SDP_GET16(len, ptr); 423 break; 424 425 case SDP_DATA_SEQ32: 426 SDP_GET32(len, ptr); 427 break; 428 429 default: 430 return (-1); 431 } 432 if (ptr + len > end) 433 return (-1); 434 435 /* Protocol */ 436 SDP_GET8(type, ptr); 437 switch (type) { 438 case SDP_DATA_SEQ8: 439 SDP_GET8(len, ptr); 440 break; 441 442 case SDP_DATA_SEQ16: 443 SDP_GET16(len, ptr); 444 break; 445 446 case SDP_DATA_SEQ32: 447 SDP_GET32(len, ptr); 448 break; 449 450 default: 451 return (-1); 452 } 453 if (ptr + len > end) 454 return (-1); 455 456 /* UUID */ 457 if (ptr + 3 > end) 458 return (-1); 459 SDP_GET8(type, ptr); 460 switch (type) { 461 case SDP_DATA_UUID16: 462 SDP_GET16(uuid, ptr); 463 if (uuid != SDP_UUID_PROTOCOL_L2CAP) 464 return (-1); 465 break; 466 467 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 468 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 469 default: 470 return (-1); 471 } 472 473 /* PSM */ 474 if (ptr + 3 > end) 475 return (-1); 476 SDP_GET8(type, ptr); 477 if (type != SDP_DATA_UINT16) 478 return (-1); 479 SDP_GET16(psm, ptr); 480 481 return (psm); 482 } 483 484 /* 485 * Parse HID descriptor string 486 * 487 * seq8 len8 2 488 * seq8 len8 2 489 * uint8 value8 2 490 * str value 3 491 * === 492 * 9 493 */ 494 495 static int32_t 496 parse_hid_descriptor(sdp_attr_t *a) 497 { 498 uint8_t *ptr = a->value; 499 uint8_t *end = a->value + a->vlen; 500 int32_t type, len, descriptor_type; 501 502 if (end - ptr < 9) 503 return (-1); 504 505 SDP_GET8(type, ptr); 506 switch (type) { 507 case SDP_DATA_SEQ8: 508 SDP_GET8(len, ptr); 509 break; 510 511 case SDP_DATA_SEQ16: 512 SDP_GET16(len, ptr); 513 break; 514 515 case SDP_DATA_SEQ32: 516 SDP_GET32(len, ptr); 517 break; 518 519 default: 520 return (-1); 521 } 522 if (ptr + len > end) 523 return (-1); 524 525 while (ptr < end) { 526 /* Descriptor */ 527 SDP_GET8(type, ptr); 528 switch (type) { 529 case SDP_DATA_SEQ8: 530 if (ptr + 1 > end) 531 return (-1); 532 SDP_GET8(len, ptr); 533 break; 534 535 case SDP_DATA_SEQ16: 536 if (ptr + 2 > end) 537 return (-1); 538 SDP_GET16(len, ptr); 539 break; 540 541 case SDP_DATA_SEQ32: 542 if (ptr + 4 > end) 543 return (-1); 544 SDP_GET32(len, ptr); 545 break; 546 547 default: 548 return (-1); 549 } 550 551 /* Descripor type */ 552 if (ptr + 1 > end) 553 return (-1); 554 SDP_GET8(type, ptr); 555 if (type != SDP_DATA_UINT8 || ptr + 1 > end) 556 return (-1); 557 SDP_GET8(descriptor_type, ptr); 558 559 /* Descriptor value */ 560 if (ptr + 1 > end) 561 return (-1); 562 SDP_GET8(type, ptr); 563 switch (type) { 564 case SDP_DATA_STR8: 565 if (ptr + 1 > end) 566 return (-1); 567 SDP_GET8(len, ptr); 568 break; 569 570 case SDP_DATA_STR16: 571 if (ptr + 2 > end) 572 return (-1); 573 SDP_GET16(len, ptr); 574 break; 575 576 case SDP_DATA_STR32: 577 if (ptr + 4 > end) 578 return (-1); 579 SDP_GET32(len, ptr); 580 break; 581 582 default: 583 return (-1); 584 } 585 if (ptr + len > end) 586 return (-1); 587 588 if (descriptor_type == UDESC_REPORT && len > 0) { 589 a->value = ptr; 590 a->vlen = len; 591 592 return (0); 593 } 594 595 ptr += len; 596 } 597 598 return (-1); 599 } 600 601 /* 602 * Parse boolean value 603 * 604 * bool8 int8 605 */ 606 607 static int32_t 608 parse_boolean(sdp_attr_t *a) 609 { 610 if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL) 611 return (-1); 612 613 return (a->value[1]); 614 } 615 616 /* 617 * Parse protocol descriptor list for the RFCOMM channel 618 * 619 * seq8 len8 2 620 * seq8 len8 2 621 * uuid16 value16 3 L2CAP 622 * seq8 len8 2 623 * uuid16 value16 3 RFCOMM 624 * uint8 value8 2 channel 625 * === 626 * 14 627 */ 628 629 static int32_t 630 parse_rfcomm_channel(sdp_attr_t *a) 631 { 632 uint8_t *ptr = a->value; 633 uint8_t *end = a->value + a->vlen; 634 int32_t type, len, uuid, channel; 635 636 if (end - ptr < 14) 637 return (-1); 638 639 SDP_GET8(type, ptr); 640 switch (type) { 641 case SDP_DATA_SEQ8: 642 SDP_GET8(len, ptr); 643 break; 644 645 case SDP_DATA_SEQ16: 646 SDP_GET16(len, ptr); 647 break; 648 649 case SDP_DATA_SEQ32: 650 SDP_GET32(len, ptr); 651 break; 652 653 default: 654 return (-1); 655 } 656 if (ptr + len > end) 657 return (-1); 658 659 /* Protocol */ 660 SDP_GET8(type, ptr); 661 switch (type) { 662 case SDP_DATA_SEQ8: 663 SDP_GET8(len, ptr); 664 break; 665 666 case SDP_DATA_SEQ16: 667 SDP_GET16(len, ptr); 668 break; 669 670 case SDP_DATA_SEQ32: 671 SDP_GET32(len, ptr); 672 break; 673 674 default: 675 return (-1); 676 } 677 if (ptr + len > end) 678 return (-1); 679 680 /* UUID */ 681 if (ptr + 3 > end) 682 return (-1); 683 SDP_GET8(type, ptr); 684 switch (type) { 685 case SDP_DATA_UUID16: 686 SDP_GET16(uuid, ptr); 687 if (uuid != SDP_UUID_PROTOCOL_L2CAP) 688 return (-1); 689 break; 690 691 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 692 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 693 default: 694 return (-1); 695 } 696 697 /* Protocol */ 698 SDP_GET8(type, ptr); 699 switch (type) { 700 case SDP_DATA_SEQ8: 701 SDP_GET8(len, ptr); 702 break; 703 704 case SDP_DATA_SEQ16: 705 SDP_GET16(len, ptr); 706 break; 707 708 case SDP_DATA_SEQ32: 709 SDP_GET32(len, ptr); 710 break; 711 712 default: 713 return (-1); 714 } 715 if (ptr + len > end) 716 return (-1); 717 718 /* UUID */ 719 if (ptr + 3 > end) 720 return (-1); 721 SDP_GET8(type, ptr); 722 switch (type) { 723 case SDP_DATA_UUID16: 724 SDP_GET16(uuid, ptr); 725 if (uuid != SDP_UUID_PROTOCOL_RFCOMM) 726 return (-1); 727 break; 728 729 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 730 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 731 default: 732 return (-1); 733 } 734 735 /* channel */ 736 if (ptr + 2 > end) 737 return (-1); 738 739 SDP_GET8(type, ptr); 740 if (type != SDP_DATA_UINT8) 741 return (-1); 742 743 SDP_GET8(channel, ptr); 744 745 return (channel); 746 } 747