Import sdpd(8) sources. This is Bluetooth Service Discovery Protocol daemon.

Extend libsdp(3) API to allow service registration and removal.
Fix uninitialized variable bug in sdpcontrol(8).

Reviewed by: imp (mentor)
No objection: ru
This commit is contained in:
Maksim Yevmenkin 2004-01-20 20:48:26 +00:00
parent be05719004
commit 07be7a6c2e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=124758
31 changed files with 4663 additions and 7 deletions

View file

@ -9,7 +9,7 @@ CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../../sys
SHLIB_MAJOR= 1
SRCS= search.c session.c util.c
SRCS= search.c service.c session.c util.c
INCS= sdp.h
MLINKS+= sdp.3 SDP_GET8.3
@ -29,5 +29,8 @@ MLINKS+= sdp.3 sdp_error.3
MLINKS+= sdp.3 sdp_search.3
MLINKS+= sdp.3 sdp_attr2desc.3
MLINKS+= sdp.3 sdp_uuid2desc.3
MLINKS+= sdp.3 sdp_register_service.3
MLINKS+= sdp.3 sdp_unregister_service.3
MLINKS+= sdp.3 sdp_change_service.3
.include <bsd.lib.mk>

View file

@ -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

View file

@ -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_ */

View file

@ -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);

237
lib/libsdp/service.c Normal file
View file

@ -0,0 +1,237 @@
/*
* service.c
*
* Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: service.c,v 1.1 2004/01/13 19:32:36 max Exp $
* $FreeBSD$
*/
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <bluetooth.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sdp-int.h>
#include <sdp.h>
static int32_t sdp_receive_error_pdu(sdp_session_p ss);
int32_t
sdp_register_service(void *xss, uint16_t uuid, bdaddr_p const bdaddr,
uint8_t const *data, uint32_t datalen, uint32_t *handle)
{
sdp_session_p ss = (sdp_session_p) xss;
struct iovec iov[4];
sdp_pdu_t pdu;
int32_t len;
if (ss == NULL)
return (-1);
if (bdaddr == NULL || data == NULL ||
datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
ss->error = EINVAL;
return (-1);
}
if (sizeof(pdu)+sizeof(uuid)+sizeof(*bdaddr)+datalen > SDP_LOCAL_MTU) {
ss->error = EMSGSIZE;
return (-1);
}
pdu.pid = SDP_PDU_SERVICE_REGISTER_REQUEST;
pdu.tid = htons(++ss->tid);
pdu.len = htons(sizeof(uuid) + sizeof(*bdaddr) + datalen);
uuid = htons(uuid);
iov[0].iov_base = (void *) &pdu;
iov[0].iov_len = sizeof(pdu);
iov[1].iov_base = (void *) &uuid;
iov[1].iov_len = sizeof(uuid);
iov[2].iov_base = (void *) bdaddr;
iov[2].iov_len = sizeof(*bdaddr);
iov[3].iov_base = (void *) data;
iov[3].iov_len = datalen;
do {
len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
} while (len < 0 && errno == EINTR);
if (len < 0) {
ss->error = errno;
return (-1);
}
len = sdp_receive_error_pdu(ss);
if (len < 0)
return (-1);
if (len != sizeof(pdu) + sizeof(uint16_t) + sizeof(uint32_t)) {
ss->error = EIO;
return (-1);
}
if (handle != NULL) {
*handle = (uint32_t) ss->rsp[--len];
*handle |= (uint32_t) ss->rsp[--len] << 8;
*handle |= (uint32_t) ss->rsp[--len] << 16;
*handle |= (uint32_t) ss->rsp[--len] << 24;
}
return (0);
}
int32_t
sdp_unregister_service(void *xss, uint32_t handle)
{
sdp_session_p ss = (sdp_session_p) xss;
struct iovec iov[2];
sdp_pdu_t pdu;
int32_t len;
if (ss == NULL)
return (-1);
if (!(ss->flags & SDP_SESSION_LOCAL)) {
ss->error = EINVAL;
return (-1);
}
if (sizeof(pdu) + sizeof(handle) > SDP_LOCAL_MTU) {
ss->error = EMSGSIZE;
return (-1);
}
pdu.pid = SDP_PDU_SERVICE_UNREGISTER_REQUEST;
pdu.tid = htons(++ss->tid);
pdu.len = htons(sizeof(handle));
handle = htonl(handle);
iov[0].iov_base = (void *) &pdu;
iov[0].iov_len = sizeof(pdu);
iov[1].iov_base = (void *) &handle;
iov[1].iov_len = sizeof(handle);
do {
len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
} while (len < 0 && errno == EINTR);
if (len < 0) {
ss->error = errno;
return (-1);
}
return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
}
int32_t
sdp_change_service(void *xss, uint32_t handle,
uint8_t const *data, uint32_t datalen)
{
sdp_session_p ss = (sdp_session_p) xss;
struct iovec iov[3];
sdp_pdu_t pdu;
int32_t len;
if (ss == NULL)
return (-1);
if (data == NULL || datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
ss->error = EINVAL;
return (-1);
}
if (sizeof(pdu) + sizeof(handle) + datalen > SDP_LOCAL_MTU) {
ss->error = EMSGSIZE;
return (-1);
}
pdu.pid = SDP_PDU_SERVICE_CHANGE_REQUEST;
pdu.tid = htons(++ss->tid);
pdu.len = htons(sizeof(handle) + datalen);
handle = htons(handle);
iov[0].iov_base = (void *) &pdu;
iov[0].iov_len = sizeof(pdu);
iov[1].iov_base = (void *) &handle;
iov[1].iov_len = sizeof(handle);
iov[2].iov_base = (void *) data;
iov[2].iov_len = datalen;
do {
len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
} while (len < 0 && errno == EINTR);
if (len < 0) {
ss->error = errno;
return (-1);
}
return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
}
static int32_t
sdp_receive_error_pdu(sdp_session_p ss)
{
sdp_pdu_p pdu;
int32_t len;
uint16_t error;
do {
len = read(ss->s, ss->rsp, ss->rsp_e - ss->rsp);
} while (len < 0 && errno == EINTR);
if (len < 0) {
ss->error = errno;
return (-1);
}
pdu = (sdp_pdu_p) ss->rsp;
pdu->tid = ntohs(pdu->tid);
pdu->len = ntohs(pdu->len);
if (pdu->pid != SDP_PDU_ERROR_RESPONSE || pdu->tid != ss->tid ||
pdu->len < 2 || pdu->len != len - sizeof(*pdu)) {
ss->error = EIO;
return (-1);
}
error = (uint16_t) ss->rsp[sizeof(pdu)] << 8;
error |= (uint16_t) ss->rsp[sizeof(pdu) + 1];
if (error != 0) {
ss->error = EIO;
return (-1);
}
return (len);
}

View file

@ -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) {

View file

@ -0,0 +1,102 @@
/*
* bgd.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bgd.c,v 1.4 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
static int32_t
bgd_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t service_classes[] = {
SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR
};
return (common_profile_create_service_class_id_list(
buf, eob,
(uint8_t const *) service_classes,
sizeof(service_classes)));
}
static int32_t
bgd_profile_create_service_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static char service_name[] = "Public Browse Group Root";
return (common_profile_create_string8(
buf, eob,
(uint8_t const *) service_name, strlen(service_name)));
}
static int32_t
bgd_profile_create_group_id(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (buf + 3 > eob)
return (-1);
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf);
return (3);
}
static attr_t bgd_profile_attrs[] = {
{ SDP_ATTR_SERVICE_RECORD_HANDLE,
common_profile_create_service_record_handle },
{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
bgd_profile_create_service_class_id_list },
{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
common_profile_create_language_base_attribute_id_list },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
bgd_profile_create_service_name },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
bgd_profile_create_service_name },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
common_profile_create_service_provider_name },
{ SDP_ATTR_GROUP_ID,
bgd_profile_create_group_id },
{ 0, NULL } /* end entry */
};
profile_t bgd_profile_descriptor = {
SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR,
0,
(profile_data_valid_p) NULL,
(attr_t const * const) &bgd_profile_attrs
};

View file

@ -0,0 +1,136 @@
/*
* dun.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: dun.c,v 1.5 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
static int32_t
dun_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t service_classes[] = {
SDP_SERVICE_CLASS_DIALUP_NETWORKING
};
return (common_profile_create_service_class_id_list(
buf, eob,
(uint8_t const *) service_classes,
sizeof(service_classes)));
}
static int32_t
dun_profile_create_bluetooth_profile_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t profile_descriptor_list[] = {
SDP_SERVICE_CLASS_DIALUP_NETWORKING,
0x0100
};
return (common_profile_create_bluetooth_profile_descriptor_list(
buf, eob,
(uint8_t const *) profile_descriptor_list,
sizeof(profile_descriptor_list)));
}
static int32_t
dun_profile_create_service_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static char service_name[] = "DialUp networking";
return (common_profile_create_string8(
buf, eob,
(uint8_t const *) service_name, strlen(service_name)));
}
static int32_t
dun_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_dun_profile_p dun = (sdp_dun_profile_p) provider->data;
return (rfcomm_profile_create_protocol_descriptor_list(
buf, eob,
(uint8_t const *) &dun->server_channel, 1));
}
static int32_t
dun_profile_create_audio_feedback_support(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_dun_profile_p dun = (sdp_dun_profile_p) provider->data;
if (buf + 2 > eob)
return (-1);
SDP_PUT8(SDP_DATA_BOOL, buf);
SDP_PUT8(dun->audio_feedback_support, buf);
return (2);
}
static attr_t dun_profile_attrs[] = {
{ SDP_ATTR_SERVICE_RECORD_HANDLE,
common_profile_create_service_record_handle },
{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
dun_profile_create_service_class_id_list },
{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
dun_profile_create_bluetooth_profile_descriptor_list },
{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
common_profile_create_language_base_attribute_id_list },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
dun_profile_create_service_name },
{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
dun_profile_create_protocol_descriptor_list },
{ SDP_ATTR_AUDIO_FEEDBACK_SUPPORT,
dun_profile_create_audio_feedback_support },
{ 0, NULL } /* end entry */
};
profile_t dun_profile_descriptor = {
SDP_SERVICE_CLASS_DIALUP_NETWORKING,
sizeof(sdp_dun_profile_t),
common_profile_server_channel_valid,
(attr_t const * const) &dun_profile_attrs
};

View file

