1 /* 2 * rfcomm_sdp.c 3 * 4 * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: rfcomm_sdp.c,v 1.1 2003/09/07 18:15:55 max Exp $ 29 * $FreeBSD$ 30 */ 31 32 #include <bluetooth.h> 33 #include <errno.h> 34 #include <sdp.h> 35 #include <stdio.h> 36 37 #undef PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 38 #define PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 256 39 40 #undef PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 41 #define PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 12 42 43 static int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end, 44 int *channel, int *error); 45 46 /* 47 * Lookup RFCOMM channel number in the Protocol Descriptor List 48 */ 49 50 #undef rfcomm_channel_lookup_exit 51 #define rfcomm_channel_lookup_exit(e) { \ 52 if (error != NULL) \ 53 *error = (e); \ 54 if (ss != NULL) { \ 55 sdp_close(ss); \ 56 ss = NULL; \ 57 } \ 58 return (((e) == 0)? 0 : -1); \ 59 } 60 61 int 62 rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote, 63 int service, int *channel, int *error) 64 { 65 uint8_t buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE]; 66 void *ss = NULL; 67 uint16_t serv = (uint16_t) service; 68 uint32_t attr = SDP_ATTR_RANGE( 69 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 70 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST); 71 sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer }; 72 uint32_t type, len; 73 74 if (local == NULL) 75 local = NG_HCI_BDADDR_ANY; 76 if (remote == NULL || channel == NULL) 77 rfcomm_channel_lookup_exit(EINVAL); 78 79 if ((ss = sdp_open(local, remote)) == NULL) 80 rfcomm_channel_lookup_exit(ENOMEM); 81 if (sdp_error(ss) != 0) 82 rfcomm_channel_lookup_exit(sdp_error(ss)); 83 84 if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0) 85 rfcomm_channel_lookup_exit(sdp_error(ss)); 86 if (proto.flags != SDP_ATTR_OK) 87 rfcomm_channel_lookup_exit(ENOATTR); 88 89 sdp_close(ss); 90 ss = NULL; 91 92 /* 93 * If it is possible for more than one kind of protocol stack to be 94 * used to gain access to the service, the ProtocolDescriptorList 95 * takes the form of a data element alternative. We always use the 96 * first protocol stack. 97 * 98 * A minimal Protocol Descriptor List for RFCOMM based service would 99 * look like 100 * 101 * seq8 len8 - 2 bytes 102 * seq8 len8 - 2 bytes 103 * uuid16 value16 - 3 bytes L2CAP 104 * seq8 len8 - 2 bytes 105 * uuid16 value16 - 3 bytes RFCOMM 106 * uint8 value8 - 2 bytes RFCOMM param #1 107 * ========= 108 * 14 bytes 109 * 110 * Lets not count first [seq8 len8] wrapper, so the minimal size of 111 * the Protocol Descriptor List (the data we are actually interested 112 * in) for RFCOMM based service would be 12 bytes. 113 */ 114 115 if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) 116 rfcomm_channel_lookup_exit(EINVAL); 117 118 SDP_GET8(type, proto.value); 119 120 if (type == SDP_DATA_ALT8) { 121 SDP_GET8(len, proto.value); 122 } else if (type == SDP_DATA_ALT16) { 123 SDP_GET16(len, proto.value); 124 } else if (type == SDP_DATA_ALT32) { 125 SDP_GET32(len, proto.value); 126 } else 127 len = 0; 128 129 if (len > 0) 130 SDP_GET8(type, proto.value); 131 132 switch (type) { 133 case SDP_DATA_SEQ8: 134 SDP_GET8(len, proto.value); 135 break; 136 137 case SDP_DATA_SEQ16: 138 SDP_GET16(len, proto.value); 139 break; 140 141 case SDP_DATA_SEQ32: 142 SDP_GET32(len, proto.value); 143 break; 144 145 default: 146 rfcomm_channel_lookup_exit(ENOATTR); 147 /* NOT REACHED */ 148 } 149 150 if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) 151 rfcomm_channel_lookup_exit(EINVAL); 152 153 return (rfcomm_proto_list_parse(proto.value, 154 buffer + proto.vlen, channel, error)); 155 } 156 157 /* 158 * Parse protocol descriptor list 159 * 160 * The ProtocolDescriptorList attribute describes one or more protocol 161 * stacks that may be used to gain access to the service described by 162 * the service record. If the ProtocolDescriptorList describes a single 163 * stack, it takes the form of a data element sequence in which each 164 * element of the sequence is a protocol descriptor. 165 */ 166 167 #undef rfcomm_proto_list_parse_exit 168 #define rfcomm_proto_list_parse_exit(e) { \ 169 if (error != NULL) \ 170 *error = (e); \ 171 return (((e) == 0)? 0 : -1); \ 172 } 173 174 static int 175 rfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end, 176 int *channel, int *error) 177 { 178 int type, len, value; 179 180 while (start < end) { 181 182 /* 183 * Parse protocol descriptor 184 * 185 * A protocol descriptor identifies a communications protocol 186 * and provides protocol specific parameters. A protocol 187 * descriptor is represented as a data element sequence. The 188 * first data element in the sequence must be the UUID that 189 * identifies the protocol. Additional data elements optionally 190 * provide protocol specific information, such as the L2CAP 191 * protocol/service multiplexer (PSM) and the RFCOMM server 192 * channel number (CN). 193 */ 194 195 /* We must have at least one byte (type) */ 196 if (end - start < 1) 197 rfcomm_proto_list_parse_exit(EINVAL) 198 199 SDP_GET8(type, start); 200 switch (type) { 201 case SDP_DATA_SEQ8: 202 SDP_GET8(len, start); 203 break; 204 205 case SDP_DATA_SEQ16: 206 SDP_GET16(len, start); 207 break; 208 209 case SDP_DATA_SEQ32: 210 SDP_GET32(len, start); 211 break; 212 213 default: 214 rfcomm_proto_list_parse_exit(ENOATTR) 215 /* NOT REACHED */ 216 } 217 218 /* We must have at least 3 bytes (type + UUID16) */ 219 if (end - start < 3) 220 rfcomm_proto_list_parse_exit(EINVAL); 221 222 /* Get protocol UUID */ 223 SDP_GET8(type, start); len -= sizeof(uint8_t); 224 switch (type) { 225 case SDP_DATA_UUID16: 226 SDP_GET16(value, start); len -= sizeof(uint16_t); 227 if (value != SDP_UUID_PROTOCOL_RFCOMM) 228 goto next_protocol; 229 break; 230 231 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 232 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 233 default: 234 rfcomm_proto_list_parse_exit(ENOATTR); 235 /* NOT REACHED */ 236 } 237 238 /* 239 * First protocol specific parameter for RFCOMM procotol must 240 * be uint8 that represents RFCOMM channel number. So we must 241 * have at least two bytes. 242 */ 243 244 if (end - start < 2) 245 rfcomm_proto_list_parse_exit(EINVAL); 246 247 SDP_GET8(type, start); 248 if (type != SDP_DATA_UINT8) 249 rfcomm_proto_list_parse_exit(ENOATTR); 250 251 SDP_GET8(*channel, start); 252 253 rfcomm_proto_list_parse_exit(0); 254 /* NOT REACHED */ 255 next_protocol: 256 start += len; 257 } 258 259 /* 260 * If we got here then it means we could not find RFCOMM protocol 261 * descriptor, but the reply format was actually valid. 262 */ 263 264 rfcomm_proto_list_parse_exit(ENOATTR); 265 } 266 267