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