@ -0,0 +1,117 @@
/*
* ftrn.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ftrn.c,v 1.5 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
static int32_t
ftrn_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t service_classes[] = {
SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER
};
return (common_profile_create_service_class_id_list(
buf, eob,
(uint8_t const *) service_classes,
sizeof(service_classes)));
}
static int32_t
ftrn_profile_create_bluetooth_profile_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t profile_descriptor_list[] = {
SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
0x0100
};
return (common_profile_create_bluetooth_profile_descriptor_list(
buf, eob,
(uint8_t const *) profile_descriptor_list,
sizeof(profile_descriptor_list)));
}
static int32_t
ftrn_profile_create_service_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static char service_name[] = "OBEX File Transfer";
return (common_profile_create_string8(
buf, eob,
(uint8_t const *) service_name, strlen(service_name)));
}
static int32_t
ftrn_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_ftrn_profile_p ftrn = (sdp_ftrn_profile_p) provider->data;
return (obex_profile_create_protocol_descriptor_list(
buf, eob,
(uint8_t const *) &ftrn->server_channel, 1));
}
static attr_t ftrn_profile_attrs[] = {
{ SDP_ATTR_SERVICE_RECORD_HANDLE,
common_profile_create_service_record_handle },
{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
ftrn_profile_create_service_class_id_list },
{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
ftrn_profile_create_bluetooth_profile_descriptor_list },
{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
common_profile_create_language_base_attribute_id_list },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
ftrn_profile_create_service_name },
{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
ftrn_profile_create_protocol_descriptor_list },
{ 0, NULL } /* end entry */
};
profile_t ftrn_profile_descriptor = {
SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER,
sizeof(sdp_ftrn_profile_t),
common_profile_server_channel_valid,
(attr_t const * const) &ftrn_profile_attrs
};

View file

@ -0,0 +1,133 @@
/*
* irmc.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: irmc.c,v 1.6 2004/01/13 19:31:54 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
static int32_t
irmc_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t service_classes[] = {
SDP_SERVICE_CLASS_IR_MC_SYNC
};
return (common_profile_create_service_class_id_list(
buf, eob,
(uint8_t const *) service_classes,
sizeof(service_classes)));
}
static int32_t
irmc_profile_create_bluetooth_profile_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t profile_descriptor_list[] = {
SDP_SERVICE_CLASS_IR_MC_SYNC,
0x0100
};
return (common_profile_create_bluetooth_profile_descriptor_list(
buf, eob,
(uint8_t const *) profile_descriptor_list,
sizeof(profile_descriptor_list)));
}
static int32_t
irmc_profile_create_service_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static char service_name[] = "IrMC Synchronization";
return (common_profile_create_string8(
buf, eob,
(uint8_t const *) service_name, strlen(service_name)));
}
static int32_t
irmc_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_irmc_profile_p irmc = (sdp_irmc_profile_p) provider->data;
return (obex_profile_create_protocol_descriptor_list(
buf, eob,
(uint8_t const *) &irmc->server_channel, 1));
}
static int32_t
irmc_profile_create_supported_formats_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_irmc_profile_p irmc = (sdp_irmc_profile_p) provider->data;
return (obex_profile_create_supported_formats_list(
buf, eob,
(uint8_t const *) irmc->supported_formats,
irmc->supported_formats_size));
}
static attr_t irmc_profile_attrs[] = {
{ SDP_ATTR_SERVICE_RECORD_HANDLE,
common_profile_create_service_record_handle },
{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
irmc_profile_create_service_class_id_list },
{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
irmc_profile_create_bluetooth_profile_descriptor_list },
{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
common_profile_create_language_base_attribute_id_list },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
irmc_profile_create_service_name },
{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
irmc_profile_create_protocol_descriptor_list },
{ SDP_ATTR_SUPPORTED_FORMATS_LIST,
irmc_profile_create_supported_formats_list },
{ 0, NULL } /* end entry */
};
profile_t irmc_profile_descriptor = {
SDP_SERVICE_CLASS_IR_MC_SYNC,
sizeof(sdp_irmc_profile_t),
obex_profile_data_valid,
(attr_t const * const) &irmc_profile_attrs
};

View file

@ -0,0 +1,117 @@
/*
* irmc_command_command_command.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: irmc_command.c,v 1.5 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
static int32_t
irmc_command_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t service_classes[] = {
SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND
};
return (common_profile_create_service_class_id_list(
buf, eob,
(uint8_t const *) service_classes,
sizeof(service_classes)));
}
static int32_t
irmc_command_profile_create_bluetooth_profile_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t profile_descriptor_list[] = {
SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,
0x0100
};
return (common_profile_create_bluetooth_profile_descriptor_list(
buf, eob,
(uint8_t const *) profile_descriptor_list,
sizeof(profile_descriptor_list)));
}
static int32_t
irmc_command_profile_create_service_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static char service_name[] = "Sync Command Service";
return (common_profile_create_string8(
buf, eob,
(uint8_t const *) service_name, strlen(service_name)));
}
static int32_t
irmc_command_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_irmc_command_profile_p irmc_command = (sdp_irmc_command_profile_p) provider->data;
return (obex_profile_create_protocol_descriptor_list(
buf, eob,
(uint8_t const *) &irmc_command->server_channel, 1));
}
static attr_t irmc_command_profile_attrs[] = {
{ SDP_ATTR_SERVICE_RECORD_HANDLE,
common_profile_create_service_record_handle },
{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
irmc_command_profile_create_service_class_id_list },
{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
irmc_command_profile_create_bluetooth_profile_descriptor_list },
{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
common_profile_create_language_base_attribute_id_list },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
irmc_command_profile_create_service_name },
{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
irmc_command_profile_create_protocol_descriptor_list },
{ 0, NULL } /* end entry */
};
profile_t irmc_command_profile_descriptor = {
SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND,
sizeof(sdp_irmc_command_profile_t),
common_profile_server_channel_valid,
(attr_t const * const) &irmc_command_profile_attrs
};

View file

@ -0,0 +1,177 @@
/*
* lan.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: lan.c,v 1.5 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <arpa/inet.h>
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <stdio.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
static int32_t
lan_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t service_classes[] = {
SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP
};
return (common_profile_create_service_class_id_list(
buf, eob,
(uint8_t const *) service_classes,
sizeof(service_classes)));
}
static int32_t
lan_profile_create_bluetooth_profile_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t profile_descriptor_list[] = {
SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
0x0100
};
return (common_profile_create_bluetooth_profile_descriptor_list(
buf, eob,
(uint8_t const *) profile_descriptor_list,
sizeof(profile_descriptor_list)));
}
static int32_t
lan_profile_create_service_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static char service_name[] = "LAN Access using PPP";
return (common_profile_create_string8(
buf, eob,
(uint8_t const *) service_name, strlen(service_name)));
}
static int32_t
lan_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_lan_profile_p lan = (sdp_lan_profile_p) provider->data;
return (rfcomm_profile_create_protocol_descriptor_list(
buf, eob,
(uint8_t const *) &lan->server_channel, 1));
}
static int32_t
lan_profile_create_service_availability(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_lan_profile_p lan = (sdp_lan_profile_p) provider->data;
if (buf + 2 > eob)
return (-1);
SDP_PUT8(SDP_DATA_UINT8, buf);
SDP_PUT8(lan->load_factor, buf);
return (2);
}
static int32_t
lan_profile_create_ip_subnet(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_lan_profile_p lan = (sdp_lan_profile_p) provider->data;
char net[32];
int32_t len;
len = snprintf(net, sizeof(net), "%s/%d",
inet_ntoa(* (struct in_addr *) &lan->ip_subnet),
lan->ip_subnet_radius);
if (len < 0 || buf + 2 + len > eob)
return (-1);
SDP_PUT8(SDP_DATA_STR8, buf);
SDP_PUT8(len, buf);
memcpy(buf, net, len);
return (2 + len);
}
static int32_t
lan_profile_data_valid(uint8_t const *data, uint32_t datalen)
{
sdp_lan_profile_p lan = (sdp_lan_profile_p) data;
if (lan->server_channel < 1 ||
lan->server_channel > 30 ||
lan->ip_subnet_radius > 32)
return (0);
return (1);
}
static attr_t lan_profile_attrs[] = {
{ SDP_ATTR_SERVICE_RECORD_HANDLE,
common_profile_create_service_record_handle },
{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
lan_profile_create_service_class_id_list },
{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
lan_profile_create_bluetooth_profile_descriptor_list },
{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
common_profile_create_language_base_attribute_id_list },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
lan_profile_create_service_name },
{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
lan_profile_create_protocol_descriptor_list },
{ SDP_ATTR_SERVICE_AVAILABILITY,
lan_profile_create_service_availability },
{ SDP_ATTR_IP_SUBNET,
lan_profile_create_ip_subnet },
{ 0, NULL } /* end entry */
};
profile_t lan_profile_descriptor = {
SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
sizeof(sdp_lan_profile_t),
lan_profile_data_valid,
(attr_t const * const) &lan_profile_attrs
};

View file

@ -0,0 +1,127 @@
/*
* log.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: log.c,v 1.1 2004/01/07 23:15:00 max Exp $
* $FreeBSD$
*/
#include <sys/types.h>
#include <stdarg.h>
#include <syslog.h>
void
log_open(char const *prog, int32_t log2stderr)
{
openlog(prog, LOG_PID|LOG_NDELAY|(log2stderr? LOG_PERROR:0), LOG_USER);
}
void
log_close(void)
{
closelog();
}
void
log_emerg(char const *message, ...)
{
va_list ap;
va_start(ap, message);
vsyslog(LOG_EMERG, message, ap);
va_end(ap);
}
void
log_alert(char const *message, ...)
{
va_list ap;
va_start(ap, message);
vsyslog(LOG_ALERT, message, ap);
va_end(ap);
}
void
log_crit(char const *message, ...)
{
va_list ap;
va_start(ap, message);
vsyslog(LOG_CRIT, message, ap);
va_end(ap);
}
void
log_err(char const *message, ...)
{
va_list ap;
va_start(ap, message);
vsyslog(LOG_ERR, message, ap);
va_end(ap);
}
void
log_warning(char const *message, ...)
{
va_list ap;
va_start(ap, message);
vsyslog(LOG_WARNING, message, ap);
va_end(ap);
}
void
log_notice(char const *message, ...)
{
va_list ap;
va_start(ap, message);
vsyslog(LOG_NOTICE, message, ap);
va_end(ap);
}
void
log_info(char const *message, ...)
{
va_list ap;
va_start(ap, message);
vsyslog(LOG_INFO, message, ap);
va_end(ap);
}
void
log_debug(char const *message, ...)
{
va_list ap;
va_start(ap, message);
vsyslog(LOG_DEBUG, message, ap);
va_end(ap);
}

View file

@ -0,0 +1,47 @@
/*
* log.h
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: log.h,v 1.1 2004/01/07 23:15:00 max Exp $
* $FreeBSD$
*/
#ifndef _LOG_H_
#define _LOG_H_
void log_open (char const *prog, int32_t log2stderr);
void log_close (void);
void log_emerg (char const *message, ...);
void log_alert (char const *message, ...);
void log_crit (char const *message, ...);
void log_err (char const *message, ...);
void log_warning (char const *message, ...);
void log_notice (char const *message, ...);
void log_info (char const *message, ...);
void log_debug (char const *message, ...);
#endif /* ndef _LOG_H_ */

View file

