16490c2ffSMaksim Yevmenkin /* 26490c2ffSMaksim Yevmenkin * sdp.c 36490c2ffSMaksim Yevmenkin * 46490c2ffSMaksim Yevmenkin * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> 56490c2ffSMaksim Yevmenkin * All rights reserved. 66490c2ffSMaksim Yevmenkin * 76490c2ffSMaksim Yevmenkin * Redistribution and use in source and binary forms, with or without 86490c2ffSMaksim Yevmenkin * modification, are permitted provided that the following conditions 96490c2ffSMaksim Yevmenkin * are met: 106490c2ffSMaksim Yevmenkin * 1. Redistributions of source code must retain the above copyright 116490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer. 126490c2ffSMaksim Yevmenkin * 2. Redistributions in binary form must reproduce the above copyright 136490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer in the 146490c2ffSMaksim Yevmenkin * documentation and/or other materials provided with the distribution. 156490c2ffSMaksim Yevmenkin * 166490c2ffSMaksim Yevmenkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 176490c2ffSMaksim Yevmenkin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 186490c2ffSMaksim Yevmenkin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 196490c2ffSMaksim Yevmenkin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 206490c2ffSMaksim Yevmenkin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 216490c2ffSMaksim Yevmenkin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 226490c2ffSMaksim Yevmenkin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 236490c2ffSMaksim Yevmenkin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 246490c2ffSMaksim Yevmenkin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 256490c2ffSMaksim Yevmenkin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 266490c2ffSMaksim Yevmenkin * SUCH DAMAGE. 276490c2ffSMaksim Yevmenkin * 286490c2ffSMaksim Yevmenkin * $Id: sdp.c,v 1.3 2004/02/17 22:14:57 max Exp $ 296490c2ffSMaksim Yevmenkin * $FreeBSD$ 306490c2ffSMaksim Yevmenkin */ 316490c2ffSMaksim Yevmenkin 326490c2ffSMaksim Yevmenkin #include <sys/queue.h> 336490c2ffSMaksim Yevmenkin #include <bluetooth.h> 346490c2ffSMaksim Yevmenkin #include <dev/usb/usb.h> 356490c2ffSMaksim Yevmenkin #include <dev/usb/usbhid.h> 366490c2ffSMaksim Yevmenkin #include <errno.h> 376490c2ffSMaksim Yevmenkin #include <sdp.h> 386490c2ffSMaksim Yevmenkin #include <stdio.h> 396490c2ffSMaksim Yevmenkin #include <string.h> 406490c2ffSMaksim Yevmenkin #include <usbhid.h> 416490c2ffSMaksim Yevmenkin #include "bthid_config.h" 426490c2ffSMaksim Yevmenkin #include "bthidcontrol.h" 436490c2ffSMaksim Yevmenkin 446490c2ffSMaksim Yevmenkin static int32_t hid_sdp_query (bdaddr_t const *local, struct hid_device *hd, int32_t *error); 456490c2ffSMaksim Yevmenkin static int32_t hid_sdp_parse_protocol_descriptor_list (sdp_attr_p a); 466490c2ffSMaksim Yevmenkin static int32_t hid_sdp_parse_hid_descriptor (sdp_attr_p a); 476490c2ffSMaksim Yevmenkin static int32_t hid_sdp_parse_boolean (sdp_attr_p a); 486490c2ffSMaksim Yevmenkin 496490c2ffSMaksim Yevmenkin static uint16_t service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE; 506490c2ffSMaksim Yevmenkin 516490c2ffSMaksim Yevmenkin static uint32_t attrs[] = { 526490c2ffSMaksim Yevmenkin SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 536490c2ffSMaksim Yevmenkin SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), 546490c2ffSMaksim Yevmenkin SDP_ATTR_RANGE (SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS, 556490c2ffSMaksim Yevmenkin SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS), 566490c2ffSMaksim Yevmenkin SDP_ATTR_RANGE( 0x0205, /* HIDReconnectInitiate */ 576490c2ffSMaksim Yevmenkin 0x0206), /* HIDDesctiptorList */ 586490c2ffSMaksim Yevmenkin SDP_ATTR_RANGE( 0x020a, /* HIDBatteryPower */ 596490c2ffSMaksim Yevmenkin 0x020a), 606490c2ffSMaksim Yevmenkin SDP_ATTR_RANGE( 0x020d, /* HIDNormallyConnectable */ 616490c2ffSMaksim Yevmenkin 0x020d) 626490c2ffSMaksim Yevmenkin }; 636490c2ffSMaksim Yevmenkin #define nattrs (sizeof(attrs)/sizeof(attrs[0])) 646490c2ffSMaksim Yevmenkin 656490c2ffSMaksim Yevmenkin static sdp_attr_t values[8]; 666490c2ffSMaksim Yevmenkin #define nvalues (sizeof(values)/sizeof(values[0])) 676490c2ffSMaksim Yevmenkin 686490c2ffSMaksim Yevmenkin static uint8_t buffer[nvalues][512]; 696490c2ffSMaksim Yevmenkin 706490c2ffSMaksim Yevmenkin /* 716490c2ffSMaksim Yevmenkin * Query remote device 726490c2ffSMaksim Yevmenkin */ 736490c2ffSMaksim Yevmenkin 746490c2ffSMaksim Yevmenkin #undef hid_sdp_query_exit 756490c2ffSMaksim Yevmenkin #define hid_sdp_query_exit(e) { \ 766490c2ffSMaksim Yevmenkin if (error != NULL) \ 776490c2ffSMaksim Yevmenkin *error = (e); \ 786490c2ffSMaksim Yevmenkin if (ss != NULL) { \ 796490c2ffSMaksim Yevmenkin sdp_close(ss); \ 806490c2ffSMaksim Yevmenkin ss = NULL; \ 816490c2ffSMaksim Yevmenkin } \ 826490c2ffSMaksim Yevmenkin return (((e) == 0)? 0 : -1); \ 836490c2ffSMaksim Yevmenkin } 846490c2ffSMaksim Yevmenkin 856490c2ffSMaksim Yevmenkin static int32_t 866490c2ffSMaksim Yevmenkin hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error) 876490c2ffSMaksim Yevmenkin { 886490c2ffSMaksim Yevmenkin void *ss = NULL; 896490c2ffSMaksim Yevmenkin uint8_t *hid_descriptor = NULL; 906490c2ffSMaksim Yevmenkin int32_t i, control_psm = -1, interrupt_psm = -1, 916490c2ffSMaksim Yevmenkin reconnect_initiate = -1, 926490c2ffSMaksim Yevmenkin normally_connectable = 0, battery_power = 0, 936490c2ffSMaksim Yevmenkin hid_descriptor_length = -1; 946490c2ffSMaksim Yevmenkin 956490c2ffSMaksim Yevmenkin if (local == NULL) 966490c2ffSMaksim Yevmenkin local = NG_HCI_BDADDR_ANY; 976490c2ffSMaksim Yevmenkin if (hd == NULL) 986490c2ffSMaksim Yevmenkin hid_sdp_query_exit(EINVAL); 996490c2ffSMaksim Yevmenkin 1006490c2ffSMaksim Yevmenkin for (i = 0; i < nvalues; i ++) { 1016490c2ffSMaksim Yevmenkin values[i].flags = SDP_ATTR_INVALID; 1026490c2ffSMaksim Yevmenkin values[i].attr = 0; 1036490c2ffSMaksim Yevmenkin values[i].vlen = sizeof(buffer[i]); 1046490c2ffSMaksim Yevmenkin values[i].value = buffer[i]; 1056490c2ffSMaksim Yevmenkin } 1066490c2ffSMaksim Yevmenkin 1076490c2ffSMaksim Yevmenkin if ((ss = sdp_open(local, &hd->bdaddr)) == NULL) 1086490c2ffSMaksim Yevmenkin hid_sdp_query_exit(ENOMEM); 1096490c2ffSMaksim Yevmenkin if (sdp_error(ss) != 0) 1106490c2ffSMaksim Yevmenkin hid_sdp_query_exit(sdp_error(ss)); 1116490c2ffSMaksim Yevmenkin if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0) 1126490c2ffSMaksim Yevmenkin hid_sdp_query_exit(sdp_error(ss)); 1136490c2ffSMaksim Yevmenkin 1146490c2ffSMaksim Yevmenkin sdp_close(ss); 1156490c2ffSMaksim Yevmenkin ss = NULL; 1166490c2ffSMaksim Yevmenkin 1176490c2ffSMaksim Yevmenkin for (i = 0; i < nvalues; i ++) { 1186490c2ffSMaksim Yevmenkin if (values[i].flags != SDP_ATTR_OK) 1196490c2ffSMaksim Yevmenkin continue; 1206490c2ffSMaksim Yevmenkin 1216490c2ffSMaksim Yevmenkin switch (values[i].attr) { 1226490c2ffSMaksim Yevmenkin case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: 1236490c2ffSMaksim Yevmenkin control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); 1246490c2ffSMaksim Yevmenkin break; 1256490c2ffSMaksim Yevmenkin 1266490c2ffSMaksim Yevmenkin case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: 1276490c2ffSMaksim Yevmenkin interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]); 1286490c2ffSMaksim Yevmenkin break; 1296490c2ffSMaksim Yevmenkin 1306490c2ffSMaksim Yevmenkin case 0x0205: /* HIDReconnectInitiate */ 1316490c2ffSMaksim Yevmenkin reconnect_initiate = hid_sdp_parse_boolean(&values[i]); 1326490c2ffSMaksim Yevmenkin break; 1336490c2ffSMaksim Yevmenkin 1346490c2ffSMaksim Yevmenkin case 0x0206: /* HIDDesctiptorList */ 1356490c2ffSMaksim Yevmenkin if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) { 1366490c2ffSMaksim Yevmenkin hid_descriptor = values[i].value; 1376490c2ffSMaksim Yevmenkin hid_descriptor_length = values[i].vlen; 1386490c2ffSMaksim Yevmenkin } 1396490c2ffSMaksim Yevmenkin break; 1406490c2ffSMaksim Yevmenkin 1416490c2ffSMaksim Yevmenkin case 0x020a: /* HIDBatteryPower */ 1426490c2ffSMaksim Yevmenkin battery_power = hid_sdp_parse_boolean(&values[i]); 1436490c2ffSMaksim Yevmenkin break; 1446490c2ffSMaksim Yevmenkin 1456490c2ffSMaksim Yevmenkin case 0x020d: /* HIDNormallyConnectable */ 1466490c2ffSMaksim Yevmenkin normally_connectable = hid_sdp_parse_boolean(&values[i]); 1476490c2ffSMaksim Yevmenkin break; 1486490c2ffSMaksim Yevmenkin } 1496490c2ffSMaksim Yevmenkin } 1506490c2ffSMaksim Yevmenkin 1516490c2ffSMaksim Yevmenkin if (control_psm == -1 || interrupt_psm == -1 || 1526490c2ffSMaksim Yevmenkin reconnect_initiate == -1 || normally_connectable == -1 || 1536490c2ffSMaksim Yevmenkin hid_descriptor == NULL || hid_descriptor_length == -1) 1546490c2ffSMaksim Yevmenkin hid_sdp_query_exit(ENOATTR); 1556490c2ffSMaksim Yevmenkin 1566490c2ffSMaksim Yevmenkin hd->control_psm = control_psm; 1576490c2ffSMaksim Yevmenkin hd->interrupt_psm = interrupt_psm; 1586490c2ffSMaksim Yevmenkin hd->reconnect_initiate = reconnect_initiate? 1 : 0; 1596490c2ffSMaksim Yevmenkin hd->battery_power = battery_power? 1 : 0; 1606490c2ffSMaksim Yevmenkin hd->normally_connectable = normally_connectable? 1 : 0; 1616490c2ffSMaksim Yevmenkin hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length); 1626490c2ffSMaksim Yevmenkin if (hd->desc == NULL) 1636490c2ffSMaksim Yevmenkin hid_sdp_query_exit(ENOMEM); 1646490c2ffSMaksim Yevmenkin 1656490c2ffSMaksim Yevmenkin return (0); 1666490c2ffSMaksim Yevmenkin } 1676490c2ffSMaksim Yevmenkin 1686490c2ffSMaksim Yevmenkin /* 1696490c2ffSMaksim Yevmenkin * seq len 2 1706490c2ffSMaksim Yevmenkin * seq len 2 1716490c2ffSMaksim Yevmenkin * uuid value 3 1726490c2ffSMaksim Yevmenkin * uint16 value 3 1736490c2ffSMaksim Yevmenkin * seq len 2 1746490c2ffSMaksim Yevmenkin * uuid value 3 1756490c2ffSMaksim Yevmenkin */ 1766490c2ffSMaksim Yevmenkin 1776490c2ffSMaksim Yevmenkin static int32_t 1786490c2ffSMaksim Yevmenkin hid_sdp_parse_protocol_descriptor_list(sdp_attr_p a) 1796490c2ffSMaksim Yevmenkin { 1806490c2ffSMaksim Yevmenkin uint8_t *ptr = a->value; 1816490c2ffSMaksim Yevmenkin uint8_t *end = a->value + a->vlen; 1826490c2ffSMaksim Yevmenkin int32_t type, len, uuid, psm; 1836490c2ffSMaksim Yevmenkin 1846490c2ffSMaksim Yevmenkin if (end - ptr < 15) 1856490c2ffSMaksim Yevmenkin return (-1); 1866490c2ffSMaksim Yevmenkin 1876490c2ffSMaksim Yevmenkin if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) { 1886490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 1896490c2ffSMaksim Yevmenkin switch (type) { 1906490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 1916490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 1926490c2ffSMaksim Yevmenkin break; 1936490c2ffSMaksim Yevmenkin 1946490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 1956490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 1966490c2ffSMaksim Yevmenkin break; 1976490c2ffSMaksim Yevmenkin 1986490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 1996490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 2006490c2ffSMaksim Yevmenkin break; 2016490c2ffSMaksim Yevmenkin 2026490c2ffSMaksim Yevmenkin default: 2036490c2ffSMaksim Yevmenkin return (-1); 2046490c2ffSMaksim Yevmenkin } 2056490c2ffSMaksim Yevmenkin if (ptr + len > end) 2066490c2ffSMaksim Yevmenkin return (-1); 2076490c2ffSMaksim Yevmenkin } 2086490c2ffSMaksim Yevmenkin 2096490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 2106490c2ffSMaksim Yevmenkin switch (type) { 2116490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 2126490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 2136490c2ffSMaksim Yevmenkin break; 2146490c2ffSMaksim Yevmenkin 2156490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 2166490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 2176490c2ffSMaksim Yevmenkin break; 2186490c2ffSMaksim Yevmenkin 2196490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 2206490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 2216490c2ffSMaksim Yevmenkin break; 2226490c2ffSMaksim Yevmenkin 2236490c2ffSMaksim Yevmenkin default: 2246490c2ffSMaksim Yevmenkin return (-1); 2256490c2ffSMaksim Yevmenkin } 2266490c2ffSMaksim Yevmenkin if (ptr + len > end) 2276490c2ffSMaksim Yevmenkin return (-1); 2286490c2ffSMaksim Yevmenkin 2296490c2ffSMaksim Yevmenkin /* Protocol */ 2306490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 2316490c2ffSMaksim Yevmenkin switch (type) { 2326490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 2336490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 2346490c2ffSMaksim Yevmenkin break; 2356490c2ffSMaksim Yevmenkin 2366490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 2376490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 2386490c2ffSMaksim Yevmenkin break; 2396490c2ffSMaksim Yevmenkin 2406490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 2416490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 2426490c2ffSMaksim Yevmenkin break; 2436490c2ffSMaksim Yevmenkin 2446490c2ffSMaksim Yevmenkin default: 2456490c2ffSMaksim Yevmenkin return (-1); 2466490c2ffSMaksim Yevmenkin } 2476490c2ffSMaksim Yevmenkin if (ptr + len > end) 2486490c2ffSMaksim Yevmenkin return (-1); 2496490c2ffSMaksim Yevmenkin 2506490c2ffSMaksim Yevmenkin /* UUID */ 2516490c2ffSMaksim Yevmenkin if (ptr + 3 > end) 2526490c2ffSMaksim Yevmenkin return (-1); 2536490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 2546490c2ffSMaksim Yevmenkin switch (type) { 2556490c2ffSMaksim Yevmenkin case SDP_DATA_UUID16: 2566490c2ffSMaksim Yevmenkin SDP_GET16(uuid, ptr); 2576490c2ffSMaksim Yevmenkin if (uuid != SDP_UUID_PROTOCOL_L2CAP) 2586490c2ffSMaksim Yevmenkin return (-1); 2596490c2ffSMaksim Yevmenkin break; 2606490c2ffSMaksim Yevmenkin 2616490c2ffSMaksim Yevmenkin case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 2626490c2ffSMaksim Yevmenkin case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 2636490c2ffSMaksim Yevmenkin default: 2646490c2ffSMaksim Yevmenkin return (-1); 2656490c2ffSMaksim Yevmenkin } 2666490c2ffSMaksim Yevmenkin 2676490c2ffSMaksim Yevmenkin /* PSM */ 2686490c2ffSMaksim Yevmenkin if (ptr + 3 > end) 2696490c2ffSMaksim Yevmenkin return (-1); 2706490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 2716490c2ffSMaksim Yevmenkin if (type != SDP_DATA_UINT16) 2726490c2ffSMaksim Yevmenkin return (-1); 2736490c2ffSMaksim Yevmenkin SDP_GET16(psm, ptr); 2746490c2ffSMaksim Yevmenkin 2756490c2ffSMaksim Yevmenkin return (psm); 2766490c2ffSMaksim Yevmenkin } 2776490c2ffSMaksim Yevmenkin 2786490c2ffSMaksim Yevmenkin /* 2796490c2ffSMaksim Yevmenkin * seq len 2 2806490c2ffSMaksim Yevmenkin * seq len 2 2816490c2ffSMaksim Yevmenkin * uint8 value8 2 2826490c2ffSMaksim Yevmenkin * str value 3 2836490c2ffSMaksim Yevmenkin */ 2846490c2ffSMaksim Yevmenkin 2856490c2ffSMaksim Yevmenkin static int32_t 2866490c2ffSMaksim Yevmenkin hid_sdp_parse_hid_descriptor(sdp_attr_p a) 2876490c2ffSMaksim Yevmenkin { 2886490c2ffSMaksim Yevmenkin uint8_t *ptr = a->value; 2896490c2ffSMaksim Yevmenkin uint8_t *end = a->value + a->vlen; 2906490c2ffSMaksim Yevmenkin int32_t type, len, descriptor_type; 2916490c2ffSMaksim Yevmenkin 2926490c2ffSMaksim Yevmenkin if (end - ptr < 9) 2936490c2ffSMaksim Yevmenkin return (-1); 2946490c2ffSMaksim Yevmenkin 2956490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 2966490c2ffSMaksim Yevmenkin switch (type) { 2976490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 2986490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 2996490c2ffSMaksim Yevmenkin break; 3006490c2ffSMaksim Yevmenkin 3016490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 3026490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 3036490c2ffSMaksim Yevmenkin break; 3046490c2ffSMaksim Yevmenkin 3056490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 3066490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 3076490c2ffSMaksim Yevmenkin break; 3086490c2ffSMaksim Yevmenkin 3096490c2ffSMaksim Yevmenkin default: 3106490c2ffSMaksim Yevmenkin return (-1); 3116490c2ffSMaksim Yevmenkin } 3126490c2ffSMaksim Yevmenkin if (ptr + len > end) 3136490c2ffSMaksim Yevmenkin return (-1); 3146490c2ffSMaksim Yevmenkin 3156490c2ffSMaksim Yevmenkin while (ptr < end) { 3166490c2ffSMaksim Yevmenkin /* Descriptor */ 3176490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 3186490c2ffSMaksim Yevmenkin switch (type) { 3196490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ8: 3206490c2ffSMaksim Yevmenkin if (ptr + 1 > end) 3216490c2ffSMaksim Yevmenkin return (-1); 3226490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 3236490c2ffSMaksim Yevmenkin break; 3246490c2ffSMaksim Yevmenkin 3256490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ16: 3266490c2ffSMaksim Yevmenkin if (ptr + 2 > end) 3276490c2ffSMaksim Yevmenkin return (-1); 3286490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 3296490c2ffSMaksim Yevmenkin break; 3306490c2ffSMaksim Yevmenkin 3316490c2ffSMaksim Yevmenkin case SDP_DATA_SEQ32: 3326490c2ffSMaksim Yevmenkin if (ptr + 4 > end) 3336490c2ffSMaksim Yevmenkin return (-1); 3346490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 3356490c2ffSMaksim Yevmenkin break; 3366490c2ffSMaksim Yevmenkin 3376490c2ffSMaksim Yevmenkin default: 3386490c2ffSMaksim Yevmenkin return (-1); 3396490c2ffSMaksim Yevmenkin } 3406490c2ffSMaksim Yevmenkin 3416490c2ffSMaksim Yevmenkin /* Descripor type */ 3426490c2ffSMaksim Yevmenkin if (ptr + 1 > end) 3436490c2ffSMaksim Yevmenkin return (-1); 3446490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 3456490c2ffSMaksim Yevmenkin if (type != SDP_DATA_UINT8 || ptr + 1 > end) 3466490c2ffSMaksim Yevmenkin return (-1); 3476490c2ffSMaksim Yevmenkin SDP_GET8(descriptor_type, ptr); 3486490c2ffSMaksim Yevmenkin 3496490c2ffSMaksim Yevmenkin /* Descriptor value */ 3506490c2ffSMaksim Yevmenkin if (ptr + 1 > end) 3516490c2ffSMaksim Yevmenkin return (-1); 3526490c2ffSMaksim Yevmenkin SDP_GET8(type, ptr); 3536490c2ffSMaksim Yevmenkin switch (type) { 3546490c2ffSMaksim Yevmenkin case SDP_DATA_STR8: 3556490c2ffSMaksim Yevmenkin if (ptr + 1 > end) 3566490c2ffSMaksim Yevmenkin return (-1); 3576490c2ffSMaksim Yevmenkin SDP_GET8(len, ptr); 3586490c2ffSMaksim Yevmenkin break; 3596490c2ffSMaksim Yevmenkin 3606490c2ffSMaksim Yevmenkin case SDP_DATA_STR16: 3616490c2ffSMaksim Yevmenkin if (ptr + 2 > end) 3626490c2ffSMaksim Yevmenkin return (-1); 3636490c2ffSMaksim Yevmenkin SDP_GET16(len, ptr); 3646490c2ffSMaksim Yevmenkin break; 3656490c2ffSMaksim Yevmenkin 3666490c2ffSMaksim Yevmenkin case SDP_DATA_STR32: 3676490c2ffSMaksim Yevmenkin if (ptr + 4 > end) 3686490c2ffSMaksim Yevmenkin return (-1); 3696490c2ffSMaksim Yevmenkin SDP_GET32(len, ptr); 3706490c2ffSMaksim Yevmenkin break; 3716490c2ffSMaksim Yevmenkin 3726490c2ffSMaksim Yevmenkin default: 3736490c2ffSMaksim Yevmenkin return (-1); 3746490c2ffSMaksim Yevmenkin } 3756490c2ffSMaksim Yevmenkin if (ptr + len > end) 3766490c2ffSMaksim Yevmenkin return (-1); 3776490c2ffSMaksim Yevmenkin 3786490c2ffSMaksim Yevmenkin if (descriptor_type == UDESC_REPORT && len > 0) { 3796490c2ffSMaksim Yevmenkin a->value = ptr; 3806490c2ffSMaksim Yevmenkin a->vlen = len; 3816490c2ffSMaksim Yevmenkin 3826490c2ffSMaksim Yevmenkin return (0); 3836490c2ffSMaksim Yevmenkin } 3846490c2ffSMaksim Yevmenkin 3856490c2ffSMaksim Yevmenkin ptr += len; 3866490c2ffSMaksim Yevmenkin } 3876490c2ffSMaksim Yevmenkin 3886490c2ffSMaksim Yevmenkin return (-1); 3896490c2ffSMaksim Yevmenkin } 3906490c2ffSMaksim Yevmenkin 3916490c2ffSMaksim Yevmenkin /* bool8 int8 */ 3926490c2ffSMaksim Yevmenkin static int32_t 3936490c2ffSMaksim Yevmenkin hid_sdp_parse_boolean(sdp_attr_p a) 3946490c2ffSMaksim Yevmenkin { 3956490c2ffSMaksim Yevmenkin if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL) 3966490c2ffSMaksim Yevmenkin return (-1); 3976490c2ffSMaksim Yevmenkin 3986490c2ffSMaksim Yevmenkin return (a->value[1]); 3996490c2ffSMaksim Yevmenkin } 4006490c2ffSMaksim Yevmenkin 4016490c2ffSMaksim Yevmenkin /* Perform SDP query */ 4026490c2ffSMaksim Yevmenkin static int32_t 4036490c2ffSMaksim Yevmenkin hid_query(bdaddr_t *bdaddr, int argc, char **argv) 4046490c2ffSMaksim Yevmenkin { 4056490c2ffSMaksim Yevmenkin struct hid_device hd; 4066490c2ffSMaksim Yevmenkin int e; 4076490c2ffSMaksim Yevmenkin 4086490c2ffSMaksim Yevmenkin memcpy(&hd.bdaddr, bdaddr, sizeof(hd.bdaddr)); 4096490c2ffSMaksim Yevmenkin if (hid_sdp_query(NULL, &hd, &e) < 0) { 4106490c2ffSMaksim Yevmenkin fprintf(stderr, "Could not perform SDP query on the " \ 4116490c2ffSMaksim Yevmenkin "device %s. %s (%d)\n", bt_ntoa(bdaddr, NULL), 4126490c2ffSMaksim Yevmenkin strerror(e), e); 4136490c2ffSMaksim Yevmenkin return (FAILED); 4146490c2ffSMaksim Yevmenkin } 4156490c2ffSMaksim Yevmenkin 4166490c2ffSMaksim Yevmenkin print_hid_device(&hd, stdout); 4176490c2ffSMaksim Yevmenkin 4186490c2ffSMaksim Yevmenkin return (OK); 4196490c2ffSMaksim Yevmenkin } 4206490c2ffSMaksim Yevmenkin 4216490c2ffSMaksim Yevmenkin struct bthid_command sdp_commands[] = 4226490c2ffSMaksim Yevmenkin { 4236490c2ffSMaksim Yevmenkin { 4246490c2ffSMaksim Yevmenkin "Query", 4256490c2ffSMaksim Yevmenkin "Perform SDP query to the specified device and print HID configuration entry\n"\ 4266490c2ffSMaksim Yevmenkin "for the device. The configuration entry should be appended to the Bluetooth\n"\ 4276490c2ffSMaksim Yevmenkin "HID daemon configuration file and the daemon should be restarted.\n", 4286490c2ffSMaksim Yevmenkin hid_query 4296490c2ffSMaksim Yevmenkin }, 4306490c2ffSMaksim Yevmenkin { NULL, NULL, NULL } 4316490c2ffSMaksim Yevmenkin }; 4326490c2ffSMaksim Yevmenkin 433