update to use new sdp(3) and sdp_data(3) APIs
This commit is contained in:
parent
384153c15a
commit
170631f4a8
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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, ¶m))
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue