1 /* 2 * profile.c 3 */ 4 5 /*- 6 * Copyright (c) 2004 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: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $ 31 * $FreeBSD$ 32 */ 33 34 #include <sys/queue.h> 35 #define L2CAP_SOCKET_CHECKED 36 #include <bluetooth.h> 37 #include <sdp.h> 38 #include <string.h> 39 #include "profile.h" 40 #include "provider.h" 41 42 /* 43 * Lookup profile descriptor 44 */ 45 46 profile_p 47 profile_get_descriptor(uint16_t uuid) 48 { 49 extern profile_t dun_profile_descriptor; 50 extern profile_t ftrn_profile_descriptor; 51 extern profile_t irmc_profile_descriptor; 52 extern profile_t irmc_command_profile_descriptor; 53 extern profile_t lan_profile_descriptor; 54 extern profile_t opush_profile_descriptor; 55 extern profile_t sp_profile_descriptor; 56 extern profile_t nap_profile_descriptor; 57 extern profile_t gn_profile_descriptor; 58 extern profile_t panu_profile_descriptor; 59 60 static const profile_p profiles[] = { 61 &dun_profile_descriptor, 62 &ftrn_profile_descriptor, 63 &irmc_profile_descriptor, 64 &irmc_command_profile_descriptor, 65 &lan_profile_descriptor, 66 &opush_profile_descriptor, 67 &sp_profile_descriptor, 68 &nap_profile_descriptor, 69 &gn_profile_descriptor, 70 &panu_profile_descriptor 71 }; 72 73 int32_t i; 74 75 for (i = 0; i < sizeof(profiles)/sizeof(profiles[0]); i++) 76 if (profiles[i]->uuid == uuid) 77 return (profiles[i]); 78 79 return (NULL); 80 } 81 82 /* 83 * Look attribute in the profile descripror 84 */ 85 86 profile_attr_create_p 87 profile_get_attr(const profile_p profile, uint16_t attr) 88 { 89 attr_p ad = (attr_p) profile->attrs; 90 91 for (; ad->create != NULL; ad ++) 92 if (ad->attr == attr) 93 return (ad->create); 94 95 return (NULL); 96 } 97 98 /* 99 * uint32 value32 - 5 bytes 100 */ 101 102 int32_t 103 common_profile_create_service_record_handle( 104 uint8_t *buf, uint8_t const * const eob, 105 uint8_t const *data, uint32_t datalen) 106 { 107 if (buf + 5 > eob) 108 return (-1); 109 110 SDP_PUT8(SDP_DATA_UINT32, buf); 111 SDP_PUT32(((provider_p) data)->handle, buf); 112 113 return (5); 114 } 115 116 /* 117 * seq8 len8 - 2 bytes 118 * uuid16 value16 - 3 bytes 119 * [ uuid16 value ] 120 */ 121 122 int32_t 123 common_profile_create_service_class_id_list( 124 uint8_t *buf, uint8_t const * const eob, 125 uint8_t const *data, uint32_t datalen) 126 { 127 int32_t len = 3 * (datalen >>= 1); 128 129 if (len <= 0 || len > 0xff || buf + 2 + len > eob) 130 return (-1); 131 132 SDP_PUT8(SDP_DATA_SEQ8, buf); 133 SDP_PUT8(len, buf); 134 135 for (; datalen > 0; datalen --) { 136 SDP_PUT8(SDP_DATA_UUID16, buf); 137 SDP_PUT16(*((uint16_t const *)data), buf); 138 data += sizeof(uint16_t); 139 } 140 141 return (2 + len); 142 } 143 144 /* 145 * seq8 len8 - 2 bytes 146 * seq 8 len8 - 2 bytes 147 * uuid16 value16 - 3 bytes 148 * uint16 value16 - 3 bytes 149 * [ seq 8 len8 150 * uuid16 value16 151 * uint16 value16 ] 152 */ 153 154 int32_t 155 common_profile_create_bluetooth_profile_descriptor_list( 156 uint8_t *buf, uint8_t const * const eob, 157 uint8_t const *data, uint32_t datalen) 158 { 159 int32_t len = 8 * (datalen >>= 2); 160 161 if (len <= 0 || len > 0xff || buf + 2 + len > eob) 162 return (-1); 163 164 SDP_PUT8(SDP_DATA_SEQ8, buf); 165 SDP_PUT8(len, buf); 166 167 for (; datalen > 0; datalen --) { 168 SDP_PUT8(SDP_DATA_SEQ8, buf); 169 SDP_PUT8(6, buf); 170 SDP_PUT8(SDP_DATA_UUID16, buf); 171 SDP_PUT16(*((uint16_t const *)data), buf); 172 data += sizeof(uint16_t); 173 SDP_PUT8(SDP_DATA_UINT16, buf); 174 SDP_PUT16(*((uint16_t const *)data), buf); 175 data += sizeof(uint16_t); 176 } 177 178 return (2 + len); 179 } 180 181 /* 182 * seq8 len8 - 2 bytes 183 * uint16 value16 - 3 bytes 184 * uint16 value16 - 3 bytes 185 * uint16 value16 - 3 bytes 186 */ 187 188 int32_t 189 common_profile_create_language_base_attribute_id_list( 190 uint8_t *buf, uint8_t const * const eob, 191 uint8_t const *data, uint32_t datalen) 192 { 193 if (buf + 11 > eob) 194 return (-1); 195 196 SDP_PUT8(SDP_DATA_SEQ8, buf); 197 SDP_PUT8(9, buf); 198 199 /* 200 * Language code per ISO 639:1988. Use "en". 201 */ 202 203 SDP_PUT8(SDP_DATA_UINT16, buf); 204 SDP_PUT16(((0x65 << 8) | 0x6e), buf); 205 206 /* 207 * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106 208 * (http://www.iana.org/assignments/character-sets) 209 */ 210 211 SDP_PUT8(SDP_DATA_UINT16, buf); 212 SDP_PUT16(106, buf); 213 214 /* 215 * Offset (Primary Language Base is 0x100) 216 */ 217 218 SDP_PUT8(SDP_DATA_UINT16, buf); 219 SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf); 220 221 return (11); 222 } 223 224 /* 225 * Common provider name is "FreeBSD" 226 */ 227 228 int32_t 229 common_profile_create_service_provider_name( 230 uint8_t *buf, uint8_t const * const eob, 231 uint8_t const *data, uint32_t datalen) 232 { 233 char provider_name[] = "FreeBSD"; 234 235 return (common_profile_create_string8(buf, eob, 236 (uint8_t const *) provider_name, 237 strlen(provider_name))); 238 } 239 240 /* 241 * str8 len8 string 242 */ 243 244 int32_t 245 common_profile_create_string8( 246 uint8_t *buf, uint8_t const * const eob, 247 uint8_t const *data, uint32_t datalen) 248 { 249 if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob) 250 return (-1); 251 252 SDP_PUT8(SDP_DATA_STR8, buf); 253 SDP_PUT8(datalen, buf); 254 memcpy(buf, data, datalen); 255 256 return (2 + datalen); 257 } 258 259 /* 260 * Service Availability 261 */ 262 263 int32_t 264 common_profile_create_service_availability( 265 uint8_t *buf, uint8_t const * const eob, 266 uint8_t const *data, uint32_t datalen) 267 { 268 if (datalen != 1 || buf + 2 > eob) 269 return (-1); 270 271 SDP_PUT8(SDP_DATA_UINT8, buf); 272 SDP_PUT8(data[0], buf); 273 274 return (2); 275 } 276 277 /* 278 * seq8 len8 - 2 bytes 279 * seq8 len8 - 2 bytes 280 * uuid16 value16 - 3 bytes 281 * seq8 len8 - 2 bytes 282 * uuid16 value16 - 3 bytes 283 * uint8 value8 - 2 bytes 284 */ 285 286 int32_t 287 rfcomm_profile_create_protocol_descriptor_list( 288 uint8_t *buf, uint8_t const * const eob, 289 uint8_t const *data, uint32_t datalen) 290 { 291 if (datalen != 1 || buf + 14 > eob) 292 return (-1); 293 294 SDP_PUT8(SDP_DATA_SEQ8, buf); 295 SDP_PUT8(12, buf); 296 297 SDP_PUT8(SDP_DATA_SEQ8, buf); 298 SDP_PUT8(3, buf); 299 SDP_PUT8(SDP_DATA_UUID16, buf); 300 SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 301 302 SDP_PUT8(SDP_DATA_SEQ8, buf); 303 SDP_PUT8(5, buf); 304 SDP_PUT8(SDP_DATA_UUID16, buf); 305 SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf); 306 SDP_PUT8(SDP_DATA_UINT8, buf); 307 SDP_PUT8(*data, buf); 308 309 return (14); 310 } 311 312 /* 313 * seq8 len8 - 2 bytes 314 * seq8 len8 - 2 bytes 315 * uuid16 value16 - 3 bytes 316 * seq8 len8 - 2 bytes 317 * uuid16 value16 - 3 bytes 318 * uint8 value8 - 2 bytes 319 * seq8 len8 - 2 bytes 320 * uuid16 value16 - 3 bytes 321 */ 322 323 int32_t 324 obex_profile_create_protocol_descriptor_list( 325 uint8_t *buf, uint8_t const * const eob, 326 uint8_t const *data, uint32_t datalen) 327 { 328 if (datalen != 1 || buf + 19 > eob) 329 return (-1); 330 331 SDP_PUT8(SDP_DATA_SEQ8, buf); 332 SDP_PUT8(17, buf); 333 334 SDP_PUT8(SDP_DATA_SEQ8, buf); 335 SDP_PUT8(3, buf); 336 SDP_PUT8(SDP_DATA_UUID16, buf); 337 SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 338 339 SDP_PUT8(SDP_DATA_SEQ8, buf); 340 SDP_PUT8(5, buf); 341 SDP_PUT8(SDP_DATA_UUID16, buf); 342 SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf); 343 SDP_PUT8(SDP_DATA_UINT8, buf); 344 SDP_PUT8(*data, buf); 345 346 SDP_PUT8(SDP_DATA_SEQ8, buf); 347 SDP_PUT8(3, buf); 348 SDP_PUT8(SDP_DATA_UUID16, buf); 349 SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf); 350 351 return (19); 352 } 353 354 /* 355 * seq8 len8 356 * uint8 value8 - bytes 357 * [ uint8 value 8 ] 358 */ 359 360 int32_t 361 obex_profile_create_supported_formats_list( 362 uint8_t *buf, uint8_t const * const eob, 363 uint8_t const *data, uint32_t datalen) 364 { 365 int32_t len = 2 * datalen; 366 367 if (len <= 0 || len > 0xff || buf + 2 + len > eob) 368 return (-1); 369 370 SDP_PUT8(SDP_DATA_SEQ8, buf); 371 SDP_PUT8(len, buf); 372 373 for (; datalen > 0; datalen --) { 374 SDP_PUT8(SDP_DATA_UINT8, buf); 375 SDP_PUT8(*data++, buf); 376 } 377 378 return (2 + len); 379 } 380 381 /* 382 * do not check anything 383 */ 384 385 int32_t 386 common_profile_always_valid(uint8_t const *data, uint32_t datalen) 387 { 388 return (1); 389 } 390 391 /* 392 * verify server channel number (the first byte in the data) 393 */ 394 395 int32_t 396 common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen) 397 { 398 if (data[0] < 1 || data[0] > 30) 399 return (0); 400 401 return (1); 402 } 403 404 /* 405 * verify server channel number and supported_formats_size 406 * sdp_opush_profile and sdp_irmc_profile 407 */ 408 409 int32_t 410 obex_profile_data_valid(uint8_t const *data, uint32_t datalen) 411 { 412 sdp_opush_profile_p opush = (sdp_opush_profile_p) data; 413 414 if (opush->server_channel < 1 || 415 opush->server_channel > 30 || 416 opush->supported_formats_size == 0 || 417 opush->supported_formats_size > sizeof(opush->supported_formats)) 418 return (0); 419 420 return (1); 421 } 422 423 /* 424 * BNEP protocol descriptor 425 */ 426 427 int32_t 428 bnep_profile_create_protocol_descriptor_list( 429 uint8_t *buf, uint8_t const * const eob, 430 uint8_t const *data, uint32_t datalen) 431 { 432 /* supported protocol types */ 433 uint16_t ptype[] = { 434 0x0800, /* IPv4 */ 435 0x0806, /* ARP */ 436 #ifdef INET6 437 0x86dd, /* IPv6 */ 438 #endif 439 }; 440 441 uint16_t i, psm, version = 0x0100, 442 nptypes = sizeof(ptype)/sizeof(ptype[0]), 443 nptypes_size = nptypes * 3; 444 445 if (datalen != 2 || 18 + nptypes_size > 255 || 446 buf + 20 + nptypes_size > eob) 447 return (-1); 448 449 memcpy(&psm, data, sizeof(psm)); 450 451 SDP_PUT8(SDP_DATA_SEQ8, buf); 452 SDP_PUT8(18 + nptypes_size, buf); 453 454 SDP_PUT8(SDP_DATA_SEQ8, buf); 455 SDP_PUT8(6, buf); 456 SDP_PUT8(SDP_DATA_UUID16, buf); 457 SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 458 SDP_PUT8(SDP_DATA_UINT16, buf); 459 SDP_PUT16(psm, buf); 460 461 SDP_PUT8(SDP_DATA_SEQ8, buf); 462 SDP_PUT8(8 + nptypes_size, buf); 463 SDP_PUT8(SDP_DATA_UUID16, buf); 464 SDP_PUT16(SDP_UUID_PROTOCOL_BNEP, buf); 465 SDP_PUT8(SDP_DATA_UINT16, buf); 466 SDP_PUT16(version, buf); 467 SDP_PUT8(SDP_DATA_SEQ8, buf); 468 SDP_PUT8(nptypes_size, buf); 469 for (i = 0; i < nptypes; i ++) { 470 SDP_PUT8(SDP_DATA_UINT16, buf); 471 SDP_PUT16(ptype[i], buf); 472 } 473 474 return (20 + nptypes_size); 475 } 476 477 /* 478 * BNEP security description 479 */ 480 481 int32_t 482 bnep_profile_create_security_description( 483 uint8_t *buf, uint8_t const * const eob, 484 uint8_t const *data, uint32_t datalen) 485 { 486 uint16_t security_descr; 487 488 if (datalen != 2 || buf + 3 > eob) 489 return (-1); 490 491 memcpy(&security_descr, data, sizeof(security_descr)); 492 493 SDP_PUT8(SDP_DATA_UINT16, buf); 494 SDP_PUT16(security_descr, buf); 495 496 return (3); 497 } 498 499