11de7b4b8SPedro F. Giffuni /*- 26490c2ffSMaksim Yevmenkin * sdp.c 36490c2ffSMaksim Yevmenkin * 44d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 51de7b4b8SPedro F. Giffuni * 66490c2ffSMaksim Yevmenkin * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> 76490c2ffSMaksim Yevmenkin * All rights reserved. 86490c2ffSMaksim Yevmenkin * 96490c2ffSMaksim Yevmenkin * Redistribution and use in source and binary forms, with or without 106490c2ffSMaksim Yevmenkin * modification, are permitted provided that the following conditions 116490c2ffSMaksim Yevmenkin * are met: 126490c2ffSMaksim Yevmenkin * 1. Redistributions of source code must retain the above copyright 136490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer. 146490c2ffSMaksim Yevmenkin * 2. Redistributions in binary form must reproduce the above copyright 156490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer in the 166490c2ffSMaksim Yevmenkin * documentation and/or other materials provided with the distribution. 176490c2ffSMaksim Yevmenkin * 186490c2ffSMaksim Yevmenkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 196490c2ffSMaksim Yevmenkin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 206490c2ffSMaksim Yevmenkin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 216490c2ffSMaksim Yevmenkin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 226490c2ffSMaksim Yevmenkin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 236490c2ffSMaksim Yevmenkin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 246490c2ffSMaksim Yevmenkin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 256490c2ffSMaksim Yevmenkin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 266490c2ffSMaksim Yevmenkin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 276490c2ffSMaksim Yevmenkin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 286490c2ffSMaksim Yevmenkin * SUCH DAMAGE. 296490c2ffSMaksim Yevmenkin * 306490c2ffSMaksim Yevmenkin * $Id: sdp.c,v 1.3 2004/02/17 22:14:57 max Exp $ 316490c2ffSMaksim Yevmenkin */ 326490c2ffSMaksim Yevmenkin 33*fdbf7cabSElyes Haouas #include <sys/param.h> 346490c2ffSMaksim Yevmenkin #include <sys/queue.h> 35e6508069SVladimir Kondratyev #include <sys/sysctl.h> 368d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED 376490c2ffSMaksim Yevmenkin #include <bluetooth.h> 386490c2ffSMaksim Yevmenkin #include <dev/usb/usb.h> 396490c2ffSMaksim Yevmenkin #include <dev/usb/usbhid.h> 406490c2ffSMaksim Yevmenkin #include <errno.h> 416490c2ffSMaksim Yevmenkin #include <sdp.h> 426490c2ffSMaksim Yevmenkin #include <stdio.h> 436490c2ffSMaksim Yevmenkin #include <string.h> 446490c2ffSMaksim Yevmenkin #include <usbhid.h> 456490c2ffSMaksim Yevmenkin #include "bthid_config.h" 466490c2ffSMaksim Yevmenkin #include "bthidcontrol.h" 476490c2ffSMaksim Yevmenkin 486490c2ffSMaksim Yevmenkin static int32_t hid_sdp_query (bdaddr_t const *local, struct hid_device *hd, int32_t *error); 496490c2ffSMaksim Yevmenkin static int32_t hid_sdp_parse_protocol_descriptor_list (sdp_attr_p a); 506490c2ffSMaksim Yevmenkin static int32_t hid_sdp_parse_hid_descriptor (sdp_attr_p a); 516490c2ffSMaksim Yevmenkin static int32_t hid_sdp_parse_boolean (sdp_attr_p a); 526490c2ffSMaksim Yevmenkin 536032284eSVladimir Kondratyev /* 5466ebda7aSElyes Haouas * Hard coded attribute IDs taken from the 556032284eSVladimir Kondratyev * DEVICE IDENTIFICATION PROFILE SPECIFICATION V13 p.12 566032284eSVladimir Kondratyev */ 576032284eSVladimir Kondratyev 586032284eSVladimir Kondratyev #define SDP_ATTR_DEVICE_ID_SERVICE_VENDORID 0x0201 596032284eSVladimir Kondratyev #define SDP_ATTR_DEVICE_ID_SERVICE_PRODUCTID 0x0202 606032284eSVladimir Kondratyev #define SDP_ATTR_DEVICE_ID_SERVICE_VERSION 0x0203 616032284eSVladimir Kondratyev #define SDP_ATTR_DEVICE_ID_RANGE SDP_ATTR_RANGE( \ 626032284eSVladimir Kondratyev SDP_ATTR_DEVICE_ID_SERVICE_VENDORID, SDP_ATTR_DEVICE_ID_SERVICE_VERSION ) 636032284eSVladimir Kondratyev 646490c2ffSMaksim Yevmenkin static uint16_t service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE; 656032284eSVladimir Kondratyev static uint16_t service_devid = SDP_SERVICE_CLASS_PNP_INFORMATION; 666032284eSVladimir Kondratyev static uint32_t attrs_devid = SDP_ATTR_DEVICE_ID_RANGE; 676490c2ffSMaksim Yevmenkin 686490c2ffSMaksim Yevmenkin static uint32_t attrs[] = { 696490c2ffSMaksim Yevmenkin SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 706490c2ffSMaksim Yevmenkin SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), 716490c2ffSMaksim Yevmenkin SDP_ATTR_RANGE (SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS, 726490c2ffSMaksim Yevmenkin SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS), 736490c2ffSMaksim Yevmenkin SDP_ATTR_RANGE( 0x0205, /* HIDReconnectInitiate */ 7433e98adeSMaksim Yevmenkin 0x0205), 7533e98adeSMaksim Yevmenkin SDP_ATTR_RANGE( 0x0206, /* HIDDescriptorList */ 7633e98adeSMaksim Yevmenkin 0x0206), 77595dedc1SMarkus Brueffer SDP_ATTR_RANGE( 0x0209, /* HIDBatteryPower */ 78595dedc1SMarkus Brueffer 0x0209), 796490c2ffSMaksim Yevmenkin SDP_ATTR_RANGE( 0x020d, /* HIDNormallyConnectable */ 806490c2ffSMaksim Yevmenkin 0x020d) 816490c2ffSMaksim Yevmenkin }; 82*fdbf7cabSElyes Haouas #define nattrs nitems(attrs) 836490c2ffSMaksim Yevmenkin 846490c2ffSMaksim Yevmenkin static sdp_attr_t values[8]; 85*fdbf7cabSElyes Haouas #define nvalues nitems(values) 866490c2ffSMaksim Yevmenkin 876490c2ffSMaksim Yevmenkin static uint8_t buffer[nvalues][512]; 886490c2ffSMaksim Yevmenkin 896490c2ffSMaksim Yevmenkin /* 906490c2ffSMaksim Yevmenkin * Query remote device 916490c2ffSMaksim Yevmenkin */ 926490c2ffSMaksim Yevmenkin 936490c2ffSMaksim Yevmenkin #undef hid_sdp_query_exit 946490c2ffSMaksim Yevmenkin #define hid_sdp_query_exit(e) { \ 956490c2ffSMaksim Yevmenkin if (error != NULL) \ 966490c2ffSMaksim Yevmenkin *error = (e); \ 976490c2ffSMaksim Yevmenkin if (ss != NULL) { \ 986490c2ffSMaksim Yevmenkin sdp_close(ss); \ 996490c2ffSMaksim Yevmenkin ss = NULL; \ 1006490c2ffSMaksim Yevmenkin } \ 1016490c2ffSMaksim Yevmenkin return (((e) == 0)? 0 : -1); \ 1026490c2ffSMaksim Yevmenkin } 1036490c2ffSMaksim Yevmenkin 1046032284eSVladimir Kondratyev static void 1056032284eSVladimir Kondratyev hid_init_return_values() { 1066032284eSVladimir Kondratyev int i; 1076490c2ffSMaksim Yevmenkin for (i = 0; i < nvalues; i ++) { 1086490c2ffSMaksim Yevmenkin values[i].flags = SDP_ATTR_INVALID; 1096490c2ffSMaksim Yevmenkin values[i].attr = 0; 1106490c2ffSMaksim Yevmenkin values[i].vlen = sizeof(buffer[i]); 1116490c2ffSMaksim Yevmenkin values[i].value = buffer[i]; 1126490c2ffSMaksim Yevmenkin } 1136032284eSVladimir Kondratyev } 1146032284eSVladimir Kondratyev 1156032284eSVladimir Kondratyev static int32_t 1166032284eSVladimir Kondratyev hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error) 1176032284eSVladimir Kondratyev { 1186032284eSVladimir Kondratyev void *ss = NULL; 1196032284eSVladimir Kondratyev uint8_t *hid_descriptor = NULL, *v; 1206032284eSVladimir Kondratyev int32_t i, control_psm = -1, interrupt_psm = -1, 1216032284eSVladimir Kondratyev reconnect_initiate = -1, 1226032284eSVladimir Kondratyev normally_connectable = 0, battery_power = 0, 1236032284eSVladimir Kondratyev hid_descriptor_length = -1, type; 1246032284eSVladimir Kondratyev int16_t vendor_id = 0, product_id = 0, version = 0; 125e6508069SVladimir Kondratyev bdaddr_t sdp_local; 126e6508069SVladimir Kondratyev char devname[HCI_DEVNAME_SIZE]; 1276032284eSVladimir Kondratyev 1286032284eSVladimir Kondratyev if (local == NULL) 1296032284eSVladimir Kondratyev local = NG_HCI_BDADDR_ANY; 1306032284eSVladimir Kondratyev if (hd == NULL) 1316032284eSVladimir Kondratyev hid_sdp_query_exit(EINVAL); 1326032284eSVladimir Kondratyev 1336032284eSVladimir Kondratyev hid_init_return_values(); 1346490c2ffSMaksim Yevmenkin 1356490c2ffSMaksim Yevmenkin if ((ss = sdp_open(local, &hd->bdaddr)) == NULL) 1366490c2ffSMaksim Yevmenkin hid_sdp_query_exit(ENOMEM); 1376490c2ffSMaksim Yevmenkin if (sdp_error(ss) != 0) 1386490c2ffSMaksim Yevmenkin hid_sdp_query_exit(sdp_error(ss)); 1396490c2ffSMaksim Yevmenkin if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0) 1406490c2ffSMaksim Yevmenkin hid_sdp_query_exit(sdp_error(ss)); 1416490c2ffSMaksim Yevmenkin 1426490c2ffSMaksim Yevmenkin for (i = 0; i < nvalues; i ++) { 1436490c2ffSMaksim Yevmenkin if (values[i].flags != SDP_ATTR_OK) 1446490c2ffSMaksim Yevmenkin continue; 1456490c2ffSMaksim Yevmenkin 1466490c2ffSMaksim Yevmenkin switch (values[i].attr) { 1476490c2ffSMaksim Yevmenkin case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: 1486490c2ffSMaksim Yevmenkin control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); 1496490c2ffSMaksim Yevmenkin break; 1506490c2ffSMaksim Yevmenkin 1516490c2ffSMaksim Yevmenkin case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: 1526490c2ffSMaksim Yevmenkin interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); 1536490c2ffSMaksim Yevmenkin break; 1546490c2ffSMaksim Yevmenkin 1556490c2ffSMaksim Yevmenkin case 0x0205: /* HIDReconnectInitiate */ 1566490c2ffSMaksim Yevmenkin reconnect_initiate = hid_sdp_parse_boolean(&values[i]); 1576490c2ffSMaksim Yevmenkin break; 1586490c2ffSMaksim Yevmenkin 159595dedc1SMarkus Brueffer case 0x0206: /* HIDDescriptorList */ 1606490c2ffSMaksim Yevmenkin if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) { 1616490c2ffSMaksim Yevmenkin hid_descriptor = values[i].value; 1626490c2ffSMaksim Yevmenkin hid_descriptor_length = values[i].vlen; 1636490c2ffSMaksim Yevmenkin } 1646490c2ffSMaksim Yevmenkin break; 1656490c2ffSMaksim Yevmenkin 166595dedc1SMarkus Brueffer case 0x0209: /* HIDBatteryPower */ 1676490c2ffSMaksim Yevmenkin battery_power = hid_sdp_parse_boolean(&values[i]); 1686490c2ffSMaksim Yevmenkin break; 1696490c2ffSMaksim Yevmenkin 1706490c2ffSMaksim Yevmenkin case 0x020d: /* HIDNormallyConnectable */ 1716490c2ffSMaksim Yevmenkin normally_connectable = hid_sdp_parse_boolean(&values[i]); 1726490c2ffSMaksim Yevmenkin break; 1736490c2ffSMaksim Yevmenkin } 1746490c2ffSMaksim Yevmenkin } 1756490c2ffSMaksim Yevmenkin 1766032284eSVladimir Kondratyev hid_init_return_values(); 1776032284eSVladimir Kondratyev 1786032284eSVladimir Kondratyev if (sdp_search(ss, 1, &service_devid, 1, &attrs_devid, nvalues, values) != 0) 1796032284eSVladimir Kondratyev hid_sdp_query_exit(sdp_error(ss)); 1806032284eSVladimir Kondratyev 181e6508069SVladimir Kondratyev /* Try extract HCI bdaddr from opened SDP session */ 182e6508069SVladimir Kondratyev if (sdp_get_lcaddr(ss, &sdp_local) != 0 || 183e6508069SVladimir Kondratyev bt_devname(devname, &sdp_local) == 0) 184e6508069SVladimir Kondratyev hid_sdp_query_exit(ENOATTR); 185e6508069SVladimir Kondratyev 1866032284eSVladimir Kondratyev sdp_close(ss); 1876032284eSVladimir Kondratyev ss = NULL; 1886032284eSVladimir Kondratyev 1896032284eSVladimir Kondratyev /* If search is successful, scan through return vals */ 1906032284eSVladimir Kondratyev for (i = 0; i < 3; i ++ ) { 1916032284eSVladimir Kondratyev if (values[i].flags == SDP_ATTR_INVALID ) 1926032284eSVladimir Kondratyev continue; 1936032284eSVladimir Kondratyev 1946032284eSVladimir Kondratyev /* Expecting tag + uint16_t on all 3 attributes */ 1956032284eSVladimir Kondratyev if (values[i].vlen != 3) 1966032284eSVladimir Kondratyev continue; 1976032284eSVladimir Kondratyev 1986032284eSVladimir Kondratyev /* Make sure, we're reading a uint16_t */ 1996032284eSVladimir Kondratyev v = values[i].value; 2006032284eSVladimir Kondratyev SDP_GET8(type, v); 2016032284eSVladimir Kondratyev if (type != SDP_DATA_UINT16 ) 2026032284eSVladimir Kondratyev continue; 2036032284eSVladimir Kondratyev 2046032284eSVladimir Kondratyev switch (values[i].attr) { 2056032284eSVladimir Kondratyev case SDP_ATTR_DEVICE_ID_SERVICE_VENDORID: 2066032284eSVladimir Kondratyev SDP_GET16(vendor_id, v); 2076032284eSVladimir Kondratyev break; 2086032284eSVladimir Kondratyev case SDP_ATTR_DEVICE_ID_SERVICE_PRODUCTID: 2096032284eSVladimir Kondratyev SDP_GET16(product_id, v); 2106032284eSVladimir Kondratyev break; 2116032284eSVladimir Kondratyev case SDP_ATTR_DEVICE_ID_SERVICE_VERSION: 2126032284eSVladimir Kondratyev SDP_GET16(version, v); 2136032284eSVladimir Kondratyev break; 2146032284eSVladimir Kondratyev default: 2156032284eSVladimir Kondratyev break; 2166032284eSVladimir Kondratyev } 2176032284eSVladimir Kondratyev } 2186032284eSVladimir Kondratyev 2196490c2ffSMaksim Yevmenkin if (control_psm == -1 || interrupt_psm == -1 || 22033e98adeSMaksim Yevmenkin reconnect_initiate == -1 || 2216490c2ffSMaksim Yevmenkin hid_descriptor == NULL || hid_descriptor_length == -1) 2226490c2ffSMaksim Yevmenkin hid_sdp_query_exit(ENOATTR); 223e6508069SVladimir Kondratyev hd->name = bt_devremote_name_gen(devname, &hd->bdaddr); 2246032284eSVladimir Kondratyev hd->vendor_id = vendor_id; 2256032284eSVladimir Kondratyev hd->product_id = product_id; 2266032284eSVladimir Kondratyev hd->version = version; 2276490c2ffSMaksim Yevmenkin hd->control_psm = control_psm; 2286490c2ffSMaksim Yevmenkin hd->interrupt_psm = interrupt_psm; 2296490c2ffSMaksim Yevmenkin hd->reconnect_initiate = reconnect_initiate? 1 : 0; 2306490c2ffSMaksim Yevmenkin hd->battery_power = battery_power? 1 : 0; 2316490c2ffSMaksim Yevmenkin hd->normally_connectable = normally_connectable? 1 : 0; 2326490c2ffSMaksim Yevmenkin hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length); 2336490c2ffSMaksim Yevmenkin if (hd->desc == NULL) 2346490c2ffSMaksim Yevmenkin hid_sdp_query_exit(ENOMEM); 2356490c2ffSMaksim Yevmenkin 2366490c2ffSMaksim Yevmenkin return (0); 2376490c2ffSMaksim Yevmenkin } 2386490c2ffSMaksim Yevmenkin 2396490c2ffSMaksim Yevmenkin /* 2406490c2ffSMaksim Yevmenkin * seq len 2 2416490c2ffSMaksim Yevmenkin * seq len 2 2426490c2ffSMaksim Yevmenkin * uuid value 3 2436490c2ffSMaksim Yevmenkin * uint16 value 3 2446490c2ffSMaksim Yevmenkin * seq len 2 2456490c2ffSMaksim Yevmenkin * uuid value 3 2466490c2ffSMaksim Yevmenkin */ 2476490c2ffSMaksim Yevmenkin 2486490c2ffSMaksim Yevmenkin static int32_t 2496490c2ffSMaksim Yevmenkin hid_sdp_parse_protocol_descriptor_list(sdp_attr_p a) 2506490c2ffSMaksim Yevmenkin { 2516490c2ffSMaksim Yevmenkin uint8_t *ptr = a->value; 2526490c2ffSMaksim Yevmenkin uint8_t *end = a->value + a->vlen; 2536490c2ffSMaksim Yevmenkin int32_t type, len, uuid, psm; 2546490c2ffSMaksim Yevmenkin 2556490c2ffSMaksim Yevmenkin if (end - ptr < 15) 2566490c2ffSMaksim Yevmenkin return (-1); 2576490c2ffSMaksim Yevmenkin 2586490c2ffSMaksim Yevmenkin if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) { 2596490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 2606490c2ffSMaksim Yevmenkin switch (type) { 2616490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 2626490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 2636490c2ffSMaksim Yevmenkin break; 2646490c2ffSMaksim Yevmenkin 2656490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 2666490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 2676490c2ffSMaksim Yevmenkin break; 2686490c2ffSMaksim Yevmenkin 2696490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 2706490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 2716490c2ffSMaksim Yevmenkin break; 2726490c2ffSMaksim Yevmenkin 2736490c2ffSMaksim Yevmenkin default: 2746490c2ffSMaksim Yevmenkin return (-1); 2756490c2ffSMaksim Yevmenkin } 2766490c2ffSMaksim Yevmenkin if (ptr + len > end) 2776490c2ffSMaksim Yevmenkin return (-1); 2786490c2ffSMaksim Yevmenkin } 2796490c2ffSMaksim Yevmenkin 2806490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 2816490c2ffSMaksim Yevmenkin switch (type) { 2826490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 2836490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 2846490c2ffSMaksim Yevmenkin break; 2856490c2ffSMaksim Yevmenkin 2866490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 2876490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 2886490c2ffSMaksim Yevmenkin break; 2896490c2ffSMaksim Yevmenkin 2906490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 2916490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 2926490c2ffSMaksim Yevmenkin break; 2936490c2ffSMaksim Yevmenkin 2946490c2ffSMaksim Yevmenkin default: 2956490c2ffSMaksim Yevmenkin return (-1); 2966490c2ffSMaksim Yevmenkin } 2976490c2ffSMaksim Yevmenkin if (ptr + len > end) 2986490c2ffSMaksim Yevmenkin return (-1); 2996490c2ffSMaksim Yevmenkin 3006490c2ffSMaksim Yevmenkin /* Protocol */ 3016490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 3026490c2ffSMaksim Yevmenkin switch (type) { 3036490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 3046490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 3056490c2ffSMaksim Yevmenkin break; 3066490c2ffSMaksim Yevmenkin 3076490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 3086490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 3096490c2ffSMaksim Yevmenkin break; 3106490c2ffSMaksim Yevmenkin 3116490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 3126490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 3136490c2ffSMaksim Yevmenkin break; 3146490c2ffSMaksim Yevmenkin 3156490c2ffSMaksim Yevmenkin default: 3166490c2ffSMaksim Yevmenkin return (-1); 3176490c2ffSMaksim Yevmenkin } 3186490c2ffSMaksim Yevmenkin if (ptr + len > end) 3196490c2ffSMaksim Yevmenkin return (-1); 3206490c2ffSMaksim Yevmenkin 3216490c2ffSMaksim Yevmenkin /* UUID */ 3226490c2ffSMaksim Yevmenkin if (ptr + 3 > end) 3236490c2ffSMaksim Yevmenkin return (-1); 3246490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 3256490c2ffSMaksim Yevmenkin switch (type) { 3266490c2ffSMaksim Yevmenkin case SDP_DATA_UUID16: 3276490c2ffSMaksim Yevmenkin SDP_GET16(uuid, ptr); 3286490c2ffSMaksim Yevmenkin if (uuid != SDP_UUID_PROTOCOL_L2CAP) 3296490c2ffSMaksim Yevmenkin return (-1); 3306490c2ffSMaksim Yevmenkin break; 3316490c2ffSMaksim Yevmenkin 3326490c2ffSMaksim Yevmenkin case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 3336490c2ffSMaksim Yevmenkin case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 3346490c2ffSMaksim Yevmenkin default: 3356490c2ffSMaksim Yevmenkin return (-1); 3366490c2ffSMaksim Yevmenkin } 3376490c2ffSMaksim Yevmenkin 3386490c2ffSMaksim Yevmenkin /* PSM */ 3396490c2ffSMaksim Yevmenkin if (ptr + 3 > end) 3406490c2ffSMaksim Yevmenkin return (-1); 3416490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 3426490c2ffSMaksim Yevmenkin if (type != SDP_DATA_UINT16) 3436490c2ffSMaksim Yevmenkin return (-1); 3446490c2ffSMaksim Yevmenkin SDP_GET16(psm, ptr); 3456490c2ffSMaksim Yevmenkin 3466490c2ffSMaksim Yevmenkin return (psm); 3476490c2ffSMaksim Yevmenkin } 3486490c2ffSMaksim Yevmenkin 3496490c2ffSMaksim Yevmenkin /* 3506490c2ffSMaksim Yevmenkin * seq len 2 3516490c2ffSMaksim Yevmenkin * seq len 2 3526490c2ffSMaksim Yevmenkin * uint8 value8 2 3536490c2ffSMaksim Yevmenkin * str value 3 3546490c2ffSMaksim Yevmenkin */ 3556490c2ffSMaksim Yevmenkin 3566490c2ffSMaksim Yevmenkin static int32_t 3576490c2ffSMaksim Yevmenkin hid_sdp_parse_hid_descriptor(sdp_attr_p a) 3586490c2ffSMaksim Yevmenkin { 3596490c2ffSMaksim Yevmenkin uint8_t *ptr = a->value; 3606490c2ffSMaksim Yevmenkin uint8_t *end = a->value + a->vlen; 3616490c2ffSMaksim Yevmenkin int32_t type, len, descriptor_type; 3626490c2ffSMaksim Yevmenkin 3636490c2ffSMaksim Yevmenkin if (end - ptr < 9) 3646490c2ffSMaksim Yevmenkin return (-1); 3656490c2ffSMaksim Yevmenkin 3666490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 3676490c2ffSMaksim Yevmenkin switch (type) { 3686490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 3696490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 3706490c2ffSMaksim Yevmenkin break; 3716490c2ffSMaksim Yevmenkin 3726490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 3736490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 3746490c2ffSMaksim Yevmenkin break; 3756490c2ffSMaksim Yevmenkin 3766490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 3776490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 3786490c2ffSMaksim Yevmenkin break; 3796490c2ffSMaksim Yevmenkin 3806490c2ffSMaksim Yevmenkin default: 3816490c2ffSMaksim Yevmenkin return (-1); 3826490c2ffSMaksim Yevmenkin } 3836490c2ffSMaksim Yevmenkin if (ptr + len > end) 3846490c2ffSMaksim Yevmenkin return (-1); 3856490c2ffSMaksim Yevmenkin 3866490c2ffSMaksim Yevmenkin while (ptr < end) { 3876490c2ffSMaksim Yevmenkin /* Descriptor */ 3886490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 3896490c2ffSMaksim Yevmenkin switch (type) { 3906490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 3916490c2ffSMaksim Yevmenkin if (ptr + 1 > end) 3926490c2ffSMaksim Yevmenkin return (-1); 3936490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 3946490c2ffSMaksim Yevmenkin break; 3956490c2ffSMaksim Yevmenkin 3966490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 3976490c2ffSMaksim Yevmenkin if (ptr + 2 > end) 3986490c2ffSMaksim Yevmenkin return (-1); 3996490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 4006490c2ffSMaksim Yevmenkin break; 4016490c2ffSMaksim Yevmenkin 4026490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 4036490c2ffSMaksim Yevmenkin if (ptr + 4 > end) 4046490c2ffSMaksim Yevmenkin return (-1); 4056490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 4066490c2ffSMaksim Yevmenkin break; 4076490c2ffSMaksim Yevmenkin 4086490c2ffSMaksim Yevmenkin default: 4096490c2ffSMaksim Yevmenkin return (-1); 4106490c2ffSMaksim Yevmenkin } 4116490c2ffSMaksim Yevmenkin 4126490c2ffSMaksim Yevmenkin /* Descripor type */ 4136490c2ffSMaksim Yevmenkin if (ptr + 1 > end) 4146490c2ffSMaksim Yevmenkin return (-1); 4156490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 4166490c2ffSMaksim Yevmenkin if (type != SDP_DATA_UINT8 || ptr + 1 > end) 4176490c2ffSMaksim Yevmenkin return (-1); 4186490c2ffSMaksim Yevmenkin SDP_GET8(descriptor_type, ptr); 4196490c2ffSMaksim Yevmenkin 4206490c2ffSMaksim Yevmenkin /* Descriptor value */ 4216490c2ffSMaksim Yevmenkin if (ptr + 1 > end) 4226490c2ffSMaksim Yevmenkin return (-1); 4236490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 4246490c2ffSMaksim Yevmenkin switch (type) { 4256490c2ffSMaksim Yevmenkin case SDP_DATA_STR8: 4266490c2ffSMaksim Yevmenkin if (ptr + 1 > end) 4276490c2ffSMaksim Yevmenkin return (-1); 4286490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 4296490c2ffSMaksim Yevmenkin break; 4306490c2ffSMaksim Yevmenkin 4316490c2ffSMaksim Yevmenkin case SDP_DATA_STR16: 4326490c2ffSMaksim Yevmenkin if (ptr + 2 > end) 4336490c2ffSMaksim Yevmenkin return (-1); 4346490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 4356490c2ffSMaksim Yevmenkin break; 4366490c2ffSMaksim Yevmenkin 4376490c2ffSMaksim Yevmenkin case SDP_DATA_STR32: 4386490c2ffSMaksim Yevmenkin if (ptr + 4 > end) 4396490c2ffSMaksim Yevmenkin return (-1); 4406490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 4416490c2ffSMaksim Yevmenkin break; 4426490c2ffSMaksim Yevmenkin 4436490c2ffSMaksim Yevmenkin default: 4446490c2ffSMaksim Yevmenkin return (-1); 4456490c2ffSMaksim Yevmenkin } 4466490c2ffSMaksim Yevmenkin if (ptr + len > end) 4476490c2ffSMaksim Yevmenkin return (-1); 4486490c2ffSMaksim Yevmenkin 4496490c2ffSMaksim Yevmenkin if (descriptor_type == UDESC_REPORT && len > 0) { 4506490c2ffSMaksim Yevmenkin a->value = ptr; 4516490c2ffSMaksim Yevmenkin a->vlen = len; 4526490c2ffSMaksim Yevmenkin 4536490c2ffSMaksim Yevmenkin return (0); 4546490c2ffSMaksim Yevmenkin } 4556490c2ffSMaksim Yevmenkin 4566490c2ffSMaksim Yevmenkin ptr += len; 4576490c2ffSMaksim Yevmenkin } 4586490c2ffSMaksim Yevmenkin 4596490c2ffSMaksim Yevmenkin return (-1); 4606490c2ffSMaksim Yevmenkin } 4616490c2ffSMaksim Yevmenkin 4626490c2ffSMaksim Yevmenkin /* bool8 int8 */ 4636490c2ffSMaksim Yevmenkin static int32_t 4646490c2ffSMaksim Yevmenkin hid_sdp_parse_boolean(sdp_attr_p a) 4656490c2ffSMaksim Yevmenkin { 4666490c2ffSMaksim Yevmenkin if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL) 4676490c2ffSMaksim Yevmenkin return (-1); 4686490c2ffSMaksim Yevmenkin 4696490c2ffSMaksim Yevmenkin return (a->value[1]); 4706490c2ffSMaksim Yevmenkin } 4716490c2ffSMaksim Yevmenkin 4726490c2ffSMaksim Yevmenkin /* Perform SDP query */ 4736490c2ffSMaksim Yevmenkin static int32_t 4746490c2ffSMaksim Yevmenkin hid_query(bdaddr_t *bdaddr, int argc, char **argv) 4756490c2ffSMaksim Yevmenkin { 4766490c2ffSMaksim Yevmenkin struct hid_device hd; 4776490c2ffSMaksim Yevmenkin int e; 4786490c2ffSMaksim Yevmenkin 4796490c2ffSMaksim Yevmenkin memcpy(&hd.bdaddr, bdaddr, sizeof(hd.bdaddr)); 4806490c2ffSMaksim Yevmenkin if (hid_sdp_query(NULL, &hd, &e) < 0) { 4816490c2ffSMaksim Yevmenkin fprintf(stderr, "Could not perform SDP query on the " \ 4826490c2ffSMaksim Yevmenkin "device %s. %s (%d)\n", bt_ntoa(bdaddr, NULL), 4836490c2ffSMaksim Yevmenkin strerror(e), e); 4846490c2ffSMaksim Yevmenkin return (FAILED); 4856490c2ffSMaksim Yevmenkin } 4866490c2ffSMaksim Yevmenkin 4876490c2ffSMaksim Yevmenkin print_hid_device(&hd, stdout); 4886490c2ffSMaksim Yevmenkin 4896490c2ffSMaksim Yevmenkin return (OK); 4906490c2ffSMaksim Yevmenkin } 4916490c2ffSMaksim Yevmenkin 4926490c2ffSMaksim Yevmenkin struct bthid_command sdp_commands[] = 4936490c2ffSMaksim Yevmenkin { 4946490c2ffSMaksim Yevmenkin { 4956490c2ffSMaksim Yevmenkin "Query", 4966490c2ffSMaksim Yevmenkin "Perform SDP query to the specified device and print HID configuration entry\n"\ 4976490c2ffSMaksim Yevmenkin "for the device. The configuration entry should be appended to the Bluetooth\n"\ 4986490c2ffSMaksim Yevmenkin "HID daemon configuration file and the daemon should be restarted.\n", 4996490c2ffSMaksim Yevmenkin hid_query 5006490c2ffSMaksim Yevmenkin }, 5016490c2ffSMaksim Yevmenkin { NULL, NULL, NULL } 5026490c2ffSMaksim Yevmenkin }; 5036490c2ffSMaksim Yevmenkin 504