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