]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bluetooth/bthidcontrol/sdp.c
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
[FreeBSD/FreeBSD.git] / usr.sbin / bluetooth / bthidcontrol / sdp.c
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