1124758Semax/* 2124758Semax * profile.c 3177059Semax */ 4177059Semax 5177059Semax/*- 6124758Semax * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7124758Semax * All rights reserved. 8124758Semax * 9124758Semax * Redistribution and use in source and binary forms, with or without 10124758Semax * modification, are permitted provided that the following conditions 11124758Semax * are met: 12124758Semax * 1. Redistributions of source code must retain the above copyright 13124758Semax * notice, this list of conditions and the following disclaimer. 14124758Semax * 2. Redistributions in binary form must reproduce the above copyright 15124758Semax * notice, this list of conditions and the following disclaimer in the 16124758Semax * documentation and/or other materials provided with the distribution. 17124758Semax * 18124758Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19124758Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20124758Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21124758Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22124758Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23124758Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24124758Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25124758Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26124758Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27124758Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28124758Semax * SUCH DAMAGE. 29124758Semax * 30124758Semax * $Id: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $ 31124758Semax * $FreeBSD$ 32124758Semax */ 33124758Semax 34124758Semax#include <sys/queue.h> 35124758Semax#include <bluetooth.h> 36124758Semax#include <sdp.h> 37124758Semax#include <string.h> 38124758Semax#include "profile.h" 39124758Semax#include "provider.h" 40124758Semax 41124758Semax/* 42124758Semax * Lookup profile descriptor 43124758Semax */ 44124758Semax 45124758Semaxprofile_p 46124758Semaxprofile_get_descriptor(uint16_t uuid) 47124758Semax{ 48124758Semax extern profile_t dun_profile_descriptor; 49124758Semax extern profile_t ftrn_profile_descriptor; 50124758Semax extern profile_t irmc_profile_descriptor; 51124758Semax extern profile_t irmc_command_profile_descriptor; 52124758Semax extern profile_t lan_profile_descriptor; 53124758Semax extern profile_t opush_profile_descriptor; 54124758Semax extern profile_t sp_profile_descriptor; 55177059Semax extern profile_t nap_profile_descriptor; 56177059Semax extern profile_t gn_profile_descriptor; 57177059Semax extern profile_t panu_profile_descriptor; 58124758Semax 59124758Semax static const profile_p profiles[] = { 60124758Semax &dun_profile_descriptor, 61124758Semax &ftrn_profile_descriptor, 62124758Semax &irmc_profile_descriptor, 63124758Semax &irmc_command_profile_descriptor, 64124758Semax &lan_profile_descriptor, 65124758Semax &opush_profile_descriptor, 66177059Semax &sp_profile_descriptor, 67177059Semax &nap_profile_descriptor, 68177059Semax &gn_profile_descriptor, 69177059Semax &panu_profile_descriptor 70124758Semax }; 71124758Semax 72124758Semax int32_t i; 73124758Semax 74124758Semax for (i = 0; i < sizeof(profiles)/sizeof(profiles[0]); i++) 75124758Semax if (profiles[i]->uuid == uuid) 76124758Semax return (profiles[i]); 77124758Semax 78124758Semax return (NULL); 79124758Semax} 80124758Semax 81124758Semax/* 82124758Semax * Look attribute in the profile descripror 83124758Semax */ 84124758Semax 85124758Semaxprofile_attr_create_p 86124758Semaxprofile_get_attr(const profile_p profile, uint16_t attr) 87124758Semax{ 88124758Semax attr_p ad = (attr_p) profile->attrs; 89124758Semax 90124758Semax for (; ad->create != NULL; ad ++) 91124758Semax if (ad->attr == attr) 92124758Semax return (ad->create); 93124758Semax 94124758Semax return (NULL); 95124758Semax} 96124758Semax 97124758Semax/* 98124758Semax * uint32 value32 - 5 bytes 99124758Semax */ 100124758Semax 101124758Semaxint32_t 102124758Semaxcommon_profile_create_service_record_handle( 103124758Semax uint8_t *buf, uint8_t const * const eob, 104124758Semax uint8_t const *data, uint32_t datalen) 105124758Semax{ 106124758Semax if (buf + 5 > eob) 107124758Semax return (-1); 108124758Semax 109124758Semax SDP_PUT8(SDP_DATA_UINT32, buf); 110124758Semax SDP_PUT32(((provider_p) data)->handle, buf); 111124758Semax 112124758Semax return (5); 113124758Semax} 114124758Semax 115124758Semax/* 116124758Semax * seq8 len8 - 2 bytes 117124758Semax * uuid16 value16 - 3 bytes 118124758Semax * [ uuid16 value ] 119124758Semax */ 120124758Semax 121124758Semaxint32_t 122124758Semaxcommon_profile_create_service_class_id_list( 123124758Semax uint8_t *buf, uint8_t const * const eob, 124124758Semax uint8_t const *data, uint32_t datalen) 125124758Semax{ 126124758Semax int32_t len = 3 * (datalen >>= 1); 127124758Semax 128124758Semax if (len <= 0 || len > 0xff || buf + 2 + len > eob) 129124758Semax return (-1); 130124758Semax 131124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 132124758Semax SDP_PUT8(len, buf); 133124758Semax 134124758Semax for (; datalen > 0; datalen --) { 135124758Semax SDP_PUT8(SDP_DATA_UUID16, buf); 136132790Skan SDP_PUT16(*((uint16_t const *)data), buf); 137132790Skan data += sizeof(uint16_t); 138124758Semax } 139124758Semax 140124758Semax return (2 + len); 141124758Semax} 142124758Semax 143124758Semax/* 144124758Semax * seq8 len8 - 2 bytes 145124758Semax * seq 8 len8 - 2 bytes 146124758Semax * uuid16 value16 - 3 bytes 147124758Semax * uint16 value16 - 3 bytes 148124758Semax * [ seq 8 len8 149124758Semax * uuid16 value16 150124758Semax * uint16 value16 ] 151124758Semax */ 152124758Semax 153124758Semaxint32_t 154124758Semaxcommon_profile_create_bluetooth_profile_descriptor_list( 155124758Semax uint8_t *buf, uint8_t const * const eob, 156124758Semax uint8_t const *data, uint32_t datalen) 157124758Semax{ 158124758Semax int32_t len = 8 * (datalen >>= 2); 159124758Semax 160124758Semax if (len <= 0 || len > 0xff || buf + 2 + len > eob) 161124758Semax return (-1); 162124758Semax 163124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 164124758Semax SDP_PUT8(len, buf); 165124758Semax 166124758Semax for (; datalen > 0; datalen --) { 167124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 168124758Semax SDP_PUT8(6, buf); 169124758Semax SDP_PUT8(SDP_DATA_UUID16, buf); 170132790Skan SDP_PUT16(*((uint16_t const *)data), buf); 171132790Skan data += sizeof(uint16_t); 172124758Semax SDP_PUT8(SDP_DATA_UINT16, buf); 173132790Skan SDP_PUT16(*((uint16_t const *)data), buf); 174132790Skan data += sizeof(uint16_t); 175124758Semax } 176124758Semax 177124758Semax return (2 + len); 178124758Semax} 179124758Semax 180124758Semax/* 181124758Semax * seq8 len8 - 2 bytes 182124758Semax * uint16 value16 - 3 bytes 183124758Semax * uint16 value16 - 3 bytes 184124758Semax * uint16 value16 - 3 bytes 185124758Semax */ 186124758Semax 187124758Semaxint32_t 188124758Semaxcommon_profile_create_language_base_attribute_id_list( 189124758Semax uint8_t *buf, uint8_t const * const eob, 190124758Semax uint8_t const *data, uint32_t datalen) 191124758Semax{ 192124758Semax if (buf + 11 > eob) 193124758Semax return (-1); 194124758Semax 195124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 196124758Semax SDP_PUT8(9, buf); 197124758Semax 198124758Semax /* 199124758Semax * Language code per ISO 639:1988. Use "en". 200124758Semax */ 201124758Semax 202124758Semax SDP_PUT8(SDP_DATA_UINT16, buf); 203124758Semax SDP_PUT16(((0x65 << 8) | 0x6e), buf); 204124758Semax 205124758Semax /* 206124758Semax * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106 207124758Semax * (http://www.iana.org/assignments/character-sets) 208124758Semax */ 209124758Semax 210124758Semax SDP_PUT8(SDP_DATA_UINT16, buf); 211124758Semax SDP_PUT16(106, buf); 212124758Semax 213124758Semax /* 214124758Semax * Offset (Primary Language Base is 0x100) 215124758Semax */ 216124758Semax 217124758Semax SDP_PUT8(SDP_DATA_UINT16, buf); 218124758Semax SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf); 219124758Semax 220124758Semax return (11); 221124758Semax} 222124758Semax 223124758Semax/* 224124758Semax * Common provider name is "FreeBSD" 225124758Semax */ 226124758Semax 227124758Semaxint32_t 228124758Semaxcommon_profile_create_service_provider_name( 229124758Semax uint8_t *buf, uint8_t const * const eob, 230124758Semax uint8_t const *data, uint32_t datalen) 231124758Semax{ 232124758Semax char provider_name[] = "FreeBSD"; 233124758Semax 234124758Semax return (common_profile_create_string8(buf, eob, 235124758Semax (uint8_t const *) provider_name, 236124758Semax strlen(provider_name))); 237124758Semax} 238124758Semax 239124758Semax/* 240124758Semax * str8 len8 string 241124758Semax */ 242124758Semax 243124758Semaxint32_t 244124758Semaxcommon_profile_create_string8( 245124758Semax uint8_t *buf, uint8_t const * const eob, 246124758Semax uint8_t const *data, uint32_t datalen) 247124758Semax{ 248124758Semax if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob) 249124758Semax return (-1); 250124758Semax 251124758Semax SDP_PUT8(SDP_DATA_STR8, buf); 252124758Semax SDP_PUT8(datalen, buf); 253124758Semax memcpy(buf, data, datalen); 254124758Semax 255124758Semax return (2 + datalen); 256124758Semax} 257124758Semax 258124758Semax/* 259177358Semax * Service Availability 260177358Semax */ 261177358Semax 262177358Semaxint32_t 263177358Semaxcommon_profile_create_service_availability( 264177358Semax uint8_t *buf, uint8_t const * const eob, 265177358Semax uint8_t const *data, uint32_t datalen) 266177358Semax{ 267177358Semax if (datalen != 1 || buf + 2 > eob) 268177358Semax return (-1); 269177358Semax 270177358Semax SDP_PUT8(SDP_DATA_UINT8, buf); 271177358Semax SDP_PUT8(data[0], buf); 272177358Semax 273177358Semax return (2); 274177358Semax} 275177358Semax 276177358Semax/* 277124758Semax * seq8 len8 - 2 bytes 278124758Semax * seq8 len8 - 2 bytes 279124758Semax * uuid16 value16 - 3 bytes 280124758Semax * seq8 len8 - 2 bytes 281124758Semax * uuid16 value16 - 3 bytes 282124758Semax * uint8 value8 - 2 bytes 283124758Semax */ 284124758Semax 285124758Semaxint32_t 286124758Semaxrfcomm_profile_create_protocol_descriptor_list( 287124758Semax uint8_t *buf, uint8_t const * const eob, 288124758Semax uint8_t const *data, uint32_t datalen) 289124758Semax{ 290124758Semax if (datalen != 1 || buf + 14 > eob) 291124758Semax return (-1); 292124758Semax 293124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 294124758Semax SDP_PUT8(12, buf); 295124758Semax 296124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 297124758Semax SDP_PUT8(3, buf); 298124758Semax SDP_PUT8(SDP_DATA_UUID16, buf); 299124758Semax SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 300124758Semax 301124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 302124758Semax SDP_PUT8(5, buf); 303124758Semax SDP_PUT8(SDP_DATA_UUID16, buf); 304124758Semax SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf); 305124758Semax SDP_PUT8(SDP_DATA_UINT8, buf); 306124758Semax SDP_PUT8(*data, buf); 307124758Semax 308124758Semax return (14); 309124758Semax} 310124758Semax 311124758Semax/* 312124758Semax * seq8 len8 - 2 bytes 313124758Semax * seq8 len8 - 2 bytes 314124758Semax * uuid16 value16 - 3 bytes 315124758Semax * seq8 len8 - 2 bytes 316124758Semax * uuid16 value16 - 3 bytes 317124758Semax * uint8 value8 - 2 bytes 318124758Semax * seq8 len8 - 2 bytes 319124758Semax * uuid16 value16 - 3 bytes 320124758Semax */ 321124758Semax 322124758Semaxint32_t 323124758Semaxobex_profile_create_protocol_descriptor_list( 324124758Semax uint8_t *buf, uint8_t const * const eob, 325124758Semax uint8_t const *data, uint32_t datalen) 326124758Semax{ 327124758Semax if (datalen != 1 || buf + 19 > eob) 328124758Semax return (-1); 329124758Semax 330124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 331124758Semax SDP_PUT8(17, buf); 332124758Semax 333124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 334124758Semax SDP_PUT8(3, buf); 335124758Semax SDP_PUT8(SDP_DATA_UUID16, buf); 336124758Semax SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 337124758Semax 338124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 339124758Semax SDP_PUT8(5, buf); 340124758Semax SDP_PUT8(SDP_DATA_UUID16, buf); 341124758Semax SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf); 342124758Semax SDP_PUT8(SDP_DATA_UINT8, buf); 343124758Semax SDP_PUT8(*data, buf); 344124758Semax 345124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 346124758Semax SDP_PUT8(3, buf); 347124758Semax SDP_PUT8(SDP_DATA_UUID16, buf); 348124758Semax SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf); 349124758Semax 350124758Semax return (19); 351124758Semax} 352124758Semax 353124758Semax/* 354124758Semax * seq8 len8 355124758Semax * uint8 value8 - bytes 356124758Semax * [ uint8 value 8 ] 357124758Semax */ 358124758Semax 359124758Semaxint32_t 360124758Semaxobex_profile_create_supported_formats_list( 361124758Semax uint8_t *buf, uint8_t const * const eob, 362124758Semax uint8_t const *data, uint32_t datalen) 363124758Semax{ 364124758Semax int32_t len = 2 * datalen; 365124758Semax 366124758Semax if (len <= 0 || len > 0xff || buf + 2 + len > eob) 367124758Semax return (-1); 368124758Semax 369124758Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 370124758Semax SDP_PUT8(len, buf); 371124758Semax 372124758Semax for (; datalen > 0; datalen --) { 373124758Semax SDP_PUT8(SDP_DATA_UINT8, buf); 374124758Semax SDP_PUT8(*data++, buf); 375124758Semax } 376124758Semax 377124758Semax return (2 + len); 378124758Semax} 379124758Semax 380124758Semax/* 381177059Semax * do not check anything 382177059Semax */ 383177059Semax 384177059Semaxint32_t 385177059Semaxcommon_profile_always_valid(uint8_t const *data, uint32_t datalen) 386177059Semax{ 387177059Semax return (1); 388177059Semax} 389177059Semax 390177059Semax/* 391124758Semax * verify server channel number (the first byte in the data) 392124758Semax */ 393124758Semax 394124758Semaxint32_t 395124758Semaxcommon_profile_server_channel_valid(uint8_t const *data, uint32_t datalen) 396124758Semax{ 397124758Semax if (data[0] < 1 || data[0] > 30) 398124758Semax return (0); 399124758Semax 400124758Semax return (1); 401124758Semax} 402124758Semax 403124758Semax/* 404124758Semax * verify server channel number and supported_formats_size 405124758Semax * sdp_opush_profile and sdp_irmc_profile 406124758Semax */ 407124758Semax 408124758Semaxint32_t 409124758Semaxobex_profile_data_valid(uint8_t const *data, uint32_t datalen) 410124758Semax{ 411124758Semax sdp_opush_profile_p opush = (sdp_opush_profile_p) data; 412124758Semax 413124758Semax if (opush->server_channel < 1 || 414124758Semax opush->server_channel > 30 || 415124758Semax opush->supported_formats_size == 0 || 416124758Semax opush->supported_formats_size > sizeof(opush->supported_formats)) 417124758Semax return (0); 418124758Semax 419124758Semax return (1); 420124758Semax} 421124758Semax 422177059Semax/* 423177059Semax * BNEP protocol descriptor 424177059Semax */ 425177059Semax 426177059Semaxint32_t 427177059Semaxbnep_profile_create_protocol_descriptor_list( 428177059Semax uint8_t *buf, uint8_t const * const eob, 429177059Semax uint8_t const *data, uint32_t datalen) 430177059Semax{ 431177059Semax /* supported protocol types */ 432177059Semax uint16_t ptype[] = { 433177059Semax 0x0800, /* IPv4 */ 434177059Semax 0x0806, /* ARP */ 435177059Semax#ifdef INET6 436177059Semax 0x86dd, /* IPv6 */ 437177059Semax#endif 438177059Semax }; 439177059Semax 440177358Semax uint16_t i, psm, version = 0x0100, 441177059Semax nptypes = sizeof(ptype)/sizeof(ptype[0]), 442177059Semax nptypes_size = nptypes * 3; 443177059Semax 444177358Semax if (datalen != 2 || 18 + nptypes_size > 255 || 445177358Semax buf + 20 + nptypes_size > eob) 446177059Semax return (-1); 447177059Semax 448177358Semax memcpy(&psm, data, sizeof(psm)); 449177358Semax 450177059Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 451177059Semax SDP_PUT8(18 + nptypes_size, buf); 452177059Semax 453177059Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 454177059Semax SDP_PUT8(6, buf); 455177059Semax SDP_PUT8(SDP_DATA_UUID16, buf); 456177059Semax SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 457177059Semax SDP_PUT8(SDP_DATA_UINT16, buf); 458177059Semax SDP_PUT16(psm, buf); 459177059Semax 460177059Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 461177059Semax SDP_PUT8(8 + nptypes_size, buf); 462177059Semax SDP_PUT8(SDP_DATA_UUID16, buf); 463177059Semax SDP_PUT16(SDP_UUID_PROTOCOL_BNEP, buf); 464177059Semax SDP_PUT8(SDP_DATA_UINT16, buf); 465177059Semax SDP_PUT16(version, buf); 466177059Semax SDP_PUT8(SDP_DATA_SEQ8, buf); 467177059Semax SDP_PUT8(nptypes_size, buf); 468177059Semax for (i = 0; i < nptypes; i ++) { 469177059Semax SDP_PUT8(SDP_DATA_UINT16, buf); 470177059Semax SDP_PUT16(ptype[i], buf); 471177059Semax } 472177059Semax 473177059Semax return (20 + nptypes_size); 474177059Semax} 475177059Semax 476177059Semax/* 477177059Semax * BNEP security description 478177059Semax */ 479177059Semax 480177059Semaxint32_t 481177059Semaxbnep_profile_create_security_description( 482177059Semax uint8_t *buf, uint8_t const * const eob, 483177059Semax uint8_t const *data, uint32_t datalen) 484177059Semax{ 485177059Semax uint16_t security_descr; 486177059Semax 487177059Semax if (datalen != 2 || buf + 3 > eob) 488177059Semax return (-1); 489177059Semax 490177059Semax memcpy(&security_descr, data, sizeof(security_descr)); 491177059Semax 492177059Semax SDP_PUT8(SDP_DATA_UINT16, buf); 493177059Semax SDP_PUT16(security_descr, buf); 494177059Semax 495177059Semax return (3); 496177059Semax} 497177059Semax 498