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