xref: /freebsd/usr.sbin/bluetooth/bthidcontrol/sdp.c (revision f126890ac5386406dadf7c4cfa9566cbb56537c5)
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/types.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	(sizeof(attrs)/sizeof(attrs[0]))
83 
84 static sdp_attr_t	values[8];
85 #define	nvalues	(sizeof(values)/sizeof(values[0]))
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
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
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
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
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
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
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