aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/bluetooth/sdpd
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bluetooth/sdpd')
-rw-r--r--usr.sbin/bluetooth/sdpd/Makefile14
-rw-r--r--usr.sbin/bluetooth/sdpd/Makefile.depend18
-rw-r--r--usr.sbin/bluetooth/sdpd/audio_sink.c186
-rw-r--r--usr.sbin/bluetooth/sdpd/audio_source.c186
-rw-r--r--usr.sbin/bluetooth/sdpd/bgd.c103
-rw-r--r--usr.sbin/bluetooth/sdpd/dun.c138
-rw-r--r--usr.sbin/bluetooth/sdpd/ftrn.c119
-rw-r--r--usr.sbin/bluetooth/sdpd/gn.c174
-rw-r--r--usr.sbin/bluetooth/sdpd/irmc.c135
-rw-r--r--usr.sbin/bluetooth/sdpd/irmc_command.c119
-rw-r--r--usr.sbin/bluetooth/sdpd/lan.c174
-rw-r--r--usr.sbin/bluetooth/sdpd/log.c128
-rw-r--r--usr.sbin/bluetooth/sdpd/log.h48
-rw-r--r--usr.sbin/bluetooth/sdpd/main.c237
-rw-r--r--usr.sbin/bluetooth/sdpd/nap.c211
-rw-r--r--usr.sbin/bluetooth/sdpd/opush.c135
-rw-r--r--usr.sbin/bluetooth/sdpd/panu.c174
-rw-r--r--usr.sbin/bluetooth/sdpd/profile.c504
-rw-r--r--usr.sbin/bluetooth/sdpd/profile.h97
-rw-r--r--usr.sbin/bluetooth/sdpd/provider.c198
-rw-r--r--usr.sbin/bluetooth/sdpd/provider.h76
-rw-r--r--usr.sbin/bluetooth/sdpd/sar.c320
-rw-r--r--usr.sbin/bluetooth/sdpd/scr.c94
-rw-r--r--usr.sbin/bluetooth/sdpd/sd.c230
-rw-r--r--usr.sbin/bluetooth/sdpd/sdpd.8139
-rw-r--r--usr.sbin/bluetooth/sdpd/server.c589
-rw-r--r--usr.sbin/bluetooth/sdpd/server.h103
-rw-r--r--usr.sbin/bluetooth/sdpd/sp.c119
-rw-r--r--usr.sbin/bluetooth/sdpd/srr.c142
-rw-r--r--usr.sbin/bluetooth/sdpd/ssar.c380
-rw-r--r--usr.sbin/bluetooth/sdpd/ssr.c285
-rw-r--r--usr.sbin/bluetooth/sdpd/sur.c85
-rw-r--r--usr.sbin/bluetooth/sdpd/uuid-private.h40
-rw-r--r--usr.sbin/bluetooth/sdpd/uuid.c57
34 files changed, 5757 insertions, 0 deletions
diff --git a/usr.sbin/bluetooth/sdpd/Makefile b/usr.sbin/bluetooth/sdpd/Makefile
new file mode 100644
index 000000000000..aabb16d4c3ca
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/Makefile
@@ -0,0 +1,14 @@
+# $Id: Makefile,v 1.1 2004/01/20 21:27:55 max Exp $
+
+PACKAGE= bluetooth
+PROG= sdpd
+MAN= sdpd.8
+SRCS= audio_sink.c audio_source.c \
+ bgd.c dun.c ftrn.c gn.c irmc.c irmc_command.c lan.c log.c \
+ main.c nap.c opush.c panu.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}
+WARNS?= 2
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bluetooth/sdpd/Makefile.depend b/usr.sbin/bluetooth/sdpd/Makefile.depend
new file mode 100644
index 000000000000..de7bb33fd2e5
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/Makefile.depend
@@ -0,0 +1,18 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libbluetooth \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libsdp \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bluetooth/sdpd/audio_sink.c b/usr.sbin/bluetooth/sdpd/audio_sink.c
new file mode 100644
index 000000000000..3b631376d02a
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/audio_sink.c
@@ -0,0 +1,186 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Hans Petter Selasky <hselasky@freebsd.org>
+ * 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.
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+audio_sink_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static const uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_AUDIO_SINK,
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *)service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+audio_sink_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_audio_sink_profile_p audio_sink = (sdp_audio_sink_profile_p) provider->data;
+
+ if (buf + 18 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(16, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(6, buf);
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(audio_sink->psm, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(6, buf);
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_AVDTP, buf);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(audio_sink->protover, buf);
+
+ return (18);
+}
+
+static int32_t
+audio_sink_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);
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf);
+
+ return (5);
+}
+
+static int32_t
+audio_sink_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static const uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *)profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+audio_sink_profile_create_service_name(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static const char service_name[] = "Audio SNK";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *)service_name, strlen(service_name)));
+}
+
+static int32_t
+audio_sink_create_supported_features(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_audio_sink_profile_p audio_sink = (sdp_audio_sink_profile_p) provider->data;
+
+ if (buf + 3 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(audio_sink->features, buf);
+
+ return (3);
+}
+
+static int32_t
+audio_sink_profile_valid(uint8_t const *data, uint32_t datalen)
+{
+
+ if (datalen < sizeof(struct sdp_audio_sink_profile))
+ return (0);
+ return (1);
+}
+
+static const attr_t audio_sink_profile_attrs[] = {
+ {SDP_ATTR_SERVICE_RECORD_HANDLE,
+ common_profile_create_service_record_handle},
+ {SDP_ATTR_SERVICE_CLASS_ID_LIST,
+ audio_sink_profile_create_service_class_id_list},
+ {SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ audio_sink_profile_create_protocol_descriptor_list},
+ {SDP_ATTR_BROWSE_GROUP_LIST,
+ audio_sink_profile_create_browse_group_list},
+ {SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+ common_profile_create_language_base_attribute_id_list},
+ {SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+ audio_sink_profile_create_bluetooth_profile_descriptor_list},
+ {SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+ audio_sink_profile_create_service_name},
+ {SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
+ common_profile_create_service_provider_name},
+ {SDP_ATTR_SUPPORTED_FEATURES,
+ audio_sink_create_supported_features},
+ {} /* end entry */
+};
+
+profile_t audio_sink_profile_descriptor = {
+ SDP_SERVICE_CLASS_AUDIO_SINK,
+ sizeof(sdp_audio_sink_profile_t),
+ audio_sink_profile_valid,
+ (attr_t const *const)&audio_sink_profile_attrs
+};
diff --git a/usr.sbin/bluetooth/sdpd/audio_source.c b/usr.sbin/bluetooth/sdpd/audio_source.c
new file mode 100644
index 000000000000..be827527732d
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/audio_source.c
@@ -0,0 +1,186 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Hans Petter Selasky <hselasky@freebsd.org>
+ * 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.
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+audio_source_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static const uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_AUDIO_SOURCE,
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *)service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+audio_source_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_audio_source_profile_p audio_source = (sdp_audio_source_profile_p) provider->data;
+
+ if (buf + 18 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(16, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(6, buf);
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(audio_source->psm, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(6, buf);
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_AVDTP, buf);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(audio_source->protover, buf);
+
+ return (18);
+}
+
+static int32_t
+audio_source_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);
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf);
+
+ return (5);
+}
+
+static int32_t
+audio_source_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static const uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *)profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+audio_source_profile_create_service_name(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static const char service_name[] = "Audio SRC";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *)service_name, strlen(service_name)));
+}
+
+static int32_t
+audio_source_create_supported_features(
+ uint8_t *buf, uint8_t const *const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_audio_source_profile_p audio_source = (sdp_audio_source_profile_p) provider->data;
+
+ if (buf + 3 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(audio_source->features, buf);
+
+ return (3);
+}
+
+static int32_t
+audio_source_profile_valid(uint8_t const *data, uint32_t datalen)
+{
+
+ if (datalen < sizeof(struct sdp_audio_source_profile))
+ return (0);
+ return (1);
+}
+
+static const attr_t audio_source_profile_attrs[] = {
+ {SDP_ATTR_SERVICE_RECORD_HANDLE,
+ common_profile_create_service_record_handle},
+ {SDP_ATTR_SERVICE_CLASS_ID_LIST,
+ audio_source_profile_create_service_class_id_list},
+ {SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ audio_source_profile_create_protocol_descriptor_list},
+ {SDP_ATTR_BROWSE_GROUP_LIST,
+ audio_source_profile_create_browse_group_list},
+ {SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+ common_profile_create_language_base_attribute_id_list},
+ {SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+ audio_source_profile_create_bluetooth_profile_descriptor_list},
+ {SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+ audio_source_profile_create_service_name},
+ {SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
+ common_profile_create_service_provider_name},
+ {SDP_ATTR_SUPPORTED_FEATURES,
+ audio_source_create_supported_features},
+ {} /* end entry */
+};
+
+profile_t audio_source_profile_descriptor = {
+ SDP_SERVICE_CLASS_AUDIO_SOURCE,
+ sizeof(sdp_audio_source_profile_t),
+ audio_source_profile_valid,
+ (attr_t const *const)&audio_source_profile_attrs
+};
diff --git a/usr.sbin/bluetooth/sdpd/bgd.c b/usr.sbin/bluetooth/sdpd/bgd.c
new file mode 100644
index 000000000000..628389efc8e1
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/bgd.c
@@ -0,0 +1,103 @@
+/*-
+ * bgd.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: bgd.c,v 1.4 2004/01/13 01:54:39 max Exp $
+ */
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+
+static int32_t
+bgd_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+bgd_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "Public Browse Group Root";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+bgd_profile_create_group_id(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ if (buf + 3 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf);
+
+ return (3);
+}
+
+static attr_t bgd_profile_attrs[] = {
+ { SDP_ATTR_SERVICE_RECORD_HANDLE,
+ common_profile_create_service_record_handle },
+ { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+ bgd_profile_create_service_class_id_list },
+ { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+ common_profile_create_language_base_attribute_id_list },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+ bgd_profile_create_service_name },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
+ bgd_profile_create_service_name },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
+ common_profile_create_service_provider_name },
+ { SDP_ATTR_GROUP_ID,
+ bgd_profile_create_group_id },
+ { 0, NULL } /* end entry */
+};
+
+profile_t bgd_profile_descriptor = {
+ SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR,
+ 0,
+ (profile_data_valid_p) NULL,
+ (attr_t const * const) &bgd_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/dun.c b/usr.sbin/bluetooth/sdpd/dun.c
new file mode 100644
index 000000000000..3f4159926275
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/dun.c
@@ -0,0 +1,138 @@
+/*-
+ * dun.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: dun.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+dun_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_DIALUP_NETWORKING
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+dun_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_DIALUP_NETWORKING,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+dun_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "DialUp networking";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+dun_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) 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_p provider = (provider_p) 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 */
+};
+
+profile_t dun_profile_descriptor = {
+ SDP_SERVICE_CLASS_DIALUP_NETWORKING,
+ sizeof(sdp_dun_profile_t),
+ common_profile_server_channel_valid,
+ (attr_t const * const) &dun_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/ftrn.c b/usr.sbin/bluetooth/sdpd/ftrn.c
new file mode 100644
index 000000000000..32b4912f25ed
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/ftrn.c
@@ -0,0 +1,119 @@
+/*-
+ * ftrn.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: ftrn.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+ftrn_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+ftrn_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+ftrn_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "OBEX File Transfer";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+ftrn_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) 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 */
+};
+
+profile_t ftrn_profile_descriptor = {
+ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
+ sizeof(sdp_ftrn_profile_t),
+ common_profile_server_channel_valid,
+ (attr_t const * const) &ftrn_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/gn.c b/usr.sbin/bluetooth/sdpd/gn.c
new file mode 100644
index 000000000000..17879c4fb193
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/gn.c
@@ -0,0 +1,174 @@
+/*
+ * gn.c
+ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2008 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: gn.c,v 1.1 2008/03/11 00:02:42 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+gn_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_GN
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+gn_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_GN,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+gn_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "Group Ad-hoc Network";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+gn_profile_create_service_description(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_descr[] =
+ "Personal Group Ad-hoc Network Service";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_descr,
+ strlen(service_descr)));
+}
+
+static int32_t
+gn_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_gn_profile_p gn = (sdp_gn_profile_p) provider->data;
+
+ return (bnep_profile_create_protocol_descriptor_list(
+ buf, eob, (uint8_t const *) &gn->psm,
+ sizeof(gn->psm)));
+}
+
+static int32_t
+gn_profile_create_security_description(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_gn_profile_p gn = (sdp_gn_profile_p) provider->data;
+
+ return (bnep_profile_create_security_description(buf, eob,
+ (uint8_t const *) &gn->security_description,
+ sizeof(gn->security_description)));
+}
+
+static int32_t
+gn_profile_create_service_availability(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_gn_profile_p gn = (sdp_gn_profile_p) provider->data;
+
+ return (common_profile_create_service_availability(buf, eob,
+ &gn->load_factor, 1));
+}
+
+static int32_t
+gn_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+ sdp_gn_profile_p gn = (sdp_gn_profile_p) data;
+
+ return ((gn->psm == 0)? 0 : 1);
+}
+
+static attr_t gn_profile_attrs[] = {
+ { SDP_ATTR_SERVICE_RECORD_HANDLE,
+ common_profile_create_service_record_handle },
+ { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+ gn_profile_create_service_class_id_list },
+ { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ gn_profile_create_protocol_descriptor_list },
+ { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+ common_profile_create_language_base_attribute_id_list },
+ { SDP_ATTR_SERVICE_AVAILABILITY,
+ gn_profile_create_service_availability },
+ { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+ gn_profile_create_bluetooth_profile_descriptor_list },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+ gn_profile_create_service_name },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
+ gn_profile_create_service_description },
+ { SDP_ATTR_SECURITY_DESCRIPTION,
+ gn_profile_create_security_description },
+ { 0, NULL } /* end entry */
+};
+
+profile_t gn_profile_descriptor = {
+ SDP_SERVICE_CLASS_GN,
+ sizeof(sdp_gn_profile_t),
+ gn_profile_data_valid,
+ (attr_t const * const) &gn_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/irmc.c b/usr.sbin/bluetooth/sdpd/irmc.c
new file mode 100644
index 000000000000..90155e065492
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/irmc.c
@@ -0,0 +1,135 @@
+/*-
+ * irmc.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: irmc.c,v 1.6 2004/01/13 19:31:54 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+irmc_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+irmc_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+irmc_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "IrMC Synchronization";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+irmc_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) 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_p provider = (provider_p) 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 */
+};
+
+profile_t irmc_profile_descriptor = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC,
+ sizeof(sdp_irmc_profile_t),
+ obex_profile_data_valid,
+ (attr_t const * const) &irmc_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/irmc_command.c b/usr.sbin/bluetooth/sdpd/irmc_command.c
new file mode 100644
index 000000000000..e8d0723fa8a4
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/irmc_command.c
@@ -0,0 +1,119 @@
+/*-
+ * irmc_command_command_command.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: irmc_command.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+irmc_command_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+irmc_command_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+irmc_command_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "Sync Command Service";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+irmc_command_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) 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 */
+};
+
+profile_t irmc_command_profile_descriptor = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,
+ sizeof(sdp_irmc_command_profile_t),
+ common_profile_server_channel_valid,
+ (attr_t const * const) &irmc_command_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/lan.c b/usr.sbin/bluetooth/sdpd/lan.c
new file mode 100644
index 000000000000..66a71754ef48
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/lan.c
@@ -0,0 +1,174 @@
+/*-
+ * lan.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: lan.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <arpa/inet.h>
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+lan_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+lan_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+lan_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "LAN Access using PPP";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+lan_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) 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_p provider = (provider_p) data;
+ sdp_lan_profile_p lan = (sdp_lan_profile_p) provider->data;
+
+ return (common_profile_create_service_availability(buf, eob,
+ &lan->load_factor, 1));
+}
+
+static int32_t
+lan_profile_create_ip_subnet(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) 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_p lan = (sdp_lan_profile_p) 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 */
+};
+
+profile_t lan_profile_descriptor = {
+ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
+ sizeof(sdp_lan_profile_t),
+ lan_profile_data_valid,
+ (attr_t const * const) &lan_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/log.c b/usr.sbin/bluetooth/sdpd/log.c
new file mode 100644
index 000000000000..f7d4fa350c65
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/log.c
@@ -0,0 +1,128 @@
+/*-
+ * log.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: log.c,v 1.1 2004/01/07 23:15:00 max Exp $
+ */
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <syslog.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/bluetooth/sdpd/log.h b/usr.sbin/bluetooth/sdpd/log.h
new file mode 100644
index 000000000000..e00ed4d8c838
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/log.h
@@ -0,0 +1,48 @@
+/*-
+ * log.h
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: log.h,v 1.1 2004/01/07 23:15:00 max 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/bluetooth/sdpd/main.c b/usr.sbin/bluetooth/sdpd/main.c
new file mode 100644
index 000000000000..cc21b314f486
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/main.c
@@ -0,0 +1,237 @@
+/*-
+ * main.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: main.c,v 1.8 2004/01/13 19:31:54 max Exp $
+ */
+
+#include <sys/select.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "log.h"
+#include "server.h"
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/queue.h>
+#include "profile.h"
+#include "provider.h"
+
+#define SDPD "sdpd"
+
+static int32_t drop_root (char const *user, char const *group);
+static void sighandler (int32_t s);
+static void usage (void);
+
+static int32_t done;
+
+/*
+ * Bluetooth Service Discovery Procotol (SDP) daemon
+ */
+
+int
+main(int argc, char *argv[])
+{
+ server_t server;
+ char const *control = SDP_LOCAL_PATH;
+ char const *user = "nobody", *group = "nobody";
+ int32_t detach = 1, opt;
+ struct sigaction sa;
+
+ while ((opt = getopt(argc, argv, "c:dg:hu:")) != -1) {
+ switch (opt) {
+ case 'c': /* control */
+ control = optarg;
+ break;
+
+ case 'd': /* do not detach */
+ detach = 0;
+ 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) < 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 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/bluetooth/sdpd/nap.c b/usr.sbin/bluetooth/sdpd/nap.c
new file mode 100644
index 000000000000..229600b9c950
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/nap.c
@@ -0,0 +1,211 @@
+/*
+ * nap.c
+ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2008 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: nap.c,v 1.1 2008/03/11 00:02:42 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+nap_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_NAP
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+nap_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_NAP,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+nap_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "Network Access Point";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+nap_profile_create_service_description(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_descr[] = "Personal Ad-hoc Network Service";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_descr,
+ strlen(service_descr)));
+}
+
+static int32_t
+nap_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_nap_profile_p nap = (sdp_nap_profile_p) provider->data;
+
+ return (bnep_profile_create_protocol_descriptor_list(
+ buf, eob, (uint8_t const *) &nap->psm,
+ sizeof(nap->psm)));
+}
+
+static int32_t
+nap_profile_create_security_description(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_nap_profile_p nap = (sdp_nap_profile_p) provider->data;
+
+ return (bnep_profile_create_security_description(buf, eob,
+ (uint8_t const *) &nap->security_description,
+ sizeof(nap->security_description)));
+}
+
+static int32_t
+nap_profile_create_net_access_type(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_nap_profile_p nap = (sdp_nap_profile_p) provider->data;
+
+ if (buf + 3 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(nap->net_access_type, buf);
+
+ return (3);
+}
+
+static int32_t
+nap_profile_create_max_net_access_rate(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_nap_profile_p nap = (sdp_nap_profile_p) provider->data;
+
+ if (buf + 3 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(nap->max_net_access_rate, buf);
+
+ return (3);
+}
+
+static int32_t
+nap_profile_create_service_availability(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_nap_profile_p nap = (sdp_nap_profile_p) provider->data;
+
+ return (common_profile_create_service_availability(buf, eob,
+ &nap->load_factor, 1));
+}
+
+static int32_t
+nap_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+ sdp_nap_profile_p nap = (sdp_nap_profile_p) data;
+
+ return ((nap->psm == 0)? 0 : 1);
+}
+
+static attr_t nap_profile_attrs[] = {
+ { SDP_ATTR_SERVICE_RECORD_HANDLE,
+ common_profile_create_service_record_handle },
+ { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+ nap_profile_create_service_class_id_list },
+ { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ nap_profile_create_protocol_descriptor_list },
+ { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+ common_profile_create_language_base_attribute_id_list },
+ { SDP_ATTR_SERVICE_AVAILABILITY,
+ nap_profile_create_service_availability },
+ { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+ nap_profile_create_bluetooth_profile_descriptor_list },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+ nap_profile_create_service_name },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
+ nap_profile_create_service_description },
+ { SDP_ATTR_SECURITY_DESCRIPTION,
+ nap_profile_create_security_description },
+ { SDP_ATTR_NET_ACCESS_TYPE,
+ nap_profile_create_net_access_type },
+ { SDP_ATTR_MAX_NET_ACCESS_RATE,
+ nap_profile_create_max_net_access_rate },
+ { 0, NULL } /* end entry */
+};
+
+profile_t nap_profile_descriptor = {
+ SDP_SERVICE_CLASS_NAP,
+ sizeof(sdp_nap_profile_t),
+ nap_profile_data_valid,
+ (attr_t const * const) &nap_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/opush.c b/usr.sbin/bluetooth/sdpd/opush.c
new file mode 100644
index 000000000000..6f2464191292
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/opush.c
@@ -0,0 +1,135 @@
+/*-
+ * opush.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: opush.c,v 1.6 2004/01/13 19:31:54 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+opush_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+opush_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+opush_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "OBEX Object Push";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+opush_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) 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_p provider = (provider_p) 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 */
+};
+
+profile_t opush_profile_descriptor = {
+ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
+ sizeof(sdp_opush_profile_t),
+ obex_profile_data_valid,
+ (attr_t const * const) &opush_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/panu.c b/usr.sbin/bluetooth/sdpd/panu.c
new file mode 100644
index 000000000000..bba1dbd45d1d
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/panu.c
@@ -0,0 +1,174 @@
+/*
+ * panu.c
+ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2008 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: panu.c,v 1.1 2008/03/11 00:02:42 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+panu_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_PANU
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+panu_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_PANU,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+panu_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "Personal Ad-hoc User Service";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+panu_profile_create_service_description(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_descr[] =
+ "Personal Ad-hoc User Service";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_descr,
+ strlen(service_descr)));
+}
+
+static int32_t
+panu_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_panu_profile_p panu = (sdp_panu_profile_p) provider->data;
+
+ return (bnep_profile_create_protocol_descriptor_list(
+ buf, eob, (uint8_t const *) &panu->psm,
+ sizeof(panu->psm)));
+}
+
+static int32_t
+panu_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+ sdp_panu_profile_p panu = (sdp_panu_profile_p) data;
+
+ return ((panu->psm == 0)? 0 : 1);
+}
+
+static int32_t
+panu_profile_create_service_availability(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_panu_profile_p panu = (sdp_panu_profile_p) provider->data;
+
+ return (common_profile_create_service_availability( buf, eob,
+ &panu->load_factor, 1));
+}
+
+static int32_t
+panu_profile_create_security_description(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) data;
+ sdp_panu_profile_p panu = (sdp_panu_profile_p) provider->data;
+
+ return (bnep_profile_create_security_description(buf, eob,
+ (uint8_t const *) &panu->security_description,
+ sizeof(panu->security_description)));
+}
+
+static attr_t panu_profile_attrs[] = {
+ { SDP_ATTR_SERVICE_RECORD_HANDLE,
+ common_profile_create_service_record_handle },
+ { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+ panu_profile_create_service_class_id_list },
+ { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ panu_profile_create_protocol_descriptor_list },
+ { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+ common_profile_create_language_base_attribute_id_list },
+ { SDP_ATTR_SERVICE_AVAILABILITY,
+ panu_profile_create_service_availability },
+ { SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+ panu_profile_create_bluetooth_profile_descriptor_list },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+ panu_profile_create_service_name },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
+ panu_profile_create_service_description },
+ { SDP_ATTR_SECURITY_DESCRIPTION,
+ panu_profile_create_security_description },
+ { 0, NULL } /* end entry */
+};
+
+profile_t panu_profile_descriptor = {
+ SDP_SERVICE_CLASS_PANU,
+ sizeof(sdp_panu_profile_t),
+ panu_profile_data_valid,
+ (attr_t const * const) &panu_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/profile.c b/usr.sbin/bluetooth/sdpd/profile.c
new file mode 100644
index 000000000000..e6d81f8ef4b1
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/profile.c
@@ -0,0 +1,504 @@
+/*
+ * profile.c
+ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+/*
+ * Lookup profile descriptor
+ */
+
+profile_p
+profile_get_descriptor(uint16_t uuid)
+{
+ extern profile_t audio_sink_profile_descriptor;
+ extern profile_t audio_source_profile_descriptor;
+ extern profile_t dun_profile_descriptor;
+ extern profile_t ftrn_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;
+ extern profile_t nap_profile_descriptor;
+ extern profile_t gn_profile_descriptor;
+ extern profile_t panu_profile_descriptor;
+
+ static const profile_p profiles[] = {
+ &audio_sink_profile_descriptor,
+ &audio_source_profile_descriptor,
+ &dun_profile_descriptor,
+ &ftrn_profile_descriptor,
+ &irmc_profile_descriptor,
+ &irmc_command_profile_descriptor,
+ &lan_profile_descriptor,
+ &opush_profile_descriptor,
+ &sp_profile_descriptor,
+ &nap_profile_descriptor,
+ &gn_profile_descriptor,
+ &panu_profile_descriptor
+ };
+
+ int32_t i;
+
+ for (i = 0; i < nitems(profiles); i++)
+ if (profiles[i]->uuid == 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_p ad = (attr_p) 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_p) 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);
+}
+
+/*
+ * Common provider name is "FreeBSD"
+ */
+
+int32_t
+common_profile_create_service_provider_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ char provider_name[] = "FreeBSD";
+
+ return (common_profile_create_string8(buf, eob,
+ (uint8_t const *) provider_name,
+ strlen(provider_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);
+}
+
+/*
+ * Service Availability
+ */
+
+int32_t
+common_profile_create_service_availability(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ if (datalen != 1 || buf + 2 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UINT8, buf);
+ SDP_PUT8(data[0], buf);
+
+ return (2);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * do not check anything
+ */
+
+int32_t
+common_profile_always_valid(uint8_t const *data, uint32_t datalen)
+{
+ return (1);
+}
+
+/*
+ * 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_p opush = (sdp_opush_profile_p) 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);
+}
+
+/*
+ * BNEP protocol descriptor
+ */
+
+int32_t
+bnep_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ /* supported protocol types */
+ uint16_t ptype[] = {
+ 0x0800, /* IPv4 */
+ 0x0806, /* ARP */
+#ifdef INET6
+ 0x86dd, /* IPv6 */
+#endif
+ };
+
+ uint16_t i, psm, version = 0x0100,
+ nptypes = nitems(ptype),
+ nptypes_size = nptypes * 3;
+
+ if (datalen != 2 || 18 + nptypes_size > 255 ||
+ buf + 20 + nptypes_size > eob)
+ return (-1);
+
+ memcpy(&psm, data, sizeof(psm));
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(18 + nptypes_size, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(6, buf);
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(psm, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(8 + nptypes_size, buf);
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_BNEP, buf);
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(version, buf);
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(nptypes_size, buf);
+ for (i = 0; i < nptypes; i ++) {
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(ptype[i], buf);
+ }
+
+ return (20 + nptypes_size);
+}
+
+/*
+ * BNEP security description
+ */
+
+int32_t
+bnep_profile_create_security_description(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ uint16_t security_descr;
+
+ if (datalen != 2 || buf + 3 > eob)
+ return (-1);
+
+ memcpy(&security_descr, data, sizeof(security_descr));
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(security_descr, buf);
+
+ return (3);
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/profile.h b/usr.sbin/bluetooth/sdpd/profile.h
new file mode 100644
index 000000000000..7184c0fd742e
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/profile.h
@@ -0,0 +1,97 @@
+/*
+ * profile.h
+ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: profile.h,v 1.6 2004/01/13 19:31:54 max 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 */
+ 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 common_profile_create_service_availability;
+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_attr_create_t bnep_profile_create_protocol_descriptor_list;
+profile_attr_create_t bnep_profile_create_security_description;
+
+profile_data_valid_t common_profile_always_valid;
+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/bluetooth/sdpd/provider.c b/usr.sbin/bluetooth/sdpd/provider.c
new file mode 100644
index 000000000000..7ac800a85006
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/provider.c
@@ -0,0 +1,198 @@
+/*-
+ * provider.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: provider.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <string.h>
+#include <stdlib.h>
+#include "profile.h"
+#include "provider.h"
+
+static TAILQ_HEAD(, provider) providers = TAILQ_HEAD_INITIALIZER(providers);
+static uint32_t change_state = 0;
+static uint32_t 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_p 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 (++ handle <= 1)
+ handle = 2;
+
+ provider->handle = 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);
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/provider.h b/usr.sbin/bluetooth/sdpd/provider.h
new file mode 100644
index 000000000000..b4f3bb0a46d0
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/provider.h
@@ -0,0 +1,76 @@
+/*-
+ * provider.h
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: provider.h,v 1.6 2004/01/13 01:54:39 max 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) \
+ (memcmp(b, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0 || \
+ memcmp(&(p)->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0 || \
+ memcmp(&(p)->bdaddr, b, sizeof(bdaddr_t)) == 0)
+
+int32_t provider_register_sd (int32_t fd);
+provider_p provider_register (profile_p const profile,
+ bdaddr_p 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);
+
+#endif /* ndef _PROVIDER_H_ */
diff --git a/usr.sbin/bluetooth/sdpd/sar.c b/usr.sbin/bluetooth/sdpd/sar.c
new file mode 100644
index 000000000000..68193b567fd3
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sar.c
@@ -0,0 +1,320 @@
+/*-
+ * sar.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sar.c,v 1.2 2004/01/08 23:46:51 max Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <stdio.h> /* for NULL */
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare SDP attr/value pair. Check if profile implements the attribute
+ * and if so call the attribute value function.
+ *
+ * uint16 value16 - 3 bytes (attribute)
+ * value - N bytes (value)
+ */
+
+static int32_t
+server_prepare_attr_value_pair(
+ provider_p const provider, uint16_t attr,
+ uint8_t *buf, uint8_t const * const eob)
+{
+ profile_attr_create_p cf = profile_get_attr(provider->profile, attr);
+ int32_t len;
+
+ if (cf == NULL)
+ return (0); /* no attribute */
+
+ if (buf + 3 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(attr, buf);
+
+ len = cf(buf, eob, (uint8_t const *) provider, sizeof(*provider));
+ if (len < 0)
+ return (-1);
+
+ return (3 + len);
+}
+
+/*
+ * seq16 value16 - 3 bytes
+ * attr value - 3+ bytes
+ * [ attr value ]
+ */
+
+int32_t
+server_prepare_attr_list(provider_p const provider,
+ uint8_t const *req, uint8_t const * const req_end,
+ uint8_t *rsp, uint8_t const * const rsp_end)
+{
+ uint8_t *ptr = rsp + 3;
+ int32_t type, hi, lo, len;
+
+ if (ptr > rsp_end)
+ return (-1);
+
+ while (req < req_end) {
+ SDP_GET8(type, req);
+
+ switch (type) {
+ case SDP_DATA_UINT16:
+ if (req + 2 > req_end)
+ return (-1);
+
+ SDP_GET16(lo, req);
+ hi = lo;
+ break;
+
+ case SDP_DATA_UINT32:
+ if (req + 4 > req_end)
+ return (-1);
+
+ SDP_GET16(lo, req);
+ SDP_GET16(hi, req);
+ break;
+
+ default:
+ return (-1);
+ /* NOT REACHED */
+ }
+
+ for (; lo <= hi; lo ++) {
+ len = server_prepare_attr_value_pair(provider, lo, ptr, rsp_end);
+ if (len < 0)
+ return (-1);
+
+ ptr += len;
+ }
+ }
+
+ len = ptr - rsp; /* we put this much bytes in rsp */
+
+ /* Fix SEQ16 header for the rsp */
+ SDP_PUT8(SDP_DATA_SEQ16, rsp);
+ SDP_PUT16(len - 3, rsp);
+
+ return (len);
+}
+
+/*
+ * Prepare SDP Service Attribute Response
+ */
+
+int32_t
+server_prepare_service_attribute_response(server_p srv, int32_t fd)
+{
+ uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
+ uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+ uint8_t *rsp = srv->fdidx[fd].rsp;
+ uint8_t const *rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
+
+ uint8_t *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 *) 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, nitems(iov));
+ } 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/bluetooth/sdpd/scr.c b/usr.sbin/bluetooth/sdpd/scr.c
new file mode 100644
index 000000000000..a5bced947f8e
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/scr.c
@@ -0,0 +1,94 @@
+/*-
+ * scr.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: scr.c,v 1.1 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare Service Change response
+ */
+
+int32_t
+server_prepare_service_change_response(server_p srv, int32_t fd)
+{
+ uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
+ uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+ uint8_t *rsp = srv->fdidx[fd].rsp;
+
+ provider_t *provider = NULL;
+ uint32_t handle;
+
+ /*
+ * Minimal Service Change Request
+ *
+ * value32 - handle 4 bytes
+ */
+
+ if (!srv->fdidx[fd].control ||
+ !srv->fdidx[fd].priv || req_end - req < 4)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ /* Get handle */
+ SDP_GET32(handle, req);
+
+ /* Lookup provider */
+ provider = provider_by_handle(handle);
+ if (provider == NULL || provider->fd != fd)
+ return (SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE);
+
+ /* Validate user data */
+ if (req_end - req < provider->profile->dsize ||
+ provider->profile->valid == NULL ||
+ (provider->profile->valid)(req, req_end - req) == 0)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ /* Update provider */
+ if (provider_update(provider, req, req_end - req) < 0)
+ return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
+
+ SDP_PUT16(0, rsp);
+
+ /* Set reply size */
+ srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
+ srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
+ srv->fdidx[fd].rsp_cs = 0;
+
+ return (0);
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/sd.c b/usr.sbin/bluetooth/sdpd/sd.c
new file mode 100644
index 000000000000..cd4f7fa3364b
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sd.c
@@ -0,0 +1,230 @@
+/*-
+ * sd.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sd.c,v 1.4 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+sd_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+sd_profile_create_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_SERVICE_DISCOVERY_SERVER,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+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 + 12 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(10, 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(3, buf);
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_SDP, buf);
+
+ return (12);
+}
+
+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_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+ sd_profile_create_bluetooth_profile_descriptor_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 */
+};
+
+profile_t sd_profile_descriptor = {
+ SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER,
+ 0,
+ (profile_data_valid_p) NULL,
+ (attr_t const * const) &sd_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/sdpd.8 b/usr.sbin/bluetooth/sdpd/sdpd.8
new file mode 100644
index 000000000000..b5915f729e46
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sdpd.8
@@ -0,0 +1,139 @@
+.\" Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: sdpd.8,v 1.1 2004/01/13 19:31:54 max 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 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 sdpcontrol 8
+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
+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 nobody .
+.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 nobody .
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /var/run/sdp" -compact
+.It Pa /var/run/sdp
+.El
+.Sh SEE ALSO
+.Xr sdp 3 ,
+.Xr sdpcontrol 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq Mt m_evmenkin@yahoo.com
+.Sh CAVEATS
+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 peer's credentials and will only accept the request if
+the application has the same effective user ID as the
+.Dq Li root
+user ID.
+.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 BUGS
+Most likely.
+Please report if found.
diff --git a/usr.sbin/bluetooth/sdpd/server.c b/usr.sbin/bluetooth/sdpd/server.c
new file mode 100644
index 000000000000..05a4cb5f0236
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/server.c
@@ -0,0 +1,589 @@
+/*-
+ * server.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: server.c,v 1.6 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <sys/ucred.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "log.h"
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+static void server_accept_client (server_p srv, int32_t fd);
+static int32_t server_process_request (server_p srv, int32_t fd);
+static int32_t server_send_error_response (server_p srv, int32_t fd,
+ uint16_t error);
+static void server_close_fd (server_p srv, int32_t fd);
+
+/*
+ * Initialize server
+ */
+
+int32_t
+server_init(server_p srv, char const *control)
+{
+ struct sockaddr_un un;
+ struct sockaddr_l2cap l2;
+ int32_t unsock, l2sock;
+ socklen_t size;
+ uint16_t imtu;
+
+ assert(srv != NULL);
+ assert(control != NULL);
+
+ memset(srv, 0, sizeof(*srv));
+
+ /* 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);
+ }
+
+ 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, BLUETOOTH_PROTO_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, SOL_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.l2cap_len = sizeof(l2);
+ l2.l2cap_family = AF_BLUETOOTH;
+ memcpy(&l2.l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2.l2cap_bdaddr));
+ l2.l2cap_psm = htole16(NG_L2CAP_PSM_SDP);
+
+ 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;
+ int32_t cfd, priv;
+ uint16_t omtu;
+ socklen_t size;
+
+ 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);
+
+ priv = 0;
+
+ 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,SOL_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 bits wide, which gives us up to 2048 chunks.
+ */
+
+ if (omtu < NG_L2CAP_MTU_MINIMUM) {
+ log_err("L2CAP OMTU is too small (%d bytes)", omtu);
+ close(cfd);
+ return;
+ }
+ } else {
+ uid_t uid;
+ gid_t gid;
+ struct passwd *pw;
+
+ /* Get peer's credentials */
+ if (getpeereid(cfd, &uid, &gid) < 0) {
+ log_err("Could not get peer's credentials. %s (%d)",
+ strerror(errno), errno);
+ close(cfd);
+ return;
+ }
+
+ /* Check credentials */
+ pw = getpwuid(uid);
+ if (pw != NULL)
+ priv = (strcmp(pw->pw_name, "root") == 0);
+ else
+ log_warning("Could not verify credentials for uid %d",
+ uid);
+
+ memcpy(&srv->req_sa.l2cap_bdaddr, NG_HCI_BDADDR_ANY,
+ sizeof(srv->req_sa.l2cap_bdaddr));
+
+ 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(NG_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 = priv;
+ 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)
+{
+ sdp_pdu_p pdu = (sdp_pdu_p) srv->req;
+ int32_t len, error;
+
+ 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 >= NG_L2CAP_MTU_MINIMUM);
+
+ do {
+ len = read(fd, srv->req, srv->imtu);
+ } 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 (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);
+ }
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/server.h b/usr.sbin/bluetooth/sdpd/server.h
new file mode 100644
index 000000000000..9a1cb86eb3da
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/server.h
@@ -0,0 +1,103 @@
+/*-
+ * server.h
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: server.h,v 1.5 2004/01/13 01:54:39 max 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
+{
+ uint32_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_l2cap req_sa; /* local address */
+};
+
+typedef struct server server_t;
+typedef struct server * server_p;
+
+/*
+ * External API
+ */
+
+int32_t server_init(server_p srv, const char *control);
+void server_shutdown(server_p srv);
+int32_t server_do(server_p srv);
+
+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/bluetooth/sdpd/sp.c b/usr.sbin/bluetooth/sdpd/sp.c
new file mode 100644
index 000000000000..3c79dd93965d
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sp.c
@@ -0,0 +1,119 @@
+/*-
+ * sp.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sp.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+sp_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_SERIAL_PORT
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+sp_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_SERIAL_PORT,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+sp_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "Serial Port";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+sp_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_p provider = (provider_p) 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 */
+};
+
+profile_t sp_profile_descriptor = {
+ SDP_SERVICE_CLASS_SERIAL_PORT,
+ sizeof(sdp_sp_profile_t),
+ common_profile_server_channel_valid,
+ (attr_t const * const) &sp_profile_attrs
+};
+
diff --git a/usr.sbin/bluetooth/sdpd/srr.c b/usr.sbin/bluetooth/sdpd/srr.c
new file mode 100644
index 000000000000..b16eb25c9ea4
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/srr.c
@@ -0,0 +1,142 @@
+/*-
+ * srr.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: srr.c,v 1.1 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare Service Register response
+ */
+
+int32_t
+server_prepare_service_register_response(server_p srv, int32_t fd)
+{
+ uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
+ uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+ uint8_t *rsp = srv->fdidx[fd].rsp;
+
+ profile_t *profile = NULL;
+ provider_t *provider = NULL;
+ bdaddr_t *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_p) 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, nitems(iov));
+ } 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/bluetooth/sdpd/ssar.c b/usr.sbin/bluetooth/sdpd/ssar.c
new file mode 100644
index 000000000000..fad498c2b34a
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/ssar.c
@@ -0,0 +1,380 @@
+/*-
+ * ssar.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+#include "uuid-private.h"
+
+/* from sar.c */
+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);
+
+/*
+ * Scan an attribute for matching UUID.
+ */
+static int
+server_search_uuid_sub(uint8_t *buf, uint8_t const * const eob, const uint128_t *uuid)
+{
+ int128_t duuid;
+ uint32_t value;
+ uint8_t type;
+
+ while (buf < eob) {
+
+ SDP_GET8(type, buf);
+
+ switch (type) {
+ case SDP_DATA_UUID16:
+ if (buf + 2 > eob)
+ continue;
+ SDP_GET16(value, buf);
+
+ memcpy(&duuid, &uuid_base, sizeof(duuid));
+ duuid.b[2] = value >> 8 & 0xff;
+ duuid.b[3] = value & 0xff;
+
+ if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
+ return (0);
+ break;
+ case SDP_DATA_UUID32:
+ if (buf + 4 > eob)
+ continue;
+ SDP_GET32(value, buf);
+ memcpy(&duuid, &uuid_base, sizeof(duuid));
+ duuid.b[0] = value >> 24 & 0xff;
+ duuid.b[1] = value >> 16 & 0xff;
+ duuid.b[2] = value >> 8 & 0xff;
+ duuid.b[3] = value & 0xff;
+
+ if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
+ return (0);
+ break;
+ case SDP_DATA_UUID128:
+ if (buf + 16 > eob)
+ continue;
+ SDP_GET_UUID128(&duuid, buf);
+
+ if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
+ return (0);
+ break;
+ case SDP_DATA_UINT8:
+ case SDP_DATA_INT8:
+ case SDP_DATA_SEQ8:
+ buf++;
+ break;
+ case SDP_DATA_UINT16:
+ case SDP_DATA_INT16:
+ case SDP_DATA_SEQ16:
+ buf += 2;
+ break;
+ case SDP_DATA_UINT32:
+ case SDP_DATA_INT32:
+ case SDP_DATA_SEQ32:
+ buf += 4;
+ break;
+ case SDP_DATA_UINT64:
+ case SDP_DATA_INT64:
+ buf += 8;
+ break;
+ case SDP_DATA_UINT128:
+ case SDP_DATA_INT128:
+ buf += 16;
+ break;
+ case SDP_DATA_STR8:
+ if (buf + 1 > eob)
+ continue;
+ SDP_GET8(value, buf);
+ buf += value;
+ break;
+ case SDP_DATA_STR16:
+ if (buf + 2 > eob)
+ continue;
+ SDP_GET16(value, buf);
+ if (value > (eob - buf))
+ return (1);
+ buf += value;
+ break;
+ case SDP_DATA_STR32:
+ if (buf + 4 > eob)
+ continue;
+ SDP_GET32(value, buf);
+ if (value > (eob - buf))
+ return (1);
+ buf += value;
+ break;
+ case SDP_DATA_BOOL:
+ buf += 1;
+ break;
+ default:
+ return (1);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Search a provider for matching UUID in its attributes.
+ */
+static int
+server_search_uuid(provider_p const provider, const uint128_t *uuid)
+{
+ uint8_t buffer[256];
+ const attr_t *attr;
+ int len;
+
+ for (attr = provider->profile->attrs; attr->create != NULL; attr++) {
+
+ len = attr->create(buffer, buffer + sizeof(buffer),
+ (const uint8_t *)provider->profile, sizeof(*provider->profile));
+ if (len < 0)
+ continue;
+ if (server_search_uuid_sub(buffer, buffer + len, uuid) == 0)
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * 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 + NG_L2CAP_MTU_MAXIMUM;
+
+ uint8_t const *sspptr = NULL, *aidptr = NULL;
+ uint8_t *ptr = NULL;
+
+ provider_t *provider = NULL;
+ int32_t type, rsp_limit, ssplen, aidlen, cslen, cs;
+ uint128_t uuid, puuid;
+
+ /*
+ * 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
+ */
+
+ if (req_end - req < 13)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ /* Get size of ServiceSearchPattern */
+ ssplen = 0;
+ SDP_GET8(type, req);
+ switch (type) {
+ case SDP_DATA_SEQ8:
+ SDP_GET8(ssplen, req);
+ break;
+
+ case SDP_DATA_SEQ16:
+ SDP_GET16(ssplen, req);
+ break;
+
+ case SDP_DATA_SEQ32:
+ SDP_GET32(ssplen, req);
+ break;
+ }
+ if (ssplen <= 0)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ sspptr = req;
+ req += ssplen;
+
+ /* 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 != 0) {
+ if (cslen != 2 || req_end - req != 2)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ SDP_GET16(cs, req);
+ } 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);
+
+ /*
+ * Service Search Attribute Response format
+ *
+ * value16 - 2 bytes AttributeListByteCount (not incl.)
+ * seq8 len16 - 3 bytes
+ * attr list - 3+ bytes AttributeLists
+ * [ attr list ]
+ */
+
+ ptr = rsp + 3;
+
+ while (ssplen > 0) {
+ SDP_GET8(type, sspptr);
+ ssplen --;
+
+ switch (type) {
+ case SDP_DATA_UUID16:
+ if (ssplen < 2)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ memcpy(&uuid, &uuid_base, sizeof(uuid));
+ uuid.b[2] = *sspptr ++;
+ uuid.b[3] = *sspptr ++;
+ ssplen -= 2;
+ break;
+
+ case SDP_DATA_UUID32:
+ if (ssplen < 4)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ memcpy(&uuid, &uuid_base, sizeof(uuid));
+ uuid.b[0] = *sspptr ++;
+ uuid.b[1] = *sspptr ++;
+ uuid.b[2] = *sspptr ++;
+ uuid.b[3] = *sspptr ++;
+ ssplen -= 4;
+ break;
+
+ case SDP_DATA_UUID128:
+ if (ssplen < 16)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ memcpy(uuid.b, sspptr, 16);
+ sspptr += 16;
+ ssplen -= 16;
+ break;
+
+ default:
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+ /* NOT REACHED */
+ }
+
+ for (provider = provider_get_first();
+ provider != NULL;
+ provider = provider_get_next(provider)) {
+ if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
+ continue;
+
+ memcpy(&puuid, &uuid_base, sizeof(puuid));
+ puuid.b[2] = provider->profile->uuid >> 8;
+ puuid.b[3] = provider->profile->uuid;
+
+ if (memcmp(&uuid, &puuid, sizeof(uuid)) != 0 &&
+ memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) != 0 &&
+ server_search_uuid(provider, &uuid) != 0)
+ continue;
+
+ cs = server_prepare_attr_list(provider,
+ aidptr, aidptr + aidlen, ptr, rsp_end);
+ if (cs < 0)
+ return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
+
+ ptr += 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 = ptr - rsp;
+ srv->fdidx[fd].rsp_cs = 0;
+
+ /* Fix AttributeLists sequence header */
+ ptr = rsp;
+ SDP_PUT8(SDP_DATA_SEQ16, ptr);
+ SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
+
+ return (0);
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/ssr.c b/usr.sbin/bluetooth/sdpd/ssr.c
new file mode 100644
index 000000000000..1a29dde97ee5
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/ssr.c
@@ -0,0 +1,285 @@
+/*-
+ * ssr.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: ssr.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+#include "uuid-private.h"
+
+/*
+ * 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 + NG_L2CAP_MTU_MAXIMUM;
+
+ uint8_t *ptr = NULL;
+ provider_t *provider = NULL;
+ int32_t type, ssplen, rsp_limit, rcount, cslen, cs;
+ uint128_t uuid, puuid;
+
+ /*
+ * Minimal SDP Service Search Request
+ *
+ * seq8 len8 - 2 bytes
+ * uuid16 value16 - 3 bytes ServiceSearchPattern
+ * value16 - 2 bytes MaximumServiceRecordCount
+ * value8 - 1 byte ContinuationState
+ */
+
+ if (req_end - req < 8)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ /* Get size of ServiceSearchPattern */
+ ssplen = 0;
+ SDP_GET8(type, req);
+ switch (type) {
+ case SDP_DATA_SEQ8:
+ SDP_GET8(ssplen, req);
+ break;
+
+ case SDP_DATA_SEQ16:
+ SDP_GET16(ssplen, req);
+ break;
+
+ case SDP_DATA_SEQ32:
+ SDP_GET32(ssplen, req);
+ break;
+ }
+ if (ssplen <= 0)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ ptr = (uint8_t *) req + ssplen;
+
+ /* Get MaximumServiceRecordCount */
+ if (ptr + 2 > req_end)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ SDP_GET16(rsp_limit, ptr);
+ if (rsp_limit <= 0)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ /* 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);
+
+ /*
+ * Service Search Response format
+ *
+ * value16 - 2 bytes TotalServiceRecordCount (not incl.)
+ * value16 - 2 bytes CurrentServiceRecordCount (not incl.)
+ * value32 - 4 bytes handle
+ * [ value32 ]
+ *
+ * Calculate how many record handles we can fit
+ * in our reply buffer and adjust rlimit.
+ */
+
+ ptr = rsp;
+ rcount = (rsp_end - ptr) / 4;
+ if (rcount < rsp_limit)
+ rsp_limit = rcount;
+
+ /* Look for the record handles */
+ for (rcount = 0; ssplen > 0 && rcount < rsp_limit; ) {
+ SDP_GET8(type, req);
+ ssplen --;
+
+ switch (type) {
+ case SDP_DATA_UUID16:
+ if (ssplen < 2)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ 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 (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ 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 (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ memcpy(uuid.b, req, 16);
+ req += 16;
+ ssplen -= 16;
+ break;
+
+ default:
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+ /* NOT REACHED */
+ }
+
+ for (provider = provider_get_first();
+ provider != NULL && rcount < rsp_limit;
+ provider = provider_get_next(provider)) {
+ if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
+ continue;
+
+ memcpy(&puuid, &uuid_base, sizeof(puuid));
+ puuid.b[2] = provider->profile->uuid >> 8;
+ puuid.b[3] = provider->profile->uuid;
+
+ if (memcmp(&uuid, &puuid, sizeof(uuid)) == 0 ||
+ memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) == 0) {
+ SDP_PUT32(provider->handle, ptr);
+ rcount ++;
+ }
+ }
+ }
+
+ /* 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 = ptr - 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, nitems(iov));
+ } 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/bluetooth/sdpd/sur.c b/usr.sbin/bluetooth/sdpd/sur.c
new file mode 100644
index 000000000000..43581be0bbf1
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sur.c
@@ -0,0 +1,85 @@
+/*-
+ * sur.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sur.c,v 1.1 2004/01/13 01:54:39 max Exp $
+ */
+
+#include <sys/queue.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare Service Unregister response
+ */
+
+int32_t
+server_prepare_service_unregister_response(server_p srv, int32_t fd)
+{
+ uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
+ uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+ uint8_t *rsp = srv->fdidx[fd].rsp;
+
+ provider_t *provider = NULL;
+ uint32_t handle;
+
+ /*
+ * Minimal Service Unregister Request
+ *
+ * value32 - uuid 4 bytes
+ */
+
+ if (!srv->fdidx[fd].control ||
+ !srv->fdidx[fd].priv || req_end - req < 4)
+ return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
+
+ /* Get handle */
+ SDP_GET32(handle, req);
+
+ /* Lookup provider */
+ provider = provider_by_handle(handle);
+ if (provider == NULL || provider->fd != fd)
+ return (SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE);
+
+ provider_unregister(provider);
+ SDP_PUT16(0, rsp);
+
+ /* Set reply size */
+ srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
+ srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
+ srv->fdidx[fd].rsp_cs = 0;
+
+ return (0);
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/uuid-private.h b/usr.sbin/bluetooth/sdpd/uuid-private.h
new file mode 100644
index 000000000000..8a3f9bb1c62b
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/uuid-private.h
@@ -0,0 +1,40 @@
+/*-
+ * uuid-private.h
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: uuid-private.h,v 1.1 2004/12/09 18:20:26 max 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/bluetooth/sdpd/uuid.c b/usr.sbin/bluetooth/sdpd/uuid.c
new file mode 100644
index 000000000000..90a6d5b17322
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/uuid.c
@@ -0,0 +1,57 @@
+/*-
+ * uuid.c
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: uuid.c,v 1.1 2004/12/09 18:20:26 max Exp $
+ */
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+#include <sdp.h>
+#include <uuid.h>
+#include "uuid-private.h"
+
+uint128_t uuid_base = {
+ .b = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x10, 0x00,
+ 0x80, 0x00,
+ 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+ }
+};
+
+uint128_t uuid_public_browse_group = {
+ .b = {
+ 0x00, 0x00, 0x10, 0x02,
+ 0x00, 0x00,
+ 0x10, 0x00,
+ 0x80, 0x00,
+ 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+ }
+};
+