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 static uint16_t service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE;
51
52 static uint32_t attrs[] = {
53 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
54 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
55 SDP_ATTR_RANGE (SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS,
56 SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS),
57 SDP_ATTR_RANGE( 0x0205, /* HIDReconnectInitiate */
58 0x0205),
59 SDP_ATTR_RANGE( 0x0206, /* HIDDescriptorList */
60 0x0206),
61 SDP_ATTR_RANGE( 0x0209, /* HIDBatteryPower */
62 0x0209),
63 SDP_ATTR_RANGE( 0x020d, /* HIDNormallyConnectable */
64 0x020d)
65 };
66 #define nattrs (sizeof(attrs)/sizeof(attrs[0]))
67
68 static sdp_attr_t values[8];
69 #define nvalues (sizeof(values)/sizeof(values[0]))
70
71 static uint8_t buffer[nvalues][512];
72
73 /*
74 * Query remote device
75 */
76
77 #undef hid_sdp_query_exit
78 #define hid_sdp_query_exit(e) { \
79 if (error != NULL) \
80 *error = (e); \
81 if (ss != NULL) { \
82 sdp_close(ss); \
83 ss = NULL; \
84 } \
85 return (((e) == 0)? 0 : -1); \
86 }
87
88 static int32_t
hid_sdp_query(bdaddr_t const * local,struct hid_device * hd,int32_t * error)89 hid_sdp_query(bdaddr_t const *local, struct hid_device *hd, int32_t *error)
90 {
91 void *ss = NULL;
92 uint8_t *hid_descriptor = NULL;
93 int32_t i, control_psm = -1, interrupt_psm = -1,
94 reconnect_initiate = -1,
95 normally_connectable = 0, battery_power = 0,
96 hid_descriptor_length = -1;
97
98 if (local == NULL)
99 local = NG_HCI_BDADDR_ANY;
100 if (hd == NULL)
101 hid_sdp_query_exit(EINVAL);
102
103 for (i = 0; i < nvalues; i ++) {
104 values[i].flags = SDP_ATTR_INVALID;
105 values[i].attr = 0;
106 values[i].vlen = sizeof(buffer[i]);
107 values[i].value = buffer[i];
108 }
109
110 if ((ss = sdp_open(local, &hd->bdaddr)) == NULL)
111 hid_sdp_query_exit(ENOMEM);
112 if (sdp_error(ss) != 0)
113 hid_sdp_query_exit(sdp_error(ss));
114 if (sdp_search(ss, 1, &service, nattrs, attrs, nvalues, values) != 0)
115 hid_sdp_query_exit(sdp_error(ss));
116
117 sdp_close(ss);
118 ss = NULL;
119
120 for (i = 0; i < nvalues; i ++) {
121 if (values[i].flags != SDP_ATTR_OK)
122 continue;
123
124 switch (values[i].attr) {
125 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
126 control_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]);
127 break;
128
129 case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS:
130 interrupt_psm = hid_sdp_parse_protocol_descriptor_list(&values[i]);
131 break;
132
133 case 0x0205: /* HIDReconnectInitiate */
134 reconnect_initiate = hid_sdp_parse_boolean(&values[i]);
135 break;
136
137 case 0x0206: /* HIDDescriptorList */
138 if (hid_sdp_parse_hid_descriptor(&values[i]) == 0) {
139 hid_descriptor = values[i].value;
140 hid_descriptor_length = values[i].vlen;
141 }
142 break;
143
144 case 0x0209: /* HIDBatteryPower */
145 battery_power = hid_sdp_parse_boolean(&values[i]);
146 break;
147
148 case 0x020d: /* HIDNormallyConnectable */
149 normally_connectable = hid_sdp_parse_boolean(&values[i]);
150 break;
151 }
152 }
153
154 if (control_psm == -1 || interrupt_psm == -1 ||
155 reconnect_initiate == -1 ||
156 hid_descriptor == NULL || hid_descriptor_length == -1)
157 hid_sdp_query_exit(ENOATTR);
158
159 hd->control_psm = control_psm;
160 hd->interrupt_psm = interrupt_psm;
161 hd->reconnect_initiate = reconnect_initiate? 1 : 0;
162 hd->battery_power = battery_power? 1 : 0;
163 hd->normally_connectable = normally_connectable? 1 : 0;
164 hd->desc = hid_use_report_desc(hid_descriptor, hid_descriptor_length);
165 if (hd->desc == NULL)
166 hid_sdp_query_exit(ENOMEM);
167
168 return (0);
169 }
170
171 /*
172 * seq len 2
173 * seq len 2
174 * uuid value 3
175 * uint16 value 3
176 * seq len 2
177 * uuid value 3
178 */
179
180 static int32_t
hid_sdp_parse_protocol_descriptor_list(sdp_attr_p a)181 hid_sdp_parse_protocol_descriptor_list(sdp_attr_p a)
182 {
183 uint8_t *ptr = a->value;
184 uint8_t *end = a->value + a->vlen;
185 int32_t type, len, uuid, psm;
186
187 if (end - ptr < 15)
188 return (-1);
189
190 if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) {
191 SDP_GET8(type, ptr);
192 switch (type) {
193 case SDP_DATA_SEQ8:
194 SDP_GET8(len, ptr);
195 break;
196
197 case SDP_DATA_SEQ16:
198 SDP_GET16(len, ptr);
199 break;
200
201 case SDP_DATA_SEQ32:
202 SDP_GET32(len, ptr);
203 break;
204
205 default:
206 return (-1);
207 }
208 if (ptr + len > end)
209 return (-1);
210 }
211
212 SDP_GET8(type, ptr);
213 switch (type) {
214 case SDP_DATA_SEQ8:
215 SDP_GET8(len, ptr);
216 break;
217
218 case SDP_DATA_SEQ16:
219 SDP_GET16(len, ptr);
220 break;
221
222 case SDP_DATA_SEQ32:
223 SDP_GET32(len, ptr);
224 break;
225
226 default:
227 return (-1);
228 }
229 if (ptr + len > end)
230 return (-1);
231
232 /* Protocol */
233 SDP_GET8(type, ptr);
234 switch (type) {
235 case SDP_DATA_SEQ8:
236 SDP_GET8(len, ptr);
237 break;
238
239 case SDP_DATA_SEQ16:
240 SDP_GET16(len, ptr);
241 break;
242
243 case SDP_DATA_SEQ32:
244 SDP_GET32(len, ptr);
245 break;
246
247 default:
248 return (-1);
249 }
250 if (ptr + len > end)
251 return (-1);
252
253 /* UUID */
254 if (ptr + 3 > end)
255 return (-1);
256 SDP_GET8(type, ptr);
257 switch (type) {
258 case SDP_DATA_UUID16:
259 SDP_GET16(uuid, ptr);
260 if (uuid != SDP_UUID_PROTOCOL_L2CAP)
261 return (-1);
262 break;
263
264 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
265 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
266 default:
267 return (-1);
268 }
269
270 /* PSM */
271 if (ptr + 3 > end)
272 return (-1);
273 SDP_GET8(type, ptr);
274 if (type != SDP_DATA_UINT16)
275 return (-1);
276 SDP_GET16(psm, ptr);
277
278 return (psm);
279 }
280
281 /*
282 * seq len 2
283 * seq len 2
284 * uint8 value8 2
285 * str value 3
286 */
287
288 static int32_t
hid_sdp_parse_hid_descriptor(sdp_attr_p a)289 hid_sdp_parse_hid_descriptor(sdp_attr_p a)
290 {
291 uint8_t *ptr = a->value;
292 uint8_t *end = a->value + a->vlen;
293 int32_t type, len, descriptor_type;
294
295 if (end - ptr < 9)
296 return (-1);
297
298 SDP_GET8(type, ptr);
299 switch (type) {
300 case SDP_DATA_SEQ8:
301 SDP_GET8(len, ptr);
302 break;
303
304 case SDP_DATA_SEQ16:
305 SDP_GET16(len, ptr);
306 break;
307
308 case SDP_DATA_SEQ32:
309 SDP_GET32(len, ptr);
310 break;
311
312 default:
313 return (-1);
314 }
315 if (ptr + len > end)
316 return (-1);
317
318 while (ptr < end) {
319 /* Descriptor */
320 SDP_GET8(type, ptr);
321 switch (type) {
322 case SDP_DATA_SEQ8:
323 if (ptr + 1 > end)
324 return (-1);
325 SDP_GET8(len, ptr);
326 break;
327
328 case SDP_DATA_SEQ16:
329 if (ptr + 2 > end)
330 return (-1);
331 SDP_GET16(len, ptr);
332 break;
333
334 case SDP_DATA_SEQ32:
335 if (ptr + 4 > end)
336 return (-1);
337 SDP_GET32(len, ptr);
338 break;
339
340 default:
341 return (-1);
342 }
343
344 /* Descripor type */
345 if (ptr + 1 > end)
346 return (-1);
347 SDP_GET8(type, ptr);
348 if (type != SDP_DATA_UINT8 || ptr + 1 > end)
349 return (-1);
350 SDP_GET8(descriptor_type, ptr);
351
352 /* Descriptor value */
353 if (ptr + 1 > end)
354 return (-1);
355 SDP_GET8(type, ptr);
356 switch (type) {
357 case SDP_DATA_STR8:
358 if (ptr + 1 > end)
359 return (-1);
360 SDP_GET8(len, ptr);
361 break;
362
363 case SDP_DATA_STR16:
364 if (ptr + 2 > end)
365 return (-1);
366 SDP_GET16(len, ptr);
367 break;
368
369 case SDP_DATA_STR32:
370 if (ptr + 4 > end)
371 return (-1);
372 SDP_GET32(len, ptr);
373 break;
374
375 default:
376 return (-1);
377 }
378 if (ptr + len > end)
379 return (-1);
380
381 if (descriptor_type == UDESC_REPORT && len > 0) {
382 a->value = ptr;
383 a->vlen = len;
384
385 return (0);
386 }
387
388 ptr += len;
389 }
390
391 return (-1);
392 }
393
394 /* bool8 int8 */
395 static int32_t
hid_sdp_parse_boolean(sdp_attr_p a)396 hid_sdp_parse_boolean(sdp_attr_p a)
397 {
398 if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL)
399 return (-1);
400
401 return (a->value[1]);
402 }
403
404 /* Perform SDP query */
405 static int32_t
hid_query(bdaddr_t * bdaddr,int argc,char ** argv)406 hid_query(bdaddr_t *bdaddr, int argc, char **argv)
407 {
408 struct hid_device hd;
409 int e;
410
411 memcpy(&hd.bdaddr, bdaddr, sizeof(hd.bdaddr));
412 if (hid_sdp_query(NULL, &hd, &e) < 0) {
413 fprintf(stderr, "Could not perform SDP query on the " \
414 "device %s. %s (%d)\n", bt_ntoa(bdaddr, NULL),
415 strerror(e), e);
416 return (FAILED);
417 }
418
419 print_hid_device(&hd, stdout);
420
421 return (OK);
422 }
423
424 struct bthid_command sdp_commands[] =
425 {
426 {
427 "Query",
428 "Perform SDP query to the specified device and print HID configuration entry\n"\
429 "for the device. The configuration entry should be appended to the Bluetooth\n"\
430 "HID daemon configuration file and the daemon should be restarted.\n",
431 hid_query
432 },
433 { NULL, NULL, NULL }
434 };
435
436