profile.c revision 124758
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: head/usr.sbin/bluetooth/sdpd/profile.c 124758 2004-01-20 20:48:26Z emax $ 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 43profile_p 44profile_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 77profile_attr_create_p 78profile_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 93int32_t 94common_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 113int32_t 114common_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 144int32_t 145common_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 176int32_t 177common_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 216int32_t 217common_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 232int32_t 233common_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 256int32_t 257rfcomm_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 293int32_t 294obex_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 330int32_t 331obex_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 355int32_t 356common_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 369int32_t 370obex_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