update to use new sdp(3) and sdp_data(3) APIs

This commit is contained in:
plunky 2009-05-12 18:39:20 +00:00
parent 384153c15a
commit 170631f4a8
3 changed files with 189 additions and 460 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.4 2009/05/12 13:09:43 plunky Exp $ # $NetBSD: Makefile,v 1.5 2009/05/12 18:39:20 plunky Exp $
PROG= btdevctl PROG= btdevctl
MAN= btdevctl.8 MAN= btdevctl.8
@ -7,6 +7,4 @@ SRCS= btdevctl.c db.c print.c sdp.c
DPADD+= ${LIBBLUETOOTH} ${LIBPROP} ${LIBUSBHID} DPADD+= ${LIBBLUETOOTH} ${LIBPROP} ${LIBUSBHID}
LDADD+= -lbluetooth -lprop -lusbhid LDADD+= -lbluetooth -lprop -lusbhid
CPPFLAGS+= -DSDP_COMPAT
.include <bsd.prog.mk> .include <bsd.prog.mk>

View File

@ -1,4 +1,4 @@
/* $NetBSD: btdevctl.c,v 1.7 2008/07/21 13:36:57 lukem Exp $ */ /* $NetBSD: btdevctl.c,v 1.8 2009/05/12 18:39:20 plunky Exp $ */
/*- /*-
* Copyright (c) 2006 Itronix Inc. * Copyright (c) 2006 Itronix Inc.
@ -32,8 +32,10 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc. All rights reserved."); __COPYRIGHT("@(#) Copyright (c) 2006 The NetBSD Foundation, Inc.\
__RCSID("$NetBSD: btdevctl.c,v 1.7 2008/07/21 13:36:57 lukem Exp $"); @(#) Copyright (c) 2006 Itronix, Inc.\
All rights reserved.");
__RCSID("$NetBSD: btdevctl.c,v 1.8 2009/05/12 18:39:20 plunky Exp $");
#include <prop/proplib.h> #include <prop/proplib.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>

View File

@ -1,4 +1,4 @@
/* $NetBSD: sdp.c,v 1.6 2009/04/15 00:35:04 lukem Exp $ */ /* $NetBSD: sdp.c,v 1.7 2009/05/12 18:39:20 plunky Exp $ */
/*- /*-
* Copyright (c) 2006 Itronix Inc. * Copyright (c) 2006 Itronix Inc.
@ -29,6 +29,7 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
/* /*
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved. * All rights reserved.
* *
@ -55,7 +56,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: sdp.c,v 1.6 2009/04/15 00:35:04 lukem Exp $"); __RCSID("$NetBSD: sdp.c,v 1.7 2009/05/12 18:39:20 plunky Exp $");
#include <sys/types.h> #include <sys/types.h>
@ -72,125 +73,104 @@ __RCSID("$NetBSD: sdp.c,v 1.6 2009/04/15 00:35:04 lukem Exp $");
#include <errno.h> #include <errno.h>
#include <sdp.h> #include <sdp.h>
#include <stdlib.h> #include <stdlib.h>
#include <strings.h>
#include <usbhid.h> #include <usbhid.h>
#include "btdevctl.h" #include "btdevctl.h"
static int32_t parse_l2cap_psm(sdp_attr_t *); static bool parse_hid_descriptor(sdp_data_t *);
static int32_t parse_rfcomm_channel(sdp_attr_t *); static int32_t parse_boolean(sdp_data_t *);
static int32_t parse_hid_descriptor(sdp_attr_t *); static int32_t parse_pdl_param(sdp_data_t *, uint16_t);
static int32_t parse_boolean(sdp_attr_t *); static int32_t parse_pdl(sdp_data_t *, uint16_t);
static int32_t parse_apdl(sdp_data_t *, uint16_t);
static int config_hid(prop_dictionary_t); static int config_hid(prop_dictionary_t, sdp_data_t *);
static int config_hset(prop_dictionary_t); static int config_hset(prop_dictionary_t, sdp_data_t *);
static int config_hf(prop_dictionary_t); static int config_hf(prop_dictionary_t, sdp_data_t *);
uint16_t hid_services[] = { uint16_t hid_services[] = {
SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE,
};
uint32_t hid_attrs[] = {
SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
SDP_ATTR_RANGE( SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS,
SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS),
SDP_ATTR_RANGE( 0x0205, /* HIDReconnectInitiate */
0x0206), /* HIDDescriptorList */
SDP_ATTR_RANGE( 0x0209, /* HIDBatteryPower */
0x0209),
SDP_ATTR_RANGE( 0x020d, /* HIDNormallyConnectable */
0x020d)
}; };
uint16_t hset_services[] = { uint16_t hset_services[] = {
SDP_SERVICE_CLASS_HEADSET SDP_SERVICE_CLASS_HEADSET,
};
uint32_t hset_attrs[] = {
SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
}; };
uint16_t hf_services[] = { uint16_t hf_services[] = {
SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY,
};
uint32_t hf_attrs[] = {
SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
}; };
static struct { static struct {
const char *name; const char *name;
int (*handler)(prop_dictionary_t); int (*handler)(prop_dictionary_t, sdp_data_t *);
const char *description; const char *description;
uint16_t *services; uint16_t *services;
int nservices; size_t nservices;
uint32_t *attrs;
int nattrs;
} cfgtype[] = { } cfgtype[] = {
{ {
"HID", config_hid, "Human Interface Device", "HID", config_hid, "Human Interface Device",
hid_services, __arraycount(hid_services), hid_services, __arraycount(hid_services),
hid_attrs, __arraycount(hid_attrs),
}, },
{ {
"HSET", config_hset, "Headset", "HSET", config_hset, "Headset",
hset_services, __arraycount(hset_services), hset_services, __arraycount(hset_services),
hset_attrs, __arraycount(hset_attrs),
}, },
{ {
"HF", config_hf, "Handsfree", "HF", config_hf, "Handsfree",
hf_services, __arraycount(hf_services), hf_services, __arraycount(hf_services),
hf_attrs, __arraycount(hf_attrs),
}, },
}; };
static sdp_attr_t values[8]; #define MAX_SSP (2 + 1 * 3) /* largest nservices is 1 */
static uint8_t buffer[__arraycount(values)][512];
prop_dictionary_t prop_dictionary_t
cfg_query(bdaddr_t *laddr, bdaddr_t *raddr, const char *service) cfg_query(bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
{ {
prop_dictionary_t dict; prop_dictionary_t dict;
void *ss; sdp_session_t ss;
int rv; uint8_t buf[MAX_SSP];
size_t i; sdp_data_t ssp, rsp, rec;
size_t i, n;
bool rv;
dict = prop_dictionary_create(); dict = prop_dictionary_create();
if (dict == NULL) if (dict == NULL)
return NULL; return NULL;
for (i = 0; i < __arraycount(values); i++) {
values[i].flags = SDP_ATTR_INVALID;
values[i].attr = 0;
values[i].vlen = sizeof(buffer[i]);
values[i].value = buffer[i];
}
for (i = 0; i < __arraycount(cfgtype); i++) { for (i = 0; i < __arraycount(cfgtype); i++) {
if (strcasecmp(service, cfgtype[i].name) == 0) { if (strcasecmp(service, cfgtype[i].name) == 0) {
ss = sdp_open(laddr, raddr); ss = sdp_open(laddr, raddr);
if (ss == NULL)
if (ss == NULL || (errno = sdp_error(ss)) != 0)
return NULL; return NULL;
rv = sdp_search(ss, /* build ServiceSearchPattern */
cfgtype[i].nservices, cfgtype[i].services, ssp.next = buf;
cfgtype[i].nattrs, cfgtype[i].attrs, ssp.end = buf + sizeof(buf);
__arraycount(values), values);
if (rv != 0) { for (n = 0; n < cfgtype[i].nservices; n++)
errno = sdp_error(ss); sdp_put_uuid16(&ssp, cfgtype[i].services[n]);
ssp.end = ssp.next;
ssp.next = buf;
rv = sdp_service_search_attribute(ss, &ssp, NULL, &rsp);
if (!rv) {
prop_object_release(dict);
sdp_close(ss);
return NULL; return NULL;
} }
while (sdp_get_seq(&rsp, &rec)) {
errno = (*cfgtype[i].handler)(dict, &rec);
if (errno == 0) {
sdp_close(ss);
return dict;
}
}
sdp_close(ss); sdp_close(ss);
prop_object_release(dict);
rv = (*cfgtype[i].handler)(dict); return NULL;
if (rv != 0)
return NULL;
return dict;
} }
} }
@ -205,54 +185,44 @@ cfg_query(bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
* Configure HID results * Configure HID results
*/ */
static int static int
config_hid(prop_dictionary_t dict) config_hid(prop_dictionary_t dict, sdp_data_t *rec)
{ {
prop_object_t obj; prop_object_t obj;
int32_t control_psm, interrupt_psm, int32_t control_psm, interrupt_psm,
reconnect_initiate, battery_power, reconnect_initiate, hid_length;
normally_connectable, hid_length;
uint8_t *hid_descriptor; uint8_t *hid_descriptor;
sdp_data_t value;
const char *mode; const char *mode;
size_t i; uint16_t attr;
control_psm = -1; control_psm = -1;
interrupt_psm = -1; interrupt_psm = -1;
reconnect_initiate = -1; reconnect_initiate = -1;
normally_connectable = 0;
battery_power = 0;
hid_descriptor = NULL; hid_descriptor = NULL;
hid_length = -1; hid_length = -1;
for (i = 0; i < __arraycount(values); i++) { while (sdp_get_attr(rec, &attr, &value)) {
if (values[i].flags != SDP_ATTR_OK) switch (attr) {
continue;
switch (values[i].attr) {
case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
control_psm = parse_l2cap_psm(&values[i]); control_psm = parse_pdl(&value, SDP_UUID_PROTOCOL_L2CAP);
break; break;
case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS:
interrupt_psm = parse_l2cap_psm(&values[i]); interrupt_psm = parse_apdl(&value, SDP_UUID_PROTOCOL_L2CAP);
break; break;
case 0x0205: /* HIDReconnectInitiate */ case 0x0205: /* HIDReconnectInitiate */
reconnect_initiate = parse_boolean(&values[i]); reconnect_initiate = parse_boolean(&value);
break; break;
case 0x0206: /* HIDDescriptorList */ case 0x0206: /* HIDDescriptorList */
if (parse_hid_descriptor(&values[i]) == 0) { if (parse_hid_descriptor(&value)) {
hid_descriptor = values[i].value; hid_descriptor = value.next;
hid_length = values[i].vlen; hid_length = value.end - value.next;
} }
break; break;
case 0x0209: /* HIDBatteryPower */ default:
battery_power = parse_boolean(&values[i]);
break;
case 0x020d: /* HIDNormallyConnectable */
normally_connectable = parse_boolean(&values[i]);
break; break;
} }
} }
@ -310,26 +280,27 @@ config_hid(prop_dictionary_t dict)
* Configure HSET results * Configure HSET results
*/ */
static int static int
config_hset(prop_dictionary_t dict) config_hset(prop_dictionary_t dict, sdp_data_t *rec)
{ {
prop_object_t obj; prop_object_t obj;
uint32_t channel; sdp_data_t value;
size_t i; int32_t channel;
uint16_t attr;
channel = -1; channel = -1;
for (i = 0; i < __arraycount(values); i++) { while (sdp_get_attr(rec, &attr, &value)) {
if (values[i].flags != SDP_ATTR_OK) switch (attr) {
continue;
switch (values[i].attr) {
case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
channel = parse_rfcomm_channel(&values[i]); channel = parse_pdl(&value, SDP_UUID_PROTOCOL_RFCOMM);
break;
default:
break; break;
} }
} }
if (channel == (uint32_t)-1) if (channel == -1)
return ENOATTR; return ENOATTR;
obj = prop_string_create_cstring_nocopy("btsco"); obj = prop_string_create_cstring_nocopy("btsco");
@ -351,26 +322,27 @@ config_hset(prop_dictionary_t dict)
* Configure HF results * Configure HF results
*/ */
static int static int
config_hf(prop_dictionary_t dict) config_hf(prop_dictionary_t dict, sdp_data_t *rec)
{ {
prop_object_t obj; prop_object_t obj;
uint32_t channel; sdp_data_t value;
size_t i; int32_t channel;
uint16_t attr;
channel = -1; channel = -1;
for (i = 0; i < __arraycount(values); i++) { while (sdp_get_attr(rec, &attr, &value)) {
if (values[i].flags != SDP_ATTR_OK) switch (attr) {
continue;
switch (values[i].attr) {
case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
channel = parse_rfcomm_channel(&values[i]); channel = parse_pdl(&value, SDP_UUID_PROTOCOL_RFCOMM);
break;
default:
break; break;
} }
} }
if (channel == (uint32_t)-1) if (channel == -1)
return ENOATTR; return ENOATTR;
obj = prop_string_create_cstring_nocopy("btsco"); obj = prop_string_create_cstring_nocopy("btsco");
@ -395,381 +367,138 @@ config_hf(prop_dictionary_t dict)
} }
/* /*
* Parse [additional] protocol descriptor list for L2CAP PSM * Parse HIDDescriptorList . This is a sequence of HIDDescriptors, of which
* each is a data element sequence containing, minimally, a ClassDescriptorType
* and ClassDescriptorData containing a byte array of data. Any extra elements
* should be ignored.
* *
* seq8 len8 2 * If a ClassDescriptorType "Report" is found, set SDP data value to the
* seq8 len8 2 * ClassDescriptorData content and return true. Note that we don't need to
* uuid16 value16 3 L2CAP * extract the actual length as the SDP data is guaranteed valid.
* uint16 value16 3 PSM
* seq8 len8 2
* uuid16 value16 3 HID Protocol
* ===
* 15
*/ */
static int32_t static bool
parse_l2cap_psm(sdp_attr_t *a) parse_hid_descriptor(sdp_data_t *value)
{ {
uint8_t *ptr = a->value; sdp_data_t list, desc;
uint8_t *end = a->value + a->vlen; uintmax_t type;
int32_t type, len, uuid, psm; char *str;
size_t len;
if (end - ptr < 15) if (!sdp_get_seq(value, &list))
return (-1); return false;
if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) { while (sdp_get_seq(&list, &desc)) {
SDP_GET8(type, ptr); if (sdp_get_uint(&desc, &type)
switch (type) { && type == UDESC_REPORT
case SDP_DATA_SEQ8: && sdp_get_str(&desc, &str, &len)) {
SDP_GET8(len, ptr); value->next = (uint8_t *)str;
break; value->end = (uint8_t *)(str + len);
return true;
case SDP_DATA_SEQ16:
SDP_GET16(len, ptr);
break;
case SDP_DATA_SEQ32:
SDP_GET32(len, ptr);
break;
default:
return (-1);
} }
if (ptr + len > end)
return (-1);
} }
SDP_GET8(type, ptr); return false;
switch (type) { }
case SDP_DATA_SEQ8:
SDP_GET8(len, ptr);
break;
case SDP_DATA_SEQ16: static int32_t
SDP_GET16(len, ptr); parse_boolean(sdp_data_t *value)
break; {
bool bv;
case SDP_DATA_SEQ32: if (!sdp_get_bool(value, &bv))
SDP_GET32(len, ptr); return -1;
break;
default: return bv;
return (-1);
}
if (ptr + len > end)
return (-1);
/* Protocol */
SDP_GET8(type, ptr);
switch (type) {
case SDP_DATA_SEQ8:
SDP_GET8(len, ptr);
break;
case SDP_DATA_SEQ16:
SDP_GET16(len, ptr);
break;
case SDP_DATA_SEQ32:
SDP_GET32(len, ptr);
break;
default:
return (-1);
}
if (ptr + len > end)
return (-1);
/* UUID */
if (ptr + 3 > end)
return (-1);
SDP_GET8(type, ptr);
switch (type) {
case SDP_DATA_UUID16:
SDP_GET16(uuid, ptr);
if (uuid != SDP_UUID_PROTOCOL_L2CAP)
return (-1);
break;
case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
default:
return (-1);
}
/* PSM */
if (ptr + 3 > end)
return (-1);
SDP_GET8(type, ptr);
if (type != SDP_DATA_UINT16)
return (-1);
SDP_GET16(psm, ptr);
return (psm);
} }
/* /*
* Parse HID descriptor string * The ProtocolDescriptorList attribute describes one or
* more protocol stacks that may be used to gain access to
* the service dscribed by the service record.
* *
* seq8 len8 2 * If the ProtocolDescriptorList describes a single stack,
* seq8 len8 2 * the attribute value takes the form of a data element
* uint8 value8 2 * sequence in which each element of the sequence is a
* str value 3 * protocol descriptor.
* === *
* 9 * seq
* <list>
*
* If it is possible for more than one kind of protocol
* stack to be used to gain access to the service, the
* ProtocolDescriptorList takes the form of a data element
* alternative where each member is a data element sequence
* consisting of a list of sequences describing each protocol
*
* alt
* seq
* <list>
* seq
* <list>
*
* Each ProtocolDescriptorList is a list containing a sequence for
* each protocol, where each sequence contains the protocol UUUID
* and any protocol specific parameters.
*
* seq
* uuid L2CAP
* uint16 psm
* seq
* uuid RFCOMM
* uint8 channel
*
* We want to extract the ProtocolSpecificParameter#1 for the
* given protocol, which will be an unsigned int.
*/ */
static int32_t
parse_pdl_param(sdp_data_t *pdl, uint16_t proto)
{
sdp_data_t seq;
uintmax_t param;
while (sdp_get_seq(pdl, &seq)) {
if (!sdp_match_uuid16(&seq, proto))
continue;
if (sdp_get_uint(&seq, &param))
return param;
break;
}
return -1;
}
static int32_t static int32_t
parse_hid_descriptor(sdp_attr_t *a) parse_pdl(sdp_data_t *value, uint16_t proto)
{ {
uint8_t *ptr = a->value; sdp_data_t seq;
uint8_t *end = a->value + a->vlen; int32_t param = -1;
int32_t type, len, descriptor_type;
if (end - ptr < 9) sdp_get_alt(value, value); /* strip any alt header */
return (-1);
SDP_GET8(type, ptr); while (param == -1 && sdp_get_seq(value, &seq))
switch (type) { param = parse_pdl_param(&seq, proto);
case SDP_DATA_SEQ8:
SDP_GET8(len, ptr);
break;
case SDP_DATA_SEQ16: return param;
SDP_GET16(len, ptr);
break;
case SDP_DATA_SEQ32:
SDP_GET32(len, ptr);
break;
default:
return (-1);
}
if (ptr + len > end)
return (-1);
while (ptr < end) {
/* Descriptor */
SDP_GET8(type, ptr);
switch (type) {
case SDP_DATA_SEQ8:
if (ptr + 1 > end)
return (-1);
SDP_GET8(len, ptr);
break;
case SDP_DATA_SEQ16:
if (ptr + 2 > end)
return (-1);
SDP_GET16(len, ptr);
break;
case SDP_DATA_SEQ32:
if (ptr + 4 > end)
return (-1);
SDP_GET32(len, ptr);
break;
default:
return (-1);
}
/* Descripor type */
if (ptr + 1 > end)
return (-1);
SDP_GET8(type, ptr);
if (type != SDP_DATA_UINT8 || ptr + 1 > end)
return (-1);
SDP_GET8(descriptor_type, ptr);
/* Descriptor value */
if (ptr + 1 > end)
return (-1);
SDP_GET8(type, ptr);
switch (type) {
case SDP_DATA_STR8:
if (ptr + 1 > end)
return (-1);
SDP_GET8(len, ptr);
break;
case SDP_DATA_STR16:
if (ptr + 2 > end)
return (-1);
SDP_GET16(len, ptr);
break;
case SDP_DATA_STR32:
if (ptr + 4 > end)
return (-1);
SDP_GET32(len, ptr);
break;
default:
return (-1);
}
if (ptr + len > end)
return (-1);
if (descriptor_type == UDESC_REPORT && len > 0) {
a->value = ptr;
a->vlen = len;
return (0);
}
ptr += len;
}
return (-1);
} }
/* /*
* Parse boolean value * Parse AdditionalProtocolDescriptorList
*
* bool8 int8
*/ */
static int32_t static int32_t
parse_boolean(sdp_attr_t *a) parse_apdl(sdp_data_t *value, uint16_t proto)
{ {
if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL) sdp_data_t seq;
return (-1); int32_t param = -1;
return (a->value[1]); sdp_get_seq(value, value); /* strip seq header */
}
/* while (param == -1 && sdp_get_seq(value, &seq))
* Parse protocol descriptor list for the RFCOMM channel param = parse_pdl_param(&seq, proto);
*
* seq8 len8 2
* seq8 len8 2
* uuid16 value16 3 L2CAP
* seq8 len8 2
* uuid16 value16 3 RFCOMM
* uint8 value8 2 channel
* ===
* 14
*/
static int32_t return param;
parse_rfcomm_channel(sdp_attr_t *a)
{
uint8_t *ptr = a->value;
uint8_t *end = a->value + a->vlen;
int32_t type, len, uuid, channel;
if (end - ptr < 14)
return (-1);
SDP_GET8(type, ptr);
switch (type) {
case SDP_DATA_SEQ8:
SDP_GET8(len, ptr);
break;
case SDP_DATA_SEQ16:
SDP_GET16(len, ptr);
break;
case SDP_DATA_SEQ32:
SDP_GET32(len, ptr);
break;
default:
return (-1);
}
if (ptr + len > end)
return (-1);
/* Protocol */
SDP_GET8(type, ptr);
switch (type) {
case SDP_DATA_SEQ8:
SDP_GET8(len, ptr);
break;
case SDP_DATA_SEQ16:
SDP_GET16(len, ptr);
break;
case SDP_DATA_SEQ32:
SDP_GET32(len, ptr);
break;
default:
return (-1);
}
if (ptr + len > end)
return (-1);
/* UUID */
if (ptr + 3 > end)
return (-1);
SDP_GET8(type, ptr);
switch (type) {
case SDP_DATA_UUID16:
SDP_GET16(uuid, ptr);
if (uuid != SDP_UUID_PROTOCOL_L2CAP)
return (-1);
break;
case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
default:
return (-1);
}
/* Protocol */
SDP_GET8(type, ptr);
switch (type) {
case SDP_DATA_SEQ8:
SDP_GET8(len, ptr);
break;
case SDP_DATA_SEQ16:
SDP_GET16(len, ptr);
break;
case SDP_DATA_SEQ32:
SDP_GET32(len, ptr);
break;
default:
return (-1);
}
if (ptr + len > end)
return (-1);
/* UUID */
if (ptr + 3 > end)
return (-1);
SDP_GET8(type, ptr);
switch (type) {
case SDP_DATA_UUID16:
SDP_GET16(uuid, ptr);
if (uuid != SDP_UUID_PROTOCOL_RFCOMM)
return (-1);
break;
case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
default:
return (-1);
}
/* channel */
if (ptr + 2 > end)
return (-1);
SDP_GET8(type, ptr);
if (type != SDP_DATA_UINT8)
return (-1);
SDP_GET8(channel, ptr);
return (channel);
} }
/* /*