Home | History | Annotate | Line # | Download | only in btdevctl
sdp.c revision 1.1
      1 /*	$NetBSD: sdp.c,v 1.1 2006/09/10 15:45:56 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.1 2006/09/10 15:45:56 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 	obj = prop_number_create_integer(control_psm);
    272 	if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVcontrolpsm, obj))
    273 		return errno;
    274 
    275 	obj = prop_number_create_integer(interrupt_psm);
    276 	if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVinterruptpsm, obj))
    277 		return errno;
    278 
    279 	obj = prop_data_create_data(hid_descriptor, hid_length);
    280 	if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVdescriptor, obj))
    281 		return errno;
    282 
    283 	if (!reconnect_initiate) {
    284 		obj = prop_bool_create(TRUE);
    285 		if (obj == NULL || !prop_dictionary_set(dict, BTHIDEVreconnect, obj))
    286 			return errno;
    287 	}
    288 
    289 	return 0;
    290 }
    291 
    292 /*
    293  * Configure HSET results
    294  */
    295 static int
    296 config_hset(prop_dictionary_t dict)
    297 {
    298 	prop_object_t obj;
    299 	uint32_t channel;
    300 	int i;
    301 
    302 	channel = -1;
    303 
    304 	for (i = 0; i < NUM(values) ; i++) {
    305 		if (values[i].flags != SDP_ATTR_OK)
    306 			continue;
    307 
    308 		switch (values[i].attr) {
    309 		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
    310 			channel = parse_rfcomm_channel(&values[i]);
    311 			break;
    312 		}
    313 	}
    314 
    315 	if (channel == -1)
    316 		return ENOATTR;
    317 
    318 	obj = prop_string_create_cstring_nocopy("btsco");
    319 	if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj))
    320 		return errno;
    321 
    322 	obj = prop_number_create_integer(channel);
    323 	if (obj == NULL || !prop_dictionary_set(dict, BTSCOchannel, obj))
    324 		return errno;
    325 
    326 	return 0;
    327 }
    328 
    329 /*
    330  * Configure HF results
    331  */
    332 static int
    333 config_hf(prop_dictionary_t dict)
    334 {
    335 	prop_object_t obj;
    336 	uint32_t channel;
    337 	int i;
    338 
    339 	channel = -1;
    340 
    341 	for (i = 0 ; i < NUM(values) ; i++) {
    342 		if (values[i].flags != SDP_ATTR_OK)
    343 			continue;
    344 
    345 		switch (values[i].attr) {
    346 		case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
    347 			channel = parse_rfcomm_channel(&values[i]);
    348 			break;
    349 		}
    350 	}
    351 
    352 	if (channel == -1)
    353 		return ENOATTR;
    354 
    355 	obj = prop_string_create_cstring_nocopy("btsco");
    356 	if (obj == NULL || !prop_dictionary_set(dict, BTDEVtype, obj))
    357 		return errno;
    358 
    359 	obj = prop_bool_create(TRUE);
    360 	if (obj == NULL || !prop_dictionary_set(dict, BTSCOlisten, obj))
    361 		return errno;
    362 
    363 	obj = prop_number_create_integer(channel);
    364 	if (obj == NULL || !prop_dictionary_set(dict, BTSCOchannel, obj))
    365 		return errno;
    366 
    367 	return 0;
    368 }
    369 
    370 /*
    371  * Parse [additional] protocol descriptor list for L2CAP PSM
    372  *
    373  * seq8 len8				2
    374  *	seq8 len8			2
    375  *		uuid16 value16		3	L2CAP
    376  *		uint16 value16		3	PSM
    377  *	seq8 len8			2
    378  *		uuid16 value16		3	HID Protocol
    379  *				      ===
    380  *				       15
    381  */
    382 
    383 static int32_t
    384 parse_l2cap_psm(sdp_attr_t *a)
    385 {
    386 	uint8_t	*ptr = a->value;
    387 	uint8_t	*end = a->value + a->vlen;
    388 	int32_t	 type, len, uuid, psm;
    389 
    390 	if (end - ptr < 15)
    391 		return (-1);
    392 
    393 	if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) {
    394 		SDP_GET8(type, ptr);
    395 		switch (type) {
    396 		case SDP_DATA_SEQ8:
    397 			SDP_GET8(len, ptr);
    398 			break;
    399 
    400 		case SDP_DATA_SEQ16:
    401 			SDP_GET16(len, ptr);
    402 			break;
    403 
    404 		case SDP_DATA_SEQ32:
    405 			SDP_GET32(len, ptr);
    406 			break;
    407 
    408 		default:
    409 			return (-1);
    410 		}
    411 		if (ptr + len > end)
    412 			return (-1);
    413 	}
    414 
    415 	SDP_GET8(type, ptr);
    416 	switch (type) {
    417 	case SDP_DATA_SEQ8:
    418 		SDP_GET8(len, ptr);
    419 		break;
    420 
    421 	case SDP_DATA_SEQ16:
    422 		SDP_GET16(len, ptr);
    423 		break;
    424 
    425 	case SDP_DATA_SEQ32:
    426 		SDP_GET32(len, ptr);
    427 		break;
    428 
    429 	default:
    430 		return (-1);
    431 	}
    432 	if (ptr + len > end)
    433 		return (-1);
    434 
    435 	/* Protocol */
    436 	SDP_GET8(type, ptr);
    437 	switch (type) {
    438 	case SDP_DATA_SEQ8:
    439 		SDP_GET8(len, ptr);
    440 		break;
    441 
    442 	case SDP_DATA_SEQ16:
    443 		SDP_GET16(len, ptr);
    444 		break;
    445 
    446 	case SDP_DATA_SEQ32:
    447 		SDP_GET32(len, ptr);
    448 		break;
    449 
    450 	default:
    451 		return (-1);
    452 	}
    453 	if (ptr + len > end)
    454 		return (-1);
    455 
    456 	/* UUID */
    457 	if (ptr + 3 > end)
    458 		return (-1);
    459 	SDP_GET8(type, ptr);
    460 	switch (type) {
    461 	case SDP_DATA_UUID16:
    462 		SDP_GET16(uuid, ptr);
    463 		if (uuid != SDP_UUID_PROTOCOL_L2CAP)
    464 			return (-1);
    465 		break;
    466 
    467 	case SDP_DATA_UUID32:  /* XXX FIXME can we have 32-bit UUID */
    468 	case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
    469 	default:
    470 		return (-1);
    471 	}
    472 
    473 	/* PSM */
    474 	if (ptr + 3 > end)
    475 		return (-1);
    476 	SDP_GET8(type, ptr);
    477 	if (type != SDP_DATA_UINT16)
    478 		return (-1);
    479 	SDP_GET16(psm, ptr);
    480 
    481 	return (psm);
    482 }
    483 
    484 /*
    485  * Parse HID descriptor string
    486  *
    487  * seq8 len8			2
    488  *	seq8 len8		2
    489  *		uint8 value8	2
    490  *		str value	3
    491  *			      ===
    492  *			        9
    493  */
    494 
    495 static int32_t
    496 parse_hid_descriptor(sdp_attr_t *a)
    497 {
    498 	uint8_t	*ptr = a->value;
    499 	uint8_t	*end = a->value + a->vlen;
    500 	int32_t	 type, len, descriptor_type;
    501 
    502 	if (end - ptr < 9)
    503 		return (-1);
    504 
    505 	SDP_GET8(type, ptr);
    506 	switch (type) {
    507 	case SDP_DATA_SEQ8:
    508 		SDP_GET8(len, ptr);
    509 		break;
    510 
    511 	case SDP_DATA_SEQ16:
    512 		SDP_GET16(len, ptr);
    513 		break;
    514 
    515 	case SDP_DATA_SEQ32:
    516 		SDP_GET32(len, ptr);
    517 		break;
    518 
    519 	default:
    520 		return (-1);
    521 	}
    522 	if (ptr + len > end)
    523 		return (-1);
    524 
    525 	while (ptr < end) {
    526 		/* Descriptor */
    527 		SDP_GET8(type, ptr);
    528 		switch (type) {
    529 		case SDP_DATA_SEQ8:
    530 			if (ptr + 1 > end)
    531 				return (-1);
    532 			SDP_GET8(len, ptr);
    533 			break;
    534 
    535 		case SDP_DATA_SEQ16:
    536 			if (ptr + 2 > end)
    537 				return (-1);
    538 			SDP_GET16(len, ptr);
    539 			break;
    540 
    541 		case SDP_DATA_SEQ32:
    542 			if (ptr + 4 > end)
    543 				return (-1);
    544 			SDP_GET32(len, ptr);
    545 			break;
    546 
    547 		default:
    548 			return (-1);
    549 		}
    550 
    551 		/* Descripor type */
    552 		if (ptr + 1 > end)
    553 			return (-1);
    554 		SDP_GET8(type, ptr);
    555 		if (type != SDP_DATA_UINT8 || ptr + 1 > end)
    556 			return (-1);
    557 		SDP_GET8(descriptor_type, ptr);
    558 
    559 		/* Descriptor value */
    560 		if (ptr + 1 > end)
    561 			return (-1);
    562 		SDP_GET8(type, ptr);
    563 		switch (type) {
    564 		case SDP_DATA_STR8:
    565 			if (ptr + 1 > end)
    566 				return (-1);
    567 			SDP_GET8(len, ptr);
    568 			break;
    569 
    570 		case SDP_DATA_STR16:
    571 			if (ptr + 2 > end)
    572 				return (-1);
    573 			SDP_GET16(len, ptr);
    574 			break;
    575 
    576 		case SDP_DATA_STR32:
    577 			if (ptr + 4 > end)
    578 				return (-1);
    579 			SDP_GET32(len, ptr);
    580 			break;
    581 
    582 		default:
    583 			return (-1);
    584 		}
    585 		if (ptr + len > end)
    586 			return (-1);
    587 
    588 		if (descriptor_type == UDESC_REPORT && len > 0) {
    589 			a->value = ptr;
    590 			a->vlen = len;
    591 
    592 			return (0);
    593 		}
    594 
    595 		ptr += len;
    596 	}
    597 
    598 	return (-1);
    599 }
    600 
    601 /*
    602  * Parse boolean value
    603  *
    604  * bool8 int8
    605  */
    606 
    607 static int32_t
    608 parse_boolean(sdp_attr_t *a)
    609 {
    610 	if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL)
    611 		return (-1);
    612 
    613 	return (a->value[1]);
    614 }
    615 
    616 /*
    617  * Parse protocol descriptor list for the RFCOMM channel
    618  *
    619  * seq8 len8				2
    620  *	seq8 len8			2
    621  *		uuid16 value16		3	L2CAP
    622  *	seq8 len8			2
    623  *		uuid16 value16		3	RFCOMM
    624  *		uint8 value8		2	channel
    625  *				      ===
    626  *				       14
    627  */
    628 
    629 static int32_t
    630 parse_rfcomm_channel(sdp_attr_t *a)
    631 {
    632 	uint8_t	*ptr = a->value;
    633 	uint8_t	*end = a->value + a->vlen;
    634 	int32_t	 type, len, uuid, channel;
    635 
    636 	if (end - ptr < 14)
    637 		return (-1);
    638 
    639 	SDP_GET8(type, ptr);
    640 	switch (type) {
    641 	case SDP_DATA_SEQ8:
    642 		SDP_GET8(len, ptr);
    643 		break;
    644 
    645 	case SDP_DATA_SEQ16:
    646 		SDP_GET16(len, ptr);
    647 		break;
    648 
    649 	case SDP_DATA_SEQ32:
    650 		SDP_GET32(len, ptr);
    651 		break;
    652 
    653 	default:
    654 		return (-1);
    655 	}
    656 	if (ptr + len > end)
    657 		return (-1);
    658 
    659 	/* Protocol */
    660 	SDP_GET8(type, ptr);
    661 	switch (type) {
    662 	case SDP_DATA_SEQ8:
    663 		SDP_GET8(len, ptr);
    664 		break;
    665 
    666 	case SDP_DATA_SEQ16:
    667 		SDP_GET16(len, ptr);
    668 		break;
    669 
    670 	case SDP_DATA_SEQ32:
    671 		SDP_GET32(len, ptr);
    672 		break;
    673 
    674 	default:
    675 		return (-1);
    676 	}
    677 	if (ptr + len > end)
    678 		return (-1);
    679 
    680 	/* UUID */
    681 	if (ptr + 3 > end)
    682 		return (-1);
    683 	SDP_GET8(type, ptr);
    684 	switch (type) {
    685 	case SDP_DATA_UUID16:
    686 		SDP_GET16(uuid, ptr);
    687 		if (uuid != SDP_UUID_PROTOCOL_L2CAP)
    688 			return (-1);
    689 		break;
    690 
    691 	case SDP_DATA_UUID32:  /* XXX FIXME can we have 32-bit UUID */
    692 	case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
    693 	default:
    694 		return (-1);
    695 	}
    696 
    697 	/* Protocol */
    698 	SDP_GET8(type, ptr);
    699 	switch (type) {
    700 	case SDP_DATA_SEQ8:
    701 		SDP_GET8(len, ptr);
    702 		break;
    703 
    704 	case SDP_DATA_SEQ16:
    705 		SDP_GET16(len, ptr);
    706 		break;
    707 
    708 	case SDP_DATA_SEQ32:
    709 		SDP_GET32(len, ptr);
    710 		break;
    711 
    712 	default:
    713 		return (-1);
    714 	}
    715 	if (ptr + len > end)
    716 		return (-1);
    717 
    718 	/* UUID */
    719 	if (ptr + 3 > end)
    720 		return (-1);
    721 	SDP_GET8(type, ptr);
    722 	switch (type) {
    723 	case SDP_DATA_UUID16:
    724 		SDP_GET16(uuid, ptr);
    725 		if (uuid != SDP_UUID_PROTOCOL_RFCOMM)
    726 			return (-1);
    727 		break;
    728 
    729 	case SDP_DATA_UUID32:  /* XXX FIXME can we have 32-bit UUID */
    730 	case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
    731 	default:
    732 		return (-1);
    733 	}
    734 
    735 	/* channel */
    736 	if (ptr + 2 > end)
    737 		return (-1);
    738 
    739 	SDP_GET8(type, ptr);
    740 	if (type != SDP_DATA_UINT8)
    741 		return (-1);
    742 
    743 	SDP_GET8(channel, ptr);
    744 
    745 	return (channel);
    746 }
    747