1128080Semax/*
2128080Semax * sdp.c
3128080Semax *
4128080Semax * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5128080Semax * All rights reserved.
6128080Semax *
7128080Semax * Redistribution and use in source and binary forms, with or without
8128080Semax * modification, are permitted provided that the following conditions
9128080Semax * are met:
10128080Semax * 1. Redistributions of source code must retain the above copyright
11128080Semax *    notice, this list of conditions and the following disclaimer.
12128080Semax * 2. Redistributions in binary form must reproduce the above copyright
13128080Semax *    notice, this list of conditions and the following disclaimer in the
14128080Semax *    documentation and/or other materials provided with the distribution.
15128080Semax *
16128080Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17128080Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18128080Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19128080Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20128080Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21128080Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22128080Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23128080Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24128080Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25128080Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26128080Semax * SUCH DAMAGE.
27128080Semax *
28128080Semax * $Id: sdp.c,v 1.3 2004/02/17 22:14:57 max Exp $
29128080Semax * $FreeBSD$
30128080Semax */
31128080Semax
32128080Semax#include <sys/queue.h>
33128080Semax#include <bluetooth.h>
34128080Semax#include <dev/usb/usb.h>
35128080Semax#include <dev/usb/usbhid.h>
36128080Semax#include <errno.h>
37128080Semax#include <sdp.h>
38128080Semax#include <stdio.h>
39128080Semax#include <string.h>
40128080Semax#include <usbhid.h>
41128080Semax#include "bthid_config.h"
42128080Semax#include "bthidcontrol.h"
43128080Semax
44128080Semaxstatic int32_t hid_sdp_query				(bdaddr_t const *local, struct hid_device *hd, int32_t *error);
45128080Semaxstatic int32_t hid_sdp_parse_protocol_descriptor_list	(sdp_attr_p a);
46128080Semaxstatic int32_t hid_sdp_parse_hid_descriptor		(sdp_attr_p a);
47128080Semaxstatic int32_t hid_sdp_parse_boolean			(sdp_attr_p a);
48128080Semax
49128080Semaxstatic uint16_t		service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
50128080Semax
51128080Semaxstatic uint32_t		attrs[] = {
52128080SemaxSDP_ATTR_RANGE(	SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
53128080Semax		SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
54128080SemaxSDP_ATTR_RANGE	(SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS,
55128080Semax		SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS),
56128080SemaxSDP_ATTR_RANGE(	0x0205,		/* HIDReconnectInitiate */
57212296Semax		0x0205),
58212296SemaxSDP_ATTR_RANGE(	0x0206,		/* HIDDescriptorList */
59212296Semax		0x0206),
60155516SmarkusSDP_ATTR_RANGE(	0x0209,		/* HIDBatteryPower */
61155516Smarkus		0x0209),
62128080SemaxSDP_ATTR_RANGE(	0x020d,		/* HIDNormallyConnectable */
63128080Semax		0x020d)
64128080Semax	};
65128080Semax#define	nattrs	(sizeof(attrs)/sizeof(attrs[0]))
66128080Semax
67128080Semaxstatic sdp_attr_t	values[8];
68128080Semax#define	nvalues	(sizeof(values)/sizeof(values[0]))
69128080Semax
70128080Semaxstatic uint8_t		buffer[nvalues][512];
71128080Semax
72128080Semax/*
73128080Semax * Query remote device
74128080Semax */
75128080Semax
76128080Semax#undef	hid_sdp_query_exit
77128080Semax#define	hid_sdp_query_exit(e) {		\
78128080Semax	if (error != NULL)		\
79128080Semax		*error = (e);		\
80128080Semax	if (ss != NULL) {		\
81128080Semax		sdp_close(ss);		\
82128080Semax		ss = NULL;		\
83128080Semax	}				\
84128080Semax	return (((e) == 0)? 0 : -1);	\
85128080Semax}
86128080Semax
87128080Semaxstatic int32_t
88128080Semaxhid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error)
89128080Semax{
90128080Semax	void	*ss = NULL;
91128080Semax	uint8_t	*hid_descriptor = NULL;
92128080Semax	int32_t	 i, control_psm = -1, interrupt_psm = -1,
93128080Semax		 reconnect_initiate = -1,
94128080Semax		 normally_connectable = 0, battery_power = 0,
95128080Semax		 hid_descriptor_length = -1;
96128080Semax
97128080Semax	if (local == NULL)
98128080Semax		local = NG_HCI_BDADDR_ANY;
99128080Semax	if (hd == NULL)
100128080Semax		hid_sdp_query_exit(EINVAL);
101128080Semax
102128080Semax	for (i = 0; i < nvalues; i ++) {
103128080Semax		values[i].flags = SDP_ATTR_INVALID;
104128080Semax		values[i].attr = 0;
105128080Semax		values[i].vlen = sizeof(buffer[i]);
106128080Semax		values[i].value = buffer[i];
107128080Semax	}
108128080Semax
109128080Semax	if ((ss = sdp_open(local, &hd->bdaddr)) == NULL)
110128080Semax		hid_sdp_query_exit(ENOMEM);
111128080Semax	if (sdp_error(ss) != 0)
112128080Semax		hid_sdp_query_exit(sdp_error(ss));
113128080Semax	if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0)
114128080Semax                hid_sdp_query_exit(sdp_error(ss));
115128080Semax
116128080Semax        sdp_close(ss);
117128080Semax        ss = NULL;
118128080Semax
119128080Semax	for (i = 0; i < nvalues; i ++) {
120128080Semax		if (values[i].flags != SDP_ATTR_OK)
121128080Semax			continue;
122128080Semax
123128080Semax		switch (values[i].attr) {
124128080Semax		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
125128080Semax			control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]);
126128080Semax			break;
127128080Semax
128128080Semax		case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS:
129128080Semax			interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]);
130128080Semax			break;
131128080Semax
132128080Semax		case 0x0205: /* HIDReconnectInitiate */
133128080Semax			reconnect_initiate = hid_sdp_parse_boolean(&values[i]);
134128080Semax			break;
135128080Semax
136155516Smarkus		case 0x0206: /* HIDDescriptorList */
137128080Semax			if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) {
138128080Semax				hid_descriptor = values[i].value;
139128080Semax				hid_descriptor_length = values[i].vlen;
140128080Semax			}
141128080Semax			break;
142128080Semax
143155516Smarkus		case 0x0209: /* HIDBatteryPower */
144128080Semax			battery_power = hid_sdp_parse_boolean(&values[i]);
145128080Semax			break;
146128080Semax
147128080Semax		case 0x020d: /* HIDNormallyConnectable */
148128080Semax			normally_connectable = hid_sdp_parse_boolean(&values[i]);
149128080Semax			break;
150128080Semax		}
151128080Semax	}
152128080Semax
153128080Semax	if (control_psm == -1 || interrupt_psm == -1 ||
154212296Semax	    reconnect_initiate == -1 ||
155128080Semax	    hid_descriptor == NULL || hid_descriptor_length == -1)
156128080Semax		hid_sdp_query_exit(ENOATTR);
157128080Semax
158128080Semax	hd->control_psm = control_psm;
159128080Semax	hd->interrupt_psm = interrupt_psm;
160128080Semax	hd->reconnect_initiate = reconnect_initiate? 1 : 0;
161128080Semax	hd->battery_power = battery_power? 1 : 0;
162128080Semax	hd->normally_connectable = normally_connectable? 1 : 0;
163128080Semax	hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length);
164128080Semax	if (hd->desc == NULL)
165128080Semax		hid_sdp_query_exit(ENOMEM);
166128080Semax
167128080Semax	return (0);
168128080Semax}
169128080Semax
170128080Semax/*
171128080Semax * seq len				2
172128080Semax *	seq len				2
173128080Semax *		uuid value		3
174128080Semax *		uint16 value		3
175128080Semax *		seq len			2
176128080Semax *			uuid value	3
177128080Semax */
178128080Semax
179128080Semaxstatic int32_t
180128080Semaxhid_sdp_parse_protocol_descriptor_list(sdp_attr_p a)
181128080Semax{
182128080Semax	uint8_t	*ptr = a->value;
183128080Semax	uint8_t	*end = a->value + a->vlen;
184128080Semax	int32_t	 type, len, uuid, psm;
185128080Semax
186128080Semax	if (end - ptr < 15)
187128080Semax		return (-1);
188128080Semax
189128080Semax	if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) {
190128080Semax		SDP_GET8(type, ptr);
191128080Semax		switch (type) {
192128080Semax		case SDP_DATA_SEQ8:
193128080Semax			SDP_GET8(len, ptr);
194128080Semax			break;
195128080Semax
196128080Semax		case SDP_DATA_SEQ16:
197128080Semax			SDP_GET16(len, ptr);
198128080Semax			break;
199128080Semax
200128080Semax		case SDP_DATA_SEQ32:
201128080Semax			SDP_GET32(len, ptr);
202128080Semax			break;
203128080Semax
204128080Semax		default:
205128080Semax			return (-1);
206128080Semax		}
207128080Semax		if (ptr + len > end)
208128080Semax			return (-1);
209128080Semax	}
210128080Semax
211128080Semax	SDP_GET8(type, ptr);
212128080Semax	switch (type) {
213128080Semax	case SDP_DATA_SEQ8:
214128080Semax		SDP_GET8(len, ptr);
215128080Semax		break;
216128080Semax
217128080Semax	case SDP_DATA_SEQ16:
218128080Semax		SDP_GET16(len, ptr);
219128080Semax		break;
220128080Semax
221128080Semax	case SDP_DATA_SEQ32:
222128080Semax		SDP_GET32(len, ptr);
223128080Semax		break;
224128080Semax
225128080Semax	default:
226128080Semax		return (-1);
227128080Semax	}
228128080Semax	if (ptr + len > end)
229128080Semax		return (-1);
230128080Semax
231128080Semax	/* Protocol */
232128080Semax	SDP_GET8(type, ptr);
233128080Semax	switch (type) {
234128080Semax	case SDP_DATA_SEQ8:
235128080Semax		SDP_GET8(len, ptr);
236128080Semax		break;
237128080Semax
238128080Semax	case SDP_DATA_SEQ16:
239128080Semax		SDP_GET16(len, ptr);
240128080Semax		break;
241128080Semax
242128080Semax	case SDP_DATA_SEQ32:
243128080Semax		SDP_GET32(len, ptr);
244128080Semax		break;
245128080Semax
246128080Semax	default:
247128080Semax		return (-1);
248128080Semax	}
249128080Semax	if (ptr + len > end)
250128080Semax		return (-1);
251128080Semax
252128080Semax	/* UUID */
253128080Semax	if (ptr + 3 > end)
254128080Semax		return (-1);
255128080Semax	SDP_GET8(type, ptr);
256128080Semax	switch (type) {
257128080Semax	case SDP_DATA_UUID16:
258128080Semax		SDP_GET16(uuid, ptr);
259128080Semax		if (uuid != SDP_UUID_PROTOCOL_L2CAP)
260128080Semax			return (-1);
261128080Semax		break;
262128080Semax
263128080Semax	case SDP_DATA_UUID32:  /* XXX FIXME can we have 32-bit UUID */
264128080Semax	case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
265128080Semax	default:
266128080Semax		return (-1);
267128080Semax	}
268128080Semax
269128080Semax	/* PSM */
270128080Semax	if (ptr + 3 > end)
271128080Semax		return (-1);
272128080Semax	SDP_GET8(type, ptr);
273128080Semax	if (type != SDP_DATA_UINT16)
274128080Semax		return (-1);
275128080Semax	SDP_GET16(psm, ptr);
276128080Semax
277128080Semax	return (psm);
278128080Semax}
279128080Semax
280128080Semax/*
281128080Semax * seq len			2
282128080Semax *	seq len			2
283128080Semax *		uint8 value8	2
284128080Semax * 		str value	3
285128080Semax */
286128080Semax
287128080Semaxstatic int32_t
288128080Semaxhid_sdp_parse_hid_descriptor(sdp_attr_p a)
289128080Semax{
290128080Semax	uint8_t	*ptr = a->value;
291128080Semax	uint8_t	*end = a->value + a->vlen;
292128080Semax	int32_t	 type, len, descriptor_type;
293128080Semax
294128080Semax	if (end - ptr < 9)
295128080Semax		return (-1);
296128080Semax
297128080Semax	SDP_GET8(type, ptr);
298128080Semax	switch (type) {
299128080Semax	case SDP_DATA_SEQ8:
300128080Semax		SDP_GET8(len, ptr);
301128080Semax		break;
302128080Semax
303128080Semax	case SDP_DATA_SEQ16:
304128080Semax		SDP_GET16(len, ptr);
305128080Semax		break;
306128080Semax
307128080Semax	case SDP_DATA_SEQ32:
308128080Semax		SDP_GET32(len, ptr);
309128080Semax		break;
310128080Semax
311128080Semax	default:
312128080Semax		return (-1);
313128080Semax	}
314128080Semax	if (ptr + len > end)
315128080Semax		return (-1);
316128080Semax
317128080Semax	while (ptr < end) {
318128080Semax		/* Descriptor */
319128080Semax		SDP_GET8(type, ptr);
320128080Semax		switch (type) {
321128080Semax		case SDP_DATA_SEQ8:
322128080Semax			if (ptr + 1 > end)
323128080Semax				return (-1);
324128080Semax			SDP_GET8(len, ptr);
325128080Semax			break;
326128080Semax
327128080Semax		case SDP_DATA_SEQ16:
328128080Semax			if (ptr + 2 > end)
329128080Semax				return (-1);
330128080Semax			SDP_GET16(len, ptr);
331128080Semax			break;
332128080Semax
333128080Semax		case SDP_DATA_SEQ32:
334128080Semax			if (ptr + 4 > end)
335128080Semax				return (-1);
336128080Semax			SDP_GET32(len, ptr);
337128080Semax			break;
338128080Semax
339128080Semax		default:
340128080Semax			return (-1);
341128080Semax		}
342128080Semax
343128080Semax		/* Descripor type */
344128080Semax		if (ptr + 1 > end)
345128080Semax			return (-1);
346128080Semax		SDP_GET8(type, ptr);
347128080Semax		if (type != SDP_DATA_UINT8 || ptr + 1 > end)
348128080Semax			return (-1);
349128080Semax		SDP_GET8(descriptor_type, ptr);
350128080Semax
351128080Semax		/* Descriptor value */
352128080Semax		if (ptr + 1 > end)
353128080Semax			return (-1);
354128080Semax		SDP_GET8(type, ptr);
355128080Semax		switch (type) {
356128080Semax		case SDP_DATA_STR8:
357128080Semax			if (ptr + 1 > end)
358128080Semax				return (-1);
359128080Semax			SDP_GET8(len, ptr);
360128080Semax			break;
361128080Semax
362128080Semax		case SDP_DATA_STR16:
363128080Semax			if (ptr + 2 > end)
364128080Semax				return (-1);
365128080Semax			SDP_GET16(len, ptr);
366128080Semax			break;
367128080Semax
368128080Semax		case SDP_DATA_STR32:
369128080Semax			if (ptr + 4 > end)
370128080Semax				return (-1);
371128080Semax			SDP_GET32(len, ptr);
372128080Semax			break;
373128080Semax
374128080Semax		default:
375128080Semax			return (-1);
376128080Semax		}
377128080Semax		if (ptr + len > end)
378128080Semax			return (-1);
379128080Semax
380128080Semax		if (descriptor_type == UDESC_REPORT && len > 0) {
381128080Semax			a->value = ptr;
382128080Semax			a->vlen = len;
383128080Semax
384128080Semax			return (0);
385128080Semax		}
386128080Semax
387128080Semax		ptr += len;
388128080Semax	}
389128080Semax
390128080Semax	return (-1);
391128080Semax}
392128080Semax
393128080Semax/* bool8 int8 */
394128080Semaxstatic int32_t
395128080Semaxhid_sdp_parse_boolean(sdp_attr_p a)
396128080Semax{
397128080Semax	if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL)
398128080Semax		return (-1);
399128080Semax
400128080Semax	return (a->value[1]);
401128080Semax}
402128080Semax
403128080Semax/* Perform SDP query */
404128080Semaxstatic int32_t
405128080Semaxhid_query(bdaddr_t *bdaddr, int argc, char **argv)
406128080Semax{
407128080Semax	struct hid_device	hd;
408128080Semax	int			e;
409128080Semax
410128080Semax	memcpy(&hd.bdaddr, bdaddr, sizeof(hd.bdaddr));
411128080Semax	if (hid_sdp_query(NULL, &hd, &e) < 0) {
412128080Semax		fprintf(stderr, "Could not perform SDP query on the " \
413128080Semax			"device %s. %s (%d)\n", bt_ntoa(bdaddr, NULL),
414128080Semax			strerror(e), e);
415128080Semax		return (FAILED);
416128080Semax	}
417128080Semax
418128080Semax	print_hid_device(&hd, stdout);
419128080Semax
420128080Semax	return (OK);
421128080Semax}
422128080Semax
423128080Semaxstruct bthid_command	sdp_commands[] =
424128080Semax{
425128080Semax{
426128080Semax"Query",
427128080Semax"Perform SDP query to the specified device and print HID configuration entry\n"\
428128080Semax"for the device. The configuration entry should be appended to the Bluetooth\n"\
429128080Semax"HID daemon configuration file and the daemon should be restarted.\n",
430128080Semaxhid_query
431128080Semax},
432128080Semax{ NULL, NULL, NULL }
433128080Semax};
434128080Semax
435