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