@ -0,0 +1,235 @@
/*
* main.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: main.c,v 1.8 2004/01/13 19:31:54 max Exp $
* $FreeBSD$
*/
#include <sys/select.h>
#include <bluetooth.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <sdp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "log.h"
#include "server.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/queue.h>
#include "profile.h"
#include "provider.h"
#define SDPD "sdpd"
static int32_t drop_root (char const *user, char const *group);
static void sighandler (int32_t s);
static void usage (void);
static int32_t done;
/*
* Bluetooth Service Discovery Procotol (SDP) daemon
*/
int
main(int argc, char *argv[])
{
server_t server;
char const *control = SDP_LOCAL_PATH;
char const *user = "nobody", *group = "nobody";
int32_t detach = 1, opt;
struct sigaction sa;
while ((opt = getopt(argc, argv, "c:dg:hu:")) != -1) {
switch (opt) {
case 'c': /* control */
control = optarg;
break;
case 'd': /* do not detach */
detach = 0;
break;
case 'g': /* group */
group = optarg;
break;
case 'u': /* user */
user = optarg;
break;
case 'h':
default:
usage();
/* NOT REACHED */
}
}
log_open(SDPD, !detach);
/* Become daemon if required */
if (detach && daemon(0, 0) < 0) {
log_crit("Could not become daemon. %s (%d)",
strerror(errno), errno);
exit(1);
}
/* Set signal handlers */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sighandler;
if (sigaction(SIGTERM, &sa, NULL) < 0 ||
sigaction(SIGHUP, &sa, NULL) < 0 ||
sigaction(SIGINT, &sa, NULL) < 0) {
log_crit("Could not install signal handlers. %s (%d)",
strerror(errno), errno);
exit(1);
}
sa.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &sa, NULL) < 0) {
log_crit("Could not install signal handlers. %s (%d)",
strerror(errno), errno);
exit(1);
}
/* Initialize server */
if (server_init(&server, control) < 0)
exit(1);
if ((user != NULL || group != NULL) && drop_root(user, group) < 0)
exit(1);
for (done = 0; !done; ) {
if (server_do(&server) != 0)
done ++;
}
server_shutdown(&server);
log_close();
return (0);
}
/*
* Drop root
*/
static int32_t
drop_root(char const *user, char const *group)
{
int uid, gid;
char *ep;
if ((uid = getuid()) != 0) {
log_notice("Cannot set uid/gid. Not a superuser");
return (0); /* dont do anything unless root */
}
gid = getgid();
if (user != NULL) {
uid = strtol(user, &ep, 10);
if (*ep != '\0') {
struct passwd *pwd = getpwnam(user);
if (pwd == NULL) {
log_err("Could not find passwd entry for " \
"user %s", user);
return (-1);
}
uid = pwd->pw_uid;
}
}
if (group != NULL) {
gid = strtol(group, &ep, 10);
if (*ep != '\0') {
struct group *grp = getgrnam(group);
if (grp == NULL) {
log_err("Could not find group entry for " \
"group %s", group);
return (-1);
}
gid = grp->gr_gid;
}
}
if (setgid(gid) < 0) {
log_err("Could not setgid(%s). %s (%d)",
group, strerror(errno), errno);
return (-1);
}
if (setuid(uid) < 0) {
log_err("Could not setuid(%s). %s (%d)",
user, strerror(errno), errno);
return (-1);
}
return (0);
}
/*
* Signal handler
*/
static void
sighandler(int32_t s)
{
log_notice("Got signal %d. Total number of signals received %d",
s, ++ done);
}
/*
* Display usage information and quit
*/
static void
usage(void)
{
fprintf(stderr,
"Usage: %s [options]\n" \
"Where options are:\n" \
" -c specify control socket name (default %s)\n" \
" -d do not detach (run in foreground)\n" \
" -g grp specify group\n" \
" -h display usage and exit\n" \
" -u usr specify user\n",
SDPD, SDP_LOCAL_PATH);
exit(255);
}

View file

@ -0,0 +1,133 @@
/*
* opush.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: opush.c,v 1.6 2004/01/13 19:31:54 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
static int32_t
opush_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t service_classes[] = {
SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH
};
return (common_profile_create_service_class_id_list(
buf, eob,
(uint8_t const *) service_classes,
sizeof(service_classes)));
}
static int32_t
opush_profile_create_bluetooth_profile_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t profile_descriptor_list[] = {
SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
0x0100
};
return (common_profile_create_bluetooth_profile_descriptor_list(
buf, eob,
(uint8_t const *) profile_descriptor_list,
sizeof(profile_descriptor_list)));
}
static int32_t
opush_profile_create_service_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static char service_name[] = "OBEX Object Push";
return (common_profile_create_string8(
buf, eob,
(uint8_t const *) service_name, strlen(service_name)));
}
static int32_t
opush_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_opush_profile_p opush = (sdp_opush_profile_p) provider->data;
return (obex_profile_create_protocol_descriptor_list(
buf, eob,
(uint8_t const *) &opush->server_channel, 1));
}
static int32_t
opush_profile_create_supported_formats_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_opush_profile_p opush = (sdp_opush_profile_p) provider->data;
return (obex_profile_create_supported_formats_list(
buf, eob,
(uint8_t const *) opush->supported_formats,
opush->supported_formats_size));
}
static attr_t opush_profile_attrs[] = {
{ SDP_ATTR_SERVICE_RECORD_HANDLE,
common_profile_create_service_record_handle },
{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
opush_profile_create_service_class_id_list },
{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
opush_profile_create_bluetooth_profile_descriptor_list },
{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
common_profile_create_language_base_attribute_id_list },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
opush_profile_create_service_name },
{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
opush_profile_create_protocol_descriptor_list },
{ SDP_ATTR_SUPPORTED_FORMATS_LIST,
opush_profile_create_supported_formats_list },
{ 0, NULL } /* end entry */
};
profile_t opush_profile_descriptor = {
SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH,
sizeof(sdp_opush_profile_t),
obex_profile_data_valid,
(attr_t const * const) &opush_profile_attrs
};

View file

@ -0,0 +1,382 @@
/*
* profile.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
/*
* Lookup profile descriptor
*/
profile_p
profile_get_descriptor(uint16_t uuid)
{
extern profile_t dun_profile_descriptor;
extern profile_t ftrn_profile_descriptor;
extern profile_t irmc_profile_descriptor;
extern profile_t irmc_command_profile_descriptor;
extern profile_t lan_profile_descriptor;
extern profile_t opush_profile_descriptor;
extern profile_t sp_profile_descriptor;
static const profile_p profiles[] = {
&dun_profile_descriptor,
&ftrn_profile_descriptor,
&irmc_profile_descriptor,
&irmc_command_profile_descriptor,
&lan_profile_descriptor,
&opush_profile_descriptor,
&sp_profile_descriptor
};
int32_t i;
for (i = 0; i < sizeof(profiles)/sizeof(profiles[0]); i++)
if (profiles[i]->uuid == uuid)
return (profiles[i]);
return (NULL);
}
/*
* Look attribute in the profile descripror
*/
profile_attr_create_p
profile_get_attr(const profile_p profile, uint16_t attr)
{
attr_p ad = (attr_p) profile->attrs;
for (; ad->create != NULL; ad ++)
if (ad->attr == attr)
return (ad->create);
return (NULL);
}
/*
* uint32 value32 - 5 bytes
*/
int32_t
common_profile_create_service_record_handle(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (buf + 5 > eob)
return (-1);
SDP_PUT8(SDP_DATA_UINT32, buf);
SDP_PUT32(((provider_p) data)->handle, buf);
return (5);
}
/*
* seq8 len8 - 2 bytes
* uuid16 value16 - 3 bytes
* [ uuid16 value ]
*/
int32_t
common_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
int32_t len = 3 * (datalen >>= 1);
if (len <= 0 || len > 0xff || buf + 2 + len > eob)
return (-1);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(len, buf);
for (; datalen > 0; datalen --) {
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(*((uint16_t const *)data)++, buf);
}
return (2 + len);
}
/*
* seq8 len8 - 2 bytes
* seq 8 len8 - 2 bytes
* uuid16 value16 - 3 bytes
* uint16 value16 - 3 bytes
* [ seq 8 len8
* uuid16 value16
* uint16 value16 ]
*/
int32_t
common_profile_create_bluetooth_profile_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
int32_t len = 8 * (datalen >>= 2);
if (len <= 0 || len > 0xff || buf + 2 + len > eob)
return (-1);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(len, buf);
for (; datalen > 0; datalen --) {
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(6, buf);
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(*((uint16_t const *)data)++, buf);
SDP_PUT8(SDP_DATA_UINT16, buf);
SDP_PUT16(*((uint16_t const *)data)++, buf);
}
return (2 + len);
}
/*
* seq8 len8 - 2 bytes
* uint16 value16 - 3 bytes
* uint16 value16 - 3 bytes
* uint16 value16 - 3 bytes
*/
int32_t
common_profile_create_language_base_attribute_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (buf + 11 > eob)
return (-1);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(9, buf);
/*
* Language code per ISO 639:1988. Use "en".
*/
SDP_PUT8(SDP_DATA_UINT16, buf);
SDP_PUT16(((0x65 << 8) | 0x6e), buf);
/*
* Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106
* (http://www.iana.org/assignments/character-sets)
*/
SDP_PUT8(SDP_DATA_UINT16, buf);
SDP_PUT16(106, buf);
/*
* Offset (Primary Language Base is 0x100)
*/
SDP_PUT8(SDP_DATA_UINT16, buf);
SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf);
return (11);
}
/*
* Common provider name is "FreeBSD"
*/
int32_t
common_profile_create_service_provider_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
char provider_name[] = "FreeBSD";
return (common_profile_create_string8(buf, eob,
(uint8_t const *) provider_name,
strlen(provider_name)));
}
/*
* str8 len8 string
*/
int32_t
common_profile_create_string8(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob)
return (-1);
SDP_PUT8(SDP_DATA_STR8, buf);
SDP_PUT8(datalen, buf);
memcpy(buf, data, datalen);
return (2 + datalen);
}
/*
* seq8 len8 - 2 bytes
* seq8 len8 - 2 bytes
* uuid16 value16 - 3 bytes
* seq8 len8 - 2 bytes
* uuid16 value16 - 3 bytes
* uint8 value8 - 2 bytes
*/
int32_t
rfcomm_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (datalen != 1 || buf + 14 > eob)
return (-1);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(12, buf);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(3, buf);
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(5, buf);
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
SDP_PUT8(SDP_DATA_UINT8, buf);
SDP_PUT8(*data, buf);
return (14);
}
/*
* seq8 len8 - 2 bytes
* seq8 len8 - 2 bytes
* uuid16 value16 - 3 bytes
* seq8 len8 - 2 bytes
* uuid16 value16 - 3 bytes
* uint8 value8 - 2 bytes
* seq8 len8 - 2 bytes
* uuid16 value16 - 3 bytes
*/
int32_t
obex_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (datalen != 1 || buf + 19 > eob)
return (-1);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(17, buf);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(3, buf);
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(5, buf);
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
SDP_PUT8(SDP_DATA_UINT8, buf);
SDP_PUT8(*data, buf);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(3, buf);
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf);
return (19);
}
/*
* seq8 len8
* uint8 value8 - bytes
* [ uint8 value 8 ]
*/
int32_t
obex_profile_create_supported_formats_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
int32_t len = 2 * datalen;
if (len <= 0 || len > 0xff || buf + 2 + len > eob)
return (-1);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(len, buf);
for (; datalen > 0; datalen --) {
SDP_PUT8(SDP_DATA_UINT8, buf);
SDP_PUT8(*data++, buf);
}
return (2 + len);
}
/*
* verify server channel number (the first byte in the data)
*/
int32_t
common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen)
{
if (data[0] < 1 || data[0] > 30)
return (0);
return (1);
}
/*
* verify server channel number and supported_formats_size
* sdp_opush_profile and sdp_irmc_profile
*/
int32_t
obex_profile_data_valid(uint8_t const *data, uint32_t datalen)
{
sdp_opush_profile_p opush = (sdp_opush_profile_p) data;
if (opush->server_channel < 1 ||
opush->server_channel > 30 ||
opush->supported_formats_size == 0 ||
opush->supported_formats_size > sizeof(opush->supported_formats))
return (0);
return (1);
}

