aboutsummaryrefslogtreecommitdiff
path: root/lib/libsdp
diff options
context:
space:
mode:
authorMaksim Yevmenkin <emax@FreeBSD.org>2004-01-20 20:48:26 +0000
committerMaksim Yevmenkin <emax@FreeBSD.org>2004-01-20 20:48:26 +0000
commit07be7a6c2edb7aa5b3f80ba3d13ace5e22d2b47d (patch)
treec318d183c555f9482f9b067d6ac25de5901a5821 /lib/libsdp
parentbe057190048a620b99399889d15ae19be50e382c (diff)
downloadsrc-07be7a6c2edb7aa5b3f80ba3d13ace5e22d2b47d.tar.gz
src-07be7a6c2edb7aa5b3f80ba3d13ace5e22d2b47d.zip
Import sdpd(8) sources. This is Bluetooth Service Discovery Protocol daemon.
Extend libsdp(3) API to allow service registration and removal. Fix uninitialized variable bug in sdpcontrol(8). Reviewed by: imp (mentor) No objection: ru
Notes
Notes: svn path=/head/; revision=124758
Diffstat (limited to 'lib/libsdp')
-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
5 files changed, 379 insertions, 7 deletions
diff --git a/lib/libsdp/Makefile b/lib/libsdp/Makefile
index 4df747114eb6..f93c690d5e70 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 e849780e265e..e19854b1cbe8 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 4f5fb277bca4..42743f988797 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 98e3e1857aeb..42f162daf831 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 000000000000..2667966c7822
--- /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);
+}
+