From 170631f4a8a646ddc5c30798786bb79821a00046 Mon Sep 17 00:00:00 2001 From: plunky Date: Tue, 12 May 2009 18:39:20 +0000 Subject: [PATCH] update to use new sdp(3) and sdp_data(3) APIs --- usr.sbin/btdevctl/Makefile | 4 +- usr.sbin/btdevctl/btdevctl.c | 8 +- usr.sbin/btdevctl/sdp.c | 637 ++++++++++------------------------- 3 files changed, 189 insertions(+), 460 deletions(-) diff --git a/usr.sbin/btdevctl/Makefile b/usr.sbin/btdevctl/Makefile index 55fdc062622a..703f91145a07 100644 --- a/usr.sbin/btdevctl/Makefile +++ b/usr.sbin/btdevctl/Makefile @@ -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 MAN= btdevctl.8 @@ -7,6 +7,4 @@ SRCS= btdevctl.c db.c print.c sdp.c DPADD+= ${LIBBLUETOOTH} ${LIBPROP} ${LIBUSBHID} LDADD+= -lbluetooth -lprop -lusbhid -CPPFLAGS+= -DSDP_COMPAT - .include diff --git a/usr.sbin/btdevctl/btdevctl.c b/usr.sbin/btdevctl/btdevctl.c index 24b302549644..6ff6e88063cd 100644 --- a/usr.sbin/btdevctl/btdevctl.c +++ b/usr.sbin/btdevctl/btdevctl.c @@ -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. @@ -32,8 +32,10 @@ */ #include -__COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc. All rights reserved."); -__RCSID("$NetBSD: btdevctl.c,v 1.7 2008/07/21 13:36:57 lukem Exp $"); +__COPYRIGHT("@(#) Copyright (c) 2006 The NetBSD Foundation, Inc.\ + @(#) Copyright (c) 2006 Itronix, Inc.\ + All rights reserved."); +__RCSID("$NetBSD: btdevctl.c,v 1.8 2009/05/12 18:39:20 plunky Exp $"); #include #include diff --git a/usr.sbin/btdevctl/sdp.c b/usr.sbin/btdevctl/sdp.c index d563af480971..c0cfaf9345a7 100644 --- a/usr.sbin/btdevctl/sdp.c +++ b/usr.sbin/btdevctl/sdp.c @@ -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. @@ -29,6 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ /* + * Copyright (c) 2009 The NetBSD Foundation, Inc. * Copyright (c) 2004 Maksim Yevmenkin * All rights reserved. * @@ -55,7 +56,7 @@ */ #include -__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 @@ -72,125 +73,104 @@ __RCSID("$NetBSD: sdp.c,v 1.6 2009/04/15 00:35:04 lukem Exp $"); #include #include #include +#include #include #include "btdevctl.h" -static int32_t parse_l2cap_psm(sdp_attr_t *); -static int32_t parse_rfcomm_channel(sdp_attr_t *); -static int32_t parse_hid_descriptor(sdp_attr_t *); -static int32_t parse_boolean(sdp_attr_t *); +static bool parse_hid_descriptor(sdp_data_t *); +static int32_t parse_boolean(sdp_data_t *); +static int32_t parse_pdl_param(sdp_data_t *, uint16_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_hset(prop_dictionary_t); -static int config_hf(prop_dictionary_t); +static int config_hid(prop_dictionary_t, sdp_data_t *); +static int config_hset(prop_dictionary_t, sdp_data_t *); +static int config_hf(prop_dictionary_t, sdp_data_t *); uint16_t hid_services[] = { - 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) + SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE, }; uint16_t hset_services[] = { - SDP_SERVICE_CLASS_HEADSET -}; - -uint32_t hset_attrs[] = { - SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, - SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), + SDP_SERVICE_CLASS_HEADSET, }; uint16_t hf_services[] = { - SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY -}; - -uint32_t hf_attrs[] = { - SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, - SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), + SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY, }; static struct { const char *name; - int (*handler)(prop_dictionary_t); + int (*handler)(prop_dictionary_t, sdp_data_t *); const char *description; uint16_t *services; - int nservices; - uint32_t *attrs; - int nattrs; + size_t nservices; } cfgtype[] = { { "HID", config_hid, "Human Interface Device", hid_services, __arraycount(hid_services), - hid_attrs, __arraycount(hid_attrs), }, { "HSET", config_hset, "Headset", hset_services, __arraycount(hset_services), - hset_attrs, __arraycount(hset_attrs), }, { "HF", config_hf, "Handsfree", hf_services, __arraycount(hf_services), - hf_attrs, __arraycount(hf_attrs), }, }; -static sdp_attr_t values[8]; -static uint8_t buffer[__arraycount(values)][512]; +#define MAX_SSP (2 + 1 * 3) /* largest nservices is 1 */ prop_dictionary_t cfg_query(bdaddr_t *laddr, bdaddr_t *raddr, const char *service) { prop_dictionary_t dict; - void *ss; - int rv; - size_t i; + sdp_session_t ss; + uint8_t buf[MAX_SSP]; + sdp_data_t ssp, rsp, rec; + size_t i, n; + bool rv; dict = prop_dictionary_create(); if (dict == 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++) { if (strcasecmp(service, cfgtype[i].name) == 0) { ss = sdp_open(laddr, raddr); - - if (ss == NULL || (errno = sdp_error(ss)) != 0) + if (ss == NULL) return NULL; - rv = sdp_search(ss, - cfgtype[i].nservices, cfgtype[i].services, - cfgtype[i].nattrs, cfgtype[i].attrs, - __arraycount(values), values); + /* build ServiceSearchPattern */ + ssp.next = buf; + ssp.end = buf + sizeof(buf); - if (rv != 0) { - errno = sdp_error(ss); + for (n = 0; n < cfgtype[i].nservices; n++) + 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; } + + while (sdp_get_seq(&rsp, &rec)) { + errno = (*cfgtype[i].handler)(dict, &rec); + if (errno == 0) { + sdp_close(ss); + return dict; + } + } + sdp_close(ss); - - rv = (*cfgtype[i].handler)(dict); - if (rv != 0) - return NULL; - - return dict; + prop_object_release(dict); + return NULL; } } @@ -205,54 +185,44 @@ cfg_query(bdaddr_t *laddr, bdaddr_t *raddr, const char *service) * Configure HID results */ static int -config_hid(prop_dictionary_t dict) +config_hid(prop_dictionary_t dict, sdp_data_t *rec) { prop_object_t obj; int32_t control_psm, interrupt_psm, - reconnect_initiate, battery_power, - normally_connectable, hid_length; + reconnect_initiate, hid_length; uint8_t *hid_descriptor; + sdp_data_t value; const char *mode; - size_t i; + uint16_t attr; control_psm = -1; interrupt_psm = -1; reconnect_initiate = -1; - normally_connectable = 0; - battery_power = 0; hid_descriptor = NULL; hid_length = -1; - for (i = 0; i < __arraycount(values); i++) { - if (values[i].flags != SDP_ATTR_OK) - continue; - - switch (values[i].attr) { + while (sdp_get_attr(rec, &attr, &value)) { + switch (attr) { case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: - control_psm = parse_l2cap_psm(&values[i]); + control_psm = parse_pdl(&value, SDP_UUID_PROTOCOL_L2CAP); break; case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: - interrupt_psm = parse_l2cap_psm(&values[i]); + interrupt_psm = parse_apdl(&value, SDP_UUID_PROTOCOL_L2CAP); break; case 0x0205: /* HIDReconnectInitiate */ - reconnect_initiate = parse_boolean(&values[i]); + reconnect_initiate = parse_boolean(&value); break; case 0x0206: /* HIDDescriptorList */ - if (parse_hid_descriptor(&values[i]) == 0) { - hid_descriptor = values[i].value; - hid_length = values[i].vlen; + if (parse_hid_descriptor(&value)) { + hid_descriptor = value.next; + hid_length = value.end - value.next; } break; - case 0x0209: /* HIDBatteryPower */ - battery_power = parse_boolean(&values[i]); - break; - - case 0x020d: /* HIDNormallyConnectable */ - normally_connectable = parse_boolean(&values[i]); + default: break; } } @@ -310,26 +280,27 @@ config_hid(prop_dictionary_t dict) * Configure HSET results */ static int -config_hset(prop_dictionary_t dict) +config_hset(prop_dictionary_t dict, sdp_data_t *rec) { prop_object_t obj; - uint32_t channel; - size_t i; + sdp_data_t value; + int32_t channel; + uint16_t attr; channel = -1; - for (i = 0; i < __arraycount(values); i++) { - if (values[i].flags != SDP_ATTR_OK) - continue; - - switch (values[i].attr) { + while (sdp_get_attr(rec, &attr, &value)) { + switch (attr) { case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: - channel = parse_rfcomm_channel(&values[i]); + channel = parse_pdl(&value, SDP_UUID_PROTOCOL_RFCOMM); + break; + + default: break; } } - if (channel == (uint32_t)-1) + if (channel == -1) return ENOATTR; obj = prop_string_create_cstring_nocopy("btsco"); @@ -351,26 +322,27 @@ config_hset(prop_dictionary_t dict) * Configure HF results */ static int -config_hf(prop_dictionary_t dict) +config_hf(prop_dictionary_t dict, sdp_data_t *rec) { prop_object_t obj; - uint32_t channel; - size_t i; + sdp_data_t value; + int32_t channel; + uint16_t attr; channel = -1; - for (i = 0; i < __arraycount(values); i++) { - if (values[i].flags != SDP_ATTR_OK) - continue; - - switch (values[i].attr) { + while (sdp_get_attr(rec, &attr, &value)) { + switch (attr) { case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: - channel = parse_rfcomm_channel(&values[i]); + channel = parse_pdl(&value, SDP_UUID_PROTOCOL_RFCOMM); + break; + + default: break; } } - if (channel == (uint32_t)-1) + if (channel == -1) return ENOATTR; 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 - * seq8 len8 2 - * uuid16 value16 3 L2CAP - * uint16 value16 3 PSM - * seq8 len8 2 - * uuid16 value16 3 HID Protocol - * === - * 15 + * If a ClassDescriptorType "Report" is found, set SDP data value to the + * ClassDescriptorData content and return true. Note that we don't need to + * extract the actual length as the SDP data is guaranteed valid. */ -static int32_t -parse_l2cap_psm(sdp_attr_t *a) +static bool +parse_hid_descriptor(sdp_data_t *value) { - uint8_t *ptr = a->value; - uint8_t *end = a->value + a->vlen; - int32_t type, len, uuid, psm; + sdp_data_t list, desc; + uintmax_t type; + char *str; + size_t len; - if (end - ptr < 15) - return (-1); + if (!sdp_get_seq(value, &list)) + return false; - if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) { - 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); + while (sdp_get_seq(&list, &desc)) { + if (sdp_get_uint(&desc, &type) + && type == UDESC_REPORT + && sdp_get_str(&desc, &str, &len)) { + value->next = (uint8_t *)str; + value->end = (uint8_t *)(str + len); + return true; } - if (ptr + len > end) - return (-1); } - SDP_GET8(type, ptr); - switch (type) { - case SDP_DATA_SEQ8: - SDP_GET8(len, ptr); - break; + return false; +} - case SDP_DATA_SEQ16: - SDP_GET16(len, ptr); - break; +static int32_t +parse_boolean(sdp_data_t *value) +{ + bool bv; - case SDP_DATA_SEQ32: - SDP_GET32(len, ptr); - break; + if (!sdp_get_bool(value, &bv)) + return -1; - 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); - } - - /* PSM */ - if (ptr + 3 > end) - return (-1); - SDP_GET8(type, ptr); - if (type != SDP_DATA_UINT16) - return (-1); - SDP_GET16(psm, ptr); - - return (psm); + return bv; } /* - * 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 - * seq8 len8 2 - * uint8 value8 2 - * str value 3 - * === - * 9 + * If the ProtocolDescriptorList describes a single stack, + * the attribute value takes the form of a data element + * sequence in which each element of the sequence is a + * protocol descriptor. + * + * seq + * + * + * 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 + * + * seq + * + * + * 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, ¶m)) + return param; + + break; + } + + return -1; +} static int32_t -parse_hid_descriptor(sdp_attr_t *a) +parse_pdl(sdp_data_t *value, uint16_t proto) { - uint8_t *ptr = a->value; - uint8_t *end = a->value + a->vlen; - int32_t type, len, descriptor_type; + sdp_data_t seq; + int32_t param = -1; - if (end - ptr < 9) - return (-1); + sdp_get_alt(value, value); /* strip any alt header */ - SDP_GET8(type, ptr); - switch (type) { - case SDP_DATA_SEQ8: - SDP_GET8(len, ptr); - break; + while (param == -1 && sdp_get_seq(value, &seq)) + param = parse_pdl_param(&seq, proto); - 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); - - 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); + return param; } /* - * Parse boolean value - * - * bool8 int8 + * Parse AdditionalProtocolDescriptorList */ - 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) - return (-1); + sdp_data_t seq; + int32_t param = -1; - return (a->value[1]); -} + sdp_get_seq(value, value); /* strip seq header */ -/* - * Parse protocol descriptor list for the RFCOMM channel - * - * seq8 len8 2 - * seq8 len8 2 - * uuid16 value16 3 L2CAP - * seq8 len8 2 - * uuid16 value16 3 RFCOMM - * uint8 value8 2 channel - * === - * 14 - */ + while (param == -1 && sdp_get_seq(value, &seq)) + param = parse_pdl_param(&seq, proto); -static int32_t -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); + return param; } /*