View file

@ -0,0 +1,90 @@
/*
* profile.h
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: profile.h,v 1.6 2004/01/13 19:31:54 max Exp $
* $FreeBSD$
*/
#ifndef _PROFILE_H_
#define _PROFILE_H_
/*
* Attribute descriptor
*/
typedef int32_t (profile_attr_create_t)(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen);
typedef profile_attr_create_t * profile_attr_create_p;
typedef int32_t (profile_data_valid_t)(
uint8_t const *data, uint32_t datalen);
typedef profile_data_valid_t * profile_data_valid_p;
struct attr
{
uint16_t attr; /* attribute id */
profile_attr_create_p create; /* create attr value */
};
typedef struct attr attr_t;
typedef struct attr * attr_p;
/*
* Profile descriptor
*/
struct profile
{
uint16_t uuid; /* profile uuid */
uint16_t dsize; /* profile data size */
profile_data_valid_p valid; /* profile data validator */
attr_t const * const attrs; /* supported attributes */
};
typedef struct profile profile_t;
typedef struct profile *profile_p;
profile_p profile_get_descriptor(uint16_t uuid);
profile_attr_create_p profile_get_attr(const profile_p profile, uint16_t attr);
profile_attr_create_t common_profile_create_service_record_handle;
profile_attr_create_t common_profile_create_service_class_id_list;
profile_attr_create_t common_profile_create_bluetooth_profile_descriptor_list;
profile_attr_create_t common_profile_create_language_base_attribute_id_list;
profile_attr_create_t common_profile_create_service_provider_name;
profile_attr_create_t common_profile_create_string8;
profile_attr_create_t rfcomm_profile_create_protocol_descriptor_list;
profile_attr_create_t obex_profile_create_protocol_descriptor_list;
profile_attr_create_t obex_profile_create_supported_formats_list;
profile_data_valid_t common_profile_server_channel_valid;
profile_data_valid_t obex_profile_data_valid;
#endif /* ndef _PROFILE_H_ */

View file

@ -0,0 +1,196 @@
/*
* provider.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: provider.c,v 1.5 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <string.h>
#include <stdlib.h>
#include "profile.h"
#include "provider.h"
static TAILQ_HEAD(, provider) providers = TAILQ_HEAD_INITIALIZER(providers);
static uint32_t change_state = 0;
static uint32_t handle = 0;
/*
* Register Service Discovery provider.
* Should not be called more the once.
*/
int32_t
provider_register_sd(int32_t fd)
{
extern profile_t sd_profile_descriptor;
extern profile_t bgd_profile_descriptor;
provider_p sd = calloc(1, sizeof(*sd));
provider_p bgd = calloc(1, sizeof(*bgd));
if (sd == NULL || bgd == NULL) {
if (sd != NULL)
free(sd);
if (bgd != NULL)
free(bgd);
return (-1);
}
sd->profile = &sd_profile_descriptor;
bgd->handle = 0;
sd->fd = fd;
TAILQ_INSERT_HEAD(&providers, sd, provider_next);
bgd->profile = &bgd_profile_descriptor;
bgd->handle = 1;
sd->fd = fd;
TAILQ_INSERT_AFTER(&providers, sd, bgd, provider_next);
change_state ++;
return (0);
}
/*
* Register new provider for a given profile, bdaddr and session.
*/
provider_p
provider_register(profile_p const profile, bdaddr_p const bdaddr, int32_t fd,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = calloc(1, sizeof(*provider));
if (provider != NULL) {
provider->data = malloc(datalen);
if (provider->data != NULL) {
provider->profile = profile;
memcpy(provider->data, data, datalen);
/*
* Record handles 0x0 and 0x1 are reserved
* for SDP itself
*/
if (++ handle <= 1)
handle = 2;
provider->handle = handle;
memcpy(&provider->bdaddr, bdaddr,
sizeof(provider->bdaddr));
provider->fd = fd;
TAILQ_INSERT_TAIL(&providers, provider, provider_next);
change_state ++;
} else {
free(provider);
provider = NULL;
}
}
return (provider);
}
/*
* Unregister provider
*/
void
provider_unregister(provider_p provider)
{
TAILQ_REMOVE(&providers, provider, provider_next);
if (provider->data != NULL)
free(provider->data);
free(provider);
change_state ++;
}
/*
* Update provider data
*/
int32_t
provider_update(provider_p provider, uint8_t const *data, uint32_t datalen)
{
uint8_t *new_data = (uint8_t *) realloc(provider->data, datalen);
if (new_data == NULL)
return (-1);
memcpy(new_data, data, datalen);
provider->data = new_data;
return (0);
}
/*
* Get a provider for given record handle
*/
provider_p
provider_by_handle(uint32_t handle)
{
provider_p provider = NULL;
TAILQ_FOREACH(provider, &providers, provider_next)
if (provider->handle == handle)
break;
return (provider);
}
/*
* Cursor access
*/
provider_p
provider_get_first(void)
{
return (TAILQ_FIRST(&providers));
}
provider_p
provider_get_next(provider_p provider)
{
return (TAILQ_NEXT(provider, provider_next));
}
/*
* Return change state
*/
uint32_t
provider_get_change_state(void)
{
return (change_state);
}

View file

