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 } 130 131 return (2 + len); 132 } 133 134 /* 135 * seq8 len8 - 2 bytes 136 * seq 8 len8 - 2 bytes 137 * uuid16 value16 - 3 bytes 138 * uint16 value16 - 3 bytes 139 * [ seq 8 len8 140 * uuid16 value16 141 * uint16 value16 ] 142 */ 143 144 int32_t 145 common_profile_create_bluetooth_profile_descriptor_list( 146 uint8_t *buf, uint8_t const * const eob, 147 uint8_t const *data, uint32_t datalen) 148 { 149 int32_t len = 8 * (datalen >>= 2); 150 151 if (len <= 0 || len > 0xff || buf + 2 + len > eob) 152 return (-1); 153 154 SDP_PUT8(SDP_DATA_SEQ8, buf); 155 SDP_PUT8(len, buf); 156 157 for (; datalen > 0; datalen --) { 158 SDP_PUT8(SDP_DATA_SEQ8, buf); 159 SDP_PUT8(6, buf); 160 SDP_PUT8(SDP_DATA_UUID16, buf); 161 SDP_PUT16(*((uint16_t const *)data)++, buf); 162 SDP_PUT8(SDP_DATA_UINT16, buf); 163 SDP_PUT16(*((uint16_t const *)data)++, buf); 164 } 165 166 return (2 + len); 167 } 168 169 /* 170 * seq8 len8 - 2 bytes 171 * uint16 value16 - 3 bytes 172 * uint16 value16 - 3 bytes 173 * uint16 value16 - 3 bytes 174 */ 175 176 int32_t 177 common_profile_create_language_base_attribute_id_list( 178 uint8_t *buf, uint8_t const * const eob, 179 uint8_t const *data, uint32_t datalen) 180 { 181 if (buf + 11 > eob) 182 return (-1); 183 184 SDP_PUT8(SDP_DATA_SEQ8, buf); 185 SDP_PUT8(9, buf); 186 187 /* 188 * Language code per ISO 639:1988. Use "en". 189 */ 190 191 SDP_PUT8(SDP_DATA_UINT16, buf); 192 SDP_PUT16(((0x65 << 8) | 0x6e), buf); 193 194 /* 195 * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106 196 * (http://www.iana.org/assignments/character-sets) 197 */ 198 199 SDP_PUT8(SDP_DATA_UINT16, buf); 200 SDP_PUT16(106, buf); 201 202 /* 203 * Offset (Primary Language Base is 0x100) 204 */ 205 206 SDP_PUT8(SDP_DATA_UINT16, buf); 207 SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf); 208 209 return (11); 210 } 211 212 /* 213 * Common provider name is "FreeBSD" 214 */ 215 216 int32_t 217 common_profile_create_service_provider_name( 218 uint8_t *buf, uint8_t const * const eob, 219 uint8_t const *data, uint32_t datalen) 220 { 221 char provider_name[] = "FreeBSD"; 222 223 return (common_profile_create_string8(buf, eob, 224 (uint8_t const *) provider_name, 225 strlen(provider_name))); 226 } 227 228 /* 229 * str8 len8 string 230 */ 231 232 int32_t 233 common_profile_create_string8( 234 uint8_t *buf, uint8_t const * const eob, 235 uint8_t const *data, uint32_t datalen) 236 { 237 if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob) 238 return (-1); 239 240 SDP_PUT8(SDP_DATA_STR8, buf); 241 SDP_PUT8(datalen, buf); 242 memcpy(buf, data, datalen); 243 244 return (2 + datalen); 245 } 246 247 /* 248 * seq8 len8 - 2 bytes 249 * seq8 len8 - 2 bytes 250 * uuid16 value16 - 3 bytes 251 * seq8 len8 - 2 bytes 252 * uuid16 value16 - 3 bytes 253 * uint8 value8 - 2 bytes 254 */ 255 256 int32_t 257 rfcomm_profile_create_protocol_descriptor_list( 258 uint8_t *buf, uint8_t const * const eob, 259 uint8_t const *data, uint32_t datalen) 260 { 261 if (datalen != 1 || buf + 14 > eob) 262 return (-1); 263 264 SDP_PUT8(SDP_DATA_SEQ8, buf); 265 SDP_PUT8(12, buf); 266 267 SDP_PUT8(SDP_DATA_SEQ8, buf); 268 SDP_PUT8(3, buf); 269 SDP_PUT8(SDP_DATA_UUID16, buf); 270 SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 271 272 SDP_PUT8(SDP_DATA_SEQ8, buf); 273 SDP_PUT8(5, buf); 274 SDP_PUT8(SDP_DATA_UUID16, buf); 275 SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf); 276 SDP_PUT8(SDP_DATA_UINT8, buf); 277 SDP_PUT8(*data, buf); 278 279 return (14); 280 } 281 282 /* 283 * seq8 len8 - 2 bytes 284 * seq8 len8 - 2 bytes 285 * uuid16 value16 - 3 bytes 286 * seq8 len8 - 2 bytes 287 * uuid16 value16 - 3 bytes 288 * uint8 value8 - 2 bytes 289 * seq8 len8 - 2 bytes 290 * uuid16 value16 - 3 bytes 291 */ 292 293 int32_t 294 obex_profile_create_protocol_descriptor_list( 295 uint8_t *buf, uint8_t const * const eob, 296 uint8_t const *data, uint32_t datalen) 297 { 298 if (datalen != 1 || buf + 19 > eob) 299 return (-1); 300 301 SDP_PUT8(SDP_DATA_SEQ8, buf); 302 SDP_PUT8(17, buf); 303 304 SDP_PUT8(SDP_DATA_SEQ8, buf); 305 SDP_PUT8(3, buf); 306 SDP_PUT8(SDP_DATA_UUID16, buf); 307 SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 308 309 SDP_PUT8(SDP_DATA_SEQ8, buf); 310 SDP_PUT8(5, buf); 311 SDP_PUT8(SDP_DATA_UUID16, buf); 312 SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf); 313 SDP_PUT8(SDP_DATA_UINT8, buf); 314 SDP_PUT8(*data, buf); 315 316 SDP_PUT8(SDP_DATA_SEQ8, buf); 317 SDP_PUT8(3, buf); 318 SDP_PUT8(SDP_DATA_UUID16, buf); 319 SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf); 320 321 return (19); 322 } 323 324 /* 325 * seq8 len8 326 * uint8 value8 - bytes 327 * [ uint8 value 8 ] 328 */ 329 330 int32_t 331 obex_profile_create_supported_formats_list( 332 uint8_t *buf, uint8_t const * const eob, 333 uint8_t const *data, uint32_t datalen) 334 { 335 int32_t len = 2 * datalen; 336 337 if (len <= 0 || len > 0xff || buf + 2 + len > eob) 338 return (-1); 339 340 SDP_PUT8(SDP_DATA_SEQ8, buf); 341 SDP_PUT8(len, buf); 342 343 for (; datalen > 0; datalen --) { 344 SDP_PUT8(SDP_DATA_UINT8, buf); 345 SDP_PUT8(*data++, buf); 346 } 347 348 return (2 + len); 349 } 350 351 /* 352 * verify server channel number (the first byte in the data) 353 */ 354 355 int32_t 356 common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen) 357 { 358 if (data[0] < 1 || data[0] > 30) 359 return (0); 360 361 return (1); 362 } 363 364 /* 365 * verify server channel number and supported_formats_size 366 * sdp_opush_profile and sdp_irmc_profile 367 */ 368 369 int32_t 370 obex_profile_data_valid(uint8_t const *data, uint32_t datalen) 371 { 372 sdp_opush_profile_p opush = (sdp_opush_profile_p) data; 373 374 if (opush->server_channel < 1 || 375 opush->server_channel > 30 || 376 opush->supported_formats_size == 0 || 377 opush->supported_formats_size > sizeof(opush->supported_formats)) 378 return (0); 379 380 return (1); 381 } 382 383