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