1128080Semax/* 2128080Semax * sdp.c 3128080Semax * 4128080Semax * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5128080Semax * All rights reserved. 6128080Semax * 7128080Semax * Redistribution and use in source and binary forms, with or without 8128080Semax * modification, are permitted provided that the following conditions 9128080Semax * are met: 10128080Semax * 1. Redistributions of source code must retain the above copyright 11128080Semax * notice, this list of conditions and the following disclaimer. 12128080Semax * 2. Redistributions in binary form must reproduce the above copyright 13128080Semax * notice, this list of conditions and the following disclaimer in the 14128080Semax * documentation and/or other materials provided with the distribution. 15128080Semax * 16128080Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17128080Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18128080Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19128080Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20128080Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21128080Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22128080Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23128080Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24128080Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25128080Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26128080Semax * SUCH DAMAGE. 27128080Semax * 28128080Semax * $Id: sdp.c,v 1.3 2004/02/17 22:14:57 max Exp $ 29128080Semax * $FreeBSD$ 30128080Semax */ 31128080Semax 32128080Semax#include <sys/queue.h> 33128080Semax#include <bluetooth.h> 34128080Semax#include <dev/usb/usb.h> 35128080Semax#include <dev/usb/usbhid.h> 36128080Semax#include <errno.h> 37128080Semax#include <sdp.h> 38128080Semax#include <stdio.h> 39128080Semax#include <string.h> 40128080Semax#include <usbhid.h> 41128080Semax#include "bthid_config.h" 42128080Semax#include "bthidcontrol.h" 43128080Semax 44128080Semaxstatic int32_t hid_sdp_query (bdaddr_t const *local, struct hid_device *hd, int32_t *error); 45128080Semaxstatic int32_t hid_sdp_parse_protocol_descriptor_list (sdp_attr_p a); 46128080Semaxstatic int32_t hid_sdp_parse_hid_descriptor (sdp_attr_p a); 47128080Semaxstatic int32_t hid_sdp_parse_boolean (sdp_attr_p a); 48128080Semax 49128080Semaxstatic uint16_t service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE; 50128080Semax 51128080Semaxstatic uint32_t attrs[] = { 52128080SemaxSDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 53128080Semax SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), 54128080SemaxSDP_ATTR_RANGE (SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS, 55128080Semax SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS), 56128080SemaxSDP_ATTR_RANGE( 0x0205, /* HIDReconnectInitiate */ 57212296Semax 0x0205), 58212296SemaxSDP_ATTR_RANGE( 0x0206, /* HIDDescriptorList */ 59212296Semax 0x0206), 60155516SmarkusSDP_ATTR_RANGE( 0x0209, /* HIDBatteryPower */ 61155516Smarkus 0x0209), 62128080SemaxSDP_ATTR_RANGE( 0x020d, /* HIDNormallyConnectable */ 63128080Semax 0x020d) 64128080Semax }; 65128080Semax#define nattrs (sizeof(attrs)/sizeof(attrs[0])) 66128080Semax 67128080Semaxstatic sdp_attr_t values[8]; 68128080Semax#define nvalues (sizeof(values)/sizeof(values[0])) 69128080Semax 70128080Semaxstatic uint8_t buffer[nvalues][512]; 71128080Semax 72128080Semax/* 73128080Semax * Query remote device 74128080Semax */ 75128080Semax 76128080Semax#undef hid_sdp_query_exit 77128080Semax#define hid_sdp_query_exit(e) { \ 78128080Semax if (error != NULL) \ 79128080Semax *error = (e); \ 80128080Semax if (ss != NULL) { \ 81128080Semax sdp_close(ss); \ 82128080Semax ss = NULL; \ 83128080Semax } \ 84128080Semax return (((e) == 0)? 0 : -1); \ 85128080Semax} 86128080Semax 87128080Semaxstatic int32_t 88128080Semaxhid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error) 89128080Semax{ 90128080Semax void *ss = NULL; 91128080Semax uint8_t *hid_descriptor = NULL; 92128080Semax int32_t i, control_psm = -1, interrupt_psm = -1, 93128080Semax reconnect_initiate = -1, 94128080Semax normally_connectable = 0, battery_power = 0, 95128080Semax hid_descriptor_length = -1; 96128080Semax 97128080Semax if (local == NULL) 98128080Semax local = NG_HCI_BDADDR_ANY; 99128080Semax if (hd == NULL) 100128080Semax hid_sdp_query_exit(EINVAL); 101128080Semax 102128080Semax for (i = 0; i < nvalues; i ++) { 103128080Semax values[i].flags = SDP_ATTR_INVALID; 104128080Semax values[i].attr = 0; 105128080Semax values[i].vlen = sizeof(buffer[i]); 106128080Semax values[i].value = buffer[i]; 107128080Semax } 108128080Semax 109128080Semax if ((ss = sdp_open(local, &hd->bdaddr)) == NULL) 110128080Semax hid_sdp_query_exit(ENOMEM); 111128080Semax if (sdp_error(ss) != 0) 112128080Semax hid_sdp_query_exit(sdp_error(ss)); 113128080Semax if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0) 114128080Semax hid_sdp_query_exit(sdp_error(ss)); 115128080Semax 116128080Semax sdp_close(ss); 117128080Semax ss = NULL; 118128080Semax 119128080Semax for (i = 0; i < nvalues; i ++) { 120128080Semax if (values[i].flags != SDP_ATTR_OK) 121128080Semax continue; 122128080Semax 123128080Semax switch (values[i].attr) { 124128080Semax case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: 125128080Semax control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); 126128080Semax break; 127128080Semax 128128080Semax case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: 129128080Semax interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); 130128080Semax break; 131128080Semax 132128080Semax case 0x0205: /* HIDReconnectInitiate */ 133128080Semax reconnect_initiate = hid_sdp_parse_boolean(&values[i]); 134128080Semax break; 135128080Semax 136155516Smarkus case 0x0206: /* HIDDescriptorList */ 137128080Semax if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) { 138128080Semax hid_descriptor = values[i].value; 139128080Semax hid_descriptor_length = values[i].vlen; 140128080Semax } 141128080Semax break; 142128080Semax 143155516Smarkus case 0x0209: /* HIDBatteryPower */ 144128080Semax battery_power = hid_sdp_parse_boolean(&values[i]); 145128080Semax break; 146128080Semax 147128080Semax case 0x020d: /* HIDNormallyConnectable */ 148128080Semax normally_connectable = hid_sdp_parse_boolean(&values[i]); 149128080Semax break; 150128080Semax } 151128080Semax } 152128080Semax 153128080Semax if (control_psm == -1 || interrupt_psm == -1 || 154212296Semax reconnect_initiate == -1 || 155128080Semax hid_descriptor == NULL || hid_descriptor_length == -1) 156128080Semax hid_sdp_query_exit(ENOATTR); 157128080Semax 158128080Semax hd->control_psm = control_psm; 159128080Semax hd->interrupt_psm = interrupt_psm; 160128080Semax hd->reconnect_initiate = reconnect_initiate? 1 : 0; 161128080Semax hd->battery_power = battery_power? 1 : 0; 162128080Semax hd->normally_connectable = normally_connectable? 1 : 0; 163128080Semax hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length); 164128080Semax if (hd->desc == NULL) 165128080Semax hid_sdp_query_exit(ENOMEM); 166128080Semax 167128080Semax return (0); 168128080Semax} 169128080Semax 170128080Semax/* 171128080Semax * seq len 2 172128080Semax * seq len 2 173128080Semax * uuid value 3 174128080Semax * uint16 value 3 175128080Semax * seq len 2 176128080Semax * uuid value 3 177128080Semax */ 178128080Semax 179128080Semaxstatic int32_t 180128080Semaxhid_sdp_parse_protocol_descriptor_list(sdp_attr_p a) 181128080Semax{ 182128080Semax uint8_t *ptr = a->value; 183128080Semax uint8_t *end = a->value + a->vlen; 184128080Semax int32_t type, len, uuid, psm; 185128080Semax 186128080Semax if (end - ptr < 15) 187128080Semax return (-1); 188128080Semax 189128080Semax if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) { 190128080Semax SDP_GET8(type, ptr); 191128080Semax switch (type) { 192128080Semax case SDP_DATA_SEQ8: 193128080Semax SDP_GET8(len, ptr); 194128080Semax break; 195128080Semax 196128080Semax case SDP_DATA_SEQ16: 197128080Semax SDP_GET16(len, ptr); 198128080Semax break; 199128080Semax 200128080Semax case SDP_DATA_SEQ32: 201128080Semax SDP_GET32(len, ptr); 202128080Semax break; 203128080Semax 204128080Semax default: 205128080Semax return (-1); 206128080Semax } 207128080Semax if (ptr + len > end) 208128080Semax return (-1); 209128080Semax } 210128080Semax 211128080Semax SDP_GET8(type, ptr); 212128080Semax switch (type) { 213128080Semax case SDP_DATA_SEQ8: 214128080Semax SDP_GET8(len, ptr); 215128080Semax break; 216128080Semax 217128080Semax case SDP_DATA_SEQ16: 218128080Semax SDP_GET16(len, ptr); 219128080Semax break; 220128080Semax 221128080Semax case SDP_DATA_SEQ32: 222128080Semax SDP_GET32(len, ptr); 223128080Semax break; 224128080Semax 225128080Semax default: 226128080Semax return (-1); 227128080Semax } 228128080Semax if (ptr + len > end) 229128080Semax return (-1); 230128080Semax 231128080Semax /* Protocol */ 232128080Semax SDP_GET8(type, ptr); 233128080Semax switch (type) { 234128080Semax case SDP_DATA_SEQ8: 235128080Semax SDP_GET8(len, ptr); 236128080Semax break; 237128080Semax 238128080Semax case SDP_DATA_SEQ16: 239128080Semax SDP_GET16(len, ptr); 240128080Semax break; 241128080Semax 242128080Semax case SDP_DATA_SEQ32: 243128080Semax SDP_GET32(len, ptr); 244128080Semax break; 245128080Semax 246128080Semax default: 247128080Semax return (-1); 248128080Semax } 249128080Semax if (ptr + len > end) 250128080Semax return (-1); 251128080Semax 252128080Semax /* UUID */ 253128080Semax if (ptr + 3 > end) 254128080Semax return (-1); 255128080Semax SDP_GET8(type, ptr); 256128080Semax switch (type) { 257128080Semax case SDP_DATA_UUID16: 258128080Semax SDP_GET16(uuid, ptr); 259128080Semax if (uuid != SDP_UUID_PROTOCOL_L2CAP) 260128080Semax return (-1); 261128080Semax break; 262128080Semax 263128080Semax case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 264128080Semax case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 265128080Semax default: 266128080Semax return (-1); 267128080Semax } 268128080Semax 269128080Semax /* PSM */ 270128080Semax if (ptr + 3 > end) 271128080Semax return (-1); 272128080Semax SDP_GET8(type, ptr); 273128080Semax if (type != SDP_DATA_UINT16) 274128080Semax return (-1); 275128080Semax SDP_GET16(psm, ptr); 276128080Semax 277128080Semax return (psm); 278128080Semax} 279128080Semax 280128080Semax/* 281128080Semax * seq len 2 282128080Semax * seq len 2 283128080Semax * uint8 value8 2 284128080Semax * str value 3 285128080Semax */ 286128080Semax 287128080Semaxstatic int32_t 288128080Semaxhid_sdp_parse_hid_descriptor(sdp_attr_p a) 289128080Semax{ 290128080Semax uint8_t *ptr = a->value; 291128080Semax uint8_t *end = a->value + a->vlen; 292128080Semax int32_t type, len, descriptor_type; 293128080Semax 294128080Semax if (end - ptr < 9) 295128080Semax return (-1); 296128080Semax 297128080Semax SDP_GET8(type, ptr); 298128080Semax switch (type) { 299128080Semax case SDP_DATA_SEQ8: 300128080Semax SDP_GET8(len, ptr); 301128080Semax break; 302128080Semax 303128080Semax case SDP_DATA_SEQ16: 304128080Semax SDP_GET16(len, ptr); 305128080Semax break; 306128080Semax 307128080Semax case SDP_DATA_SEQ32: 308128080Semax SDP_GET32(len, ptr); 309128080Semax break; 310128080Semax 311128080Semax default: 312128080Semax return (-1); 313128080Semax } 314128080Semax if (ptr + len > end) 315128080Semax return (-1); 316128080Semax 317128080Semax while (ptr < end) { 318128080Semax /* Descriptor */ 319128080Semax SDP_GET8(type, ptr); 320128080Semax switch (type) { 321128080Semax case SDP_DATA_SEQ8: 322128080Semax if (ptr + 1 > end) 323128080Semax return (-1); 324128080Semax SDP_GET8(len, ptr); 325128080Semax break; 326128080Semax 327128080Semax case SDP_DATA_SEQ16: 328128080Semax if (ptr + 2 > end) 329128080Semax return (-1); 330128080Semax SDP_GET16(len, ptr); 331128080Semax break; 332128080Semax 333128080Semax case SDP_DATA_SEQ32: 334128080Semax if (ptr + 4 > end) 335128080Semax return (-1); 336128080Semax SDP_GET32(len, ptr); 337128080Semax break; 338128080Semax 339128080Semax default: 340128080Semax return (-1); 341128080Semax } 342128080Semax 343128080Semax /* Descripor type */ 344128080Semax if (ptr + 1 > end) 345128080Semax return (-1); 346128080Semax SDP_GET8(type, ptr); 347128080Semax if (type != SDP_DATA_UINT8 || ptr + 1 > end) 348128080Semax return (-1); 349128080Semax SDP_GET8(descriptor_type, ptr); 350128080Semax 351128080Semax /* Descriptor value */ 352128080Semax if (ptr + 1 > end) 353128080Semax return (-1); 354128080Semax SDP_GET8(type, ptr); 355128080Semax switch (type) { 356128080Semax case SDP_DATA_STR8: 357128080Semax if (ptr + 1 > end) 358128080Semax return (-1); 359128080Semax SDP_GET8(len, ptr); 360128080Semax break; 361128080Semax 362128080Semax case SDP_DATA_STR16: 363128080Semax if (ptr + 2 > end) 364128080Semax return (-1); 365128080Semax SDP_GET16(len, ptr); 366128080Semax break; 367128080Semax 368128080Semax case SDP_DATA_STR32: 369128080Semax if (ptr + 4 > end) 370128080Semax return (-1); 371128080Semax SDP_GET32(len, ptr); 372128080Semax break; 373128080Semax 374128080Semax default: 375128080Semax return (-1); 376128080Semax } 377128080Semax if (ptr + len > end) 378128080Semax return (-1); 379128080Semax 380128080Semax if (descriptor_type == UDESC_REPORT && len > 0) { 381128080Semax a->value = ptr; 382128080Semax a->vlen = len; 383128080Semax 384128080Semax return (0); 385128080Semax } 386128080Semax 387128080Semax ptr += len; 388128080Semax } 389128080Semax 390128080Semax return (-1); 391128080Semax} 392128080Semax 393128080Semax/* bool8 int8 */ 394128080Semaxstatic int32_t 395128080Semaxhid_sdp_parse_boolean(sdp_attr_p a) 396128080Semax{ 397128080Semax if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL) 398128080Semax return (-1); 399128080Semax 400128080Semax return (a->value[1]); 401128080Semax} 402128080Semax 403128080Semax/* Perform SDP query */ 404128080Semaxstatic int32_t 405128080Semaxhid_query(bdaddr_t *bdaddr, int argc, char **argv) 406128080Semax{ 407128080Semax struct hid_device hd; 408128080Semax int e; 409128080Semax 410128080Semax memcpy(&hd.bdaddr, bdaddr, sizeof(hd.bdaddr)); 411128080Semax if (hid_sdp_query(NULL, &hd, &e) < 0) { 412128080Semax fprintf(stderr, "Could not perform SDP query on the " \ 413128080Semax "device %s. %s (%d)\n", bt_ntoa(bdaddr, NULL), 414128080Semax strerror(e), e); 415128080Semax return (FAILED); 416128080Semax } 417128080Semax 418128080Semax print_hid_device(&hd, stdout); 419128080Semax 420128080Semax return (OK); 421128080Semax} 422128080Semax 423128080Semaxstruct bthid_command sdp_commands[] = 424128080Semax{ 425128080Semax{ 426128080Semax"Query", 427128080Semax"Perform SDP query to the specified device and print HID configuration entry\n"\ 428128080Semax"for the device. The configuration entry should be appended to the Bluetooth\n"\ 429128080Semax"HID daemon configuration file and the daemon should be restarted.\n", 430128080Semaxhid_query 431128080Semax}, 432128080Semax{ NULL, NULL, NULL } 433128080Semax}; 434128080Semax 435