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