1 /* 2 * sdp.c 3 * 4 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: sdp.c,v 1.3 2004/02/17 22:14:57 max Exp $ 29 * $FreeBSD$ 30 */ 31 32 #include <sys/queue.h> 33 #define L2CAP_SOCKET_CHECKED 34 #include <bluetooth.h> 35 #include <dev/usb/usb.h> 36 #include <dev/usb/usbhid.h> 37 #include <errno.h> 38 #include <sdp.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <usbhid.h> 42 #include "bthid_config.h" 43 #include "bthidcontrol.h" 44 45 static int32_t hid_sdp_query (bdaddr_t const *local, struct hid_device *hd, int32_t *error); 46 static int32_t hid_sdp_parse_protocol_descriptor_list (sdp_attr_p a); 47 static int32_t hid_sdp_parse_hid_descriptor (sdp_attr_p a); 48 static int32_t hid_sdp_parse_boolean (sdp_attr_p a); 49 50 /* 51 * Hard coded attibute IDs taken from the 52 * DEVICE IDENTIFICATION PROFILE SPECIFICATION V13 p.12 53 */ 54 55 #define SDP_ATTR_DEVICE_ID_SERVICE_VENDORID 0x0201 56 #define SDP_ATTR_DEVICE_ID_SERVICE_PRODUCTID 0x0202 57 #define SDP_ATTR_DEVICE_ID_SERVICE_VERSION 0x0203 58 #define SDP_ATTR_DEVICE_ID_RANGE SDP_ATTR_RANGE( \ 59 SDP_ATTR_DEVICE_ID_SERVICE_VENDORID, SDP_ATTR_DEVICE_ID_SERVICE_VERSION ) 60 61 static uint16_t service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE; 62 static uint16_t service_devid = SDP_SERVICE_CLASS_PNP_INFORMATION; 63 static uint32_t attrs_devid = SDP_ATTR_DEVICE_ID_RANGE; 64 65 static uint32_t attrs[] = { 66 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 67 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), 68 SDP_ATTR_RANGE (SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS, 69 SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS), 70 SDP_ATTR_RANGE( 0x0205, /* HIDReconnectInitiate */ 71 0x0205), 72 SDP_ATTR_RANGE( 0x0206, /* HIDDescriptorList */ 73 0x0206), 74 SDP_ATTR_RANGE( 0x0209, /* HIDBatteryPower */ 75 0x0209), 76 SDP_ATTR_RANGE( 0x020d, /* HIDNormallyConnectable */ 77 0x020d) 78 }; 79 #define nattrs (sizeof(attrs)/sizeof(attrs[0])) 80 81 static sdp_attr_t values[8]; 82 #define nvalues (sizeof(values)/sizeof(values[0])) 83 84 static uint8_t buffer[nvalues][512]; 85 86 /* 87 * Query remote device 88 */ 89 90 #undef hid_sdp_query_exit 91 #define hid_sdp_query_exit(e) { \ 92 if (error != NULL) \ 93 *error = (e); \ 94 if (ss != NULL) { \ 95 sdp_close(ss); \ 96 ss = NULL; \ 97 } \ 98 return (((e) == 0)? 0 : -1); \ 99 } 100 101 static void 102 hid_init_return_values() { 103 int i; 104 for (i = 0; i < nvalues; i ++) { 105 values[i].flags = SDP_ATTR_INVALID; 106 values[i].attr = 0; 107 values[i].vlen = sizeof(buffer[i]); 108 values[i].value = buffer[i]; 109 } 110 } 111 112 static int32_t 113 hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error) 114 { 115 void *ss = NULL; 116 uint8_t *hid_descriptor = NULL, *v; 117 int32_t i, control_psm = -1, interrupt_psm = -1, 118 reconnect_initiate = -1, 119 normally_connectable = 0, battery_power = 0, 120 hid_descriptor_length = -1, type; 121 int16_t vendor_id = 0, product_id = 0, version = 0; 122 123 if (local == NULL) 124 local = NG_HCI_BDADDR_ANY; 125 if (hd == NULL) 126 hid_sdp_query_exit(EINVAL); 127 128 hid_init_return_values(); 129 130 if ((ss = sdp_open(local, &hd->bdaddr)) == NULL) 131 hid_sdp_query_exit(ENOMEM); 132 if (sdp_error(ss) != 0) 133 hid_sdp_query_exit(sdp_error(ss)); 134 if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0) 135 hid_sdp_query_exit(sdp_error(ss)); 136 137 for (i = 0; i < nvalues; i ++) { 138 if (values[i].flags != SDP_ATTR_OK) 139 continue; 140 141 switch (values[i].attr) { 142 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: 143 control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); 144 break; 145 146 case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: 147 interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); 148 break; 149 150 case 0x0205: /* HIDReconnectInitiate */ 151 reconnect_initiate = hid_sdp_parse_boolean(&values[i]); 152 break; 153 154 case 0x0206: /* HIDDescriptorList */ 155 if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) { 156 hid_descriptor = values[i].value; 157 hid_descriptor_length = values[i].vlen; 158 } 159 break; 160 161 case 0x0209: /* HIDBatteryPower */ 162 battery_power = hid_sdp_parse_boolean(&values[i]); 163 break; 164 165 case 0x020d: /* HIDNormallyConnectable */ 166 normally_connectable = hid_sdp_parse_boolean(&values[i]); 167 break; 168 } 169 } 170 171 hid_init_return_values(); 172 173 if (sdp_search(ss, 1, &service_devid, 1, &attrs_devid, nvalues, values) != 0) 174 hid_sdp_query_exit(sdp_error(ss)); 175 176 sdp_close(ss); 177 ss = NULL; 178 179 /* If search is successful, scan through return vals */ 180 for (i = 0; i < 3; i ++ ) { 181 if (values[i].flags == SDP_ATTR_INVALID ) 182 continue; 183 184 /* Expecting tag + uint16_t on all 3 attributes */ 185 if (values[i].vlen != 3) 186 continue; 187 188 /* Make sure, we're reading a uint16_t */ 189 v = values[i].value; 190 SDP_GET8(type, v); 191 if (type != SDP_DATA_UINT16 ) 192 continue; 193 194 switch (values[i].attr) { 195 case SDP_ATTR_DEVICE_ID_SERVICE_VENDORID: 196 SDP_GET16(vendor_id, v); 197 break; 198 case SDP_ATTR_DEVICE_ID_SERVICE_PRODUCTID: 199 SDP_GET16(product_id, v); 200 break; 201 case SDP_ATTR_DEVICE_ID_SERVICE_VERSION: 202 SDP_GET16(version, v); 203 break; 204 default: 205 break; 206 } 207 } 208 209 if (control_psm == -1 || interrupt_psm == -1 || 210 reconnect_initiate == -1 || 211 hid_descriptor == NULL || hid_descriptor_length == -1) 212 hid_sdp_query_exit(ENOATTR); 213 hd->vendor_id = vendor_id; 214 hd->product_id = product_id; 215 hd->version = version; 216 hd->control_psm = control_psm; 217 hd->interrupt_psm = interrupt_psm; 218 hd->reconnect_initiate = reconnect_initiate? 1 : 0; 219 hd->battery_power = battery_power? 1 : 0; 220 hd->normally_connectable = normally_connectable? 1 : 0; 221 hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length); 222 if (hd->desc == NULL) 223 hid_sdp_query_exit(ENOMEM); 224 225 return (0); 226 } 227 228 /* 229 * seq len 2 230 * seq len 2 231 * uuid value 3 232 * uint16 value 3 233 * seq len 2 234 * uuid value 3 235 */ 236 237 static int32_t 238 hid_sdp_parse_protocol_descriptor_list(sdp_attr_p a) 239 { 240 uint8_t *ptr = a->value; 241 uint8_t *end = a->value + a->vlen; 242 int32_t type, len, uuid, psm; 243 244 if (end - ptr < 15) 245 return (-1); 246 247 if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) { 248 SDP_GET8(type, ptr); 249 switch (type) { 250 case SDP_DATA_SEQ8: 251 SDP_GET8(len, ptr); 252 break; 253 254 case SDP_DATA_SEQ16: 255 SDP_GET16(len, ptr); 256 break; 257 258 case SDP_DATA_SEQ32: 259 SDP_GET32(len, ptr); 260 break; 261 262 default: 263 return (-1); 264 } 265 if (ptr + len > end) 266 return (-1); 267 } 268 269 SDP_GET8(type, ptr); 270 switch (type) { 271 case SDP_DATA_SEQ8: 272 SDP_GET8(len, ptr); 273 break; 274 275 case SDP_DATA_SEQ16: 276 SDP_GET16(len, ptr); 277 break; 278 279 case SDP_DATA_SEQ32: 280 SDP_GET32(len, ptr); 281 break; 282 283 default: 284 return (-1); 285 } 286 if (ptr + len > end) 287 return (-1); 288 289 /* Protocol */ 290 SDP_GET8(type, ptr); 291 switch (type) { 292 case SDP_DATA_SEQ8: 293 SDP_GET8(len, ptr); 294 break; 295 296 case SDP_DATA_SEQ16: 297 SDP_GET16(len, ptr); 298 break; 299 300 case SDP_DATA_SEQ32: 301 SDP_GET32(len, ptr); 302 break; 303 304 default: 305 return (-1); 306 } 307 if (ptr + len > end) 308 return (-1); 309 310 /* UUID */ 311 if (ptr + 3 > end) 312 return (-1); 313 SDP_GET8(type, ptr); 314 switch (type) { 315 case SDP_DATA_UUID16: 316 SDP_GET16(uuid, ptr); 317 if (uuid != SDP_UUID_PROTOCOL_L2CAP) 318 return (-1); 319 break; 320 321 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 322 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 323 default: 324 return (-1); 325 } 326 327 /* PSM */ 328 if (ptr + 3 > end) 329 return (-1); 330 SDP_GET8(type, ptr); 331 if (type != SDP_DATA_UINT16) 332 return (-1); 333 SDP_GET16(psm, ptr); 334 335 return (psm); 336 } 337 338 /* 339 * seq len 2 340 * seq len 2 341 * uint8 value8 2 342 * str value 3 343 */ 344 345 static int32_t 346 hid_sdp_parse_hid_descriptor(sdp_attr_p a) 347 { 348 uint8_t *ptr = a->value; 349 uint8_t *end = a->value + a->vlen; 350 int32_t type, len, descriptor_type; 351 352 if (end - ptr < 9) 353 return (-1); 354 355 SDP_GET8(type, ptr); 356 switch (type) { 357 case SDP_DATA_SEQ8: 358 SDP_GET8(len, ptr); 359 break; 360 361 case SDP_DATA_SEQ16: 362 SDP_GET16(len, ptr); 363 break; 364 365 case SDP_DATA_SEQ32: 366 SDP_GET32(len, ptr); 367 break; 368 369 default: 370 return (-1); 371 } 372 if (ptr + len > end) 373 return (-1); 374 375 while (ptr < end) { 376 /* Descriptor */ 377 SDP_GET8(type, ptr); 378 switch (type) { 379 case SDP_DATA_SEQ8: 380 if (ptr + 1 > end) 381 return (-1); 382 SDP_GET8(len, ptr); 383 break; 384 385 case SDP_DATA_SEQ16: 386 if (ptr + 2 > end) 387 return (-1); 388 SDP_GET16(len, ptr); 389 break; 390 391 case SDP_DATA_SEQ32: 392 if (ptr + 4 > end) 393 return (-1); 394 SDP_GET32(len, ptr); 395 break; 396 397 default: 398 return (-1); 399 } 400 401 /* Descripor type */ 402 if (ptr + 1 > end) 403 return (-1); 404 SDP_GET8(type, ptr); 405 if (type != SDP_DATA_UINT8 || ptr + 1 > end) 406 return (-1); 407 SDP_GET8(descriptor_type, ptr); 408 409 /* Descriptor value */ 410 if (ptr + 1 > end) 411 return (-1); 412 SDP_GET8(type, ptr); 413 switch (type) { 414 case SDP_DATA_STR8: 415 if (ptr + 1 > end) 416 return (-1); 417 SDP_GET8(len, ptr); 418 break; 419 420 case SDP_DATA_STR16: 421 if (ptr + 2 > end) 422 return (-1); 423 SDP_GET16(len, ptr); 424 break; 425 426 case SDP_DATA_STR32: 427 if (ptr + 4 > end) 428 return (-1); 429 SDP_GET32(len, ptr); 430 break; 431 432 default: 433 return (-1); 434 } 435 if (ptr + len > end) 436 return (-1); 437 438 if (descriptor_type == UDESC_REPORT && len > 0) { 439 a->value = ptr; 440 a->vlen = len; 441 442 return (0); 443 } 444 445 ptr += len; 446 } 447 448 return (-1); 449 } 450 451 /* bool8 int8 */ 452 static int32_t 453 hid_sdp_parse_boolean(sdp_attr_p a) 454 { 455 if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL) 456 return (-1); 457 458 return (a->value[1]); 459 } 460 461 /* Perform SDP query */ 462 static int32_t 463 hid_query(bdaddr_t *bdaddr, int argc, char **argv) 464 { 465 struct hid_device hd; 466 int e; 467 468 memcpy(&hd.bdaddr, bdaddr, sizeof(hd.bdaddr)); 469 if (hid_sdp_query(NULL, &hd, &e) < 0) { 470 fprintf(stderr, "Could not perform SDP query on the " \ 471 "device %s. %s (%d)\n", bt_ntoa(bdaddr, NULL), 472 strerror(e), e); 473 return (FAILED); 474 } 475 476 print_hid_device(&hd, stdout); 477 478 return (OK); 479 } 480 481 struct bthid_command sdp_commands[] = 482 { 483 { 484 "Query", 485 "Perform SDP query to the specified device and print HID configuration entry\n"\ 486 "for the device. The configuration entry should be appended to the Bluetooth\n"\ 487 "HID daemon configuration file and the daemon should be restarted.\n", 488 hid_query 489 }, 490 { NULL, NULL, NULL } 491 }; 492 493