diff options
| author | Maksim Yevmenkin <emax@FreeBSD.org> | 2004-01-20 20:48:26 +0000 | 
|---|---|---|
| committer | Maksim Yevmenkin <emax@FreeBSD.org> | 2004-01-20 20:48:26 +0000 | 
| commit | 07be7a6c2edb7aa5b3f80ba3d13ace5e22d2b47d (patch) | |
| tree | c318d183c555f9482f9b067d6ac25de5901a5821 | |
| parent | be057190048a620b99399889d15ae19be50e382c (diff) | |
Notes
31 files changed, 4663 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); +} + diff --git a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c index d77438655c46..6cb4863c4a75 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 000000000000..70dda891072f --- /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 000000000000..e7aeb78d679e --- /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 000000000000..bcebfc79807f --- /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 000000000000..d28a1205be67 --- /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 000000000000..10dafe0b1ed2 --- /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 000000000000..a5612eda64a7 --- /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 000000000000..b03f7e141d23 --- /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 000000000000..8c9ce778cfdd --- /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 000000000000..1df3bf0d5887 --- /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 000000000000..36359daa98ef --- /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 000000000000..d49929f7b94b --- /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 000000000000..0ca42211de11 --- /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 000000000000..b0f5347018f8 --- /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 000000000000..b48bc8dfe427 --- /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 000000000000..5bf8448619e4 --- /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 000000000000..f6f482d55fbb --- /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 000000000000..52f6c953bd09 --- /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 000000000000..38f4c6bf8269 --- /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 000000000000..14b2041cf220 --- /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 000000000000..6f8f08860768 --- /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 000000000000..31a9585a25e1 --- /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 000000000000..a1f3ded86339 --- /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 000000000000..d6f50950be50 --- /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 000000000000..807ceff44ca7 --- /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 000000000000..6d7f778aa51a --- /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); +} + | 
