rfcomm_sdp.c revision 128077
1184054Slulf/* 2186743Slulf * rfcomm_sdp.c 3184054Slulf * 4184054Slulf * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5184054Slulf * All rights reserved. 6184054Slulf * 7184054Slulf * Redistribution and use in source and binary forms, with or without 8184054Slulf * modification, are permitted provided that the following conditions 9184054Slulf * are met: 10184054Slulf * 1. Redistributions of source code must retain the above copyright 11184054Slulf * notice, this list of conditions and the following disclaimer. 12184054Slulf * 2. Redistributions in binary form must reproduce the above copyright 13184054Slulf * notice, this list of conditions and the following disclaimer in the 14184054Slulf * documentation and/or other materials provided with the distribution. 15184054Slulf * 16184054Slulf * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184054Slulf * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184054Slulf * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184054Slulf * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184054Slulf * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184054Slulf * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184054Slulf * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184054Slulf * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184054Slulf * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184054Slulf * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26184054Slulf * SUCH DAMAGE. 27184054Slulf * 28184054Slulf * $Id: rfcomm_sdp.c,v 1.1 2003/09/07 18:15:55 max Exp $ 29184054Slulf * $FreeBSD: head/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c 128077 2004-04-09 23:26:16Z emax $ 30185134Slulf */ 31185134Slulf 32184054Slulf#include <bluetooth.h> 33184054Slulf#include <errno.h> 34184054Slulf#include <sdp.h> 35185134Slulf#include <stdio.h> 36184054Slulf 37185134Slulf#undef PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 38184054Slulf#define PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 256 39185134Slulf 40185134Slulf#undef PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 41184054Slulf#define PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 12 42184054Slulf 43184054Slulfstatic int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end, 44184054Slulf int *channel, int *error); 45185134Slulf 46185134Slulf/* 47184054Slulf * Lookup RFCOMM channel number in the Protocol Descriptor List 48184054Slulf */ 49184054Slulf 50184054Slulf#undef rfcomm_channel_lookup_exit 51184054Slulf#define rfcomm_channel_lookup_exit(e) { \ 52184054Slulf if (error != NULL) \ 53184054Slulf *error = (e); \ 54184054Slulf if (ss != NULL) { \ 55184054Slulf sdp_close(ss); \ 56184054Slulf ss = NULL; \ 57184054Slulf } \ 58184054Slulf return (((e) == 0)? 0 : -1); \ 59184054Slulf} 60184054Slulf 61184054Slulfint 62184054Slulfrfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote, 63184054Slulf int service, int *channel, int *error) 64184054Slulf{ 65184054Slulf uint8_t buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE]; 66184054Slulf void *ss = NULL; 67184054Slulf uint16_t serv = (uint16_t) service; 68184054Slulf uint32_t attr = SDP_ATTR_RANGE( 69184054Slulf SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 70184054Slulf SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST); 71184054Slulf sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer }; 72184054Slulf uint32_t type, len; 73184054Slulf 74184054Slulf if (local == NULL) 75184054Slulf local = NG_HCI_BDADDR_ANY; 76184054Slulf if (remote == NULL || channel == NULL) 77184054Slulf rfcomm_channel_lookup_exit(EINVAL); 78184054Slulf 79184054Slulf if ((ss = sdp_open(local, remote)) == NULL) 80184054Slulf rfcomm_channel_lookup_exit(ENOMEM); 81184054Slulf if (sdp_error(ss) != 0) 82184054Slulf rfcomm_channel_lookup_exit(sdp_error(ss)); 83184054Slulf 84184054Slulf if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0) 85184054Slulf rfcomm_channel_lookup_exit(sdp_error(ss)); 86184054Slulf if (proto.flags != SDP_ATTR_OK) 87184054Slulf rfcomm_channel_lookup_exit(ENOATTR); 88184054Slulf 89184054Slulf sdp_close(ss); 90184054Slulf ss = NULL; 91184054Slulf 92186727Slulf /* 93184054Slulf * If it is possible for more than one kind of protocol stack to be 94184054Slulf * used to gain access to the service, the ProtocolDescriptorList 95184054Slulf * takes the form of a data element alternative. We always use the 96184054Slulf * first protocol stack. 97184054Slulf * 98184054Slulf * A minimal Protocol Descriptor List for RFCOMM based service would 99184054Slulf * look like 100184054Slulf * 101184054Slulf * seq8 len8 - 2 bytes 102184054Slulf * seq8 len8 - 2 bytes 103186727Slulf * uuid16 value16 - 3 bytes L2CAP 104184054Slulf * seq8 len8 - 2 bytes 105184054Slulf * uuid16 value16 - 3 bytes RFCOMM 106184054Slulf * uint8 value8 - 2 bytes RFCOMM param #1 107184054Slulf * ========= 108184054Slulf * 14 bytes 109184054Slulf * 110184054Slulf * Lets not count first [seq8 len8] wrapper, so the minimal size of 111184054Slulf * the Protocol Descriptor List (the data we are actually interested 112184054Slulf * in) for RFCOMM based service would be 12 bytes. 113184054Slulf */ 114184054Slulf 115184054Slulf if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) 116184054Slulf rfcomm_channel_lookup_exit(EINVAL); 117184054Slulf 118184054Slulf SDP_GET8(type, proto.value); 119184054Slulf 120184054Slulf if (type == SDP_DATA_ALT8) { 121184054Slulf SDP_GET8(len, proto.value); 122186700Slulf } else if (type == SDP_DATA_ALT16) { 123184054Slulf SDP_GET16(len, proto.value); 124184054Slulf } else if (type == SDP_DATA_ALT32) { 125184054Slulf SDP_GET32(len, proto.value); 126184054Slulf } else 127184054Slulf len = 0; 128184054Slulf 129184054Slulf if (len > 0) 130184054Slulf SDP_GET8(type, proto.value); 131184054Slulf 132184054Slulf switch (type) { 133184054Slulf case SDP_DATA_SEQ8: 134184054Slulf SDP_GET8(len, proto.value); 135184054Slulf break; 136184054Slulf 137184054Slulf case SDP_DATA_SEQ16: 138184054Slulf SDP_GET16(len, proto.value); 139184054Slulf break; 140184054Slulf 141184054Slulf case SDP_DATA_SEQ32: 142184054Slulf SDP_GET32(len, proto.value); 143190422Slulf break; 144186727Slulf 145184054Slulf default: 146184054Slulf rfcomm_channel_lookup_exit(ENOATTR); 147184054Slulf /* NOT REACHED */ 148184054Slulf } 149184054Slulf 150184054Slulf if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) 151184054Slulf rfcomm_channel_lookup_exit(EINVAL); 152184054Slulf 153184054Slulf return (rfcomm_proto_list_parse(proto.value, 154184054Slulf buffer + proto.vlen, channel, error)); 155184054Slulf} 156186700Slulf 157184054Slulf/* 158184054Slulf * Parse protocol descriptor list 159184054Slulf * 160184054Slulf * The ProtocolDescriptorList attribute describes one or more protocol 161184054Slulf * stacks that may be used to gain access to the service described by 162184054Slulf * the service record. If the ProtocolDescriptorList describes a single 163184054Slulf * stack, it takes the form of a data element sequence in which each 164184054Slulf * element of the sequence is a protocol descriptor. 165184054Slulf */ 166184054Slulf 167184054Slulf#undef rfcomm_proto_list_parse_exit 168185134Slulf#define rfcomm_proto_list_parse_exit(e) { \ 169184054Slulf if (error != NULL) \ 170184054Slulf *error = (e); \ 171185134Slulf return (((e) == 0)? 0 : -1); \ 172184054Slulf} 173184054Slulf 174184054Slulfstatic int 175184054Slulfrfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end, 176184054Slulf int *channel, int *error) 177184054Slulf{ 178186700Slulf int type, len, value; 179184054Slulf 180185134Slulf while (start < end) { 181184054Slulf 182184054Slulf /* 183184054Slulf * Parse protocol descriptor 184184054Slulf * 185184054Slulf * A protocol descriptor identifies a communications protocol 186184054Slulf * and provides protocol specific parameters. A protocol 187184054Slulf * descriptor is represented as a data element sequence. The 188184054Slulf * first data element in the sequence must be the UUID that 189184054Slulf * identifies the protocol. Additional data elements optionally 190184054Slulf * provide protocol specific information, such as the L2CAP 191184054Slulf * protocol/service multiplexer (PSM) and the RFCOMM server 192184054Slulf * channel number (CN). 193184054Slulf */ 194185134Slulf 195184054Slulf /* We must have at least one byte (type) */ 196184054Slulf if (end - start < 1) 197184054Slulf rfcomm_proto_list_parse_exit(EINVAL) 198184054Slulf 199184054Slulf SDP_GET8(type, start); 200184054Slulf switch (type) { 201184054Slulf case SDP_DATA_SEQ8: 202184054Slulf SDP_GET8(len, start); 203184054Slulf break; 204184054Slulf 205184054Slulf case SDP_DATA_SEQ16: 206184054Slulf SDP_GET16(len, start); 207184054Slulf break; 208185592Slulf 209184054Slulf case SDP_DATA_SEQ32: 210186700Slulf SDP_GET32(len, start); 211184054Slulf break; 212184054Slulf 213184054Slulf default: 214184054Slulf rfcomm_proto_list_parse_exit(ENOATTR) 215184054Slulf /* NOT REACHED */ 216184054Slulf } 217184054Slulf 218186700Slulf /* We must have at least 3 bytes (type + UUID16) */ 219184054Slulf if (end - start < 3) 220184054Slulf rfcomm_proto_list_parse_exit(EINVAL); 221184054Slulf 222184054Slulf /* Get protocol UUID */ 223184054Slulf SDP_GET8(type, start); len -= sizeof(uint8_t); 224184054Slulf switch (type) { 225184054Slulf case SDP_DATA_UUID16: 226184054Slulf SDP_GET16(value, start); len -= sizeof(uint16_t); 227184054Slulf if (value != SDP_UUID_PROTOCOL_RFCOMM) 228184054Slulf goto next_protocol; 229184054Slulf break; 230184054Slulf 231184054Slulf case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 232184054Slulf case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 233184054Slulf default: 234184054Slulf rfcomm_proto_list_parse_exit(ENOATTR); 235184054Slulf /* NOT REACHED */ 236184054Slulf } 237185811Slulf 238184054Slulf /* 239184054Slulf * First protocol specific parameter for RFCOMM procotol must 240184054Slulf * be uint8 that represents RFCOMM channel number. So we must 241184054Slulf * have at least two bytes. 242184054Slulf */ 243184054Slulf 244184054Slulf if (end - start < 2) 245184054Slulf rfcomm_proto_list_parse_exit(EINVAL); 246184054Slulf 247184054Slulf SDP_GET8(type, start); 248184054Slulf if (type != SDP_DATA_UINT8) 249184054Slulf rfcomm_proto_list_parse_exit(ENOATTR); 250184054Slulf 251184054Slulf SDP_GET8(*channel, start); 252184054Slulf 253184054Slulf rfcomm_proto_list_parse_exit(0); 254184054Slulf /* NOT REACHED */ 255184054Slulfnext_protocol: 256184054Slulf start += len; 257184054Slulf } 258184054Slulf 259184054Slulf /* 260184054Slulf * If we got here then it means we could not find RFCOMM protocol 261184054Slulf * descriptor, but the reply format was actually valid. 262184054Slulf */ 263184054Slulf 264184054Slulf rfcomm_proto_list_parse_exit(ENOATTR); 265184054Slulf} 266184054Slulf 267184054Slulf