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 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 + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +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 + * 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 +#include +#include +#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 + * 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 +#include +#include +#include +#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 + * 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 +#include +#include +#include +#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 + * 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 +#include +#include +#include +#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 + * 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 +#include +#include +#include +#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 + * 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 +#include +#include +#include +#include +#include +#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 + * 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 +#include +#include + +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 + * 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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "server.h" + +#include +#include +#include +#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 + * 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 +#include +#include +#include +#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 + * 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 +#include +#include +#include +#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 + * 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 + * 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 +#include +#include +#include +#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 + * 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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include /* 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 + * 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 +#include +#include +#include +#include +#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 + * 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 +#include +#include +#include +#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 +.\" 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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + * 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 + * 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 +#include +#include +#include +#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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 + * 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 +#include +#include +#include +#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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 + * 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 +#include +#include +#include +#include +#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); +} +