1 /* 2 * profile.c 3 * 4 * Copyright (c) 2004 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: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $ 29 * $FreeBSD$ 30 */ 31 32 #include <sys/queue.h> 33 #include <bluetooth.h> 34 #include <sdp.h> 35 #include <string.h> 36 #include "profile.h" 37 #include "provider.h" 38 39 /* 40 * Lookup profile descriptor 41 */ 42 43 profile_p 44 profile_get_descriptor(uint16_t uuid) 45 { 46 extern profile_t dun_profile_descriptor; 47 extern profile_t ftrn_profile_descriptor; 48 extern profile_t irmc_profile_descriptor; 49 extern profile_t irmc_command_profile_descriptor; 50 extern profile_t lan_profile_descriptor; 51 extern profile_t opush_profile_descriptor; 52 extern profile_t sp_profile_descriptor; 53 54 static const profile_p profiles[] = { 55 &dun_profile_descriptor, 56 &ftrn_profile_descriptor, 57 &irmc_profile_descriptor, 58 &irmc_command_profile_descriptor, 59 &lan_profile_descriptor, 60 &opush_profile_descriptor, 61 &sp_profile_descriptor 62 }; 63 64 int32_t i; 65 66 for (i = 0; i < sizeof(profiles)/sizeof(profiles[0]); i++) 67 if (profiles[i]->uuid == uuid) 68 return (profiles[i]); 69 70 return (NULL); 71 } 72 73 /* 74 * Look attribute in the profile descripror 75 */ 76 77 profile_attr_create_p 78 profile_get_attr(const profile_p profile, uint16_t attr) 79 { 80 attr_p ad = (attr_p) profile->attrs; 81 82 for (; ad->create != NULL; ad ++) 83 if (ad->attr == attr) 84 return (ad->create); 85 86 return (NULL); 87 } 88 89 /* 90 * uint32 value32 - 5 bytes 91 */ 92 93 int32_t 94 common_profile_create_service_record_handle( 95 uint8_t *buf, uint8_t const * const eob, 96 uint8_t const *data, uint32_t datalen) 97 { 98 if (buf + 5 > eob) 99 return (-1); 100 101 SDP_PUT8(SDP_DATA_UINT32, buf); 102 SDP_PUT32(((provider_p) data)->handle, buf); 103 104 return (5); 105 } 106 107 /* 108 * seq8 len8 - 2 bytes 109 * uuid16 value16 - 3 bytes 110 * [ uuid16 value ] 111 */ 112 113 int32_t 114 common_profile_create_service_class_id_list( 115 uint8_t *buf, uint8_t const * const eob, 116 uint8_t const *data, uint32_t datalen) 117 { 118 int32_t len = 3 * (datalen >>= 1); 119 120 if (len <= 0 || len > 0xff || buf + 2 + len > eob) 121 return (-1); 122 123 SDP_PUT8(SDP_DATA_SEQ8, buf); 124 SDP_PUT8(len, buf); 125 126 for (; datalen > 0; datalen --) { 127 SDP_PUT8(SDP_DATA_UUID16, buf); 128 SDP_PUT16(*((uint16_t const *)data), buf); 129 data += sizeof(uint16_t); 130 } 131 132 return (2 + len); 133 } 134 135 /* 136 * seq8 len8 - 2 bytes 137 * seq 8 len8 - 2 bytes 138 * uuid16 value16 - 3 bytes 139 * uint16 value16 - 3 bytes 140 * [ seq 8 len8 141 * uuid16 value16 142 * uint16 value16 ] 143 */ 144 145 int32_t 146 common_profile_create_bluetooth_profile_descriptor_list( 147 uint8_t *buf, uint8_t const * const eob, 148 uint8_t const *data, uint32_t datalen) 149 { 150 int32_t len = 8 * (datalen >>= 2); 151 152 if (len <= 0 || len > 0xff || buf + 2 + len > eob) 153 return (-1); 154 155 SDP_PUT8(SDP_DATA_SEQ8, buf); 156 SDP_PUT8(len, buf); 157 158 for (; datalen > 0; datalen --) { 159 SDP_PUT8(SDP_DATA_SEQ8, buf); 160 SDP_PUT8(6, buf); 161 SDP_PUT8(SDP_DATA_UUID16, buf); 162 SDP_PUT16(*((uint16_t const *)data), buf); 163 data += sizeof(uint16_t); 164 SDP_PUT8(SDP_DATA_UINT16, buf); 165 SDP_PUT16(*((uint16_t const *)data), buf); 166 data += sizeof(uint16_t); 167 } 168 169 return (2 + len); 170 } 171 172 /* 173 * seq8 len8 - 2 bytes 174 * uint16 value16 - 3 bytes 175 * uint16 value16 - 3 bytes 176 * uint16 value16 - 3 bytes 177 */ 178 179 int32_t 180 common_profile_create_language_base_attribute_id_list( 181 uint8_t *buf, uint8_t const * const eob, 182 uint8_t const *data, uint32_t datalen) 183 { 184 if (buf + 11 > eob) 185 return (-1); 186 187 SDP_PUT8(SDP_DATA_SEQ8, buf); 188 SDP_PUT8(9, buf); 189 190 /* 191 * Language code per ISO 639:1988. Use "en". 192 */ 193 194 SDP_PUT8(SDP_DATA_UINT16, buf); 195 SDP_PUT16(((0x65 << 8) | 0x6e), buf); 196 197 /* 198 * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106 199 * (http://www.iana.org/assignments/character-sets) 200 */ 201 202 SDP_PUT8(SDP_DATA_UINT16, buf); 203 SDP_PUT16(106, buf); 204 205 /* 206 * Offset (Primary Language Base is 0x100) 207 */ 208 209 SDP_PUT8(SDP_DATA_UINT16, buf); 210 SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf); 211 212 return (11); 213 } 214 215 /* 216 * Common provider name is "FreeBSD" 217 */ 218 219 int32_t 220 common_profile_create_service_provider_name( 221 uint8_t *buf, uint8_t const * const eob, 222 uint8_t const *data, uint32_t datalen) 223 { 224 char provider_name[] = "FreeBSD"; 225 226 return (common_profile_create_string8(buf, eob, 227 (uint8_t const *) provider_name, 228 strlen(provider_name))); 229 } 230 231 /* 232 * str8 len8 string 233 */ 234 235 int32_t 236 common_profile_create_string8( 237 uint8_t *buf, uint8_t const * const eob, 238 uint8_t const *data, uint32_t datalen) 239 { 240 if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob) 241 return (-1); 242 243 SDP_PUT8(SDP_DATA_STR8, buf); 244 SDP_PUT8(datalen, buf); 245 memcpy(buf, data, datalen); 246 247 return (2 + datalen); 248 } 249 250 /* 251 * seq8 len8 - 2 bytes 252 * seq8 len8 - 2 bytes 253 * uuid16 value16 - 3 bytes 254 * seq8 len8 - 2 bytes 255 * uuid16 value16 - 3 bytes 256 * uint8 value8 - 2 bytes 257 */ 258 259 int32_t 260 rfcomm_profile_create_protocol_descriptor_list( 261 uint8_t *buf, uint8_t const * const eob, 262 uint8_t const *data, uint32_t datalen) 263 { 264 if (datalen != 1 || buf + 14 > eob) 265 return (-1); 266 267 SDP_PUT8(SDP_DATA_SEQ8, buf); 268 SDP_PUT8(12, buf); 269 270 SDP_PUT8(SDP_DATA_SEQ8, buf); 271 SDP_PUT8(3, buf); 272 SDP_PUT8(SDP_DATA_UUID16, buf); 273 SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 274 275 SDP_PUT8(SDP_DATA_SEQ8, buf); 276 SDP_PUT8(5, buf); 277 SDP_PUT8(SDP_DATA_UUID16, buf); 278 SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf); 279 SDP_PUT8(SDP_DATA_UINT8, buf); 280 SDP_PUT8(*data, buf); 281 282 return (14); 283 } 284 285 /* 286 * seq8 len8 - 2 bytes 287 * seq8 len8 - 2 bytes 288 * uuid16 value16 - 3 bytes 289 * seq8 len8 - 2 bytes 290 * uuid16 value16 - 3 bytes 291 * uint8 value8 - 2 bytes 292 * seq8 len8 - 2 bytes 293 * uuid16 value16 - 3 bytes 294 */ 295 296 int32_t 297 obex_profile_create_protocol_descriptor_list( 298 uint8_t *buf, uint8_t const * const eob, 299 uint8_t const *data, uint32_t datalen) 300 { 301 if (datalen != 1 || buf + 19 > eob) 302 return (-1); 303 304 SDP_PUT8(SDP_DATA_SEQ8, buf); 305 SDP_PUT8(17, buf); 306 307 SDP_PUT8(SDP_DATA_SEQ8, buf); 308 SDP_PUT8(3, buf); 309 SDP_PUT8(SDP_DATA_UUID16, buf); 310 SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 311 312 SDP_PUT8(SDP_DATA_SEQ8, buf); 313 SDP_PUT8(5, buf); 314 SDP_PUT8(SDP_DATA_UUID16, buf); 315 SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf); 316 SDP_PUT8(SDP_DATA_UINT8, buf); 317 SDP_PUT8(*data, buf); 318 319 SDP_PUT8(SDP_DATA_SEQ8, buf); 320 SDP_PUT8(3, buf); 321 SDP_PUT8(SDP_DATA_UUID16, buf); 322 SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf); 323 324 return (19); 325 } 326 327 /* 328 * seq8 len8 329 * uint8 value8 - bytes 330 * [ uint8 value 8 ] 331 */ 332 333 int32_t 334 obex_profile_create_supported_formats_list( 335 uint8_t *buf, uint8_t const * const eob, 336 uint8_t const *data, uint32_t datalen) 337 { 338 int32_t len = 2 * datalen; 339 340 if (len <= 0 || len > 0xff || buf + 2 + len > eob) 341 return (-1); 342 343 SDP_PUT8(SDP_DATA_SEQ8, buf); 344 SDP_PUT8(len, buf); 345 346 for (; datalen > 0; datalen --) { 347 SDP_PUT8(SDP_DATA_UINT8, buf); 348 SDP_PUT8(*data++, buf); 349 } 350 351 return (2 + len); 352 } 353 354 /* 355 * verify server channel number (the first byte in the data) 356 */ 357 358 int32_t 359 common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen) 360 { 361 if (data[0] < 1 || data[0] > 30) 362 return (0); 363 364 return (1); 365 } 366 367 /* 368 * verify server channel number and supported_formats_size 369 * sdp_opush_profile and sdp_irmc_profile 370 */ 371 372 int32_t 373 obex_profile_data_valid(uint8_t const *data, uint32_t datalen) 374 { 375 sdp_opush_profile_p opush = (sdp_opush_profile_p) data; 376 377 if (opush->server_channel < 1 || 378 opush->server_channel > 30 || 379 opush->supported_formats_size == 0 || 380 opush->supported_formats_size > sizeof(opush->supported_formats)) 381 return (0); 382 383 return (1); 384 } 385 386