@ -0,0 +1,75 @@
/*
* provider.h
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: provider.h,v 1.6 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#ifndef _PROVIDER_H_
#define _PROVIDER_H_
/*
* Provider of service
*/
struct profile;
struct provider
{
struct profile *profile; /* profile */
void *data; /* profile data */
uint32_t handle; /* record handle */
bdaddr_t bdaddr; /* provider's BDADDR */
int32_t fd; /* session descriptor */
TAILQ_ENTRY(provider) provider_next; /* all providers */
};
typedef struct provider provider_t;
typedef struct provider * provider_p;
#define provider_match_bdaddr(p, b) \
(memcmp(b, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0 || \
memcmp(&(p)->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0 || \
memcmp(&(p)->bdaddr, b, sizeof(bdaddr_t)) == 0)
int32_t provider_register_sd (int32_t fd);
provider_p provider_register (profile_p const profile,
bdaddr_p const bdaddr,
int32_t fd,
uint8_t const *data,
uint32_t datalen);
void provider_unregister (provider_p provider);
int32_t provider_update (provider_p provider,
uint8_t const *data,
uint32_t datalen);
provider_p provider_by_handle (uint32_t handle);
provider_p provider_get_first (void);
provider_p provider_get_next (provider_p provider);
uint32_t provider_get_change_state (void);
#endif /* ndef _PROVIDER_H_ */

View file

@ -0,0 +1,315 @@
/*
* sar.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sar.c,v 1.2 2004/01/08 23:46:51 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
#include <stdio.h> /* for NULL */
#include "profile.h"
#include "provider.h"
#include "server.h"
/*
* Prepare SDP attr/value pair. Check if profile implements the attribute
* and if so call the attribute value function.
*
* uint16 value16 - 3 bytes (attribute)
* value - N bytes (value)
*/
static int32_t
server_prepare_attr_value_pair(
provider_p const provider, uint16_t attr,
uint8_t *buf, uint8_t const * const eob)
{
profile_attr_create_p cf = profile_get_attr(provider->profile, attr);
int32_t len;
if (cf == NULL)
return (0); /* no attribute */
if (buf + 3 > eob)
return (-1);
SDP_PUT8(SDP_DATA_UINT16, buf);
SDP_PUT16(attr, buf);
len = cf(buf, eob, (uint8_t const *) provider, sizeof(*provider));
if (len < 0)
return (-1);
return (3 + len);
}
/*
* seq16 value16 - 3 bytes
* attr value - 3+ bytes
* [ attr value ]
*/
int32_t
server_prepare_attr_list(provider_p const provider,
uint8_t const *req, uint8_t const * const req_end,
uint8_t *rsp, uint8_t const * const rsp_end)
{
uint8_t *ptr = rsp + 3;
int32_t type, hi, lo, len;
if (ptr > rsp_end)
return (-1);
while (req < req_end) {
SDP_GET8(type, req);
switch (type) {
case SDP_DATA_UINT16:
if (req + 2 > req_end)
return (-1);
SDP_GET16(lo, req);
hi = lo;
break;
case SDP_DATA_UINT32:
if (req + 4 > req_end)
return (-1);
SDP_GET16(lo, req);
SDP_GET16(hi, req);
break;
default:
return (-1);
/* NOT REACHED */
}
for (; lo <= hi; lo ++) {
len = server_prepare_attr_value_pair(provider, lo, ptr, rsp_end);
if (len < 0)
return (-1);
ptr += len;
}
}
len = ptr - rsp; /* we put this much bytes in rsp */
/* Fix SEQ16 header for the rsp */
SDP_PUT8(SDP_DATA_SEQ16, rsp);
SDP_PUT16(len - 3, rsp);
return (len);
}
/*
* Prepare SDP Service Attribute Response
*/
int32_t
server_prepare_service_attribute_response(server_p srv, int32_t fd)
{
uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
uint8_t *rsp = srv->fdidx[fd].rsp;
uint8_t const *rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
uint8_t *ptr = NULL;
provider_t *provider = NULL;
uint32_t handle;
int32_t type, rsp_limit, aidlen, cslen, cs;
/*
* Minimal Service Attribute Request request
*
* value32 - 4 bytes ServiceRecordHandle
* value16 - 2 bytes MaximumAttributeByteCount
* seq8 len8 - 2 bytes
* uint16 value16 - 3 bytes AttributeIDList
* value8 - 1 byte ContinuationState
*/
if (req_end - req < 12)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Get ServiceRecordHandle and MaximumAttributeByteCount */
SDP_GET32(handle, req);
SDP_GET16(rsp_limit, req);
if (rsp_limit <= 0)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Get size of AttributeIDList */
aidlen = 0;
SDP_GET8(type, req);
switch (type) {
case SDP_DATA_SEQ8:
SDP_GET8(aidlen, req);
break;
case SDP_DATA_SEQ16:
SDP_GET16(aidlen, req);
break;
case SDP_DATA_SEQ32:
SDP_GET32(aidlen, req);
break;
}
if (aidlen <= 0)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
ptr = (uint8_t *) req + aidlen;
/* Get ContinuationState */
if (ptr + 1 > req_end)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET8(cslen, ptr);
if (cslen != 0) {
if (cslen != 2 || req_end - ptr != 2)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET16(cs, ptr);
} else
cs = 0;
/* Process the request. First, check continuation state */
if (srv->fdidx[fd].rsp_cs != cs)
return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
if (srv->fdidx[fd].rsp_size > 0)
return (0);
/* Lookup record handle */
if ((provider = provider_by_handle(handle)) == NULL)
return (SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE);
/*
* Service Attribute Response format
*
* value16 - 2 bytes AttributeListByteCount (not incl.)
* seq8 len16 - 3 bytes
* attr value - 3+ bytes AttributeList
* [ attr value ]
*/
cs = server_prepare_attr_list(provider, req, req+aidlen, rsp, rsp_end);
if (cs < 0)
return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
/* Set reply size (not counting PDU header and continuation state) */
srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
if (srv->fdidx[fd].rsp_limit > rsp_limit)
srv->fdidx[fd].rsp_limit = rsp_limit;
srv->fdidx[fd].rsp_size = cs;
srv->fdidx[fd].rsp_cs = 0;
return (0);
}
/*
* Send SDP Service [Search] Attribute Response
*/
int32_t
server_send_service_attribute_response(server_p srv, int32_t fd)
{
uint8_t *rsp = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_cs;
uint8_t *rsp_end = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_size;
struct iovec iov[4];
sdp_pdu_t pdu;
uint16_t bcount;
uint8_t cs[3];
int32_t size;
/* First update continuation state (assume we will send all data) */
size = rsp_end - rsp;
srv->fdidx[fd].rsp_cs += size;
if (size + 1 > srv->fdidx[fd].rsp_limit) {
/*
* We need to split out response. Add 3 more bytes for the
* continuation state and move rsp_end and rsp_cs backwards.
*/
while ((rsp_end - rsp) + 3 > srv->fdidx[fd].rsp_limit) {
rsp_end --;
srv->fdidx[fd].rsp_cs --;
}
cs[0] = 2;
cs[1] = srv->fdidx[fd].rsp_cs >> 8;
cs[2] = srv->fdidx[fd].rsp_cs & 0xff;
} else
cs[0] = 0;
assert(rsp_end >= rsp);
bcount = htons(rsp_end - rsp);
if (((sdp_pdu_p)(srv->req))->pid == SDP_PDU_SERVICE_ATTRIBUTE_REQUEST)
pdu.pid = SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE;
else
pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
pdu.tid = ((sdp_pdu_p)(srv->req))->tid;
pdu.len = htons(sizeof(bcount) + bcount + 1 + cs[0]);
iov[0].iov_base = &pdu;
iov[0].iov_len = sizeof(pdu);
iov[1].iov_base = &bcount;
iov[1].iov_len = sizeof(bcount);
iov[2].iov_base = rsp;
iov[2].iov_len = rsp_end - rsp;
iov[3].iov_base = cs;
iov[3].iov_len = 1 + cs[0];
do {
size = writev(fd, (struct iovec const *) &iov, sizeof(iov)/sizeof(iov[0]));
} while (size < 0 && errno == EINTR);
/* Check if we have sent (or failed to sent) last response chunk */
if (srv->fdidx[fd].rsp_cs == srv->fdidx[fd].rsp_size) {
srv->fdidx[fd].rsp_cs = 0;
srv->fdidx[fd].rsp_size = 0;
srv->fdidx[fd].rsp_limit = 0;
}
return ((size < 0)? errno : 0);
}

View file

@ -0,0 +1,91 @@
/*
* scr.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: scr.c,v 1.1 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
#include "server.h"
/*
* Prepare Service Change response
*/
int32_t
server_prepare_service_change_response(server_p srv, int32_t fd)
{
uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
uint8_t *rsp = srv->fdidx[fd].rsp;
provider_t *provider = NULL;
uint32_t handle;
/*
* Minimal Service Change Request
*
* value32 - handle 4 bytes
*/
if (!srv->fdidx[fd].control || req_end - req < 4)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Get handle */
SDP_GET32(handle, req);
/* Lookup provider */
provider = provider_by_handle(handle);
if (provider == NULL || provider->fd != fd)
return (SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE);
/* Validate user data */
if (req_end - req < provider->profile->dsize ||
provider->profile->valid == NULL ||
(provider->profile->valid)(req, req_end - req) == 0)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Update provider */
if (provider_update(provider, req, req_end - req) < 0)
return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
SDP_PUT16(0, rsp);
/* Set reply size */
srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
srv->fdidx[fd].rsp_cs = 0;
return (0);
}

View file

@ -0,0 +1,212 @@
/*
* sd.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sd.c,v 1.4 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
static int32_t
sd_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t service_classes[] = {
SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER
};
return (common_profile_create_service_class_id_list(
buf, eob,
(uint8_t const *) service_classes,
sizeof(service_classes)));
}
static int32_t
sd_profile_create_service_id(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (buf + 3 > eob)
return (-1);
/*
* The ServiceID is a UUID that universally and uniquely identifies
* the service instance described by the service record. This service
* attribute is particularly useful if the same service is described
* by service records in more than one SDP server
*/
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(SDP_UUID_PROTOCOL_SDP, buf); /* XXX ??? */
return (3);
}
static int32_t
sd_profile_create_service_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static char service_name[] = "Bluetooth service discovery";
return (common_profile_create_string8(
buf, eob,
(uint8_t const *) service_name, strlen(service_name)));
}
static int32_t
sd_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (buf + 13 > eob)
return (-1);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(11, buf);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(9, buf);
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
SDP_PUT8(SDP_DATA_UINT16, buf);
SDP_PUT16(NG_L2CAP_PSM_SDP, buf);
SDP_PUT8(SDP_DATA_UINT16, buf);
SDP_PUT16(1, buf); /* version */
return (13);
}
static int32_t
sd_profile_create_browse_group_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (buf + 5 > eob)
return (-1);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(3, buf);
/*
* The top-level browse group ID, called PublicBrowseRoot and
* representing the root of the browsing hierarchy, has the value
* 00001002-0000-1000-8000-00805F9B34FB (UUID16: 0x1002) from the
* Bluetooth Assigned Numbers document
*/
SDP_PUT8(SDP_DATA_UUID16, buf);
SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf);
return (5);
}
static int32_t
sd_profile_create_version_number_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
if (buf + 5 > eob)
return (-1);
SDP_PUT8(SDP_DATA_SEQ8, buf);
SDP_PUT8(3, buf);
/*
* The VersionNumberList is a data element sequence in which each
* element of the sequence is a version number supported by the SDP
* server. A version number is a 16-bit unsigned integer consisting
* of two fields. The higher-order 8 bits contain the major version
* number field and the low-order 8 bits contain the minor version
* number field. The initial version of SDP has a major version of
* 1 and a minor version of 0
*/
SDP_PUT8(SDP_DATA_UINT16, buf);
SDP_PUT16(0x0100, buf);
return (5);
}
static int32_t
sd_profile_create_service_database_state(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
uint32_t change_state = provider_get_change_state();
if (buf + 5 > eob)
return (-1);
SDP_PUT8(SDP_DATA_UINT32, buf);
SDP_PUT32(change_state, buf);
return (5);
}
static attr_t sd_profile_attrs[] = {
{ SDP_ATTR_SERVICE_RECORD_HANDLE,
common_profile_create_service_record_handle },
{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
sd_profile_create_service_class_id_list },
{ SDP_ATTR_SERVICE_ID,
sd_profile_create_service_id },
{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
common_profile_create_language_base_attribute_id_list },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
sd_profile_create_service_name },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET,
sd_profile_create_service_name },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET,
common_profile_create_service_provider_name },
{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
sd_profile_create_protocol_descriptor_list },
{ SDP_ATTR_BROWSE_GROUP_LIST,
sd_profile_create_browse_group_list },
{ SDP_ATTR_VERSION_NUMBER_LIST,
sd_profile_create_version_number_list },
{ SDP_ATTR_SERVICE_DATABASE_STATE,
sd_profile_create_service_database_state },
{ 0, NULL } /* end entry */
};
profile_t sd_profile_descriptor = {
SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER,
0,
(profile_data_valid_p) NULL,
(attr_t const * const) &sd_profile_attrs
};

View file

@ -0,0 +1,136 @@
.\" Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: sdpd.8,v 1.1 2004/01/13 19:31:54 max Exp $
.\" $FreeBSD$
.\"
.Dd January 13, 2004
.Dt SDPD 8
.Os
.Sh NAME
.Nm sdpd
.Nd Bluetooth Service Discovery Protocol daemon
.Sh SYNOPSIS
.Nm
.Op Fl dh
.Op Fl c Ar path
.Op Fl g Ar group
.Op Fl u Ar user
.Sh DESCRIPTION
The
.Nm
daemon keeps track of the Bluetooth services registered on the host
and responds to Service Discovery inquiries from the remote Bluetooth devices.
.Pp
In order to use any service remote Bluetooth device need to send Sevice
Search and Service Attribute or Service Search Attribute request over
Bluetooth L2CAP connection on SDP PSM (0x0001).
The
.Nm
daemon will try to find matching Service Record in its Service Database
and will send appropriate response back.
The remote device then will process the response, extract all required
information and will make a separate connection in order to use the service.
.Pp
Bluetooth applications, running on the host, register services with
the local
.Nm
daemon.
Operation like service registration, service removal and service change are
performed over the control socket.
It is possible to query entire content of the
.Nm
Service Database with
.Xr sdpcontrol 8
by issuing
.Cm browse
command on the control socket.
.Pp
The command line options are as follows:
.Bl -tag -width indent
.It Fl d
Do not detach from the controlling terminal.
.It Fl c Ar path
Specify path to the control socket.
The default path is
.Pa /var/run/sdp .
.It Fl g Ar group
Specifies the group the
.Nm
should run as after it initializes.
The value specified may be either a group name or a numeric group id.
This only works if
.Nm
was started as root.
The default group name is
.Dq nobody .
.It Fl h
Display usage message and exit.
.It Fl u Ar user
Specifies the user the
.Nm
should run as after it initializes.
The value specified may be either a user name or a numeric user id.
This only works if
.Nm
was started as root.
The default user name is
.Dq nobody .
.El
.Sh CAVEAT
The
.Nm
daemon
will listen for incoming L2CAP connections on a wildcard BD_ADDR.
.Pp
In case of multiple Bluetooth devices connected to the same host it is
possible to specify which services should be
.Dq bound
to which Bluetooth device. Such assigment should be done at service
registration time.
.Pp
Access rights on the control socket define which application can register,
remove or change the service.
The application must be able to write to and read from the control socket
in order to perform any query to the Service Database via control socket.
.Pp
The
.Nm
daemon does not checks for duplicated Service Records.
It only performs minimal check on the service data sent in the Service
Register request.
It is assumed that application must obtain all required resources such
as RFCOMM channels etc. before registering the service.
.Sh BUGS
Most likely.
Please report if found.
.Sh FILES
.Bl -tag -width ".Pa /var/run/sdp" -compact
.It Pa /var/run/sdp
.El
.Sh SEE ALSO
.Xr sdp 3 ,
.Xr sdpcontrol 8
.Sh AUTHORS
.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com

