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