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