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