sdp.c revision 1.2 1 /* $NetBSD: sdp.c,v 1.2 2007/04/11 20:01:01 plunky Exp $ */
2
3 /*-
4 * Copyright (c) 2006 Itronix Inc.
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 * 3. The name of Itronix Inc. may not be used to endorse
16 * or promote products derived from this software without specific
17 * prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 /*
32 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin (at) yahoo.com>
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57 #include <sys/cdefs.h>
58 __RCSID("$NetBSD: sdp.c,v 1.2 2007/04/11 20:01:01 plunky Exp $");
59
60 #include <sys/types.h>
61
62 #include <dev/bluetooth/btdev.h>
63 #include <dev/bluetooth/bthidev.h>
64 #include <dev/bluetooth/btsco.h>
65 #include <dev/usb/usb.h>
66 #include <dev/usb/usbhid.h>
67
68 #include <prop/proplib.h>
69
70 #include <bluetooth.h>
71 #include <err.h>
72 #include <errno.h>
73 #include <sdp.h>
74 #include <stdlib.h>
75 #include <usbhid.h>
76
77 #include "btdevctl.h"
78
79 static int32_t parse_l2cap_psm(sdp_attr_t *);
80 static int32_t parse_rfcomm_channel(sdp_attr_t *);
81 static int32_t parse_hid_descriptor(sdp_attr_t *);
82 static int32_t parse_boolean(sdp_attr_t *);
83
84 static int config_hid(prop_dictionary_t);
85 static int config_hset(prop_dictionary_t);
86 static int config_hf(prop_dictionary_t);
87
88 uint16_t hid_services[] = {
89 SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE
90 };
91
92 uint32_t hid_attrs[] = {
93 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
94 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
95 SDP_ATTR_RANGE( SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS,
96 SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS),
97 SDP_ATTR_RANGE( 0x0205, /* HIDReconnectInitiate */
98 0x0206), /* HIDDescriptorList */
99 SDP_ATTR_RANGE( 0x0209, /* HIDBatteryPower */
100 0x0209),
101 SDP_ATTR_RANGE( 0x020d, /* HIDNormallyConnectable */
102 0x020d)
103 };
104
105 uint16_t hset_services[] = {
106 SDP_SERVICE_CLASS_HEADSET
107 };
108
109 uint32_t hset_attrs[] = {
110 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
111 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
112 };
113
114 uint16_t hf_services[] = {
115 SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY
116 };
117
118 uint32_t hf_attrs[] = {
119 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
120 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
121 };
122
123 #define NUM(v) (sizeof(v) / sizeof(v[0]))
124
125 static struct {
126 const char *name;
127 int (*handler)(prop_dictionary_t);
128 const char *description;
129 uint16_t *services;
130 int nservices;
131 uint32_t *attrs;
132 int nattrs;
133 } cfgtype[] = {
134 {
135 "HID", config_hid, "Human Interface Device",
136 hid_services, NUM(hid_services),
137 hid_attrs, NUM(hid_attrs),
138 },
139 {
140 "HSET", config_hset, "Headset",
141 hset_services, NUM(hset_services),
142 hset_attrs, NUM(hset_attrs),
143 },
144 {
145 "HF", config_hf, "Handsfree",
146 hf_services, NUM(hf_services),
147 hf_attrs, NUM(hf_attrs),
148 },
149 };
150
151 static sdp_attr_t values[8];
152 static uint8_t buffer[NUM(values)][512];
153
154 prop_dictionary_t
155 cfg_query(bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
156 {
157 prop_dictionary_t dict;
158 void *ss;
159 int rv, i;
160
161 dict = prop_dictionary_create();
162 if (dict == NULL)
163 return NULL;
164
165 for (i = 0 ; i < NUM(values) ; i++) {
166 values[i].flags = SDP_ATTR_INVALID;
167 values[i].attr = 0;
168 values[i].vlen = sizeof(buffer[i]);
169 values[i].value = buffer[i];
170 }
171
172 for (i = 0 ; i < NUM(cfgtype) ; i++) {
173 if (strcasecmp(service, cfgtype[i].name) == 0) {
174 ss = sdp_open(laddr, raddr);
175
176 if (ss == NULL || (errno = sdp_error(ss)) != 0)
177 return NULL;
178
179 rv = sdp_search(ss,
180 cfgtype[i].nservices, cfgtype[i].services,
181 cfgtype[i].nattrs, cfgtype[i].attrs,
182 NUM(values), values);
183
184 if (rv != 0) {
185 errno = sdp_error(ss);
186 return NULL;
187 }
188 sdp_close(ss);
189
190 rv = (*cfgtype[i].handler)(dict);
191 if (rv != 0)
192 return NULL;
193
194 return dict;
195 }
196 }
197
198 printf("Known config types:\n");
199 for (i = 0 ; i < NUM(cfgtype) ; i++)
200 printf("\t%s\t%s\n", cfgtype[i].name, cfgtype[i].description);
201
202 exit(EXIT_FAILURE);
203 }
204
205 /*
206 * Configure HID results
207 */
208 static int
209 config_hid(prop_dictionary_t dict)
210 {
211 prop_object_t obj;
212 int32_t control_psm, interrupt_psm,
213 reconnect_initiate, battery_power,
214 normally_connectable, hid_length;
215 uint8_t *hid_descriptor;
216 int i;
217
218 control_psm = -1;
219 interrupt_psm = -1;
220 reconnect_initiate = -1;
221 normally_connectable = 0;
222 battery_power = 0;
223 hid_descriptor = NULL;
224 hid_length = -1;
225
226 for (i = 0; i < NUM(values) ; i++) {
227 if (values[i].flags != SDP_ATTR_OK)
228 continue;
229
230 switch (values[i].attr) {
231 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
232 control_psm = parse_l2cap_psm(&values[i]);
233 break;
234
235 case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS:
236 interrupt_psm = parse_l2cap_psm(&values[i]);
237 break;
238
239 case 0x0205: /* HIDReconnectInitiate */
240 reconnect_initiate = parse_boolean(&values[i]);
241 break;
242
243 case 0x0206: /* HIDDescriptorList */
244 if (parse_hid_descriptor(&values[i]) == 0) {
245 hid_descriptor = values[i].value;
246 hid_length = values[i].vlen;
247 }
248 break;
249
250 case 0x0209: /* HIDBatteryPower */
251 battery_power = parse_boolean(&values[i]);
252 break;
253
254 case 0x020d: /* HIDNormallyConnectable */
255 normally_connectable = parse_boolean(&values[i]);
256 break;
257 }
258 }
259
260 if (control_psm == -1
261 || interrupt_psm == -1
262 || reconnect_initiate == -1
263 || hid_descriptor == NULL
264 || hid_length == -1)
265 return ENOATTR;
266
267 obj = prop_string_create_cstring_nocopy("bthidev");
268 if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj))
269 return errno;
270
271 prop_object_release(obj);
272
273 obj = prop_number_create_integer(control_psm);
274 if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVcontrolpsm, obj))
275 return errno;
276
277 prop_object_release(obj);
278
279 obj = prop_number_create_integer(interrupt_psm);
280 if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVinterruptpsm, obj))
281 return errno;
282
283 prop_object_release(obj);
284
285 obj = prop_data_create_data(hid_descriptor, hid_length);
286 if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVdescriptor, obj))
287 return errno;
288
289 prop_object_release(obj);
290
291 if (!reconnect_initiate) {
292 obj = prop_bool_create(TRUE);
293 if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVreconnect, obj))
294 return errno;
295
296 prop_object_release(obj);
297 }
298
299 return 0;
300 }
301
302 /*
303 * Configure HSET results
304 */
305 static int
306 config_hset(prop_dictionary_t dict)
307 {
308 prop_object_t obj;
309 uint32_t channel;
310 int i;
311
312 channel = -1;
313
314 for (i = 0; i < NUM(values) ; i++) {
315 if (values[i].flags != SDP_ATTR_OK)
316 continue;
317
318 switch (values[i].attr) {
319 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
320 channel = parse_rfcomm_channel(&values[i]);
321 break;
322 }
323 }
324
325 if (channel == -1)
326 return ENOATTR;
327
328 obj = prop_string_create_cstring_nocopy("btsco");
329 if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj))
330 return errno;
331
332 prop_object_release(obj);
333
334 obj = prop_number_create_integer(channel);
335 if (obj == NULL || !prop_dictionary_set(dict, BTSCOchannel, obj))
336 return errno;
337
338 prop_object_release(obj);
339
340 return 0;
341 }
342
343 /*
344 * Configure HF results
345 */
346 static int
347 config_hf(prop_dictionary_t dict)
348 {
349 prop_object_t obj;
350 uint32_t channel;
351 int i;
352
353 channel = -1;
354
355 for (i = 0 ; i < NUM(values) ; i++) {
356 if (values[i].flags != SDP_ATTR_OK)
357 continue;
358
359 switch (values[i].attr) {
360 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
361 channel = parse_rfcomm_channel(&values[i]);
362 break;
363 }
364 }
365
366 if (channel == -1)
367 return ENOATTR;
368
369 obj = prop_string_create_cstring_nocopy("btsco");
370 if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj))
371 return errno;
372
373 prop_object_release(obj);
374
375 obj = prop_bool_create(TRUE);
376 if (obj == NULL || !prop_dictionary_set(dict, BTSCOlisten, obj))
377 return errno;
378
379 prop_object_release(obj);
380
381 obj = prop_number_create_integer(channel);
382 if (obj == NULL || !prop_dictionary_set(dict, BTSCOchannel, obj))
383 return errno;
384
385 prop_object_release(obj);
386
387 return 0;
388 }
389
390 /*
391 * Parse [additional] protocol descriptor list for L2CAP PSM
392 *
393 * seq8 len8 2
394 * seq8 len8 2
395 * uuid16 value16 3 L2CAP
396 * uint16 value16 3 PSM
397 * seq8 len8 2
398 * uuid16 value16 3 HID Protocol
399 * ===
400 * 15
401 */
402
403 static int32_t
404 parse_l2cap_psm(sdp_attr_t *a)
405 {
406 uint8_t *ptr = a->value;
407 uint8_t *end = a->value + a->vlen;
408 int32_t type, len, uuid, psm;
409
410 if (end - ptr < 15)
411 return (-1);
412
413 if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) {
414 SDP_GET8(type, ptr);
415 switch (type) {
416 case SDP_DATA_SEQ8:
417 SDP_GET8(len, ptr);
418 break;
419
420 case SDP_DATA_SEQ16:
421 SDP_GET16(len, ptr);
422 break;
423
424 case SDP_DATA_SEQ32:
425 SDP_GET32(len, ptr);
426 break;
427
428 default:
429 return (-1);
430 }
431 if (ptr + len > end)
432 return (-1);
433 }
434
435 SDP_GET8(type, ptr);
436 switch (type) {
437 case SDP_DATA_SEQ8:
438 SDP_GET8(len, ptr);
439 break;
440
441 case SDP_DATA_SEQ16:
442 SDP_GET16(len, ptr);
443 break;
444
445 case SDP_DATA_SEQ32:
446 SDP_GET32(len, ptr);
447 break;
448
449 default:
450 return (-1);
451 }
452 if (ptr + len > end)
453 return (-1);
454
455 /* Protocol */
456 SDP_GET8(type, ptr);
457 switch (type) {
458 case SDP_DATA_SEQ8:
459 SDP_GET8(len, ptr);
460 break;
461
462 case SDP_DATA_SEQ16:
463 SDP_GET16(len, ptr);
464 break;
465
466 case SDP_DATA_SEQ32:
467 SDP_GET32(len, ptr);
468 break;
469
470 default:
471 return (-1);
472 }
473 if (ptr + len > end)
474 return (-1);
475
476 /* UUID */
477 if (ptr + 3 > end)
478 return (-1);
479 SDP_GET8(type, ptr);
480 switch (type) {
481 case SDP_DATA_UUID16:
482 SDP_GET16(uuid, ptr);
483 if (uuid != SDP_UUID_PROTOCOL_L2CAP)
484 return (-1);
485 break;
486
487 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
488 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
489 default:
490 return (-1);
491 }
492
493 /* PSM */
494 if (ptr + 3 > end)
495 return (-1);
496 SDP_GET8(type, ptr);
497 if (type != SDP_DATA_UINT16)
498 return (-1);
499 SDP_GET16(psm, ptr);
500
501 return (psm);
502 }
503
504 /*
505 * Parse HID descriptor string
506 *
507 * seq8 len8 2
508 * seq8 len8 2
509 * uint8 value8 2
510 * str value 3
511 * ===
512 * 9
513 */
514
515 static int32_t
516 parse_hid_descriptor(sdp_attr_t *a)
517 {
518 uint8_t *ptr = a->value;
519 uint8_t *end = a->value + a->vlen;
520 int32_t type, len, descriptor_type;
521
522 if (end - ptr < 9)
523 return (-1);
524
525 SDP_GET8(type, ptr);
526 switch (type) {
527 case SDP_DATA_SEQ8:
528 SDP_GET8(len, ptr);
529 break;
530
531 case SDP_DATA_SEQ16:
532 SDP_GET16(len, ptr);
533 break;
534
535 case SDP_DATA_SEQ32:
536 SDP_GET32(len, ptr);
537 break;
538
539 default:
540 return (-1);
541 }
542 if (ptr + len > end)
543 return (-1);
544
545 while (ptr < end) {
546 /* Descriptor */
547 SDP_GET8(type, ptr);
548 switch (type) {
549 case SDP_DATA_SEQ8:
550 if (ptr + 1 > end)
551 return (-1);
552 SDP_GET8(len, ptr);
553 break;
554
555 case SDP_DATA_SEQ16:
556 if (ptr + 2 > end)
557 return (-1);
558 SDP_GET16(len, ptr);
559 break;
560
561 case SDP_DATA_SEQ32:
562 if (ptr + 4 > end)
563 return (-1);
564 SDP_GET32(len, ptr);
565 break;
566
567 default:
568 return (-1);
569 }
570
571 /* Descripor type */
572 if (ptr + 1 > end)
573 return (-1);
574 SDP_GET8(type, ptr);
575 if (type != SDP_DATA_UINT8 || ptr + 1 > end)
576 return (-1);
577 SDP_GET8(descriptor_type, ptr);
578
579 /* Descriptor value */
580 if (ptr + 1 > end)
581 return (-1);
582 SDP_GET8(type, ptr);
583 switch (type) {
584 case SDP_DATA_STR8:
585 if (ptr + 1 > end)
586 return (-1);
587 SDP_GET8(len, ptr);
588 break;
589
590 case SDP_DATA_STR16:
591 if (ptr + 2 > end)
592 return (-1);
593 SDP_GET16(len, ptr);
594 break;
595
596 case SDP_DATA_STR32:
597 if (ptr + 4 > end)
598 return (-1);
599 SDP_GET32(len, ptr);
600 break;
601
602 default:
603 return (-1);
604 }
605 if (ptr + len > end)
606 return (-1);
607
608 if (descriptor_type == UDESC_REPORT && len > 0) {
609 a->value = ptr;
610 a->vlen = len;
611
612 return (0);
613 }
614
615 ptr += len;
616 }
617
618 return (-1);
619 }
620
621 /*
622 * Parse boolean value
623 *
624 * bool8 int8
625 */
626
627 static int32_t
628 parse_boolean(sdp_attr_t *a)
629 {
630 if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL)
631 return (-1);
632
633 return (a->value[1]);
634 }
635
636 /*
637 * Parse protocol descriptor list for the RFCOMM channel
638 *
639 * seq8 len8 2
640 * seq8 len8 2
641 * uuid16 value16 3 L2CAP
642 * seq8 len8 2
643 * uuid16 value16 3 RFCOMM
644 * uint8 value8 2 channel
645 * ===
646 * 14
647 */
648
649 static int32_t
650 parse_rfcomm_channel(sdp_attr_t *a)
651 {
652 uint8_t *ptr = a->value;
653 uint8_t *end = a->value + a->vlen;
654 int32_t type, len, uuid, channel;
655
656 if (end - ptr < 14)
657 return (-1);
658
659 SDP_GET8(type, ptr);
660 switch (type) {
661 case SDP_DATA_SEQ8:
662 SDP_GET8(len, ptr);
663 break;
664
665 case SDP_DATA_SEQ16:
666 SDP_GET16(len, ptr);
667 break;
668
669 case SDP_DATA_SEQ32:
670 SDP_GET32(len, ptr);
671 break;
672
673 default:
674 return (-1);
675 }
676 if (ptr + len > end)
677 return (-1);
678
679 /* Protocol */
680 SDP_GET8(type, ptr);
681 switch (type) {
682 case SDP_DATA_SEQ8:
683 SDP_GET8(len, ptr);
684 break;
685
686 case SDP_DATA_SEQ16:
687 SDP_GET16(len, ptr);
688 break;
689
690 case SDP_DATA_SEQ32:
691 SDP_GET32(len, ptr);
692 break;
693
694 default:
695 return (-1);
696 }
697 if (ptr + len > end)
698 return (-1);
699
700 /* UUID */
701 if (ptr + 3 > end)
702 return (-1);
703 SDP_GET8(type, ptr);
704 switch (type) {
705 case SDP_DATA_UUID16:
706 SDP_GET16(uuid, ptr);
707 if (uuid != SDP_UUID_PROTOCOL_L2CAP)
708 return (-1);
709 break;
710
711 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
712 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
713 default:
714 return (-1);
715 }
716
717 /* Protocol */
718 SDP_GET8(type, ptr);
719 switch (type) {
720 case SDP_DATA_SEQ8:
721 SDP_GET8(len, ptr);
722 break;
723
724 case SDP_DATA_SEQ16:
725 SDP_GET16(len, ptr);
726 break;
727
728 case SDP_DATA_SEQ32:
729 SDP_GET32(len, ptr);
730 break;
731
732 default:
733 return (-1);
734 }
735 if (ptr + len > end)
736 return (-1);
737
738 /* UUID */
739 if (ptr + 3 > end)
740 return (-1);
741 SDP_GET8(type, ptr);
742 switch (type) {
743 case SDP_DATA_UUID16:
744 SDP_GET16(uuid, ptr);
745 if (uuid != SDP_UUID_PROTOCOL_RFCOMM)
746 return (-1);
747 break;
748
749 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
750 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
751 default:
752 return (-1);
753 }
754
755 /* channel */
756 if (ptr + 2 > end)
757 return (-1);
758
759 SDP_GET8(type, ptr);
760 if (type != SDP_DATA_UINT8)
761 return (-1);
762
763 SDP_GET8(channel, ptr);
764
765 return (channel);
766 }
767