View file

@ -0,0 +1,547 @@
/*
* server.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: server.c,v 1.6 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/select.h>
#include <sys/queue.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "log.h"
#include "profile.h"
#include "provider.h"
#include "server.h"
static void server_accept_client (server_p srv, int32_t fd);
static int32_t server_process_request (server_p srv, int32_t fd);
static int32_t server_send_error_response (server_p srv, int32_t fd,
uint16_t error);
static void server_close_fd (server_p srv, int32_t fd);
/*
* Initialize server
*/
int32_t
server_init(server_p srv, char const *control)
{
struct sockaddr_un un;
struct sockaddr_l2cap l2;
int32_t unsock, l2sock, size;
uint16_t imtu;
assert(srv != NULL);
assert(control != NULL);
memset(srv, 0, sizeof(srv));
/* Open control socket */
if (unlink(control) < 0 && errno != ENOENT) {
log_crit("Could not unlink(%s). %s (%d)",
control, strerror(errno), errno);
return (-1);
}
unsock = socket(PF_LOCAL, SOCK_STREAM, 0);
if (unsock < 0) {
log_crit("Could not create control socket. %s (%d)",
strerror(errno), errno);
return (-1);
}
memset(&un, 0, sizeof(un));
un.sun_len = sizeof(un);
un.sun_family = AF_LOCAL;
strlcpy(un.sun_path, control, sizeof(un.sun_path));
if (bind(unsock, (struct sockaddr *) &un, sizeof(un)) < 0) {
log_crit("Could not bind control socket. %s (%d)",
strerror(errno), errno);
close(unsock);
return (-1);
}
if (listen(unsock, 10) < 0) {
log_crit("Could not listen on control socket. %s (%d)",
strerror(errno), errno);
close(unsock);
return (-1);
}
/* Open L2CAP socket */
l2sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
if (l2sock < 0) {
log_crit("Could not create L2CAP socket. %s (%d)",
strerror(errno), errno);
close(unsock);
return (-1);
}
size = sizeof(imtu);
if (getsockopt(l2sock, SOL_L2CAP, SO_L2CAP_IMTU, &imtu, &size) < 0) {
log_crit("Could not get L2CAP IMTU. %s (%d)",
strerror(errno), errno);
close(unsock);
close(l2sock);
return (-1);
}
memset(&l2, 0, sizeof(l2));
l2.l2cap_len = sizeof(l2);
l2.l2cap_family = AF_BLUETOOTH;
memcpy(&l2.l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(l2.l2cap_bdaddr));
l2.l2cap_psm = NG_L2CAP_PSM_SDP;
if (bind(l2sock, (struct sockaddr *) &l2, sizeof(l2)) < 0) {
log_crit("Could not bind L2CAP socket. %s (%d)",
strerror(errno), errno);
close(unsock);
close(l2sock);
return (-1);
}
if (listen(l2sock, 10) < 0) {
log_crit("Could not listen on L2CAP socket. %s (%d)",
strerror(errno), errno);
close(unsock);
close(l2sock);
return (-1);
}
/* Allocate incoming buffer */
srv->imtu = (imtu > SDP_LOCAL_MTU)? imtu : SDP_LOCAL_MTU;
srv->req = (uint8_t *) calloc(srv->imtu, sizeof(srv->req[0]));
if (srv->req == NULL) {
log_crit("Could not allocate request buffer");
close(unsock);
close(l2sock);
return (-1);
}
/* Allocate memory for descriptor index */
srv->fdidx = (fd_idx_p) calloc(FD_SETSIZE, sizeof(srv->fdidx[0]));
if (srv->fdidx == NULL) {
log_crit("Could not allocate fd index");
free(srv->req);
close(unsock);
close(l2sock);
return (-1);
}
/* Register Service Discovery profile (attach it to control socket) */
if (provider_register_sd(unsock) < 0) {
log_crit("Could not register Service Discovery profile");
free(srv->fdidx);
free(srv->req);
close(unsock);
close(l2sock);
return (-1);
}
/*
* If we got here then everything is fine. Add both control sockets
* to the index.
*/
FD_ZERO(&srv->fdset);
srv->maxfd = (unsock > l2sock)? unsock : l2sock;
FD_SET(unsock, &srv->fdset);
srv->fdidx[unsock].valid = 1;
srv->fdidx[unsock].server = 1;
srv->fdidx[unsock].control = 1;
srv->fdidx[unsock].rsp_cs = 0;
srv->fdidx[unsock].rsp_size = 0;
srv->fdidx[unsock].rsp_limit = 0;
srv->fdidx[unsock].omtu = SDP_LOCAL_MTU;
srv->fdidx[unsock].rsp = NULL;
FD_SET(l2sock, &srv->fdset);
srv->fdidx[l2sock].valid = 1;
srv->fdidx[l2sock].server = 1;
srv->fdidx[l2sock].control = 0;
srv->fdidx[l2sock].rsp_cs = 0;
srv->fdidx[l2sock].rsp_size = 0;
srv->fdidx[l2sock].rsp_limit = 0;
srv->fdidx[l2sock].omtu = 0; /* unknown */
srv->fdidx[l2sock].rsp = NULL;
return (0);
}
/*
* Shutdown server
*/
void
server_shutdown(server_p srv)
{
int fd;
assert(srv != NULL);
for (fd = 0; fd < srv->maxfd + 1; fd ++)
if (srv->fdidx[fd].valid)
server_close_fd(srv, fd);
free(srv->req);
free(srv->fdidx);
memset(srv, 0, sizeof(*srv));
}
/*
* Do one server iteration
*/
int32_t
server_do(server_p srv)
{
fd_set fdset;
int32_t n, fd;
assert(srv != NULL);
/* Copy cached version of the fd set and call select */
memcpy(&fdset, &srv->fdset, sizeof(fdset));
n = select(srv->maxfd + 1, &fdset, NULL, NULL, NULL);
if (n < 0) {
if (errno == EINTR)
return (0);
log_err("Could not select(%d, %p). %s (%d)",
srv->maxfd + 1, &fdset, strerror(errno), errno);
return (-1);
}
/* Process descriptors */
for (fd = 0; fd < srv->maxfd + 1 && n > 0; fd ++) {
if (!FD_ISSET(fd, &fdset))
continue;
assert(srv->fdidx[fd].valid);
n --;
if (srv->fdidx[fd].server)
server_accept_client(srv, fd);
else if (server_process_request(srv, fd) != 0)
server_close_fd(srv, fd);
}
return (0);
}
/*
* Accept new client connection and register it with index
*/
static void
server_accept_client(server_p srv, int32_t fd)
{
uint8_t *rsp = NULL;
int32_t cfd, size;
uint16_t omtu;
do {
cfd = accept(fd, NULL, NULL);
} while (cfd < 0 && errno == EINTR);
if (cfd < 0) {
log_err("Could not accept connection on %s socket. %s (%d)",
srv->fdidx[fd].control? "control" : "L2CAP",
strerror(errno), errno);
return;
}
assert(!FD_ISSET(cfd, &srv->fdset));
assert(!srv->fdidx[cfd].valid);
if (!srv->fdidx[fd].control) {
/* Get local BD_ADDR */
size = sizeof(srv->req_sa);
if (getsockname(cfd,(struct sockaddr*)&srv->req_sa,&size) < 0) {
log_err("Could not get local BD_ADDR. %s (%d)",
strerror(errno), errno);
close(cfd);
return;
}
/* Get outgoing MTU */
size = sizeof(omtu);
if (getsockopt(cfd,SOL_L2CAP,SO_L2CAP_OMTU,&omtu,&size) < 0) {
log_err("Could not get L2CAP OMTU. %s (%d)",
strerror(errno), errno);
close(cfd);
return;
}
/*
* The maximum size of the L2CAP packet is 65536 bytes.
* The minimum L2CAP MTU is 43 bytes. That means we need
* 65536 / 43 = ~1524 chunks to transfer maximum packet
* size with minimum MTU. The "rsp_cs" field in fd_idx_t
* is 11 bit wide that gives us upto 2048 chunks.
*/
if (omtu < NG_L2CAP_MTU_MINIMUM) {
log_err("L2CAP OMTU is too small (%d bytes)", omtu);
close(cfd);
return;
}
} else {
memcpy(&srv->req_sa.l2cap_bdaddr, NG_HCI_BDADDR_ANY,
sizeof(srv->req_sa.l2cap_bdaddr));
omtu = srv->fdidx[fd].omtu;
}
/*
* Allocate buffer. This is an overkill, but we can not know how
* big our reply is going to be.
*/
rsp = (uint8_t *) calloc(NG_L2CAP_MTU_MAXIMUM, sizeof(rsp[0]));
if (rsp == NULL) {
log_crit("Could not allocate response buffer");
close(cfd);
return;
}
/* Add client descriptor to the index */
FD_SET(cfd, &srv->fdset);
if (srv->maxfd < cfd)
srv->maxfd = cfd;
srv->fdidx[cfd].valid = 1;
srv->fdidx[cfd].server = 0;
srv->fdidx[cfd].control = srv->fdidx[fd].control;
srv->fdidx[cfd].rsp_cs = 0;
srv->fdidx[cfd].rsp_size = 0;
srv->fdidx[cfd].rsp_limit = 0;
srv->fdidx[cfd].omtu = omtu;
srv->fdidx[cfd].rsp = rsp;
}
/*
* Process request from the client
*/
static int32_t
server_process_request(server_p srv, int32_t fd)
{
sdp_pdu_p pdu = (sdp_pdu_p) srv->req;
int32_t len, error;
assert(srv->imtu > 0);
assert(srv->req != NULL);
assert(FD_ISSET(fd, &srv->fdset));
assert(srv->fdidx[fd].valid);
assert(!srv->fdidx[fd].server);
assert(srv->fdidx[fd].rsp != NULL);
assert(srv->fdidx[fd].omtu >= NG_L2CAP_MTU_MINIMUM);
do {
len = read(fd, srv->req, srv->imtu);
} while (len < 0 && errno == EINTR);
if (len < 0) {
log_err("Could not receive SDP request from %s socket. %s (%d)",
srv->fdidx[fd].control? "control" : "L2CAP",
strerror(errno), errno);
return (-1);
}
if (len == 0) {
log_info("Client on %s socket has disconnected",
srv->fdidx[fd].control? "control" : "L2CAP");
return (-1);
}
if (sizeof(*pdu) + (pdu->len = ntohs(pdu->len)) == len) {
switch (pdu->pid) {
case SDP_PDU_SERVICE_SEARCH_REQUEST:
error = server_prepare_service_search_response(srv, fd);
break;
case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
error = server_prepare_service_attribute_response(srv, fd);
break;
case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
error = server_prepare_service_search_attribute_response(srv, fd);
break;
case SDP_PDU_SERVICE_REGISTER_REQUEST:
error = server_prepare_service_register_response(srv, fd);
break;
case SDP_PDU_SERVICE_UNREGISTER_REQUEST:
error = server_prepare_service_unregister_response(srv, fd);
break;
case SDP_PDU_SERVICE_CHANGE_REQUEST:
error = server_prepare_service_change_response(srv, fd);
break;
default:
error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
break;
}
} else
error = SDP_ERROR_CODE_INVALID_PDU_SIZE;
if (error == 0) {
switch (pdu->pid) {
case SDP_PDU_SERVICE_SEARCH_REQUEST:
error = server_send_service_search_response(srv, fd);
break;
case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
error = server_send_service_attribute_response(srv, fd);
break;
case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
error = server_send_service_search_attribute_response(srv, fd);
break;
case SDP_PDU_SERVICE_REGISTER_REQUEST:
error = server_send_service_register_response(srv, fd);
break;
case SDP_PDU_SERVICE_UNREGISTER_REQUEST:
error = server_send_service_unregister_response(srv, fd);
break;
case SDP_PDU_SERVICE_CHANGE_REQUEST:
error = server_send_service_change_response(srv, fd);
default:
error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
break;
}
if (error != 0)
log_err("Could not send SDP response to %s socket, " \
"pdu->pid=%d, pdu->tid=%d, error=%d",
srv->fdidx[fd].control? "control" : "L2CAP",
pdu->pid, ntohs(pdu->tid), error);
} else {
log_err("Could not process SDP request from %s socket, " \
"pdu->pid=%d, pdu->tid=%d, pdu->len=%d, len=%d, " \
"error=%d",
srv->fdidx[fd].control? "control" : "L2CAP",
pdu->pid, ntohs(pdu->tid), pdu->len, len, error);
error = server_send_error_response(srv, fd, error);
if (error != 0)
log_err("Could not send SDP error response to %s " \
"socket, pdu->pid=%d, pdu->tid=%d, error=%d",
srv->fdidx[fd].control? "control" : "L2CAP",
pdu->pid, ntohs(pdu->tid), error);
}
/* On error forget response (if any) */
if (error != 0) {
srv->fdidx[fd].rsp_cs = 0;
srv->fdidx[fd].rsp_size = 0;
srv->fdidx[fd].rsp_limit = 0;
}
return (error);
}
/*
* Send SDP_Error_Response PDU
*/
static int32_t
server_send_error_response(server_p srv, int32_t fd, uint16_t error)
{
int32_t size;
struct {
sdp_pdu_t pdu;
uint16_t error;
} __attribute__ ((packed)) rsp;
/* Prepare and send SDP error response */
rsp.pdu.pid = SDP_PDU_ERROR_RESPONSE;
rsp.pdu.tid = ((sdp_pdu_p)(srv->req))->tid;
rsp.pdu.len = htons(sizeof(rsp.error));
rsp.error = htons(error);
do {
size = write(fd, &rsp, sizeof(rsp));
} while (size < 0 && errno == EINTR);
return ((size < 0)? errno : 0);
}
/*
* Close descriptor and remove it from index
*/
static void
server_close_fd(server_p srv, int32_t fd)
{
provider_p provider = NULL, provider_next = NULL;
assert(FD_ISSET(fd, &srv->fdset));
assert(srv->fdidx[fd].valid);
close(fd);
FD_CLR(fd, &srv->fdset);
if (fd == srv->maxfd)
srv->maxfd --;
if (srv->fdidx[fd].rsp != NULL)
free(srv->fdidx[fd].rsp);
memset(&srv->fdidx[fd], 0, sizeof(srv->fdidx[fd]));
for (provider = provider_get_first();
provider != NULL;
provider = provider_next) {
provider_next = provider_get_next(provider);
if (provider->fd == fd)
provider_unregister(provider);
}
}

