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 */ 32 #define L2CAP_SOCKET_CHECKED 33 #include <bluetooth.h> 34 #include <errno.h> 35 #include <sdp.h> 36 #include <stdio.h> 37 38 #undef PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 39 #define PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 256 40 41 #undef PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 42 #define PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 12 43 44 static int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end, 45 int *channel, int *error); 46 47 /* 48 * Lookup RFCOMM channel number in the Protocol Descriptor List 49 */ 50 51 #undef rfcomm_channel_lookup_exit 52 #define rfcomm_channel_lookup_exit(e) { \ 53 if (error != NULL) \ 54 *error = (e); \ 55 if (ss != NULL) { \ 56 sdp_close(ss); \ 57 ss = NULL; \ 58 } \ 59 return (((e) == 0)? 0 : -1); \ 60 } 61 62 int 63 rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote, 64 int service, int *channel, int *error) 65 { 66 uint8_t buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE]; 67 void *ss = NULL; 68 uint16_t serv = (uint16_t) service; 69 uint32_t attr = SDP_ATTR_RANGE( 70 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 71 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST); 72 sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer }; 73 uint32_t type, len; 74 75 if (local == NULL) 76 local = NG_HCI_BDADDR_ANY; 77 if (remote == NULL || channel == NULL) 78 rfcomm_channel_lookup_exit(EINVAL); 79 80 if ((ss = sdp_open(local, remote)) == NULL) 81 rfcomm_channel_lookup_exit(ENOMEM); 82 if (sdp_error(ss) != 0) 83 rfcomm_channel_lookup_exit(sdp_error(ss)); 84 85 if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0) 86 rfcomm_channel_lookup_exit(sdp_error(ss)); 87 if (proto.flags != SDP_ATTR_OK) 88 rfcomm_channel_lookup_exit(ENOATTR); 89 90 sdp_close(ss); 91 ss = NULL; 92 93 /* 94 * If it is possible for more than one kind of protocol stack to be 95 * used to gain access to the service, the ProtocolDescriptorList 96 * takes the form of a data element alternative. We always use the 97 * first protocol stack. 98 * 99 * A minimal Protocol Descriptor List for RFCOMM based service would 100 * look like 101 * 102 * seq8 len8 - 2 bytes 103 * seq8 len8 - 2 bytes 104 * uuid16 value16 - 3 bytes L2CAP 105 * seq8 len8 - 2 bytes 106 * uuid16 value16 - 3 bytes RFCOMM 107 * uint8 value8 - 2 bytes RFCOMM param #1 108 * ========= 109 * 14 bytes 110 * 111 * Lets not count first [seq8 len8] wrapper, so the minimal size of 112 * the Protocol Descriptor List (the data we are actually interested 113 * in) for RFCOMM based service would be 12 bytes. 114 */ 115 116 if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) 117 rfcomm_channel_lookup_exit(EINVAL); 118 119 SDP_GET8(type, proto.value); 120 121 if (type == SDP_DATA_ALT8) { 122 SDP_GET8(len, proto.value); 123 } else if (type == SDP_DATA_ALT16) { 124 SDP_GET16(len, proto.value); 125 } else if (type == SDP_DATA_ALT32) { 126 SDP_GET32(len, proto.value); 127 } else 128 len = 0; 129 130 if (len > 0) 131 SDP_GET8(type, proto.value); 132 133 switch (type) { 134 case SDP_DATA_SEQ8: 135 SDP_GET8(len, proto.value); 136 break; 137 138 case SDP_DATA_SEQ16: 139 SDP_GET16(len, proto.value); 140 break; 141 142 case SDP_DATA_SEQ32: 143 SDP_GET32(len, proto.value); 144 break; 145 146 default: 147 rfcomm_channel_lookup_exit(ENOATTR); 148 /* NOT REACHED */ 149 } 150 151 if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) 152 rfcomm_channel_lookup_exit(EINVAL); 153 154 return (rfcomm_proto_list_parse(proto.value, 155 buffer + proto.vlen, channel, error)); 156 } 157 158 /* 159 * Parse protocol descriptor list 160 * 161 * The ProtocolDescriptorList attribute describes one or more protocol 162 * stacks that may be used to gain access to the service described by 163 * the service record. If the ProtocolDescriptorList describes a single 164 * stack, it takes the form of a data element sequence in which each 165 * element of the sequence is a protocol descriptor. 166 */ 167 168 #undef rfcomm_proto_list_parse_exit 169 #define rfcomm_proto_list_parse_exit(e) { \ 170 if (error != NULL) \ 171 *error = (e); \ 172 return (((e) == 0)? 0 : -1); \ 173 } 174 175 static int 176 rfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end, 177 int *channel, int *error) 178 { 179 int type, len, value; 180 181 while (start < end) { 182 183 /* 184 * Parse protocol descriptor 185 * 186 * A protocol descriptor identifies a communications protocol 187 * and provides protocol specific parameters. A protocol 188 * descriptor is represented as a data element sequence. The 189 * first data element in the sequence must be the UUID that 190 * identifies the protocol. Additional data elements optionally 191 * provide protocol specific information, such as the L2CAP 192 * protocol/service multiplexer (PSM) and the RFCOMM server 193 * channel number (CN). 194 */ 195 196 /* We must have at least one byte (type) */ 197 if (end - start < 1) 198 rfcomm_proto_list_parse_exit(EINVAL) 199 200 SDP_GET8(type, start); 201 switch (type) { 202 case SDP_DATA_SEQ8: 203 SDP_GET8(len, start); 204 break; 205 206 case SDP_DATA_SEQ16: 207 SDP_GET16(len, start); 208 break; 209 210 case SDP_DATA_SEQ32: 211 SDP_GET32(len, start); 212 break; 213 214 default: 215 rfcomm_proto_list_parse_exit(ENOATTR) 216 /* NOT REACHED */ 217 } 218 219 /* We must have at least 3 bytes (type + UUID16) */ 220 if (end - start < 3) 221 rfcomm_proto_list_parse_exit(EINVAL); 222 223 /* Get protocol UUID */ 224 SDP_GET8(type, start); len -= sizeof(uint8_t); 225 switch (type) { 226 case SDP_DATA_UUID16: 227 SDP_GET16(value, start); len -= sizeof(uint16_t); 228 if (value != SDP_UUID_PROTOCOL_RFCOMM) 229 goto next_protocol; 230 break; 231 232 case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 233 case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 234 default: 235 rfcomm_proto_list_parse_exit(ENOATTR); 236 /* NOT REACHED */ 237 } 238 239 /* 240 * First protocol specific parameter for RFCOMM procotol must 241 * be uint8 that represents RFCOMM channel number. So we must 242 * have at least two bytes. 243 */ 244 245 if (end - start < 2) 246 rfcomm_proto_list_parse_exit(EINVAL); 247 248 SDP_GET8(type, start); 249 if (type != SDP_DATA_UINT8) 250 rfcomm_proto_list_parse_exit(ENOATTR); 251 252 SDP_GET8(*channel, start); 253 254 rfcomm_proto_list_parse_exit(0); 255 /* NOT REACHED */ 256 next_protocol: 257 start += len; 258 } 259 260 /* 261 * If we got here then it means we could not find RFCOMM protocol 262 * descriptor, but the reply format was actually valid. 263 */ 264 265 rfcomm_proto_list_parse_exit(ENOATTR); 266 } 267 268