Add bluetooth userspace libraries - bluetooth(3) and sdp(3).
authorHasso Tepper <hasso@dragonflybsd.org>
Thu, 3 Jan 2008 11:47:53 +0000 (11:47 +0000)
committerHasso Tepper <hasso@dragonflybsd.org>
Thu, 3 Jan 2008 11:47:53 +0000 (11:47 +0000)
Obtained-from: NetBSD

14 files changed:
lib/Makefile
lib/libbluetooth/Makefile [new file with mode: 0644]
lib/libbluetooth/bluetooth.3 [new file with mode: 0644]
lib/libbluetooth/bluetooth.c [new file with mode: 0644]
lib/libbluetooth/bluetooth.h [new file with mode: 0644]
lib/libbluetooth/devaddr.c [new file with mode: 0644]
lib/libsdp/Makefile [new file with mode: 0644]
lib/libsdp/sdp-int.h [new file with mode: 0644]
lib/libsdp/sdp.3 [new file with mode: 0644]
lib/libsdp/sdp.h [new file with mode: 0644]
lib/libsdp/search.c [new file with mode: 0644]
lib/libsdp/service.c [new file with mode: 0644]
lib/libsdp/session.c [new file with mode: 0644]
lib/libsdp/util.c [new file with mode: 0644]

index 44acdf4..cdc41db 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/4/93
 # $FreeBSD: src/lib/Makefile,v 1.107.2.16 2002/10/10 19:24:35 kbyanc Exp $
-# $DragonFly: src/lib/Makefile,v 1.31 2007/12/15 07:13:18 sephe Exp $
+# $DragonFly: src/lib/Makefile,v 1.32 2008/01/03 11:47:52 hasso Exp $
 
 # To satisfy shared library or ELF linkage when only the libraries being
 # built are visible:
 #
 # Otherwise, the SUBDIR list should be in alphabetical order.
 
-SUBDIR=        libarchive libcom_err libcrypt libm libmd \
+SUBDIR=        libarchive libbluetooth libcom_err libcrypt libm libmd \
        libncurses libradius libskey libtacplus libutil libsbuf \
        libalias libatm ${_libbind} ${_libbind9} libbz2 libc ${_libc_r} \
        libcalendar libcam libcompat libdevstat libedit libfetch \
        libftpio libipsec libipx libisc libkcore libkinfo libkvm libmagic \
        ${_libmilter} ${_libncp} libnetgraph libopie libpam \
-       libpcap libposix1e libthread_xu libpthread librpcsvc ${_libsm} \
+       libpcap libposix1e libsdp libthread_xu libpthread librpcsvc ${_libsm} \
        ${_libsmb} ${_libsmdb} ${_libsmutil} libstand libtelnet libusbhid \
        ${_libvgl} libwrap libxpg4 liby libz i18n_module pam_module \
        libc_rtld libsctp