View file

@ -0,0 +1,101 @@
/*
* server.h
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: server.h,v 1.5 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#ifndef _SERVER_H_
#define _SERVER_H_
/*
* File descriptor index entry
*/
struct fd_idx
{
unsigned valid : 1; /* descriptor is valid */
unsigned server : 1; /* descriptor is listening */
unsigned control : 1; /* descriptor is a control socket */
unsigned reserved : 2;
unsigned rsp_cs : 11; /* response continuation state */
uint16_t rsp_size; /* response size */
uint16_t rsp_limit; /* response limit */
uint16_t omtu; /* outgoing MTU */
uint8_t *rsp; /* outgoing buffer */
};
typedef struct fd_idx fd_idx_t;
typedef struct fd_idx * fd_idx_p;
/*
* SDP server
*/
struct server
{
uint32_t imtu; /* incoming MTU */
uint8_t *req; /* incoming buffer */
int32_t maxfd; /* max. descriptor is the set */
fd_set fdset; /* current descriptor set */
fd_idx_p fdidx; /* descriptor index */
struct sockaddr_l2cap req_sa; /* local address */
};
typedef struct server server_t;
typedef struct server * server_p;
/*
* External API
*/
int32_t server_init(server_p srv, const char *control);
void server_shutdown(server_p srv);
int32_t server_do(server_p srv);
int32_t server_prepare_service_search_response(server_p srv, int32_t fd);
int32_t server_send_service_search_response(server_p srv, int32_t fd);
int32_t server_prepare_service_attribute_response(server_p srv, int32_t fd);
int32_t server_send_service_attribute_response(server_p srv, int32_t fd);
int32_t server_prepare_service_search_attribute_response(server_p srv, int32_t fd);
#define server_send_service_search_attribute_response \
server_send_service_attribute_response
int32_t server_prepare_service_register_response(server_p srv, int32_t fd);
int32_t server_send_service_register_response(server_p srv, int32_t fd);
int32_t server_prepare_service_unregister_response(server_p srv, int32_t fd);
#define server_send_service_unregister_response \
server_send_service_register_response
int32_t server_prepare_service_change_response(server_p srv, int32_t fd);
#define server_send_service_change_response \
server_send_service_register_response
#endif /* ndef _SERVER_H_ */

View file

@ -0,0 +1,117 @@
/*
* sp.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sp.c,v 1.5 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
static int32_t
sp_profile_create_service_class_id_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t service_classes[] = {
SDP_SERVICE_CLASS_SERIAL_PORT
};
return (common_profile_create_service_class_id_list(
buf, eob,
(uint8_t const *) service_classes,
sizeof(service_classes)));
}
static int32_t
sp_profile_create_bluetooth_profile_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static uint16_t profile_descriptor_list[] = {
SDP_SERVICE_CLASS_SERIAL_PORT,
0x0100
};
return (common_profile_create_bluetooth_profile_descriptor_list(
buf, eob,
(uint8_t const *) profile_descriptor_list,
sizeof(profile_descriptor_list)));
}
static int32_t
sp_profile_create_service_name(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
static char service_name[] = "Serial Port";
return (common_profile_create_string8(
buf, eob,
(uint8_t const *) service_name, strlen(service_name)));
}
static int32_t
sp_profile_create_protocol_descriptor_list(
uint8_t *buf, uint8_t const * const eob,
uint8_t const *data, uint32_t datalen)
{
provider_p provider = (provider_p) data;
sdp_sp_profile_p sp = (sdp_sp_profile_p) provider->data;
return (rfcomm_profile_create_protocol_descriptor_list(
buf, eob,
(uint8_t const *) &sp->server_channel, 1));
}
static attr_t sp_profile_attrs[] = {
{ SDP_ATTR_SERVICE_RECORD_HANDLE,
common_profile_create_service_record_handle },
{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
sp_profile_create_service_class_id_list },
{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
sp_profile_create_bluetooth_profile_descriptor_list },
{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
common_profile_create_language_base_attribute_id_list },
{ SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET,
sp_profile_create_service_name },
{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
sp_profile_create_protocol_descriptor_list },
{ 0, NULL } /* end entry */
};
profile_t sp_profile_descriptor = {
SDP_SERVICE_CLASS_SERIAL_PORT,
sizeof(sdp_sp_profile_t),
common_profile_server_channel_valid,
(attr_t const * const) &sp_profile_attrs
};

View file

@ -0,0 +1,138 @@
/*
* srr.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: srr.c,v 1.1 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
#include "server.h"
/*
* Prepare Service Register response
*/
int32_t
server_prepare_service_register_response(server_p srv, int32_t fd)
{
uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
uint8_t *rsp = srv->fdidx[fd].rsp;
profile_t *profile = NULL;
provider_t *provider = NULL;
bdaddr_t *bdaddr = NULL;
int32_t uuid;
/*
* Minimal Service Register Request
*
* value16 - uuid 2 bytes
* bdaddr - BD_ADDR 6 bytes
*/
if (!srv->fdidx[fd].control || req_end - req < 8)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Get ServiceClass UUID */
SDP_GET16(uuid, req);
/* Get BD_ADDR */
bdaddr = (bdaddr_p) req;
req += sizeof(*bdaddr);
/* Lookup profile descriptror */
profile = profile_get_descriptor(uuid);
if (profile == NULL)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Validate user data */
if (req_end - req < profile->dsize ||
profile->valid == NULL ||
(profile->valid)(req, req_end - req) == 0)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Register provider */
provider = provider_register(profile, bdaddr, fd, req, req_end - req);
if (provider == NULL)
return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
SDP_PUT16(0, rsp);
SDP_PUT32(provider->handle, rsp);
/* Set reply size */
srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
srv->fdidx[fd].rsp_cs = 0;
return (0);
}
/*
* Send Service Register Response
*/
int32_t
server_send_service_register_response(server_p srv, int32_t fd)
{
struct iovec iov[2];
sdp_pdu_t pdu;
int32_t size;
assert(srv->fdidx[fd].rsp_size < srv->fdidx[fd].rsp_limit);
pdu.pid = SDP_PDU_ERROR_RESPONSE;
pdu.tid = ((sdp_pdu_p)(srv->req))->tid;
pdu.len = htons(srv->fdidx[fd].rsp_size);
iov[0].iov_base = &pdu;
iov[0].iov_len = sizeof(pdu);
iov[1].iov_base = srv->fdidx[fd].rsp;
iov[1].iov_len = srv->fdidx[fd].rsp_size;
do {
size = writev(fd, (struct iovec const *) &iov, sizeof(iov)/sizeof(iov[0]));
} while (size < 0 && errno == EINTR);
srv->fdidx[fd].rsp_cs = 0;
srv->fdidx[fd].rsp_size = 0;
srv->fdidx[fd].rsp_limit = 0;
return ((size < 0)? errno : 0);
}

