summaryrefslogtreecommitdiff
path: root/lib/libbluetooth
diff options
context:
space:
mode:
authorplunky <plunky@NetBSD.org>2009-05-12 10:05:06 +0000
committerplunky <plunky@NetBSD.org>2009-05-12 10:05:06 +0000
commitdfbf818a22d811e97c87c95a064bcff7ee2abb4d (patch)
tree23994d7f278a62a4efcb30be6d9421e0fad40ec9 /lib/libbluetooth
parent93dfc06da921375d7d447c56760b4bf9622786f1 (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/Makefile70
-rw-r--r--lib/libbluetooth/sdp-int.h56
-rw-r--r--lib/libbluetooth/sdp.3259
-rw-r--r--lib/libbluetooth/sdp.h708
-rw-r--r--lib/libbluetooth/sdp_compat.c611
-rw-r--r--lib/libbluetooth/sdp_data.3394
-rw-r--r--lib/libbluetooth/sdp_data.c732
-rw-r--r--lib/libbluetooth/sdp_get.c377
-rw-r--r--lib/libbluetooth/sdp_match.c60
-rw-r--r--lib/libbluetooth/sdp_put.c375
-rw-r--r--lib/libbluetooth/sdp_record.c220
-rw-r--r--lib/libbluetooth/sdp_service.c470
-rw-r--r--lib/libbluetooth/sdp_session.c273
-rw-r--r--lib/libbluetooth/sdp_set.c248
-rw-r--r--lib/libbluetooth/sdp_uuid.c44
-rw-r--r--lib/libbluetooth/shlib_version4
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