]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bluetooth/bthidcontrol/sdp.c
Merge ACPICA 20170929.
[FreeBSD/FreeBSD.git] / usr.sbin / bluetooth / bthidcontrol / sdp.c
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