View file

@ -0,0 +1,225 @@
/*
* ssar.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
#include "server.h"
/* from sar.c */
int32_t server_prepare_attr_list(provider_p const provider,
uint8_t const *req, uint8_t const * const req_end,
uint8_t *rsp, uint8_t const * const rsp_end);
/*
* Prepare SDP Service Search Attribute Response
*/
int32_t
server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
{
uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
uint8_t *rsp = srv->fdidx[fd].rsp;
uint8_t const *rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
uint8_t const *sspptr = NULL, *aidptr = NULL;
uint8_t *ptr = NULL;
provider_t *provider = NULL;
int32_t type, rsp_limit, ssplen, aidlen, cslen, cs, uuid;
/*
* Minimal Service Search Attribute Request request
*
* seq8 len8 - 2 bytes
* uuid16 value16 - 3 bytes ServiceSearchPattern
* value16 - 2 bytes MaximumAttributeByteCount
* seq8 len8 - 2 bytes
* uint16 value16 - 3 bytes AttributeIDList
* value8 - 1 byte ContinuationState
*/
if (req_end - req < 13)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Get size of ServiceSearchPattern */
ssplen = 0;
SDP_GET8(type, req);
switch (type) {
case SDP_DATA_SEQ8:
SDP_GET8(ssplen, req);
break;
case SDP_DATA_SEQ16:
SDP_GET16(ssplen, req);
break;
case SDP_DATA_SEQ32:
SDP_GET32(ssplen, req);
break;
}
if (ssplen <= 0)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
sspptr = req;
req += ssplen;
/* Get MaximumAttributeByteCount */
if (req + 2 > req_end)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET16(rsp_limit, req);
if (rsp_limit <= 0)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Get size of AttributeIDList */
if (req + 1 > req_end)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
aidlen = 0;
SDP_GET8(type, req);
switch (type) {
case SDP_DATA_SEQ8:
if (req + 1 > req_end)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET8(aidlen, req);
break;
case SDP_DATA_SEQ16:
if (req + 2 > req_end)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET16(aidlen, req);
break;
case SDP_DATA_SEQ32:
if (req + 4 > req_end)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET32(aidlen, req);
break;
}
if (aidlen <= 0)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
aidptr = req;
req += aidlen;
/* Get ContinuationState */
if (req + 1 > req_end)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET8(cslen, req);
if (cslen != 0) {
if (cslen != 2 || req_end - req != 2)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET16(cs, req);
} else
cs = 0;
/* Process the request. First, check continuation state */
if (srv->fdidx[fd].rsp_cs != cs)
return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
if (srv->fdidx[fd].rsp_size > 0)
return (0);
/*
* Service Search Attribute Response format
*
* value16 - 2 bytes AttributeListByteCount (not incl.)
* seq8 len16 - 3 bytes
* attr list - 3+ bytes AttributeLists
* [ attr list ]
*/
ptr = rsp + 3;
while (ssplen > 0) {
SDP_GET8(type, sspptr);
ssplen --;
switch (type) {
case SDP_DATA_UUID16:
if (ssplen < 2)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET16(uuid, sspptr);
ssplen -= 2;
break;
case SDP_DATA_UUID32: /* XXX FIXME */
case SDP_DATA_UUID128: /* XXX FIXME */
default:
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* NOT REACHED */
}
for (provider = provider_get_first();
provider != NULL;
provider = provider_get_next(provider)) {
if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
continue;
if (provider->profile->uuid != uuid &&
SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP != uuid)
continue;
cs = server_prepare_attr_list(provider,
aidptr, aidptr + aidlen, ptr, rsp_end);
if (cs < 0)
return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
ptr += cs;
}
}
/* Set reply size (not counting PDU header and continuation state) */
srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
if (srv->fdidx[fd].rsp_limit > rsp_limit)
srv->fdidx[fd].rsp_limit = rsp_limit;
srv->fdidx[fd].rsp_size = ptr - rsp;
srv->fdidx[fd].rsp_cs = 0;
/* Fix AttributeLists sequence header */
ptr = rsp;
SDP_PUT8(SDP_DATA_SEQ16, ptr);
SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
return (0);
}

View file

@ -0,0 +1,252 @@
/*
* ssr.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ssr.c,v 1.5 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
#include "server.h"
/*
* Prepare SDP Service Search Response
*/
int32_t
server_prepare_service_search_response(server_p srv, int32_t fd)
{
uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
uint8_t *rsp = srv->fdidx[fd].rsp;
uint8_t const *rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
uint8_t *ptr = NULL;
provider_t *provider = NULL;
int32_t type, ssplen, rsp_limit, rcount, cslen, cs, uuid;
/*
* Minimal SDP Service Search Request
*
* seq8 len8 - 2 bytes
* uuid16 value16 - 3 bytes ServiceSearchPattern
* value16 - 2 bytes MaximumServiceRecordCount
* value8 - 1 byte ContinuationState
*/
if (req_end - req < 8)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Get size of ServiceSearchPattern */
ssplen = 0;
SDP_GET8(type, req);
switch (type) {
case SDP_DATA_SEQ8:
SDP_GET8(ssplen, req);
break;
case SDP_DATA_SEQ16:
SDP_GET16(ssplen, req);
break;
case SDP_DATA_SEQ32:
SDP_GET32(ssplen, req);
break;
}
if (ssplen <= 0)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
ptr = (uint8_t *) req + ssplen;
/* Get MaximumServiceRecordCount */
if (ptr + 2 > req_end)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET16(rsp_limit, ptr);
if (rsp_limit <= 0)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Get ContinuationState */
if (ptr + 1 > req_end)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET8(cslen, ptr);
if (cslen != 0) {
if (cslen != 2 || req_end - ptr != 2)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET16(cs, ptr);
} else
cs = 0;
/* Process the request. First, check continuation state */
if (srv->fdidx[fd].rsp_cs != cs)
return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
if (srv->fdidx[fd].rsp_size > 0)
return (0);
/*
* Service Search Response format
*
* value16 - 2 bytes TotalServiceRecordCount (not incl.)
* value16 - 2 bytes CurrentServiceRecordCount (not incl.)
* value32 - 4 bytes handle
* [ value32 ]
*
* Calculate how many record handles we can fit
* in our reply buffer and adjust rlimit.
*/
ptr = rsp;
rcount = (rsp_end - ptr) / 4;
if (rcount < rsp_limit)
rsp_limit = rcount;
/* Look for the record handles */
for (rcount = 0; ssplen > 0 && rcount < rsp_limit; ) {
SDP_GET8(type, req);
ssplen --;
switch (type) {
case SDP_DATA_UUID16:
if (ssplen < 2)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
SDP_GET16(uuid, req);
ssplen -= 2;
break;
case SDP_DATA_UUID32: /* XXX FIXME */
case SDP_DATA_UUID128: /* XXX FIXME */
default:
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* NOT REACHED */
}
for (provider = provider_get_first();
provider != NULL && rcount < rsp_limit;
provider = provider_get_next(provider)) {
if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
continue;
if (provider->profile->uuid == uuid ||
SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP == uuid) {
SDP_PUT32(provider->handle, ptr);
rcount ++;
}
}
}
/* Set reply size (not counting PDU header and continuation state) */
srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 4;
srv->fdidx[fd].rsp_size = ptr - rsp;
srv->fdidx[fd].rsp_cs = 0;
return (0);
}
/*
* Send SDP Service Search Response
*/
int32_t
server_send_service_search_response(server_p srv, int32_t fd)
{
uint8_t *rsp = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_cs;
uint8_t *rsp_end = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_size;
struct iovec iov[4];
sdp_pdu_t pdu;
uint16_t rcounts[2];
uint8_t cs[3];
int32_t size;
/* First update continuation state (assume we will send all data) */
size = rsp_end - rsp;
srv->fdidx[fd].rsp_cs += size;
if (size + 1 > srv->fdidx[fd].rsp_limit) {
/*
* We need to split out response. Add 3 more bytes for the
* continuation state and move rsp_end and rsp_cs backwards.
*/
while ((rsp_end - rsp) + 3 > srv->fdidx[fd].rsp_limit) {
rsp_end -= 4;
srv->fdidx[fd].rsp_cs -= 4;
}
cs[0] = 2;
cs[1] = srv->fdidx[fd].rsp_cs >> 8;
cs[2] = srv->fdidx[fd].rsp_cs & 0xff;
} else
cs[0] = 0;
assert(rsp_end >= rsp);
rcounts[0] = srv->fdidx[fd].rsp_size / 4; /* TotalServiceRecordCount */
rcounts[1] = (rsp_end - rsp) / 4; /* CurrentServiceRecordCount */
pdu.pid = SDP_PDU_SERVICE_SEARCH_RESPONSE;
pdu.tid = ((sdp_pdu_p)(srv->req))->tid;
pdu.len = htons(sizeof(rcounts) + rcounts[1] * 4 + 1 + cs[0]);
iov[0].iov_base = &pdu;
iov[0].iov_len = sizeof(pdu);
iov[1].iov_base = rcounts;
iov[1].iov_len = sizeof(rcounts);
iov[2].iov_base = rsp;
iov[2].iov_len = rsp_end - rsp;
iov[3].iov_base = cs;
iov[3].iov_len = 1 + cs[0];
do {
size = writev(fd, (struct iovec const *) &iov, sizeof(iov)/sizeof(iov[0]));
} while (size < 0 && errno == EINTR);
/* Check if we have sent (or failed to sent) last response chunk */
if (srv->fdidx[fd].rsp_cs == srv->fdidx[fd].rsp_size) {
srv->fdidx[fd].rsp_cs = 0;
srv->fdidx[fd].rsp_size = 0;
srv->fdidx[fd].rsp_limit = 0;
}
return ((size < 0)? errno : 0);
}

View file

@ -0,0 +1,82 @@
/*
* sur.c
*
* Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sur.c,v 1.1 2004/01/13 01:54:39 max Exp $
* $FreeBSD$
*/
#include <sys/queue.h>
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
#include <string.h>
#include "profile.h"
#include "provider.h"
#include "server.h"
/*
* Prepare Service Unregister response
*/
int32_t
server_prepare_service_unregister_response(server_p srv, int32_t fd)
{
uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
uint8_t *rsp = srv->fdidx[fd].rsp;
provider_t *provider = NULL;
uint32_t handle;
/*
* Minimal Service Unregister Request
*
* value32 - uuid 4 bytes
*/
if (!srv->fdidx[fd].control || req_end - req < 4)
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
/* Get handle */
SDP_GET32(handle, req);
/* Lookup provider */
provider = provider_by_handle(handle);
if (provider == NULL || provider->fd != fd)
return (SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE);
provider_unregister(provider);
SDP_PUT16(0, rsp);
/* Set reply size */
srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t);
srv->fdidx[fd].rsp_size = rsp - srv->fdidx[fd].rsp;
srv->fdidx[fd].rsp_cs = 0;
return (0);
}