diff --git a/lib/libbluetooth/Makefile b/lib/libbluetooth/Makefile
new file mode 100644 (file)
index 0000000..8bd4fa7
--- /dev/null
@@ -0,0 +1,36 @@
+# $NetBSD: Makefile,v 1.3 2007/05/28 12:06:18 tls Exp $
+# $DragonFly: src/lib/libbluetooth/Makefile,v 1.1 2008/01/03 11:47:52 hasso Exp $
+
+SYSDIR= ${.CURDIR}/../../sys/
+
+LIB=           bluetooth
+SHLIB_MAJOR=   3
+SRCS=          bluetooth.c devaddr.c
+MAN=           bluetooth.3
+
+CFLAGS+=       -I${.CURDIR} -I${SYSDIR}
+
+INCS=          bluetooth.h
+INCSDIR=       /usr/include
+
+MLINKS+=       bluetooth.3 bt_gethostbyname.3
+MLINKS+=       bluetooth.3 bt_gethostbyaddr.3
+MLINKS+=       bluetooth.3 bt_gethostent.3
+MLINKS+=       bluetooth.3 bt_sethostent.3
+MLINKS+=       bluetooth.3 bt_endhostent.3
+
+MLINKS+=       bluetooth.3 bt_getprotobyname.3
+MLINKS+=       bluetooth.3 bt_getprotobynumber.3
+MLINKS+=       bluetooth.3 bt_getprotoent.3
+MLINKS+=       bluetooth.3 bt_setprotoent.3
+MLINKS+=       bluetooth.3 bt_endprotoent.3
+
+MLINKS+=       bluetooth.3 bt_ntoa.3
+MLINKS+=       bluetooth.3 bt_aton.3
+
+MLINKS+=       bluetooth.3 bt_devaddr.3
+MLINKS+=       bluetooth.3 bt_devname.3
+
+CFLAGS+=       -I${.CURDIR} -I${SYSDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/libbluetooth/bluetooth.3 b/lib/libbluetooth/bluetooth.3
new file mode 100644 (file)
index 0000000..c32fb64
--- /dev/null
@@ -0,0 +1,323 @@
+.\" $NetBSD: bluetooth.3,v 1.3 2006/07/30 00:15:54 wiz Exp $
+.\" $DragonFly: src/lib/libbluetooth/bluetooth.3,v 1.1 2008/01/03 11:47:52 hasso Exp $
+.\"
+.\" Copyright (c) 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.
+.\"
+.\" $Id: bluetooth.3,v 1.3 2006/07/30 00:15:54 wiz Exp $
+.\" $FreeBSD: src/lib/libbluetooth/bluetooth.3,v 1.7 2005/01/21 10:26:11 ru Exp $
+.\"
+.Dd July 26, 2006
+.Dt BLUETOOTH 3
+.Os
+.Sh NAME
+.Nm bt_gethostbyname ,
+.Nm bt_gethostbyaddr ,
+.Nm bt_gethostent ,
+.Nm bt_sethostent ,
+.Nm bt_endhostent ,
+.Nm bt_getprotobyname ,
+.Nm bt_getprotobynumber ,
+.Nm bt_getprotoent ,
+.Nm bt_setprotoent ,
+.Nm bt_endprotoent ,
+.Nm bt_aton ,
+.Nm bt_ntoa ,
+.Nm bt_devaddr ,
+.Nm bt_devname ,
+.Nd Bluetooth routines
+.Sh LIBRARY
+.Lb libbluetooth
+.Sh SYNOPSIS
+.In bluetooth.h
+.Ft struct hostent *
+.Fn bt_gethostbyname "const char *name"
+.Ft struct hostent *
+.Fn bt_gethostbyaddr "const char *addr" "int len" "int type"
+.Ft struct hostent *
+.Fn bt_gethostent void
+.Ft void
+.Fn bt_sethostent "int stayopen"
+.Ft void
+.Fn bt_endhostent void
+.Ft struct protoent *
+.Fn bt_getprotobyname "const char *name"
+.Ft struct protoent *
+.Fn bt_getprotobynumber "int proto"
+.Ft struct protoent *
+.Fn bt_getprotoent void
+.Ft void
+.Fn bt_setprotoent "int stayopen"
+.Ft void
+.Fn bt_endprotoent void
+.Ft int
+.Fn bt_aton "const char *str" "bdaddr_t *ba"
+.Ft const char *
+.Fn bt_ntoa "const bdaddr_t *ba" "char *str"
+.Ft int
+.Fn bt_devaddr "const char *name" "bdaddr_t *addr"
+.Ft int
+.Fn bt_devname "char *name" "const bdaddr_t *addr"
+.Sh DESCRIPTION
+The
+.Fn bt_gethostent ,
+.Fn bt_gethostbyname ,
+and
+.Fn bt_gethostbyaddr
+functions each return a pointer to an object with the
+.Vt hostent
+structure describing a Bluetooth host
+referenced by name or by address, respectively.
+.Pp
+The
+.Fa name
+argument passed to
+.Fn bt_gethostbyname
+should point to a
+.Dv NUL Ns -terminated
+hostname.
+The
+.Fa addr
+argument passed to
+.Fn bt_gethostbyaddr
+should point to an address which is
+.Fa len
+bytes long,
+in binary form
+(i.e., not a Bluetooth BD_ADDR in human readable
+.Tn ASCII
+form).
+The
+.Fa type
+argument specifies the address family of this address and must be set to
+.Dv AF_BLUETOOTH .
+.Pp
+The structure returned contains the information obtained from a line in
+.Pa /etc/bluetooth/hosts
+file.
+.Pp
+The
+.Fn bt_sethostent
+function controls whether
+.Pa /etc/bluetooth/hosts
+file should stay open after each call to
+.Fn bt_gethostbyname
+or
+.Fn bt_gethostbyaddr .
+If the
+.Fa stayopen
+flag is non-zero, the file will not be closed.
+.Pp
+The
+.Fn bt_endhostent
+function closes the
+.Pa /etc/bluetooth/hosts
+file.
+.Pp
+The
+.Fn bt_getprotoent ,
+.Fn bt_getprotobyname ,
+and
+.Fn bt_getprotobynumber
+functions each return a pointer to an object with the
+.Vt protoent
+structure describing a Bluetooth Protocol Service Multiplexor referenced
+by name or number, respectively.
+.Pp
+The
+.Fa name
+argument passed to
+.Fn bt_getprotobyname
+should point to a
+.Dv NUL Ns -terminated
+Bluetooth Protocol Service Multiplexor name.
+The
+.Fa proto
+argument passed to
+.Fn bt_getprotobynumber
+should have numeric value of the desired Bluetooth Protocol Service
+Multiplexor.
+.Pp
+The structure returned contains the information obtained from a line in
+.Pa /etc/bluetooth/protocols
+file.
+.Pp
+The
+.Fn bt_setprotoent
+function controls whether
+.Pa /etc/bluetooth/protocols
+file should stay open after each call to
+.Fn bt_getprotobyname
+or
+.Fn bt_getprotobynumber .
+If the
+.Fa stayopen
+flag is non-zero, the file will not be closed.
+.Pp
+The
+.Fn bt_endprotoent
+function closes the
+.Pa /etc/bluetooth/protocols
+file.
+.Pp
+The
+.Fn bt_aton
+routine interprets the specified character string as a Bluetooth address,
+placing the address into the structure provided.
+It returns 1 if the string was successfully interpreted,
+or 0 if the string is invalid.
+.Pp
+The routine
+.Fn bt_ntoa
+takes a Bluetooth address and places an
+.Tn ASCII
+string representing the address into the buffer provided.
+It is up to the caller to ensure that provided buffer has enough space.
+If no buffer was provided then an internal static buffer will be used.
+.Pp
+The
+.Fn bt_devaddr
+function interprets the specified character string as the
+address or device name of a Bluetooth device on the local system, and
+places the device address in the structure provided, if any.
+It returns 1 if the string was successfully interpreted,
+or 0 if the string did not match any local device. The
+.Fn bt_devname
+function takes a Bluetooth device address and copies the local device
+name associated with that address into the buffer provided, if any.
+It returns 1 when the device was found, otherwise 0.
+.Sh FILES
+.Bl -tag -width ".Pa /etc/bluetooth/hosts" -compact
+.It Pa /etc/bluetooth/hosts
+.It Pa /etc/bluetooth/protocols
+.El
+.Sh EXAMPLES
+Print out the hostname associated with a specific BD_ADDR:
+.Bd -literal -offset indent
+const char *bdstr = "00:01:02:03:04:05";
+bdaddr_t bd;
+struct hostent *hp;
+
+if (!bt_aton(bdstr, \*[Am]bd))
+       errx(1, "can't parse BD_ADDR %s", bdstr);
+
+if ((hp = bt_gethostbyaddr((const char *)\*[Am]bd,
+    sizeof(bd), AF_BLUETOOTH)) == NULL)
+       errx(1, "no name associated with %s", bdstr);
+
+printf("name associated with %s is %s\en", bdstr, hp-\*[Gt]h_name);
+.Ed
+.Sh DIAGNOSTICS
+Error return status from
+.Fn bt_gethostent ,
+.Fn bt_gethostbyname ,
+and
+.Fn bt_gethostbyaddr
+is indicated by return of a
+.Dv NULL
+pointer.
+The external integer
+.Va h_errno
+may then be checked to see whether this is a temporary failure
+or an invalid or unknown host.
+The routine
+.Xr herror 3
+can be used to print an error message describing the failure.
+If its argument
+.Fa string
+is
+.Pf non- Dv NULL ,
+it is printed, followed by a colon and a space.
+The error message is printed with a trailing newline.
+.Pp
+The variable
+.Va h_errno
+can have the following values:
+.Bl -tag -width ".Dv HOST_NOT_FOUND"
+.It Dv HOST_NOT_FOUND
+No such host is known.
+.It Dv NO_RECOVERY
+Some unexpected server failure was encountered.
+This is a non-recoverable error.
+.El
+.Pp
+The
+.Fn bt_getprotoent ,
+.Fn bt_getprotobyname ,
+and
+.Fn bt_getprotobynumber
+return
+.Dv NULL
+on EOF or error.
+.Sh SEE ALSO
+.Xr gethostbyaddr 3 ,
+.Xr gethostbyname 3 ,
+.Xr getprotobyname 3 ,
+.Xr getprotobynumber 3 ,
+.Xr herror 3 ,
+.Xr inet_aton 3 ,
+.Xr inet_ntoa 3
+.Sh HISTORY
+.Nm libbluetooth
+first appeared in
+.Fx
+was ported to
+.Nx 4.0
+and extended by
+.An Iain Hibbert
+for Itronix, Inc.
+.Nm libbluetooth
+was imported into
+.Dx 1.11 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
+.An Iain Hibbert
+.Sh CAVEATS
+The
+.Fn bt_gethostent
+function reads the next line of
+.Pa /etc/bluetooth/hosts ,
+opening the file if necessary.
+.Pp
+The
+.Fn bt_sethostent
+function opens and/or rewinds the
+.Pa /etc/bluetooth/hosts
+file.
+.Pp
+The
+.Fn bt_getprotoent
+function reads the next line of
+.Pa /etc/bluetooth/protocols ,
+opening the file if necessary.
+.Pp
+The
+.Fn bt_setprotoent
+function opens and/or rewinds the
+.Pa /etc/bluetooth/protocols
+file.
+.Sh BUGS
+These functions use static data storage;
+if the data is needed for future use, it should be
+copied before any subsequent calls overwrite it.
diff --git a/lib/libbluetooth/bluetooth.c b/lib/libbluetooth/bluetooth.c
new file mode 100644 (file)
index 0000000..0177400
--- /dev/null
@@ -0,0 +1,371 @@
+/* $NetBSD: bluetooth.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
+/* $DragonFly: src/lib/libbluetooth/bluetooth.c,v 1.1 2008/01/03 11:47:52 hasso Exp $ */
+
+/*
+ * bluetooth.c
+ *
+ * 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.
+ *
+ * $Id: bluetooth.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
+ * $FreeBSD: src/lib/libbluetooth/bluetooth.c,v 1.2 2004/03/05 08:10:17 markm Exp $
+ */
+
+#include <bluetooth.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _PATH_BT_HOSTS         "/etc/bluetooth/hosts"
+#define _PATH_BT_PROTOCOLS     "/etc/bluetooth/protocols"
+#define MAXALIASES              35
+
+static FILE            *hostf = NULL;
+static int              host_stayopen = 0;
+static struct hostent   host;
+static bdaddr_t                 host_addr;
+static char            *host_addr_ptrs[2];
+static char            *host_aliases[MAXALIASES];
+
+static FILE            *protof = NULL;
+static int              proto_stayopen = 0;
+static struct protoent  proto;
+static char            *proto_aliases[MAXALIASES];
+
+static char             buf[BUFSIZ + 1];
+
+static int bt_hex_byte   (char const *str);
+static int bt_hex_nibble (char nibble);
+
+struct hostent *
+bt_gethostbyname(char const *name)
+{
+       struct hostent  *p;
+       char            **cp;
+
+       bt_sethostent(host_stayopen);
+       while ((p = bt_gethostent()) != NULL) {
+               if (strcasecmp(p->h_name, name) == 0)
+                       break;
+               for (cp = p->h_aliases; *cp != 0; cp++)
+                       if (strcasecmp(*cp, name) == 0)
+                               goto found;
+       }
+found:
+       bt_endhostent();
+
+       return (p);
+}
+
+struct hostent *
+bt_gethostbyaddr(char const *addr, socklen_t len, int type)
+{
+       struct hostent  *p;
+
+       if (type != AF_BLUETOOTH || len != sizeof(bdaddr_t)) {
+               h_errno = NO_RECOVERY;
+               return (NULL);
+       }
+
+       bt_sethostent(host_stayopen);
+       while ((p = bt_gethostent()) != NULL)
+               if (p->h_addrtype == type && memcmp(p->h_addr, addr, len) == 0)
+                       break;
+       bt_endhostent();
+
+       return (p);
+}
+
+struct hostent *
+bt_gethostent(void)
+{
+       char    *p, *cp, **q;
+
+       if (hostf == NULL)
+               hostf = fopen(_PATH_BT_HOSTS, "r");
+
+       if (hostf == NULL) {
+               h_errno = NETDB_INTERNAL;
+               return (NULL);
+       }
+again:
+       if ((p = fgets(buf, sizeof(buf), hostf)) == NULL) {
+               h_errno = HOST_NOT_FOUND;
+               return (NULL);
+       }
+       if (*p == '#')
+               goto again;
+       if ((cp = strpbrk(p, "#\n")) == NULL)
+               goto again;
+       *cp = 0;
+       if ((cp = strpbrk(p, " \t")) == NULL)
+               goto again;
+       *cp++ = 0;
+       if (bt_aton(p, &host_addr) == 0)
+               goto again;
+       host_addr_ptrs[0] = (char *) &host_addr;
+       host_addr_ptrs[1] = NULL;
+       host.h_addr_list = host_addr_ptrs;
+       host.h_length = sizeof(host_addr);
+       host.h_addrtype = AF_BLUETOOTH;
+       while (*cp == ' ' || *cp == '\t')
+               cp++;
+       host.h_name = cp;
+       q = host.h_aliases = host_aliases;
+       if ((cp = strpbrk(cp, " \t")) != NULL)
+               *cp++ = 0;
+       while (cp != NULL && *cp != 0) {
+               if (*cp == ' ' || *cp == '\t') {
+                       cp++;
+                       continue;
+               }
+               if (q < &host_aliases[MAXALIASES - 1])
+                       *q++ = cp;
+               if ((cp = strpbrk(cp, " \t")) != NULL)
+                       *cp++ = 0;
+       }
+       *q = NULL;
+       h_errno = NETDB_SUCCESS;
+
+       return (&host);
+}
+
+void
+bt_sethostent(int stayopen)
+{
+       if (hostf == NULL)
+               hostf = fopen(_PATH_BT_HOSTS, "r");
+       else
+               rewind(hostf);
+
+       host_stayopen = stayopen;
+}
+
+void
+bt_endhostent(void)
+{
+       if (hostf != NULL && host_stayopen == 0) {
+               (void) fclose(hostf);
+               hostf = NULL;
+       }
+}
+
+struct protoent *
+bt_getprotobyname(char const *name)
+{
+       struct protoent  *p;
+       char            **cp;
+
+       bt_setprotoent(proto_stayopen);
+       while ((p = bt_getprotoent()) != NULL) {
+               if (strcmp(p->p_name, name) == 0)
+                       break;
+               for (cp = p->p_aliases; *cp != 0; cp++)
+                       if (strcmp(*cp, name) == 0)
+                               goto found;
+       }
+found:
+       bt_endprotoent();
+
+       return (p);
+}
+
+struct protoent *
+bt_getprotobynumber(int num)
+{
+       struct protoent *p;
+
+       bt_setprotoent(proto_stayopen);
+       while ((p = bt_getprotoent()) != NULL)
+               if (p->p_proto == num)
+                       break;
+       bt_endprotoent();
+
+       return (p);
+}
+
+struct protoent *
+bt_getprotoent(void)
+{
+       char    *p, *cp, **q;
+
+       if (protof == NULL)
+               protof = fopen(_PATH_BT_PROTOCOLS, "r");
+
+       if (protof == NULL)
+               return (NULL);
+again:
+       if ((p = fgets(buf, sizeof(buf), protof)) == NULL)
+               return (NULL);
+       if (*p == '#')
+               goto again;
+       if ((cp = strpbrk(p, "#\n")) == NULL)
+               goto again;
+       *cp = '\0';
+       proto.p_name = p;
+       if ((cp = strpbrk(p, " \t")) == NULL)
+               goto again;
+       *cp++ = '\0';
+       while (*cp == ' ' || *cp == '\t')
+               cp++;
+       if ((p = strpbrk(cp, " \t")) != NULL)
+               *p++ = '\0';
+       proto.p_proto = (int)strtol(cp, NULL, 0);
+       q = proto.p_aliases = proto_aliases;
+       if (p != NULL) {
+               cp = p;
+               while (cp != NULL && *cp != 0) {
+                       if (*cp == ' ' || *cp == '\t') {
+                               cp++;
+                               continue;
+                       }
+                       if (q < &proto_aliases[MAXALIASES - 1])
+                               *q++ = cp;
+                       if ((cp = strpbrk(cp, " \t")) != NULL)
+                               *cp++ = '\0';
+               }
+       }
+       *q = NULL;
+
+       return (&proto);
+}
+
+void
+bt_setprotoent(int stayopen)
+{
+       if (protof == NULL)
+               protof = fopen(_PATH_BT_PROTOCOLS, "r");
+       else
+               rewind(protof);
+
+       proto_stayopen = stayopen;
+}
+
+void
+bt_endprotoent(void)
+{
+       if (protof != NULL) {
+               (void) fclose(protof);
+               protof = NULL;
+       }
+}
+
+char const *
+bt_ntoa(bdaddr_t const *ba, char *str)
+{
+       static char     buffer[24];
+
+       if (str == NULL)
+               str = buffer;
+
+       sprintf(str, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+               ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
+
+       return (str);
+}
+
+int
+bt_aton(char const *str, bdaddr_t *ba)
+{
+       int      i, b;
+       char    *end = NULL;
+
+       memset(ba, 0, sizeof(*ba));
+
+       for (i = 5, end = strchr(str, ':');
+            i > 0 && *str != '\0' && end != NULL;
+            i --, str = end + 1, end = strchr(str, ':')) {
+               switch (end - str) {
+               case 1:
+                       b = bt_hex_nibble(str[0]);
+                       break;
+
+               case 2:
+                       b = bt_hex_byte(str);
+                       break;
+
+               default:
+                       b = -1;
+                       break;
+               }
+
+               if (b < 0)
+                       return (0);
+
+               ba->b[i] = b;
+       }
+
+       if (i != 0 || end != NULL || *str == 0)
+               return (0);
+
+       switch (strlen(str)) {
+       case 1:
+               b = bt_hex_nibble(str[0]);
+               break;
+
+       case 2:
+               b = bt_hex_byte(str);
+               break;
+
+       default:
+               b = -1;
+               break;
+       }
+
+       if (b < 0)
+               return (0);
+
+       ba->b[i] = b;
+
+       return (1);
+}
+
+static int
+bt_hex_byte(char const *str)
+{
+       int     n1, n2;
+
+       if ((n1 = bt_hex_nibble(str[0])) < 0)
+               return (-1);
+
+       if ((n2 = bt_hex_nibble(str[1])) < 0)
+               return (-1);
+
+       return ((((n1 & 0x0f) << 4) | (n2 & 0x0f)) & 0xff);
+}
+
+static int
+bt_hex_nibble(char nibble)
+{
+       if ('0' <= nibble && nibble <= '9')
+               return (nibble - '0');
+
+       if ('a' <= nibble && nibble <= 'f')
+               return (nibble - 'a' + 0xa);
+
+       if ('A' <= nibble && nibble <= 'F')
+               return (nibble - 'A' + 0xa);
+
+       return (-1);
+}
diff --git a/lib/libbluetooth/bluetooth.h b/lib/libbluetooth/bluetooth.h
new file mode 100644 (file)
index 0000000..500206e
--- /dev/null
@@ -0,0 +1,115 @@
+/* $NetBSD: bluetooth.h,v 1.3 2006/09/26 19:18:19 plunky Exp $ */
+/* $DragonFly: src/lib/libbluetooth/bluetooth.h,v 1.1 2008/01/03 11:47:52 hasso Exp $ */
+
+/*
+ * bluetooth.h
+ *
+ * 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.
+ *
+ * $Id: bluetooth.h,v 1.3 2006/09/26 19:18:19 plunky Exp $
+ * $FreeBSD: src/lib/libbluetooth/bluetooth.h,v 1.2 2005/03/17 21:39:44 emax Exp $
+ */
+
+#ifndef _BLUETOOTH_H_
+#define _BLUETOOTH_H_
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netbt/bluetooth.h>
+#include <netbt/hci.h>
+#include <netbt/l2cap.h>
+#include <stdio.h>
+
+__BEGIN_DECLS
+
+/*
+ * Interface to the outside world
+ */
+
+struct hostent *  bt_gethostbyname    (char const *);
+struct hostent *  bt_gethostbyaddr    (char const *, socklen_t, int);
+struct hostent *  bt_gethostent       (void);
+void              bt_sethostent       (int);
+void              bt_endhostent       (void);
+
+struct protoent * bt_getprotobyname   (char const *);
+struct protoent * bt_getprotobynumber (int);
+struct protoent * bt_getprotoent      (void);
+void              bt_setprotoent      (int);
+void              bt_endprotoent      (void);
+
+char const *      bt_ntoa             (bdaddr_t const *, char *);
+int               bt_aton             (char const *, bdaddr_t *);
+
+int               bt_devaddr          (const char *, bdaddr_t *);
+int               bt_devname          (char *, const bdaddr_t *);
+
+/*
+ * bthcid(8) PIN Client API
+ */
+
+/* Client PIN Request packet */
+typedef struct {
+       bdaddr_t        laddr;                  /* local address */
+       bdaddr_t        raddr;                  /* remote address */
+       uint8_t         time;                   /* validity (seconds) */
+} __attribute__ ((packed)) bthcid_pin_request_t;
+
+/* Client PIN Response packet */
+typedef struct {
+       bdaddr_t        laddr;                  /* local address */
+       bdaddr_t        raddr;                  /* remote address */
+       uint8_t         pin[HCI_PIN_SIZE];      /* PIN */
+} __attribute__ ((packed)) bthcid_pin_response_t;
+
+/* Default socket name */
+#define BTHCID_SOCKET_NAME     "/var/run/bthcid"
+
+#define COMPAT_BLUEZ 
+#ifdef COMPAT_BLUEZ
+/*
+ * Linux BlueZ compatibility
+ */
+
+#define        bacmp(ba1, ba2) memcmp((ba1), (ba2), sizeof(bdaddr_t))
+#define        bacpy(dst, src) memcpy((dst), (src), sizeof(bdaddr_t))
+#define ba2str(ba, str)        bt_ntoa((ba), (str))
+#define str2ba(str, ba)        (bt_aton((str), (ba)) == 1 ? 0 : -1)
+
+#define htobs(x)       htole16(x)
+#define htobl(x)       htole32(x)
+#define btohs(x)       le16toh(x)
+#define btohl(x)       le32toh(x)
+
+#define bt_malloc(n)   malloc(n)
+#define bt_free(p)     free(p)
+
+#endif /* COMPAT_BLUEZ */
+
+__END_DECLS
+
+#endif /* ndef _BLUETOOTH_H_ */
diff --git a/lib/libbluetooth/devaddr.c b/lib/libbluetooth/devaddr.c
new file mode 100644 (file)
index 0000000..5c787d7
--- /dev/null
@@ -0,0 +1,116 @@
+/* $NetBSD: devaddr.c,v 1.2 2006/08/28 08:24:39 plunky Exp $ */
+/* $DragonFly: src/lib/libbluetooth/devaddr.c,v 1.1 2008/01/03 11:47:52 hasso 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.
+ */
+
+#include <sys/ioctl.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int
+bt_devaddr(const char *name, bdaddr_t *addr)
+{
+       struct btreq btr;
+       bdaddr_t bdaddr;
+       int s, rv;
+
+       if (name == NULL) {
+               errno = EINVAL;
+               return 0;
+       }
+
+       if (addr == NULL)
+               addr = &bdaddr;
+
+       if (bt_aton(name, addr))
+               return bt_devname(NULL, addr);
+
+       memset(&btr, 0, sizeof(btr));
+       strlcpy(btr.btr_name, name, HCI_DEVNAME_SIZE);
+
+       s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (s == -1)
+               return 0;
+
+       rv = ioctl(s, SIOCGBTINFO, &btr);
+       close(s);
+
+       if (rv == -1)
+               return 0;
+
+       if ((btr.btr_flags & BTF_UP) == 0) {
+               errno = ENXIO;
+               return 0;
+       }
+
+       bdaddr_copy(addr, &btr.btr_bdaddr);
+       return 1;
+}
+
+int
+bt_devname(char *name, const bdaddr_t *addr)
+{
+       struct btreq btr;
+       int s, rv;
+
+       if (addr == NULL) {
+               errno = EINVAL;
+               return 0;
+       }
+
+       memset(&btr, 0, sizeof(btr));
+       bdaddr_copy(&btr.btr_bdaddr, addr);
+
+       s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (s == -1)
+               return 0;
+
+       rv = ioctl(s, SIOCGBTINFOA, &btr);
+       close(s);
+
+       if (rv == -1)
+               return 0;
+
+       if ((btr.btr_flags & BTF_UP) == 0) {
+               errno = ENXIO;
+               return 0;
+       }
+
+       if (name != NULL)
+               strlcpy(name, btr.btr_name, HCI_DEVNAME_SIZE);
+
+       return 1;
+}
diff --git a/lib/libsdp/Makefile b/lib/libsdp/Makefile
new file mode 100644 (file)
index 0000000..aa5edfb
--- /dev/null
@@ -0,0 +1,38 @@
+# $NetBSD: Makefile,v 1.2 2007/05/28 12:06:21 tls Exp $
+# $FreeBSD: src/lib/libsdp/Makefile,v 1.4 2005/07/22 17:19:03 kensmith Exp $
+# $DragonFly: src/lib/libsdp/Makefile,v 1.1 2008/01/03 11:47:53 hasso Exp $
+
+SYSDIR= ${.CURDIR}/../../sys/
+
+LIB=           sdp
+SHLIB_MAJOR=   2
+MAN=           sdp.3
+
+SRCS=          search.c service.c session.c util.c
+INCS=          sdp.h
+INCSDIR=       /usr/include
+
+CFLAGS+=       -I${.CURDIR} -I${SYSDIR}
+
+MLINKS+=       sdp.3 SDP_GET8.3
+MLINKS+=       sdp.3 SDP_GET16.3
+MLINKS+=       sdp.3 SDP_GET32.3
+MLINKS+=       sdp.3 SDP_GET64.3
+MLINKS+=       sdp.3 SDP_GET128.3
+MLINKS+=       sdp.3 SDP_PUT8.3
+MLINKS+=       sdp.3 SDP_PUT16.3
+MLINKS+=       sdp.3 SDP_PUT32.3
+MLINKS+=       sdp.3 SDP_PUT64.3
+MLINKS+=       sdp.3 SDP_PUT128.3
+MLINKS+=       sdp.3 sdp_open.3
+MLINKS+=       sdp.3 sdp_open_local.3
+MLINKS+=       sdp.3 sdp_close.3
+MLINKS+=       sdp.3 sdp_error.3
+MLINKS+=       sdp.3 sdp_search.3
+MLINKS+=       sdp.3 sdp_attr2desc.3
+MLINKS+=       sdp.3 sdp_uuid2desc.3
+MLINKS+=       sdp.3 sdp_register_service.3
+MLINKS+=       sdp.3 sdp_unregister_service.3
+MLINKS+=       sdp.3 sdp_change_service.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libsdp/sdp-int.h b/lib/libsdp/sdp-int.h
new file mode 100644 (file)
index 0000000..84b6e01
--- /dev/null
@@ -0,0 +1,64 @@
+/* $NetBSD: sdp-int.h,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
+/* $DragonFly: src/lib/libsdp/sdp-int.h,v 1.1 2008/01/03 11:47:53 hasso Exp $ */
+
+/*
+ * sdp-int.h
+ *
+ * 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.
+ *
+ * $Id: sdp-int.h,v 1.1 2006/06/19 15:44:36 gdamore Exp $
+ * $FreeBSD: src/lib/libsdp/sdp-int.h,v 1.2 2004/01/09 18:19:12 emax Exp $
+ */
+
+#ifndef _SDP_INT_H_
+#define _SDP_INT_H_
+
+__BEGIN_DECLS
+
+/*
+ * SDP session
+ */
+
+struct sdp_session {
+       uint16_t         flags;
+#define SDP_SESSION_LOCAL      (1 << 0)
+       uint16_t         tid;   /* current session transaction ID (tid) */
+       uint16_t         omtu;  /* outgoing MTU (req buffer size) */
+       uint16_t         imtu;  /* incoming MTU (rsp buffer size) */
+       uint8_t         *req;   /* request buffer (start) */
+       uint8_t         *req_e; /* request buffer (end) */
+       uint8_t         *rsp;   /* response buffer (start) */
+       uint8_t         *rsp_e; /* response buffer (end) */
+       uint32_t         cslen; /* continuation state length */
+       uint8_t          cs[16];/* continuation state */
+       int32_t          s;     /* L2CAP socket */
+       int32_t          error; /* last error code */
+};
+typedef struct sdp_session     sdp_session_t;
+typedef struct sdp_session *   sdp_session_p;
+
+__END_DECLS
+
+#endif /* ndef _SDP_INT_H_ */
diff --git a/lib/libsdp/sdp.3 b/lib/libsdp/sdp.3
new file mode 100644 (file)
index 0000000..ed3cd9a
--- /dev/null
@@ -0,0 +1,427 @@
+.\" $NetBSD: sdp.3,v 1.1 2006/06/19 15:44:36 gdamore Exp $
+.\" $DragonFly: src/lib/libsdp/sdp.3,v 1.1 2008/01/03 11:47:53 hasso Exp $
+.\"
+.\" Copyright (c) 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.
+.\"
+.\" $Id: sdp.3,v 1.1 2006/06/19 15:44:36 gdamore Exp $
+.\" $FreeBSD: src/lib/libsdp/sdp.3,v 1.10 2005/06/15 19:04:04 ru Exp $
+.\"
+.Dd May 27, 2005
+.Dt SDP 3
+.Os
+.Sh NAME
+.Nm SDP_GET8 ,
+.Nm SDP_GET16 ,
+.Nm SDP_GET32 ,
+.Nm SDP_GET64 ,
+.Nm SDP_GET128 ,
+.Nm SDP_GET_UUID128 ,
+.Nm SDP_PUT8 ,
+.Nm SDP_PUT16 ,
+.Nm SDP_PUT32 ,
+.Nm SDP_PUT64 ,
+.Nm SDP_PUT128 ,
+.Nm SDP_PUT_UUID128 ,
+.Nm sdp_open ,
+.Nm sdp_open_local ,
+.Nm sdp_close ,
+.Nm sdp_error ,
+.Nm sdp_search ,
+.Nm sdp_attr2desc ,
+.Nm sdp_uuid2desc
+.Nd Bluetooth SDP routines
+.Sh LIBRARY
+.Lb libsdp
+.Sh SYNOPSIS
+.In bluetooth.h
+.In sdp.h
+.Fn SDP_GET8 "b" "cp"
+.Fn SDP_GET16 "s" "cp"
+.Fn SDP_GET32 "l" "cp"
+.Fn SDP_GET64 "l" "cp"
+.Fn SDP_GET128 "l" "cp"
+.Fn SDP_GET_UUID128 "l" "cp"
+.Fn SDP_PUT8 "b" "cp"
+.Fn SDP_PUT16 "s" "cp"
+.Fn SDP_PUT32 "l" "cp"
+.Fn SDP_PUT64 "l" "cp"
+.Fn SDP_PUT128 "l" "cp"
+.Fn SDP_PUT_UUID128 "l" "cp"
+.Ft "void *"
+.Fn sdp_open "bdaddr_t const *l" "bdaddr_t const *r"
+.Ft "void *"
+.Fn sdp_open_local "char const *control"
+.Ft int32_t
+.Fn sdp_close "void *xs"
+.Ft int32_t
+.Fn sdp_error "void *xs"
+.Ft int32_t
+.Fo sdp_search
+.Fa "void *xs" "uint32_t plen" "uint16_t const *pp" "uint32_t alen"
+.Fa "uint32_t const *ap" "uint32_t vlen" "sdp_attr_t *vp"
+.Fc
+.Ft "char const * const"
+.Fn sdp_attr2desc "uint16_t attr"
+.Ft "char const * const"
+.Fn sdp_uuid2desc "uint16_t uuid"
+.Ft int32_t
+.Fo sdp_register_service
+.Fa "void *xss" "uint16_t uuid" "bdaddr_t const *bdaddr" "uint8_t const *data"
+.Fa "uint32_t datalen" "uint32_t *handle"
+.Fc
+.Ft int32_t
+.Fn sdp_unregister_service "void *xss" "uint32_t handle"
+.Ft int32_t
+.Fo sdp_change_service
+.Fa "void *xss" "uint32_t handle" "uint8_t const *data" "uint32_t datalen"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn SDP_GET8 ,
+.Fn SDP_GET16 ,
+.Fn SDP_GET32 ,
+.Fn SDP_GET64
+and
+.Fn SDP_GET128
+macros are used to get byte, short, long, long long and 128-bit integer
+from the buffer pointed by
+.Fa cp
+pointer.
+The pointer is automatically advanced.
+.Pp
+The
+.Fn SDP_PUT8 ,
+.Fn SDP_PUT16 ,
+.Fn SDP_PUT32 ,
+.Fn SDP_PUT64
+and
+.Fn SDP_PUT128
+macros are used to put byte, short, long, long long and 128-bit integer
+into the buffer pointed by
+.Fa cp
+pointer.
+The pointer is automatically advanced.
+.Pp
+.Fn SDP_GET_UUID128
+and
+.Fn SDP_PUT_UUID128
+macros are used to get and put 128-bit UUID into the buffer pointed by
+.Fa cp
+pointer.
+The pointer is automatically advanced.
+.Pp
+The
+.Fn sdp_open
+and
+.Fn sdp_open_local
+functions each return a pointer to an opaque object describing SDP session.
+The
+.Fa l
+argument passed to
+.Fn sdp_open
+function should point to a source BD_ADDR.
+If source BD_ADDR is
+.Dv NULL
+then source address
+.Dv BDADDR_ANY
+is used.
+The
+.Fa r
+argument passed to
+.Fn sdp_open
+function should point to a
+.Pf non- Dv NULL
+remote BD_ADDR.
+Remote BD_ADDR cannot be
+.Dv BDADDR_ANY .
+The
+.Fn sdp_open_local
+function takes path to the control socket and opens a connection to a local
+SDP server.
+If path to the control socket is
+.Dv NULL
+then default
+.Pa /var/run/sdp
+path will be used.
+.Pp
+The
+.Fn sdp_close
+function terminates active SDP session and deletes SDP session object.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+.Pp
+The
+.Fn sdp_error
+function returns last error that is stored inside SDP session object.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+The error value returned can be converted to a human readable message by
+calling
+.Xr strerror 3
+function.
+.Pp
+The
+.Fn sdp_search
+function is used to perform SDP Service Search Attribute Request.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+The
+.Fa pp
+parameter is a Service Search Pattern - an array of one or more Service
+Class IDs.
+The maximum number of Service Class IDs in the array is 12.
+The
+.Fa plen
+parameter is the length of the Service Search pattern.
+The
+.Fa ap
+parameter is an Attribute ID Range List - an array of one or more SDP Attribute
+ID Range.
+Each attribute ID Range is encoded as a 32-bit unsigned integer data
+element, where the high order 16 bits are interpreted as the beginning
+attribute ID of the range and the low order 16 bits are interpreted as the
+ending attribute ID of the range.
+The attribute IDs contained in the Attribute ID Ranges List must be listed in
+ascending order without duplication of any attribute ID values.
+Note that all attributes may be requested by specifying a range of
+0x0000-0xFFFF.
+The
+.Fa alen
+parameter is the length of the Attribute ID Ranges List.
+The
+.Fn SDP_ATTR_RANGE "lo" "hi"
+macro can be used to prepare Attribute ID Range.
+The
+.Fa vp
+parameter should be an array of
+.Vt sdp_attr_t
+structures.
+Each
+.Vt sdp_attr_t
+structure describes single SDP attribute and defined as follows:
+.Bd -literal -offset indent
+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;
+.Ed
+.Pp
+The caller of the
+.Fn sdp_search
+function is expected to prepare the array of
+.Vt sdp_attr
+structures and for each element of the array both
+.Va vlen
+and
+.Va value
+must be set.
+The
+.Fn sdp_search
+function will fill each
+.Vt sdp_attr_t
+structure with attribute and value, i.e., it will set
+.Va flags ,
+.Va attr
+and
+.Va vlen
+fields.
+The actual value of the attribute will be copied into
+.Va value
+buffer.
+Note: attributes are returned in the order they appear in the Service Search
+Attribute Response.
+SDP server could return several attributes for the same record.
+In this case the order of the attributes will be: all attributes for the first
+records, then all attributes for the secord record etc.
+.Pp
+The
+.Fn sdp_attr2desc
+and
+.Fn sdp_uuid2desc
+functions each take a numeric attribute ID/UUID value and convert it to a
+human readable description.
+.Pp
+The
+.Fn sdp_register_service
+function
+is used to register service with the local SDP server.
+The
+.Fa xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Fa uuid
+parameter is a SDP Service Class ID for the service to be registered.
+The
+.Fa bdaddr
+parameter should point to a valid BD_ADDR.
+The service will be only advertised if request was received by the local device
+with
+.Fa bdaddr .
+If
+.Fa bdaddr
+is set to
+.Dv BDADDR_ANY
+then the service will be advertised to any remote devices that queries for it.
+The
+.Fa data
+and
+.Fa datalen
+parameters specify data and size of the data for the service.
+Upon successful return
+.Fn sdp_register_service
+will populate
+.Fa handle
+with the SDP record handle.
+This parameter is optional and can be set to
+.Dv NULL .
+.Pp
+The
+.Fn sdp_unregister_service
+function
+is used to unregister service with the local SDP server.
+The
+.Fa xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Fa handle
+parameter should contain a valid SDP record handle of the service to be
+unregistered.
+.Pp
+The
+.Fn sdp_change_service
+function is used to change data associated with the existing service on
+the local SDP server.
+The
+.Fa xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Fa handle
+parameter should contain a valid SDP record handle of the service to be changed.
+The
+.Fa data
+and
+.Fa datalen
+parameters specify data and size of the data for the service.
+.Sh CAVEAT
+When registering services with the local SDP server the application must
+keep the SDP session open.
+If SDP session is closed then the local SDP server will remove all services
+that were registered over the session.
+The application is allowed to change or unregister service if it was registered
+over the same session.
+.Sh EXAMPLES
+The following example shows how to get
+.Dv SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST
+attribute for the
+.Dv SDP_SERVICE_CLASS_SERIAL_PORT
+service from the remote device.
+.Bd -literal -offset indent
+bdaddr_t       remote;
+uint8_t        buffer[1024];
+void          *ss    = NULL;
+uint16_t       serv  = SDP_SERVICE_CLASS_SERIAL_PORT;
+uint32_t       attr  = SDP_ATTR_RANGE(
+                            SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+                            SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
+sdp_attr_t     proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer };
+
+/* Obtain/set remote BDADDR here */
+
+if ((ss = sdp_open(BDADDR_ANY, remote)) == NULL)
+        /* exit ENOMEM */
+if (sdp_error(ss) != 0)
+        /* exit sdp_error(ss) */
+
+if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0)
+        /* exit sdp_error(ss) */
+
+if (proto.flags != SDP_ATTR_OK)
+        /* exit see proto.flags for details */
+
+/* If we got here then we have attribute value in proto.value */
+.Ed
+.Sh DIAGNOSTICS
+Both
+.Fn sdp_open
+and
+.Fn sdp_open_local
+will return
+.Dv NULL
+if memory allocation for the new SDP session object fails.
+If the new SDP object was created then caller is still expected to call
+.Fn sdp_error
+to check if there was connection error.
+.Pp
+The
+.Fn sdp_search ,
+.Fn sdp_register_service ,
+.Fn sdp_unregister_service
+and
+.Fn sdp_change_service
+functions return non-zero value on error.
+The caller is expected to call
+.Fn sdp_error
+to find out more about error.
+.Sh SEE ALSO
+.Xr bluetooth 4 ,
+.Xr sdpquery 1 ,
+.Xr sdpd 8 ,
+.Xr strerror 3
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report bugs if found.
+.Sh HISTORY
+.Nm libsdp
+first appeared in
+.Fx ,
+was ported to
+.Nx 4.0
+by
+.An Iain Hibbert and imported into
+.Dx 1.11 .
diff --git a/lib/libsdp/sdp.h b/lib/libsdp/sdp.h
new file mode 100644 (file)
index 0000000..4817376
--- /dev/null
@@ -0,0 +1,602 @@
+/* $NetBSD: sdp.h,v 1.2 2006/08/17 20:13:31 plunky Exp $ */
+/* $DragonFly: src/lib/libsdp/sdp.h,v 1.1 2008/01/03 11:47:53 hasso 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.
+ */
+/*
+ * sdp.h
+ *
+ * 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.
+ *
+ * $Id: sdp.h,v 1.2 2006/08/17 20:13:31 plunky Exp $
+ * $FreeBSD: src/lib/libsdp/sdp.h,v 1.5 2005/05/27 19:11:33 emax Exp $
+ */
+
+#ifndef _SDP_H_
+#define _SDP_H_
+
+#include <string.h>
+
+__BEGIN_DECLS
+
+/*
+ * Data representation (page 349)
+ */
+
+/* Nil, the null type */
+#define SDP_DATA_NIL                                   0x00
+
+/* Unsigned integer */
+#define SDP_DATA_UINT8                                 0x08
+#define SDP_DATA_UINT16                                        0x09
+#define SDP_DATA_UINT32                                        0x0A
+#define SDP_DATA_UINT64                                        0x0B
+#define SDP_DATA_UINT128                               0x0C
+
+/* Signed two's-complement integer */
+#define SDP_DATA_INT8                                  0x10
+#define SDP_DATA_INT16                                 0x11
+#define SDP_DATA_INT32                                 0x12
+#define SDP_DATA_INT64                                 0x13
+#define SDP_DATA_INT128                                        0x14
+
+/* UUID, a universally unique identifier */
+#define SDP_DATA_UUID16                                        0x19
+#define SDP_DATA_UUID32                                        0x1A
+#define SDP_DATA_UUID128                               0x1C
+
+/* Text string */
+#define SDP_DATA_STR8                                  0x25
+#define SDP_DATA_STR16                                 0x26
+#define SDP_DATA_STR32                                 0x27
+
+/* Boolean */
+#define SDP_DATA_BOOL                                  0x28
+
+/*
+ * Data element sequence.
+ * A data element whose data field is a sequence of data elements
+ */
+#define SDP_DATA_SEQ8                                  0x35
+#define SDP_DATA_SEQ16                                 0x36
+#define SDP_DATA_SEQ32                                 0x37
+
+/*
+ * Data element alternative.
+ * A data element whose data field is a sequence of data elements from
+ * which one data element is to be selected.
+ */
+#define SDP_DATA_ALT8                                  0x3D
+#define SDP_DATA_ALT16                                 0x3E
+#define SDP_DATA_ALT32                                 0x3F
+
+/* URL, a uniform resource locator */
+#define SDP_DATA_URL8                                  0x45
+#define SDP_DATA_URL16                                 0x46
+#define SDP_DATA_URL32                                 0x47
+
+/*
+ * Protocols UUID (short) http://www.bluetoothsig.org/assigned-numbers/sdp.htm
+ * 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 http://www.bluetoothsig.org/assigned-numbers/sdp.htm
+ */
+
+#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 (page 366) and
+ * http://www.bluetoothsig.org/assigned-numbers/sdp.htm
+ */
+
+#define SDP_ATTR_RANGE(lo, hi) \
+       (uint32_t)(((uint16_t)(lo) << 16) | ((uint16_t)(hi)))
+
+#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
+#define SDP_ATTR_GROUP_ID                              0x0200
+#define SDP_ATTR_IP_SUBNET                             0x0200
+#define SDP_ATTR_VERSION_NUMBER_LIST                   0x0200
+#define SDP_ATTR_SERVICE_DATABASE_STATE                        0x0201
+#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
+
+/*
+ * The offset must be added to the attribute ID base (contained in the
+ * LANGUAGE_BASE_ATTRIBUTE_ID_LIST attribute) in order to compute the
+ * attribute ID for these attributes.
+ */
+
+#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
+
+/*
+ * Protocol data unit (PDU) format (page 352)
+ */
+
+#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
+
+struct sdp_pdu {
+       uint8_t         pid;    /* PDU ID - SDP_PDU_xxx */
+       uint16_t        tid;    /* transaction ID */
+       uint16_t        len;    /* parameters length (in bytes) */
+} __attribute__ ((packed));
+typedef struct sdp_pdu         sdp_pdu_t;
+typedef struct sdp_pdu *       sdp_pdu_p;
+
+/*
+ * 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
+
+/*
+ * 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;
+
+/******************************************************************************
+ * User interface
+ *****************************************************************************/
+
+/* 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 */
+
+void *             sdp_open       (bdaddr_t const *l, bdaddr_t const *r);
+void *             sdp_open_local (char const *control);
+int32_t            sdp_close      (void *xs);
+int32_t            sdp_error      (void *xs);
+
+int32_t            sdp_search     (void *xs,
+                                   uint32_t plen, uint16_t const *pp,
+                                   uint32_t alen, uint32_t const *ap,
+                                   uint32_t vlen, sdp_attr_t *vp);
+
+char const *       sdp_attr2desc  (uint16_t attr);
+char const *       sdp_uuid2desc  (uint16_t uuid);
+void               sdp_print      (uint32_t level, uint8_t *start,
+                                   uint8_t const *end);
+
+/******************************************************************************
+ * sdpd interface and Bluetooth profiles data
+ *****************************************************************************/
+
+#define SDP_LOCAL_PATH "/var/run/sdp"
+#define SDP_LOCAL_MTU  4096
+
+/*
+ * These are NOT defined in spec and only accepted on control sockets.
+ * The response to these request always will be SDP_PDU_ERROR_RESPONSE.
+ * The first 2 bytes (after PDU header) is an error code (in network
+ * byte order). The rest of the data (pdu->len - 2) is a response data
+ * and depend on the request.
+ *
+ * SDP_PDU_SERVICE_REGISTER_REQUEST
+ *     pdu_header_t    hdr;
+ *     uint16_t        uuid;   service class UUID (network byte order)
+ *     bdaddr_t        bdaddr; local BD_ADDR (or ANY)
+ *     profile data[pdu->len - sizeof(uuid) - sizeof(bdaddr)]
+ *
+ * in successful reponse additional data will contain 4 bytes record handle
+ *
+ *
+ * SDP_PDU_SERVICE_UNREGISTER_REQUEST
+ *     pdu_header_t    hdr;
+ *     uint32_t        record_handle;  (network byte order)
+ *
+ * no additional data in response.
+ *
+ *
+ * SDP_PDU_SERVICE_CHANGE_REQUEST
+ *     pdu_header_t    hdr;
+ *     uint32_t        record_handle;  (network byte order)
+ *     profile data[pdu->len - sizeof(record_handle)]
+ *
+ * no additional data in response.
+ */
+
+#define SDP_PDU_SERVICE_REGISTER_REQUEST       0x81
+#define SDP_PDU_SERVICE_UNREGISTER_REQUEST     0x82
+#define SDP_PDU_SERVICE_CHANGE_REQUEST         0x83
+
+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;
+
+int32_t        sdp_register_service    (void *xss, uint16_t uuid,
+                                bdaddr_t *bdaddr, uint8_t *data,
+                                uint32_t datalen, uint32_t *handle);
+int32_t        sdp_unregister_service  (void *xss, uint32_t handle);
+int32_t        sdp_change_service      (void *xss, uint32_t handle,
+                                uint8_t *data, uint32_t datalen);
+
+__END_DECLS
+
+#endif /* ndef _SDP_H_ */
diff --git a/lib/libsdp/search.c b/lib/libsdp/search.c
new file mode 100644 (file)
index 0000000..b586f2f
--- /dev/null
@@ -0,0 +1,423 @@
+/* $NetBSD: search.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
+/* $DragonFly: src/lib/libsdp/search.c,v 1.1 2008/01/03 11:47:53 hasso Exp $ */
+
+/*
+ * search.c
+ *
+ * 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.
+ *
+ * $Id: search.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
+ * $FreeBSD: src/lib/libsdp/search.c,v 1.7 2004/12/09 18:57:12 emax Exp $
+ */
+
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+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_xpdu {
+               sdp_pdu_t                pdu;
+               uint16_t                 len;
+       } __attribute__ ((packed))       xpdu;
+
+       sdp_session_p                    ss = (sdp_session_p) xss;
+       uint8_t                         *req = NULL, *rsp = NULL, *rsp_tmp = NULL;
+       int32_t                          t, len;
+       uint16_t                         lo, hi;
+
+       if (ss == NULL)
+               return (-1);
+
+       if (ss->req == NULL || ss->rsp == NULL ||
+           plen == 0 || pp == NULL || alen == 0 || ap == NULL) {
+               ss->error = EINVAL;
+               return (-1);
+       }
+
+       req = ss->req;
+
+       /* Calculate ServiceSearchPattern length */
+       plen = plen * (sizeof(pp[0]) + 1);
+
+       /* Calculate AttributeIDList length */
+       for (len = 0, t = 0; t < alen; t ++) {
+               lo = (uint16_t) (ap[t] >> 16);
+               hi = (uint16_t) (ap[t]);
+
+               if (lo > hi) {
+                       ss->error = EINVAL;
+                       return (-1);
+               }
+
+               if (lo != hi)
+                       len += (sizeof(ap[t]) + 1);
+               else
+                       len += (sizeof(lo) + 1);
+       }
+       alen = len;
+
+       /* Calculate length of the request */
+       len =   plen + sizeof(uint8_t) + sizeof(uint16_t) +
+                       /* ServiceSearchPattern */
+               sizeof(uint16_t) +
+                       /* MaximumAttributeByteCount */
+               alen + sizeof(uint8_t) + sizeof(uint16_t);
+                       /* AttributeIDList */
+
+       if (ss->req_e - req < len) {
+               ss->error = ENOBUFS;
+               return (-1);
+       }
+
+       /* Put ServiceSearchPattern */
+       SDP_PUT8(SDP_DATA_SEQ16, req);
+       SDP_PUT16(plen, req);
+       for (; plen > 0; pp ++, plen -= (sizeof(pp[0]) + 1)) {
+               SDP_PUT8(SDP_DATA_UUID16, req);
+               SDP_PUT16(*pp, req);
+       }
+
+       /* Put MaximumAttributeByteCount */
+       SDP_PUT16(0xffff, req);
+
+       /* Put AttributeIDList */
+       SDP_PUT8(SDP_DATA_SEQ16, req);
+       SDP_PUT16(alen, req);
+       for (; alen > 0; ap ++) {
+               lo = (uint16_t) (*ap >> 16);
+               hi = (uint16_t) (*ap);
+
+               if (lo != hi) {
+                       /* Put attribute range */
+                       SDP_PUT8(SDP_DATA_UINT32, req);
+                       SDP_PUT32(*ap, req);
+                       alen -= (sizeof(ap[0]) + 1);
+               } else {
+                       /* Put attribute */
+                       SDP_PUT8(SDP_DATA_UINT16, req);
+                       SDP_PUT16(lo, req);
+                       alen -= (sizeof(lo) + 1);
+               }
+       }
+
+       /* Submit ServiceSearchAttributeRequest and wait for response */
+       ss->cslen = 0;
+       rsp = ss->rsp;
+
+       do {
+               struct iovec     iov[2];
+               uint8_t         *req_cs = req;
+
+               /* Add continuation state (if any) */
+               if (ss->req_e - req_cs < ss->cslen + 1) {
+                       ss->error = ENOBUFS;
+                       return (-1);
+               }
+
+               SDP_PUT8(ss->cslen, req_cs);
+               if (ss->cslen > 0) {
+                       memcpy(req_cs, ss->cs, ss->cslen);
+                       req_cs += ss->cslen;
+               }
+
+               /* Prepare SDP PDU header */
+               xpdu.pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
+               xpdu.pdu.tid = htons(ss->tid);
+               xpdu.pdu.len = htons(req_cs - ss->req);
+
+               /* Submit request */
+               iov[0].iov_base = (void *) &xpdu;
+               iov[0].iov_len = sizeof(xpdu.pdu);
+               iov[1].iov_base = (void *) ss->req;
+               iov[1].iov_len = req_cs - ss->req;
+
+               do {
+                       len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+               } while (len < 0 && errno == EINTR);
+
+               if (len < 0) {
+                       ss->error = errno;
+                       return (-1);
+               }
+
+               /* Read response */
+               iov[0].iov_base = (void *) &xpdu;
+               iov[0].iov_len = sizeof(xpdu);
+               iov[1].iov_base = (void *) rsp;
+               iov[1].iov_len = ss->imtu;
+
+               do {
+                       len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+               } while (len < 0 && errno == EINTR);
+
+               if (len < 0) {
+                       ss->error = errno;
+                       return (-1);
+               }
+               if (len < sizeof(xpdu)) {
+                       ss->error = ENOMSG;
+                       return (-1);
+               }
+
+               xpdu.pdu.tid = ntohs(xpdu.pdu.tid);
+               xpdu.pdu.len = ntohs(xpdu.pdu.len);
+               xpdu.len = ntohs(xpdu.len);
+
+               if (xpdu.pdu.pid == SDP_PDU_ERROR_RESPONSE ||
+                   xpdu.pdu.tid != ss->tid ||
+                   xpdu.pdu.len > len ||
+                   xpdu.len > xpdu.pdu.len) {
+                       ss->error = EIO;
+                       return (-1);
+               }
+
+               /* Save continuation state (if any) */
+               ss->cslen = rsp[xpdu.len];
+               if (ss->cslen > 0) {
+                       if (ss->cslen > sizeof(ss->cs)) {
+                               ss->error = ENOBUFS;
+                               return (-1);
+                       }
+
+                       memcpy(ss->cs, rsp + xpdu.len + 1, ss->cslen);
+
+                       /*
+                        * Ensure that we always have ss->imtu bytes
+                        * available in the ss->rsp buffer
+                        */
+
+                       if (ss->rsp_e - rsp <= ss->imtu) {
+                               uint32_t         size, offset;
+
+                               size = ss->rsp_e - ss->rsp + ss->imtu;
+                               offset = rsp - ss->rsp;
+
+                               rsp_tmp = realloc(ss->rsp, size);
+                               if (rsp_tmp == NULL) {
+                                       ss->error = ENOMEM;
+                                       return (-1);
+                               }
+
+                               ss->rsp = rsp_tmp;
+                               ss->rsp_e = ss->rsp + size;
+                               rsp = ss->rsp + offset;
+                       }
+               }
+
+               rsp += xpdu.len;
+               ss->tid ++;
+       } while (ss->cslen > 0);
+
+       /*
+        * If we got here then we have completed SDP transaction and now
+        * we must populate attribute values into vp array. At this point
+        * ss->rsp points to the beginning of the response and rsp points
+        * to the end of the response.
+        *
+        * From Bluetooth v1.1 spec page 364
+        *
+        * The AttributeLists is a data element sequence where each element
+        * in turn is a data element sequence representing an attribute list.
+        * Each attribute list contains attribute IDs and attribute values
+        * from one service record. The first element in each attribute list
+        * contains the attribute ID of the first attribute to be returned for
+        * that service record. The second element in each attribute list
+        * contains the corresponding attribute value. Successive pairs of
+        * elements in each attribute list contain additional attribute ID
+        * and value pairs. Only attributes that have non-null values within
+        * the service record and whose attribute IDs were specified in the
+        * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
+        * Neither an attribute ID nor attribute value is placed in
+        * AttributeLists for attributes in the service record that have no
+        * value. Within each attribute list, the attributes are listed in
+        * ascending order of attribute ID value.
+        */
+
+       if (vp == NULL)
+               goto done;
+
+       rsp_tmp = ss->rsp;
+
+       /* Skip the first SEQ */
+       SDP_GET8(t, rsp_tmp);
+       switch (t) {
+       case SDP_DATA_SEQ8:
+               SDP_GET8(len, rsp_tmp);
+               break;
+
+       case SDP_DATA_SEQ16:
+               SDP_GET16(len, rsp_tmp);
+               break;
+
+       case SDP_DATA_SEQ32:
+               SDP_GET32(len, rsp_tmp);
+               break;
+
+       default:
+               ss->error = ENOATTR;
+               return (-1);
+               /* NOT REACHED */
+       }
+
+       for (; rsp_tmp < rsp && vlen > 0; ) {
+               /* Get set of attributes for the next record */
+               SDP_GET8(t, rsp_tmp);
+               switch (t) {
+               case SDP_DATA_SEQ8:
+                       SDP_GET8(len, rsp_tmp);
+                       break;
+
+               case SDP_DATA_SEQ16:
+                       SDP_GET16(len, rsp_tmp);
+                       break;
+
+               case SDP_DATA_SEQ32:
+                       SDP_GET32(len, rsp_tmp);
+                       break;
+
+               default:
+                       ss->error = ENOATTR;
+                       return (-1);
+                       /* NOT REACHED */
+               }
+
+               /* Now rsp_tmp points to list of (attr,value) pairs */
+               for (; len > 0 && vlen > 0; vp ++, vlen --) {
+                       /* Attribute */
+                       SDP_GET8(t, rsp_tmp);
+                       if (t != SDP_DATA_UINT16) {
+                               ss->error = ENOATTR;
+                               return (-1);
+                       }
+                       SDP_GET16(vp->attr, rsp_tmp);
+
+                       /* Attribute value */
+                       switch (rsp_tmp[0]) {
+                       case SDP_DATA_NIL:
+                               alen = 0;
+                               break;
+
+                       case SDP_DATA_UINT8:
+                       case SDP_DATA_INT8:
+                       case SDP_DATA_BOOL:
+                               alen = sizeof(uint8_t);
+                               break;
+
+                       case SDP_DATA_UINT16:
+                       case SDP_DATA_INT16:
+                       case SDP_DATA_UUID16:
+                               alen = sizeof(uint16_t);
+                               break;
+
+                       case SDP_DATA_UINT32:
+                       case SDP_DATA_INT32:
+                       case SDP_DATA_UUID32:
+                               alen = sizeof(uint32_t);
+                               break;
+
+                       case SDP_DATA_UINT64:
+                       case SDP_DATA_INT64:
+                               alen = sizeof(uint64_t);
+                               break;
+
+                       case SDP_DATA_UINT128:
+                       case SDP_DATA_INT128:
+                       case SDP_DATA_UUID128:
+                               alen = sizeof(uint128_t);
+                               break;
+
+                       case SDP_DATA_STR8:
+                       case SDP_DATA_URL8:
+                       case SDP_DATA_SEQ8:
+                       case SDP_DATA_ALT8:
+                               alen = rsp_tmp[1] + sizeof(uint8_t);
+                               break;
+
+                       case SDP_DATA_STR16:
+                       case SDP_DATA_URL16:
+                       case SDP_DATA_SEQ16:
+                       case SDP_DATA_ALT16:
+                               alen =    ((uint16_t)rsp_tmp[1] << 8)
+                                       | ((uint16_t)rsp_tmp[2]);
+                               alen += sizeof(uint16_t);
+                               break;
+
+                       case SDP_DATA_STR32:
+                       case SDP_DATA_URL32:
+                       case SDP_DATA_SEQ32:
+                       case SDP_DATA_ALT32:
+                               alen =    ((uint32_t)rsp_tmp[1] << 24)
+                                       | ((uint32_t)rsp_tmp[2] << 16)
+                                       | ((uint32_t)rsp_tmp[3] <<  8)
+                                       | ((uint32_t)rsp_tmp[4]);
+                               alen += sizeof(uint32_t);
+                               break;
+
+                       default:
+                               ss->error = ENOATTR;
+                               return (-1);
+                               /* NOT REACHED */
+                       }
+
+                       alen += sizeof(uint8_t);
+
+                       if (vp->value != NULL) {
+                               if (alen <= vp->vlen) {
+                                       vp->flags = SDP_ATTR_OK;
+                                       vp->vlen = alen;
+                               } else
+                                       vp->flags = SDP_ATTR_TRUNCATED;
+
+                               memcpy(vp->value, rsp_tmp, vp->vlen);
+                       } else
+                               vp->flags = SDP_ATTR_INVALID;
+
+                       len -=  (
+                               sizeof(uint8_t) + sizeof(uint16_t) +
+                               alen
+                               );
+
+                       rsp_tmp += alen;
+               }
+       }
+done:
+       ss->error = 0;
+
+       return (0);
+}
diff --git a/lib/libsdp/service.c b/lib/libsdp/service.c
new file mode 100644 (file)
index 0000000..9def829
--- /dev/null
@@ -0,0 +1,272 @@
+/* $NetBSD: service.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
+/* $DragonFly: src/lib/libsdp/service.c,v 1.1 2008/01/03 11:47:53 hasso 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.
+ */
+/*
+ * service.c
+ *
+ * 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.
+ *
+ * $Id: service.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
+ * $FreeBSD: src/lib/libsdp/service.c,v 1.1 2004/01/20 20:48:25 emax Exp $
+ */
+
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+static int32_t sdp_receive_error_pdu(sdp_session_p ss);
+
+int32_t
+sdp_register_service(void *xss, uint16_t uuid, bdaddr_t *bdaddr,
+               uint8_t *data, uint32_t datalen, uint32_t *handle)
+{
+       sdp_session_p   ss = (sdp_session_p) xss;
+       struct iovec    iov[4];
+       sdp_pdu_t       pdu;
+       int32_t         len;
+
+       if (ss == NULL)
+               return (-1);
+       if (bdaddr == NULL || data == NULL ||
+           datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
+               ss->error = EINVAL;
+               return (-1);
+       }
+       if (sizeof(pdu)+sizeof(uuid)+sizeof(*bdaddr)+datalen > SDP_LOCAL_MTU) {
+               ss->error = EMSGSIZE;
+               return (-1);
+       }
+
+       pdu.pid = SDP_PDU_SERVICE_REGISTER_REQUEST;
+       pdu.tid = htons(++ss->tid);
+       pdu.len = htons(sizeof(uuid) + sizeof(*bdaddr) + datalen);
+
+       uuid = htons(uuid);
+
+       iov[0].iov_base = (void *) &pdu;
+       iov[0].iov_len = sizeof(pdu);
+
+       iov[1].iov_base = (void *) &uuid;
+       iov[1].iov_len = sizeof(uuid);
+
+       iov[2].iov_base = (void *) bdaddr;
+       iov[2].iov_len = sizeof(*bdaddr);
+
+       iov[3].iov_base = (void *) data;
+       iov[3].iov_len = datalen;
+
+       do {
+               len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+       } while (len < 0 && errno == EINTR);
+
+       if (len < 0) {
+               ss->error = errno;
+               return (-1);
+       }
+
+       len = sdp_receive_error_pdu(ss);
+       if (len < 0)
+               return (-1);
+       if (len != sizeof(pdu) + sizeof(uint16_t) + sizeof(uint32_t)) {
+               ss->error = EIO;
+               return (-1);
+       }
+
+       if (handle != NULL) {
+               *handle  = (uint32_t) ss->rsp[--len];
+               *handle |= (uint32_t) ss->rsp[--len] << 8;
+               *handle |= (uint32_t) ss->rsp[--len] << 16;
+               *handle |= (uint32_t) ss->rsp[--len] << 24;
+       }
+
+       return (0);
+}
+
+int32_t
+sdp_unregister_service(void *xss, uint32_t handle)
+{
+       sdp_session_p   ss = (sdp_session_p) xss;
+       struct iovec    iov[2];
+       sdp_pdu_t       pdu;
+       int32_t         len;
+
+       if (ss == NULL)
+               return (-1);
+       if (!(ss->flags & SDP_SESSION_LOCAL)) {
+               ss->error = EINVAL;
+               return (-1);
+       }
+#if 0
+       if (sizeof(pdu) + sizeof(handle) > SDP_LOCAL_MTU) {
+               ss->error = EMSGSIZE;
+               return (-1);
+       }
+#endif
+
+       pdu.pid = SDP_PDU_SERVICE_UNREGISTER_REQUEST;
+       pdu.tid = htons(++ss->tid);
+       pdu.len = htons(sizeof(handle));
+
+       handle = htonl(handle);
+
+       iov[0].iov_base = (void *) &pdu;
+       iov[0].iov_len = sizeof(pdu);
+
+       iov[1].iov_base = (void *) &handle;
+       iov[1].iov_len = sizeof(handle);
+
+       do {
+               len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+       } while (len < 0 && errno == EINTR);
+
+       if (len < 0) {
+               ss->error = errno;
+               return (-1);
+       }
+
+       return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
+}
+
+int32_t
+sdp_change_service(void *xss, uint32_t handle,
+               uint8_t *data, uint32_t datalen)
+{
+       sdp_session_p   ss = (sdp_session_p) xss;
+       struct iovec    iov[3];
+       sdp_pdu_t       pdu;
+       int32_t         len;
+
+       if (ss == NULL)
+               return (-1);
+       if (data == NULL || datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
+               ss->error = EINVAL;
+               return (-1);
+       }
+       if (sizeof(pdu) + sizeof(handle) + datalen > SDP_LOCAL_MTU) {
+               ss->error = EMSGSIZE;
+               return (-1);
+       }
+
+       pdu.pid = SDP_PDU_SERVICE_CHANGE_REQUEST;
+       pdu.tid = htons(++ss->tid);
+       pdu.len = htons(sizeof(handle) + datalen);
+
+       handle = htons(handle);
+
+       iov[0].iov_base = (void *) &pdu;
+       iov[0].iov_len = sizeof(pdu);
+
+       iov[1].iov_base = (void *) &handle;
+       iov[1].iov_len = sizeof(handle);
+
+       iov[2].iov_base = (void *) data;
+       iov[2].iov_len = datalen;
+
+       do {
+               len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+       } while (len < 0 && errno == EINTR);
+
+       if (len < 0) {
+               ss->error = errno;
+               return (-1);
+       }
+
+       return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
+}
+
+static int32_t
+sdp_receive_error_pdu(sdp_session_p ss)
+{
+       sdp_pdu_t       pdu;
+       int32_t         len;
+       uint16_t        error;
+
+       do {
+               len = read(ss->s, ss->rsp, (size_t)(ss->rsp_e - ss->rsp));
+       } while (len < 0 && errno == EINTR);
+
+       if (len < 0) {
+               ss->error = errno;
+               return (-1);
+       }
+
+       memcpy(&pdu, ss->rsp, sizeof(pdu));
+       pdu.tid = ntohs(pdu.tid);
+       pdu.len = ntohs(pdu.len);
+       memcpy(ss->rsp, &pdu, sizeof(pdu));
+
+       if (pdu.pid != SDP_PDU_ERROR_RESPONSE || pdu.tid != ss->tid ||
+           pdu.len < 2 || pdu.len != len - sizeof(pdu)) {
+               ss->error = EIO;
+               return (-1);
+       }
+
+       error  = (uint16_t) ss->rsp[sizeof(pdu)] << 8;
+       error |= (uint16_t) ss->rsp[sizeof(pdu) + 1];
+
+       if (error != 0) {
+               ss->error = EIO;
+               return (-1);
+       }
+
+       return (len);
+}
diff --git a/lib/libsdp/session.c b/lib/libsdp/session.c
new file mode 100644 (file)
index 0000000..1c3c402
--- /dev/null
@@ -0,0 +1,221 @@
+/* $NetBSD: session.c,v 1.2 2007/04/07 21:08:46 plunky Exp $ */
+/* $DragonFly: src/lib/libsdp/session.c,v 1.1 2008/01/03 11:47:53 hasso 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.
+ */
+/*
+ * session.c
+ *
+ * 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.
+ *
+ * $Id: session.c,v 1.2 2007/04/07 21:08:46 plunky Exp $
+ * $FreeBSD: src/lib/libsdp/session.c,v 1.3 2004/01/09 22:44:28 emax Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/un.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+void *
+sdp_open(bdaddr_t const *l, bdaddr_t const *r)
+{
+       sdp_session_p           ss = NULL;
+       struct sockaddr_bt      sa;
+       struct linger           li;
+       socklen_t               size;
+
+       if ((ss = calloc(1, sizeof(*ss))) == NULL)
+               goto fail;
+
+       if (l == NULL || r == NULL) {
+               ss->error = EINVAL;
+               goto fail;
+       }
+
+       ss->s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+       if (ss->s < 0) {
+               ss->error = errno;
+               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)) < 0) {
+               ss->error = errno;
+               goto fail;
+       }
+
+       memset(&sa, 0, sizeof(sa));
+       sa.bt_len = sizeof(sa);
+       sa.bt_family = AF_BLUETOOTH;
+       bdaddr_copy(&sa.bt_bdaddr, l);
+       if (bind(ss->s, (void *) &sa, sizeof(sa)) < 0) {
+               ss->error = errno;
+               goto fail;
+       }
+
+       sa.bt_psm = L2CAP_PSM_SDP;
+       bdaddr_copy(&sa.bt_bdaddr, r);
+       if (connect(ss->s, (void *) &sa, sizeof(sa)) < 0) {
+               ss->error = errno;
+               goto fail;
+       }
+
+       size = sizeof(ss->omtu);
+       if (getsockopt(ss->s, BTPROTO_L2CAP, SO_L2CAP_OMTU, &ss->omtu, &size) < 0) {
+               ss->error = errno;
+               goto fail;
+       }
+       if ((ss->req = malloc((size_t)ss->omtu)) == NULL) {
+               ss->error = ENOMEM;
+               goto fail;
+       }
+       ss->req_e = ss->req + ss->omtu;
+
+       size = sizeof(ss->imtu);
+       if (getsockopt(ss->s, BTPROTO_L2CAP, SO_L2CAP_IMTU, &ss->imtu, &size) < 0) {
+               ss->error = errno;
+               goto fail;
+       }
+       if ((ss->rsp = malloc((size_t)ss->imtu)) == NULL) {
+               ss->error = ENOMEM;
+               goto fail;
+       }
+       ss->rsp_e = ss->rsp + ss->imtu;
+       ss->error = 0;
+fail:
+       return ((void *) ss);
+}
+
+void *
+sdp_open_local(char const *control)
+{
+       sdp_session_p           ss = NULL;
+       struct sockaddr_un      sa;
+
+       if ((ss = calloc(1, sizeof(*ss))) == NULL)
+               goto fail;
+
+       ss->s = socket(PF_LOCAL, SOCK_STREAM, 0);
+       if (ss->s < 0) {
+               ss->error = errno;
+               goto fail;
+       }
+
+       if (control == NULL)
+               control = SDP_LOCAL_PATH;
+
+       sa.sun_len = sizeof(sa);
+       sa.sun_family = AF_LOCAL;
+       strlcpy(sa.sun_path, control, sizeof(sa.sun_path));
+
+       if (connect(ss->s, (void *) &sa, sizeof(sa)) < 0) {
+               ss->error = errno;
+               goto fail;
+       }
+
+       ss->flags |= SDP_SESSION_LOCAL;
+       ss->imtu = ss->omtu = SDP_LOCAL_MTU;
+
+       if ((ss->req = malloc((size_t)ss->omtu)) == NULL) {
+               ss->error = ENOMEM;
+               goto fail;
+       }
+       ss->req_e = ss->req + ss->omtu;
+
+       if ((ss->rsp = malloc((size_t)ss->imtu)) == NULL) {
+               ss->error = ENOMEM;
+               goto fail;
+       }
+       ss->rsp_e = ss->rsp + ss->imtu;
+       ss->error = 0;
+fail:
+       return ((void *) ss);
+}
+
+int32_t
+sdp_close(void *xss)
+{
+       sdp_session_p   ss = (sdp_session_p) xss;
+
+       if (ss != NULL) {
+               if (ss->s >= 0)
+                       close(ss->s);
+
+               if (ss->req != NULL)
+                       free(ss->req);
+               if (ss->rsp != NULL)
+                       free(ss->rsp);
+
+               memset(ss, 0, sizeof(*ss));
+               free(ss);
+       }
+
+       return (0);
+}
+
+int32_t
+sdp_error(void *xss)
+{
+       sdp_session_p   ss = (sdp_session_p) xss;
+
+       return ((ss != NULL)? ss->error : EINVAL);
+}
diff --git a/lib/libsdp/util.c b/lib/libsdp/util.c
new file mode 100644 (file)
index 0000000..7def3c8
--- /dev/null
@@ -0,0 +1,495 @@
+/* $NetBSD: util.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */
+/* $DragonFly: src/lib/libsdp/util.c,v 1.1 2008/01/03 11:47:53 hasso 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.
+ */
+/*
+ * util.c
+ *
+ * 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.
+ *
+ * $Id: util.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $
+ * $FreeBSD: src/lib/libsdp/util.c,v 1.5 2005/05/27 19:11:33 emax Exp $
+ */
+
+#include <netinet/in.h>
+#include <bluetooth.h>
+#include <stdio.h>
+#include <sdp.h>
+
+/*
+ * 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)
+{
+       union {
+               int8_t          int8;
+               int16_t         int16;
+               int32_t         int32;
+               int64_t         int64;
+               int128_t        int128;
+               uint8_t         uint8;
+               uint16_t        uint16;
+               uint32_t        uint32;
+               uint64_t        uint64;
+       }                       value;
+       uint8_t                 type;
+       uint32_t                i;
+
+       if (start == NULL || end == NULL)
+               return;
+
+       while (start < end) {
+               for (i = 0; i < level; i++)
+                       printf("\t");
+
+               SDP_GET8(type, start);
+
+               switch (type) {
+               case SDP_DATA_NIL:
+                       printf("nil\n");
+                       break;
+
+               case SDP_DATA_UINT8:
+                       SDP_GET8(value.uint8, start);
+                       printf("uint8 %u\n", value.uint8);
+                       break;
+               case SDP_DATA_UINT16:
+                       SDP_GET16(value.uint16, start);
+                       printf("uint16 %u\n", value.uint16);
+                       break;
+               case SDP_DATA_UINT32:
+                       SDP_GET32(value.uint32, start);
+                       printf("uint32 %u\n", value.uint32);
+                       break;
+               case SDP_DATA_UINT64:
+                       SDP_GET64(value.uint64, start);
+                       printf("uint64 %ju\n", value.uint64);
+                       break;
+
+               case SDP_DATA_UINT128:
+               case SDP_DATA_INT128:
+                       SDP_GET128(&value.int128, start);
+                       printf("u/int128 0x"
+                               "%2.2x%2.2x%2.2x%2.2x"
+                               "%2.2x%2.2x%2.2x%2.2x"
+                               "%2.2x%2.2x%2.2x%2.2x"
+                               "%2.2x%2.2x%2.2x%2.2x\n",
+                               value.int128.b[ 0], value.int128.b[ 1],
+                               value.int128.b[ 2], value.int128.b[ 3],
+                               value.int128.b[ 4], value.int128.b[ 5],
+                               value.int128.b[ 6], value.int128.b[ 7],
+                               value.int128.b[ 8], value.int128.b[ 9],
+                               value.int128.b[10], value.int128.b[11],
+                               value.int128.b[12], value.int128.b[13],
+                               value.int128.b[14], value.int128.b[15]);
+                       break;
+
+               case SDP_DATA_UUID128:
+                       SDP_GET_UUID128(&value.int128, start);
+                       printf("uuid128 0x"
+                               "%2.2x%2.2x%2.2x%2.2x-"
+                               "%2.2x%2.2x-"
+                               "%2.2x%2.2x-"
+                               "%2.2x%2.2x-"
+                               "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+                               value.int128.b[ 0], value.int128.b[ 1],
+                               value.int128.b[ 2], value.int128.b[ 3],
+                               value.int128.b[ 4], value.int128.b[ 5],
+                               value.int128.b[ 6], value.int128.b[ 7],
+                               value.int128.b[ 8], value.int128.b[ 9],
+                               value.int128.b[10], value.int128.b[11],
+                               value.int128.b[12], value.int128.b[13],
+                               value.int128.b[14], value.int128.b[15]);
+                       break;
+
+               case SDP_DATA_INT8:
+                       SDP_GET8(value.int8, start);
+                       printf("int8 %d\n", value.int8);
+                       break;
+               case SDP_DATA_INT16:
+                       SDP_GET16(value.int16, start);
+                       printf("int16 %d\n", value.int16);
+                       break;
+               case SDP_DATA_INT32:
+                       SDP_GET32(value.int32, start);
+                       printf("int32 %d\n", value.int32);
+                       break;
+               case SDP_DATA_INT64:
+                       SDP_GET64(value.int64, start);
+                       printf("int64 %ju\n", value.int64);
+                       break;
+
+               case SDP_DATA_UUID16:
+                       SDP_GET16(value.uint16, start);
+                       printf("uuid16 %#4.4x - %s\n", value.uint16,
+                               sdp_uuid2desc(value.uint16));
+                       break;
+               case SDP_DATA_UUID32:
+                       SDP_GET32(value.uint32, start);
+                       printf("uuid32 %#8.8x\n", value.uint32);
+                       break;
+
+               case SDP_DATA_STR8:
+                       SDP_GET8(value.uint8, start);
+                       printf("str8 %*.*s\n", value.uint8, value.uint8, start);
+                       start += value.uint8;
+                       break;
+               case SDP_DATA_STR16:
+                       SDP_GET16(value.uint16, start);
+                       printf("str16 %*.*s\n", value.uint16, value.uint16, start);
+                       start += value.uint16;
+                       break;
+               case SDP_DATA_STR32:
+                       SDP_GET32(value.uint32, start);
+                       printf("str32 %*.*s\n", value.uint32, value.uint32, start);
+                       start += value.uint32;
+                       break;
+
+               case SDP_DATA_BOOL:
+                       SDP_GET8(value.uint8, start);
+                       printf("bool %d\n", value.uint8);
+                       break;
+
+               case SDP_DATA_SEQ8:
+                       SDP_GET8(value.uint8, start);
+                       printf("seq8 %d\n", value.uint8);
+                       sdp_print(level + 1, start, start + value.uint8);
+                       start += value.uint8;
+                       break;
+               case SDP_DATA_SEQ16:
+                       SDP_GET16(value.uint16, start);
+                       printf("seq16 %d\n", value.uint16);
+                       sdp_print(level + 1, start, start + value.uint16);
+                       start += value.uint16;
+                       break;
+               case SDP_DATA_SEQ32:
+                       SDP_GET32(value.uint32, start);
+                       printf("seq32 %d\n", value.uint32);
+                       sdp_print(level + 1, start, start + value.uint32);
+                       start += value.uint32;
+                       break;
+
+               case SDP_DATA_ALT8:
+                       SDP_GET8(value.uint8, start);
+                       printf("alt8 %d\n", value.uint8);
+                       sdp_print(level + 1, start, start + value.uint8);
+                       start += value.uint8;
+                       break;
+               case SDP_DATA_ALT16:
+                       SDP_GET16(value.uint16, start);
+                       printf("alt16 %d\n", value.uint16);
+                       sdp_print(level + 1, start, start + value.uint16);
+                       start += value.uint16;
+                       break;
+               case SDP_DATA_ALT32:
+                       SDP_GET32(value.uint32, start);
+                       printf("alt32 %d\n", value.uint32);
+                       sdp_print(level + 1, start, start + value.uint32);
+                       start += value.uint32;
+                       break;
+
+               case SDP_DATA_URL8:
+                       SDP_GET8(value.uint8, start);
+                       printf("url8 %*.*s\n", value.uint8, value.uint8, start);
+                       start += value.uint8;
+                       break;
+               case SDP_DATA_URL16:
+                       SDP_GET16(value.uint16, start);
+                       printf("url16 %*.*s\n", value.uint16, value.uint16, start);
+                       start += value.uint16;
+                       break;
+               case SDP_DATA_URL32:
+                       SDP_GET32(value.uint32, start);
+                       printf("url32 %*.*s\n", value.uint32, value.uint32, start);
+                       start += value.uint32;
+                       break;
+
+               default:
+                       printf("unknown data type: %#02x\n", *start ++);
+                       break;
+               }
+       }
+}