From 5dcc9b0168325968f54a3d24b5c1243485999d3e Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Sun, 6 Jan 2008 21:51:30 +0000 Subject: [PATCH] Add sdpd(8) (Bluetooth Service Discovery Protocol daemon) and sdpquery(1) (SDP query utility). Also add btconfig rc script in progress. Obtained-from: NetBSD --- etc/Makefile | 8 +- etc/group | 3 +- etc/master.passwd | 3 +- etc/rc.d/Makefile | 10 +- etc/rc.d/btconfig | 67 ++++ etc/rc.d/sdpd | 17 + usr.sbin/Makefile | 4 +- usr.sbin/sdpd/Makefile | 12 + usr.sbin/sdpd/bgd.c | 109 ++++++ usr.sbin/sdpd/dun.c | 146 ++++++++ usr.sbin/sdpd/ftrn.c | 127 +++++++ usr.sbin/sdpd/hf.c | 162 ++++++++ usr.sbin/sdpd/hset.c | 143 ++++++++ usr.sbin/sdpd/irmc.c | 143 ++++++++ usr.sbin/sdpd/irmc_command.c | 127 +++++++ usr.sbin/sdpd/lan.c | 186 ++++++++++ usr.sbin/sdpd/log.c | 131 +++++++ usr.sbin/sdpd/log.h | 49 +++ usr.sbin/sdpd/main.c | 243 ++++++++++++ usr.sbin/sdpd/opush.c | 143 ++++++++ usr.sbin/sdpd/profile.c | 397 ++++++++++++++++++++ usr.sbin/sdpd/profile.h | 93 +++++ usr.sbin/sdpd/provider.c | 235 ++++++++++++ usr.sbin/sdpd/provider.h | 111 ++++++ usr.sbin/sdpd/sar.c | 319 ++++++++++++++++ usr.sbin/sdpd/scr.c | 94 +++++ usr.sbin/sdpd/sd.c | 220 +++++++++++ usr.sbin/sdpd/sdpd.8 | 164 +++++++++ usr.sbin/sdpd/server.c | 673 ++++++++++++++++++++++++++++++++++ usr.sbin/sdpd/server.h | 136 +++++++ usr.sbin/sdpd/sp.c | 126 +++++++ usr.sbin/sdpd/srr.c | 141 +++++++ usr.sbin/sdpd/ssar.c | 180 +++++++++ usr.sbin/sdpd/ssr.c | 309 ++++++++++++++++ usr.sbin/sdpd/sur.c | 85 +++++ usr.sbin/sdpd/uuid-private.h | 41 +++ usr.sbin/sdpd/uuid.c | 58 +++ usr.sbin/sdpquery/Makefile | 12 + usr.sbin/sdpquery/sdpquery.1 | 210 +++++++++++ usr.sbin/sdpquery/sdpquery.c | 152 ++++++++ usr.sbin/sdpquery/sdpquery.h | 43 +++ usr.sbin/sdpquery/search.c | 693 +++++++++++++++++++++++++++++++++++ 42 files changed, 6316 insertions(+), 9 deletions(-) create mode 100644 etc/rc.d/btconfig create mode 100644 etc/rc.d/sdpd create mode 100644 usr.sbin/sdpd/Makefile create mode 100644 usr.sbin/sdpd/bgd.c create mode 100644 usr.sbin/sdpd/dun.c create mode 100644 usr.sbin/sdpd/ftrn.c create mode 100644 usr.sbin/sdpd/hf.c create mode 100644 usr.sbin/sdpd/hset.c create mode 100644 usr.sbin/sdpd/irmc.c create mode 100644 usr.sbin/sdpd/irmc_command.c create mode 100644 usr.sbin/sdpd/lan.c create mode 100644 usr.sbin/sdpd/log.c create mode 100644 usr.sbin/sdpd/log.h create mode 100644 usr.sbin/sdpd/main.c create mode 100644 usr.sbin/sdpd/opush.c create mode 100644 usr.sbin/sdpd/profile.c create mode 100644 usr.sbin/sdpd/profile.h create mode 100644 usr.sbin/sdpd/provider.c create mode 100644 usr.sbin/sdpd/provider.h create mode 100644 usr.sbin/sdpd/sar.c create mode 100644 usr.sbin/sdpd/scr.c create mode 100644 usr.sbin/sdpd/sd.c create mode 100644 usr.sbin/sdpd/sdpd.8 create mode 100644 usr.sbin/sdpd/server.c create mode 100644 usr.sbin/sdpd/server.h create mode 100644 usr.sbin/sdpd/sp.c create mode 100644 usr.sbin/sdpd/srr.c create mode 100644 usr.sbin/sdpd/ssar.c create mode 100644 usr.sbin/sdpd/ssr.c create mode 100644 usr.sbin/sdpd/sur.c create mode 100644 usr.sbin/sdpd/uuid-private.h create mode 100644 usr.sbin/sdpd/uuid.c create mode 100644 usr.sbin/sdpquery/Makefile create mode 100644 usr.sbin/sdpquery/sdpquery.1 create mode 100644 usr.sbin/sdpquery/sdpquery.c create mode 100644 usr.sbin/sdpquery/sdpquery.h create mode 100644 usr.sbin/sdpquery/search.c diff --git a/etc/Makefile b/etc/Makefile index 87195c02f8..1f58a5b9d8 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -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 diff --git a/etc/group b/etc/group index 6a8ab87bba..d54ee08128 100644 --- 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: diff --git a/etc/master.passwd b/etc/master.passwd index 7485ac2223..9b75aeec5e 100644 --- a/etc/master.passwd +++ b/etc/master.passwd @@ -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 diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index eecc3847dc..da9e633b88 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -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 @@ -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 index 0000000000..7c8509872e --- /dev/null +++ b/etc/rc.d/btconfig @@ -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_} 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 index 0000000000..6888930c41 --- /dev/null +++ b/etc/rc.d/sdpd @@ -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" diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 1d1f5adb60..a33b7b8d6f 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -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 index 0000000000..a09437ae79 --- /dev/null +++ b/usr.sbin/sdpd/Makefile @@ -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 diff --git a/usr.sbin/sdpd/bgd.c b/usr.sbin/sdpd/bgd.c new file mode 100644 index 0000000000..a29734e32d --- /dev/null +++ b/usr.sbin/sdpd/bgd.c @@ -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 + * 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 +#include +#include +#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 index 0000000000..980b66c550 --- /dev/null +++ b/usr.sbin/sdpd/dun.c @@ -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 + * 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 +#include +#include +#include +#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 index 0000000000..828efdfb72 --- /dev/null +++ b/usr.sbin/sdpd/ftrn.c @@ -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 + * 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 +#include +#include +#include +#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 index 0000000000..3d3ccbda2e --- /dev/null +++ b/usr.sbin/sdpd/hf.c @@ -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 +#include +#include +#include +#include + +#include + +#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 index 0000000000..d33e42e737 --- /dev/null +++ b/usr.sbin/sdpd/hset.c @@ -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 +#include +#include +#include +#include + +#include + +#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 index 0000000000..2b78887d49 --- /dev/null +++ b/usr.sbin/sdpd/irmc.c @@ -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 + * 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 +#include +#include +#include +#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 index 0000000000..801bb19af8 --- /dev/null +++ b/usr.sbin/sdpd/irmc_command.c @@ -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 + * 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 +#include +#include +#include +#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 index 0000000000..1cd054f3ff --- /dev/null +++ b/usr.sbin/sdpd/lan.c @@ -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 + * 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 +#include +#include +#include +#include +#include +#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 index 0000000000..33f9bf10ab --- /dev/null +++ b/usr.sbin/sdpd/log.c @@ -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 + * 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 +#include +#include + +#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 index 0000000000..a53d9b255e --- /dev/null +++ b/usr.sbin/sdpd/log.h @@ -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 + * 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 index 0000000000..50da99a716 --- /dev/null +++ b/usr.sbin/sdpd/main.c @@ -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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "server.h" + +#include +#include +#include +#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 index 0000000000..24c8a30b81 --- /dev/null +++ b/usr.sbin/sdpd/opush.c @@ -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 + * 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 +#include +#include +#include +#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 index 0000000000..c1d33a5d16 --- /dev/null +++ b/usr.sbin/sdpd/profile.c @@ -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 + * 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 +#include +#include +#include +#include +#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 index 0000000000..87e4b915b4 --- /dev/null +++ b/usr.sbin/sdpd/profile.h @@ -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 + * 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 index 0000000000..cee68ff988 --- /dev/null +++ b/usr.sbin/sdpd/provider.c @@ -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 + * 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 +#include +#include +#include +#include +#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 index 0000000000..a1eeca4a60 --- /dev/null +++ b/usr.sbin/sdpd/provider.h @@ -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 + * 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 index 0000000000..1f3ca787c7 --- /dev/null +++ b/usr.sbin/sdpd/sar.c @@ -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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include /* 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 index 0000000000..df19fff73a --- /dev/null +++ b/usr.sbin/sdpd/scr.c @@ -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 + * 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 +#include +#include +#include +#include +#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 index 0000000000..16fbd00b3c --- /dev/null +++ b/usr.sbin/sdpd/sd.c @@ -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 + * 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 +#include +#include +#include +#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 index 0000000000..defc347b52 --- /dev/null +++ b/usr.sbin/sdpd/sdpd.8 @@ -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 +.\" 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 index 0000000000..cc84b65dbc --- /dev/null +++ b/usr.sbin/sdpd/server.c @@ -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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000000..74411d18c0 --- /dev/null +++ b/usr.sbin/sdpd/server.h @@ -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 + * 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 index 0000000000..936988be01 --- /dev/null +++ b/usr.sbin/sdpd/sp.c @@ -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 + * 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 +#include +#include +#include +#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 index 0000000000..cc16564493 --- /dev/null +++ b/usr.sbin/sdpd/srr.c @@ -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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000000..9d3227f9ec --- /dev/null +++ b/usr.sbin/sdpd/ssar.c @@ -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 + * 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 +#include +#include +#include +#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 index 0000000000..edde22a627 --- /dev/null +++ b/usr.sbin/sdpd/ssr.c @@ -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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000000..1b76ebaa7b --- /dev/null +++ b/usr.sbin/sdpd/sur.c @@ -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 + * 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 +#include +#include +#include +#include +#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 index 0000000000..ca0daf7634 --- /dev/null +++ b/usr.sbin/sdpd/uuid-private.h @@ -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 + * 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 index 0000000000..4c80f2eda7 --- /dev/null +++ b/usr.sbin/sdpd/uuid.c @@ -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 + * 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 +#include +#include +#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 index 0000000000..2045475225 --- /dev/null +++ b/usr.sbin/sdpquery/Makefile @@ -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 diff --git a/usr.sbin/sdpquery/sdpquery.1 b/usr.sbin/sdpquery/sdpquery.1 new file mode 100644 index 0000000000..5a634118d0 --- /dev/null +++ b/usr.sbin/sdpquery/sdpquery.1 @@ -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 +.\" 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 index 0000000000..5bb7d77c4c --- /dev/null +++ b/usr.sbin/sdpquery/sdpquery.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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, "" }, + { 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 [parameters..]\n" + " %s [-c path] -l [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 index 0000000000..4b34455e59 --- /dev/null +++ b/usr.sbin/sdpquery/sdpquery.h @@ -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 index 0000000000..767bb15dcb --- /dev/null +++ b/usr.sbin/sdpquery/search.c @@ -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 + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 */ -- 2.41.0