diff options
author | emax <emax@FreeBSD.org> | 2004-01-20 20:48:26 +0000 |
---|---|---|
committer | emax <emax@FreeBSD.org> | 2004-01-20 20:48:26 +0000 |
commit | 8a9c8a287a37066fd95659d3185b331a52843591 (patch) | |
tree | c318d183c555f9482f9b067d6ac25de5901a5821 /lib | |
parent | 63d4653d05ffbec70fdf5d14dc3b1cb29e2b4425 (diff) | |
download | FreeBSD-src-8a9c8a287a37066fd95659d3185b331a52843591.zip FreeBSD-src-8a9c8a287a37066fd95659d3185b331a52843591.tar.gz |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libsdp/Makefile | 5 | ||||
-rw-r--r-- | lib/libsdp/sdp.3 | 90 | ||||
-rw-r--r-- | lib/libsdp/sdp.h | 44 | ||||
-rw-r--r-- | lib/libsdp/search.c | 10 | ||||
-rw-r--r-- | lib/libsdp/service.c | 237 |
5 files changed, 379 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); +} + |