Add sdpd(8) (Bluetooth Service Discovery Protocol daemon) and sdpquery(1)
authorHasso Tepper <hasso@dragonflybsd.org>
Sun, 6 Jan 2008 21:51:30 +0000 (21:51 +0000)
committerHasso Tepper <hasso@dragonflybsd.org>
Sun, 6 Jan 2008 21:51:30 +0000 (21:51 +0000)
(SDP query utility). Also add btconfig rc script in progress.

Obtained-from: NetBSD

42 files changed:
etc/Makefile
etc/group
etc/master.passwd
etc/rc.d/Makefile
etc/rc.d/btconfig [new file with mode: 0644]
etc/rc.d/sdpd [new file with mode: 0644]
usr.sbin/Makefile
usr.sbin/sdpd/Makefile [new file with mode: 0644]
usr.sbin/sdpd/bgd.c [new file with mode: 0644]
usr.sbin/sdpd/dun.c [new file with mode: 0644]
usr.sbin/sdpd/ftrn.c [new file with mode: 0644]
usr.sbin/sdpd/hf.c [new file with mode: 0644]
usr.sbin/sdpd/hset.c [new file with mode: 0644]
usr.sbin/sdpd/irmc.c [new file with mode: 0644]
usr.sbin/sdpd/irmc_command.c [new file with mode: 0644]
usr.sbin/sdpd/lan.c [new file with mode: 0644]
usr.sbin/sdpd/log.c [new file with mode: 0644]
usr.sbin/sdpd/log.h [new file with mode: 0644]
usr.sbin/sdpd/main.c [new file with mode: 0644]
usr.sbin/sdpd/opush.c [new file with mode: 0644]
usr.sbin/sdpd/profile.c [new file with mode: 0644]
usr.sbin/sdpd/profile.h [new file with mode: 0644]
usr.sbin/sdpd/provider.c [new file with mode: 0644]
usr.sbin/sdpd/provider.h [new file with mode: 0644]
usr.sbin/sdpd/sar.c [new file with mode: 0644]
usr.sbin/sdpd/scr.c [new file with mode: 0644]
usr.sbin/sdpd/sd.c [new file with mode: 0644]
usr.sbin/sdpd/sdpd.8 [new file with mode: 0644]
usr.sbin/sdpd/server.c [new file with mode: 0644]
usr.sbin/sdpd/server.h [new file with mode: 0644]
usr.sbin/sdpd/sp.c [new file with mode: 0644]
usr.sbin/sdpd/srr.c [new file with mode: 0644]
usr.sbin/sdpd/ssar.c [new file with mode: 0644]
usr.sbin/sdpd/ssr.c [new file with mode: 0644]
usr.sbin/sdpd/sur.c [new file with mode: 0644]
usr.sbin/sdpd/uuid-private.h [new file with mode: 0644]
usr.sbin/sdpd/uuid.c [new file with mode: 0644]
usr.sbin/sdpquery/Makefile [new file with mode: 0644]
usr.sbin/sdpquery/sdpquery.1 [new file with mode: 0644]
usr.sbin/sdpquery/sdpquery.c [new file with mode: 0644]
usr.sbin/sdpquery/sdpquery.h [new file with mode: 0644]
usr.sbin/sdpquery/search.c [new file with mode: 0644]

index 87195c0..1f58a5b 100644 (file)
@@ -1,6 +1,6 @@
 #      from: @(#)Makefile      5.11 (Berkeley) 5/21/91
 # $FreeBSD: src/etc/Makefile,v 1.219.2.38 2003/03/04 09:49:00 ru Exp $
-# $DragonFly: src/etc/Makefile,v 1.201 2008/01/03 13:35:20 hasso Exp $
+# $DragonFly: src/etc/Makefile,v 1.202 2008/01/06 21:51:30 hasso Exp $
 
 .if !defined(NO_SENDMAIL)
 SUBDIR=        sendmail
@@ -101,12 +101,18 @@ preupgrade:
                pw -V ${DESTDIR}/etc useradd _ntp -u 65 \
                   -c "ntpd privsep user" \
                   -d /var/empty -s /sbin/nologin
+       (pw -V ${DESTDIR}/etc usershow _sdpd -q > /dev/null) || \
+               pw -V ${DESTDIR}/etc useradd _sdpd -u 70 \
+                  -c "sdpd privsep user" \
+                  -d /var/empty -s /sbin/nologin
        (pw -V ${DESTDIR}/etc groupshow authpf -q > /dev/null) || \
                pw -V ${DESTDIR}/etc groupadd authpf -g 63
        (pw -V ${DESTDIR}/etc groupshow _pflogd -q > /dev/null) || \
                pw -V ${DESTDIR}/etc groupadd _pflogd -g 64
        (pw -V ${DESTDIR}/etc groupshow _ntp -q > /dev/null) || \
                pw -V ${DESTDIR}/etc groupadd _ntp -g 65
+       (pw -V ${DESTDIR}/etc groupshow _sdpd -q > /dev/null) || \
+               pw -V ${DESTDIR}/etc groupadd _sdpd -g 70
 
 upgrade_etc:   preupgrade
 .if !defined(BINARY_UPGRADE) # binary upgrade just copies these files
index 6a8ab87..d54ee08 100644 (file)
--- a/etc/group
+++ b/etc/group
@@ -1,5 +1,5 @@
 # $FreeBSD: src/etc/group,v 1.19.2.3 2002/06/30 17:57:17 des Exp $
-# $DragonFly: src/etc/group,v 1.4 2004/11/12 09:37:25 joerg Exp $
+# $DragonFly: src/etc/group,v 1.5 2008/01/06 21:51:30 hasso Exp $
 #
 wheel:*:0:root
 daemon:*:1:daemon
@@ -26,6 +26,7 @@ uucp:*:66:
 xten:*:67:xten
 dialer:*:68:
 network:*:69:
+_sdpd:*:70:
 www:*:80:
 nogroup:*:65533:
 nobody:*:65534:
index 7485ac2..9b75aee 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/etc/master.passwd,v 1.25.2.6 2002/06/30 17:57:17 des Exp $
-# $DragonFly: src/etc/master.passwd,v 1.4 2004/11/12 09:37:25 joerg Exp $
+# $DragonFly: src/etc/master.passwd,v 1.5 2008/01/06 21:51:30 hasso Exp $
 #
 root::0:0::0:0:Charlie &:/root:/bin/csh
 toor:*:0:0::0:0:Bourne-again Superuser:/root:
@@ -21,5 +21,6 @@ _ntp:*:65:65::0:0:ntpd privsep user:/var/empty:/sbin/nologin
 uucp:*:66:66::0:0:UUCP pseudo-user:/var/spool/uucppublic:/usr/libexec/uucp/uucico
 xten:*:67:67::0:0:X-10 daemon:/usr/local/xten:/sbin/nologin
 pop:*:68:6::0:0:Post Office Owner:/nonexistent:/sbin/nologin
+_sdpd:*:70:70::0:0:sdpd privsep user:/var/empty:/sbin/nologin
 www:*:80:80::0:0:World Wide Web Owner:/nonexistent:/sbin/nologin
 nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/sbin/nologin
index eecc384..da9e633 100644 (file)
@@ -1,6 +1,6 @@
 # $NetBSD: Makefile,v 1.16 2001/01/14 15:37:22 minoura Exp $
 # $FreeBSD: src/etc/rc.d/Makefile,v 1.20 2003/06/29 05:15:57 mtm Exp $
-# $DragonFly: src/etc/rc.d/Makefile,v 1.23 2007/10/02 12:57:00 hasso Exp $
+# $DragonFly: src/etc/rc.d/Makefile,v 1.24 2008/01/06 21:51:30 hasso Exp $
 
 .include <bsd.own.mk>
 
@@ -8,7 +8,7 @@
 #
 FILES= DAEMON LOGIN NETWORKING SERVERS abi accounting addswap adjkerntz \
        amd apm apmd atm1 atm2.sh atm3.sh \
-       battd bootconf bootparams ccd cleanvar \
+       battd bootconf bootparams btconfig ccd cleanvar \
        cleartmp cron dhclient dhcpd dhcrelay diskless dmesg dumpon \
        fsck ftpd hostapd hostname \
        inetd initdiskless initrandom ip6fw ipfilter ipfs ipfw ipmon \
@@ -21,9 +21,9 @@ FILES=        DAEMON LOGIN NETWORKING SERVERS abi accounting addswap adjkerntz \
        network_ipv6 nfsclient nfsd nfslocking nfsserver nisdomain ntpd \
        dntpd othermta pf pflog ppp ppp-user pppoed pwcheck \
        quota random rarpd rcconf.sh resident rndcontrol root route6d routed \
-       routing rpcbind rtadvd rtsold rwho sysdb savecore securelevel sendmail \
-       sensorsd serial sppp sshd swap1 syscons sysctl syslogd timed ttys usbd \
-       varsym vinum virecover watchdogd wpa_supplicant \
+       routing rpcbind rtadvd rtsold rwho sysdb savecore sdpd securelevel \
+       sendmail sensorsd serial sppp sshd swap1 syscons sysctl syslogd \
+       timed ttys usbd varsym vinum virecover watchdogd wpa_supplicant \
        ypbind yppasswdd ypserv ypset ypupdated ypxfrd
 FILESDIR=      /etc/rc.d
 FILESMODE=     ${BINMODE}
diff --git a/etc/rc.d/btconfig b/etc/rc.d/btconfig
new file mode 100644 (file)
index 0000000..7c85098
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/sh
+#
+# $NetBSD: btconfig,v 1.1 2006/06/19 15:44:36 gdamore Exp $
+# $DragonFly: src/etc/rc.d/btconfig,v 1.1 2008/01/06 21:51:30 hasso Exp $
+
+# PROVIDE: bluetooth
+# REQUIRE: DAEMON
+# BEFORE:  LOGIN
+
+$_rc_subr_loaded . /etc/rc.subr
+
+name="btconfig"
+rcvar=${name}
+command="/usr/sbin/${name}"
+start_cmd="btconfig_start"
+stop_cmd="btconfig_stop"
+status_cmd="btconfig_status"
+
+btconfig_start()
+{
+       echo -n 'Configuring Bluetooth controllers:'
+
+       #
+       # Configure Bluetooth controllers.
+       #
+       # If ${btconfig_devices} is set, it should be a list of devices to
+       # configure. Otherwise, all available devices will be configured.
+       #
+       # If ${btconfig_<dev>} is set, it will be used as the parameter
+       # list for btconfig. Otherwise ${btconfig_args} will be used or
+       # if that is not set, the default string "enable" will be used.
+       #
+
+       devs="${btconfig_devices:-$(${command} -l)}"
+       for dev in ${devs}; do
+               eval args="\$btconfig_${dev}"
+               if [ -z "${args}" ]; then
+                       args="${btconfig_args:-enable}"
+               fi
+
+               echo -n " ${dev}"
+               ${command} ${dev} ${args}
+       done
+
+       echo '.'
+}
+
+btconfig_stop()
+{
+       echo -n 'Disabling Bluetooth controllers:'
+
+       devs="${btconfig_devices:-$(${command} -l)}"
+       for dev in ${devs}; do
+               echo -n " ${dev}"
+               ${command} ${dev} disable
+       done
+
+       echo '.'
+}
+
+btconfig_status()
+{
+       ${command}
+}
+
+load_rc_config ${name}
+run_rc_command "$1"
diff --git a/etc/rc.d/sdpd b/etc/rc.d/sdpd
new file mode 100644 (file)
index 0000000..6888930
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# $NetBSD: sdpd,v 1.2 2007/03/18 15:53:54 plunky Exp $
+# $DragonFly: src/etc/rc.d/sdpd,v 1.1 2008/01/06 21:51:30 hasso Exp $
+
+# PROVIDE: sdpd
+# REQUIRE: bluetooth
+# BEFORE: LOGIN
+
+$rc_subr_loaded . /etc/rc.subr
+
+name="sdpd"
+rcvar=$name
+command="/usr/sbin/${name}"
+
+load_rc_config $name
+run_rc_command "$1"
index 1d1f5ad..a33b7b8 100644 (file)
@@ -1,6 +1,6 @@
 #      From: @(#)Makefile      5.20 (Berkeley) 6/12/93
 # $FreeBSD: src/usr.sbin/Makefile,v 1.183.2.14 2003/04/16 11:01:51 ru Exp $
-# $DragonFly: src/usr.sbin/Makefile,v 1.36 2008/01/04 09:54:22 hasso Exp $
+# $DragonFly: src/usr.sbin/Makefile,v 1.37 2008/01/06 21:51:30 hasso Exp $
 
 .include "../sys/platform/${MACHINE_PLATFORM}/Makefile.inc"
 
@@ -109,6 +109,8 @@ SUBDIR= 802_11 \
        rtsold \
        rwhod \
        sa \
+       sdpd \
+       sdpquery \
        sensorsd \
        setkey \
        sliplogin \
