NetBSD/usr.sbin/sdpd/compat.c

891 lines
27 KiB
C

/* $NetBSD: compat.c,v 1.2 2010/03/07 10:58:40 plunky Exp $ */
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Iain Hibbert.
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: compat.c,v 1.2 2010/03/07 10:58:40 plunky Exp $");
#include <arpa/inet.h>
#include <netbt/rfcomm.h>
#include <bluetooth.h>
#include <errno.h>
#include <sdp.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "sdpd.h"
/*
* This file provides for compatibility with the old ABI. Clients send
* a data structure and we generate a record based from that using the
* server output buffer as temporary storage. The sdp_put functions will
* not write invalid data or overflow the buffer which is big enough to
* contain all these records, no need to worry about that.
*/
static bool
dun_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_dun_profile_t *data = arg;
uint8_t *first = buf->next;
if (len != sizeof(*data)
|| data->server_channel < RFCOMM_CHANNEL_MIN
|| data->server_channel > RFCOMM_CHANNEL_MAX)
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_DIALUP_NETWORKING);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 12);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_seq(buf, 5);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
sdp_put_uint8(buf, data->server_channel);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_DIALUP_NETWORKING);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "Dialup Networking", -1);
sdp_put_uint16(buf, SDP_ATTR_AUDIO_FEEDBACK_SUPPORT);
sdp_put_bool(buf, data->audio_feedback_support);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
ftrn_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_ftrn_profile_t *data = arg;
uint8_t *first = buf->next;
if (len != sizeof(*data)
|| data->server_channel < RFCOMM_CHANNEL_MIN
|| data->server_channel > RFCOMM_CHANNEL_MAX)
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 17);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_seq(buf, 5);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
sdp_put_uint8(buf, data->server_channel);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_OBEX);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "OBEX File Transfer", -1);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
hset_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_hset_profile_t *data = arg;
uint8_t *first = buf->next;
if (len != sizeof(*data)
|| data->server_channel < RFCOMM_CHANNEL_MIN
|| data->server_channel > RFCOMM_CHANNEL_MAX)
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_GENERIC_AUDIO);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 12);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_seq(buf, 5);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
sdp_put_uint8(buf, data->server_channel);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_HEADSET);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "Voice Gateway", -1);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
hf_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_hf_profile_t *data = arg;
uint8_t *first = buf->next;
if (len != sizeof(*data)
|| data->server_channel < RFCOMM_CHANNEL_MIN
|| data->server_channel > RFCOMM_CHANNEL_MAX
|| (data->supported_features & ~0x001f))
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_HANDSFREE);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_GENERIC_AUDIO);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 12);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_seq(buf, 5);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
sdp_put_uint8(buf, data->server_channel);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_HANDSFREE);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "Hands-Free unit", -1);
sdp_put_uint16(buf, SDP_ATTR_SUPPORTED_FEATURES);
sdp_put_uint16(buf, data->supported_features);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
irmc_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_irmc_profile_t *data = arg;
uint8_t *first = buf->next;
int i;
if (len != sizeof(*data)
|| data->server_channel < RFCOMM_CHANNEL_MIN
|| data->server_channel > RFCOMM_CHANNEL_MAX
|| data->supported_formats_size == 0
|| data->supported_formats_size > sizeof(data->supported_formats))
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_IR_MC_SYNC);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 17);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_seq(buf, 5);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
sdp_put_uint8(buf, data->server_channel);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_OBEX);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_IR_MC_SYNC);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "IrMC Syncrhonization", -1);
sdp_put_uint16(buf, SDP_ATTR_SUPPORTED_DATA_STORES_LIST);
sdp_put_seq(buf, data->supported_formats_size * 2);
for (i = 0; i < data->supported_formats_size; i++)
sdp_put_uint8(buf, data->supported_formats[i]);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
irmc_cmd_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_irmc_command_profile_t *data = arg;
uint8_t *first = buf->next;
if (len != sizeof(*data)
|| data->server_channel < RFCOMM_CHANNEL_MIN
|| data->server_channel > RFCOMM_CHANNEL_MAX)
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 17);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_seq(buf, 5);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
sdp_put_uint8(buf, data->server_channel);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_OBEX);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "Sync Command Service", -1);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
lan_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_lan_profile_t *data = arg;
uint8_t *first = buf->next;
struct in_addr in;
char str[32];
if (len != sizeof(*data)
|| data->server_channel < RFCOMM_CHANNEL_MIN
|| data->server_channel > RFCOMM_CHANNEL_MAX
|| data->ip_subnet_radius > 32)
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 12);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_seq(buf, 5);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
sdp_put_uint8(buf, data->server_channel);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_AVAILABILITY);
sdp_put_uint8(buf, data->load_factor);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "LAN Access using PPP", -1);
in.s_addr= data->ip_subnet;
sprintf(str, "%s/%d", inet_ntoa(in), data->ip_subnet_radius);
sdp_put_uint16(buf, SDP_ATTR_IP_SUBNET);
sdp_put_str(buf, str, -1);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
opush_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_opush_profile_t *data = arg;
uint8_t *first = buf->next;
int i;
if (len != sizeof(*data)
|| data->server_channel < RFCOMM_CHANNEL_MIN
|| data->server_channel > RFCOMM_CHANNEL_MAX
|| data->supported_formats_size == 0
|| data->supported_formats_size > sizeof(data->supported_formats))
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 17);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_seq(buf, 5);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
sdp_put_uint8(buf, data->server_channel);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_OBEX);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "OBEX Object Push", -1);
sdp_put_uint16(buf, SDP_ATTR_SUPPORTED_FORMATS_LIST);
sdp_put_seq(buf, data->supported_formats_size * 2);
for (i = 0; i < data->supported_formats_size; i++)
sdp_put_uint8(buf, data->supported_formats[i]);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
sp_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_sp_profile_t *data = arg;
uint8_t *first = buf->next;
if (len != sizeof(*data)
|| data->server_channel < RFCOMM_CHANNEL_MIN
|| data->server_channel > RFCOMM_CHANNEL_MAX)
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_SERIAL_PORT);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 12);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_seq(buf, 5);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_RFCOMM);
sdp_put_uint8(buf, data->server_channel);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_SERIAL_PORT);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "Serial Port", -1);
buf->end = buf->next;
buf->next = first;
return true;
}
/* list of protocols used by PAN profiles. */
static const uint16_t proto[] = {
0x0800, /* IPv4 */
0x0806, /* ARP */
#ifdef INET6
0x86dd, /* IPv6 */
#endif
};
static bool
nap_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_nap_profile_t *data = arg;
uint8_t *first = buf->next;
size_t i;
if (len != sizeof(*data)
|| L2CAP_PSM_INVALID(data->psm)
|| data->security_description > 0x0002)
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_NAP);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 18 + 3 * __arraycount(proto));
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_uint16(buf, data->psm);
sdp_put_seq(buf, 8 + 3 * __arraycount(proto));
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_BNEP);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_seq(buf, 3 * __arraycount(proto));
for (i = 0; i < __arraycount(proto); i++)
sdp_put_uint16(buf, proto[i]);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_AVAILABILITY);
sdp_put_uint8(buf, data->load_factor);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_NAP);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "Network Access Point", -1);
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET);
sdp_put_str(buf, "Personal Ad-hoc Network Service", -1);
sdp_put_uint16(buf, SDP_ATTR_SECURITY_DESCRIPTION);
sdp_put_uint16(buf, data->security_description);
sdp_put_uint16(buf, SDP_ATTR_NET_ACCESS_TYPE);
sdp_put_uint16(buf, data->net_access_type);
sdp_put_uint16(buf, SDP_ATTR_MAX_NET_ACCESS_RATE);
sdp_put_uint32(buf, data->max_net_access_rate);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
gn_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_gn_profile_t *data = arg;
uint8_t *first = buf->next;
size_t i;
if (len != sizeof(*data)
|| L2CAP_PSM_INVALID(data->psm)
|| data->security_description > 0x0002)
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_GN);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 18 + 3 * __arraycount(proto));
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_uint16(buf, data->psm);
sdp_put_seq(buf, 8 + 3 * __arraycount(proto));
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_BNEP);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_seq(buf, 3 * __arraycount(proto));
for (i = 0; i < __arraycount(proto); i++)
sdp_put_uint16(buf, proto[i]);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_AVAILABILITY);
sdp_put_uint8(buf, data->load_factor);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_GN);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "Group Ad-hoc Network", -1);
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET);
sdp_put_str(buf, "Personal Group Ad-hoc Network Service", -1);
sdp_put_uint16(buf, SDP_ATTR_SECURITY_DESCRIPTION);
sdp_put_uint16(buf, data->security_description);
buf->end = buf->next;
buf->next = first;
return true;
}
static bool
panu_profile(sdp_data_t *buf, void *arg, ssize_t len)
{
sdp_panu_profile_t *data = arg;
uint8_t *first = buf->next;
size_t i;
if (len != sizeof(*data)
|| L2CAP_PSM_INVALID(data->psm)
|| data->security_description > 0x0002)
return false;
sdp_put_uint16(buf, SDP_ATTR_SERVICE_RECORD_HANDLE);
sdp_put_uint32(buf, 0x00000000);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_CLASS_ID_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PANU);
sdp_put_uint16(buf, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
sdp_put_seq(buf, 18 + 3 * __arraycount(proto));
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_L2CAP);
sdp_put_uint16(buf, data->psm);
sdp_put_seq(buf, 8 + 3 * __arraycount(proto));
sdp_put_uuid16(buf, SDP_UUID_PROTOCOL_BNEP);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_seq(buf, 3 * __arraycount(proto));
for (i = 0; i < __arraycount(proto); i++)
sdp_put_uint16(buf, proto[i]);
sdp_put_uint16(buf, SDP_ATTR_BROWSE_GROUP_LIST);
sdp_put_seq(buf, 3);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
sdp_put_uint16(buf, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
sdp_put_seq(buf, 9);
sdp_put_uint16(buf, 0x656e); /* "en" */
sdp_put_uint16(buf, 106); /* UTF-8 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
sdp_put_uint16(buf, SDP_ATTR_SERVICE_AVAILABILITY);
sdp_put_uint8(buf, data->load_factor);
sdp_put_uint16(buf, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
sdp_put_seq(buf, 8);
sdp_put_seq(buf, 6);
sdp_put_uuid16(buf, SDP_SERVICE_CLASS_PANU);
sdp_put_uint16(buf, 0x0100); /* v1.0 */
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET);
sdp_put_str(buf, "Personal Ad-hoc User Service", -1);
sdp_put_uint16(buf, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_DESCRIPTION_OFFSET);
sdp_put_str(buf, "Personal Ad-hoc User Service", -1);
sdp_put_uint16(buf, SDP_ATTR_SECURITY_DESCRIPTION);
sdp_put_uint16(buf, data->security_description);
buf->end = buf->next;
buf->next = first;
return true;
}
static const struct {
uint16_t class;
bool (*create)(sdp_data_t *, void *, ssize_t);
} known[] = {
{ SDP_SERVICE_CLASS_DIALUP_NETWORKING, dun_profile },
{ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER, ftrn_profile },
{ SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY, hset_profile },
{ SDP_SERVICE_CLASS_HANDSFREE, hf_profile },
{ SDP_SERVICE_CLASS_IR_MC_SYNC, irmc_profile },
{ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND, irmc_cmd_profile },
{ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP, lan_profile },
{ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH, opush_profile },
{ SDP_SERVICE_CLASS_SERIAL_PORT, sp_profile },
{ SDP_SERVICE_CLASS_NAP, nap_profile },
{ SDP_SERVICE_CLASS_GN, gn_profile },
{ SDP_SERVICE_CLASS_PANU, panu_profile },
};
uint16_t
compat_register_request(server_t *srv, int fd)
{
sdp_data_t d, r;
bdaddr_t bdaddr;
uint16_t class;
int i;
log_debug("compat RegisterRequest by client on fd#%d", fd);
if (!srv->fdidx[fd].control
|| !srv->fdidx[fd].priv)
return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
srv->fdidx[fd].offset = 0;
db_unselect(srv, fd);
d.next = srv->ibuf;
d.end = srv->ibuf + srv->pdu.len;
if (d.next + sizeof(uint16_t) + sizeof(bdaddr_t) > d.end)
return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
class = be16dec(d.next);
d.next += sizeof(uint16_t);
memcpy(&bdaddr, d.next, sizeof(bdaddr_t));
d.next += sizeof(bdaddr_t);
for (i = 0;; i++) {
if (i == __arraycount(known))
return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
if (known[i].class == class)
break;
}
r.next = srv->obuf;
r.end = srv->obuf + srv->omtu;
if (!(known[i].create(&r, d.next, d.end - d.next)))
return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
if (!db_create(srv, fd, &bdaddr, srv->handle, &r))
return SDP_ERROR_CODE_INSUFFICIENT_RESOURCES;
/* successful return */
be16enc(srv->obuf, 0x0000);
be32enc(srv->obuf + sizeof(uint16_t), srv->handle++);
srv->pdu.pid = SDP_PDU_ERROR_RESPONSE;
srv->pdu.len = sizeof(uint16_t) + sizeof(uint32_t);
return 0;
}
uint16_t
compat_change_request(server_t *srv, int fd)
{
record_t *rec;
sdp_data_t d, r;
int i;
log_debug("compat ChangeRequest by client on fd#%d", fd);
if (!srv->fdidx[fd].control
|| !srv->fdidx[fd].priv)
return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
srv->fdidx[fd].offset = 0;
db_unselect(srv, fd);
d.next = srv->ibuf;
d.end = srv->ibuf + srv->pdu.len;
if (d.next + sizeof(uint32_t) > d.end)
return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
db_select_handle(srv, fd, be32dec(d.next));
d.next += sizeof(uint32_t);
rec = NULL;
db_next(srv, fd, &rec);
if (rec == NULL || rec->fd != fd)
return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
/*
* This is rather simplistic but it works. We don't keep a
* record of the ServiceClass but we do know the format of
* of the stored record and where it should be. If we dont
* find it there, just give up.
*/
r = rec->data;
r.next += 3; /* uint16 ServiceRecordHandle */
r.next += 5; /* uint32 %handle% */
r.next += 3; /* uint16 ServiceClassIDList */
r.next += 2; /* seq8 */
for (i = 0;; i++) {
if (i == __arraycount(known))
return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
if (sdp_match_uuid16(&r, known[i].class))
break;
}
r.next = srv->obuf;
r.end = srv->obuf + srv->omtu;
if (!(known[i].create(&r, d.next, d.end - d.next)))
return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
if (!db_create(srv, fd, &rec->bdaddr, rec->handle, &r))
return SDP_ERROR_CODE_INSUFFICIENT_RESOURCES;
db_unselect(srv, fd);
/* successful return */
be16enc(srv->obuf, 0x0000);
srv->pdu.pid = SDP_PDU_ERROR_RESPONSE;
srv->pdu.len = sizeof(uint16_t);
return 0;
}