summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libsdp/Makefile5
-rw-r--r--lib/libsdp/sdp.390
-rw-r--r--lib/libsdp/sdp.h44
-rw-r--r--lib/libsdp/search.c10
-rw-r--r--lib/libsdp/service.c237
-rw-r--r--usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c1
-rw-r--r--usr.sbin/bluetooth/sdpd/bgd.c102
-rw-r--r--usr.sbin/bluetooth/sdpd/dun.c136
-rw-r--r--usr.sbin/bluetooth/sdpd/ftrn.c117
-rw-r--r--usr.sbin/bluetooth/sdpd/irmc.c133
-rw-r--r--usr.sbin/bluetooth/sdpd/irmc_command.c117
-rw-r--r--usr.sbin/bluetooth/sdpd/lan.c177
-rw-r--r--usr.sbin/bluetooth/sdpd/log.c127
-rw-r--r--usr.sbin/bluetooth/sdpd/log.h47
-rw-r--r--usr.sbin/bluetooth/sdpd/main.c235
-rw-r--r--usr.sbin/bluetooth/sdpd/opush.c133
-rw-r--r--usr.sbin/bluetooth/sdpd/profile.c382
-rw-r--r--usr.sbin/bluetooth/sdpd/profile.h90
-rw-r--r--usr.sbin/bluetooth/sdpd/provider.c196
-rw-r--r--usr.sbin/bluetooth/sdpd/provider.h75
-rw-r--r--usr.sbin/bluetooth/sdpd/sar.c315
-rw-r--r--usr.sbin/bluetooth/sdpd/scr.c91
-rw-r--r--usr.sbin/bluetooth/sdpd/sd.c212
-rw-r--r--usr.sbin/bluetooth/sdpd/sdpd.8136
-rw-r--r--usr.sbin/bluetooth/sdpd/server.c547
-rw-r--r--usr.sbin/bluetooth/sdpd/server.h101
-rw-r--r--usr.sbin/bluetooth/sdpd/sp.c117
-rw-r--r--usr.sbin/bluetooth/sdpd/srr.c138
-rw-r--r--usr.sbin/bluetooth/sdpd/ssar.c225
-rw-r--r--usr.sbin/bluetooth/sdpd/ssr.c252
-rw-r--r--usr.sbin/bluetooth/sdpd/sur.c82
31 files changed, 4663 insertions, 7 deletions
diff --git a/lib/libsdp/Makefile b/lib/libsdp/Makefile
index 4df7471..f93c690 100644
--- a/lib/libsdp/Makefile
+++ b/lib/libsdp/Makefile
@@ -9,7 +9,7 @@ CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../../sys
SHLIB_MAJOR= 1
-SRCS= search.c session.c util.c
+SRCS= search.c service.c session.c util.c
INCS= sdp.h
MLINKS+= sdp.3 SDP_GET8.3
@@ -29,5 +29,8 @@ MLINKS+= sdp.3 sdp_error.3
MLINKS+= sdp.3 sdp_search.3
MLINKS+= sdp.3 sdp_attr2desc.3
MLINKS+= sdp.3 sdp_uuid2desc.3
+MLINKS+= sdp.3 sdp_register_service.3
+MLINKS+= sdp.3 sdp_unregister_service.3
+MLINKS+= sdp.3 sdp_change_service.3
.include <bsd.lib.mk>
diff --git a/lib/libsdp/sdp.3 b/lib/libsdp/sdp.3
index e849780..e19854b 100644
--- a/lib/libsdp/sdp.3
+++ b/lib/libsdp/sdp.3
@@ -84,6 +84,12 @@
.Fn sdp_attr2desc "uint16_t attr"
.Ft char const * const
.Fn sdp_uuid2desc "uint16_t uuid"
+.Ft int32_t
+.Fn sdp_register_service "void *xss" "uint16_t uuid" "bdaddr_p const bdaddr" "uint8_t const *data" "uint32_t datalen" "uint32_t *handle"
+.Ft int32_t
+.Fn sdp_unregister_service "void *xss" "uint32_t handle"
+.Ft int32_t
+.Fn sdp_change_service "void *xss" "uint32_t handle" "uint8_t const *data" "uint32_t datalen"
.Sh DESCRIPTION
The
.Fn SDP_GET8 ,
@@ -256,6 +262,76 @@ and
.Fn sdp_uuid2desc
functions each take a numeric attribute ID/UUID value and convert it to a
human readable description.
+.Pp
+The
+.Fn sdp_register_service
+is used to register service with the local SDP server.
+The
+.Vt xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Vt uuid
+parameter is a SDP Service Class ID for the service to be registered.
+The
+.Vt bdaddr
+parameter should point to a valid BD_ADDR.
+The service will be only advertised if request was received by the local device
+with
+.Vt bdaddr .
+If
+.Vt bdaddr
+is set to
+.Dv NG_HCI_BDADDR_ANY
+then the service will be advertised to any remote devices that queries for it.
+The
+.Vt data
+and
+.Vt datalen
+parameters specify data and size of the data for the service.
+Upon successful return
+.Fn sdp_register_service
+will populate
+.Vt handle
+with the SDP record handle.
+This parameter is optional and can be set to
+.Dv NULL .
+.Pp
+The
+.Fn sdp_unregister_service
+is used to unregister service with the local SDP server.
+The
+.Vt xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Vt handle
+parameter should contain a valid SDP record handle of the service to be
+unregistered.
+.Pp
+The
+.Fn sdp_change_service
+function is used to change data associated with the existing service on
+the local SDP server.
+The
+.Vt xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Vt handle
+parameter should contain a valid SDP record handle of the service to be changed.
+The
+.Vt data
+and
+.Vt datalen
+parameters specify data and size of the data for the service.
+.Sh CAVEAT
+When registering services with the local SDP server the application must
+keep the SDP session open.
+If SDP session is closed then the local SDP server will remove all services
+that were registered over the session.
+The application is allowed to change or unregister service if it was registered
+over the same session.
.Sh EXAMPLES
The following example shows how to get
.Dv SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST
@@ -300,16 +376,22 @@ If the new SDP object was created then caller is still expected to call
to check if there was connection error.
.Pp
The
-.Fn sdp_search
-function returns non-zero value on error.
+.Fn sdp_search ,
+.Fn sdp_register_service ,
+.Fn sdp_unregister_service
+and
+.Fn sdp_change_service
+functions return non-zero value on error.
The caller is expected to call
.Fn sdp_error
to find out more about error.
.Sh SEE ALSO
.Xr bluetooth 3 ,
-.Xr strerror 3
+.Xr strerror 3 ,
+.Xr sdpcontrol 8 ,
+.Xr sdpd 8
.Sh BUGS
-This is client only library for now.
+Most likely.
Please report bugs if found.
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/lib/libsdp/sdp.h b/lib/libsdp/sdp.h
index 4f5fb27..42743f9 100644
--- a/lib/libsdp/sdp.h
+++ b/lib/libsdp/sdp.h
@@ -490,6 +490,41 @@ void sdp_print (uint32_t level, uint8_t const *start,
#define SDP_LOCAL_PATH "/var/run/sdp"
#define SDP_LOCAL_MTU 4096
+/*
+ * These are NOT defined in spec and only accepted on control sockets.
+ * The response to these request always will be SDP_PDU_ERROR_RESPONSE.
+ * The first 2 bytes (after PDU header) is an error code (in network
+ * byte order). The rest of the data (pdu->len - 2) is a response data
+ * and depend on the request.
+ *
+ * SDP_PDU_SERVICE_REGISTER_REQUEST
+ * pdu_header_t hdr;
+ * u_int16_t uuid; service class UUID (network byte order)
+ * bdaddr_t bdaddr; local BD_ADDR (or ANY)
+ * profile data[pdu->len - sizeof(uuid) - sizeof(bdaddr)]
+ *
+ * in successful reponse additional data will contain 4 bytes record handle
+ *
+ *
+ * SDP_PDU_SERVICE_UNREGISTER_REQUEST
+ * pdu_header_t hdr;
+ * u_int32_t record_handle; (network byte order)
+ *
+ * no additional data in response.
+ *
+ *
+ * SDP_PDU_SERVICE_CHANGE_REQUEST
+ * pdu_header_t hdr;
+ * u_int32_t record_handle; (network byte order)
+ * profile data[pdu->len - sizeof(record_handle)]
+ *
+ * no additional data in response.
+ */
+
+#define SDP_PDU_SERVICE_REGISTER_REQUEST 0x81
+#define SDP_PDU_SERVICE_UNREGISTER_REQUEST 0x82
+#define SDP_PDU_SERVICE_CHANGE_REQUEST 0x83
+
struct sdp_dun_profile
{
uint8_t server_channel;
@@ -507,6 +542,7 @@ struct sdp_ftrn_profile
typedef struct sdp_ftrn_profile sdp_ftrn_profile_t;
typedef struct sdp_ftrn_profile * sdp_ftrn_profile_p;
+/* Keep this in sync with sdp_opush_profile */
struct sdp_irmc_profile
{
uint8_t server_channel;
@@ -535,6 +571,7 @@ struct sdp_lan_profile
typedef struct sdp_lan_profile sdp_lan_profile_t;
typedef struct sdp_lan_profile * sdp_lan_profile_p;
+/* Keep this in sync with sdp_irmc_profile */
struct sdp_opush_profile
{
uint8_t server_channel;
@@ -552,6 +589,13 @@ struct sdp_sp_profile
typedef struct sdp_sp_profile sdp_sp_profile_t;
typedef struct sdp_sp_profile * sdp_sp_profile_p;
+int32_t sdp_register_service (void *xss, uint16_t uuid,
+ bdaddr_p const bdaddr, uint8_t const *data,
+ uint32_t datalen, uint32_t *handle);
+int32_t sdp_unregister_service (void *xss, uint32_t handle);
+int32_t sdp_change_service (void *xss, uint32_t handle,
+ uint8_t const *data, uint32_t datalen);
+
__END_DECLS
#endif /* ndef _SDP_H_ */
diff --git a/lib/libsdp/search.c b/lib/libsdp/search.c
index 98e3e18..42f162d 100644
--- a/lib/libsdp/search.c
+++ b/lib/libsdp/search.c
@@ -133,7 +133,10 @@ sdp_search(void *xss,
iov[1].iov_base = (void *) ss->req;
iov[1].iov_len = req_cs - ss->req;
- len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
if (len < 0) {
ss->error = errno;
return (-1);
@@ -145,7 +148,10 @@ sdp_search(void *xss,
iov[1].iov_base = (void *) rsp;
iov[1].iov_len = ss->imtu;
- len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ do {
+ len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
if (len < 0) {
ss->error = errno;
return (-1);
diff --git a/lib/libsdp/service.c b/lib/libsdp/service.c
new file mode 100644
index 0000000..2667966
--- /dev/null
+++ b/lib/libsdp/service.c
@@ -0,0 +1,237 @@
+/*
+ * service.c
+ *
+ * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: service.c,v 1.1 2004/01/13 19:32:36 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+static int32_t sdp_receive_error_pdu(sdp_session_p ss);
+
+int32_t
+sdp_register_service(void *xss, uint16_t uuid, bdaddr_p const bdaddr,
+ uint8_t const *data, uint32_t datalen, uint32_t *handle)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+ struct iovec iov[4];
+ sdp_pdu_t pdu;
+ int32_t len;
+
+ if (ss == NULL)
+ return (-1);
+ if (bdaddr == NULL || data == NULL ||
+ datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+ if (sizeof(pdu)+sizeof(uuid)+sizeof(*bdaddr)+datalen > SDP_LOCAL_MTU) {
+ ss->error = EMSGSIZE;
+ return (-1);
+ }
+
+ pdu.pid = SDP_PDU_SERVICE_REGISTER_REQUEST;
+ pdu.tid = htons(++ss->tid);
+ pdu.len = htons(sizeof(uuid) + sizeof(*bdaddr) + datalen);
+
+ uuid = htons(uuid);
+
+ iov[0].iov_base = (void *) &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = (void *) &uuid;
+ iov[1].iov_len = sizeof(uuid);
+
+ iov[2].iov_base = (void *) bdaddr;
+ iov[2].iov_len = sizeof(*bdaddr);
+
+ iov[3].iov_base = (void *) data;
+ iov[3].iov_len = datalen;
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ len = sdp_receive_error_pdu(ss);
+ if (len < 0)
+ return (-1);
+ if (len != sizeof(pdu) + sizeof(uint16_t) + sizeof(uint32_t)) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ if (handle != NULL) {
+ *handle = (uint32_t) ss->rsp[--len];
+ *handle |= (uint32_t) ss->rsp[--len] << 8;
+ *handle |= (uint32_t) ss->rsp[--len] << 16;
+ *handle |= (uint32_t) ss->rsp[--len] << 24;
+ }
+
+ return (0);
+}
+
+int32_t
+sdp_unregister_service(void *xss, uint32_t handle)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+ struct iovec iov[2];
+ sdp_pdu_t pdu;
+ int32_t len;
+
+ if (ss == NULL)
+ return (-1);
+ if (!(ss->flags & SDP_SESSION_LOCAL)) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+ if (sizeof(pdu) + sizeof(handle) > SDP_LOCAL_MTU) {
+ ss->error = EMSGSIZE;
+ return (-1);
+ }
+
+ pdu.pid = SDP_PDU_SERVICE_UNREGISTER_REQUEST;
+ pdu.tid = htons(++ss->tid);
+ pdu.len = htons(sizeof(handle));
+
+ handle = htonl(handle);
+
+ iov[0].iov_base = (void *) &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = (void *) &handle;
+ iov[1].iov_len = sizeof(handle);
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
+}
+
+int32_t
+sdp_change_service(void *xss, uint32_t handle,
+ uint8_t const *data, uint32_t datalen)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+ struct iovec iov[3];
+ sdp_pdu_t pdu;
+ int32_t len;
+
+ if (ss == NULL)
+ return (-1);
+ if (data == NULL || datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+ if (sizeof(pdu) + sizeof(handle) + datalen > SDP_LOCAL_MTU) {
+ ss->error = EMSGSIZE;
+ return (-1);
+ }
+
+ pdu.pid = SDP_PDU_SERVICE_CHANGE_REQUEST;
+ pdu.tid = htons(++ss->tid);
+ pdu.len = htons(sizeof(handle) + datalen);
+
+ handle = htons(handle);
+
+ iov[0].iov_base = (void *) &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = (void *) &handle;
+ iov[1].iov_len = sizeof(handle);
+
+ iov[2].iov_base = (void *) data;
+ iov[2].iov_len = datalen;
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
+}
+
+static int32_t
+sdp_receive_error_pdu(sdp_session_p ss)
+{
+ sdp_pdu_p pdu;
+ int32_t len;
+ uint16_t error;
+
+ do {
+ len = read(ss->s, ss->rsp, ss->rsp_e - ss->rsp);
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ pdu = (sdp_pdu_p) ss->rsp;
+ pdu->tid = ntohs(pdu->tid);
+ pdu->len = ntohs(pdu->len);
+
+ if (pdu->pid != SDP_PDU_ERROR_RESPONSE || pdu->tid != ss->tid ||
+ pdu->len < 2 || pdu->len != len - sizeof(*pdu)) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ error = (uint16_t) ss->rsp[sizeof(pdu)] << 8;
+ error |= (uint16_t) ss->rsp[sizeof(pdu) + 1];
+
+ if (error != 0) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ return (len);
+}
+
diff --git a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c
index d774386..6cb4863 100644
--- a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c
+++ b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c
@@ -57,6 +57,7 @@ main(int argc, char *argv[])
bdaddr_t bdaddr;
memset(&bdaddr, 0, sizeof(bdaddr));
+ local = 0;
/* Process command line arguments */
while ((n = getopt(argc, argv, "a:c:lh")) != -1) {
diff --git a/usr.sbin/bluetooth/sdpd/bgd.c b/usr.sbin/bluetooth/sdpd/bgd.c
new file mode 100644
index 0000000..70dda89
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/bgd.c
@@ -0,0 +1,102 @@
+/*
+ * bgd.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: bgd.c,v 1.4 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#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 0000000..e7aeb78
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/dun.c
@@ -0,0 +1,136 @@
+/*
+ * dun.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: dun.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+dun_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_DIALUP_NETWORKING
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+dun_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_DIALUP_NETWORKING,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+dun_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "DialUp networking";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+dun_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_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 0000000..bcebfc7
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/ftrn.c
@@ -0,0 +1,117 @@
+/*
+ * ftrn.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: ftrn.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+ftrn_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+ftrn_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+ftrn_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "OBEX File Transfer";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+ftrn_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_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/irmc.c b/usr.sbin/bluetooth/sdpd/irmc.c
new file mode 100644
index 0000000..d28a120
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/irmc.c
@@ -0,0 +1,133 @@
+/*
+ * irmc.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: irmc.c,v 1.6 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+irmc_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+irmc_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+irmc_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "IrMC Synchronization";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+irmc_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_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 0000000..10dafe0
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/irmc_command.c
@@ -0,0 +1,117 @@
+/*
+ * irmc_command_command_command.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: irmc_command.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+irmc_command_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+irmc_command_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+irmc_command_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "Sync Command Service";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+irmc_command_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_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 0000000..a5612ed
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/lan.c
@@ -0,0 +1,177 @@
+/*
+ * lan.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: lan.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <arpa/inet.h>
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+lan_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+lan_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+lan_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "LAN Access using PPP";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+lan_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_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;
+
+ if (buf + 2 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UINT8, buf);
+ SDP_PUT8(lan->load_factor, buf);
+
+ return (2);
+}
+
+static int32_t
+lan_profile_create_ip_subnet(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_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 0000000..b03f7e1
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/log.c
@@ -0,0 +1,127 @@
+/*
+ * log.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: log.c,v 1.1 2004/01/07 23:15:00 max Exp $
+ * $FreeBSD$
+ */
+
+#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 0000000..8c9ce77
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/log.h
@@ -0,0 +1,47 @@
+/*
+ * log.h
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: log.h,v 1.1 2004/01/07 23:15:00 max Exp $
+ * $FreeBSD$
+ */
+
+#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 0000000..1df3bf0
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/main.c
@@ -0,0 +1,235 @@
+/*
+ * main.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: main.c,v 1.8 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/select.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <sdp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "log.h"
+#include "server.h"
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/queue.h>
+#include "profile.h"
+#include "provider.h"
+
+#define SDPD "sdpd"
+
+static int32_t drop_root (char const *user, char const *group);
+static void sighandler (int32_t s);
+static void usage (void);
+
+static int32_t done;
+
+/*
+ * Bluetooth Service Discovery Procotol (SDP) daemon
+ */
+
+int
+main(int argc, char *argv[])
+{
+ server_t server;
+ char const *control = SDP_LOCAL_PATH;
+ char const *user = "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/opush.c b/usr.sbin/bluetooth/sdpd/opush.c
new file mode 100644
index 0000000..36359da
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/opush.c
@@ -0,0 +1,133 @@
+/*
+ * opush.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: opush.c,v 1.6 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+opush_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+opush_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+opush_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "OBEX Object Push";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+opush_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_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/profile.c b/usr.sbin/bluetooth/sdpd/profile.c
new file mode 100644
index 0000000..d49929f
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/profile.c
@@ -0,0 +1,382 @@
+/*
+ * profile.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+/*
+ * Lookup profile descriptor
+ */
+
+profile_p
+profile_get_descriptor(uint16_t uuid)
+{
+ extern profile_t dun_profile_descriptor;
+ extern profile_t ftrn_profile_descriptor;
+ extern profile_t irmc_profile_descriptor;
+ extern profile_t irmc_command_profile_descriptor;
+ extern profile_t lan_profile_descriptor;
+ extern profile_t opush_profile_descriptor;
+ extern profile_t sp_profile_descriptor;
+
+ static const profile_p profiles[] = {
+ &dun_profile_descriptor,
+ &ftrn_profile_descriptor,
+ &irmc_profile_descriptor,
+ &irmc_command_profile_descriptor,
+ &lan_profile_descriptor,
+ &opush_profile_descriptor,
+ &sp_profile_descriptor
+ };
+
+ int32_t i;
+
+ for (i = 0; i < sizeof(profiles)/sizeof(profiles[0]); i++)
+ if (profiles[i]->uuid == 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);
+ }
+
+ 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);
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(*((uint16_t const *)data)++, buf);
+ }
+
+ 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);
+}
+
+/*
+ * seq8 len8 - 2 bytes
+ * seq8 len8 - 2 bytes
+ * uuid16 value16 - 3 bytes
+ * seq8 len8 - 2 bytes
+ * uuid16 value16 - 3 bytes
+ * uint8 value8 - 2 bytes
+ */
+
+int32_t
+rfcomm_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ if (datalen != 1 || buf + 14 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(12, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(3, buf);
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(5, buf);
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
+ SDP_PUT8(SDP_DATA_UINT8, buf);
+ SDP_PUT8(*data, buf);
+
+ return (14);
+}
+
+/*
+ * seq8 len8 - 2 bytes
+ * seq8 len8 - 2 bytes
+ * uuid16 value16 - 3 bytes
+ * seq8 len8 - 2 bytes
+ * uuid16 value16 - 3 bytes
+ * uint8 value8 - 2 bytes
+ * seq8 len8 - 2 bytes
+ * uuid16 value16 - 3 bytes
+ */
+
+int32_t
+obex_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ if (datalen != 1 || buf + 19 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(17, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(3, buf);
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(5, buf);
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
+ SDP_PUT8(SDP_DATA_UINT8, buf);
+ SDP_PUT8(*data, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(3, buf);
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf);
+
+ return (19);
+}
+
+/*
+ * seq8 len8
+ * uint8 value8 - bytes
+ * [ uint8 value 8 ]
+ */
+
+int32_t
+obex_profile_create_supported_formats_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ int32_t len = 2 * datalen;
+
+ if (len <= 0 || len > 0xff || buf + 2 + len > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(len, buf);
+
+ for (; datalen > 0; datalen --) {
+ SDP_PUT8(SDP_DATA_UINT8, buf);
+ SDP_PUT8(*data++, buf);
+ }
+
+ return (2 + len);
+}
+
+/*
+ * verify server channel number (the first byte in the data)
+ */
+
+int32_t
+common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen)
+{
+ if (data[0] < 1 || data[0] > 30)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * verify server channel number and supported_formats_size
+ * sdp_opush_profile and sdp_irmc_profile
+ */
+
+int32_t
+obex_profile_data_valid(uint8_t const *data, uint32_t datalen)
+{
+ sdp_opush_profile_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);
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/profile.h b/usr.sbin/bluetooth/sdpd/profile.h
new file mode 100644
index 0000000..0ca4221
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/profile.h
@@ -0,0 +1,90 @@
+/*
+ * profile.h
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: profile.h,v 1.6 2004/01/13 19:31:54 max Exp $
+ * $FreeBSD$
+ */
+
+#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 rfcomm_profile_create_protocol_descriptor_list;
+profile_attr_create_t obex_profile_create_protocol_descriptor_list;
+profile_attr_create_t obex_profile_create_supported_formats_list;
+
+profile_data_valid_t common_profile_server_channel_valid;
+profile_data_valid_t obex_profile_data_valid;
+
+#endif /* ndef _PROFILE_H_ */
+
diff --git a/usr.sbin/bluetooth/sdpd/provider.c b/usr.sbin/bluetooth/sdpd/provider.c
new file mode 100644
index 0000000..b0f5347
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/provider.c
@@ -0,0 +1,196 @@
+/*
+ * provider.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: provider.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#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 0000000..b48bc8d
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/provider.h
@@ -0,0 +1,75 @@
+/*
+ * provider.h
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: provider.h,v 1.6 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#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 0000000..5bf8448
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sar.c
@@ -0,0 +1,315 @@
+/*
+ * sar.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sar.c,v 1.2 2004/01/08 23:46:51 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <stdio.h> /* for NULL */
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare SDP attr/value pair. Check if profile implements the attribute
+ * and if so call the attribute value function.
+ *
+ * uint16 value16 - 3 bytes (attribute)
+ * value - N bytes (value)
+ */
+
+static int32_t
+server_prepare_attr_value_pair(
+ provider_p const provider, uint16_t attr,
+ uint8_t *buf, uint8_t const * const eob)
+{
+ profile_attr_create_p cf = profile_get_attr(provider->profile, attr);
+ int32_t len;
+
+ if (cf == NULL)
+ return (0); /* no attribute */
+
+ if (buf + 3 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(attr, buf);
+
+ len = cf(buf, eob, (uint8_t const *) provider, sizeof(*provider));
+ if (len < 0)
+ return (-1);
+
+ return (3 + len);
+}
+
+/*
+ * seq16 value16 - 3 bytes
+ * attr value - 3+ bytes
+ * [ attr value ]
+ */
+
+int32_t
+server_prepare_attr_list(provider_p const provider,
+ uint8_t const *req, uint8_t const * const req_end,
+ uint8_t *rsp, uint8_t const * const rsp_end)
+{
+ uint8_t *ptr = rsp + 3;
+ int32_t type, hi, lo, len;
+
+ if (ptr > rsp_end)
+ return (-1);
+
+ while (req < req_end) {
+ SDP_GET8(type, req);
+
+ switch (type) {
+ case SDP_DATA_UINT16:
+ if (req + 2 > req_end)
+ return (-1);
+
+ SDP_GET16(lo, req);
+ hi = lo;
+ break;
+
+ case SDP_DATA_UINT32:
+ if (req + 4 > req_end)
+ return (-1);
+
+ SDP_GET16(lo, req);
+ SDP_GET16(hi, req);
+ break;
+
+ default:
+ return (-1);
+ /* NOT REACHED */
+ }
+
+ for (; lo <= hi; lo ++) {
+ len = server_prepare_attr_value_pair(provider, lo, ptr, rsp_end);
+ if (len < 0)
+ return (-1);
+
+ ptr += len;
+ }
+ }
+
+ len = ptr - rsp; /* we put this much bytes in rsp */
+
+ /* Fix SEQ16 header for the rsp */
+ SDP_PUT8(SDP_DATA_SEQ16, rsp);
+ SDP_PUT16(len - 3, rsp);
+
+ return (len);
+}
+
+/*
+ * Prepare SDP Service Attribute Response
+ */
+
+int32_t
+server_prepare_service_attribute_response(server_p srv, int32_t fd)
+{
+ uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
+ uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+ uint8_t *rsp = srv->fdidx[fd].rsp;
+ uint8_t const *rsp_end = rsp + 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 = htons(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]);
+
+ iov[0].iov_base = &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = &bcount;
+ iov[1].iov_len = sizeof(bcount);
+
+ iov[2].iov_base = rsp;
+ iov[2].iov_len = rsp_end - rsp;
+
+ iov[3].iov_base = cs;
+ iov[3].iov_len = 1 + cs[0];
+
+ do {
+ size = writev(fd, (struct iovec const *) &iov, sizeof(iov)/sizeof(iov[0]));
+ } while (size < 0 && errno == EINTR);
+
+ /* Check if we have sent (or failed to sent) last response chunk */
+ if (srv->fdidx[fd].rsp_cs == srv->fdidx[fd].rsp_size) {
+ srv->fdidx[fd].rsp_cs = 0;
+ srv->fdidx[fd].rsp_size = 0;
+ srv->fdidx[fd].rsp_limit = 0;
+ }
+
+ return ((size < 0)? errno : 0);
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/scr.c b/usr.sbin/bluetooth/sdpd/scr.c
new file mode 100644
index 0000000..f6f482d
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/scr.c
@@ -0,0 +1,91 @@
+/*
+ * scr.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: scr.c,v 1.1 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare Service Change response
+ */
+
+int32_t
+server_prepare_service_change_response(server_p srv, int32_t fd)
+{
+ uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
+ uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+ uint8_t *rsp = srv->fdidx[fd].rsp;
+
+ provider_t *provider = NULL;
+ uint32_t handle;
+
+ /*
+ * Minimal Service Change Request
+ *
+ * value32 - handle 4 bytes
+ */
+
+ if (!srv->fdidx[fd].control || 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 0000000..52f6c95
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sd.c
@@ -0,0 +1,212 @@
+/*
+ * sd.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sd.c,v 1.4 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+sd_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+sd_profile_create_service_id(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ if (buf + 3 > eob)
+ return (-1);
+
+ /*
+ * The ServiceID is a UUID that universally and uniquely identifies
+ * the service instance described by the service record. This service
+ * attribute is particularly useful if the same service is described
+ * by service records in more than one SDP server
+ */
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_SDP, buf); /* XXX ??? */
+
+ return (3);
+}
+
+static int32_t
+sd_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "Bluetooth service discovery";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+sd_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ if (buf + 13 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(11, buf);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(9, buf);
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(NG_L2CAP_PSM_SDP, buf);
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(1, buf); /* version */
+
+ return (13);
+}
+
+static int32_t
+sd_profile_create_browse_group_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ if (buf + 5 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(3, buf);
+
+ /*
+ * The top-level browse group ID, called PublicBrowseRoot and
+ * representing the root of the browsing hierarchy, has the value
+ * 00001002-0000-1000-8000-00805F9B34FB (UUID16: 0x1002) from the
+ * Bluetooth Assigned Numbers document
+ */
+
+ SDP_PUT8(SDP_DATA_UUID16, buf);
+ SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf);
+
+ return (5);
+}
+
+static int32_t
+sd_profile_create_version_number_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ if (buf + 5 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_SEQ8, buf);
+ SDP_PUT8(3, buf);
+
+ /*
+ * The VersionNumberList is a data element sequence in which each
+ * element of the sequence is a version number supported by the SDP
+ * server. A version number is a 16-bit unsigned integer consisting
+ * of two fields. The higher-order 8 bits contain the major version
+ * number field and the low-order 8 bits contain the minor version
+ * number field. The initial version of SDP has a major version of
+ * 1 and a minor version of 0
+ */
+
+ SDP_PUT8(SDP_DATA_UINT16, buf);
+ SDP_PUT16(0x0100, buf);
+
+ return (5);
+}
+
+static int32_t
+sd_profile_create_service_database_state(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ uint32_t change_state = provider_get_change_state();
+
+ if (buf + 5 > eob)
+ return (-1);
+
+ SDP_PUT8(SDP_DATA_UINT32, buf);
+ SDP_PUT32(change_state, buf);
+
+ return (5);
+}
+
+static attr_t sd_profile_attrs[] = {
+ { SDP_ATTR_SERVICE_RECORD_HANDLE,
+ common_profile_create_service_record_handle },
+ { SDP_ATTR_SERVICE_CLASS_ID_LIST,
+ sd_profile_create_service_class_id_list },
+ { SDP_ATTR_SERVICE_ID,
+ sd_profile_create_service_id },
+ { SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+ common_profile_create_language_base_attribute_id_list },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
+ sd_profile_create_service_name },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
+ sd_profile_create_service_name },
+ { SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
+ common_profile_create_service_provider_name },
+ { SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ sd_profile_create_protocol_descriptor_list },
+ { SDP_ATTR_BROWSE_GROUP_LIST,
+ sd_profile_create_browse_group_list },
+ { SDP_ATTR_VERSION_NUMBER_LIST,
+ sd_profile_create_version_number_list },
+ { SDP_ATTR_SERVICE_DATABASE_STATE,
+ sd_profile_create_service_database_state },
+ { 0, NULL } /* end entry */
+};
+
+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 0000000..38f4c6b
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sdpd.8
@@ -0,0 +1,136 @@
+.\" 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 $
+.\" $FreeBSD$
+.\"
+.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 Sevice
+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 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 nobody .
+.El
+.Sh CAVEAT
+The
+.Nm
+daemon
+will listen for incoming L2CAP connections on a wildcard BD_ADDR.
+.Pp
+In case of multiple Bluetooth devices connected to the same host it is
+possible to specify which services should be
+.Dq bound
+to which Bluetooth device. Such assigment should be done at service
+registration time.
+.Pp
+Access rights on the control socket define which application can register,
+remove or change the service.
+The application must be able to write to and read from the control socket
+in order to perform any query to the Service Database via control socket.
+.Pp
+The
+.Nm
+daemon does not checks for duplicated Service Records.
+It only performs minimal check 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.
+.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 m_evmenkin@yahoo.com
diff --git a/usr.sbin/bluetooth/sdpd/server.c b/usr.sbin/bluetooth/sdpd/server.c
new file mode 100644
index 0000000..14b2041
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/server.c
@@ -0,0 +1,547 @@
+/*
+ * server.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: server.c,v 1.6 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/select.h>
+#include <sys/queue.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.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, 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 (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 = 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].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].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, size;
+ uint16_t omtu;
+
+ do {
+ cfd = accept(fd, NULL, NULL);
+ } while (cfd < 0 && errno == EINTR);
+
+ if (cfd < 0) {
+ log_err("Could not accept connection on %s socket. %s (%d)",
+ srv->fdidx[fd].control? "control" : "L2CAP",
+ strerror(errno), errno);
+ return;
+ }
+
+ assert(!FD_ISSET(cfd, &srv->fdset));
+ assert(!srv->fdidx[cfd].valid);
+
+ if (!srv->fdidx[fd].control) {
+ /* Get local BD_ADDR */
+ size = sizeof(srv->req_sa);
+ if (getsockname(cfd,(struct sockaddr*)&srv->req_sa,&size) < 0) {
+ log_err("Could not get local BD_ADDR. %s (%d)",
+ strerror(errno), errno);
+ close(cfd);
+ return;
+ }
+
+ /* Get outgoing MTU */
+ size = sizeof(omtu);
+ if (getsockopt(cfd,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 bit wide that gives us upto 2048 chunks.
+ */
+
+ if (omtu < NG_L2CAP_MTU_MINIMUM) {
+ log_err("L2CAP OMTU is too small (%d bytes)", omtu);
+ close(cfd);
+ return;
+ }
+ } else {
+ 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].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 (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);
+
+ 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 0000000..6f8f088
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/server.h
@@ -0,0 +1,101 @@
+/*
+ * server.h
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: server.h,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#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 reserved : 2;
+ 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 0000000..31a9585a
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sp.c
@@ -0,0 +1,117 @@
+/*
+ * sp.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sp.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+
+static int32_t
+sp_profile_create_service_class_id_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t service_classes[] = {
+ SDP_SERVICE_CLASS_SERIAL_PORT
+ };
+
+ return (common_profile_create_service_class_id_list(
+ buf, eob,
+ (uint8_t const *) service_classes,
+ sizeof(service_classes)));
+}
+
+static int32_t
+sp_profile_create_bluetooth_profile_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static uint16_t profile_descriptor_list[] = {
+ SDP_SERVICE_CLASS_SERIAL_PORT,
+ 0x0100
+ };
+
+ return (common_profile_create_bluetooth_profile_descriptor_list(
+ buf, eob,
+ (uint8_t const *) profile_descriptor_list,
+ sizeof(profile_descriptor_list)));
+}
+
+static int32_t
+sp_profile_create_service_name(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ static char service_name[] = "Serial Port";
+
+ return (common_profile_create_string8(
+ buf, eob,
+ (uint8_t const *) service_name, strlen(service_name)));
+}
+
+static int32_t
+sp_profile_create_protocol_descriptor_list(
+ uint8_t *buf, uint8_t const * const eob,
+ uint8_t const *data, uint32_t datalen)
+{
+ provider_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 0000000..a1f3ded
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/srr.c
@@ -0,0 +1,138 @@
+/*
+ * srr.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: srr.c,v 1.1 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare Service Register response
+ */
+
+int32_t
+server_prepare_service_register_response(server_p srv, int32_t fd)
+{
+ uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
+ uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+ uint8_t *rsp = srv->fdidx[fd].rsp;
+
+ profile_t *profile = NULL;
+ provider_t *provider = NULL;
+ bdaddr_t *bdaddr = NULL;
+ int32_t uuid;
+
+ /*
+ * Minimal Service Register Request
+ *
+ * value16 - uuid 2 bytes
+ * bdaddr - BD_ADDR 6 bytes
+ */
+
+ if (!srv->fdidx[fd].control || 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, sizeof(iov)/sizeof(iov[0]));
+ } while (size < 0 && errno == EINTR);
+
+ srv->fdidx[fd].rsp_cs = 0;
+ srv->fdidx[fd].rsp_size = 0;
+ srv->fdidx[fd].rsp_limit = 0;
+
+ return ((size < 0)? errno : 0);
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/ssar.c b/usr.sbin/bluetooth/sdpd/ssar.c
new file mode 100644
index 0000000..d6f5095
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/ssar.c
@@ -0,0 +1,225 @@
+/*
+ * ssar.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.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);
+
+/*
+ * 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, uuid;
+
+ /*
+ * 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);
+
+ SDP_GET16(uuid, sspptr);
+ ssplen -= 2;
+ break;
+
+ case SDP_DATA_UUID32: /* XXX FIXME */
+ case SDP_DATA_UUID128: /* XXX FIXME */
+ 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;
+
+ if (provider->profile->uuid != uuid &&
+ SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP != uuid)
+ 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 0000000..807ceff
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/ssr.c
@@ -0,0 +1,252 @@
+/*
+ * ssr.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: ssr.c,v 1.5 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare 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, uuid;
+
+ /*
+ * 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);
+
+ SDP_GET16(uuid, req);
+ ssplen -= 2;
+ break;
+
+ case SDP_DATA_UUID32: /* XXX FIXME */
+ case SDP_DATA_UUID128: /* XXX FIXME */
+ 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;
+
+ if (provider->profile->uuid == uuid ||
+ SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP == uuid) {
+ 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]);
+
+ iov[0].iov_base = &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = rcounts;
+ iov[1].iov_len = sizeof(rcounts);
+
+ iov[2].iov_base = rsp;
+ iov[2].iov_len = rsp_end - rsp;
+
+ iov[3].iov_base = cs;
+ iov[3].iov_len = 1 + cs[0];
+
+ do {
+ size = writev(fd, (struct iovec const *) &iov, sizeof(iov)/sizeof(iov[0]));
+ } while (size < 0 && errno == EINTR);
+
+ /* Check if we have sent (or failed to sent) last response chunk */
+ if (srv->fdidx[fd].rsp_cs == srv->fdidx[fd].rsp_size) {
+ srv->fdidx[fd].rsp_cs = 0;
+ srv->fdidx[fd].rsp_size = 0;
+ srv->fdidx[fd].rsp_limit = 0;
+ }
+
+ return ((size < 0)? errno : 0);
+}
+
diff --git a/usr.sbin/bluetooth/sdpd/sur.c b/usr.sbin/bluetooth/sdpd/sur.c
new file mode 100644
index 0000000..6d7f778
--- /dev/null
+++ b/usr.sbin/bluetooth/sdpd/sur.c
@@ -0,0 +1,82 @@
+/*
+ * sur.c
+ *
+ * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sur.c,v 1.1 2004/01/13 01:54:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <sdp.h>
+#include <string.h>
+#include "profile.h"
+#include "provider.h"
+#include "server.h"
+
+/*
+ * Prepare Service Unregister response
+ */
+
+int32_t
+server_prepare_service_unregister_response(server_p srv, int32_t fd)
+{
+ uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
+ uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
+ uint8_t *rsp = srv->fdidx[fd].rsp;
+
+ provider_t *provider = NULL;
+ uint32_t handle;
+
+ /*
+ * Minimal Service Unregister Request
+ *
+ * value32 - uuid 4 bytes
+ */
+
+ if (!srv->fdidx[fd].control || 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);
+}
+
OpenPOWER on IntegriCloud