diff --git a/usr.sbin/sdpd/Makefile b/usr.sbin/sdpd/Makefile
new file mode 100644 (file)
index 0000000..a09437a
--- /dev/null
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.3 2007/05/28 12:06:41 tls Exp $
+# $DragonFly: src/usr.sbin/sdpd/Makefile,v 1.1 2008/01/06 21:51:30 hasso Exp $
+
+PROG=          sdpd
+MAN=           sdpd.8
+SRCS=          bgd.c dun.c ftrn.c hf.c hset.c irmc.c irmc_command.c lan.c \
+               log.c main.c opush.c profile.c provider.c sar.c scr.c \
+               sd.c server.c sp.c srr.c ssar.c ssr.c sur.c uuid.c
+
+CFLAGS+=       -I${.CURDIR}/../../sys
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sdpd/bgd.c b/usr.sbin/sdpd/bgd.c
new file mode 100644 (file)
index 0000000..a29734e
--- /dev/null
@@ -0,0 +1,109 @@
+/* $NetBSD: bgd.c,v 1.2 2007/11/09 20:08:40 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/bgd.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * bgd.c
+ *
+ * Copyright (c) 2004 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: bgd.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/bgd.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+
+static int32_t
+bgd_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+bgd_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "Public Browse Group Root";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+bgd_profile_create_group_id(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       if (buf + 3 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_UUID16, buf);
+       SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf);
+
+       return (3);
+}
+
+static attr_t  bgd_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         bgd_profile_create_service_class_id_list },
+       { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+         common_profile_create_language_base_attribute_id_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         bgd_profile_create_service_name },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
+         bgd_profile_create_service_name },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
+         common_profile_create_service_provider_name },
+       { SDP_ATTR_GROUP_ID,
+         bgd_profile_create_group_id },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t        bgd_profile_uuids[] = {
+       SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR,
+};
+
+profile_t      bgd_profile_descriptor = {
+       bgd_profile_uuids,
+       sizeof(bgd_profile_uuids),
+       0,
+       (profile_data_valid_p) NULL,
+       (attr_t const * const) &bgd_profile_attrs
+};
diff --git a/usr.sbin/sdpd/dun.c b/usr.sbin/sdpd/dun.c
new file mode 100644 (file)
index 0000000..980b66c
--- /dev/null
@@ -0,0 +1,146 @@
+/* $NetBSD: dun.c,v 1.2 2007/11/09 20:08:40 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/dun.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * dun.c
+ *
+ * Copyright (c) 2004 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: dun.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/dun.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+dun_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_DIALUP_NETWORKING
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+dun_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t profile_descriptor_list[] = {
+               SDP_SERVICE_CLASS_DIALUP_NETWORKING,
+               0x0100
+       };
+
+       return (common_profile_create_bluetooth_profile_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) profile_descriptor_list,
+                       sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+dun_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "DialUp networking";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+dun_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_dun_profile_p       dun = (sdp_dun_profile_p) provider->data;
+
+       return (rfcomm_profile_create_protocol_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) &dun->server_channel, 1));
+}
+
+static int32_t
+dun_profile_create_audio_feedback_support(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_dun_profile_p       dun = (sdp_dun_profile_p) provider->data;
+
+       if (buf + 2 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_BOOL, buf);
+       SDP_PUT8(dun->audio_feedback_support, buf);
+
+       return (2);
+}
+
+static attr_t  dun_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         dun_profile_create_service_class_id_list },
+       { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+         dun_profile_create_bluetooth_profile_descriptor_list },
+       { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+         common_profile_create_language_base_attribute_id_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         dun_profile_create_service_name },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         dun_profile_create_protocol_descriptor_list },
+       { SDP_ATTR_AUDIO_FEEDBACK_SUPPORT,
+         dun_profile_create_audio_feedback_support },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t dun_profile_uuids[] = {
+       SDP_SERVICE_CLASS_DIALUP_NETWORKING,
+       SDP_SERVICE_CLASS_GENERIC_NETWORKING,
+       SDP_UUID_PROTOCOL_L2CAP,
+       SDP_UUID_PROTOCOL_RFCOMM,
+};
+
+profile_t      dun_profile_descriptor = {
+       dun_profile_uuids,
+       sizeof(dun_profile_uuids),
+       sizeof(sdp_dun_profile_t),
+       common_profile_server_channel_valid,
+       (attr_t const * const) &dun_profile_attrs
+};
diff --git a/usr.sbin/sdpd/ftrn.c b/usr.sbin/sdpd/ftrn.c
new file mode 100644 (file)
index 0000000..828efdf
--- /dev/null
@@ -0,0 +1,127 @@
+/* $NetBSD: ftrn.c,v 1.2 2007/11/09 20:08:40 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/ftrn.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * ftrn.c
+ *
+ * Copyright (c) 2004 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: ftrn.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/ftrn.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+ftrn_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+ftrn_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t profile_descriptor_list[] = {
+               SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
+               0x0100
+       };
+
+       return (common_profile_create_bluetooth_profile_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) profile_descriptor_list,
+                       sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+ftrn_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "OBEX File Transfer";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+ftrn_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_ftrn_profile_p      ftrn = (sdp_ftrn_profile_p) provider->data;
+
+       return (obex_profile_create_protocol_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) &ftrn->server_channel, 1));
+}
+
+static attr_t  ftrn_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         ftrn_profile_create_service_class_id_list },
+       { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+         ftrn_profile_create_bluetooth_profile_descriptor_list },
+       { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+         common_profile_create_language_base_attribute_id_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         ftrn_profile_create_service_name },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         ftrn_profile_create_protocol_descriptor_list },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t ftrn_profile_uuids[] = {
+       SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
+       SDP_UUID_PROTOCOL_L2CAP,
+       SDP_UUID_PROTOCOL_RFCOMM,
+       SDP_UUID_PROTOCOL_OBEX,
+};
+
+profile_t      ftrn_profile_descriptor = {
+       ftrn_profile_uuids,
+       sizeof(ftrn_profile_uuids),
+       sizeof(sdp_ftrn_profile_t),
+       common_profile_server_channel_valid,
+       (attr_t const * const) &ftrn_profile_attrs
+};
diff --git a/usr.sbin/sdpd/hf.c b/usr.sbin/sdpd/hf.c
new file mode 100644 (file)
index 0000000..3d3ccbd
--- /dev/null
@@ -0,0 +1,162 @@
+/* $NetBSD: hf.c,v 1.2 2007/11/09 20:08:40 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/hf.c,v 1.1 2008/01/06 21:51:30 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/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <netbt/rfcomm.h>
+
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+hf_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_HANDSFREE,
+               SDP_SERVICE_CLASS_GENERIC_AUDIO,
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+hf_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_hf_profile_t        *hf = (sdp_hf_profile_t *) provider->data;
+
+       return (rfcomm_profile_create_protocol_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) &hf->server_channel, 1));
+}
+
+static int32_t
+hf_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t profile_descriptor_list[] = {
+               SDP_SERVICE_CLASS_HANDSFREE,
+               0x0105
+       };
+
+       return (common_profile_create_bluetooth_profile_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) profile_descriptor_list,
+                       sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+hf_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "Hands-Free unit";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+hf_profile_create_supported_features(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_hf_profile_t        *hf = (sdp_hf_profile_t *) provider->data;
+
+       if (buf + 3 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_UINT16, buf);
+       SDP_PUT16(hf->supported_features, buf);
+
+       return (3);
+}
+
+static int32_t
+hf_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+       sdp_hf_profile_t const *hf = (sdp_hf_profile_t const *) data;
+
+       if (hf->server_channel < RFCOMM_CHANNEL_MIN
+           || hf->server_channel > RFCOMM_CHANNEL_MAX
+           || (hf->supported_features & ~0x001f))
+               return 0;
+
+       return 1;
+}
+
+static attr_t  hf_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         hf_profile_create_service_class_id_list },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         hf_profile_create_protocol_descriptor_list },
+       { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+         hf_profile_create_bluetooth_profile_descriptor_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         hf_profile_create_service_name },
+       { SDP_ATTR_SUPPORTED_FEATURES,
+         hf_profile_create_supported_features },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t        hf_profile_uuids[] = {
+       SDP_SERVICE_CLASS_HANDSFREE,
+       SDP_SERVICE_CLASS_GENERIC_AUDIO,
+       SDP_UUID_PROTOCOL_L2CAP,
+       SDP_UUID_PROTOCOL_RFCOMM,
+};
+
+profile_t      hf_profile_descriptor = {
+       hf_profile_uuids,
+       sizeof(hf_profile_uuids),
+       sizeof(sdp_hf_profile_t),
+       hf_profile_data_valid,
+       (attr_t const * const) &hf_profile_attrs
+};
diff --git a/usr.sbin/sdpd/hset.c b/usr.sbin/sdpd/hset.c
new file mode 100644 (file)
index 0000000..d33e42e
--- /dev/null
@@ -0,0 +1,143 @@
+/* $NetBSD: hset.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/hset.c,v 1.1 2008/01/06 21:51:30 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/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <netbt/rfcomm.h>
+
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+hset_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY,
+               SDP_SERVICE_CLASS_GENERIC_AUDIO,
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+hset_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_hset_profile_t      *hset = (sdp_hset_profile_t *) provider->data;
+
+       return (rfcomm_profile_create_protocol_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) &hset->server_channel, 1));
+}
+
+static int32_t
+hset_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t profile_descriptor_list[] = {
+               SDP_SERVICE_CLASS_HEADSET,
+               0x0100
+       };
+
+       return (common_profile_create_bluetooth_profile_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) profile_descriptor_list,
+                       sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+hset_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "Voice Gateway";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+hset_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+       sdp_hset_profile_t const *hset = (sdp_hset_profile_t const *) data;
+
+       if (hset->server_channel < RFCOMM_CHANNEL_MIN
+           || hset->server_channel > RFCOMM_CHANNEL_MAX)
+               return 0;
+
+       return 1;
+}
+
+static attr_t  hset_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         hset_profile_create_service_class_id_list },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         hset_profile_create_protocol_descriptor_list },
+       { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+         hset_profile_create_bluetooth_profile_descriptor_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         hset_profile_create_service_name },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t hset_profile_uuids[] = {
+       SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY,
+       SDP_SERVICE_CLASS_GENERIC_AUDIO,
+       SDP_UUID_PROTOCOL_L2CAP,
+       SDP_UUID_PROTOCOL_RFCOMM,
+       SDP_SERVICE_CLASS_HEADSET,
+};
+
+profile_t      hset_profile_descriptor = {
+       hset_profile_uuids,
+       sizeof(hset_profile_uuids),
+       sizeof(sdp_hset_profile_t),
+       hset_profile_data_valid,
+       (attr_t const * const) &hset_profile_attrs
+};
diff --git a/usr.sbin/sdpd/irmc.c b/usr.sbin/sdpd/irmc.c
new file mode 100644 (file)
index 0000000..2b78887
--- /dev/null
@@ -0,0 +1,143 @@
+/* $NetBSD: irmc.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/irmc.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * irmc.c
+ *
+ * Copyright (c) 2004 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: irmc.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/irmc.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+irmc_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_IR_MC_SYNC
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+irmc_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t profile_descriptor_list[] = {
+               SDP_SERVICE_CLASS_IR_MC_SYNC,
+               0x0100
+       };
+
+       return (common_profile_create_bluetooth_profile_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) profile_descriptor_list,
+                       sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+irmc_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "IrMC Synchronization";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+irmc_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_irmc_profile_p      irmc = (sdp_irmc_profile_p) provider->data;
+
+       return (obex_profile_create_protocol_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) &irmc->server_channel, 1));
+}
+
+static int32_t
+irmc_profile_create_supported_formats_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_irmc_profile_p      irmc = (sdp_irmc_profile_p) provider->data;
+
+       return (obex_profile_create_supported_formats_list(
+                       buf, eob,
+                       (uint8_t const *) irmc->supported_formats,
+                       irmc->supported_formats_size));
+}
+
+static attr_t  irmc_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         irmc_profile_create_service_class_id_list },
+       { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+         irmc_profile_create_bluetooth_profile_descriptor_list },
+       { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+         common_profile_create_language_base_attribute_id_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         irmc_profile_create_service_name },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         irmc_profile_create_protocol_descriptor_list },
+       { SDP_ATTR_SUPPORTED_FORMATS_LIST,
+         irmc_profile_create_supported_formats_list },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t irmc_profile_uuids[] = {
+       SDP_SERVICE_CLASS_IR_MC_SYNC,
+       SDP_UUID_PROTOCOL_L2CAP,
+       SDP_UUID_PROTOCOL_RFCOMM,
+       SDP_UUID_PROTOCOL_OBEX,
+};
+
+profile_t      irmc_profile_descriptor = {
+       irmc_profile_uuids,
+       sizeof(irmc_profile_uuids),
+       sizeof(sdp_irmc_profile_t),
+       obex_profile_data_valid,
+       (attr_t const * const) &irmc_profile_attrs
+};
diff --git a/usr.sbin/sdpd/irmc_command.c b/usr.sbin/sdpd/irmc_command.c
new file mode 100644 (file)
index 0000000..801bb19
--- /dev/null
@@ -0,0 +1,127 @@
+/* $NetBSD: irmc_command.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/irmc_command.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * irmc_command_command_command.c
+ *
+ * Copyright (c) 2004 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: irmc_command.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/irmc_command.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+irmc_command_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+irmc_command_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t profile_descriptor_list[] = {
+               SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,
+               0x0100
+       };
+
+       return (common_profile_create_bluetooth_profile_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) profile_descriptor_list,
+                       sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+irmc_command_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "Sync Command Service";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+irmc_command_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const                *provider = (provider_t const *) data;
+       sdp_irmc_command_profile_p      irmc_command = (sdp_irmc_command_profile_p) provider->data;
+
+       return (obex_profile_create_protocol_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) &irmc_command->server_channel, 1));
+}
+
+static attr_t  irmc_command_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         irmc_command_profile_create_service_class_id_list },
+       { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+         irmc_command_profile_create_bluetooth_profile_descriptor_list },
+       { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+         common_profile_create_language_base_attribute_id_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         irmc_command_profile_create_service_name },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         irmc_command_profile_create_protocol_descriptor_list },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t        irmc_command_profile_uuids[] = {
+       SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,
+       SDP_UUID_PROTOCOL_L2CAP,
+       SDP_UUID_PROTOCOL_RFCOMM,
+       SDP_UUID_PROTOCOL_OBEX,
+};
+
+profile_t      irmc_command_profile_descriptor = {
+       irmc_command_profile_uuids,
+       sizeof(irmc_command_profile_uuids),
+       sizeof(sdp_irmc_command_profile_t),
+       common_profile_server_channel_valid,
+       (attr_t const * const) &irmc_command_profile_attrs
+};
diff --git a/usr.sbin/sdpd/lan.c b/usr.sbin/sdpd/lan.c
new file mode 100644 (file)
index 0000000..1cd054f
--- /dev/null
@@ -0,0 +1,186 @@
+/* $NetBSD: lan.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/lan.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * lan.c
+ *
+ * Copyright (c) 2004 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: lan.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/lan.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <arpa/inet.h>
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+lan_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+lan_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t profile_descriptor_list[] = {
+               SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
+               0x0100
+       };
+
+       return (common_profile_create_bluetooth_profile_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) profile_descriptor_list,
+                       sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+lan_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "LAN Access using PPP";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+lan_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_lan_profile_p       lan = (sdp_lan_profile_p) provider->data;
+
+       return (rfcomm_profile_create_protocol_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) &lan->server_channel, 1));
+}
+
+static int32_t
+lan_profile_create_service_availability(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_lan_profile_p       lan = (sdp_lan_profile_p) provider->data;
+
+       if (buf + 2 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_UINT8, buf);
+       SDP_PUT8(lan->load_factor, buf);
+
+       return (2);
+}
+
+static int32_t
+lan_profile_create_ip_subnet(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_lan_profile_p       lan = (sdp_lan_profile_p) provider->data;
+       char                    net[32];
+       int32_t                 len;
+
+       len = snprintf(net, sizeof(net), "%s/%d",
+                       inet_ntoa(* (struct in_addr *) &lan->ip_subnet),
+                       lan->ip_subnet_radius);
+
+       if (len < 0 || buf + 2 + len > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_STR8, buf);
+       SDP_PUT8(len, buf);
+       memcpy(buf, net, len);
+
+       return (2 + len);
+}
+
+static int32_t
+lan_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+       sdp_lan_profile_t const *lan = (sdp_lan_profile_t const *) data;
+
+       if (lan->server_channel < 1 ||
+           lan->server_channel > 30 ||
+           lan->ip_subnet_radius > 32)
+               return (0);
+
+       return (1);
+}
+
+static attr_t  lan_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         lan_profile_create_service_class_id_list },
+       { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+         lan_profile_create_bluetooth_profile_descriptor_list },
+       { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+         common_profile_create_language_base_attribute_id_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         lan_profile_create_service_name },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         lan_profile_create_protocol_descriptor_list },
+       { SDP_ATTR_SERVICE_AVAILABILITY,
+         lan_profile_create_service_availability },
+       { SDP_ATTR_IP_SUBNET,
+         lan_profile_create_ip_subnet },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t lan_profile_uuids[] = {
+       SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
+       SDP_UUID_PROTOCOL_L2CAP,
+       SDP_UUID_PROTOCOL_RFCOMM,
+};
+
+profile_t      lan_profile_descriptor = {
+       lan_profile_uuids,
+       sizeof(lan_profile_uuids),
+       sizeof(sdp_lan_profile_t),
+       lan_profile_data_valid,
+       (attr_t const * const) &lan_profile_attrs
+};
diff --git a/usr.sbin/sdpd/log.c b/usr.sbin/sdpd/log.c
new file mode 100644 (file)
index 0000000..33f9bf1
--- /dev/null
@@ -0,0 +1,131 @@
+/* $NetBSD: log.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/log.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * log.c
+ *
+ * Copyright (c) 2004 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: log.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/log.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include "log.h"
+
+void
+log_open(char const *prog, int32_t log2stderr)
+{
+       openlog(prog, LOG_PID|LOG_NDELAY|(log2stderr? LOG_PERROR:0), LOG_USER);
+}
+
+void
+log_close(void)
+{
+       closelog();
+}
+
+void
+log_emerg(char const *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_EMERG, message, ap);
+       va_end(ap);
+}
+
+void
+log_alert(char const *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_ALERT, message, ap);
+       va_end(ap);
+}
+
+void
+log_crit(char const *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_CRIT, message, ap);
+       va_end(ap);
+}
+
+void
+log_err(char const *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_ERR, message, ap);
+       va_end(ap);
+}
+
+void
+log_warning(char const *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_WARNING, message, ap);
+       va_end(ap);
+}
+
+void
+log_notice(char const *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_NOTICE, message, ap);
+       va_end(ap);
+}
+
+void
+log_info(char const *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_INFO, message, ap);
+       va_end(ap);
+}
+
+void
+log_debug(char const *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_DEBUG, message, ap);
+       va_end(ap);
+}
diff --git a/usr.sbin/sdpd/log.h b/usr.sbin/sdpd/log.h
new file mode 100644 (file)
index 0000000..a53d9b2
--- /dev/null
@@ -0,0 +1,49 @@
+/* $NetBSD: log.h,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/log.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * log.h
+ *
+ * Copyright (c) 2004 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: log.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/log.h,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+void   log_open        (char const *prog, int32_t log2stderr);
+void   log_close       (void);
+void   log_emerg       (char const *message, ...);
+void   log_alert       (char const *message, ...);
+void   log_crit        (char const *message, ...);
+void   log_err         (char const *message, ...);
+void   log_warning     (char const *message, ...);
+void   log_notice      (char const *message, ...);
+void   log_info        (char const *message, ...);
+void   log_debug       (char const *message, ...);
+
+#endif /* ndef _LOG_H_ */
diff --git a/usr.sbin/sdpd/main.c b/usr.sbin/sdpd/main.c
new file mode 100644 (file)
index 0000000..50da99a
--- /dev/null
@@ -0,0 +1,243 @@
+/* $NetBSD: main.c,v 1.3 2007/03/18 15:53:55 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/main.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * main.c
+ *
+ * Copyright (c) 2004 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: main.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/main.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/select.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "log.h"
+#include "server.h"
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/queue.h>
+#include "profile.h"
+#include "provider.h"
+
+#define        SDPD                    "sdpd"
+
+static int32_t drop_root       (char const *user, char const *group);
+static void    sighandler      (int32_t s);
+static void    usage           (void);
+
+static int32_t done;
+
+/*
+ * Bluetooth Service Discovery Procotol (SDP) daemon
+ */
+
+int
+main(int argc, char *argv[])
+{
+       server_t                 server;
+       char const              *control = SDP_LOCAL_PATH;
+       char const              *user = "_sdpd", *group = "_sdpd";
+       char const              *sgroup = NULL;
+       int32_t                  detach = 1, opt;
+       struct sigaction         sa;
+
+       while ((opt = getopt(argc, argv, "c:dG:g:hu:")) != -1) {
+               switch (opt) {
+               case 'c': /* control */
+                       control = optarg;
+                       break;
+
+               case 'd': /* do not detach */
+                       detach = 0;
+                       break;
+
+               case 'G': /* super group */
+                       sgroup = optarg;
+                       break;
+
+               case 'g': /* group */
+                       group = optarg;
+                       break;
+
+               case 'u': /* user */
+                       user = optarg;
+                       break;
+
+               case 'h':
+               default:
+                       usage();
+                       /* NOT REACHED */
+               }
+       }
+
+       log_open(SDPD, !detach);
+
+       /* Become daemon if required */
+       if (detach && daemon(0, 0) < 0) {
+               log_crit("Could not become daemon. %s (%d)",
+                       strerror(errno), errno);
+               exit(1);
+       }
+
+       /* Set signal handlers */
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = sighandler;
+
+       if (sigaction(SIGTERM, &sa, NULL) < 0 ||
+           sigaction(SIGHUP,  &sa, NULL) < 0 ||
+           sigaction(SIGINT,  &sa, NULL) < 0) {
+               log_crit("Could not install signal handlers. %s (%d)",
+                       strerror(errno), errno);
+               exit(1);
+       }
+
+       sa.sa_handler = SIG_IGN;
+       if (sigaction(SIGPIPE, &sa, NULL) < 0) {
+               log_crit("Could not install signal handlers. %s (%d)",
+                       strerror(errno), errno);
+               exit(1);
+       }
+
+       /* Initialize server */
+       if (server_init(&server, control, sgroup) < 0)
+               exit(1);
+
+       if ((user != NULL || group != NULL) && drop_root(user, group) < 0)
+               exit(1);
+
+       for (done = 0; !done; ) {
+               if (server_do(&server) != 0)
+                       done ++;
+       }
+
+       server_shutdown(&server);
+       log_close();
+
+       return (0);
+}
+
+/*
+ * Drop root
+ */
+
+static int32_t
+drop_root(char const *user, char const *group)
+{
+       int      uid, gid;
+       char    *ep;
+
+       if ((uid = getuid()) != 0) {
+               log_notice("Cannot set uid/gid. Not a superuser");
+               return (0); /* dont do anything unless root */
+       }
+
+       gid = getgid();
+
+       if (user != NULL) {
+               uid = strtol(user, &ep, 10);
+               if (*ep != '\0') {
+                       struct passwd   *pwd = getpwnam(user);
+
+                       if (pwd == NULL) {
+                               log_err("Could not find passwd entry for " \
+                                       "user %s", user);
+                               return (-1);
+                       }
+
+                       uid = pwd->pw_uid;
+               }
+       }
+
+       if (group != NULL) {
+               gid = strtol(group, &ep, 10);
+               if (*ep != '\0') {
+                       struct group    *grp = getgrnam(group);
+
+                       if (grp == NULL) {
+                               log_err("Could not find group entry for " \
+                                       "group %s", group);
+                               return (-1);
+                       }
+
+                       gid = grp->gr_gid;
+               }
+       }
+
+       if (setgid(gid) < 0) {
+               log_err("Could not setgid(%s). %s (%d)",
+                       group, strerror(errno), errno);
+               return (-1);
+       }
+
+       if (setuid(uid) < 0) {
+               log_err("Could not setuid(%s). %s (%d)",
+                       user, strerror(errno), errno);
+               return (-1);
+       }
+
+       return (0);
+}
+
+/*
+ * Signal handler
+ */
+
+static void
+sighandler(int32_t s)
+{
+       log_notice("Got signal %d. Total number of signals received %d",
+               s, ++ done);
+}
+
+/*
+ * Display usage information and quit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr,
+"Usage: %s [options]\n" \
+"Where options are:\n" \
+"      -c      specify control socket name (default %s)\n" \
+"      -d      do not detach (run in foreground)\n" \
+"      -G grp  allow privileges to group\n" \
+"      -g grp  specify group\n" \
+"      -h      display usage and exit\n" \
+"      -u usr  specify user\n",
+               SDPD, SDP_LOCAL_PATH);
+       exit(255);
+}
diff --git a/usr.sbin/sdpd/opush.c b/usr.sbin/sdpd/opush.c
new file mode 100644 (file)
index 0000000..24c8a30
--- /dev/null
@@ -0,0 +1,143 @@
+/* $NetBSD: opush.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/opush.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * opush.c
+ *
+ * Copyright (c) 2004 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: opush.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/opush.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+opush_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+opush_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t profile_descriptor_list[] = {
+               SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
+               0x0100
+       };
+
+       return (common_profile_create_bluetooth_profile_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) profile_descriptor_list,
+                       sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+opush_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "OBEX Object Push";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+opush_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_opush_profile_p     opush = (sdp_opush_profile_p) provider->data;
+
+       return (obex_profile_create_protocol_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) &opush->server_channel, 1));
+}
+
+static int32_t
+opush_profile_create_supported_formats_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_opush_profile_p     opush = (sdp_opush_profile_p) provider->data;
+
+       return (obex_profile_create_supported_formats_list(
+                       buf, eob,
+                       (uint8_t const *) opush->supported_formats,
+                       opush->supported_formats_size));
+}
+
+static attr_t  opush_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         opush_profile_create_service_class_id_list },
+       { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+         opush_profile_create_bluetooth_profile_descriptor_list },
+       { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+         common_profile_create_language_base_attribute_id_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         opush_profile_create_service_name },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         opush_profile_create_protocol_descriptor_list },
+       { SDP_ATTR_SUPPORTED_FORMATS_LIST,
+         opush_profile_create_supported_formats_list },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t opush_profile_uuids[] = {
+       SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
+       SDP_UUID_PROTOCOL_L2CAP,
+       SDP_UUID_PROTOCOL_RFCOMM,
+       SDP_UUID_PROTOCOL_OBEX,
+};
+
+profile_t      opush_profile_descriptor = {
+       opush_profile_uuids,
+       sizeof(opush_profile_uuids),
+       sizeof(sdp_opush_profile_t),
+       obex_profile_data_valid,
+       (attr_t const * const) &opush_profile_attrs
+};
diff --git a/usr.sbin/sdpd/profile.c b/usr.sbin/sdpd/profile.c
new file mode 100644 (file)
index 0000000..c1d33a5
--- /dev/null
@@ -0,0 +1,397 @@
+/* $NetBSD: profile.c,v 1.4 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/profile.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * profile.c
+ *
+ * Copyright (c) 2004 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: profile.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/profile.c,v 1.2 2004/07/28 07:15:44 kan Exp $
+ */
+
+#include <sys/queue.h>
+#include <sys/utsname.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+/*
+ * Lookup profile descriptor
+ */
+
+profile_p
+profile_get_descriptor(uint16_t uuid)
+{
+       extern  profile_t       dun_profile_descriptor;
+       extern  profile_t       ftrn_profile_descriptor;
+       extern  profile_t       hf_profile_descriptor;
+       extern  profile_t       hset_profile_descriptor;
+       extern  profile_t       irmc_profile_descriptor;
+       extern  profile_t       irmc_command_profile_descriptor;
+       extern  profile_t       lan_profile_descriptor;
+       extern  profile_t       opush_profile_descriptor;
+       extern  profile_t       sp_profile_descriptor;
+
+       static const profile_p  profiles[] = {
+               &dun_profile_descriptor,
+               &ftrn_profile_descriptor,
+               &hf_profile_descriptor,
+               &hset_profile_descriptor,
+               &irmc_profile_descriptor,
+               &irmc_command_profile_descriptor,
+               &lan_profile_descriptor,
+               &opush_profile_descriptor,
+               &sp_profile_descriptor
+       };
+
+       int32_t                 i;
+
+       for (i = 0; i < sizeof(profiles)/sizeof(profiles[0]); i++)
+               if (profiles[i]->uuid[0] == uuid)
+                       return (profiles[i]);
+
+       return (NULL);
+}
+
+/*
+ * Look attribute in the profile descripror
+ */
+
+profile_attr_create_p
+profile_get_attr(const profile_p profile, uint16_t attr)
+{
+       attr_t const    *ad = (attr_t const *) profile->attrs;
+
+       for (; ad->create != NULL; ad ++)
+               if (ad->attr == attr)
+                       return (ad->create);
+
+       return (NULL);
+}
+
+/*
+ * uint32 value32 - 5 bytes
+ */
+
+int32_t
+common_profile_create_service_record_handle(
+       uint8_t *buf, uint8_t const * const eob,
+       uint8_t const *data, uint32_t datalen)
+{
+       if (buf + 5 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_UINT32, buf);
+       SDP_PUT32(((provider_t const *) data)->handle, buf);
+
+       return (5);
+}
+
+/*
+ * seq8 len8                   - 2 bytes
+ *     uuid16 value16          - 3 bytes
+ *     [ uuid16 value ]
+ */
+
+int32_t
+common_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       int32_t len = 3 * (datalen >>= 1);
+
+       if (len <= 0 || len > 0xff || buf + 2 + len > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(len, buf);
+
+       for (; datalen > 0; datalen --) {
+               SDP_PUT8(SDP_DATA_UUID16, buf);
+               SDP_PUT16(*((uint16_t const *)data), buf);
+               data += sizeof(uint16_t);
+       }
+
+       return (2 + len);
+}
+
+/*
+ * seq8 len8                   - 2 bytes
+ *     seq 8 len8              - 2 bytes
+ *             uuid16 value16  - 3 bytes
+ *             uint16 value16  - 3 bytes
+ *     [ seq 8 len8
+ *             uuid16 value16
+ *             uint16 value16 ]
+ */
+
+int32_t
+common_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       int32_t len = 8 * (datalen >>= 2);
+
+       if (len <= 0 || len > 0xff || buf + 2 + len > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(len, buf);
+
+       for (; datalen > 0; datalen --) {
+               SDP_PUT8(SDP_DATA_SEQ8, buf);
+               SDP_PUT8(6, buf);
+               SDP_PUT8(SDP_DATA_UUID16, buf);
+               SDP_PUT16(*((uint16_t const *)data), buf);
+               data += sizeof(uint16_t);
+               SDP_PUT8(SDP_DATA_UINT16, buf);
+               SDP_PUT16(*((uint16_t const *)data), buf);
+               data += sizeof(uint16_t);
+       }
+
+       return (2 + len);
+}
+
+/*
+ * seq8 len8           - 2 bytes
+ *     uint16 value16  - 3 bytes
+ *     uint16 value16  - 3 bytes
+ *     uint16 value16  - 3 bytes
+ */
+
+int32_t
+common_profile_create_language_base_attribute_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       if (buf + 11 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(9, buf);
+
+       /*
+        * Language code per ISO 639:1988. Use "en".
+        */
+
+       SDP_PUT8(SDP_DATA_UINT16, buf);
+       SDP_PUT16(((0x65 << 8) | 0x6e), buf);
+
+       /*
+        * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106
+        * (http://www.iana.org/assignments/character-sets)
+        */
+
+       SDP_PUT8(SDP_DATA_UINT16, buf);
+       SDP_PUT16(106, buf);
+
+       /*
+        * Offset (Primary Language Base is 0x100)
+        */
+
+       SDP_PUT8(SDP_DATA_UINT16, buf);
+       SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf);
+
+       return (11);
+}
+
+/*
+ * Use Operating System name as provider name
+ */
+
+int32_t
+common_profile_create_service_provider_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       struct utsname u;
+       char const *name;
+
+       if (uname(&u) < 0)
+               name = "Unknown";
+       else
+               name = u.sysname;
+
+       return (common_profile_create_string8(buf, eob,
+                       (uint8_t const *)name, strlen(name)));
+}
+
+/*
+ * str8 len8 string
+ */
+
+int32_t
+common_profile_create_string8(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_STR8, buf);
+       SDP_PUT8(datalen, buf);
+       memcpy(buf, data, datalen);
+
+       return (2 + datalen);
+}
+
+/*
+ * seq8 len8                   - 2 bytes
+ *     seq8 len8               - 2 bytes
+ *             uuid16 value16  - 3 bytes
+ *     seq8 len8               - 2 bytes
+ *             uuid16 value16  - 3 bytes
+ *             uint8 value8    - 2 bytes
+ */
+
+int32_t
+rfcomm_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       if (datalen != 1 || buf + 14 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(12, buf);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(3, buf);
+       SDP_PUT8(SDP_DATA_UUID16, buf);
+       SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(5, buf);
+       SDP_PUT8(SDP_DATA_UUID16, buf);
+       SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
+       SDP_PUT8(SDP_DATA_UINT8, buf);
+       SDP_PUT8(*data, buf);
+
+       return (14);
+}
+
+/*
+ * seq8 len8                   - 2 bytes
+ *     seq8 len8               - 2 bytes
+ *             uuid16 value16  - 3 bytes
+ *     seq8 len8               - 2 bytes
+ *             uuid16 value16  - 3 bytes
+ *             uint8 value8    - 2 bytes
+ *     seq8 len8               - 2 bytes
+ *             uuid16 value16  - 3 bytes
+ */
+
+int32_t
+obex_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       if (datalen != 1 || buf + 19 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(17, buf);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(3, buf);
+       SDP_PUT8(SDP_DATA_UUID16, buf);
+       SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(5, buf);
+       SDP_PUT8(SDP_DATA_UUID16, buf);
+       SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
+       SDP_PUT8(SDP_DATA_UINT8, buf);
+       SDP_PUT8(*data, buf);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(3, buf);
+       SDP_PUT8(SDP_DATA_UUID16, buf);
+       SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf);
+
+       return (19);
+}
+
+/*
+ * seq8 len8
+ *     uint8 value8    - bytes
+ *     [ uint8 value 8 ]
+ */
+
+int32_t
+obex_profile_create_supported_formats_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       int32_t len = 2 * datalen;
+
+       if (len <= 0 || len > 0xff || buf + 2 + len > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(len, buf);
+
+       for (; datalen > 0; datalen --) {
+               SDP_PUT8(SDP_DATA_UINT8, buf);
+               SDP_PUT8(*data++, buf);
+       }
+
+       return (2 + len);
+}
+
+/*
+ * verify server channel number (the first byte in the data)
+ */
+
+int32_t
+common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen)
+{
+       if (data[0] < 1 || data[0] > 30)
+               return (0);
+
+       return (1);
+}
+
+/*
+ * verify server channel number and supported_formats_size
+ * sdp_opush_profile and sdp_irmc_profile
+ */
+
+int32_t
+obex_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+       sdp_opush_profile_t const *opush = (sdp_opush_profile_t const *) data;
+
+       if (opush->server_channel < 1 ||
+           opush->server_channel > 30 ||
+           opush->supported_formats_size == 0 ||
+           opush->supported_formats_size > sizeof(opush->supported_formats))
+               return (0);
+
+       return (1);
+}
diff --git a/usr.sbin/sdpd/profile.h b/usr.sbin/sdpd/profile.h
new file mode 100644 (file)
index 0000000..87e4b91
--- /dev/null
@@ -0,0 +1,93 @@
+/* $NetBSD: profile.h,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/profile.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * profile.h
+ *
+ * Copyright (c) 2004 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: profile.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/profile.h,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#ifndef _PROFILE_H_
+#define _PROFILE_H_
+
+/*
+ * Attribute descriptor
+ */
+
+typedef int32_t        (profile_attr_create_t)(
+                       uint8_t *buf, uint8_t const * const eob,
+                       uint8_t const *data, uint32_t datalen);
+typedef profile_attr_create_t *        profile_attr_create_p;
+
+typedef int32_t        (profile_data_valid_t)(
+                       uint8_t const *data, uint32_t datalen);
+typedef profile_data_valid_t * profile_data_valid_p;
+
+struct attr
+{
+       uint16_t                attr;   /* attribute id */
+       profile_attr_create_p   create; /* create attr value */
+};
+
+typedef struct attr    attr_t;
+typedef struct attr *  attr_p;
+
+/*
+ * Profile descriptor
+ */
+
+
+struct profile
+{
+       uint16_t *              uuid;   /* profile uuid list */
+       ssize_t                 usize;  /* profile uuid list size */
+       uint16_t                dsize;  /* profile data size */
+       profile_data_valid_p    valid;  /* profile data validator */
+       attr_t const * const    attrs;  /* supported attributes */
+};
+
+typedef struct profile profile_t;
+typedef struct profile *profile_p;
+
+profile_p              profile_get_descriptor(uint16_t uuid);
+profile_attr_create_p  profile_get_attr(const profile_p profile, uint16_t attr);
+
+profile_attr_create_t  common_profile_create_service_record_handle;
+profile_attr_create_t  common_profile_create_service_class_id_list;
+profile_attr_create_t  common_profile_create_bluetooth_profile_descriptor_list;
+profile_attr_create_t  common_profile_create_language_base_attribute_id_list;
+profile_attr_create_t  common_profile_create_service_provider_name;
+profile_attr_create_t  common_profile_create_string8;
+profile_attr_create_t  rfcomm_profile_create_protocol_descriptor_list;
+profile_attr_create_t  obex_profile_create_protocol_descriptor_list;
+profile_attr_create_t  obex_profile_create_supported_formats_list;
+
+profile_data_valid_t   common_profile_server_channel_valid;
+profile_data_valid_t   obex_profile_data_valid;
+
+#endif /* ndef _PROFILE_H_ */
diff --git a/usr.sbin/sdpd/provider.c b/usr.sbin/sdpd/provider.c
new file mode 100644 (file)
index 0000000..cee68ff
--- /dev/null
@@ -0,0 +1,235 @@
+/* $NetBSD: provider.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/provider.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * provider.c
+ *
+ * Copyright (c) 2004 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: provider.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/provider.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include <stdlib.h>
+#include "profile.h"
+#include "provider.h"
+#include "uuid-private.h"
+
+static TAILQ_HEAD(, provider)  providers = TAILQ_HEAD_INITIALIZER(providers);
+static uint32_t                        change_state = 0;
+static uint32_t                        next_handle = 0;
+
+/*
+ * Register Service Discovery provider.
+ * Should not be called more the once.
+ */
+
+int32_t
+provider_register_sd(int32_t fd)
+{
+       extern profile_t        sd_profile_descriptor;
+       extern profile_t        bgd_profile_descriptor;
+
+       provider_p              sd = calloc(1, sizeof(*sd));
+       provider_p              bgd = calloc(1, sizeof(*bgd));
+
+       if (sd == NULL || bgd == NULL) {
+               if (sd != NULL)
+                       free(sd);
+
+               if (bgd != NULL)
+                       free(bgd);
+
+               return (-1);
+       }
+
+       sd->profile = &sd_profile_descriptor;
+       bgd->handle = 0;
+       sd->fd = fd;
+       TAILQ_INSERT_HEAD(&providers, sd, provider_next);
+
+       bgd->profile = &bgd_profile_descriptor;
+       bgd->handle = 1;
+       sd->fd = fd;
+       TAILQ_INSERT_AFTER(&providers, sd, bgd, provider_next);
+
+       change_state ++;
+
+       return (0);
+}
+
+/*
+ * Register new provider for a given profile, bdaddr and session.
+ */
+
+provider_p
+provider_register(profile_p const profile, bdaddr_t const *bdaddr, int32_t fd,
+       uint8_t const *data, uint32_t datalen)
+{
+       provider_p      provider = calloc(1, sizeof(*provider));
+
+       if (provider != NULL) {
+               provider->data = malloc(datalen);
+               if (provider->data != NULL) {
+                       provider->profile = profile;
+                       memcpy(provider->data, data, datalen);
+
+                       /*
+                        * Record handles 0x0 and 0x1 are reserved
+                        * for SDP itself
+                        */
+
+                       if (++ next_handle <= 1)
+                               next_handle = 2;
+
+                       provider->handle = next_handle;
+
+                       memcpy(&provider->bdaddr, bdaddr,
+                               sizeof(provider->bdaddr));
+                       provider->fd = fd;
+
+                       TAILQ_INSERT_TAIL(&providers, provider, provider_next);
+                       change_state ++;
+               } else {
+                       free(provider);
+                       provider = NULL;
+               }
+       }
+
+       return (provider);
+}
+
+/*
+ * Unregister provider
+ */
+
+void
+provider_unregister(provider_p provider)
+{
+       TAILQ_REMOVE(&providers, provider, provider_next);
+       if (provider->data != NULL)
+               free(provider->data);
+       free(provider);
+       change_state ++;
+}
+
+/*
+ * Update provider data
+ */
+
+int32_t
+provider_update(provider_p provider, uint8_t const *data, uint32_t datalen)
+{
+       uint8_t *new_data = (uint8_t *) realloc(provider->data, datalen);
+
+       if (new_data == NULL)
+               return (-1);
+
+       memcpy(new_data, data, datalen);
+       provider->data = new_data;
+
+       return (0);
+}
+
+/*
+ * Get a provider for given record handle
+ */
+
+provider_p
+provider_by_handle(uint32_t handle)
+{
+       provider_p      provider = NULL;
+
+       TAILQ_FOREACH(provider, &providers, provider_next)
+               if (provider->handle == handle)
+                       break;
+
+       return (provider);
+}
+
+/*
+ * Cursor access
+ */
+
+provider_p
+provider_get_first(void)
+{
+       return (TAILQ_FIRST(&providers));
+}
+
+provider_p
+provider_get_next(provider_p provider)
+{
+       return (TAILQ_NEXT(provider, provider_next));
+}
+
+/*
+ * Return change state
+ */
+
+uint32_t
+provider_get_change_state(void)
+{
+       return (change_state);
+}
+
+/*
+ * Match provider to UUID list
+ *
+ *     all UUIDs in list must match one of the
+ *     provider UUIDs or the PublicBrowseGroup
+ */
+
+int
+provider_match_uuid(provider_p provider, uint128_t *uuid, int ucount)
+{
+       uint128_t puuid;
+       int num, max;
+
+       max = provider->profile->usize / sizeof(provider->profile->uuid[0]);
+
+       for (; ucount-- > 0 ; uuid++) {
+               if (memcmp(uuid, &uuid_public_browse_group, sizeof(*uuid)) == 0)
+                       continue;
+
+               for (num = 0 ; ; num++) {
+                       if (num == max)
+                               return 0;
+
+                       memcpy(&puuid, &uuid_base, sizeof(puuid));
+                       puuid.b[2] = provider->profile->uuid[num] >> 8;
+                       puuid.b[3] = provider->profile->uuid[num];
+
+                       if (memcmp(uuid, &puuid, sizeof(*uuid)) == 0)
+                               break;
+               }
+       }
+
+       return 1;
+}
diff --git a/usr.sbin/sdpd/provider.h b/usr.sbin/sdpd/provider.h
new file mode 100644 (file)
index 0000000..a1eeca4
--- /dev/null
@@ -0,0 +1,111 @@
+/* $NetBSD: provider.h,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/provider.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * 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.
+ * 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.
+ */
+/*
+ * provider.h
+ *
+ * Copyright (c) 2004 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: provider.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/provider.h,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#ifndef _PROVIDER_H_
+#define _PROVIDER_H_
+
+/*
+ * Provider of service
+ */
+
+struct profile;
+
+struct provider
+{
+       struct profile          *profile;               /* profile */
+       void                    *data;                  /* profile data */
+       uint32_t                 handle;                /* record handle */
+       bdaddr_t                 bdaddr;                /* provider's BDADDR */
+       int32_t                  fd;                    /* session descriptor */
+       TAILQ_ENTRY(provider)    provider_next;         /* all providers */
+};
+
+typedef struct provider                provider_t;
+typedef struct provider        *       provider_p;
+
+#define                provider_match_bdaddr(p, b) \
+       (bdaddr_any(b) || bdaddr_any(&(p)->bdaddr) || \
+        bdaddr_same(&(p)->bdaddr, (b)))
+
+int32_t                provider_register_sd            (int32_t fd);
+provider_p     provider_register               (profile_p const profile,
+                                                bdaddr_t const *bdaddr,
+                                                int32_t fd,
+                                                uint8_t const *data,
+                                                uint32_t datalen);
+
+void           provider_unregister             (provider_p provider);
+int32_t                provider_update                 (provider_p provider,
+                                                uint8_t const *data,
+                                                uint32_t datalen);
+provider_p     provider_by_handle              (uint32_t handle);
+provider_p     provider_get_first              (void);
+provider_p     provider_get_next               (provider_p provider);
+uint32_t       provider_get_change_state       (void);
+
+int            provider_match_uuid             (provider_p provider,
+                                                uint128_t *ulist, int ucount);
+
+int32_t server_prepare_attr_list(provider_p const, uint8_t const *, uint8_t const *,
+               uint8_t *, uint8_t const *);
+
+#endif /* ndef _PROVIDER_H_ */
diff --git a/usr.sbin/sdpd/sar.c b/usr.sbin/sdpd/sar.c
new file mode 100644 (file)
index 0000000..1f3ca78
--- /dev/null
@@ -0,0 +1,319 @@
+/* $NetBSD: sar.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/sar.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * sar.c
+ *
+ * Copyright (c) 2004 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: sar.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/sar.c,v 1.2 2004/02/26 20:44:55 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <stdio.h> /* for NULL */
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare SDP attr/value pair. Check if profile implements the attribute
+ * and if so call the attribute value function.
+ *
+ * uint16 value16      - 3 bytes (attribute)
+ * value               - N bytes (value)
+ */
+
+static int32_t
+server_prepare_attr_value_pair(
+               provider_p const provider, uint16_t attr,
+               uint8_t *buf, uint8_t const * const eob)
+{
+       profile_attr_create_p   cf = profile_get_attr(provider->profile, attr);
+       int32_t                 len;
+
+       if (cf == NULL)
+               return (0); /* no attribute */
+
+       if (buf + 3 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_UINT16, buf);
+       SDP_PUT16(attr, buf);
+
+       len = cf(buf, eob, (uint8_t const *) provider, sizeof(*provider));
+       if (len < 0)
+               return (-1);
+
+       return (3 + len);
+}
+
+/*
+ * seq16 value16       - 3 bytes
+ *     attr value      - 3+ bytes
+ *     [ attr value ]
+ */
+
+int32_t
+server_prepare_attr_list(provider_p const provider,
+               uint8_t const *req, uint8_t const * const req_end,
+               uint8_t *rsp, uint8_t const * const rsp_end)
+{
+       uint8_t *ptr = rsp + 3;
+       int32_t  type, hi, lo, len;
+
+       if (ptr > rsp_end)
+               return (-1);
+
+       while (req < req_end) {
+               SDP_GET8(type, req);
+
+               switch (type) {
+               case SDP_DATA_UINT16:
+                       if (req + 2 > req_end)
+                               return (-1);
+
+                       SDP_GET16(lo, req);
+                       hi = lo;
+                       break;
+
+               case SDP_DATA_UINT32:
+                       if (req + 4 > req_end)
+                               return (-1);
+
+                       SDP_GET16(lo, req);
+                       SDP_GET16(hi, req);
+                       break;
+
+               default:
+                       return (-1);
+                       /* NOT REACHED */
+               }
+
+               for (; lo <= hi; lo ++) {
+                       len = server_prepare_attr_value_pair(provider, lo, ptr, rsp_end);
+                       if (len < 0)
+                               return (-1);
+
+                       ptr += len;
+               }
+       }
+
+       len = ptr - rsp; /* we put this much bytes in rsp */
+
+       /* Fix SEQ16 header for the rsp */
+       SDP_PUT8(SDP_DATA_SEQ16, rsp);
+       SDP_PUT16(len - 3, rsp);
+
+       return (len);
+}
+
+/*
+ * Prepare SDP Service Attribute Response
+ */
+
+int32_t
+server_prepare_service_attribute_response(server_p srv, int32_t fd)
+{
+       uint8_t const   *req = srv->req + sizeof(sdp_pdu_t);
+       uint8_t const   *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+       uint8_t         *rsp = srv->fdidx[fd].rsp;
+       uint8_t const   *rsp_end = rsp + L2CAP_MTU_MAXIMUM;
+
+       uint8_t const   *ptr = NULL;
+       provider_t      *provider = NULL;
+       uint32_t         handle;
+       int32_t          type, rsp_limit, aidlen, cslen, cs;
+
+       /*
+        * Minimal Service Attribute Request request
+        *
+        * value32              - 4 bytes ServiceRecordHandle
+        * value16              - 2 bytes MaximumAttributeByteCount
+        * seq8 len8            - 2 bytes
+        *      uint16 value16  - 3 bytes AttributeIDList
+        * value8               - 1 byte  ContinuationState
+        */
+
+       if (req_end - req < 12)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Get ServiceRecordHandle and MaximumAttributeByteCount */
+       SDP_GET32(handle, req);
+       SDP_GET16(rsp_limit, req);
+       if (rsp_limit <= 0)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Get size of AttributeIDList */
+       aidlen = 0;
+       SDP_GET8(type, req);
+       switch (type) {
+       case SDP_DATA_SEQ8:
+               SDP_GET8(aidlen, req);
+               break;
+
+       case SDP_DATA_SEQ16:
+               SDP_GET16(aidlen, req);
+               break;
+
+       case SDP_DATA_SEQ32:
+               SDP_GET32(aidlen, req);
+               break;
+       }
+       if (aidlen <= 0)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       ptr = (uint8_t const *) req + aidlen;
+
+       /* Get ContinuationState */
+       if (ptr + 1 > req_end)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       SDP_GET8(cslen, ptr);
+       if (cslen != 0) {
+               if (cslen != 2 || req_end - ptr != 2)
+                       return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+               SDP_GET16(cs, ptr);
+       } else
+               cs = 0;
+
+       /* Process the request. First, check continuation state */
+       if (srv->fdidx[fd].rsp_cs != cs)
+               return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
+       if (srv->fdidx[fd].rsp_size > 0)
+               return (0);
+
+       /* Lookup record handle */
+       if ((provider = provider_by_handle(handle)) == NULL)
+               return (SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE);
+
+       /*
+        * Service Attribute Response format
+        *
+        * value16              - 2 bytes  AttributeListByteCount (not incl.)
+        * seq8 len16           - 3 bytes
+        *      attr value      - 3+ bytes AttributeList
+        *      [ attr value ]
+        */
+
+       cs = server_prepare_attr_list(provider, req, req+aidlen, rsp, rsp_end);
+       if (cs < 0)
+               return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
+
+       /* Set reply size (not counting PDU header and continuation state) */
+       srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
+       if (srv->fdidx[fd].rsp_limit > rsp_limit)
+               srv->fdidx[fd].rsp_limit = rsp_limit;
+
+       srv->fdidx[fd].rsp_size = cs;
+       srv->fdidx[fd].rsp_cs = 0;
+
+       return (0);
+}
+
+/*
+ * Send SDP Service [Search] Attribute Response
+ */
+
+int32_t
+server_send_service_attribute_response(server_p srv, int32_t fd)
+{
+       uint8_t         *rsp = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_cs;
+       uint8_t         *rsp_end = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_size;
+
+       struct iovec    iov[4];
+       sdp_pdu_t       pdu;
+       uint16_t        bcount;
+       uint8_t         cs[3];
+       int32_t         size;
+
+       /* First update continuation state  (assume we will send all data) */
+       size = rsp_end - rsp;
+       srv->fdidx[fd].rsp_cs += size;
+
+       if (size + 1 > srv->fdidx[fd].rsp_limit) {
+               /*
+                * We need to split out response. Add 3 more bytes for the
+                * continuation state and move rsp_end and rsp_cs backwards.
+                */
+
+               while ((rsp_end - rsp) + 3 > srv->fdidx[fd].rsp_limit) {
+                       rsp_end --;
+                       srv->fdidx[fd].rsp_cs --;
+               }
+
+               cs[0] = 2;
+               cs[1] = srv->fdidx[fd].rsp_cs >> 8;
+               cs[2] = srv->fdidx[fd].rsp_cs & 0xff;
+       } else
+               cs[0] = 0;
+
+       assert(rsp_end >= rsp);
+
+       bcount = rsp_end - rsp;
+
+       if (((sdp_pdu_p)(srv->req))->pid == SDP_PDU_SERVICE_ATTRIBUTE_REQUEST)
+               pdu.pid = SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE;
+       else
+               pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
+
+       pdu.tid = ((sdp_pdu_p)(srv->req))->tid;
+       pdu.len = htons(sizeof(bcount) + bcount + 1 + cs[0]);
+
+       bcount = htons(bcount);
+
+       iov[0].iov_base = &pdu;
+       iov[0].iov_len = sizeof(pdu);
+
+       iov[1].iov_base = &bcount;
+       iov[1].iov_len = sizeof(bcount);
+
+       iov[2].iov_base = rsp;
+       iov[2].iov_len = rsp_end - rsp;
+
+       iov[3].iov_base = cs;
+       iov[3].iov_len = 1 + cs[0];
+
+       do {
+               size = writev(fd, (struct iovec const *) &iov, sizeof(iov)/sizeof(iov[0]));
+       } while (size < 0 && errno == EINTR);
+
+       /* Check if we have sent (or failed to sent) last response chunk */
+       if (srv->fdidx[fd].rsp_cs == srv->fdidx[fd].rsp_size) {
+               srv->fdidx[fd].rsp_cs = 0;
+               srv->fdidx[fd].rsp_size = 0;
+               srv->fdidx[fd].rsp_limit = 0;
+       }
+
+       return ((size < 0)? errno : 0);
+}
diff --git a/usr.sbin/sdpd/scr.c b/usr.sbin/sdpd/scr.c
new file mode 100644 (file)
index 0000000..df19fff
--- /dev/null
@@ -0,0 +1,94 @@
+/* $NetBSD: scr.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/scr.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * scr.c
+ *
+ * Copyright (c) 2004 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: scr.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/scr.c,v 1.2 2005/12/06 17:56:36 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare Service Change response
+ */
+
+int32_t
+server_prepare_service_change_response(server_p srv, int32_t fd)
+{
+       uint8_t const   *req = srv->req + sizeof(sdp_pdu_t);
+       uint8_t const   *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+       uint8_t         *rsp = srv->fdidx[fd].rsp;
+
+       provider_t      *provider = NULL;
+       uint32_t         handle;
+
+       /*
+        * Minimal Service Change Request
+        *
+        * value32      - handle 4 bytes
+        */
+
+       if (!srv->fdidx[fd].control ||
+           !srv->fdidx[fd].priv || req_end - req < 4)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Get handle */
+       SDP_GET32(handle, req);
+
+       /* Lookup provider */
+       provider = provider_by_handle(handle);
+       if (provider == NULL || provider->fd != fd)
+               return (SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE);
+
+       /* Validate user data */
+       if (req_end - req < provider->profile->dsize ||
+           provider->profile->valid == NULL ||
+           (provider->profile->valid)(req, req_end - req) == 0)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Update provider */
+       if (provider_update(provider, req, req_end - req) < 0)
+               return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
+
+       SDP_PUT16(0, rsp);
+
+       /* Set reply size */
+       srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
+       srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
+       srv->fdidx[fd].rsp_cs = 0;
+
+       return (0);
+}
diff --git a/usr.sbin/sdpd/sd.c b/usr.sbin/sdpd/sd.c
new file mode 100644 (file)
index 0000000..16fbd00
--- /dev/null
@@ -0,0 +1,220 @@
+/* $NetBSD: sd.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/sd.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * sd.c
+ *
+ * Copyright (c) 2004 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: sd.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/sd.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+sd_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+sd_profile_create_service_id(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       if (buf + 3 > eob)
+               return (-1);
+
+       /*
+        * The ServiceID is a UUID that universally and uniquely identifies
+        * the service instance described by the service record. This service
+        * attribute is particularly useful if the same service is described
+        * by service records in more than one SDP server
+        */
+
+       SDP_PUT8(SDP_DATA_UUID16, buf);
+       SDP_PUT16(SDP_UUID_PROTOCOL_SDP, buf); /* XXX ??? */
+
+       return (3);
+}
+
+static int32_t
+sd_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "Bluetooth service discovery";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+sd_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       if (buf + 13 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(11, buf);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(9, buf);
+
+       SDP_PUT8(SDP_DATA_UUID16, buf);
+       SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+
+       SDP_PUT8(SDP_DATA_UINT16, buf);
+       SDP_PUT16(L2CAP_PSM_SDP, buf);
+
+       SDP_PUT8(SDP_DATA_UINT16, buf);
+       SDP_PUT16(1, buf); /* version */
+
+       return (13);
+}
+
+static int32_t
+sd_profile_create_browse_group_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       if (buf + 5 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(3, buf);
+
+       /*
+        * The top-level browse group ID, called PublicBrowseRoot and
+        * representing the root of the browsing hierarchy, has the value
+        * 00001002-0000-1000-8000-00805F9B34FB (UUID16: 0x1002) from the
+        * Bluetooth Assigned Numbers document
+        */
+
+       SDP_PUT8(SDP_DATA_UUID16, buf);
+       SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf);
+
+       return (5);
+}
+
+static int32_t
+sd_profile_create_version_number_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       if (buf + 5 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_SEQ8, buf);
+       SDP_PUT8(3, buf);
+
+       /*
+        * The VersionNumberList is a data element sequence in which each
+        * element of the sequence is a version number supported by the SDP
+        * server. A version number is a 16-bit unsigned integer consisting
+        * of two fields. The higher-order 8 bits contain the major version
+        * number field and the low-order 8 bits contain the minor version
+        * number field. The initial version of SDP has a major version of
+        * 1 and a minor version of 0
+        */
+
+       SDP_PUT8(SDP_DATA_UINT16, buf);
+       SDP_PUT16(0x0100, buf);
+
+       return (5);
+}
+
+static int32_t
+sd_profile_create_service_database_state(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       uint32_t        change_state = provider_get_change_state();
+
+       if (buf + 5 > eob)
+               return (-1);
+
+       SDP_PUT8(SDP_DATA_UINT32, buf);
+       SDP_PUT32(change_state, buf);
+
+       return (5);
+}
+
+static attr_t  sd_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         sd_profile_create_service_class_id_list },
+       { SDP_ATTR_SERVICE_ID,
+         sd_profile_create_service_id },
+       { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+         common_profile_create_language_base_attribute_id_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         sd_profile_create_service_name },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
+         sd_profile_create_service_name },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
+         common_profile_create_service_provider_name },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         sd_profile_create_protocol_descriptor_list },
+       { SDP_ATTR_BROWSE_GROUP_LIST,
+         sd_profile_create_browse_group_list },
+       { SDP_ATTR_VERSION_NUMBER_LIST,
+         sd_profile_create_version_number_list },
+       { SDP_ATTR_SERVICE_DATABASE_STATE,
+         sd_profile_create_service_database_state },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t sd_profile_uuids[] = {
+       SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER,
+       SDP_UUID_PROTOCOL_L2CAP,
+};
+
+profile_t      sd_profile_descriptor = {
+       sd_profile_uuids,
+       sizeof(sd_profile_uuids),
+       0,
+       (profile_data_valid_p) NULL,
+       (attr_t const * const) &sd_profile_attrs
+};
diff --git a/usr.sbin/sdpd/sdpd.8 b/usr.sbin/sdpd/sdpd.8
new file mode 100644 (file)
index 0000000..defc347
--- /dev/null
@@ -0,0 +1,164 @@
+.\" $NetBSD: sdpd.8,v 1.3 2007/03/18 15:53:55 plunky Exp $
+.\" $DragonFly: src/usr.sbin/sdpd/sdpd.8,v 1.1 2008/01/06 21:51:30 hasso Exp $
+.\"
+.\" Copyright (c) 2004 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: sdpd.8,v 1.2 2007/11/30 07:39:37 griffin Exp $
+.\" $FreeBSD: src/usr.sbin/bluetooth/sdpd/sdpd.8,v 1.5 2005/12/06 17:56:36 emax Exp $
+.\"
+.Dd January 13, 2004
+.Dt SDPD 8
+.Os
+.Sh NAME
+.Nm sdpd
+.Nd Bluetooth Service Discovery Protocol daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl dh
+.Op Fl c Ar path
+.Op Fl G Ar group
+.Op Fl g Ar group
+.Op Fl u Ar user
+.Sh DESCRIPTION
+The
+.Nm
+daemon keeps track of the Bluetooth services registered on the host
+and responds to Service Discovery inquiries from the remote Bluetooth devices.
+.Pp
+In order to use any service remote Bluetooth device need to send Service
+Search and Service Attribute or Service Search Attribute request over
+Bluetooth L2CAP connection on SDP PSM (0x0001).
+The
+.Nm
+daemon will try to find matching Service Record in its Service Database
+and will send appropriate response back.
+The remote device then will process the response, extract all required
+information and will make a separate connection in order to use the service.
+.Pp
+Bluetooth applications, running on the host, register services with
+the local
+.Nm
+daemon.
+Operation like service registration, service removal and service change are
+performed over the control socket.
+It is possible to query entire content of the
+.Nm
+Service Database with
+.Xr sdpquery 1
+by issuing
+.Cm browse
+command on the control socket.
+.Pp
+The command line options are as follows:
+.Bl -tag -width indent
+.It Fl d
+Do not detach from the controlling terminal.
+.It Fl c Ar path
+Specify path to the control socket.
+The default path is
+.Pa /var/run/sdp .
+.It Fl G Ar group
+Grant permission to members of the
+.Ar group
+to modify the
+.Nm
+Service Database.
+.It Fl g Ar group
+Specifies the group the
+.Nm
+should run as after it initializes.
+The value specified may be either a group name or a numeric group ID.
+This only works if
+.Nm
+was started as root.
+The default group name is
+.Dq Li _sdpd .
+.It Fl h
+Display usage message and exit.
+.It Fl u Ar user
+Specifies the user the
+.Nm
+should run as after it initializes.
+The value specified may be either a user name or a numeric user ID.
+This only works if
+.Nm
+was started as root.
+The default user name is
+.Dq Li _sdpd .
+.El
+.Sh CAVEAT
+The
+.Nm
+daemon
+will listen for incoming L2CAP connections on a wildcard BD_ADDR.
+.Pp
+In case of multiple Bluetooth devices connected to the same host it is
+possible to specify which services should be
+.Dq bound
+to which Bluetooth device.
+Such assignment should be done at service registration time.
+.Pp
+Requests to register, remove or change service can only be made via the
+control socket.
+The
+.Nm
+daemon will check the peer's credentials and will only accept the request
+when the peer is the superuser, of if the peer is a member of the group
+specified with the
+.Fl G
+option.
+.Pp
+The
+.Nm
+daemon does not check for duplicated Service Records.
+It only performs minimal checking on the service data sent in the Service
+Register request.
+It is assumed that application must obtain all required resources such
+as RFCOMM channels etc., before registering the service.
+.Sh FILES
+.Bl -tag -width ".Pa /var/run/sdp" -compact
+.It Pa /var/run/sdp
+.El
+.Sh SEE ALSO
+.Xr sdp 3 ,
+.Xr sdpquery 1
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
+.Sh HISTORY
+The
+.Nm
+daemon first appeared in
+.Fx 5.3
+and was imported into
+.Nx 4.0
+by
+.An Iain Hibbert
+under the sponsorship of
+.An Itronix, Inc.
+It was imported into
+.Dx 1.11 .
+.Sh BUGS
+Most likely.
+Please report if found.
diff --git a/usr.sbin/sdpd/server.c b/usr.sbin/sdpd/server.c
new file mode 100644 (file)
index 0000000..cc84b65
--- /dev/null
@@ -0,0 +1,673 @@
+/* $NetBSD: server.c,v 1.3 2007/03/18 10:00:42 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/server.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * 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.
+ * 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.
+ */
+/*
+ * server.c
+ *
+ * Copyright (c) 2004 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: server.c,v 1.1.1.1 2007/11/20 11:56:11 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/server.c,v 1.2 2005/12/06 17:56:36 emax Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <sys/ucred.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "log.h"
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+static void    server_accept_client            (server_p srv, int32_t fd);
+static int32_t server_process_request          (server_p srv, int32_t fd);
+static int32_t server_send_error_response      (server_p srv, int32_t fd,
+                                                uint16_t error);
+static void    server_close_fd                 (server_p srv, int32_t fd);
+#if 0
+static int     server_auth_check               (server_p srv, struct sockcred *cred);
+#endif
+static int     server_auth_check               (server_p srv, struct cmsgcred *cred);
+
+/*
+ * Initialize server
+ */
+
+int32_t
+server_init(server_p srv, char const *control, char const *sgroup)
+{
+       struct sockaddr_un      un;
+       struct sockaddr_bt      l2;
+       socklen_t               size;
+       int32_t                 unsock, l2sock;
+       uint16_t                imtu;
+       int                     opt;
+
+       assert(srv != NULL);
+       assert(control != NULL);
+
+       memset(srv, 0, sizeof(srv));
+       srv->sgroup = sgroup;
+
+       /* Open control socket */
+       if (unlink(control) < 0 && errno != ENOENT) {
+               log_crit("Could not unlink(%s). %s (%d)",
+                       control, strerror(errno), errno);
+               return (-1);
+       }
+
+       unsock = socket(PF_LOCAL, SOCK_STREAM, 0);
+       if (unsock < 0) {
+               log_crit("Could not create control socket. %s (%d)",
+                       strerror(errno), errno);
+               return (-1);
+       }
+
+       opt = 1;
+#if 0
+       if (setsockopt(unsock, 0, LOCAL_CREDS, &opt, sizeof(opt)) < 0)
+               log_crit("Warning: No credential checks on control socket");
+#endif
+       memset(&un, 0, sizeof(un));
+       un.sun_len = sizeof(un);
+       un.sun_family = AF_LOCAL;
+       strlcpy(un.sun_path, control, sizeof(un.sun_path));
+
+       if (bind(unsock, (struct sockaddr *) &un, sizeof(un)) < 0) {
+               log_crit("Could not bind control socket. %s (%d)",
+                       strerror(errno), errno);
+               close(unsock);
+               return (-1);
+       }
+
+       if (chmod(control, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) < 0) {
+               log_crit("Could not change permissions on control socket. " \
+                       "%s (%d)", strerror(errno), errno);
+               close(unsock);
+               return (-1);
+       }
+
+       if (listen(unsock, 10) < 0) {
+               log_crit("Could not listen on control socket. %s (%d)",
+                       strerror(errno), errno);
+               close(unsock);
+               return (-1);
+       }
+
+       /* Open L2CAP socket */
+       l2sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+       if (l2sock < 0) {
+               log_crit("Could not create L2CAP socket. %s (%d)",
+                       strerror(errno), errno);
+               close(unsock);
+               return (-1);
+       }
+
+       size = sizeof(imtu);
+        if (getsockopt(l2sock, BTPROTO_L2CAP, SO_L2CAP_IMTU, &imtu, &size) < 0) {
+               log_crit("Could not get L2CAP IMTU. %s (%d)",
+                       strerror(errno), errno);
+               close(unsock);
+               close(l2sock);
+               return (-1);
+        }
+
+       memset(&l2, 0, sizeof(l2));
+       l2.bt_len = sizeof(l2);
+       l2.bt_family = AF_BLUETOOTH;
+       l2.bt_psm = L2CAP_PSM_SDP;
+       bdaddr_copy(&l2.bt_bdaddr, BDADDR_ANY);
+
+       if (bind(l2sock, (struct sockaddr *) &l2, sizeof(l2)) < 0) {
+               log_crit("Could not bind L2CAP socket. %s (%d)",
+                       strerror(errno), errno);
+               close(unsock);
+               close(l2sock);
+               return (-1);
+       }
+
+       if (listen(l2sock, 10) < 0) {
+               log_crit("Could not listen on L2CAP socket. %s (%d)",
+                       strerror(errno), errno);
+               close(unsock);
+               close(l2sock);
+               return (-1);
+       }
+
+       /* Allocate incoming buffer */
+       srv->imtu = (imtu > SDP_LOCAL_MTU)? imtu : SDP_LOCAL_MTU;
+       srv->req = (uint8_t *) calloc(srv->imtu, sizeof(srv->req[0]));
+       if (srv->req == NULL) {
+               log_crit("Could not allocate request buffer");
+               close(unsock);
+               close(l2sock);
+               return (-1);
+       }
+
+       /* Allocate memory for descriptor index */
+       srv->fdidx = (fd_idx_p) calloc(FD_SETSIZE, sizeof(srv->fdidx[0]));
+       if (srv->fdidx == NULL) {
+               log_crit("Could not allocate fd index");
+               free(srv->req);
+               close(unsock);
+               close(l2sock);
+               return (-1);
+       }
+
+       /* Register Service Discovery profile (attach it to control socket) */
+       if (provider_register_sd(unsock) < 0) {
+               log_crit("Could not register Service Discovery profile");
+               free(srv->fdidx);
+               free(srv->req);
+               close(unsock);
+               close(l2sock);
+               return (-1);
+       }
+
+       /*
+        * If we got here then everything is fine. Add both control sockets
+        * to the index.
+        */
+
+       FD_ZERO(&srv->fdset);
+       srv->maxfd = (unsock > l2sock)? unsock : l2sock;
+
+       FD_SET(unsock, &srv->fdset);
+       srv->fdidx[unsock].valid = 1;
+       srv->fdidx[unsock].server = 1;
+       srv->fdidx[unsock].control = 1;
+       srv->fdidx[unsock].priv = 0;
+       srv->fdidx[unsock].rsp_cs = 0;
+       srv->fdidx[unsock].rsp_size = 0;
+       srv->fdidx[unsock].rsp_limit = 0;
+       srv->fdidx[unsock].omtu = SDP_LOCAL_MTU;
+       srv->fdidx[unsock].rsp = NULL;
+
+       FD_SET(l2sock, &srv->fdset);
+       srv->fdidx[l2sock].valid = 1;
+       srv->fdidx[l2sock].server = 1;
+       srv->fdidx[l2sock].control = 0;
+       srv->fdidx[l2sock].priv = 0;
+       srv->fdidx[l2sock].rsp_cs = 0;
+       srv->fdidx[l2sock].rsp_size = 0;
+       srv->fdidx[l2sock].rsp_limit = 0;
+       srv->fdidx[l2sock].omtu = 0; /* unknown */
+       srv->fdidx[l2sock].rsp = NULL;
+
+       return (0);
+}
+
+/*
+ * Shutdown server
+ */
+
+void
+server_shutdown(server_p srv)
+{
+       int     fd;
+
+       assert(srv != NULL);
+
+       for (fd = 0; fd < srv->maxfd + 1; fd ++)
+               if (srv->fdidx[fd].valid)
+                       server_close_fd(srv, fd);
+
+       free(srv->req);
+       free(srv->fdidx);
+
+       memset(srv, 0, sizeof(*srv));
+}
+
+/*
+ * Do one server iteration
+ */
+
+int32_t
+server_do(server_p srv)
+{
+       fd_set  fdset;
+       int32_t n, fd;
+
+       assert(srv != NULL);
+
+       /* Copy cached version of the fd set and call select */
+       memcpy(&fdset, &srv->fdset, sizeof(fdset));
+       n = select(srv->maxfd + 1, &fdset, NULL, NULL, NULL);
+       if (n < 0) {
+               if (errno == EINTR)
+                       return (0);
+
+               log_err("Could not select(%d, %p). %s (%d)",
+                       srv->maxfd + 1, &fdset, strerror(errno), errno);
+
+               return (-1);
+       }
+
+       /* Process  descriptors */
+       for (fd = 0; fd < srv->maxfd + 1 && n > 0; fd ++) {
+               if (!FD_ISSET(fd, &fdset))
+                       continue;
+
+               assert(srv->fdidx[fd].valid);
+               n --;
+
+               if (srv->fdidx[fd].server)
+                       server_accept_client(srv, fd);
+               else if (server_process_request(srv, fd) != 0)
+                       server_close_fd(srv, fd);
+       }
+
+       return (0);
+
+}
+
+/*
+ * Accept new client connection and register it with index
+ */
+
+static void
+server_accept_client(server_p srv, int32_t fd)
+{
+       uint8_t         *rsp = NULL;
+       socklen_t        size;
+       int32_t          cfd;
+       uint16_t         omtu;
+
+       do {
+               cfd = accept(fd, NULL, NULL);
+       } while (cfd < 0 && errno == EINTR);
+
+       if (cfd < 0) {
+               log_err("Could not accept connection on %s socket. %s (%d)",
+                       srv->fdidx[fd].control? "control" : "L2CAP",
+                       strerror(errno), errno);
+               return;
+       }
+
+       assert(!FD_ISSET(cfd, &srv->fdset));
+       assert(!srv->fdidx[cfd].valid);
+
+       if (!srv->fdidx[fd].control) {
+               /* Get local BD_ADDR */
+               size = sizeof(srv->req_sa);
+               if (getsockname(cfd,(struct sockaddr*)&srv->req_sa, &size) < 0) {
+                       log_err("Could not get local BD_ADDR. %s (%d)",
+                               strerror(errno), errno);
+                       close(cfd);
+                       return;
+               }
+
+               /* Get outgoing MTU */
+               size = sizeof(omtu);
+               if (getsockopt(cfd, BTPROTO_L2CAP, SO_L2CAP_OMTU, &omtu, &size) < 0) {
+                       log_err("Could not get L2CAP OMTU. %s (%d)",
+                               strerror(errno), errno);
+                       close(cfd);
+                       return;
+               }
+
+               /*
+                * The maximum size of the L2CAP packet is 65536 bytes.
+                * The minimum L2CAP MTU is 43 bytes. That means we need
+                * 65536 / 43 = ~1524 chunks to transfer maximum packet
+                * size with minimum MTU. The "rsp_cs" field in fd_idx_t
+                * is 11 bit wide that gives us upto 2048 chunks.
+                */
+
+               if (omtu < L2CAP_MTU_MINIMUM) {
+                       log_err("L2CAP OMTU is too small (%d bytes)", omtu);
+                       close(cfd);
+                       return;
+               }
+       } else {
+               bdaddr_copy(&srv->req_sa.bt_bdaddr, BDADDR_ANY);
+               omtu = srv->fdidx[fd].omtu;
+       }
+
+       /*
+        * Allocate buffer. This is an overkill, but we can not know how
+        * big our reply is going to be.
+        */
+
+       rsp = (uint8_t *) calloc(L2CAP_MTU_MAXIMUM, sizeof(rsp[0]));
+       if (rsp == NULL) {
+               log_crit("Could not allocate response buffer");
+               close(cfd);
+               return;
+       }
+
+       /* Add client descriptor to the index */
+       FD_SET(cfd, &srv->fdset);
+       if (srv->maxfd < cfd)
+               srv->maxfd = cfd;
+       srv->fdidx[cfd].valid = 1;
+       srv->fdidx[cfd].server = 0;
+       srv->fdidx[cfd].control = srv->fdidx[fd].control;
+       srv->fdidx[cfd].priv = 0;
+       srv->fdidx[cfd].rsp_cs = 0;
+       srv->fdidx[cfd].rsp_size = 0;
+       srv->fdidx[cfd].rsp_limit = 0;
+       srv->fdidx[cfd].omtu = omtu;
+       srv->fdidx[cfd].rsp = rsp;
+}
+
+/*
+ * Process request from the client
+ */
+
+static int32_t
+server_process_request(server_p srv, int32_t fd)
+{
+       uint8_t         ctl[128];
+       sdp_pdu_p       pdu = (sdp_pdu_p) srv->req;
+       struct msghdr   msg;
+       struct iovec    iov;
+       int32_t         len, error;
+       struct cmsghdr  *cmsg;
+
+       assert(srv->imtu > 0);
+       assert(srv->req != NULL);
+       assert(FD_ISSET(fd, &srv->fdset));
+       assert(srv->fdidx[fd].valid);
+       assert(!srv->fdidx[fd].server);
+       assert(srv->fdidx[fd].rsp != NULL);
+       assert(srv->fdidx[fd].omtu >= L2CAP_MTU_MINIMUM);
+
+       iov.iov_base = srv->req;
+       iov.iov_len = srv->imtu;
+
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = ctl;
+       msg.msg_controllen = sizeof(ctl);
+       msg.msg_flags = 0;
+
+       do {
+               len = recvmsg(fd, &msg, 0);
+       } while (len < 0 && errno == EINTR);
+
+       if (len < 0) {
+               log_err("Could not receive SDP request from %s socket. %s (%d)",
+                       srv->fdidx[fd].control? "control" : "L2CAP",
+                       strerror(errno), errno);
+               return (-1);
+       }
+       if (len == 0) {
+               log_info("Client on %s socket has disconnected",
+                       srv->fdidx[fd].control? "control" : "L2CAP");
+               return (-1);
+       }
+
+#if XXX
+       if ((cmsg = CMSG_FIRSTHDR(&msg)) != NULL
+           && cmsg->cmsg_level == SOL_SOCKET
+           && cmsg->cmsg_type == SCM_CREDS
+#if 0
+           && cmsg->cmsg_len >= CMSG_LEN(SOCKCREDSIZE(0))
+#endif
+)
+               srv->fdidx[fd].priv = 
+                   server_auth_check(srv, (struct cmsgcred *)CMSG_DATA(cmsg));
+#if 0
+                   server_auth_check(srv, (struct sockcred *)CMSG_DATA(cmsg));
+#endif
+#else
+srv->fdidx[fd].priv = 1;
+#endif
+
+       if (len >= sizeof(*pdu)
+           && (sizeof(*pdu) + (pdu->len = ntohs(pdu->len))) == len) {
+               switch (pdu->pid) {
+               case SDP_PDU_SERVICE_SEARCH_REQUEST:
+                       error = server_prepare_service_search_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
+                       error = server_prepare_service_attribute_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
+                       error = server_prepare_service_search_attribute_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_REGISTER_REQUEST:
+                       error = server_prepare_service_register_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_UNREGISTER_REQUEST:
+                       error = server_prepare_service_unregister_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_CHANGE_REQUEST:
+                       error = server_prepare_service_change_response(srv, fd);
+                       break;
+
+               default:
+                       error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
+                       break;
+               }
+       } else
+               error = SDP_ERROR_CODE_INVALID_PDU_SIZE;
+
+       if (error == 0) {
+               switch (pdu->pid) {
+               case SDP_PDU_SERVICE_SEARCH_REQUEST:
+                       error = server_send_service_search_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
+                       error = server_send_service_attribute_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
+                       error = server_send_service_search_attribute_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_REGISTER_REQUEST:
+                       error = server_send_service_register_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_UNREGISTER_REQUEST:
+                       error = server_send_service_unregister_response(srv, fd);
+                       break;
+
+               case SDP_PDU_SERVICE_CHANGE_REQUEST:
+                       error = server_send_service_change_response(srv, fd);
+                       break;
+
+               default:
+                       error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
+                       break;
+               }
+
+               if (error != 0)
+                       log_err("Could not send SDP response to %s socket, " \
+                               "pdu->pid=%d, pdu->tid=%d, error=%d",
+                               srv->fdidx[fd].control? "control" : "L2CAP",
+                               pdu->pid, ntohs(pdu->tid), error);
+       } else {
+               log_err("Could not process SDP request from %s socket, " \
+                       "pdu->pid=%d, pdu->tid=%d, pdu->len=%d, len=%d, " \
+                       "error=%d",
+                       srv->fdidx[fd].control? "control" : "L2CAP",
+                       pdu->pid, ntohs(pdu->tid), pdu->len, len, error);
+
+               error = server_send_error_response(srv, fd, error);
+               if (error != 0)
+                       log_err("Could not send SDP error response to %s " \
+                               "socket, pdu->pid=%d, pdu->tid=%d, error=%d",
+                               srv->fdidx[fd].control? "control" : "L2CAP",
+                               pdu->pid, ntohs(pdu->tid), error);
+       }
+
+       /* On error forget response (if any) */
+       if (error != 0) {
+               srv->fdidx[fd].rsp_cs = 0;
+               srv->fdidx[fd].rsp_size = 0;
+               srv->fdidx[fd].rsp_limit = 0;
+       }
+
+       return (error);
+}
+
+/*
+ * Send SDP_Error_Response PDU
+ */
+
+static int32_t
+server_send_error_response(server_p srv, int32_t fd, uint16_t error)
+{
+       int32_t size;
+
+       struct {
+               sdp_pdu_t               pdu;
+               uint16_t                error;
+       } __attribute__ ((packed))      rsp;
+
+       /* Prepare and send SDP error response */
+       rsp.pdu.pid = SDP_PDU_ERROR_RESPONSE;
+       rsp.pdu.tid = ((sdp_pdu_p)(srv->req))->tid;
+       rsp.pdu.len = htons(sizeof(rsp.error));
+       rsp.error   = htons(error);
+
+       do {
+               size = write(fd, &rsp, sizeof(rsp));
+       } while (size < 0 && errno == EINTR);
+
+       return ((size < 0)? errno : 0);
+}
+
+/*
+ * Close descriptor and remove it from index
+ */
+
+static void
+server_close_fd(server_p srv, int32_t fd)
+{
+       provider_p      provider = NULL, provider_next = NULL;
+
+       assert(FD_ISSET(fd, &srv->fdset));
+       assert(srv->fdidx[fd].valid);
+
+       close(fd);
+
+       FD_CLR(fd, &srv->fdset);
+       if (fd == srv->maxfd)
+               srv->maxfd --;
+
+       if (srv->fdidx[fd].rsp != NULL)
+               free(srv->fdidx[fd].rsp);
+
+       memset(&srv->fdidx[fd], 0, sizeof(srv->fdidx[fd]));
+
+       for (provider = provider_get_first();
+            provider != NULL;
+            provider = provider_next) {
+               provider_next = provider_get_next(provider);
+
+               if (provider->fd == fd)
+                       provider_unregister(provider);
+       }
+}
+
+static int
+/*server_auth_check(server_p srv, struct sockcred *cred)*/
+server_auth_check(server_p srv, struct cmsgcred *cred)
+{
+       struct group *grp;
+       int n;
+
+       if (cred == NULL)
+               return 0;
+
+       if (cred->cmcred_uid == 0 || cred->cmcred_euid == 0)
+               return 1;
+
+       if (srv->sgroup == NULL)
+               return 0;
+
+       grp = getgrnam(srv->sgroup);
+       if (grp == NULL) {
+               log_err("No gid for group '%s'", srv->sgroup);
+               srv->sgroup = NULL;
+               return 0;
+       }
+
+
+       if (cred->cmcred_gid == grp->gr_gid)
+               return 1;
+
+       for (n = 0 ; n < cred->cmcred_ngroups ; n++) {
+               if (cred->cmcred_groups[n] == grp->gr_gid)
+                       return 1;
+       }
+
+       return 0;
+}
diff --git a/usr.sbin/sdpd/server.h b/usr.sbin/sdpd/server.h
new file mode 100644 (file)
index 0000000..74411d1
--- /dev/null
@@ -0,0 +1,136 @@
+/* $NetBSD: server.h,v 1.3 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/server.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * 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.
+ * 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.
+ */
+/*
+ * server.h
+ *
+ * Copyright (c) 2004 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: server.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/server.h,v 1.2 2005/12/06 17:56:36 emax Exp $
+ */
+
+#ifndef _SERVER_H_
+#define _SERVER_H_
+
+/*
+ * File descriptor index entry
+ */
+
+struct fd_idx
+{
+       unsigned         valid    : 1;  /* descriptor is valid */
+       unsigned         server   : 1;  /* descriptor is listening */
+       unsigned         control  : 1;  /* descriptor is a control socket */
+       unsigned         priv     : 1;  /* descriptor is privileged */
+       unsigned         reserved : 1;
+       unsigned         rsp_cs   : 11; /* response continuation state */
+       uint16_t         rsp_size;      /* response size */
+       uint16_t         rsp_limit;     /* response limit */
+       uint16_t         omtu;          /* outgoing MTU */
+       uint8_t         *rsp;           /* outgoing buffer */
+};
+
+typedef struct fd_idx  fd_idx_t;
+typedef struct fd_idx *        fd_idx_p;
+
+/*
+ * SDP server
+ */
+
+struct server
+{
+       uint16_t                 imtu;          /* incoming MTU */
+       uint8_t                 *req;           /* incoming buffer */
+       int32_t                  maxfd;         /* max. descriptor is the set */
+       fd_set                   fdset;         /* current descriptor set */
+       fd_idx_p                 fdidx;         /* descriptor index */
+       struct sockaddr_bt       req_sa;        /* local address */
+       const char              *sgroup;        /* privileged group */
+};
+
+typedef struct server  server_t;
+typedef struct server *        server_p;
+
+/*
+ * External API
+ */
+
+int32_t        server_init(server_p srv, const char *control, char const *sgroup);
+void   server_shutdown(server_p srv);
+int32_t        server_do(server_p srv);
+
+int    server_get_service_search_pattern(uint8_t const **buf, uint8_t const *end, uint128_t *uuid);
+
+int32_t        server_prepare_service_search_response(server_p srv, int32_t fd);
+int32_t        server_send_service_search_response(server_p srv, int32_t fd);
+
+int32_t        server_prepare_service_attribute_response(server_p srv, int32_t fd);
+int32_t        server_send_service_attribute_response(server_p srv, int32_t fd);
+
+int32_t        server_prepare_service_search_attribute_response(server_p srv, int32_t fd);
+#define        server_send_service_search_attribute_response \
+       server_send_service_attribute_response
+
+int32_t        server_prepare_service_register_response(server_p srv, int32_t fd);
+int32_t        server_send_service_register_response(server_p srv, int32_t fd);
+
+int32_t        server_prepare_service_unregister_response(server_p srv, int32_t fd);
+#define        server_send_service_unregister_response \
+       server_send_service_register_response
+
+int32_t        server_prepare_service_change_response(server_p srv, int32_t fd);
+#define        server_send_service_change_response \
+       server_send_service_register_response
+
+#endif /* ndef _SERVER_H_ */
diff --git a/usr.sbin/sdpd/sp.c b/usr.sbin/sdpd/sp.c
new file mode 100644 (file)
index 0000000..936988b
--- /dev/null
@@ -0,0 +1,126 @@
+/* $NetBSD: sp.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/sp.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * sp.c
+ *
+ * Copyright (c) 2004 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: sp.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/sp.c,v 1.1 2004/01/20 20:48:26 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+sp_profile_create_service_class_id_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t service_classes[] = {
+               SDP_SERVICE_CLASS_SERIAL_PORT
+       };
+
+       return (common_profile_create_service_class_id_list(
+                       buf, eob,
+                       (uint8_t const *) service_classes,
+                       sizeof(service_classes)));
+}
+
+static int32_t
+sp_profile_create_bluetooth_profile_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static uint16_t profile_descriptor_list[] = {
+               SDP_SERVICE_CLASS_SERIAL_PORT,
+               0x0100
+       };
+
+       return (common_profile_create_bluetooth_profile_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) profile_descriptor_list,
+                       sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+sp_profile_create_service_name(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       static char     service_name[] = "Serial Port";
+
+       return (common_profile_create_string8(
+                       buf, eob,
+                       (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+sp_profile_create_protocol_descriptor_list(
+               uint8_t *buf, uint8_t const * const eob,
+               uint8_t const *data, uint32_t datalen)
+{
+       provider_t const        *provider = (provider_t const *) data;
+       sdp_sp_profile_p        sp = (sdp_sp_profile_p) provider->data;
+
+       return (rfcomm_profile_create_protocol_descriptor_list(
+                       buf, eob,
+                       (uint8_t const *) &sp->server_channel, 1));
+}
+
+static attr_t  sp_profile_attrs[] = {
+       { SDP_ATTR_SERVICE_RECORD_HANDLE,
+         common_profile_create_service_record_handle },
+       { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+         sp_profile_create_service_class_id_list },
+       { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+         sp_profile_create_bluetooth_profile_descriptor_list },
+       { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+         common_profile_create_language_base_attribute_id_list },
+       { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+         sp_profile_create_service_name },
+       { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+         sp_profile_create_protocol_descriptor_list },
+       { 0, NULL } /* end entry */
+};
+
+static uint16_t sp_profile_uuids[] = {
+       SDP_SERVICE_CLASS_SERIAL_PORT,
+       SDP_UUID_PROTOCOL_L2CAP,
+       SDP_UUID_PROTOCOL_RFCOMM,
+};
+
+profile_t      sp_profile_descriptor = {
+       sp_profile_uuids,
+       sizeof(sp_profile_uuids),
+       sizeof(sdp_sp_profile_t),
+       common_profile_server_channel_valid,
+       (attr_t const * const) &sp_profile_attrs
+};
diff --git a/usr.sbin/sdpd/srr.c b/usr.sbin/sdpd/srr.c
new file mode 100644 (file)
index 0000000..cc16564
--- /dev/null
@@ -0,0 +1,141 @@
+/* $NetBSD: srr.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/srr.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * srr.c
+ *
+ * Copyright (c) 2004 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: srr.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/srr.c,v 1.2 2005/12/06 17:56:36 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare Service Register response
+ */
+
+int32_t
+server_prepare_service_register_response(server_p srv, int32_t fd)
+{
+       uint8_t const   *req = srv->req + sizeof(sdp_pdu_t);
+       uint8_t const   *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+       uint8_t         *rsp = srv->fdidx[fd].rsp;
+
+       profile_t       *profile = NULL;
+       provider_t      *provider = NULL;
+       bdaddr_t const  *bdaddr = NULL;
+       int32_t          uuid;
+
+       /*
+        * Minimal Service Register Request
+        *
+        * value16      - uuid 2 bytes
+        * bdaddr       - BD_ADDR 6 bytes
+        */
+
+       if (!srv->fdidx[fd].control ||
+           !srv->fdidx[fd].priv || req_end - req < 8)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Get ServiceClass UUID */
+       SDP_GET16(uuid, req);
+
+       /* Get BD_ADDR */
+       bdaddr = (bdaddr_t const *) req;
+       req += sizeof(*bdaddr);
+
+       /* Lookup profile descriptror */
+       profile = profile_get_descriptor(uuid);
+       if (profile == NULL)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Validate user data */
+       if (req_end - req < profile->dsize ||
+           profile->valid == NULL ||
+           (profile->valid)(req, req_end - req) == 0)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Register provider */
+       provider = provider_register(profile, bdaddr, fd, req, req_end - req);
+       if (provider == NULL)
+               return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
+
+       SDP_PUT16(0, rsp);
+       SDP_PUT32(provider->handle, rsp);
+
+       /* Set reply size */
+       srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
+       srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
+       srv->fdidx[fd].rsp_cs = 0;
+
+       return (0);
+}
+
+/*
+ * Send Service Register Response
+ */
+
+int32_t
+server_send_service_register_response(server_p srv, int32_t fd)
+{
+       struct iovec    iov[2];
+       sdp_pdu_t       pdu;
+       int32_t         size;
+
+       assert(srv->fdidx[fd].rsp_size < srv->fdidx[fd].rsp_limit);
+
+       pdu.pid = SDP_PDU_ERROR_RESPONSE;
+       pdu.tid = ((sdp_pdu_p)(srv->req))->tid;
+       pdu.len = htons(srv->fdidx[fd].rsp_size);
+
+       iov[0].iov_base = &pdu;
+       iov[0].iov_len = sizeof(pdu);
+
+       iov[1].iov_base = srv->fdidx[fd].rsp;
+       iov[1].iov_len = srv->fdidx[fd].rsp_size;
+
+       do {
+               size = writev(fd, (struct iovec const *) &iov, sizeof(iov)/sizeof(iov[0]));
+       } while (size < 0 && errno == EINTR);
+
+       srv->fdidx[fd].rsp_cs = 0;
+       srv->fdidx[fd].rsp_size = 0;
+       srv->fdidx[fd].rsp_limit = 0;
+
+       return ((size < 0)? errno : 0);
+}
diff --git a/usr.sbin/sdpd/ssar.c b/usr.sbin/sdpd/ssar.c
new file mode 100644 (file)
index 0000000..9d3227f
--- /dev/null
@@ -0,0 +1,180 @@
+/* $NetBSD: ssar.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/ssar.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * ssar.c
+ *
+ * Copyright (c) 2004 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: ssar.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/ssar.c,v 1.2 2005/01/05 18:37:37 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+#include "uuid-private.h"
+
+/*
+ * Prepare SDP Service Search Attribute Response
+ */
+
+int32_t
+server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
+{
+       uint8_t const   *req = srv->req + sizeof(sdp_pdu_t);
+       uint8_t const   *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+       uint8_t         *rsp = srv->fdidx[fd].rsp;
+       uint8_t const   *rsp_end = rsp + L2CAP_MTU_MAXIMUM;
+
+       uint8_t const   *aidptr = NULL;
+
+       provider_t      *provider = NULL;
+       int32_t          type, rsp_limit, ucount, aidlen, cslen, cs;
+       uint128_t        ulist[12];
+
+       /*
+        * Minimal Service Search Attribute Request request
+        *
+        * seq8 len8            - 2 bytes
+        *      uuid16 value16  - 3 bytes ServiceSearchPattern
+        * value16              - 2 bytes MaximumAttributeByteCount
+        * seq8 len8            - 2 bytes
+        *      uint16 value16  - 3 bytes AttributeIDList
+        * value8               - 1 byte  ContinuationState
+        */
+
+       /* Get ServiceSearchPattern */
+       ucount = server_get_service_search_pattern(&req, req_end, ulist);
+       if (ucount < 1 || ucount > 12)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Get MaximumAttributeByteCount */
+       if (req + 2 > req_end)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       SDP_GET16(rsp_limit, req);
+       if (rsp_limit <= 0)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Get size of AttributeIDList */
+       if (req + 1 > req_end)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       aidlen = 0;
+       SDP_GET8(type, req);
+       switch (type) {
+       case SDP_DATA_SEQ8:
+               if (req + 1 > req_end)
+                       return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+               SDP_GET8(aidlen, req);
+               break;
+
+       case SDP_DATA_SEQ16:
+               if (req + 2 > req_end)
+                       return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+               SDP_GET16(aidlen, req);
+               break;
+
+       case SDP_DATA_SEQ32:
+               if (req + 4 > req_end)
+                       return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+               SDP_GET32(aidlen, req);
+               break;
+       }
+       if (aidlen <= 0)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       aidptr = req;
+       req += aidlen;
+
+       /* Get ContinuationState */
+       if (req + 1 > req_end)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       SDP_GET8(cslen, req);
+       if (cslen == 2 && req + 2 == req_end)
+               SDP_GET16(cs, req);
+       else if (cslen == 0 && req == req_end)
+               cs = 0;
+       else
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Process the request. First, check continuation state */
+       if (srv->fdidx[fd].rsp_cs != cs)
+               return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
+       if (srv->fdidx[fd].rsp_size > 0)
+               return (0);
+
+       /*
+        * Service Search Attribute Response format
+        *
+        * value16              - 2 bytes  AttributeListByteCount (not incl.)
+        * seq8 len16           - 3 bytes
+        *      attr list       - 3+ bytes AttributeLists
+        *      [ attr list ]
+        */
+
+       rsp += 3;       /* leave space for sequence header */
+
+       for (provider = provider_get_first();
+            provider != NULL;
+            provider = provider_get_next(provider)) {
+               if (!provider_match_bdaddr(provider, &srv->req_sa.bt_bdaddr))
+                       continue;
+
+               if (!provider_match_uuid(provider, ulist, ucount))
+                       continue;
+
+               cs = server_prepare_attr_list(provider,
+                       aidptr, aidptr + aidlen, rsp, rsp_end);
+               if (cs < 0)
+                       return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
+
+               rsp += cs;
+       }
+
+       /* Set reply size (not counting PDU header and continuation state) */
+       srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
+       if (srv->fdidx[fd].rsp_limit > rsp_limit)
+               srv->fdidx[fd].rsp_limit = rsp_limit;
+
+       srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
+       srv->fdidx[fd].rsp_cs = 0;
+
+       /* Fix AttributeLists sequence header */
+       rsp = srv->fdidx[fd].rsp;
+       SDP_PUT8(SDP_DATA_SEQ16, rsp);
+       SDP_PUT16(srv->fdidx[fd].rsp_size - 3, rsp);
+
+       return (0);
+}
diff --git a/usr.sbin/sdpd/ssr.c b/usr.sbin/sdpd/ssr.c
new file mode 100644 (file)
index 0000000..edde22a
--- /dev/null
@@ -0,0 +1,309 @@
+/* $NetBSD: ssr.c,v 1.2 2007/11/09 20:08:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/ssr.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * ssr.c
+ *
+ * Copyright (c) 2004 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: ssr.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/ssr.c,v 1.3 2005/01/05 18:37:37 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+#include "uuid-private.h"
+
+/*
+ * Extract ServiceSearchPattern from request to uuid array
+ *     return count or 0 if error
+ */
+int
+server_get_service_search_pattern(uint8_t const **buf, uint8_t const *end, uint128_t *uuid)
+{
+       uint8_t const *req = *buf;
+       uint32_t type, ssplen;
+       int count;
+
+       if (req + 1 > end)
+               return 0;
+
+       SDP_GET8(type, req);
+
+       ssplen = 0;
+       switch (type) {
+       case SDP_DATA_SEQ8:
+               if (req + 1 > end)
+                       return 0;
+
+               SDP_GET8(ssplen, req);
+               break;
+
+       case SDP_DATA_SEQ16:
+               if (req + 2 > end)
+                       return 0;
+
+               SDP_GET16(ssplen, req);
+               break;
+
+       case SDP_DATA_SEQ32:
+               if (req + 4 > end)
+                       return 0;
+
+               SDP_GET32(ssplen, req);
+               break;
+
+       default:
+               return 0;
+       }
+
+       if (req + ssplen > end)
+               return 0;
+
+       count = 0;
+       while (ssplen > 0) {
+               if (count == 12)
+                       return 0;
+
+               SDP_GET8(type, req);
+               ssplen--;
+
+               switch (type) {
+               case SDP_DATA_UUID16:
+                       if (ssplen < 2)
+                               return 0;
+
+                       memcpy(uuid, &uuid_base, sizeof(*uuid));
+                       uuid->b[2] = *req++;
+                       uuid->b[3] = *req++;
+                       ssplen -= 2;
+                       break;
+
+               case SDP_DATA_UUID32:
+                       if (ssplen < 4)
+                               return 0;
+
+                       memcpy(uuid, &uuid_base, sizeof(*uuid));
+                       uuid->b[0] = *req++;
+                       uuid->b[1] = *req++;
+                       uuid->b[2] = *req++;
+                       uuid->b[3] = *req++;
+                       ssplen -= 4;
+                       break;
+
+               case SDP_DATA_UUID128:
+                       if (ssplen < 16)
+                               return 0;
+
+                       memcpy(uuid, req, 16);
+                       req += 16;
+                       ssplen -= 16;
+                       break;
+
+               default:
+                       return 0;
+               }
+
+               count++;
+               uuid++;
+       }
+
+       *buf = req;
+       return count;
+}
+
+/*
+ * Prepare SDP Service Search Response
+ */
+
+int32_t
+server_prepare_service_search_response(server_p srv, int32_t fd)
+{
+       uint8_t const   *req = srv->req + sizeof(sdp_pdu_t);
+       uint8_t const   *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+       uint8_t         *rsp = srv->fdidx[fd].rsp;
+       uint8_t const   *rsp_end = rsp + L2CAP_MTU_MAXIMUM;
+
+       provider_t      *provider = NULL;
+       int32_t          ucount, rsp_limit, cslen, cs;
+       uint128_t        ulist[12];
+
+       /*
+        * Minimal SDP Service Search Request
+        *
+        * seq8 len8            - 2 bytes
+        *      uuid16 value16  - 3 bytes ServiceSearchPattern
+        * value16              - 2 bytes MaximumServiceRecordCount
+        * value8               - 1 byte  ContinuationState
+        */
+
+       /* Get ServiceSearchPattern into uuid array */
+       ucount = server_get_service_search_pattern(&req, req_end, ulist);
+       if (ucount < 1 || ucount > 12)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Get MaximumServiceRecordCount */
+       if (req + 2 > req_end)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       SDP_GET16(rsp_limit, req);
+       if (rsp_limit <= 0)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Get ContinuationState */
+       if (req + 1 > req_end)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       SDP_GET8(cslen, req);
+       if (cslen == 2 && req + 2 == req_end)
+               SDP_GET16(cs, req);
+       else if (cslen == 0 && req == req_end)
+               cs = 0;
+       else
+               return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
+
+       /* Process the request. First, check continuation state */
+       if (srv->fdidx[fd].rsp_cs != cs)
+               return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
+       if (srv->fdidx[fd].rsp_size > 0)
+               return (0);
+
+       /*
+        * Service Search Response format
+        *
+        * value16      - 2 bytes TotalServiceRecordCount (not incl.)
+        * value16      - 2 bytes CurrentServiceRecordCount (not incl.)
+        * value32      - 4 bytes handle
+        * [ value32 ]
+        */
+
+       /* Look for the record handles and add to the rsp buffer */
+       for (provider = provider_get_first();
+            provider != NULL;
+            provider = provider_get_next(provider)) {
+               if (!provider_match_bdaddr(provider, &srv->req_sa.bt_bdaddr))
+                       continue;
+
+               if (!provider_match_uuid(provider, ulist, ucount))
+                       continue;
+
+               if (rsp + 4 > rsp_end)
+                       break;
+
+               SDP_PUT32(provider->handle, rsp);
+       }
+
+       /* Set reply size (not counting PDU header and continuation state) */
+       srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 4;
+       srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
+       srv->fdidx[fd].rsp_cs = 0;
+
+       return (0);
+}
+
+/*
+ * Send SDP Service Search Response
+ */
+
+int32_t
+server_send_service_search_response(server_p srv, int32_t fd)
+{
+       uint8_t         *rsp = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_cs;
+       uint8_t         *rsp_end = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_size;
+
+       struct iovec    iov[4];
+       sdp_pdu_t       pdu;
+       uint16_t        rcounts[2];
+       uint8_t         cs[3];
+       int32_t         size;
+
+       /* First update continuation state (assume we will send all data) */
+       size = rsp_end - rsp;
+       srv->fdidx[fd].rsp_cs += size;
+
+       if (size + 1 > srv->fdidx[fd].rsp_limit) {
+               /*
+                * We need to split out response. Add 3 more bytes for the
+                * continuation state and move rsp_end and rsp_cs backwards.
+                */
+
+               while ((rsp_end - rsp) + 3 > srv->fdidx[fd].rsp_limit) {
+                       rsp_end -= 4;
+                       srv->fdidx[fd].rsp_cs -= 4;
+               }
+
+               cs[0] = 2;
+               cs[1] = srv->fdidx[fd].rsp_cs >> 8;
+               cs[2] = srv->fdidx[fd].rsp_cs & 0xff;
+       } else
+               cs[0] = 0;
+
+       assert(rsp_end >= rsp);
+
+       rcounts[0] = srv->fdidx[fd].rsp_size / 4; /* TotalServiceRecordCount */
+       rcounts[1] = (rsp_end - rsp) / 4; /* CurrentServiceRecordCount */
+
+       pdu.pid = SDP_PDU_SERVICE_SEARCH_RESPONSE;
+       pdu.tid = ((sdp_pdu_p)(srv->req))->tid;
+       pdu.len = htons(sizeof(rcounts) + rcounts[1] * 4 + 1 + cs[0]);
+
+       rcounts[0] = htons(rcounts[0]);
+       rcounts[1] = htons(rcounts[1]);
+
+       iov[0].iov_base = &pdu;
+       iov[0].iov_len = sizeof(pdu);
+
+       iov[1].iov_base = rcounts;
+       iov[1].iov_len = sizeof(rcounts);
+
+       iov[2].iov_base = rsp;
+       iov[2].iov_len = rsp_end - rsp;
+
+       iov[3].iov_base = cs;
+       iov[3].iov_len = 1 + cs[0];
+
+       do {
+               size = writev(fd, (struct iovec const *) &iov, sizeof(iov)/sizeof(iov[0]));
+       } while (size < 0 && errno == EINTR);
+
+       /* Check if we have sent (or failed to sent) last response chunk */
+       if (srv->fdidx[fd].rsp_cs == srv->fdidx[fd].rsp_size) {
+               srv->fdidx[fd].rsp_cs = 0;
+               srv->fdidx[fd].rsp_size = 0;
+               srv->fdidx[fd].rsp_limit = 0;
+       }
+
+       return ((size < 0)? errno : 0);
+}
diff --git a/usr.sbin/sdpd/sur.c b/usr.sbin/sdpd/sur.c
new file mode 100644 (file)
index 0000000..1b76eba
--- /dev/null
@@ -0,0 +1,85 @@
+/* $NetBSD: sur.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/sur.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * sur.c
+ *
+ * Copyright (c) 2004 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: sur.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/sur.c,v 1.2 2005/12/06 17:56:36 emax Exp $
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare Service Unregister response
+ */
+
+int32_t
+server_prepare_service_unregister_response(server_p srv, int32_t fd)
+{
+       uint8_t const   *req = srv->req + sizeof(sdp_pdu_t);
+       uint8_t const   *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+       uint8_t         *rsp = srv->fdidx[fd].rsp;
+
+       provider_t      *provider = NULL;
+       uint32_t         handle;
+
+       /*
+        * Minimal Service Unregister Request
+        *
+        * value32      - uuid 4 bytes
+        */
+
+       if (!srv->fdidx[fd].control ||
+           !srv->fdidx[fd].priv || req_end - req < 4)
+               return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+       /* Get handle */
+       SDP_GET32(handle, req);
+
+       /* Lookup provider */
+       provider = provider_by_handle(handle);
+       if (provider == NULL || provider->fd != fd)
+               return (SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE);
+
+       provider_unregister(provider);
+       SDP_PUT16(0, rsp);
+
+       /* Set reply size */
+       srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
+       srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
+       srv->fdidx[fd].rsp_cs = 0;
+
+       return (0);
+}
diff --git a/usr.sbin/sdpd/uuid-private.h b/usr.sbin/sdpd/uuid-private.h
new file mode 100644 (file)
index 0000000..ca0daf7
--- /dev/null
@@ -0,0 +1,41 @@
+/* $NetBSD: uuid-private.h,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/uuid-private.h,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * uuid-private.h
+ *
+ * Copyright (c) 2005 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: uuid-private.h,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/uuid-private.h,v 1.1 2005/01/05 18:37:37 emax Exp $
+ */
+
+#ifndef _UUID_PRIVATE_H_
+#define _UUID_PRIVATE_H_
+
+extern uint128_t       uuid_base;
+extern uint128_t       uuid_public_browse_group;
+
+#endif /* ndef _UUID_PRIVATE_H_ */
diff --git a/usr.sbin/sdpd/uuid.c b/usr.sbin/sdpd/uuid.c
new file mode 100644 (file)
index 0000000..4c80f2e
--- /dev/null
@@ -0,0 +1,58 @@
+/* $NetBSD: uuid.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
+/* $DragonFly: src/usr.sbin/sdpd/uuid.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*
+ * uuid.c
+ *
+ * Copyright (c) 2005 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: uuid.c,v 1.2 2007/11/30 07:39:37 griffin Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpd/uuid.c,v 1.1 2005/01/05 18:37:37 emax Exp $
+ */
+
+#include <bluetooth.h>
+#include <sdp.h>
+#include <uuid.h>
+#include "uuid-private.h"
+
+uint128_t      uuid_base = {
+       .b = {
+               0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00,
+               0x10, 0x00,
+               0x80, 0x00,
+               0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+       }
+};
+
+uint128_t      uuid_public_browse_group = {
+       .b  = {
+               0x00, 0x00, 0x10, 0x02,
+               0x00, 0x00,
+               0x10, 0x00,
+               0x80, 0x00,
+               0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+       }
+};
diff --git a/usr.sbin/sdpquery/Makefile b/usr.sbin/sdpquery/Makefile
new file mode 100644 (file)
index 0000000..2045475
--- /dev/null
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.3 2007/05/28 12:06:31 tls Exp $
+# $DragonFly: src/usr.sbin/sdpquery/Attic/Makefile,v 1.1 2008/01/06 21:51:30 hasso Exp $
+
+PROG=          sdpquery
+MAN=           sdpquery.1
+SRCS=          sdpquery.c search.c
+
+CFLAGS+=       -I${.CURDIR}/../../sys
+DPADD+=                ${LIBBLUETOOTH} ${LIBSDP}
+LDADD+=                -lbluetooth -lsdp
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sdpquery/sdpquery.1 b/usr.sbin/sdpquery/sdpquery.1
new file mode 100644 (file)
index 0000000..5a63411
--- /dev/null
@@ -0,0 +1,210 @@
+.\" $NetBSD: sdpquery.1,v 1.8 2007/02/17 09:39:11 wiz Exp $
+.\" $DragonFly: src/usr.sbin/sdpquery/Attic/sdpquery.1,v 1.1 2008/01/06 21:51:30 hasso Exp $
+.\"
+.\" Copyright (c) 2006 Itronix Inc.
+.\" 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.
+.\" 3. The name of Itronix Inc. may not be used to endorse
+.\"    or promote products derived from this software without specific
+.\"    prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Copyright (c) 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: sdpquery.1,v 1.8 2007/02/17 09:39:11 wiz Exp $
+.\" $FreeBSD: src/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8,v 1.6 2005/07/09 19:04:43 markus Exp $
+.\"
+.Dd February 17, 2007
+.Dt SDPQUERY 1
+.Os
+.Sh NAME
+.Nm sdpquery
+.Nd SDP query utility
+.Sh SYNOPSIS
+.Nm
+.Fl h
+.Nm
+.Op Fl d Ar device
+.Fl a Ar address
+.Ar command
+.Op Ar parameters ...
+.Nm
+.Op Fl c Ar path
+.Fl l
+.Ar command
+.Op Ar parameters ...
+.Sh DESCRIPTION
+The
+.Nm
+utility attempts to query the specified Service Discovery Protocol
+(SDP) server.
+Remote SDP servers are identified by their address.
+Connection to the local SDP server is made via the control socket.
+The
+.Nm
+utility uses Service Search Attribute Requests and prints results to
+standard output and error messages to standard error.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl a Ar address"
+.It Fl a Ar address
+Connect to the remote device with the specified address.
+The address can be specified as BD_ADDR or a name.
+If a name was specified, the
+.Nm
+utility attempts to resolve the name via
+.Xr bt_gethostbyname 3 .
+If no remote address is given,
+.Nm
+attempts to contact a local SDP server via the control socket.
+.It Fl c Ar path
+Specify path to the control socket.
+The default path is
+.Pa /var/run/sdp .
+.It Fl d Ar device
+Connect from the local device with the specifed address.
+The device can be specified by BD_ADDR or device name.
+See
+.Xr btconfig 8
+for a list of devices available.
+If no device is specified, the
+.Nm
+utility will use the best available.
+.It Fl l
+Query the local SDP server via the control socket.
+.It Fl h
+Display usage message and exit.
+.El
+.Pp
+The currently supported commands in
+.Nm
+are:
+.Pp
+.Bl -tag -width ".Cm search Ar service" -compact
+.It Cm Browse Op Ar group
+Browse for services.
+The
+.Ar group
+parameter is a 16-bit UUID of the group to browse.
+If omitted, the Public Browse Group. is used.
+.Pp
+.It Cm Search Ar service
+Search for the
+.Ar service .
+The
+.Ar service
+parameter is a 16-bit UUID of the service to search for.
+For the following services it is possible to use service name
+instead of service UUID:
+.Pp
+.Bl -tag -compact
+.It CIP
+Common ISDN Access
+.It CTP
+Cordless Telephony
+.It DUN
+DialUp Networking
+.It FAX
+Fax
+.It FTRN
+OBEX File Transfer
+.It GN
+Group ad-hoc Network
+.It HID
+Human Interface Device
+.It HF
+Handsfree
+.It HSET
+Headset
+.It LAN
+LAN Access Using PPP
+.It NAP
+Network Access Point
+.It OPUSH
+OBEX Object Push
+.It PANU
+Personal Area Networking User
+.It SP
+Serial Port
+.El
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr bluetooth 3 ,
+.Xr sdp 3 ,
+.Xr btconfig 8 ,
+.Xr sdpd 8
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Fx 5.3
+as
+.Nm sdpcontrol .
+It was ported to
+.Nx 4.0
+under its present name by
+.An Iain Hibbert
+under the sponsorship of Itronix, Inc and imported into
+.Dx 1.11 .
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
+.An Iain Hibbert
+for Itronix, Inc.
+.Sh CAVEATS
+The
+.Nm
+utility only requests the following attributes from the SDP server:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+Service Record Handle
+.It
+Service Class ID List
+.It
+Protocol Descriptor List
+.It
+Bluetooth Profile Descriptor List
+.El
diff --git a/usr.sbin/sdpquery/sdpquery.c b/usr.sbin/sdpquery/sdpquery.c
new file mode 100644 (file)
index 0000000..5bb7d77
--- /dev/null
@@ -0,0 +1,152 @@
+/* $NetBSD: sdpquery.c,v 1.3 2007/03/30 21:25:00 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpquery/Attic/sdpquery.c,v 1.1 2008/01/06 21:51:30 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 <assert.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sdpquery.h"
+
+static void usage(void);
+
+const char *control_socket;
+
+static struct command {
+       const char      *command;
+       int             (*handler)(bdaddr_t *, bdaddr_t *, int, char const **);
+       const char      *usage;
+} commands[] = {
+       { "Browse",     do_sdp_browse,  "[UUID]"        },
+       { "Search",     do_sdp_search,  "<service>"     },
+       { NULL,         NULL,           NULL            }
+};
+
+int
+main(int argc, char *argv[])
+{
+       bdaddr_t        laddr, raddr;
+       struct command *cmd;
+       int             ch, local;
+
+       bdaddr_copy(&laddr, BDADDR_ANY);
+       bdaddr_copy(&raddr, BDADDR_ANY);
+       control_socket = NULL;
+       local = 0;
+
+       while ((ch = getopt(argc, argv, "a:c:d:hl")) != -1) {
+               switch (ch) {
+               case 'a': /* remote address */
+                       if (!bt_aton(optarg, &raddr)) {
+                               struct hostent  *he = NULL;
+
+                               if ((he = bt_gethostbyname(optarg)) == NULL)
+                                       errx(EXIT_FAILURE, "%s: %s",
+                                               optarg, hstrerror(h_errno));
+
+                               bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
+                       }
+                       break;
+
+               case 'c':
+                       control_socket = optarg;
+                       break;
+
+               case 'd': /* local device address */
+                       if (!bt_devaddr(optarg, &laddr))
+                               err(EXIT_FAILURE, "%s", optarg);
+
+                       break;
+
+               case 'l': /* local sdpd */
+                       local = 1;
+                       break;
+
+               case 'h':
+               default:
+                       usage();
+                       /* NOT REACHED */
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       optind = 0;
+       optreset = 1;
+
+       if (argc < 1
+           || (bdaddr_any(&raddr) && !local)
+           || (!bdaddr_any(&raddr) && local))
+               usage();
+
+       for (cmd = commands ; cmd->command != NULL; cmd++) {
+               if (strcasecmp(*argv, cmd->command) == 0)
+                       return (*cmd->handler)(&laddr, &raddr, --argc, (char const **)++argv);
+       }
+
+       errx(EXIT_FAILURE, "%s: Unknown Command", *argv);
+}
+
+/* Usage */
+static void
+usage(void)
+{
+       struct command *cmd;
+
+       fprintf(stderr,
+               "Usage: %s [-d device] -a bdaddr <command> [parameters..]\n"
+               "       %s [-c path] -l <command> [parameters..]\n"
+               "\n", getprogname(), getprogname());
+
+       fprintf(stderr,
+               "Where:\n"
+               "\t-a bdaddr    remote address\n"
+               "\t-c path      path to control socket\n"
+               "\t-d device    local device address\n"
+               "\t-l           connect to the local SDP server via control socket\n"
+               "\t-h           display usage and quit\n"
+               "\n"
+               "Commands:\n");
+
+       for (cmd = commands ; cmd->command != NULL ; cmd++)
+               fprintf(stderr, "\t%-13s%s\n", cmd->command, cmd->usage);
+
+       exit(EXIT_FAILURE);
+}
diff --git a/usr.sbin/sdpquery/sdpquery.h b/usr.sbin/sdpquery/sdpquery.h
new file mode 100644 (file)
index 0000000..4b34455
--- /dev/null
@@ -0,0 +1,43 @@
+/* $NetBSD: sdpquery.h,v 1.2 2006/07/26 10:54:49 tron Exp $ */
+/* $DragonFly: src/usr.sbin/sdpquery/Attic/sdpquery.h,v 1.1 2008/01/06 21:51:30 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.
+ */
+
+#ifndef __BTQUERY_H__
+#define __BTQUERY_H__
+
+extern const char *control_socket;
+
+int do_sdp_browse(bdaddr_t *, bdaddr_t *, int, char const **);
+int do_sdp_search(bdaddr_t *, bdaddr_t *, int, char const **);
+
+#endif /* __BTQUERY_H__ */
diff --git a/usr.sbin/sdpquery/search.c b/usr.sbin/sdpquery/search.c
new file mode 100644 (file)
index 0000000..767bb15
--- /dev/null
@@ -0,0 +1,693 @@
+/* $NetBSD: search.c,v 1.6 2007/11/06 21:35:52 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/sdpquery/Attic/search.c,v 1.1 2008/01/06 21:51:30 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * 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.
+ * 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.
+ */
+/*
+ * 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.6 2007/11/06 21:35:52 plunky Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/sdpcontrol/search.c,v 1.4 2005/05/27 19:11:33 emax Exp $
+ */
+
+#include <netinet/in.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sdpquery.h"
+
+/* List of the attributes we are looking for */
+static uint32_t        attrs[] =
+{
+       SDP_ATTR_RANGE( SDP_ATTR_SERVICE_RECORD_HANDLE,
+                       SDP_ATTR_SERVICE_RECORD_HANDLE),
+       SDP_ATTR_RANGE( SDP_ATTR_SERVICE_CLASS_ID_LIST,
+                       SDP_ATTR_SERVICE_CLASS_ID_LIST),
+       SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+                       SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
+       SDP_ATTR_RANGE( SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+                       SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST)
+};
+#define attrs_len      (sizeof(attrs)/sizeof(attrs[0]))
+
+/* Buffer for the attributes */
+#define NRECS  25      /* request this much records from the SDP server */
+#define        BSIZE   256     /* one attribute buffer size */
+static uint8_t         buffer[NRECS * attrs_len][BSIZE];
+
+/* SDP attributes */
+static sdp_attr_t      values[NRECS * attrs_len];
+#define values_len     (sizeof(values)/sizeof(values[0]))
+
+/*
+ * Print Service Class ID List
+ *
+ * The ServiceClassIDList attribute consists of a data element sequence in
+ * which each data element is a UUID representing the service classes that
+ * a given service record conforms to. The UUIDs are listed in order from
+ * the most specific class to the most general class. The ServiceClassIDList
+ * must contain at least one service class UUID.
+ */
+
+static void
+print_service_class_id_list(uint8_t const *start, uint8_t const *end)
+{
+       uint32_t        type, len, value;
+
+       if (end - start < 2) {
+               fprintf(stderr, "Invalid Service Class ID List. " \
+                               "Too short, len=%zd\n", end - start);
+               return;
+       }
+
+       SDP_GET8(type, start);
+       switch (type) {
+       case SDP_DATA_SEQ8:
+               SDP_GET8(len, start);
+               break;
+
+       case SDP_DATA_SEQ16:
+               SDP_GET16(len, start);
+               break;
+
+       case SDP_DATA_SEQ32:
+               SDP_GET32(len, start);
+               break;
+
+       default:
+               fprintf(stderr, "Invalid Service Class ID List. " \
+                               "Not a sequence, type=%#x\n", type);
+               return;
+               /* NOT REACHED */
+       }
+
+       while (start < end) {
+               SDP_GET8(type, start);
+               switch (type) {
+               case SDP_DATA_UUID16:
+                       SDP_GET16(value, start);
+                       fprintf(stdout, "\t%s (%#4.4x)\n",
+                                       sdp_uuid2desc(value), value);
+                       break;
+
+               case SDP_DATA_UUID32:
+                       SDP_GET32(value, start);
+                       fprintf(stdout, "\t%#8.8x\n", value);
+                       break;
+
+               case SDP_DATA_UUID128: {
+                       int128_t        uuid;
+
+                       SDP_GET_UUID128(&uuid, start);
+                       fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
+                                       ntohl(*(uint32_t *)&uuid.b[0]),
+                                       ntohs(*(uint16_t *)&uuid.b[4]),
+                                       ntohs(*(uint16_t *)&uuid.b[6]),
+                                       ntohs(*(uint16_t *)&uuid.b[8]),
+                                       ntohs(*(uint16_t *)&uuid.b[10]),
+                                       ntohl(*(uint32_t *)&uuid.b[12]));
+                       } break;
+
+               default:
+                       fprintf(stderr, "Invalid Service Class ID List. " \
+                                       "Not a UUID, type=%#x\n", type);
+                       return;
+                       /* NOT REACHED */
+               }
+       }
+} /* print_service_class_id_list */
+
+/*
+ * Print Protocol Descriptor List
+ *
+ * If the ProtocolDescriptorList describes a single stack, it takes the form
+ * of a data element sequence in which each element of the sequence is a
+ * protocol descriptor. Each protocol descriptor is, in turn, a data element
+ * sequence whose first element is a UUID identifying the protocol and whose
+ * successive elements are protocol-specific parameters. The protocol
+ * descriptors are listed in order from the lowest layer protocol to the
+ * highest layer protocol used to gain access to the service. If it is possible
+ * for more than one kind of protocol stack to be used to gain access to the
+ * service, the ProtocolDescriptorList takes the form of a data element
+ * alternative where each member is a data element sequence as described above.
+ */
+
+static void
+print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
+{
+       union {
+               uint8_t         uint8;
+               uint16_t        uint16;
+               uint32_t        uint32;
+               uint64_t        uint64;
+               int128_t        int128;
+       }                       value;
+       uint32_t                type, len, param;
+
+       /* Get Protocol UUID */
+       SDP_GET8(type, start);
+       switch (type) {
+       case SDP_DATA_UUID16:
+               SDP_GET16(value.uint16, start);
+               fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16),
+                               value.uint16);
+               break;
+
+       case SDP_DATA_UUID32:
+               SDP_GET32(value.uint32, start);
+               fprintf(stdout, "\t%#8.8x\n", value.uint32);
+               break;
+
+       case SDP_DATA_UUID128:
+               SDP_GET_UUID128(&value.int128, start);
+               fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
+                               ntohl(*(uint32_t *)&value.int128.b[0]),
+                               ntohs(*(uint16_t *)&value.int128.b[4]),
+                               ntohs(*(uint16_t *)&value.int128.b[6]),
+                               ntohs(*(uint16_t *)&value.int128.b[8]),
+                               ntohs(*(uint16_t *)&value.int128.b[10]),
+                               ntohl(*(uint32_t *)&value.int128.b[12]));
+               break;
+
+       default:
+               fprintf(stderr, "Invalid Protocol Descriptor. " \
+                               "Not a UUID, type=%#x\n", type);
+               return;
+               /* NOT REACHED */
+       }
+
+       /* Protocol specific parameters */
+       for (param = 1; start < end; param ++) {
+               fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param);
+
+               SDP_GET8(type, start);
+               switch (type) {
+               case SDP_DATA_NIL:
+                       fprintf(stdout, "nil\n");
+                       break;
+
+               case SDP_DATA_UINT8:
+               case SDP_DATA_INT8:
+               case SDP_DATA_BOOL:
+                       SDP_GET8(value.uint8, start);
+                       fprintf(stdout, "u/int8/bool %u\n", value.uint8);
+                       break;
+
+               case SDP_DATA_UINT16:
+               case SDP_DATA_INT16:
+               case SDP_DATA_UUID16:
+                       SDP_GET16(value.uint16, start);
+                       fprintf(stdout, "u/int/uuid16 %u\n", value.uint16);
+                       break;
+
+               case SDP_DATA_UINT32:
+               case SDP_DATA_INT32:
+               case SDP_DATA_UUID32:
+                       SDP_GET32(value.uint32, start);
+                       fprintf(stdout, "u/int/uuid32 %u\n", value.uint32);
+                       break;
+
+               case SDP_DATA_UINT64:
+               case SDP_DATA_INT64:
+                       SDP_GET64(value.uint64, start);
+                       fprintf(stdout, "u/int64 %ju\n", value.uint64);
+                       break;
+
+               case SDP_DATA_UINT128:
+               case SDP_DATA_INT128:
+                       SDP_GET128(&value.int128, start);
+                       fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
+                               *(uint32_t *)&value.int128.b[0],
+                               *(uint32_t *)&value.int128.b[4],
+                               *(uint32_t *)&value.int128.b[8],
+                               *(uint32_t *)&value.int128.b[12]);
+                       break;
+
+               case SDP_DATA_UUID128:
+                       SDP_GET_UUID128(&value.int128, start);
+                       fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
+                               ntohl(*(uint32_t *)&value.int128.b[0]),
+                               ntohs(*(uint16_t *)&value.int128.b[4]),
+                               ntohs(*(uint16_t *)&value.int128.b[6]),
+                               ntohs(*(uint16_t *)&value.int128.b[8]),
+                               ntohs(*(uint16_t *)&value.int128.b[10]),
+                               ntohl(*(uint32_t *)&value.int128.b[12]));
+                       break;
+
+               case SDP_DATA_STR8:
+               case SDP_DATA_URL8:
+                       SDP_GET8(len, start);
+                       fprintf(stdout, "%*.*s\n", len, len,  start);
+                       start += len;
+                       break;
+
+               case SDP_DATA_STR16:
+               case SDP_DATA_URL16:
+                       SDP_GET16(len, start);
+                       fprintf(stdout, "%*.*s\n", len, len,  start);
+                       start += len;
+                       break;
+
+               case SDP_DATA_STR32:
+               case SDP_DATA_URL32:
+                       SDP_GET32(len, start);
+                       fprintf(stdout, "%*.*s\n", len, len,  start);
+                       start += len;
+                       break;
+
+               case SDP_DATA_SEQ8:
+               case SDP_DATA_ALT8:
+                       SDP_GET8(len, start);
+                       for (; len > 0; start ++, len --)
+                               fprintf(stdout, "%#2.2x ", *start);
+                       fprintf(stdout, "\n");
+                       break;
+
+               case SDP_DATA_SEQ16:
+               case SDP_DATA_ALT16:
+                       SDP_GET16(len, start);
+                       for (; len > 0; start ++, len --)
+                               fprintf(stdout, "%#2.2x ", *start);
+                       fprintf(stdout, "\n");
+                       break;
+
+               case SDP_DATA_SEQ32:
+               case SDP_DATA_ALT32:
+                       SDP_GET32(len, start);
+                       for (; len > 0; start ++, len --)
+                               fprintf(stdout, "%#2.2x ", *start);
+                       fprintf(stdout, "\n");
+                       break;
+
+               default:
+                       fprintf(stderr, "Invalid Protocol Descriptor. " \
+                                       "Unknown data type: %#02x\n", type);
+                       return;
+                       /* NOT REACHED */
+               }
+       }
+} /* print_protocol_descriptor */
+
+static void
+print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
+{
+       uint32_t        type, len;
+
+       if (end - start < 2) {
+               fprintf(stderr, "Invalid Protocol Descriptor List. " \
+                               "Too short, len=%zd\n", end - start);
+               return;
+       }
+
+       SDP_GET8(type, start);
+       switch (type) {
+       case SDP_DATA_SEQ8:
+               SDP_GET8(len, start);
+               break;
+
+       case SDP_DATA_SEQ16:
+               SDP_GET16(len, start);
+               break;
+
+       case SDP_DATA_SEQ32:
+               SDP_GET32(len, start);
+               break;
+
+       default:
+               fprintf(stderr, "Invalid Protocol Descriptor List. " \
+                               "Not a sequence, type=%#x\n", type);
+               return;
+               /* NOT REACHED */
+       }
+
+       while (start < end) {
+               SDP_GET8(type, start);
+               switch (type) {
+               case SDP_DATA_SEQ8:
+                       SDP_GET8(len, start);
+                       break;
+
+               case SDP_DATA_SEQ16:
+                       SDP_GET16(len, start);
+                       break;
+
+               case SDP_DATA_SEQ32:
+                       SDP_GET32(len, start);
+                       break;
+
+               default:
+                       fprintf(stderr, "Invalid Protocol Descriptor List. " \
+                                       "Not a sequence, type=%#x\n", type);
+                       return;
+                       /* NOT REACHED */
+               }
+
+               print_protocol_descriptor(start, start + len);
+               start += len;
+       }
+} /* print_protocol_descriptor_list */
+
+/*
+ * Print Bluetooth Profile Descriptor List
+ *
+ * The BluetoothProfileDescriptorList attribute consists of a data element
+ * sequence in which each element is a profile descriptor that contains
+ * information about a Bluetooth profile to which the service represented by
+ * this service record conforms. Each profile descriptor is a data element
+ * sequence whose first element is the UUID assigned to the profile and whose
+ * second element is a 16-bit profile version number. Each version of a profile
+ * is assigned a 16-bit unsigned integer profile version number, which consists
+ * of two 8-bit fields. The higher-order 8 bits contain the major version
+ * number field and the lower-order 8 bits contain the minor version number
+ * field.
+ */
+
+static void
+print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end)
+{
+       uint32_t        type, len, value;
+
+       if (end - start < 2) {
+               fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
+                               "Too short, len=%zd\n", end - start);
+               return;
+       }
+
+       SDP_GET8(type, start);
+       switch (type) {
+       case SDP_DATA_SEQ8:
+               SDP_GET8(len, start);
+               break;
+
+       case SDP_DATA_SEQ16:
+               SDP_GET16(len, start);
+               break;
+
+       case SDP_DATA_SEQ32:
+               SDP_GET32(len, start);
+               break;
+
+       default:
+               fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
+                               "Not a sequence, type=%#x\n", type);
+               return;
+               /* NOT REACHED */
+       }
+
+       while (start < end) {
+               SDP_GET8(type, start);
+               switch (type) {
+               case SDP_DATA_SEQ8:
+                       SDP_GET8(len, start);
+                       break;
+
+               case SDP_DATA_SEQ16:
+                       SDP_GET16(len, start);
+                       break;
+
+               case SDP_DATA_SEQ32:
+                       SDP_GET32(len, start);
+                       break;
+
+               default:
+                       fprintf(stderr, "Invalid Bluetooth Profile " \
+                                       "Descriptor List. " \
+                                       "Not a sequence, type=%#x\n", type);
+                       return;
+                       /* NOT REACHED */
+               }
+
+               /* Get UUID */
+               SDP_GET8(type, start);
+               switch (type) {
+               case SDP_DATA_UUID16:
+                       SDP_GET16(value, start);
+                       fprintf(stdout, "\t%s (%#4.4x) ",
+                                       sdp_uuid2desc(value), value);
+                       break;
+
+               case SDP_DATA_UUID32:
+                       SDP_GET32(value, start);
+                       fprintf(stdout, "\t%#8.8x ", value);
+                       break;
+
+               case SDP_DATA_UUID128: {
+                       int128_t        uuid;
+
+                       SDP_GET_UUID128(&uuid, start);
+                       fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ",
+                                       ntohl(*(uint32_t *)&uuid.b[0]),
+                                       ntohs(*(uint16_t *)&uuid.b[4]),
+                                       ntohs(*(uint16_t *)&uuid.b[6]),
+                                       ntohs(*(uint16_t *)&uuid.b[8]),
+                                       ntohs(*(uint16_t *)&uuid.b[10]),
+                                       ntohl(*(uint32_t *)&uuid.b[12]));
+                       } break;
+
+               default:
+                       fprintf(stderr, "Invalid Bluetooth Profile " \
+                                       "Descriptor List. " \
+                                       "Not a UUID, type=%#x\n", type);
+                       return;
+                       /* NOT REACHED */
+               }
+
+               /* Get version */
+               SDP_GET8(type, start);
+               if (type != SDP_DATA_UINT16) {
+                       fprintf(stderr, "Invalid Bluetooth Profile " \
+                                       "Descriptor List. " \
+                                       "Invalid version type=%#x\n", type);
+                       return;
+               }
+
+               SDP_GET16(value, start);
+               fprintf(stdout, "ver. %d.%d\n",
+                               (value >> 8) & 0xff, value & 0xff);
+       }
+} /* print_bluetooth_profile_descriptor_list */
+
+struct service {
+       const char      *name;
+       uint16_t        class;
+       const char      *description;
+} services[] = {
+       { "CIP",        SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS,
+         "Common ISDN Access"          },
+       { "CTP",        SDP_SERVICE_CLASS_CORDLESS_TELEPHONY,
+         "Cordless Telephony"          },
+       { "DUN",        SDP_SERVICE_CLASS_DIALUP_NETWORKING,
+         "Dial Up Networking"          },
+       { "FAX",        SDP_SERVICE_CLASS_FAX,
+         "Fax"                         },
+       { "FTRN",       SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
+         "Obex File Transfer"          },
+       { "GN",         SDP_SERVICE_CLASS_GN,
+         "Group ad-hoc Network"        },
+       { "HID",        SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE,
+         "Human Interface Device"      },
+       { "HF",         SDP_SERVICE_CLASS_HANDSFREE,
+         "Handsfree"                   },
+       { "HSET",       SDP_SERVICE_CLASS_HEADSET,
+         "Headset"                     },
+       { "LAN",        SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
+         "Lan access using PPP"        },
+       { "NAP",        SDP_SERVICE_CLASS_NAP,
+         "Network Access Point"        },
+       { "OPUSH",      SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
+         "OBEX Object Push"            },
+       { "PANU",       SDP_SERVICE_CLASS_PANU,
+         "Personal Area Networking User"               },
+       { "SP",         SDP_SERVICE_CLASS_SERIAL_PORT,
+         "Serial Port"                 },
+       { NULL,         0,
+         NULL                          }
+};
+
+/* Perform SDP search command */
+int
+do_sdp_search(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
+{
+       struct service  *s;
+       void            *xs;
+       char            *ep;
+       int32_t          n, type, value;
+       uint16_t         service;
+
+       if (argc != 1)
+               goto usage;
+
+       service = strtoul(*argv, &ep, 16);
+       if (*ep != 0) {
+               for (s = services ; ; s++) {
+                       if (s->name == NULL)
+                               goto usage;
+
+                       if (strcasecmp(s->name, *argv) == 0)
+                               break;
+               }
+               service = s->class;
+       }
+
+       /* Initialize attribute values array */
+       for (n = 0; n < values_len; n ++) {
+               values[n].flags = SDP_ATTR_INVALID;
+               values[n].attr = 0;
+               values[n].vlen = BSIZE;
+               values[n].value = buffer[n];
+       }
+
+       if (bdaddr_any(raddr))
+               xs = sdp_open_local(control_socket);
+       else
+               xs = sdp_open(laddr, raddr);
+
+       if (xs == NULL || (errno = sdp_error(xs)) != 0)
+               err(EXIT_FAILURE, "sdp_open");
+
+       /* Do SDP Service Search Attribute Request */
+       n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values);
+       if (n != 0)
+               err(EXIT_FAILURE, "sdp_search");
+
+       sdp_close(xs);
+
+       /* Print attributes values */
+       for (n = 0; n < values_len; n ++) {
+               if (values[n].flags != SDP_ATTR_OK)
+                       break;
+
+               switch (values[n].attr) {
+               case SDP_ATTR_SERVICE_RECORD_HANDLE:
+                       fprintf(stdout, "\n");
+                       if (values[n].vlen == 5) {
+                               SDP_GET8(type, values[n].value);
+                               if (type == SDP_DATA_UINT32) {
+                                       SDP_GET32(value, values[n].value);
+                                       fprintf(stdout, "Record Handle: " \
+                                                       "%#8.8x\n", value);
+                               } else
+                                       fprintf(stderr, "Invalid type=%#x " \
+                                                       "Record Handle " \
+                                                       "attribute!\n", type);
+                       } else
+                               fprintf(stderr, "Invalid size=%d for Record " \
+                                               "Handle attribute\n",
+                                               values[n].vlen);
+                       break;
+
+               case SDP_ATTR_SERVICE_CLASS_ID_LIST:
+                       fprintf(stdout, "Service Class ID List:\n");
+                       print_service_class_id_list(values[n].value,
+                                       values[n].value + values[n].vlen);
+                       break;
+
+               case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
+                       fprintf(stdout, "Protocol Descriptor List:\n");
+                       print_protocol_descriptor_list(values[n].value,
+                                       values[n].value + values[n].vlen);
+                       break;
+
+               case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
+                       fprintf(stdout, "Bluetooth Profile Descriptor List:\n");
+                       print_bluetooth_profile_descriptor_list(values[n].value,
+                                       values[n].value + values[n].vlen);
+                       break;
+
+               default:
+                       fprintf(stderr, "Unexpected attribute ID=%#4.4x\n",
+                                       values[n].attr);
+                       break;
+               }
+       }
+
+       return EXIT_SUCCESS;
+
+usage:
+       fprintf(stderr, "Known services:\n");
+       for (s = services ; s->name != NULL ; s++)
+               fprintf(stderr, "\t%s\t%s\n", s->name, s->description);
+
+       return EXIT_FAILURE;
+} /* do_sdp_search */
+
+/* Perform SDP browse command */
+int
+do_sdp_browse(bdaddr_t *laddr, bdaddr_t *raddr, int argc, char const **argv)
+{
+#undef _STR
+#undef STR
+#define        _STR(x) #x
+#define        STR(x)  _STR(x)
+
+       static char     const * av[] = {
+               STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP),
+               NULL
+       };
+
+       switch (argc) {
+       case 0:
+               argc = 1;
+               argv =  (char const **) av;
+               /* FALL THROUGH */
+       case 1:
+               return (do_sdp_search(laddr, raddr, argc, argv));
+       }
+
+       return EXIT_FAILURE;
+} /* do_sdp_browse */