diff options
| author | plunky <plunky@NetBSD.org> | 2009-05-12 10:05:06 +0000 |
|---|---|---|
| committer | plunky <plunky@NetBSD.org> | 2009-05-12 10:05:06 +0000 |
| commit | dfbf818a22d811e97c87c95a064bcff7ee2abb4d (patch) | |
| tree | 23994d7f278a62a4efcb30be6d9421e0fad40ec9 /lib/libbluetooth | |
| parent | 93dfc06da921375d7d447c56760b4bf9622786f1 (diff) | |
Add in the new Service Discovery Protocol API as announced previously in
http://mail-index.netbsd.org/tech-userlevel/2009/02/27/msg001764.html
in lib/libbluetooth, add new SDP functions and bump minor version
replace usr.sbin/sdpd with new version
install sdp.h and sdp.3 from lib/libbluetooth
(Don't remove libsdp yet since some programs still refer to it)
Diffstat (limited to 'lib/libbluetooth')
| -rw-r--r-- | lib/libbluetooth/Makefile | 70 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp-int.h | 56 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp.3 | 259 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp.h | 708 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_compat.c | 611 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_data.3 | 394 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_data.c | 732 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_get.c | 377 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_match.c | 60 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_put.c | 375 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_record.c | 220 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_service.c | 470 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_session.c | 273 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_set.c | 248 | ||||
| -rw-r--r-- | lib/libbluetooth/sdp_uuid.c | 44 | ||||
| -rw-r--r-- | lib/libbluetooth/shlib_version | 4 |
16 files changed, 4895 insertions, 6 deletions
diff --git a/lib/libbluetooth/Makefile b/lib/libbluetooth/Makefile index 2d6f64bfc8f..a085821c84b 100644 --- a/lib/libbluetooth/Makefile +++ b/lib/libbluetooth/Makefile @@ -1,15 +1,21 @@ -# $NetBSD: Makefile,v 1.3 2007/05/28 12:06:18 tls Exp $ +# $NetBSD: Makefile,v 1.4 2009/05/12 10:05:06 plunky Exp $ USE_FORT?= yes # network protocol library LIB= bluetooth -SRCS= bluetooth.c devaddr.c -MAN= bluetooth.3 +SRCS= bluetooth.c devaddr.c \ + sdp_data.c sdp_get.c sdp_match.c sdp_put.c sdp_record.c \ + sdp_set.c sdp_uuid.c sdp_service.c sdp_session.c +MAN= bluetooth.3 sdp.3 sdp_data.3 CPPFLAGS+= -I${.CURDIR} -INCS= bluetooth.h +.if (${SDP_COMPAT:Uyes} != "no") +SRCS+= sdp_compat.c +.endif + +INCS= bluetooth.h sdp.h INCSDIR= /usr/include MLINKS+= bluetooth.3 bt_gethostbyname.3 @@ -30,4 +36,60 @@ MLINKS+= bluetooth.3 bt_aton.3 MLINKS+= bluetooth.3 bt_devaddr.3 MLINKS+= bluetooth.3 bt_devname.3 +MLINKS+= sdp.3 sdp_open.3 +MLINKS+= sdp.3 sdp_open_local.3 +MLINKS+= sdp.3 sdp_close.3 +MLINKS+= sdp.3 sdp_service_search.3 +MLINKS+= sdp.3 sdp_service_attribute.3 +MLINKS+= sdp.3 sdp_service_search_attribute.3 +MLINKS+= sdp.3 sdp_record_insert.3 +MLINKS+= sdp.3 sdp_record_update.3 +MLINKS+= sdp.3 sdp_record_remove.3 + +MLINKS+= sdp_data.3 sdp_match_uuid16.3 + +MLINKS+= sdp_data.3 sdp_data_print.3 +MLINKS+= sdp_data.3 sdp_data_size.3 +MLINKS+= sdp_data.3 sdp_data_type.3 +MLINKS+= sdp_data.3 sdp_data_valid.3 + +MLINKS+= sdp_data.3 sdp_get_alt.3 +MLINKS+= sdp_data.3 sdp_get_attr.3 +MLINKS+= sdp_data.3 sdp_get_bool.3 +MLINKS+= sdp_data.3 sdp_get_data.3 +MLINKS+= sdp_data.3 sdp_get_int.3 +MLINKS+= sdp_data.3 sdp_get_seq.3 +MLINKS+= sdp_data.3 sdp_get_str.3 +MLINKS+= sdp_data.3 sdp_get_url.3 +MLINKS+= sdp_data.3 sdp_get_uint.3 +MLINKS+= sdp_data.3 sdp_get_uuid.3 + +MLINKS+= sdp_data.3 sdp_put_alt.3 +MLINKS+= sdp_data.3 sdp_put_attr.3 +MLINKS+= sdp_data.3 sdp_put_bool.3 +MLINKS+= sdp_data.3 sdp_put_data.3 +MLINKS+= sdp_data.3 sdp_put_int.3 +MLINKS+= sdp_data.3 sdp_put_int8.3 +MLINKS+= sdp_data.3 sdp_put_int16.3 +MLINKS+= sdp_data.3 sdp_put_int32.3 +MLINKS+= sdp_data.3 sdp_put_int64.3 +MLINKS+= sdp_data.3 sdp_put_seq.3 +MLINKS+= sdp_data.3 sdp_put_str.3 +MLINKS+= sdp_data.3 sdp_put_uint.3 +MLINKS+= sdp_data.3 sdp_put_uint8.3 +MLINKS+= sdp_data.3 sdp_put_uint16.3 +MLINKS+= sdp_data.3 sdp_put_uint32.3 +MLINKS+= sdp_data.3 sdp_put_uint64.3 +MLINKS+= sdp_data.3 sdp_put_url.3 +MLINKS+= sdp_data.3 sdp_put_uuid.3 +MLINKS+= sdp_data.3 sdp_put_uuid16.3 +MLINKS+= sdp_data.3 sdp_put_uuid32.3 +MLINKS+= sdp_data.3 sdp_put_uuid128.3 + +MLINKS+= sdp_data.3 sdp_set_alt.3 +MLINKS+= sdp_data.3 sdp_set_bool.3 +MLINKS+= sdp_data.3 sdp_set_seq.3 +MLINKS+= sdp_data.3 sdp_set_uint.3 +MLINKS+= sdp_data.3 sdp_set_int.3 + .include <bsd.lib.mk> diff --git a/lib/libbluetooth/sdp-int.h b/lib/libbluetooth/sdp-int.h new file mode 100644 index 00000000000..745d4484bd0 --- /dev/null +++ b/lib/libbluetooth/sdp-int.h @@ -0,0 +1,56 @@ +/* $NetBSD: sdp-int.h,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/* + * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SDP_INT_H_ +#define _SDP_INT_H_ + +struct sdp_session { + uint16_t tid; /* current session transaction ID */ + uint16_t imtu; /* incoming MTU */ + uint8_t *ibuf; /* incoming buffer */ + uint8_t *rbuf; /* response buffer */ + uint8_t cs[17];/* continuation state */ + int32_t s; /* L2CAP socket */ +}; + +/* sdp_session.c */ +sdp_session_t _sdp_open(const bdaddr_t *, const bdaddr_t *); +sdp_session_t _sdp_open_local(const char *); +void _sdp_close(sdp_session_t); +bool _sdp_send_pdu(struct sdp_session *, uint8_t, struct iovec *, int); +ssize_t _sdp_recv_pdu(struct sdp_session *, uint8_t); +int _sdp_errno(uint16_t); + +/* sdp_data.c */ +bool _sdp_data_print(const uint8_t *, const uint8_t *, int); + +/* sdp_service.c */ +bool sdp_service_search_attribute(sdp_session_t, const sdp_data_t *, + const sdp_data_t *, sdp_data_t *); + +#endif /* _SDP_INT_H_ */ diff --git a/lib/libbluetooth/sdp.3 b/lib/libbluetooth/sdp.3 new file mode 100644 index 00000000000..ed2a7b0c954 --- /dev/null +++ b/lib/libbluetooth/sdp.3 @@ -0,0 +1,259 @@ +.\" $NetBSD: sdp.3,v 1.1 2009/05/12 10:05:06 plunky Exp $ +.\" +.\" Copyright (c) 2009 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Iain Hibbert. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 7, 2009 +.Dt SDP 3 +.Os +.Sh NAME +.Nm sdp_open , +.Nm sdp_open_local , +.Nm sdp_close , +.Nm sdp_service_search , +.Nm sdp_service_attribute , +.Nm sdp_service_search_attribute , +.Nm sdp_record_insert , +.Nm sdp_record_update , +.Nm sdp_record_remove +.Nd Service Discovery Protocol session routines +.Sh LIBRARY +.Lb libbluetooth +.Sh SYNOPSIS +.In sdp.h +.Ft sdp_session_t +.Fn sdp_open "const bdaddr_t *laddr" "const bdaddr_t *raddr" +.Ft sdp_session_t +.Fn sdp_open_local "const char *control" +.Ft void +.Fn sdp_close "sdp_session_t ss" +.Ft bool +.Fo sdp_service_search +.Fa "sdp_session_t ss" "sdp_data_t *ssp" "uint32_t *handlep" "int *num" +.Fc +.Ft bool +.Fo sdp_service_attribute +.Fa "sdp_session_t ss" "uint32_t handle" "sdp_data_t *ail" "sdp_data_t *response" +.Fc +.Ft bool +.Fo sdp_service_search_attribute +.Fa "sdp_session_t ss" "sdp_data_t *ssp" "sdp_data_t *ail" "sdp_data_t *response" +.Fc +.Ft bool +.Fo sdp_record_insert +.Fa "sdp_session_t ss" "bdaddr_t *bdaddr" "uint32_t *handlep" "sdp_data_t *record" +.Fc +.Ft bool +.Fn sdp_record_update "sdp_session_t ss" "uint32_t handle" "sdp_data_t *record" +.Ft bool +.Fn sdp_record_remove "sdp_session_t ss" "uint32_t handle" +.Sh DESCRIPTION +The SDP library provides means for client programs to perform Bluetooth +Service Discovery, and to advertise Service Records on the local host. +.Pp +The Service Discovery API reflects the Bluetooth SDP specification, providing +access to complete ServiceSearch, ServiceAttribute or ServiceSearchAttribute +transactions and using SDP data element lists directly which can be +constructed and parsed with the +.Xr sdp_data 3 +library functions. +.Pp +The ServiceSearchPattern is a list of UUID data elements. The list must +contain at least one UUID and the maximum number of UUIDs is 12. +A service record will be matched when all the UUIDs from the +ServiceSearchPattern are contained in the record. +.Pp +The AttributeIDList is a list of data elements where each is either an +attribute ID encoded as an unsigned 16-bit integer, or a range of attribute +IDs encoded as an unsigned 32-bit integer where the high order 16-bits are +the start of the range and the low order 16-bits are the end of the range +.Pq inclusive . +The AttributeIDList should be arranged in ascending order and there should +be no duplicate attribute ID values. +If +.Dv NULL +is passed, all attributes +.Pq 0x0000-0xffff +will be requested. +.Pp +ServiceRecords to be registered with the local +.Xr sdpd 8 +server should consist of a list of attribute ID/value pairs, where the +attribute ID is a 16-bit unsigned integer element, and the attribute value +is any data element. +The attribute IDs should be in ascending order, and the first one must be +.Dv SDP_ATTR_SERVICE_RECORD_HANDLE +.Pq 0x0000 , +otherwise the server will reject the record. +For consistency, records should also contain a BrowseGroupList with the +PublicBrowseGroup UUID, plus at least a ServiceName string in the native +language with an associated LanguageBaseAttributeIDList although this is +not currently enforced. +.Sh FUNCTIONS +.Bl -tag -width xxxx +.It Fn sdp_open "laddr" "raddr" +Open a SDP session to a remote Bluetooth device. +.Ar laddr +refers to the local bluetooth device address and may be +.Dv NULL +in which case it will default to +.Dv BDADDR_ANY . +.It Fn sdp_open_local "control" +Open a SDP session to a server using a local socket. +The +.Ar control +socket path may be given as +.Dv NULL +in which case the default control path +.Pa /var/run/sdp +will be used. +.It Fn sdp_close ss +Close SDP session and release all resources. +.It Fn sdp_service_search "ss" "ssp" "handlep" "num" +Perform a complete ServiceSearch transaction on the SDP session. +At most +.Ar num +service record handles matching the ServiceSearchPattern +.Ar ssp +will be returned in the array pointed to by +.Ar handlep . +.It Fn sdp_service_attribute "ss" "handle" "ail" "response" +Perform a complete ServiceAttribute transaction on the SDP session. +The ServiceRecord with ServiceRecordHandle +.Ar handle +will be parsed using the AttributeIDList +.Ar ail . +If the transaction succeeds, the +.Ar response +data buffer will contain a validated data element list of attribute +ID/value pairs from the selected record. +.It Fn sdp_service_search_attribute "ss" "ssp" "ail" "response" +Perform a complete ServiceSearchAttribute transaction on the SDP session. +All ServiceRecords matching the ServiceSearchPattern +.Ar ssp +will be parsed using the AttributeIDList +.Ar ail . +If the transaction succeeds, the +.Ar response +data buffer will contain a valid data element list of sequences, where +each sequence is the attribute ID/value list from a matched record. +.It Fn sdp_record_insert "ss" "bdaddr" "handlep" "record" +Insert a ServiceRecord +.Ar record . +If +.Ar bdaddr +is given, the service record will be restricted to clients connecting +through the Bluetooth controller with that BD_ADDR. +When the +.Ar handlep +pointer is non NULL, the resulting ServiceRecordHandle will be written +to the address given. +The record will be valid while the session is active and will be +purged when the session is closed. +.It Fn sdp_record_update "ss" "handle" "record" +Update a ServiceRecord that is owned by this session. +.Ar handle +is the identifier returned by the +.Fn sdp_record_insert +call, and +.Ar record +is the updated ServiceRecord as described above. +.It Fn sdp_record_remove "ss" "handle" +Remove a ServiceRecord owned by this session. +.Ar handle +is the identifier returned by the +.Fn sdp_record_insert +call. +.El +.Pp +A single response buffer is maintained for each session, so the results +of a ServiceAttribute or ServiceSearchAttribute request will only be valid +until another request is made or the session is closed. +The SDP specifications do not mandate a limit on the size of the response +buffer but this implementation has a default limit of UINT16_MAX bytes. +This limit can be increased at runtime by setting the environment variable +.Ev SDP_RESPONSE_MAX +to a numeric value. +.Pp +Records are only allowed to be removed or updated by the session that inserted +them, and records will be removed automatically when the session is closed. +Further, manipulating service records will normally only be possible for +privileged users on a SDP session connected with a local socket. +See +.Xr sdpd 8 +and your local system administrator for details. +.Sh RETURN VALUES +Session open routines will return a session handle on success and +.Dv NULL +on failure. +For service lookup and record manipulation routines, a boolean value is +returned indicating success or failure. +On failure, +.Ar errno +will be set to indicate the error. +.Sh ERRORS +In addition to errors returned by the standard C library IO functions, +the following errors may be detected by +.Nm libbluetooth : +.Bl -tag -offset indent -width ".Bq Er ENOATTR" +.It Bq Er EINVAL +A provided function argument was not valid. +.It Bq Er EIO +A response from the remote server was not understood. +.It Bq Er ENOATTR +The record +.Ar handle +did not exist on the server. +.El +.Sh FILES +.Pa /var/run/sdp +.Sh SEE ALSO +.Xr sdpquery 1 , +.Xr bluetooth 3 , +.Xr sdp_data 3 , +.Xr sdpd 8 +.Pp +The +.Qq Service Discovery Protocol +section of the Bluetooth Core specifications, available at +.Qq http://www.bluetooth.com/ +.Sh HISTORY +The first Service Discovery implementation was written for +.Fx +and was ported to +.Nx 4.0 . +This, the second version API, was designed by +.An Iain Hibbert +for +.Nx 6.0 +in order to simplify the +.Xr sdpd 8 +daemon and allow client code greater control over all aspects of the +service records. +The original API is still available when +.Dv SDP_COMPAT +is defined but will eventually be removed. diff --git a/lib/libbluetooth/sdp.h b/lib/libbluetooth/sdp.h new file mode 100644 index 00000000000..94978ba75c9 --- /dev/null +++ b/lib/libbluetooth/sdp.h @@ -0,0 +1,708 @@ +/* $NetBSD: sdp.h,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Iain Hibbert for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 2001-2003, 2008 Maksim Yevmenkin <m_evmenkin@yahoo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libsdp/sdp.h,v 1.5 2005/05/27 19:11:33 emax Exp $ + */ + +#ifndef _SDP_H_ +#define _SDP_H_ + +#include <stdbool.h> +#include <uuid.h> + +#include <bluetooth.h> + +/* + * SDP Data Element types + */ + +#define SDP_DATA_TYPE(b) ((b) & 0xf8) +#define SDP_DATA_SIZE(b) ((b) & 0x07) + +/* data size descriptors */ +#define SDP_DATA_8 0x00 +#define SDP_DATA_16 0x01 +#define SDP_DATA_32 0x02 +#define SDP_DATA_64 0x03 +#define SDP_DATA_128 0x04 +#define SDP_DATA_EXT8 0x05 +#define SDP_DATA_EXT16 0x06 +#define SDP_DATA_EXT32 0x07 + +/* data type descriptors */ +#define SDP_DATA_NIL 0x00 +#define SDP_DATA_UINT 0x08 +#define SDP_DATA_INT 0x10 +#define SDP_DATA_UUID 0x18 +#define SDP_DATA_STR 0x20 +#define SDP_DATA_BOOL 0x28 +#define SDP_DATA_SEQ 0x30 +#define SDP_DATA_ALT 0x38 +#define SDP_DATA_URL 0x40 + +/* Unsigned integer */ +#define SDP_DATA_UINT8 (SDP_DATA_UINT | SDP_DATA_8) +#define SDP_DATA_UINT16 (SDP_DATA_UINT | SDP_DATA_16) +#define SDP_DATA_UINT32 (SDP_DATA_UINT | SDP_DATA_32) +#define SDP_DATA_UINT64 (SDP_DATA_UINT | SDP_DATA_64) +#define SDP_DATA_UINT128 (SDP_DATA_UINT | SDP_DATA_128) + +/* Signed two's-complement integer */ +#define SDP_DATA_INT8 (SDP_DATA_INT | SDP_DATA_8) +#define SDP_DATA_INT16 (SDP_DATA_INT | SDP_DATA_16) +#define SDP_DATA_INT32 (SDP_DATA_INT | SDP_DATA_32) +#define SDP_DATA_INT64 (SDP_DATA_INT | SDP_DATA_64) +#define SDP_DATA_INT128 (SDP_DATA_INT | SDP_DATA_128) + +/* UUID, a universally unique identifier */ +#define SDP_DATA_UUID16 (SDP_DATA_UUID | SDP_DATA_16) +#define SDP_DATA_UUID32 (SDP_DATA_UUID | SDP_DATA_32) +#define SDP_DATA_UUID128 (SDP_DATA_UUID | SDP_DATA_128) + +/* Text string */ +#define SDP_DATA_STR8 (SDP_DATA_STR | SDP_DATA_EXT8) +#define SDP_DATA_STR16 (SDP_DATA_STR | SDP_DATA_EXT16) +#define SDP_DATA_STR32 (SDP_DATA_STR | SDP_DATA_EXT32) + +/* Data element sequence */ +#define SDP_DATA_SEQ8 (SDP_DATA_SEQ | SDP_DATA_EXT8) +#define SDP_DATA_SEQ16 (SDP_DATA_SEQ | SDP_DATA_EXT16) +#define SDP_DATA_SEQ32 (SDP_DATA_SEQ | SDP_DATA_EXT32) + +/* Data element alternative */ +#define SDP_DATA_ALT8 (SDP_DATA_ALT | SDP_DATA_EXT8) +#define SDP_DATA_ALT16 (SDP_DATA_ALT | SDP_DATA_EXT16) +#define SDP_DATA_ALT32 (SDP_DATA_ALT | SDP_DATA_EXT32) + +/* URL, a uniform resource locator */ +#define SDP_DATA_URL8 (SDP_DATA_URL | SDP_DATA_EXT8) +#define SDP_DATA_URL16 (SDP_DATA_URL | SDP_DATA_EXT16) +#define SDP_DATA_URL32 (SDP_DATA_URL | SDP_DATA_EXT32) + +/* + * Protocol UUIDs (short alias version) + * + * BLUETOOTH BASE UUID 00000000-0000-1000-8000-00805F9B34FB + */ +#define SDP_UUID_PROTOCOL_SDP 0x0001 +#define SDP_UUID_PROTOCOL_UDP 0x0002 +#define SDP_UUID_PROTOCOL_RFCOMM 0x0003 +#define SDP_UUID_PROTOCOL_TCP 0x0004 +#define SDP_UUID_PROTOCOL_TCS_BIN 0x0005 +#define SDP_UUID_PROTOCOL_TCS_AT 0x0006 +#define SDP_UUID_PROTOCOL_OBEX 0x0008 +#define SDP_UUID_PROTOCOL_IP 0x0009 +#define SDP_UUID_PROTOCOL_FTP 0x000A +#define SDP_UUID_PROTOCOL_HTTP 0x000C +#define SDP_UUID_PROTOCOL_WSP 0x000E +#define SDP_UUID_PROTOCOL_BNEP 0x000F +#define SDP_UUID_PROTOCOL_UPNP 0x0010 +#define SDP_UUID_PROTOCOL_HIDP 0x0011 +#define SDP_UUID_PROTOCOL_HARDCOPY_CONTROL_CHANNEL 0x0012 +#define SDP_UUID_PROTOCOL_HARDCOPY_DATA_CHANNEL 0x0014 +#define SDP_UUID_PROTOCOL_HARDCOPY_NOTIFICATION 0x0016 +#define SDP_UUID_PROTOCOL_AVCTP 0x0017 +#define SDP_UUID_PROTOCOL_AVDTP 0x0019 +#define SDP_UUID_PROTOCOL_CMPT 0x001B +#define SDP_UUID_PROTOCOL_UDI_C_PLANE 0x001D +#define SDP_UUID_PROTOCOL_L2CAP 0x0100 + +/* + * Service Class IDs + */ +#define SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER 0x1000 +#define SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR 0x1001 +#define SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP 0x1002 +#define SDP_SERVICE_CLASS_SERIAL_PORT 0x1101 +#define SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP 0x1102 +#define SDP_SERVICE_CLASS_DIALUP_NETWORKING 0x1103 +#define SDP_SERVICE_CLASS_IR_MC_SYNC 0x1104 +#define SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH 0x1105 +#define SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER 0x1106 +#define SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND 0x1107 +#define SDP_SERVICE_CLASS_HEADSET 0x1108 +#define SDP_SERVICE_CLASS_CORDLESS_TELEPHONY 0x1109 +#define SDP_SERVICE_CLASS_AUDIO_SOURCE 0x110A +#define SDP_SERVICE_CLASS_AUDIO_SINK 0x110B +#define SDP_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET 0x110C +#define SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION 0x110D +#define SDP_SERVICE_CLASS_AV_REMOTE_CONTROL 0x110E +#define SDP_SERVICE_CLASS_VIDEO_CONFERENCING 0x110F +#define SDP_SERVICE_CLASS_INTERCOM 0x1110 +#define SDP_SERVICE_CLASS_FAX 0x1111 +#define SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY 0x1112 +#define SDP_SERVICE_CLASS_WAP 0x1113 +#define SDP_SERVICE_CLASS_WAP_CLIENT 0x1114 +#define SDP_SERVICE_CLASS_PANU 0x1115 +#define SDP_SERVICE_CLASS_NAP 0x1116 +#define SDP_SERVICE_CLASS_GN 0x1117 +#define SDP_SERVICE_CLASS_DIRECT_PRINTING 0x1118 +#define SDP_SERVICE_CLASS_REFERENCE_PRINTING 0x1119 +#define SDP_SERVICE_CLASS_IMAGING 0x111A +#define SDP_SERVICE_CLASS_IMAGING_RESPONDER 0x111B +#define SDP_SERVICE_CLASS_IMAGING_AUTOMATIC_ARCHIVE 0x111C +#define SDP_SERVICE_CLASS_IMAGING_REFERENCED_OBJECTS 0x111D +#define SDP_SERVICE_CLASS_HANDSFREE 0x111E +#define SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY 0x111F +#define SDP_SERVICE_CLASS_DIRECT_PRINTING_REFERENCE_OBJECTS 0x1120 +#define SDP_SERVICE_CLASS_REFLECTED_UI 0x1121 +#define SDP_SERVICE_CLASS_BASIC_PRINTING 0x1122 +#define SDP_SERVICE_CLASS_PRINTING_STATUS 0x1123 +#define SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE 0x1124 +#define SDP_SERVICE_CLASS_HARDCOPY_CABLE_REPLACEMENT 0x1125 +#define SDP_SERVICE_CLASS_HCR_PRINT 0x1126 +#define SDP_SERVICE_CLASS_HCR_SCAN 0x1127 +#define SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS 0x1128 +#define SDP_SERVICE_CLASS_VIDEO_CONFERENCING_GW 0x1129 +#define SDP_SERVICE_CLASS_UDI_MT 0x112A +#define SDP_SERVICE_CLASS_UDI_TA 0x112B +#define SDP_SERVICE_CLASS_AUDIO_VIDEO 0x112C +#define SDP_SERVICE_CLASS_SIM_ACCESS 0x112D +#define SDP_SERVICE_CLASS_PNP_INFORMATION 0x1200 +#define SDP_SERVICE_CLASS_GENERIC_NETWORKING 0x1201 +#define SDP_SERVICE_CLASS_GENERIC_FILE_TRANSFER 0x1202 +#define SDP_SERVICE_CLASS_GENERIC_AUDIO 0x1203 +#define SDP_SERVICE_CLASS_GENERIC_TELEPHONY 0x1204 +#define SDP_SERVICE_CLASS_UPNP 0x1205 +#define SDP_SERVICE_CLASS_UPNP_IP 0x1206 +#define SDP_SERVICE_CLASS_ESDP_UPNP_IP_PAN 0x1300 +#define SDP_SERVICE_CLASS_ESDP_UPNP_IP_LAP 0x1301 +#define SDP_SERVICE_CLASS_ESDP_UPNP_L2CAP 0x1302 + +/* + * Universal Attribute definitions valid in all service classes + */ +#define SDP_ATTR_SERVICE_RECORD_HANDLE 0x0000 +#define SDP_ATTR_SERVICE_CLASS_ID_LIST 0x0001 +#define SDP_ATTR_SERVICE_RECORD_STATE 0x0002 +#define SDP_ATTR_SERVICE_ID 0x0003 +#define SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST 0x0004 +#define SDP_ATTR_BROWSE_GROUP_LIST 0x0005 +#define SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST 0x0006 +#define SDP_ATTR_SERVICE_INFO_TIME_TO_LIVE 0x0007 +#define SDP_ATTR_SERVICE_AVAILABILITY 0x0008 +#define SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST 0x0009 +#define SDP_ATTR_DOCUMENTATION_URL 0x000A +#define SDP_ATTR_CLIENT_EXECUTABLE_URL 0x000B +#define SDP_ATTR_ICON_URL 0x000C +#define SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS 0x000D +/* 0x000E-0x01ff are reserved */ + +/* + * The offset must be added to the attribute ID base (contained in the + * LANGUAGE_BASE_ATTRIBUTE_ID_LIST attribute value) in order to compute + * the attribute ID for these attributes. + * The primary language base is always 0x0100. + */ +#define SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID 0x0100 +#define SDP_ATTR_SERVICE_NAME_OFFSET 0x0000 +#define SDP_ATTR_SERVICE_DESCRIPTION_OFFSET 0x0001 +#define SDP_ATTR_PROVIDER_NAME_OFFSET 0x0002 + +/* ServiceDiscoveryServer profile attribute definitions */ +#define SDP_ATTR_VERSION_NUMBER_LIST 0x0200 +#define SDP_ATTR_SERVICE_DATABASE_STATE 0x0201 + +/* BrowseGroupDescriptor profile attribute definitions */ +#define SDP_ATTR_GROUP_ID 0x0200 + +/* Other profile attribute definitions */ +#define SDP_ATTR_IP_SUBNET 0x0200 +#define SDP_ATTR_SERVICE_VERSION 0x0300 +#define SDP_ATTR_EXTERNAL_NETWORK 0x0301 +#define SDP_ATTR_NETWORK 0x0301 +#define SDP_ATTR_SUPPORTED_DATA_STORES_LIST 0x0301 +#define SDP_ATTR_FAX_CLASS1_SUPPORT 0x0302 +#define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL 0x0302 +#define SDP_ATTR_FAX_CLASS20_SUPPORT 0x0303 +#define SDP_ATTR_SUPPORTED_FORMATS_LIST 0x0303 +#define SDP_ATTR_FAX_CLASS2_SUPPORT 0x0304 +#define SDP_ATTR_AUDIO_FEEDBACK_SUPPORT 0x0305 +#define SDP_ATTR_NETWORK_ADDRESS 0x0306 +#define SDP_ATTR_WAP_GATEWAY 0x0307 +#define SDP_ATTR_HOME_PAGE_URL 0x0308 +#define SDP_ATTR_WAP_STACK_TYPE 0x0309 +#define SDP_ATTR_SECURITY_DESCRIPTION 0x030A +#define SDP_ATTR_NET_ACCESS_TYPE 0x030B +#define SDP_ATTR_MAX_NET_ACCESS_RATE 0x030C +#define SDP_ATTR_IPV4_SUBNET 0x030D +#define SDP_ATTR_IPV6_SUBNET 0x030E +#define SDP_ATTR_SUPPORTED_CAPABALITIES 0x0310 +#define SDP_ATTR_SUPPORTED_FEATURES 0x0311 +#define SDP_ATTR_SUPPORTED_FUNCTIONS 0x0312 +#define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY 0x0313 + +/* + * Protocol Data Unit (PDU) header format + */ + +typedef struct { + uint8_t pid; /* PDU ID - SDP_PDU_xxx */ + uint16_t tid; /* transaction ID */ + uint16_t len; /* parameters length (in bytes) */ +} __packed sdp_pdu_t; + +/* PDU IDs */ +#define SDP_PDU_ERROR_RESPONSE 0x01 +#define SDP_PDU_SERVICE_SEARCH_REQUEST 0x02 +#define SDP_PDU_SERVICE_SEARCH_RESPONSE 0x03 +#define SDP_PDU_SERVICE_ATTRIBUTE_REQUEST 0x04 +#define SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE 0x05 +#define SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST 0x06 +#define SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE 0x07 + +/* Error codes for SDP_PDU_ERROR_RESPONSE */ +#define SDP_ERROR_CODE_INVALID_SDP_VERSION 0x0001 +#define SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE 0x0002 +#define SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX 0x0003 +#define SDP_ERROR_CODE_INVALID_PDU_SIZE 0x0004 +#define SDP_ERROR_CODE_INVALID_CONTINUATION_STATE 0x0005 +#define SDP_ERROR_CODE_INSUFFICIENT_RESOURCES 0x0006 + + +/***************************************************************************** + * sdpd(8) interface + */ + +#define SDP_LOCAL_PATH "/var/run/sdp" +#define SDP_LOCAL_MTU L2CAP_MTU_DEFAULT + +/* + * These are NOT defined in spec and the requests are only accepted + * by sdpd(8) on the control socket. The response will be an Error + * Response with an ErrorCode of 0x0000 indicating success. + */ +#define SDP_PDU_RECORD_INSERT_REQUEST 0x84 +#define SDP_PDU_RECORD_UPDATE_REQUEST 0x86 +#define SDP_PDU_RECORD_REMOVE_REQUEST 0x82 + + +/****************************************************************************** + * Service Discovery API in libbluetooth(3) + */ + +typedef struct { + uint8_t *next; + uint8_t *end; +} sdp_data_t; + +typedef struct sdp_session *sdp_session_t; + +/* sdp_uuid.c */ +extern const uuid_t BLUETOOTH_BASE_UUID; + +#ifndef SDP_COMPAT +/* sdp_session.c */ +sdp_session_t sdp_open(const bdaddr_t *, const bdaddr_t *) __RENAME(_sdp_open); +sdp_session_t sdp_open_local(const char *) __RENAME(_sdp_open_local); +void sdp_close(sdp_session_t) __RENAME(_sdp_close); + +/* sdp_record.c */ +bool sdp_record_insert(sdp_session_t, bdaddr_t *, uint32_t *, const sdp_data_t *); +bool sdp_record_update(sdp_session_t, uint32_t, const sdp_data_t *); +bool sdp_record_remove(sdp_session_t, uint32_t); + +/* sdp_service.c */ +bool sdp_service_search(sdp_session_t, const sdp_data_t *, uint32_t *, int *); +bool sdp_service_attribute(sdp_session_t, uint32_t, const sdp_data_t *, sdp_data_t *); +bool sdp_service_search_attribute(sdp_session_t, const sdp_data_t *, const sdp_data_t *, sdp_data_t *); +#endif + +/* sdp_match.c */ +bool sdp_match_uuid16(sdp_data_t *, uint16_t); + +/* sdp_get.c */ +bool sdp_get_data(sdp_data_t *, sdp_data_t *); +bool sdp_get_attr(sdp_data_t *, uint16_t *, sdp_data_t *); +bool sdp_get_uuid(sdp_data_t *, uuid_t *); +bool sdp_get_bool(sdp_data_t *, bool *); +bool sdp_get_seq(sdp_data_t *, sdp_data_t *); +bool sdp_get_alt(sdp_data_t *, sdp_data_t *); +bool sdp_get_uint(sdp_data_t *, uintmax_t *); +bool sdp_get_int(sdp_data_t *, intmax_t *); +bool sdp_get_str(sdp_data_t *, char **, size_t *); +bool sdp_get_url(sdp_data_t *, char **, size_t *); + +/* sdp_put.c */ +bool sdp_put_data(sdp_data_t *, sdp_data_t *); +bool sdp_put_attr(sdp_data_t *, uint16_t, sdp_data_t *); +bool sdp_put_uuid(sdp_data_t *, const uuid_t *); +bool sdp_put_uuid16(sdp_data_t *, uint16_t); +bool sdp_put_uuid32(sdp_data_t *, uint32_t); +bool sdp_put_uuid128(sdp_data_t *, const uuid_t *); +bool sdp_put_bool(sdp_data_t *, bool); +bool sdp_put_uint(sdp_data_t *, uintmax_t); +bool sdp_put_uint8(sdp_data_t *, uint8_t); +bool sdp_put_uint16(sdp_data_t *, uint16_t); +bool sdp_put_uint32(sdp_data_t *, uint32_t); +bool sdp_put_uint64(sdp_data_t *, uint64_t); +bool sdp_put_int(sdp_data_t *, intmax_t); +bool sdp_put_int8(sdp_data_t *, int8_t); +bool sdp_put_int16(sdp_data_t *, int16_t); +bool sdp_put_int32(sdp_data_t *, int32_t); +bool sdp_put_int64(sdp_data_t *, int64_t); +bool sdp_put_seq(sdp_data_t *, ssize_t); +bool sdp_put_alt(sdp_data_t *, ssize_t); +bool sdp_put_str(sdp_data_t *, const char *, ssize_t); +bool sdp_put_url(sdp_data_t *, const char *, ssize_t); + +/* sdp_set.c */ +bool sdp_set_bool(const sdp_data_t *, bool); +bool sdp_set_uint(const sdp_data_t *, uintmax_t); +bool sdp_set_int(const sdp_data_t *, intmax_t); +bool sdp_set_seq(const sdp_data_t *, ssize_t); +bool sdp_set_alt(const sdp_data_t *, ssize_t); + +/* sdp_data.c */ +ssize_t sdp_data_size(const sdp_data_t *); +int sdp_data_type(const sdp_data_t *); +bool sdp_data_valid(const sdp_data_t *); +void sdp_data_print(const sdp_data_t *, int); + +/****************************************************************************** + * + * Source level compatibility with old API + * + * enable with -DSDP_COMPAT but it will be removed eventually + * + ******************************************************************************/ + +#ifdef SDP_COMPAT +#include <strings.h> + +typedef sdp_pdu_t *sdp_pdu_p; + +#define SDP_PDU_SERVICE_REGISTER_REQUEST 0x81 +#define SDP_PDU_SERVICE_UNREGISTER_REQUEST 0x82 +#define SDP_PDU_SERVICE_CHANGE_REQUEST 0x83 + +/* + * SDP int128/uint128 parameter + */ + +struct int128 { + int8_t b[16]; +}; +typedef struct int128 int128_t; +typedef struct int128 uint128_t; + +/* + * SDP attribute + */ + +struct sdp_attr { + uint16_t flags; +#define SDP_ATTR_OK (0 << 0) +#define SDP_ATTR_INVALID (1 << 0) +#define SDP_ATTR_TRUNCATED (1 << 1) + uint16_t attr; /* SDP_ATTR_xxx */ + uint32_t vlen; /* length of the value[] in bytes */ + uint8_t *value; /* base pointer */ +}; +typedef struct sdp_attr sdp_attr_t; +typedef struct sdp_attr * sdp_attr_p; + +#define SDP_ATTR_RANGE(lo, hi) \ + (uint32_t)(((uint16_t)(lo) << 16) | ((uint16_t)(hi))) + +/* sdp_compat.c */ +void *sdp_open(bdaddr_t const *, bdaddr_t const *); +void *sdp_open_local(char const *); +int32_t sdp_close(void *); +int32_t sdp_error(void *); +int32_t sdp_search(void *, uint32_t, uint16_t const *, uint32_t, uint32_t const *, uint32_t, sdp_attr_t *); +int32_t sdp_register_service(void *, uint16_t, bdaddr_t *, uint8_t *, uint32_t, uint32_t *); +int32_t sdp_unregister_service(void *, uint32_t); +int32_t sdp_change_service(void *, uint32_t, uint8_t *, uint32_t); +const char *sdp_attr2desc(uint16_t); +const char *sdp_uuid2desc(uint16_t); +void sdp_print(uint32_t, uint8_t *, uint8_t const *); + +/* Inline versions of get/put byte/short/long. Pointer is advanced */ +#define SDP_GET8(b, cp) do { \ + (b) = *(const uint8_t *)(cp); \ + (cp) += sizeof(uint8_t); \ +} while (/* CONSTCOND */0) + +#define SDP_GET16(s, cp) do { \ + (s) = be16dec(cp); \ + (cp) += sizeof(uint16_t); \ +} while (/* CONSTCOND */0) + +#define SDP_GET32(l, cp) do { \ + (l) = be32dec(cp); \ + (cp) += sizeof(uint32_t); \ +} while (/* CONSTCOND */0) + +#define SDP_GET64(l, cp) do { \ + (l) = be64dec(cp); \ + (cp) += sizeof(uint64_t); \ +} while (/* CONSTCOND */0) + +#if BYTE_ORDER == LITTLE_ENDIAN +#define SDP_GET128(l, cp) do { \ + register const uint8_t *t_cp = (const uint8_t *)(cp); \ + (l)->b[15] = *t_cp++; \ + (l)->b[14] = *t_cp++; \ + (l)->b[13] = *t_cp++; \ + (l)->b[12] = *t_cp++; \ + (l)->b[11] = *t_cp++; \ + (l)->b[10] = *t_cp++; \ + (l)->b[9] = *t_cp++; \ + (l)->b[8] = *t_cp++; \ + (l)->b[7] = *t_cp++; \ + (l)->b[6] = *t_cp++; \ + (l)->b[5] = *t_cp++; \ + (l)->b[4] = *t_cp++; \ + (l)->b[3] = *t_cp++; \ + (l)->b[2] = *t_cp++; \ + (l)->b[1] = *t_cp++; \ + (l)->b[0] = *t_cp++; \ + (cp) += 16; \ +} while (/* CONSTCOND */0) + +#define SDP_GET_UUID128(l, cp) do { \ + memcpy(&((l)->b), (cp), 16); \ + (cp) += 16; \ +} while (/* CONSTCOND */0) +#elif BYTE_ORDER == BIG_ENDIAN +#define SDP_GET128(l, cp) do { \ + memcpy(&((l)->b), (cp), 16); \ + (cp) += 16; \ +} while (/* CONSTCOND */0) + +#define SDP_GET_UUID128(l, cp) SDP_GET128(l, cp) +#else +#error "Unsupported BYTE_ORDER" +#endif /* BYTE_ORDER */ + +#define SDP_PUT8(b, cp) do { \ + *(uint8_t *)(cp) = (b); \ + (cp) += sizeof(uint8_t); \ +} while (/* CONSTCOND */0) + +#define SDP_PUT16(s, cp) do { \ + be16enc((cp), (s)); \ + (cp) += sizeof(uint16_t); \ +} while (/* CONSTCOND */0) + +#define SDP_PUT32(s, cp) do { \ + be32enc((cp), (s)); \ + (cp) += sizeof(uint32_t); \ +} while (/* CONSTCOND */0) + +#define SDP_PUT64(s, cp) do { \ + be64enc((cp), (s)); \ + (cp) += sizeof(uint64_t); \ +} while (/* CONSTCOND */0) + +#if BYTE_ORDER == LITTLE_ENDIAN +#define SDP_PUT128(l, cp) do { \ + register const uint8_t *t_cp = (const uint8_t *)(cp); \ + *t_cp++ = (l)->b[15]; \ + *t_cp++ = (l)->b[14]; \ + *t_cp++ = (l)->b[13]; \ + *t_cp++ = (l)->b[12]; \ + *t_cp++ = (l)->b[11]; \ + *t_cp++ = (l)->b[10]; \ + *t_cp++ = (l)->b[9]; \ + *t_cp++ = (l)->b[8]; \ + *t_cp++ = (l)->b[7]; \ + *t_cp++ = (l)->b[6]; \ + *t_cp++ = (l)->b[5]; \ + *t_cp++ = (l)->b[4]; \ + *t_cp++ = (l)->b[3]; \ + *t_cp++ = (l)->b[2]; \ + *t_cp++ = (l)->b[1]; \ + *t_cp = (l)->b[0]; \ + (cp) += 16; \ +} while (/* CONSTCOND */0) + +#define SDP_PUT_UUID128(l, cp) do { \ + memcpy((cp), &((l)->b), 16); \ + (cp) += 16; \ +} while (/* CONSTCOND */0) +#elif BYTE_ORDER == BIG_ENDIAN +#define SDP_PUT128(l, cp) do { \ + memcpy((cp), &((l)->b), 16); \ + (cp) += 16; \ +} while (/* CONSTCOND */0) + +#define SDP_PUT_UUID128(l, cp) SDP_PUT128(l, cp) +#else +#error "Unsupported BYTE_ORDER" +#endif /* BYTE_ORDER */ + +struct sdp_dun_profile +{ + uint8_t server_channel; + uint8_t audio_feedback_support; + uint8_t reserved[2]; +}; +typedef struct sdp_dun_profile sdp_dun_profile_t; +typedef struct sdp_dun_profile * sdp_dun_profile_p; + +struct sdp_ftrn_profile +{ + uint8_t server_channel; + uint8_t reserved[3]; +}; +typedef struct sdp_ftrn_profile sdp_ftrn_profile_t; +typedef struct sdp_ftrn_profile * sdp_ftrn_profile_p; + +struct sdp_hset_profile +{ + uint8_t server_channel; + uint8_t reserved[3]; +}; +typedef struct sdp_hset_profile sdp_hset_profile_t; +typedef struct sdp_hset_profile * sdp_hset_profile_p; + +struct sdp_hf_profile +{ + uint8_t server_channel; + uint16_t supported_features; +}; +typedef struct sdp_hf_profile sdp_hf_profile_t; +typedef struct sdp_hf_profile * sdp_hf_profile_p; + +/* Keep this in sync with sdp_opush_profile */ +struct sdp_irmc_profile +{ + uint8_t server_channel; + uint8_t supported_formats_size; + uint8_t supported_formats[30]; +}; +typedef struct sdp_irmc_profile sdp_irmc_profile_t; +typedef struct sdp_irmc_profile * sdp_irmc_profile_p; + +struct sdp_irmc_command_profile +{ + uint8_t server_channel; + uint8_t reserved[3]; +}; +typedef struct sdp_irmc_command_profile sdp_irmc_command_profile_t; +typedef struct sdp_irmc_command_profile * sdp_irmc_command_profile_p; + +struct sdp_lan_profile +{ + uint8_t server_channel; + uint8_t load_factor; + uint8_t reserved; + uint8_t ip_subnet_radius; + uint32_t ip_subnet; +}; +typedef struct sdp_lan_profile sdp_lan_profile_t; +typedef struct sdp_lan_profile * sdp_lan_profile_p; + +/* Keep this in sync with sdp_irmc_profile */ +struct sdp_opush_profile +{ + uint8_t server_channel; + uint8_t supported_formats_size; + uint8_t supported_formats[30]; +}; +typedef struct sdp_opush_profile sdp_opush_profile_t; +typedef struct sdp_opush_profile * sdp_opush_profile_p; + +struct sdp_sp_profile +{ + uint8_t server_channel; + uint8_t reserved[3]; +}; +typedef struct sdp_sp_profile sdp_sp_profile_t; +typedef struct sdp_sp_profile * sdp_sp_profile_p; + +struct sdp_nap_profile +{ + uint8_t reserved; + uint8_t load_factor; + uint16_t psm; + uint16_t security_description; + uint16_t net_access_type; + uint32_t max_net_access_rate; +}; +typedef struct sdp_nap_profile sdp_nap_profile_t; +typedef struct sdp_nap_profile * sdp_nap_profile_p; + +struct sdp_gn_profile +{ + uint8_t reserved; + uint8_t load_factor; + uint16_t psm; + uint16_t security_description; + uint16_t reserved2; + uint32_t reserved3; +}; +typedef struct sdp_gn_profile sdp_gn_profile_t; +typedef struct sdp_gn_profile * sdp_gn_profile_p; + +struct sdp_panu_profile +{ + uint8_t reserved; + uint8_t load_factor; + uint16_t psm; + uint16_t security_description; + uint16_t reserved2; + uint32_t reserved3; +}; +typedef struct sdp_panu_profile sdp_panu_profile_t; +typedef struct sdp_panu_profile * sdp_panu_profile_p; + +#endif /* SDP_COMPAT */ + +#endif /* _SDP_H_ */ diff --git a/lib/libbluetooth/sdp_compat.c b/lib/libbluetooth/sdp_compat.c new file mode 100644 index 00000000000..a618086e013 --- /dev/null +++ b/lib/libbluetooth/sdp_compat.c @@ -0,0 +1,611 @@ +/* $NetBSD: sdp_compat.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Iain Hibbert for Itronix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/*- + * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file provides compatibility with the original library API, + * use -DSDP_COMPAT to access it. + * + * These functions are deprecated and will be removed eventually. + * + * sdp_open(laddr, raddr) + * sdp_open_local(control) + * sdp_close(session) + * sdp_error(session) + * sdp_search(session, plen, protos, alen, attrs, vlen, values) + * sdp_register_service(session, uuid, bdaddr, data, datalen, handle) + * sdp_change_service(session, handle, data, datalen) + * sdp_unregister_service(session, handle) + * sdp_attr2desc(attribute) + * sdp_uuid2desc(uuid16) + * sdp_print(level, start, end) + */ +#define SDP_COMPAT + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_compat.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <errno.h> +#include <sdp.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "sdp-int.h" + +struct sdp_compat { + sdp_session_t ss; + int error; + uint8_t buf[256]; +}; + +void * +sdp_open(bdaddr_t const *l, bdaddr_t const *r) +{ + struct sdp_compat *sc; + + sc = malloc(sizeof(struct sdp_compat)); + if (sc == NULL) + return NULL; + + if (l == NULL || r == NULL) { + sc->error = EINVAL; + return sc; + } + + sc->ss = _sdp_open(l, r); + if (sc->ss == NULL) { + sc->error = errno; + return sc; + } + + sc->error = 0; + return sc; +} + +void * +sdp_open_local(char const *control) +{ + struct sdp_compat *sc; + + sc = malloc(sizeof(struct sdp_compat)); + if (sc == NULL) + return NULL; + + sc->ss = _sdp_open_local(control); + if (sc->ss == NULL) { + sc->error = errno; + return sc; + } + + sc->error = 0; + return sc; +} + +int32_t +sdp_close(void *xss) +{ + struct sdp_compat *sc = xss; + + if (sc == NULL) + return 0; + + if (sc->ss != NULL) + _sdp_close(sc->ss); + + free(sc); + + return 0; +} + +int32_t +sdp_error(void *xss) +{ + struct sdp_compat *sc = xss; + + if (sc == NULL) + return EINVAL; + + return sc->error; +} + +int32_t +sdp_search(void *xss, uint32_t plen, uint16_t const *pp, uint32_t alen, + uint32_t const *ap, uint32_t vlen, sdp_attr_t *vp) +{ + struct sdp_compat *sc = xss; + sdp_data_t seq, ssp, ail, rsp, value; + uint16_t attr; + int i; + bool rv; + + if (sc == NULL) + return -1; + + if (plen == 0 || pp == NULL || alen == 0 || ap == NULL) { + sc->error = EINVAL; + return -1; + } + + /* + * encode ServiceSearchPattern + */ + ssp.next = sc->buf; + ssp.end = sc->buf + sizeof(sc->buf); + for (i = 0; i < plen; i++) + sdp_put_uuid16(&ssp, pp[i]); + + ssp.end = ssp.next; + ssp.next = sc->buf; + + /* + * encode AttributeIDList + */ + ail.next = ssp.end; + ail.end = sc->buf + sizeof(sc->buf); + for (i = 0; i < alen; i++) + sdp_put_uint32(&ail, ap[i]); + + ail.end = ail.next; + ail.next = ssp.end; + + /* + * perform ServiceSearchAttribute transaction + */ + rv = sdp_service_search_attribute(sc->ss, &ssp, &ail, &rsp); + if (rv == false) { + sc->error = errno; + return -1; + } + + if (vp == NULL) + return 0; + + /* + * The response buffer is a list of data element sequences, + * each containing a list of attribute/value pairs. We want to + * parse those to the attribute array that the user passed in. + */ + while (vlen > 0 && sdp_get_seq(&rsp, &seq)) { + while (vlen > 0 && sdp_get_attr(&seq, &attr, &value)) { + vp->attr = attr; + if (vp->value != NULL) { + if (value.end - value.next > vp->vlen) { + vp->flags = SDP_ATTR_TRUNCATED; + } else { + vp->flags = SDP_ATTR_OK; + vp->vlen = value.end - value.next; + } + memcpy(vp->value, value.next, vp->vlen); + } else { + vp->flags = SDP_ATTR_INVALID; + } + + vp++; + vlen--; + } + } + + while (vlen-- > 0) + vp++->flags = SDP_ATTR_INVALID; + + return 0; +} + +int32_t +sdp_register_service(void *xss, uint16_t uuid, bdaddr_t *bdaddr, + uint8_t *data, uint32_t datalen, uint32_t *handle) +{ + struct sdp_compat *sc = xss; + struct iovec req[4]; + ssize_t len; + + if (sc == NULL) + return -1; + + if (bdaddr == NULL || data == NULL || datalen == 0) { + sc->error = EINVAL; + return -1; + } + + uuid = htobe16(uuid); + req[1].iov_base = &uuid; + req[1].iov_len = sizeof(uint16_t); + + req[2].iov_base = bdaddr; + req[2].iov_len = sizeof(bdaddr_t); + + req[3].iov_base = data; + req[3].iov_len = datalen; + + if (!_sdp_send_pdu(sc->ss, SDP_PDU_SERVICE_REGISTER_REQUEST, + req, __arraycount(req))) { + sc->error = errno; + return -1; + } + + len = _sdp_recv_pdu(sc->ss, SDP_PDU_ERROR_RESPONSE); + if (len == -1) { + sc->error = errno; + return -1; + } + + if (len != sizeof(uint16_t) + sizeof(uint32_t) + || be16dec(sc->ss->ibuf) != 0) { + sc->error = EIO; + return -1; + } + + if (handle != NULL) + *handle = be32dec(sc->ss->ibuf + sizeof(uint16_t)); + + return 0; +} + +int32_t +sdp_change_service(void *xss, uint32_t handle, + uint8_t *data, uint32_t datalen) +{ + struct sdp_compat *sc = xss; + struct iovec req[3]; + ssize_t len; + + if (data == NULL || datalen == 0) { + sc->error = EINVAL; + return -1; + } + + handle = htobe32(handle); + req[1].iov_base = &handle; + req[1].iov_len = sizeof(uint32_t); + + req[2].iov_base = data; + req[2].iov_len = datalen; + + if (!_sdp_send_pdu(sc->ss, SDP_PDU_SERVICE_CHANGE_REQUEST, + req, __arraycount(req))) { + sc->error = errno; + return -1; + } + + len = _sdp_recv_pdu(sc->ss, SDP_PDU_ERROR_RESPONSE); + if (len == -1) { + sc->error = errno; + return -1; + } + + if (len != sizeof(uint16_t) + || be16dec(sc->ss->ibuf) != 0) { + sc->error = EIO; + return -1; + } + + return 0; +} + +int32_t +sdp_unregister_service(void *xss, uint32_t handle) +{ + struct sdp_compat *sc = xss; + struct iovec req[2]; + ssize_t len; + + handle = htobe32(handle); + req[1].iov_base = &handle; + req[1].iov_len = sizeof(uint32_t); + + if (!_sdp_send_pdu(sc->ss, SDP_PDU_SERVICE_UNREGISTER_REQUEST, + req, __arraycount(req))) { + sc->error = errno; + return -1; + } + + len = _sdp_recv_pdu(sc->ss, SDP_PDU_ERROR_RESPONSE); + if (len == -1) { + sc->error = errno; + return -1; + } + + if (len != sizeof(uint16_t) + || be16dec(sc->ss->ibuf) != 0) { + sc->error = EIO; + return -1; + } + + return 0; +} + +/* + * SDP attribute description + */ + +struct sdp_attr_desc { + uint32_t attr; + char const *desc; +}; +typedef struct sdp_attr_desc sdp_attr_desc_t; +typedef struct sdp_attr_desc * sdp_attr_desc_p; + +static sdp_attr_desc_t sdp_uuids_desc[] = { +{ SDP_UUID_PROTOCOL_SDP, "SDP", }, +{ SDP_UUID_PROTOCOL_UDP, "UDP", }, +{ SDP_UUID_PROTOCOL_RFCOMM, "RFCOMM", }, +{ SDP_UUID_PROTOCOL_TCP, "TCP", }, +{ SDP_UUID_PROTOCOL_TCS_BIN, "TCS BIN", }, +{ SDP_UUID_PROTOCOL_TCS_AT, "TCS AT", }, +{ SDP_UUID_PROTOCOL_OBEX, "OBEX", }, +{ SDP_UUID_PROTOCOL_IP, "IP", }, +{ SDP_UUID_PROTOCOL_FTP, "FTP", }, +{ SDP_UUID_PROTOCOL_HTTP, "HTTP", }, +{ SDP_UUID_PROTOCOL_WSP, "WSP", }, +{ SDP_UUID_PROTOCOL_BNEP, "BNEP", }, +{ SDP_UUID_PROTOCOL_UPNP, "UPNP", }, +{ SDP_UUID_PROTOCOL_HIDP, "HIDP", }, +{ SDP_UUID_PROTOCOL_HARDCOPY_CONTROL_CHANNEL, "Hardcopy Control Channel", }, +{ SDP_UUID_PROTOCOL_HARDCOPY_DATA_CHANNEL, "Hardcopy Data Channel", }, +{ SDP_UUID_PROTOCOL_HARDCOPY_NOTIFICATION, "Hardcopy Notification", }, +{ SDP_UUID_PROTOCOL_AVCTP, "AVCTP", }, +{ SDP_UUID_PROTOCOL_AVDTP, "AVDTP", }, +{ SDP_UUID_PROTOCOL_CMPT, "CMPT", }, +{ SDP_UUID_PROTOCOL_UDI_C_PLANE, "UDI C-Plane", }, +{ SDP_UUID_PROTOCOL_L2CAP, "L2CAP", }, +/* Service Class IDs/Bluetooth Profile IDs */ +{ SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER, "Service Discovery Server", }, +{ SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR, "Browse Group Descriptor", }, +{ SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, "Public Browse Group", }, +{ SDP_SERVICE_CLASS_SERIAL_PORT, "Serial Port", }, +{ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP, "LAN Access Using PPP", }, +{ SDP_SERVICE_CLASS_DIALUP_NETWORKING, "Dial-Up Networking", }, +{ SDP_SERVICE_CLASS_IR_MC_SYNC, "IrMC Sync", }, +{ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH, "OBEX Object Push", }, +{ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER, "OBEX File Transfer", }, +{ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND, "IrMC Sync Command", }, +{ SDP_SERVICE_CLASS_HEADSET, "Headset", }, +{ SDP_SERVICE_CLASS_CORDLESS_TELEPHONY, "Cordless Telephony", }, +{ SDP_SERVICE_CLASS_AUDIO_SOURCE, "Audio Source", }, +{ SDP_SERVICE_CLASS_AUDIO_SINK, "Audio Sink", }, +{ SDP_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET, "A/V Remote Control Target", }, +{ SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION, "Advanced Audio Distribution", }, +{ SDP_SERVICE_CLASS_AV_REMOTE_CONTROL, "A/V Remote Control", }, +{ SDP_SERVICE_CLASS_VIDEO_CONFERENCING, "Video Conferencing", }, +{ SDP_SERVICE_CLASS_INTERCOM, "Intercom", }, +{ SDP_SERVICE_CLASS_FAX, "Fax", }, +{ SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY, "Headset Audio Gateway", }, +{ SDP_SERVICE_CLASS_WAP, "WAP", }, +{ SDP_SERVICE_CLASS_WAP_CLIENT, "WAP Client", }, +{ SDP_SERVICE_CLASS_PANU, "PANU", }, +{ SDP_SERVICE_CLASS_NAP, "Network Access Point", }, +{ SDP_SERVICE_CLASS_GN, "GN", }, +{ SDP_SERVICE_CLASS_DIRECT_PRINTING, "Direct Printing", }, +{ SDP_SERVICE_CLASS_REFERENCE_PRINTING, "Reference Printing", }, +{ SDP_SERVICE_CLASS_IMAGING, "Imaging", }, +{ SDP_SERVICE_CLASS_IMAGING_RESPONDER, "Imaging Responder", }, +{ SDP_SERVICE_CLASS_IMAGING_AUTOMATIC_ARCHIVE, "Imaging Automatic Archive", }, +{ SDP_SERVICE_CLASS_IMAGING_REFERENCED_OBJECTS, "Imaging Referenced Objects", }, +{ SDP_SERVICE_CLASS_HANDSFREE, "Handsfree", }, +{ SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY, "Handsfree Audio Gateway", }, +{ SDP_SERVICE_CLASS_DIRECT_PRINTING_REFERENCE_OBJECTS, "Direct Printing Reference Objects", }, +{ SDP_SERVICE_CLASS_REFLECTED_UI, "Reflected UI", }, +{ SDP_SERVICE_CLASS_BASIC_PRINTING, "Basic Printing", }, +{ SDP_SERVICE_CLASS_PRINTING_STATUS, "Printing Status", }, +{ SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE, "Human Interface Device", }, +{ SDP_SERVICE_CLASS_HARDCOPY_CABLE_REPLACEMENT, "Hardcopy Cable Replacement", }, +{ SDP_SERVICE_CLASS_HCR_PRINT, "HCR Print", }, +{ SDP_SERVICE_CLASS_HCR_SCAN, "HCR Scan", }, +{ SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS, "Common ISDN Access", }, +{ SDP_SERVICE_CLASS_VIDEO_CONFERENCING_GW, "Video Conferencing Gateway", }, +{ SDP_SERVICE_CLASS_UDI_MT, "UDI MT", }, +{ SDP_SERVICE_CLASS_UDI_TA, "UDI TA", }, +{ SDP_SERVICE_CLASS_AUDIO_VIDEO, "Audio/Video", }, +{ SDP_SERVICE_CLASS_SIM_ACCESS, "SIM Access", }, +{ SDP_SERVICE_CLASS_PNP_INFORMATION, "PNP Information", }, +{ SDP_SERVICE_CLASS_GENERIC_NETWORKING, "Generic Networking", }, +{ SDP_SERVICE_CLASS_GENERIC_FILE_TRANSFER, "Generic File Transfer", }, +{ SDP_SERVICE_CLASS_GENERIC_AUDIO, "Generic Audio", }, +{ SDP_SERVICE_CLASS_GENERIC_TELEPHONY, "Generic Telephony", }, +{ SDP_SERVICE_CLASS_UPNP, "UPNP", }, +{ SDP_SERVICE_CLASS_UPNP_IP, "UPNP IP", }, +{ SDP_SERVICE_CLASS_ESDP_UPNP_IP_PAN, "ESDP UPNP IP PAN", }, +{ SDP_SERVICE_CLASS_ESDP_UPNP_IP_LAP, "ESDP UPNP IP LAP", }, +{ SDP_SERVICE_CLASS_ESDP_UPNP_L2CAP, "ESDP UPNP L2CAP", }, +{ 0xffff, NULL, } +}; + +static sdp_attr_desc_t sdp_attrs_desc[] = { +{ SDP_ATTR_SERVICE_RECORD_HANDLE, + "Record handle", + }, +{ SDP_ATTR_SERVICE_CLASS_ID_LIST, + "Service Class ID list", + }, +{ SDP_ATTR_SERVICE_RECORD_STATE, + "Service Record State", + }, +{ SDP_ATTR_SERVICE_ID, + "Service ID", + }, +{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, + "Protocol Descriptor List", + }, +{ SDP_ATTR_BROWSE_GROUP_LIST, + "Browse Group List", + }, +{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST, + "Language Base Attribute ID List", + }, +{ SDP_ATTR_SERVICE_INFO_TIME_TO_LIVE, + "Service Info Time-To-Live", + }, +{ SDP_ATTR_SERVICE_AVAILABILITY, + "Service Availability", + }, +{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, + "Bluetooh Profile Descriptor List", + }, +{ SDP_ATTR_DOCUMENTATION_URL, + "Documentation URL", + }, +{ SDP_ATTR_CLIENT_EXECUTABLE_URL, + "Client Executable URL", + }, +{ SDP_ATTR_ICON_URL, + "Icon URL", + }, +{ SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS, + "Additional Protocol Descriptor Lists" }, +{ SDP_ATTR_GROUP_ID, +/*SDP_ATTR_IP_SUBNET, + SDP_ATTR_VERSION_NUMBER_LIST*/ + "Group ID/IP Subnet/Version Number List", + }, +{ SDP_ATTR_SERVICE_DATABASE_STATE, + "Service Database State", + }, +{ SDP_ATTR_SERVICE_VERSION, + "Service Version", + }, +{ SDP_ATTR_EXTERNAL_NETWORK, +/*SDP_ATTR_NETWORK, + SDP_ATTR_SUPPORTED_DATA_STORES_LIST*/ + "External Network/Network/Supported Data Stores List", + }, +{ SDP_ATTR_FAX_CLASS1_SUPPORT, +/*SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL*/ + "Fax Class1 Support/Remote Audio Volume Control", + }, +{ SDP_ATTR_FAX_CLASS20_SUPPORT, +/*SDP_ATTR_SUPPORTED_FORMATS_LIST*/ + "Fax Class20 Support/Supported Formats List", + }, +{ SDP_ATTR_FAX_CLASS2_SUPPORT, + "Fax Class2 Support", + }, +{ SDP_ATTR_AUDIO_FEEDBACK_SUPPORT, + "Audio Feedback Support", + }, +{ SDP_ATTR_NETWORK_ADDRESS, + "Network Address", + }, +{ SDP_ATTR_WAP_GATEWAY, + "WAP Gateway", + }, +{ SDP_ATTR_HOME_PAGE_URL, + "Home Page URL", + }, +{ SDP_ATTR_WAP_STACK_TYPE, + "WAP Stack Type", + }, +{ SDP_ATTR_SECURITY_DESCRIPTION, + "Security Description", + }, +{ SDP_ATTR_NET_ACCESS_TYPE, + "Net Access Type", + }, +{ SDP_ATTR_MAX_NET_ACCESS_RATE, + "Max Net Access Rate", + }, +{ SDP_ATTR_IPV4_SUBNET, + "IPv4 Subnet", + }, +{ SDP_ATTR_IPV6_SUBNET, + "IPv6 Subnet", + }, +{ SDP_ATTR_SUPPORTED_CAPABALITIES, + "Supported Capabalities", + }, +{ SDP_ATTR_SUPPORTED_FEATURES, + "Supported Features", + }, +{ SDP_ATTR_SUPPORTED_FUNCTIONS, + "Supported Functions", + }, +{ SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY, + "Total Imaging Data Capacity", + }, +{ 0xffff, NULL, } +}; + +char const * +sdp_attr2desc(uint16_t attr) +{ + register sdp_attr_desc_p a = sdp_attrs_desc; + + for (; a->desc != NULL; a++) + if (attr == a->attr) + break; + + return ((a->desc != NULL)? a->desc : "Unknown"); +} + +char const * +sdp_uuid2desc(uint16_t uuid) +{ + register sdp_attr_desc_p a = sdp_uuids_desc; + + for (; a->desc != NULL; a++) + if (uuid == a->attr) + break; + + return ((a->desc != NULL)? a->desc : "Unknown"); +} + +void +sdp_print(uint32_t level, uint8_t *start, uint8_t const *end) +{ + + (void)_sdp_data_print(start, end, level); +} diff --git a/lib/libbluetooth/sdp_data.3 b/lib/libbluetooth/sdp_data.3 new file mode 100644 index 00000000000..302f114aa36 --- /dev/null +++ b/lib/libbluetooth/sdp_data.3 @@ -0,0 +1,394 @@ +.\" $NetBSD: sdp_data.3,v 1.1 2009/05/12 10:05:06 plunky Exp $ +.\" +.\" Copyright (c) 2009 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Iain Hibbert. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 7, 2009 +.Dt SDP_DATA 3 +.Os +.Sh NAME +.Nm sdp_match_uuid16 +.Nm sdp_get_data +.Nm sdp_get_attr +.Nm sdp_get_uuid +.Nm sdp_get_bool +.Nm sdp_get_seq +.Nm sdp_get_alt +.Nm sdp_get_uint +.Nm sdp_get_int +.Nm sdp_get_str +.Nm sdp_get_url +.Nm sdp_put_data +.Nm sdp_put_attr +.Nm sdp_put_uuid +.Nm sdp_put_uuid16 +.Nm sdp_put_uuid32 +.Nm sdp_put_uuid128 +.Nm sdp_put_bool +.Nm sdp_put_uint +.Nm sdp_put_uint8 +.Nm sdp_put_uint16 +.Nm sdp_put_uint32 +.Nm sdp_put_uint64 +.Nm sdp_put_int +.Nm sdp_put_int8 +.Nm sdp_put_int16 +.Nm sdp_put_int32 +.Nm sdp_put_int64 +.Nm sdp_put_seq +.Nm sdp_put_alt +.Nm sdp_put_str +.Nm sdp_put_url +.Nm sdp_set_bool +.Nm sdp_set_uint +.Nm sdp_set_int +.Nm sdp_set_seq +.Nm sdp_set_alt +.Nm sdp_data_size +.Nm sdp_data_type +.Nm sdp_data_valid +.Nm sdp_data_print +.Nd Service Discovery Protocol data manipulation routines +.Sh LIBRARY +.Lb libbluetooth +.Sh SYNOPSIS +.In sdp.h +.Vt extern const uuid_t BLUETOOTH_BASE_UUID ; +.Ft bool +.Fn sdp_match_uuid16 "sdp_data_t *data" "uint16_t uuid" +.Ft bool +.Fn sdp_get_data "sdp_data_t *data" "sdp_data_t *value" +.Ft bool +.Fn sdp_get_attr "sdp_data_t *data" "uint16_t *attr" "sdp_data_t *value" +.Ft bool +.Fn sdp_get_uuid "sdp_data_t *data" "uuid_t *uuid" +.Ft bool +.Fn sdp_get_bool "sdp_data_t *data" "bool *value" +.Ft bool +.Fn sdp_get_seq "sdp_data_t *data" "sdp_data_t *seq" +.Ft bool +.Fn sdp_get_alt "sdp_data_t *data" "sdp_data_t *alt" +.Ft bool +.Fn sdp_get_uint "sdp_data_t *data" "uintmax_t *value" +.Ft bool +.Fn sdp_get_int "sdp_data_t *data" "intmax_t *value" +.Ft bool +.Fn sdp_get_str "sdp_data_t *data" "char **str" "size_t *length" +.Ft bool +.Fn sdp_get_url "sdp_data_t *data" "char **url" "size_t *length" +.Ft bool +.Fn sdp_put_data "sdp_data_t *data" "sdp_data_t *value" +.Ft bool +.Fn sdp_put_attr "sdp_data_t *data" "uint16_t attr" "sdp_data_t *value" +.Ft bool +.Fn sdp_put_uuid "sdp_data_t *data" "const uuid_t *value" +.Ft bool +.Fn sdp_put_uuid16 "sdp_data_t *data" "uint16_t value" +.Ft bool +.Fn sdp_put_uuid32 "sdp_data_t *data" "uint32_t value" +.Ft bool +.Fn sdp_put_uuid128 "sdp_data_t *data" "const uuid_t *value" +.Ft bool +.Fn sdp_put_bool "sdp_data_t *data" "bool value" +.Ft bool +.Fn sdp_put_uint "sdp_data_t *data" "uintmax_t value" +.Ft bool +.Fn sdp_put_uint8 "sdp_data_t *data" "uint8_t value" +.Ft bool +.Fn sdp_put_uint16 "sdp_data_t *data" "uint16_t value" +.Ft bool +.Fn sdp_put_uint32 "sdp_data_t *data" "uint32_t value" +.Ft bool +.Fn sdp_put_int "sdp_data_t *data" "intmax_t value" +.Ft bool +.Fn sdp_put_int8 "sdp_data_t *data" "int8_t value" +.Ft bool +.Fn sdp_put_int16 "sdp_data_t *data" "int16_t value" +.Ft bool +.Fn sdp_put_int32 "sdp_data_t *data" "int32_t value" +.Ft bool +.Fn sdp_put_seq "sdp_data_t *data" "ssize_t length" +.Ft bool +.Fn sdp_put_alt "sdp_data_t *data" "ssize_t length" +.Ft bool +.Fn sdp_put_str "sdp_data_t *data" "const char *str" "ssize_t length" +.Ft bool +.Fn sdp_put_url "sdp_data_t *data" "const char *url" "ssize_t length" +.Ft bool +.Fn sdp_set_bool "const sdp_data_t *data" "bool value" +.Ft bool +.Fn sdp_set_uint "const sdp_data_t *data" "uintmax_t value" +.Ft bool +.Fn sdp_set_int "const sdp_data_t *data" "intmax_t value" +.Ft bool +.Fn sdp_set_seq "const sdp_data_t *data" "ssize_t length" +.Ft ssize_t +.Fn sdp_data_size "const sdp_data_t *data" +.Ft int +.Fn sdp_data_type "const sdp_data_t *data" +.Ft bool +.Fn sdp_data_valid "const sdp_data_t *data" +.Ft void +.Fn sdp_data_print "const sdp_data_t *data" "int indent" +.Sh DESCRIPTION +These routines provide for the manipulation of Service Discovery +Protocol data buffers. +An SDP data buffer type is defined as: +.Bd -literal -offset indent +typedef struct { + uint8_t *next; + uint8_t *end; +} sdp_data_t; +.Ed +.Pp +Where +.Ar next +points to the next available byte, and +.Ar end +points to the first address past end of the data area, such that +.Qq end = next + length . +.Pp +The SDP data consists of byte streams describing data elements, where +a data element is a typed data representation consisting of a header +field and a data field. +The header field consists of type and size descriptors, and the data +field is a sequence of bytes whose length is specified in the size +descriptor and whose content is specified by the type descriptor. +For instance, the byte sequence +.Qq 0x09, 0x01, 0x00 +describes an 16-bit unsigned integer element (type 0x09) with +value of 0x0100. +.Pp +Data element types including signed and unsigned integers, boolean, +string, sequence and alternative lists are defined in the +.In sdp.h +include file. +See the +.Qq Service Discovery Protocol +chapters of the +.Qq Bluetooth Core Specifications +for more information. +.Pp +To reduce the burden of storing and transferring 128-bit UUID values, a +range of UUID values has been pre-allocated for assignment to often-used, +registered purposes. The first UUID in this pre-allocated range is known +as the +.Qq Bluetooth Base UUID , +defined in the +.Qq Bluetooth Assigned Numbers +document and declared in +.In sdp.h +as +.Vt const uuid_t BLUETOOTH_BASE_UUID ; +.Pp +The data manipulation routines are arranged into major groups +by function: +.Bl -hang +.It The Fn sdp_match_uuid16 +routine examines the next data element in the data buffer for +an element of type UUID that matches the Bluetooth short alias +UUID with 16-bit value given. +If the UUID matches, the function will return +.Dv true +and the +.Ar next +field of the SDP data buffer will be advanced to the next element. +Otherwise +.Dv false +will be returned. +.It The Fn sdp_get_xxxx +routines examine the next data element in the data buffer for an +element of the given type. +If the type matches, the function will extract the typed value to +the address given and advance the +.Ar next +field of the SDP data buffer to the next element then return +.Dv true . +Otherwise +.Dv false +will be returned. +Note, these functions will not modify the +.Ar data +argument unless the correct type was found, and will update the +.Ar data +argument first to allow discarding in the case where a +.Dv sdp_data_t +was being returned. +.It The Fn sdp_put_xxxx +routines will attempt to write a data element of the given type +and value to the data buffer. +If the data buffer is too small to contain the encoded data element, +the function will return +.Dv false , +otherwise +.Dv true +will be returned and the +.Ar next +field of the SDP data pointer will be advanced. +In the case of +.Fn sdp_put_seq +and +.Fn sdp_put_alt , +the +.Ar length +argument may be -1, in which case the generated sequence header will +describe all the remaining buffer space. +For +.Fn sdp_put_str +and +.Fn sdp_put_url +the +.Ar length +argument may be -1 in which case the string pointer is treated as +nul terminated. +.It The Fn sdp_set_xxxx +routines examine the SDP data buffer for a data element of the given +type, and replace the content with the passed value. +If the next data element in the buffer is not of the appropriate +type, the function will return +.Dv false , +otherwise +.Dv true +will be returned and the value updated. +In the case of +.Fn sdp_set_seq +and +.Fn sdp_set_alt , +the +.Ar length +argument may be -1, in which case the sequence header will be +adjusted to describe the entire data space where possible. +.It The Fn sdp_data_xxxx +routines include various functions to provide information about +the data stream such as +.Fn sdp_data_size +to return the size of the next data element, and +.Fn sdp_data_type +to return the type of the next data element. +.Fn sdp_data_valid +can be used to ensure that the entire data buffer contains +valid SDP data elements and that all of the elements are contained +exactly within the data buffer. +Finally, +.Fn sdp_data_print +will print the data buffer in human readable format. +.El +.Sh EXAMPLES +To parse a ServiceAttribute response obtained from a remote server +using +.Xr sdp_service_attribute 3 , +examining various attribute values: +.Bd -literal + sdp_data_t rsp, val; + uint16_t attr; + uintmax_t handle; + + /* rsp contains remote response */ + + /* discard sequence header */ + if (!sdp_get_seq(\*[Am]rsp, \*[Am]rsp)) + err(EXIT_FAILURE, "response is not a sequence"); + + while (sdp_get_attr(\*[Am]rsp, \*[Am]attr, \*[Am]val)) { + switch(attr) { + case SDP_ATTR_SERVICE_RECORD_HANDLE: + sdp_get_uint(\*[Am]val, \*[Am]handle); + printf("ServiceRecordHandle: 0x%08x\\n", handle); + break; + + case SDP_ATTR_PROFILE_DESCRIPTOR_LIST: + printf("ProfileDescriptorList:\\n"); + sdp_data_print(\*[Am]val, 0); + break; + + default: + printf("uninteresting attribute 0x%04x\\n", attr); + break; + } + } + +.Ed +The following code creates a ProtocolDataList attribute value for a service +using the L2CAP and RFCOMM protocols and illustrates how to construct sequences +of known and unknown length. +.Bd -literal + uint8_t buf[SIZE]; + sdp_data_t seq; + uint16_t psm; + uint8_t channel; + + seq.next = buf; + seq.end = buf + sizeof(buf); + sdp_put_seq(\*[Am]seq, -1); + + sdp_put_seq(\*[Am]seq, 6); + sdp_put_uuid16(\*[Am]seq, SDP_UUID_PROTOCOL_L2CAP); + sdp_put_uint16(\*[Am]seq, psm); + + sdp_put_seq(\*[Am]seq, 5); + sdp_put_uuid16(\*[Am]seq, SDP_UUID_PROTOCOL_RFCOMM); + sdp_put_uint8(\*[Am]seq, channel); + + seq.end = seq.next; + seq.next = buf; + sdp_set_seq(\*[Am]seq, -1); +.Ed +.Pp +Note that although +.Dv SIZE +is assumed to be large enough to contain the entire sequence +in this case, the +.Fn sdp_put_xxxx +routines will not overflow the buffer area or write partial data. +.Pp +The encoded data stream will be stored in a space efficient +manner where possible. +In the above example, it is known that the data element sequence +containing the L2CAP UUID will be 8 bytes long overall since the +container length of 6 can be stored in a single byte. +But, because the value of +.Dv SIZE +is unknown, the overall length of the ProtocolDataList may vary +depending if 8, 16 or 32 bits were needed to represent the original +buffer size. +.Fn sdp_seq_seq +will only modify the content, not the size of the header. +.Pp +.Sh SEE ALSO +.Xr sdpquery 1 , +.Xr bluetooth 3 , +.Xr sdp 3 , +.Xr uuid 3 , +.Xr sdpd 8 +.Pp +The +.Qq Service Discovery Protocol +section of the Bluetooth Core specifications, available at +.Qq http://www.bluetooth.com/ +.Sh HISTORY +These SDP data parsing and manipulation functions first appeared in +.Nx 6.0 . diff --git a/lib/libbluetooth/sdp_data.c b/lib/libbluetooth/sdp_data.c new file mode 100644 index 00000000000..ae05ca0bad3 --- /dev/null +++ b/lib/libbluetooth/sdp_data.c @@ -0,0 +1,732 @@ +/* $NetBSD: sdp_data.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Iain Hibbert. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_data.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <sdp.h> +#include <stdarg.h> +#include <stdio.h> +#include <vis.h> + +#include "sdp-int.h" + + +/****************************************************************************** + * sdp_data_type(data) + * + * return SDP data element type + */ +int +sdp_data_type(const sdp_data_t *data) +{ + + if (data->next + 1 > data->end) + return -1; + + return data->next[0]; +} + + +/****************************************************************************** + * sdp_data_size(data) + * + * return the size of SDP data element. This will fail (return -1) if + * the data element does not fit into the data space. + */ +ssize_t +sdp_data_size(const sdp_data_t *data) +{ + uint8_t *p = data->next; + + if (p + 1 > data->end) + return -1; + + switch (*p++) { + case SDP_DATA_NIL: + break; + + case SDP_DATA_BOOL: + case SDP_DATA_INT8: + case SDP_DATA_UINT8: + p += 1; + break; + + case SDP_DATA_INT16: + case SDP_DATA_UINT16: + case SDP_DATA_UUID16: + p += 2; + break; + + case SDP_DATA_INT32: + case SDP_DATA_UINT32: + case SDP_DATA_UUID32: + p += 4; + break; + + case SDP_DATA_INT64: + case SDP_DATA_UINT64: + p += 8; + break; + + case SDP_DATA_INT128: + case SDP_DATA_UINT128: + case SDP_DATA_UUID128: + p += 16; + break; + + case SDP_DATA_ALT8: + case SDP_DATA_SEQ8: + case SDP_DATA_STR8: + case SDP_DATA_URL8: + if (p + 1 > data->end) + return -1; + + p += 1 + *p; + break; + + case SDP_DATA_ALT16: + case SDP_DATA_SEQ16: + case SDP_DATA_STR16: + case SDP_DATA_URL16: + if (p + 2 > data->end) + return -1; + + p += 2 + be16dec(p); + break; + + case SDP_DATA_ALT32: + case SDP_DATA_SEQ32: + case SDP_DATA_STR32: + case SDP_DATA_URL32: + if (p + 4 > data->end) + return -1; + + p += 4 + be32dec(p); + break; + + default: + return -1; + } + + if (p > data->end) + return -1; + + return (p - data->next); +} + +/****************************************************************************** + * sdp_data_valid(data) + * + * validate an SDP data element list recursively, ensuring elements do not + * expand past the claimed length and that there is no invalid data. + */ +static bool +_sdp_data_valid(uint8_t *ptr, uint8_t *end) +{ + size_t len; + + while (ptr < end) { + if (ptr + 1 > end) + return false; + + switch (*ptr++) { + case SDP_DATA_NIL: + break; + + case SDP_DATA_BOOL: + case SDP_DATA_INT8: + case SDP_DATA_UINT8: + if (ptr + 1 > end) + return false; + + ptr += 1; + break; + + case SDP_DATA_INT16: + case SDP_DATA_UINT16: + case SDP_DATA_UUID16: + if (ptr + 2 > end) + return false; + + ptr += 2; + break; + + case SDP_DATA_INT32: + case SDP_DATA_UINT32: + case SDP_DATA_UUID32: + if (ptr + 4 > end) + return false; + + ptr += 4; + break; + + case SDP_DATA_INT64: + case SDP_DATA_UINT64: + if (ptr + 8 > end) + return false; + + ptr += 8; + break; + + case SDP_DATA_INT128: + case SDP_DATA_UINT128: + case SDP_DATA_UUID128: + if (ptr + 16 > end) + return false; + + ptr += 16; + break; + + case SDP_DATA_STR8: + case SDP_DATA_URL8: + if (ptr + 1 > end) + return false; + + len = *ptr; + ptr += 1; + + if (ptr + len > end) + return false; + + ptr += len; + break; + + case SDP_DATA_STR16: + case SDP_DATA_URL16: + if (ptr + 2 > end) + return false; + + len = be16dec(ptr); + ptr += 2; + + if (ptr + len > end) + return false; + + ptr += len; + break; + + case SDP_DATA_STR32: + case SDP_DATA_URL32: + if (ptr + 4 > end) + return false; + + len = be32dec(ptr); + ptr += 4; + + if (ptr + len > end) + return false; + + ptr += len; + break; + + case SDP_DATA_SEQ8: + case SDP_DATA_ALT8: + if (ptr + 1 > end) + return false; + + len = *ptr; + ptr += 1; + + if (ptr + len > end) + return false; + + if (!_sdp_data_valid(ptr, ptr + len)) + return false; + + ptr += len; + break; + + case SDP_DATA_SEQ16: + case SDP_DATA_ALT16: + if (ptr + 2 > end) + return false; + + len = be16dec(ptr); + ptr += 2; + + if (ptr + len > end) + return false; + + if (!_sdp_data_valid(ptr, ptr + len)) + return false; + + ptr += len; + break; + + case SDP_DATA_SEQ32: + case SDP_DATA_ALT32: + if (ptr + 4 > end) + return false; + + len = be32dec(ptr); + ptr += 4; + + if (ptr + len > end) + return false; + + if (!_sdp_data_valid(ptr, ptr + len)) + return false; + + ptr += len; + break; + + default: + return false; + } + } + + return true; +} + +bool +sdp_data_valid(const sdp_data_t *data) +{ + + if (data->next == NULL || data->end == NULL) + return false; + + if (data->next >= data->end) + return false; + + return _sdp_data_valid(data->next, data->end); +} + +/****************************************************************************** + * sdp_data_print(data, indent) + * + * print out a SDP data element list in human readable format + */ +static void +_sdp_put(int indent, const char *type, const char *fmt, ...) +{ + va_list ap; + + indent = printf("%*s%s", indent, "", type); + indent = 18 - indent; + if (indent < 2) + indent = 2; + + printf("%*s", indent, ""); + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + + printf("\n"); +} + +static void +_sdp_putstr(int indent, int style, const char *type, + const uint8_t *str, size_t len) +{ + char buf[50], *dst = buf; + + indent = printf("%*s%s(%zu)", indent, "", type, len); + indent = 18 - indent; + if (indent < 2) + indent = 2; + + printf("%*s", indent, ""); + + style |= VIS_NL; + + while (len > 0 && (dst + 5) < (buf + sizeof(buf))) { + dst = vis(dst, str[0], style, (len > 0 ? str[1] : 0)); + str++; + len--; + } + + printf("\"%s%s\n", buf, (len == 0 ? "\"" : " ...")); +} + +bool +_sdp_data_print(const uint8_t *next, const uint8_t *end, int indent) +{ + size_t len; + + while (next < end) { + if (next + 1 > end) + return false; + + switch (*next++) { + case SDP_DATA_NIL: + _sdp_put(indent, "nil", ""); + break; + + case SDP_DATA_BOOL: + if (next + 1 > end) + return false; + + _sdp_put(indent, "bool", "%s", + (*next == 0x00 ? "false" : "true")); + + next += 1; + break; + + case SDP_DATA_INT8: + if (next + 1 > end) + return false; + + _sdp_put(indent, "int8", "%" PRId8, + *(const int8_t *)next); + next += 1; + break; + + case SDP_DATA_UINT8: + if (next + 1 > end) + return false; + + _sdp_put(indent, "uint8", "0x%02" PRIx8, + *next); + next += 1; + break; + + case SDP_DATA_INT16: + if (next + 2 > end) + return false; + + _sdp_put(indent, "int16", "%" PRId16, + (int16_t)be16dec(next)); + next += 2; + break; + + case SDP_DATA_UINT16: + if (next + 2 > end) + return false; + + _sdp_put(indent, "uint16", "0x%04" PRIx16, + be16dec(next)); + next += 2; + break; + + case SDP_DATA_UUID16: + if (next + 2 > end) + return false; + + _sdp_put(indent, "uuid16", "0x%04" PRIx16, + be16dec(next)); + next += 2; + break; + + case SDP_DATA_INT32: + if (next + 4 > end) + return false; + + _sdp_put(indent, "int32", "%" PRId32, + (int32_t)be32dec(next)); + next += 4; + break; + + case SDP_DATA_UINT32: + if (next + 4 > end) + return false; + + _sdp_put(indent, "uint32", "0x%08" PRIx32, + be32dec(next)); + next += 4; + break; + + case SDP_DATA_UUID32: + if (next + 4 > end) + return false; + + _sdp_put(indent, "uuid32", "0x%08" PRIx32, + be32dec(next)); + next += 4; + break; + + case SDP_DATA_INT64: + if (next + 8 > end) + return false; + + _sdp_put(indent, "int64", "%" PRId64, + (int64_t)be64dec(next)); + next += 8; + break; + + case SDP_DATA_UINT64: + if (next + 8 > end) + return false; + + _sdp_put(indent, "uint64", "0x%016" PRIx64, + be64dec(next)); + next += 8; + break; + + case SDP_DATA_INT128: + if (next + 16 > end) + return false; + + _sdp_put(indent, "int128", + "0x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x", + next[0], next[1], next[2], next[3], + next[4], next[5], next[6], next[7], + next[8], next[9], next[10], next[11], + next[12], next[13], next[14], next[15]); + next += 16; + break; + + case SDP_DATA_UINT128: + if (next + 16 > end) + return false; + + _sdp_put(indent, "uint128", + "0x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x", + next[0], next[1], next[2], next[3], + next[4], next[5], next[6], next[7], + next[8], next[9], next[10], next[11], + next[12], next[13], next[14], next[15]); + next += 16; + break; + + case SDP_DATA_UUID128: + if (next + 16 > end) + return false; + + _sdp_put(indent, "uuid128", + "%02x%02x%02x%02x-" + "%02x%02x-" + "%02x%02x-" + "%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + next[0], next[1], next[2], next[3], + next[4], next[5], + next[6], next[7], + next[8], next[9], + next[10], next[11], next[12], + next[13], next[14], next[15]); + next += 16; + break; + + case SDP_DATA_STR8: + if (next + 1 > end) + return false; + + len = *next; + next += 1; + + if (next + len > end) + return false; + + _sdp_putstr(indent, VIS_CSTYLE, "str8", next, len); + next += len; + break; + + case SDP_DATA_URL8: + if (next + 1 > end) + return false; + + len = *next; + next += 1; + + if (next + len > end) + return false; + + _sdp_putstr(indent, VIS_HTTPSTYLE, "url8", next, len); + next += len; + break; + + case SDP_DATA_STR16: + if (next + 2 > end) + return false; + + len = be16dec(next); + next += 2; + + if (next + len > end) + return false; + + _sdp_putstr(indent, VIS_CSTYLE, "str16", next, len); + next += len; + break; + + case SDP_DATA_URL16: + if (next + 2 > end) + return false; + + len = be16dec(next); + next += 2; + + if (next + len > end) + return false; + + _sdp_putstr(indent, VIS_HTTPSTYLE, "url16", next, len); + next += len; + break; + + case SDP_DATA_STR32: + if (next + 4 > end) + return false; + + len = be32dec(next); + next += 4; + + if (next + len > end) + return false; + + _sdp_putstr(indent, VIS_CSTYLE, "str32", next, len); + next += len; + break; + + case SDP_DATA_URL32: + if (next + 4 > end) + return false; + + len = be32dec(next); + next += 4; + + if (next + len > end) + return false; + + _sdp_putstr(indent, VIS_HTTPSTYLE, "url32", next, len); + next += len; + break; + + case SDP_DATA_SEQ8: + if (next + 1 > end) + return false; + + len = *next; + next += 1; + + if (next + len > end) + return false; + + printf("%*sseq8(%zu)\n", indent, "", len); + if (!_sdp_data_print(next, next + len, indent + 1)) + return false; + + next += len; + break; + + case SDP_DATA_ALT8: + if (next + 1 > end) + return false; + + len = *next; + next += 1; + + if (next + len > end) + return false; + + printf("%*salt8(%zu)\n", indent, "", len); + if (!_sdp_data_print(next, next + len, indent + 1)) + return false; + + next += len; + break; + + case SDP_DATA_SEQ16: + if (next + 2 > end) + return false; + + len = be16dec(next); + next += 2; + + if (next + len > end) + return false; + + printf("%*sseq16(%zu)\n", indent, "", len); + if (!_sdp_data_print(next, next + len, indent + 1)) + return false; + + next += len; + break; + + case SDP_DATA_ALT16: + if (next + 2 > end) + return false; + + len = be16dec(next); + next += 2; + + if (next + len > end) + return false; + + printf("%*salt16(%zu)\n", indent, "", len); + if (!_sdp_data_print(next, next + len, indent + 1)) + return false; + + next += len; + break; + + case SDP_DATA_SEQ32: + if (next + 4 > end) + return false; + + len = be32dec(next); + next += 4; + + if (next + len > end) + return false; + + printf("%*sseq32(%zu)\n", indent, "", len); + if (!_sdp_data_print(next, next + len, indent + 1)) + return false; + + next += len; + break; + + case SDP_DATA_ALT32: + if (next + 4 > end) + return false; + + len = be32dec(next); + next += 4; + + if (next + len > end) + return false; + + printf("%*salt32(%zu)\n", indent, "", len); + if (!_sdp_data_print(next, next + len, indent + 1)) + return false; + + next += len; + break; + + default: + return false; + } + } + + return true; +} + +void +sdp_data_print(const sdp_data_t *data, int indent) +{ + + if (!_sdp_data_print(data->next, data->end, indent)) + printf("SDP data error\n"); +} diff --git a/lib/libbluetooth/sdp_get.c b/lib/libbluetooth/sdp_get.c new file mode 100644 index 00000000000..3dcc9a16b5a --- /dev/null +++ b/lib/libbluetooth/sdp_get.c @@ -0,0 +1,377 @@ +/* $NetBSD: sdp_get.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Iain Hibbert. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_get.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <sdp.h> +#include <limits.h> + +/****************************************************************************** + * sdp_get_xxxx(data, value) + * + * examine first SDP data element in list for xxx type, extracting to given + * storage and advancing pointer if found. + * - these functions will not modify data pointer unless the value was + * extracted successfully + * - these functions always update the data pointer before the value pointer, + * so where the value is a sdp_data_t the data struct can be discarded. + */ + +bool +sdp_get_data(sdp_data_t *data, sdp_data_t *value) +{ + uint8_t *p = data->next; + ssize_t l = sdp_data_size(data); + + if (l == -1 + || p + l > data->end) + return false; + + data->next = p + l; + value->next = p; + value->end = p + l; + return true; +} + +bool +sdp_get_attr(sdp_data_t *data, uint16_t *attr, sdp_data_t *value) +{ + sdp_data_t v, d = *data; + uintmax_t a; + + if (sdp_data_type(&d) != SDP_DATA_UINT16 + || !sdp_get_uint(&d, &a) + || !sdp_get_data(&d, &v)) + return false; + + *attr = (uint16_t)a; + *data = d; + *value = v; + return true; +} + +bool +sdp_get_uuid(sdp_data_t *data, uuid_t *uuid) +{ + uint8_t *p = data->next; + + if (p + 1 > data->end) + return false; + + switch (*p++) { + case SDP_DATA_UUID16: + if (p + 2 > data->end) + return false; + + *uuid = BLUETOOTH_BASE_UUID; + uuid->time_low = be16dec(p); + p += 2; + break; + + case SDP_DATA_UUID32: + if (p + 4 > data->end) + return false; + + *uuid = BLUETOOTH_BASE_UUID; + uuid->time_low = be32dec(p); + p += 4; + break; + + case SDP_DATA_UUID128: + if (p + 16 > data->end) + return false; + + uuid_dec_be(p, uuid); + p += 16; + break; + + default: + return false; + } + + data->next = p; + return true; +} + +bool +sdp_get_bool(sdp_data_t *data, bool *value) +{ + uint8_t *p = data->next; + uint8_t v; + + if (p + 1 > data->end) + return false; + + switch (*p++) { + case SDP_DATA_BOOL: + if (p + 1 > data->end) + return false; + + v = *p; + p += 1; + break; + + default: + return false; + } + + data->next = p; + *value = ((v != 0) ? true : false); + return true; +} + +bool +sdp_get_uint(sdp_data_t *data, uintmax_t *value) +{ + uint8_t *p = data->next; + uint64_t v, x; + + if (p + 1 > data->end) + return false; + + switch (*p++) { + case SDP_DATA_UINT8: + if (p + 1 > data->end) + return false; + + v = *p; + p += 1; + break; + + case SDP_DATA_UINT16: + if (p + 2 > data->end) + return false; + + v = be16dec(p); + p += 2; + break; + + case SDP_DATA_UINT32: + if (p + 4 > data->end) + return false; + + v = be32dec(p); + p += 4; + break; + + case SDP_DATA_UINT64: + if (p + 8 > data->end) + return false; + + v = be64dec(p); + if (v > UINTMAX_MAX) + return false; + + p += 8; + break; + + case SDP_DATA_UINT128: + if (p + 16 > data->end) + return false; + + x = be64dec(p); + v = be64dec(p + 8); + if (x != 0 || v > UINTMAX_MAX) + return false; + + p += 16; + break; + + default: + return false; + } + + data->next = p; + *value = (uintmax_t)v; + return true; +} + +bool +sdp_get_int(sdp_data_t *data, intmax_t *value) +{ + uint8_t *p = data->next; + int64_t v, x; + + if (p + 1 > data->end) + return false; + + switch (*p++) { + case SDP_DATA_INT8: + if (p + 1 > data->end) + return false; + + v = *(int8_t *)p; + p += 1; + break; + + case SDP_DATA_INT16: + if (p + 2 > data->end) + return false; + + v = (int16_t)be16dec(p); + p += 2; + break; + + case SDP_DATA_INT32: + if (p + 4 > data->end) + return false; + + v = (int32_t)be32dec(p); + p += 4; + break; + + case SDP_DATA_INT64: + if (p + 8 > data->end) + return false; + + v = (int64_t)be64dec(p); + if (v > INTMAX_MAX || v < INTMAX_MIN) + return false; + + p += 8; + break; + + case SDP_DATA_INT128: + if (p + 16 > data->end) + return false; + + x = (int64_t)be64dec(p); + v = (int64_t)be64dec(p + 8); + if (x == 0) { + if (v > INTMAX_MAX) + return false; + } else if (x == -1) { + if (v < INTMAX_MIN) + return false; + } else { + return false; + } + + p += 16; + break; + + default: + return false; + } + + data->next = p; + *value = (intmax_t)v; + return true; +} + +static bool +_sdp_get_ext(uint8_t type, sdp_data_t *data, sdp_data_t *ext) +{ + uint8_t *p = data->next; + uint32_t l; + + if (p + 1 > data->end + || SDP_DATA_TYPE(*p) != type) + return false; + + switch (SDP_DATA_SIZE(*p++)) { + case SDP_DATA_EXT8: + if (p + 1 > data->end) + return false; + + l = *p; + p += 1; + break; + + case SDP_DATA_EXT16: + if (p + 2 > data->end) + return false; + + l = be16dec(p); + p += 2; + break; + + case SDP_DATA_EXT32: + if (p + 4 > data->end) + return false; + + l = be32dec(p); + p += 4; + break; + + default: + return false; + } + + if (p + l > data->end) + return false; + + data->next = p + l; + ext->next = p; + ext->end = p + l; + return true; +} + +bool +sdp_get_seq(sdp_data_t *data, sdp_data_t *seq) +{ + + return _sdp_get_ext(SDP_DATA_SEQ, data, seq); +} + +bool +sdp_get_alt(sdp_data_t *data, sdp_data_t *alt) +{ + + return _sdp_get_ext(SDP_DATA_ALT, data, alt); +} + +bool +sdp_get_str(sdp_data_t *data, char **str, size_t *len) +{ + sdp_data_t s; + + if (!_sdp_get_ext(SDP_DATA_STR, data, &s)) + return false; + + *str = (char *)s.next; + *len = s.end - s.next; + return true; +} + +bool +sdp_get_url(sdp_data_t *data, char **url, size_t *len) +{ + sdp_data_t u; + + if (!_sdp_get_ext(SDP_DATA_URL, data, &u)) + return false; + + *url = (char *)u.next; + *len = u.end - u.next; + return true; +} diff --git a/lib/libbluetooth/sdp_match.c b/lib/libbluetooth/sdp_match.c new file mode 100644 index 00000000000..7e7b6c4eb3b --- /dev/null +++ b/lib/libbluetooth/sdp_match.c @@ -0,0 +1,60 @@ +/* $NetBSD: sdp_match.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Iain Hibbert. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_match.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <limits.h> +#include <sdp.h> + +/****************************************************************************** + * sdp_match_xxxx(data, value) + * + * examine SDP data element. Advance pointer and return true if it + * matches the supplied type value + */ + +bool +sdp_match_uuid16(sdp_data_t *data, uint16_t uuid) +{ + sdp_data_t d = *data; + uuid_t u1, u2; + + u1 = BLUETOOTH_BASE_UUID; + u1.time_low = uuid; + + if (!sdp_get_uuid(&d, &u2) + || !uuid_equal(&u1, &u2, NULL)) + return false; + + *data = d; + return true; +} diff --git a/lib/libbluetooth/sdp_put.c b/lib/libbluetooth/sdp_put.c new file mode 100644 index 00000000000..b6e5013b6d0 --- /dev/null +++ b/lib/libbluetooth/sdp_put.c @@ -0,0 +1,375 @@ +/* $NetBSD: sdp_put.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Iain Hibbert. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_put.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <bluetooth.h> +#include <limits.h> +#include <sdp.h> +#include <string.h> + +/****************************************************************************** + * sdp_put_xxxx(data, value) + * + * write a value to data space and advance data pointers, + * fail if data space is not large enough + */ + +bool +sdp_put_data(sdp_data_t *data, sdp_data_t *value) +{ + ssize_t len; + + len = value->end - value->next; + + if (data->next + len > data->end) + return false; + + memcpy(data->next, value->next, (size_t)len); + data->next += len; + return true; +} + +bool +sdp_put_attr(sdp_data_t *data, uint16_t attr, sdp_data_t *value) +{ + sdp_data_t d = *data; + + if (!sdp_put_uint16(&d, attr) + || sdp_put_data(&d, value)) + return false; + + *data = d; + return true; +} + +bool +sdp_put_uuid(sdp_data_t *data, const uuid_t *uuid) +{ + uuid_t u = *uuid; + + u.time_low = 0; + + if (uuid_equal(&u, &BLUETOOTH_BASE_UUID, NULL) == 0) + return sdp_put_uuid128(data, uuid); + + if (uuid->time_low > UINT16_MAX) + return sdp_put_uuid32(data, (uint32_t)uuid->time_low); + + return sdp_put_uuid16(data, (uint16_t)uuid->time_low); +} + +bool +sdp_put_uuid16(sdp_data_t *data, uint16_t uuid) +{ + + if (data->next + 3 > data->end) + return false; + + data->next[0] = SDP_DATA_UUID16; + be16enc(data->next + 1, uuid); + data->next += 3; + return true; +} + +bool +sdp_put_uuid32(sdp_data_t *data, uint32_t uuid) +{ + + if (data->next + 5 > data->end) + return false; + + data->next[0] = SDP_DATA_UUID32; + be32enc(data->next + 1, uuid); + data->next += 5; + return true; +} + +bool +sdp_put_uuid128(sdp_data_t *data, const uuid_t *uuid) +{ + + if (data->next + 17 > data->end) + return false; + + data->next[0] = SDP_DATA_UUID128; + uuid_enc_be(data->next + 1, uuid); + data->next += 17; + return true; +} + +bool +sdp_put_bool(sdp_data_t *data, bool value) +{ + + if (data->next + 2 > data->end) + return false; + + data->next[0] = SDP_DATA_BOOL; + data->next[1] = (value ? 0x01 : 0x00); + data->next += 2; + return true; +} + +bool +sdp_put_uint(sdp_data_t *data, uintmax_t value) +{ + + if (value > UINT64_MAX) + return false; + + if (value > UINT32_MAX) + return sdp_put_uint64(data, (uint64_t)value); + + if (value > UINT16_MAX) + return sdp_put_uint32(data, (uint32_t)value); + + if (value > UINT8_MAX) + return sdp_put_uint16(data, (uint16_t)value); + + return sdp_put_uint8(data, (uint8_t)value); +} + +bool +sdp_put_uint8(sdp_data_t *data, uint8_t value) +{ + + if (data->next + 2 > data->end) + return false; + + data->next[0] = SDP_DATA_UINT8; + data->next[1] = value; + data->next += 2; + return true; +} + +bool +sdp_put_uint16(sdp_data_t *data, uint16_t value) +{ + + if (data->next + 3 > data->end) + return false; + + data->next[0] = SDP_DATA_UINT16; + be16enc(data->next + 1, value); + data->next += 3; + return true; +} + +bool +sdp_put_uint32(sdp_data_t *data, uint32_t value) +{ + + if (data->next + 5 > data->end) + return false; + + data->next[0] = SDP_DATA_UINT32; + be32enc(data->next + 1, value); + data->next += 5; + return true; +} + +bool +sdp_put_uint64(sdp_data_t *data, uint64_t value) +{ + + if (data->next + 9 > data->end) + return false; + + data->next[0] = SDP_DATA_UINT64; + be64enc(data->next + 1, value); + data->next += 9; + return true; +} + +bool +sdp_put_int(sdp_data_t *data, intmax_t value) +{ + + if (value > INT64_MAX || value < INT64_MIN) + return false; + + if (value > INT32_MAX || value < INT32_MIN) + return sdp_put_int64(data, (int64_t)value); + + if (value > INT16_MAX || value < INT16_MIN) + return sdp_put_int32(data, (int32_t)value); + + if (value > INT8_MAX || value < INT8_MIN) + return sdp_put_int16(data, (int16_t)value); + + return sdp_put_int8(data, (int8_t)value); +} + +bool +sdp_put_int8(sdp_data_t *data, int8_t value) +{ + + if (data->next + 2 > data->end) + return false; + + data->next[0] = SDP_DATA_INT8; + data->next[1] = (uint8_t)value; + data->next += 2; + return true; +} + +bool +sdp_put_int16(sdp_data_t *data, int16_t value) +{ + + if (data->next + 3 > data->end) + return false; + + data->next[0] = SDP_DATA_INT16; + be16enc(data->next + 1, (uint16_t)value); + data->next += 3; + return true; +} + +bool +sdp_put_int32(sdp_data_t *data, int32_t value) +{ + + if (data->next + 5 > data->end) + return false; + + data->next[0] = SDP_DATA_INT32; + be32enc(data->next + 1, (uint32_t)value); + data->next += 5; + return true; +} + +bool +sdp_put_int64(sdp_data_t *data, int64_t value) +{ + + if (data->next + 9 > data->end) + return false; + + data->next[0] = SDP_DATA_INT64; + be64enc(data->next + 1, (uint64_t)value); + data->next += 9; + return true; +} + +static bool +_sdp_put_ext(uint8_t type, sdp_data_t *data, ssize_t len) +{ + uint8_t *p = data->next; + + if (len == -1) { + if (p + 2 > data->end) + return false; + + len = data->end - p - 2; + + if (len > UINT8_MAX) + len -= 1; + + if (len > UINT16_MAX) + len -= 2; + } + + if (len > UINT32_MAX) + return false; + + if (len > UINT16_MAX) { + if (p + 5 + len > data->end) + return false; + + p[0] = type | SDP_DATA_EXT32; + be32enc(p + 1, (uint32_t)len); + p += 5; + } else if (len > UINT8_MAX) { + if (p + 3 + len > data->end) + return false; + + p[0] = type | SDP_DATA_EXT16; + be16enc(p + 1, (uint16_t)len); + p += 3; + } else { + if (p + 2 + len > data->end) + return false; + + p[0] = type | SDP_DATA_EXT8; + p[1] = (uint8_t)len; + p += 2; + } + + data->next = p; + return true; +} + +bool +sdp_put_seq(sdp_data_t *data, ssize_t len) +{ + + return _sdp_put_ext(SDP_DATA_SEQ, data, len); +} + +bool +sdp_put_alt(sdp_data_t *data, ssize_t len) +{ + + return _sdp_put_ext(SDP_DATA_ALT, data, len); +} + +bool +sdp_put_str(sdp_data_t *data, const char *str, ssize_t len) +{ + + if (len == -1) + len = strlen(str); + + if (!_sdp_put_ext(SDP_DATA_STR, data, len)) + return false; + + memcpy(data->next, str, len); + data->next += len; + return true; +} + +bool +sdp_put_url(sdp_data_t *data, const char *url, ssize_t len) +{ + + if (len == -1) + len = strlen(url); + + if (!_sdp_put_ext(SDP_DATA_URL, data, len)) + return false; + + memcpy(data->next, url, len); + data->next += len; + return true; +} diff --git a/lib/libbluetooth/sdp_record.c b/lib/libbluetooth/sdp_record.c new file mode 100644 index 00000000000..0f3f59f8d59 --- /dev/null +++ b/lib/libbluetooth/sdp_record.c @@ -0,0 +1,220 @@ +/* $NetBSD: sdp_record.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Iain Hibbert. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_record.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <errno.h> +#include <sdp.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "sdp-int.h" + +/* + * This is the interface to sdpd(8); These PDU IDs are NOT part + * of the Bluetooth specification. + */ + +bool +sdp_record_insert(struct sdp_session *ss, bdaddr_t *bdaddr, + uint32_t *handle, const sdp_data_t *rec) +{ + struct iovec req[4]; + sdp_data_t hdr; + uint8_t data[5]; + ssize_t len; + bdaddr_t ba; + uint16_t ec; + + /* + * setup BluetoothDeviceAddress + */ + bdaddr_copy(&ba, (bdaddr == NULL) ? BDADDR_ANY : bdaddr); + req[1].iov_base = &ba; + req[1].iov_len = sizeof(bdaddr_t); + + /* + * setup ServiceRecord + */ + len = rec->end - rec->next; + if (len < 0 || len > UINT16_MAX) { + errno = EINVAL; + return false; + } + + hdr.next = data; + hdr.end = data + sizeof(data) + len; + sdp_put_seq(&hdr, len); + req[2].iov_base = data; + req[2].iov_len = hdr.next - data; + + req[3].iov_base = rec->next; + req[3].iov_len = len; + + /* + * InsertRecord Transaction + */ + if (!_sdp_send_pdu(ss, SDP_PDU_RECORD_INSERT_REQUEST, + req, __arraycount(req))) + return false; + + len = _sdp_recv_pdu(ss, SDP_PDU_ERROR_RESPONSE); + if (len == -1) + return false; + + if (len != sizeof(uint16_t) + sizeof(uint32_t)) { + errno = EIO; + return false; + } + + /* + * extract and check ErrorCode (success == 0) + */ + ec = be16dec(ss->ibuf); + if (ec != 0) { + errno = _sdp_errno(ec); + return false; + } + + /* + * extract ServiceRecordHandle if required + */ + if (handle != NULL) + *handle = be32dec(ss->ibuf + sizeof(uint16_t)); + + return true; +} + +bool +sdp_record_update(struct sdp_session *ss, uint32_t handle, + const sdp_data_t *rec) +{ + struct iovec req[4]; + sdp_data_t hdr; + uint8_t data[5]; + ssize_t len; + uint16_t ec; + + /* + * setup ServiceRecordHandle + */ + handle = htobe32(handle); + req[1].iov_base = &handle; + req[1].iov_len = sizeof(handle); + + /* + * setup ServiceRecord + */ + len = rec->end - rec->next; + if (len < 0 || len > UINT16_MAX) { + errno = EINVAL; + return false; + } + + hdr.next = data; + hdr.end = data + sizeof(data) + len; + sdp_put_seq(&hdr, len); + req[2].iov_base = data; + req[2].iov_len = hdr.next - data; + + req[3].iov_base = rec->next; + req[3].iov_len = len; + + /* + * UpdateRecord Transaction + */ + if (!_sdp_send_pdu(ss, SDP_PDU_RECORD_UPDATE_REQUEST, + req, __arraycount(req))) + return false; + + len = _sdp_recv_pdu(ss, SDP_PDU_ERROR_RESPONSE); + if (len == -1) + return false; + + if (len != sizeof(uint16_t)) { + errno = EIO; + return false; + } + + /* + * extract and check ErrorCode (success == 0) + */ + if ((ec = be16dec(ss->ibuf)) != 0) { + errno = _sdp_errno(ec); + return false; + } + + return true; +} + +bool +sdp_record_remove(struct sdp_session *ss, uint32_t handle) +{ + struct iovec req[2]; + ssize_t len; + uint16_t ec; + + /* + * setup ServiceRecordHandle + */ + handle = htobe32(handle); + req[1].iov_base = &handle; + req[1].iov_len = sizeof(handle); + + /* + * RemoveRecord Transaction + */ + if (!_sdp_send_pdu(ss, SDP_PDU_RECORD_REMOVE_REQUEST, + req, __arraycount(req))) + return false; + + len = _sdp_recv_pdu(ss, SDP_PDU_ERROR_RESPONSE); + if (len == -1) + return false; + + if (len != sizeof(uint16_t)) { + errno = EIO; + return false; + } + + /* + * extract and check ErrorCode (success == 0) + */ + ec = be16dec(ss->ibuf); + if (ec != 0) { + errno = _sdp_errno(ec); + return false; + } + + return true; +} diff --git a/lib/libbluetooth/sdp_service.c b/lib/libbluetooth/sdp_service.c new file mode 100644 index 00000000000..cd9ab1a9d6e --- /dev/null +++ b/lib/libbluetooth/sdp_service.c @@ -0,0 +1,470 @@ +/* $NetBSD: sdp_service.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Iain Hibbert. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_service.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <errno.h> +#include <limits.h> +#include <sdp.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "sdp-int.h" + +/* + * If AttributeIDList is given as NULL, request all attributes. + */ +static uint8_t ail_default[] = { 0x0a, 0x00, 0x00, 0xff, 0xff }; + +/* + * This provides the maximum size that the response buffer will be + * allowed to grow to. + * + * Default is UINT16_MAX but it can be overridden at runtime. + */ +static size_t +sdp_response_max(void) +{ + static size_t max = UINT16_MAX; + static bool check = true; + char *env, *ep; + unsigned long v; + + while (check) { + check = false; /* only check env once */ + + env = getenv("SDP_RESPONSE_MAX"); + if (env == NULL) + break; + + errno = 0; + v = strtoul(env, &ep, 0); + if (env[0] == '\0' || *ep != '\0') + break; + + if (errno == ERANGE && v == ULONG_MAX) + break; + + /* lower limit is arbitrary */ + if (v < UINT8_MAX || v > UINT32_MAX) + break; + + max = v; + } + + return max; +} + +bool +sdp_service_search(struct sdp_session *ss, const sdp_data_t *ssp, + uint32_t *id, int *num) +{ + struct iovec req[5]; + sdp_data_t hdr; + uint8_t sdata[5], max[2]; + uint8_t *ptr, *end; + ssize_t len; + uint16_t total, count, got; + + /* + * setup ServiceSearchPattern + */ + len = ssp->end - ssp->next; + if (len < 0 || len > UINT16_MAX) { + errno = EINVAL; + return false; + } + + hdr.next = sdata; + hdr.end = sdata + sizeof(sdata) + len; + sdp_put_seq(&hdr, len); + req[1].iov_base = sdata; + req[1].iov_len = hdr.next - sdata; + + req[2].iov_base = ssp->next; + req[2].iov_len = len; + + /* + * setup MaximumServiceRecordCount + */ + if (*num < 0 || *num > UINT16_MAX) { + errno = EINVAL; + return false; + } + be16enc(max, *num); + req[3].iov_base = max; + req[3].iov_len = sizeof(uint16_t); + + /* + * clear ContinuationState + */ + ss->cs[0] = 0; + + /* + * ServiceSearch Transaction + */ + got = 0; + for (;;) { + /* + * setup ContinuationState + */ + req[4].iov_base = ss->cs; + req[4].iov_len = ss->cs[0] + 1; + + if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_REQUEST, + req, __arraycount(req))) + return false; + + len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_RESPONSE); + if (len == -1) + return false; + + ptr = ss->ibuf; + end = ss->ibuf + len; + + /* + * extract TotalServiceRecordCount + */ + if (ptr + sizeof(uint16_t) > end) + break; + + total = be16dec(ptr); + ptr += sizeof(uint16_t); + if (total > *num) + break; + + /* + * extract CurrentServiceRecordCount + */ + if (ptr + sizeof(uint16_t) > end) + break; + + count = be16dec(ptr); + ptr += sizeof(uint16_t); + if (got + count > total) + break; + + /* + * extract ServiceRecordHandleList + */ + if (ptr + count * sizeof(uint32_t) > end) + break; + + while (count-- > 0) { + id[got++] = be32dec(ptr); + ptr += sizeof(uint32_t); + } + + /* + * extract ContinuationState + */ + if (ptr + 1 > end + || ptr[0] > 16 + || ptr + ptr[0] + 1 != end) + break; + + memcpy(ss->cs, ptr, ptr[0] + 1); + + /* + * Complete? + */ + if (ss->cs[0] == 0) { + *num = got; + return true; + } + } + + errno = EIO; + return false; +} + +bool +sdp_service_attribute(struct sdp_session *ss, uint32_t id, + const sdp_data_t *ail, sdp_data_t *rsp) +{ + struct iovec req[6]; + sdp_data_t hdr; + uint8_t adata[5], handle[4], max[2]; + uint8_t *ptr, *end, *rbuf; + ssize_t len; + size_t rlen, count; + + /* + * setup ServiceRecordHandle + */ + be32enc(handle, id); + req[1].iov_base = handle; + req[1].iov_len = sizeof(uint32_t); + + /* + * setup MaximumAttributeByteCount + */ + be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs)); + req[2].iov_base = max; + req[2].iov_len = sizeof(uint16_t); + + /* + * setup AttributeIDList + */ + len = (ail == NULL ? sizeof(ail_default) : (ail->end - ail->next)); + if (len < 0 || len > UINT16_MAX) { + errno = EINVAL; + return false; + } + + hdr.next = adata; + hdr.end = adata + sizeof(adata) + len; + sdp_put_seq(&hdr, len); + req[3].iov_base = adata; + req[3].iov_len = hdr.next - adata; + + req[4].iov_base = (ail == NULL ? ail_default : ail->next); + req[4].iov_len = len; + + /* + * clear ContinuationState + */ + ss->cs[0] = 0; + + /* + * ServiceAttribute Transaction + */ + rlen = 0; + for (;;) { + /* + * setup ContinuationState + */ + req[5].iov_base = ss->cs; + req[5].iov_len = ss->cs[0] + 1; + + if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_REQUEST, + req, __arraycount(req))) + return false; + + len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE); + if (len == -1) + return false; + + ptr = ss->ibuf; + end = ss->ibuf + len; + + /* + * extract AttributeListByteCount + */ + if (ptr + sizeof(uint16_t) > end) + break; + + count = be16dec(ptr); + ptr += sizeof(uint16_t); + if (count == 0 || ptr + count > end) + break; + + /* + * extract AttributeList + */ + if (rlen + count > sdp_response_max()) + break; + + rbuf = realloc(ss->rbuf, rlen + count); + if (rbuf == NULL) + return false; + + ss->rbuf = rbuf; + memcpy(rbuf + rlen, ptr, count); + rlen += count; + ptr += count; + + /* + * extract ContinuationState + */ + if (ptr + 1 > end + || ptr[0] > 16 + || ptr + ptr[0] + 1 != end) + break; + + memcpy(ss->cs, ptr, ptr[0] + 1); + + /* + * Complete? + */ + if (ss->cs[0] == 0) { + rsp->next = rbuf; + rsp->end = rbuf + rlen; + if (sdp_data_size(rsp) != rlen + || !sdp_data_valid(rsp) + || !sdp_get_seq(rsp, rsp)) + break; + + return true; + } + } + + errno = EIO; + return false; +} + +bool +sdp_service_search_attribute(struct sdp_session *ss, const sdp_data_t *ssp, + const sdp_data_t *ail, sdp_data_t *rsp) +{ + struct iovec req[7]; + sdp_data_t hdr; + uint8_t sdata[5], adata[5], max[2]; + uint8_t *ptr, *end, *rbuf; + ssize_t len; + size_t rlen, count; + + /* + * setup ServiceSearchPattern + */ + len = ssp->end - ssp->next; + if (len < 0 || len > UINT16_MAX) { + errno = EINVAL; + return false; + } + + hdr.next = sdata; + hdr.end = sdata + sizeof(sdata) + len; + sdp_put_seq(&hdr, len); + req[1].iov_base = sdata; + req[1].iov_len = hdr.next - sdata; + + req[2].iov_base = ssp->next; + req[2].iov_len = len; + + /* + * setup MaximumAttributeByteCount + */ + be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs)); + req[3].iov_base = max; + req[3].iov_len = sizeof(uint16_t); + + /* + * setup AttributeIDList + */ + len = (ail == NULL ? sizeof(ail_default) : (ail->end - ail->next)); + if (len < 0 || len > UINT16_MAX) { + errno = EINVAL; + return false; + } + + hdr.next = adata; + hdr.end = adata + sizeof(adata) + len; + sdp_put_seq(&hdr, len); + req[4].iov_base = adata; + req[4].iov_len = hdr.next - adata; + + req[5].iov_base = (ail == NULL ? ail_default : ail->next); + req[5].iov_len = len; + + /* + * clear ContinuationState + */ + ss->cs[0] = 0; + + /* + * ServiceSearchAttribute Transaction + */ + rlen = 0; + for (;;) { + /* + * setup ContinuationState + */ + req[6].iov_base = ss->cs; + req[6].iov_len = ss->cs[0] + 1; + + if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST, + req, __arraycount(req))) + return false; + + len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE); + if (len == -1) + return false; + + ptr = ss->ibuf; + end = ss->ibuf + len; + + /* + * extract AttributeListsByteCount + */ + if (ptr + sizeof(uint16_t) > end) + break; + + count = be16dec(ptr); + ptr += sizeof(uint16_t); + if (count == 0 || ptr + count > end) + break; + + /* + * extract AttributeLists + */ + if (rlen + count > sdp_response_max()) + break; + + rbuf = realloc(ss->rbuf, rlen + count); + if (rbuf == NULL) + return false; + + ss->rbuf = rbuf; + memcpy(rbuf + rlen, ptr, count); + rlen += count; + ptr += count; + + /* + * extract ContinuationState + */ + if (ptr + 1 > end + || ptr[0] > 16 + || ptr + ptr[0] + 1 != end) + break; + + memcpy(ss->cs, ptr, ptr[0] + 1); + + /* + * Complete? + */ + if (ss->cs[0] == 0) { + rsp->next = rbuf; + rsp->end = rbuf + rlen; + if (sdp_data_size(rsp) != rlen + || !sdp_data_valid(rsp) + || !sdp_get_seq(rsp, rsp)) + break; + + return true; + } + } + + errno = EIO; + return false; +} diff --git a/lib/libbluetooth/sdp_session.c b/lib/libbluetooth/sdp_session.c new file mode 100644 index 00000000000..e7addcd4d3d --- /dev/null +++ b/lib/libbluetooth/sdp_session.c @@ -0,0 +1,273 @@ +/* $NetBSD: sdp_session.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Iain Hibbert. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_session.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <sys/socket.h> +#include <sys/un.h> + +#include <errno.h> +#include <sdp.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "sdp-int.h" + +/* + * open session with remote Bluetooth SDP server + */ +struct sdp_session * +_sdp_open(const bdaddr_t *laddr, const bdaddr_t *raddr) +{ + struct sdp_session * ss; + struct sockaddr_bt sa; + struct linger li; + socklen_t len; + + ss = calloc(1, sizeof(struct sdp_session)); + if (ss == NULL) + goto fail; + + ss->s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (ss->s == -1) + goto fail; + + memset(&li, 0, sizeof(li)); + li.l_onoff = 1; + li.l_linger = 5; + if (setsockopt(ss->s, SOL_SOCKET, SO_LINGER, &li, sizeof(li)) == -1) + goto fail; + + if (laddr == NULL) + laddr = BDADDR_ANY; + + memset(&sa, 0, sizeof(sa)); + sa.bt_len = sizeof(sa); + sa.bt_family = AF_BLUETOOTH; + bdaddr_copy(&sa.bt_bdaddr, laddr); + if (bind(ss->s, (struct sockaddr *)&sa, sizeof(sa)) == -1) + goto fail; + + sa.bt_psm = L2CAP_PSM_SDP; + bdaddr_copy(&sa.bt_bdaddr, raddr); + if (connect(ss->s, (struct sockaddr *)&sa, sizeof(sa)) == -1) + goto fail; + + len = sizeof(ss->imtu); + if (getsockopt(ss->s, BTPROTO_L2CAP, SO_L2CAP_IMTU, &ss->imtu, &len) == -1) + goto fail; + + ss->ibuf = malloc(ss->imtu); + if (ss->ibuf == NULL) + goto fail; + + return ss; + +fail: + _sdp_close(ss); + return NULL; +} + +/* + * open session with local SDP server + */ +struct sdp_session * +_sdp_open_local(const char *control) +{ + struct sdp_session * ss; + struct sockaddr_un sa; + + ss = calloc(1, sizeof(struct sdp_session)); + if (ss == NULL) + goto fail; + + ss->s = socket(PF_LOCAL, SOCK_STREAM, 0); + if (ss->s == -1) + goto fail; + + if (control == NULL) + control = SDP_LOCAL_PATH; + + memset(&sa, 0, sizeof(sa)); + sa.sun_len = sizeof(sa); + sa.sun_family = AF_LOCAL; + strlcpy(sa.sun_path, control, sizeof(sa.sun_path)); + if (connect(ss->s, (struct sockaddr *)&sa, sizeof(sa)) == -1) + goto fail; + + ss->imtu = L2CAP_MTU_DEFAULT; + + ss->ibuf = malloc(ss->imtu); + if (ss->ibuf == NULL) + goto fail; + + return ss; + +fail: + _sdp_close(ss); + return NULL; +} + +/* + * close session and release all resources + */ +void +_sdp_close(struct sdp_session *ss) +{ + + if (ss == NULL) + return; + + if (ss->s != -1) + close(ss->s); + + if (ss->ibuf != NULL) + free(ss->ibuf); + + if (ss->rbuf != NULL) + free(ss->rbuf); + + free(ss); +} + +/* + * internal function; send a PDU on session + * + * caller provides an iovec array with an empty slot at the beginning for + * PDU header, num is total iovec count. + */ +bool +_sdp_send_pdu(struct sdp_session *ss, uint8_t pid, struct iovec *iov, int num) +{ + sdp_pdu_t pdu; + ssize_t len, nw; + int i; + + for (len = 0, i = 1; i < num; i++) + len += iov[i].iov_len; + + if (len > UINT16_MAX) { + errno = EMSGSIZE; + return false; + } + + ss->tid += 1; + + pdu.pid = pid; + pdu.tid = htobe16(ss->tid); + pdu.len = htobe16(len); + + iov[0].iov_base = &pdu; + iov[0].iov_len = sizeof(pdu); + + do { + nw = writev(ss->s, iov, num); + } while (nw == -1 && errno == EINTR); + + if (nw != sizeof(pdu) + len) { + errno = EIO; + return false; + } + + return true; +} + +/* + * internal function; receive a PDU on session + * + * validate the PDU and transaction IDs and data length, stores + * received data in the session incoming buffer. + */ +ssize_t +_sdp_recv_pdu(struct sdp_session *ss, uint8_t pid) +{ + struct iovec iov[2]; + sdp_pdu_t pdu; + ssize_t nr; + + iov[0].iov_base = &pdu; + iov[0].iov_len = sizeof(pdu); + + iov[1].iov_base = ss->ibuf; + iov[1].iov_len = ss->imtu; + + do { + nr = readv(ss->s, iov, __arraycount(iov)); + } while (nr == -1 && errno == EINTR); + + if (nr == -1) + return -1; + + if (nr < sizeof(pdu)) { + errno = EIO; + return -1; + } + + pdu.tid = be16toh(pdu.tid); + pdu.len = be16toh(pdu.len); + + if (pid != pdu.pid + || ss->tid != pdu.tid + || nr != sizeof(pdu) + pdu.len) { + if (pdu.pid == SDP_PDU_ERROR_RESPONSE + && pdu.len == sizeof(uint16_t)) + errno = _sdp_errno(be16dec(ss->ibuf)); + else + errno = EIO; + + return -1; + } + + return pdu.len; +} + +/* + * translate ErrorCode to errno + */ +int +_sdp_errno(uint16_t ec) +{ + + switch (ec) { + case SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE: + return ENOATTR; + + case SDP_ERROR_CODE_INVALID_SDP_VERSION: + case SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX: + case SDP_ERROR_CODE_INVALID_PDU_SIZE: + case SDP_ERROR_CODE_INVALID_CONTINUATION_STATE: + case SDP_ERROR_CODE_INSUFFICIENT_RESOURCES: + default: + return EIO; + } +} diff --git a/lib/libbluetooth/sdp_set.c b/lib/libbluetooth/sdp_set.c new file mode 100644 index 00000000000..0f575b0eb19 --- /dev/null +++ b/lib/libbluetooth/sdp_set.c @@ -0,0 +1,248 @@ +/* $NetBSD: sdp_set.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Iain Hibbert. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_set.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <bluetooth.h> +#include <limits.h> +#include <sdp.h> + +/****************************************************************************** + * sdp_set_xxxx(data, value) + * + * update a value, will fail if data element is not of the correct type + */ + +bool +sdp_set_bool(const sdp_data_t *data, bool value) +{ + uint8_t *p = data->next; + + if (p + 2 > data->end + || *p != SDP_DATA_BOOL) + return false; + + *p = (value ? 0x01 : 0x00); + return true; +} + +bool +sdp_set_uint(const sdp_data_t *data, uintmax_t value) +{ + uint8_t *p = data->next; + + if (p + 1 > data->end) + return false; + + switch (*p++) { + case SDP_DATA_UINT8: + if (p + 1 > data->end + || value > UINT8_MAX) + return false; + + *p = (uint8_t)value; + break; + + case SDP_DATA_UINT16: + if (p + 2 > data->end + || value > UINT16_MAX) + return false; + + be16enc(p, (uint16_t)value); + break; + + case SDP_DATA_UINT32: + if (p + 4 > data->end + || value > UINT32_MAX) + return false; + + be32enc(p, (uint32_t)value); + break; + + case SDP_DATA_UINT64: + if (p + 8 > data->end + || value > UINT64_MAX) + return false; + + be64enc(p, (uint64_t)value); + break; + + case SDP_DATA_UINT128: + if (p + 16 > data->end) + return false; + + be64enc(p + 0, (uint64_t)0); + be64enc(p + 8, (uint64_t)value); + break; + + default: + return false; + } + + return true; +} + +bool +sdp_set_int(const sdp_data_t *data, intmax_t value) +{ + uint8_t *p = data->next; + + if (p + 1 > data->end) + return false; + + switch (*p++) { + case SDP_DATA_INT8: + if (p + 1 > data->end + || value > INT8_MAX + || value < INT8_MIN) + return false; + + *p = (uint8_t)value; + break; + + case SDP_DATA_INT16: + if (p + 2 > data->end + || value > INT16_MAX + || value < INT16_MIN) + return false; + + be16enc(p, (uint16_t)value); + break; + + case SDP_DATA_INT32: + if (p + 4 > data->end + || value > INT32_MAX + || value < INT32_MIN) + return false; + + be32enc(p, (uint32_t)value); + break; + + case SDP_DATA_INT64: + if (p + 8 > data->end + || value > INT64_MAX + || value < INT64_MIN) + return false; + + be64enc(p, (uint64_t)value); + break; + + case SDP_DATA_INT128: + if (p + 16 > data->end) + return false; + + be64enc(p + 0, (uint64_t)0); + be64enc(p + 8, (uint64_t)value); + break; + + default: + return false; + } + + return true; +} + +static bool +_sdp_set_ext(uint8_t type, const sdp_data_t *data, ssize_t len) +{ + uint8_t *p = data->next; + + if (p + 1 > data->end + || SDP_DATA_TYPE(*p) != type) + return false; + + switch (SDP_DATA_SIZE(*p++)) { + case SDP_DATA_EXT8: + if (len == -1) { + if (p + 1 > data->end) + return false; + + len = data->end - p - 1; + } else if (p + 1 + len > data->end) + return false; + + if (len > UINT8_MAX) + return false; + + *p = (uint8_t)len; + break; + + case SDP_DATA_EXT16: + if (len == -1) { + if (p + 2 > data->end) + return false; + + len = data->end - p - 2; + } else if (p + 2 + len > data->end) + return false; + + if (len > UINT16_MAX) + return false; + + be16enc(p, (uint16_t)len); + break; + + case SDP_DATA_EXT32: + if (len == -1) { + if (p + 4 > data->end) + return false; + + len = data->end - p - 4; + } else if (p + 4 + len > data->end) + return false; + + if (len > UINT32_MAX) + return false; + + be32enc(p, (uint32_t)len); + break; + + default: + return false; + } + + return true; +} + +bool +sdp_set_seq(const sdp_data_t *data, ssize_t len) +{ + + return _sdp_set_ext(SDP_DATA_SEQ, data, len); +} + +bool +sdp_set_alt(const sdp_data_t *data, ssize_t len) +{ + + return _sdp_set_ext(SDP_DATA_ALT, data, len); +} diff --git a/lib/libbluetooth/sdp_uuid.c b/lib/libbluetooth/sdp_uuid.c new file mode 100644 index 00000000000..7fb8d6094de --- /dev/null +++ b/lib/libbluetooth/sdp_uuid.c @@ -0,0 +1,44 @@ +/* $NetBSD: sdp_uuid.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ + +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Iain Hibbert. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: sdp_uuid.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); + +#include <sdp.h> + +const uuid_t BLUETOOTH_BASE_UUID = { + 0x00000000, + 0x0000, + 0x1000, + 0x80, + 0x00, + { 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb } +}; diff --git a/lib/libbluetooth/shlib_version b/lib/libbluetooth/shlib_version index 4a1680302b3..7bcee8afb4b 100644 --- a/lib/libbluetooth/shlib_version +++ b/lib/libbluetooth/shlib_version @@ -1,5 +1,5 @@ -# $NetBSD: shlib_version,v 1.3 2009/01/11 03:07:47 christos Exp $ +# $NetBSD: shlib_version,v 1.4 2009/05/12 10:05:06 plunky Exp $ # Remember to update distrib/sets/lists/base/shl.* when changing # major=4 -minor=0 +minor=1 |
