1 /* $NetBSD: sdp_get.c,v 1.1 2009/05/12 10:05:06 plunky Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Iain Hibbert. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: sdp_get.c,v 1.1 2009/05/12 10:05:06 plunky Exp $"); 34 35 #include <sdp.h> 36 #include <limits.h> 37 38 /****************************************************************************** 39 * sdp_get_xxxx(data, value) 40 * 41 * examine first SDP data element in list for xxx type, extracting to given 42 * storage and advancing pointer if found. 43 * - these functions will not modify data pointer unless the value was 44 * extracted successfully 45 * - these functions always update the data pointer before the value pointer, 46 * so where the value is a sdp_data_t the data struct can be discarded. 47 */ 48 49 bool 50 sdp_get_data(sdp_data_t *data, sdp_data_t *value) 51 { 52 uint8_t *p = data->next; 53 ssize_t l = sdp_data_size(data); 54 55 if (l == -1 56 || p + l > data->end) 57 return false; 58 59 data->next = p + l; 60 value->next = p; 61 value->end = p + l; 62 return true; 63 } 64 65 bool 66 sdp_get_attr(sdp_data_t *data, uint16_t *attr, sdp_data_t *value) 67 { 68 sdp_data_t v, d = *data; 69 uintmax_t a; 70 71 if (sdp_data_type(&d) != SDP_DATA_UINT16 72 || !sdp_get_uint(&d, &a) 73 || !sdp_get_data(&d, &v)) 74 return false; 75 76 *attr = (uint16_t)a; 77 *data = d; 78 *value = v; 79 return true; 80 } 81 82 bool 83 sdp_get_uuid(sdp_data_t *data, uuid_t *uuid) 84 { 85 uint8_t *p = data->next; 86 87 if (p + 1 > data->end) 88 return false; 89 90 switch (*p++) { 91 case SDP_DATA_UUID16: 92 if (p + 2 > data->end) 93 return false; 94 95 *uuid = BLUETOOTH_BASE_UUID; 96 uuid->time_low = be16dec(p); 97 p += 2; 98 break; 99 100 case SDP_DATA_UUID32: 101 if (p + 4 > data->end) 102 return false; 103 104 *uuid = BLUETOOTH_BASE_UUID; 105 uuid->time_low = be32dec(p); 106 p += 4; 107 break; 108 109 case SDP_DATA_UUID128: 110 if (p + 16 > data->end) 111 return false; 112 113 uuid_dec_be(p, uuid); 114 p += 16; 115 break; 116 117 default: 118 return false; 119 } 120 121 data->next = p; 122 return true; 123 } 124 125 bool 126 sdp_get_bool(sdp_data_t *data, bool *value) 127 { 128 uint8_t *p = data->next; 129 uint8_t v; 130 131 if (p + 1 > data->end) 132 return false; 133 134 switch (*p++) { 135 case SDP_DATA_BOOL: 136 if (p + 1 > data->end) 137 return false; 138 139 v = *p; 140 p += 1; 141 break; 142 143 default: 144 return false; 145 } 146 147 data->next = p; 148 *value = ((v != 0) ? true : false); 149 return true; 150 } 151 152 bool 153 sdp_get_uint(sdp_data_t *data, uintmax_t *value) 154 { 155 uint8_t *p = data->next; 156 uint64_t v, x; 157 158 if (p + 1 > data->end) 159 return false; 160 161 switch (*p++) { 162 case SDP_DATA_UINT8: 163 if (p + 1 > data->end) 164 return false; 165 166 v = *p; 167 p += 1; 168 break; 169 170 case SDP_DATA_UINT16: 171 if (p + 2 > data->end) 172 return false; 173 174 v = be16dec(p); 175 p += 2; 176 break; 177 178 case SDP_DATA_UINT32: 179 if (p + 4 > data->end) 180 return false; 181 182 v = be32dec(p); 183 p += 4; 184 break; 185 186 case SDP_DATA_UINT64: 187 if (p + 8 > data->end) 188 return false; 189 190 v = be64dec(p); 191 if (v > UINTMAX_MAX) 192 return false; 193 194 p += 8; 195 break; 196 197 case SDP_DATA_UINT128: 198 if (p + 16 > data->end) 199 return false; 200 201 x = be64dec(p); 202 v = be64dec(p + 8); 203 if (x != 0 || v > UINTMAX_MAX) 204 return false; 205 206 p += 16; 207 break; 208 209 default: 210 return false; 211 } 212 213 data->next = p; 214 *value = (uintmax_t)v; 215 return true; 216 } 217 218 bool 219 sdp_get_int(sdp_data_t *data, intmax_t *value) 220 { 221 uint8_t *p = data->next; 222 int64_t v, x; 223 224 if (p + 1 > data->end) 225 return false; 226 227 switch (*p++) { 228 case SDP_DATA_INT8: 229 if (p + 1 > data->end) 230 return false; 231 232 v = *(int8_t *)p; 233 p += 1; 234 break; 235 236 case SDP_DATA_INT16: 237 if (p + 2 > data->end) 238 return false; 239 240 v = (int16_t)be16dec(p); 241 p += 2; 242 break; 243 244 case SDP_DATA_INT32: 245 if (p + 4 > data->end) 246 return false; 247 248 v = (int32_t)be32dec(p); 249 p += 4; 250 break; 251 252 case SDP_DATA_INT64: 253 if (p + 8 > data->end) 254 return false; 255 256 v = (int64_t)be64dec(p); 257 if (v > INTMAX_MAX || v < INTMAX_MIN) 258 return false; 259 260 p += 8; 261 break; 262 263 case SDP_DATA_INT128: 264 if (p + 16 > data->end) 265 return false; 266 267 x = (int64_t)be64dec(p); 268 v = (int64_t)be64dec(p + 8); 269 if (x == 0) { 270 if (v > INTMAX_MAX) 271 return false; 272 } else if (x == -1) { 273 if (v < INTMAX_MIN) 274 return false; 275 } else { 276 return false; 277 } 278 279 p += 16; 280 break; 281 282 default: 283 return false; 284 } 285 286 data->next = p; 287 *value = (intmax_t)v; 288 return true; 289 } 290 291 static bool 292 _sdp_get_ext(uint8_t type, sdp_data_t *data, sdp_data_t *ext) 293 { 294 uint8_t *p = data->next; 295 uint32_t l; 296 297 if (p + 1 > data->end 298 || SDP_DATA_TYPE(*p) != type) 299 return false; 300 301 switch (SDP_DATA_SIZE(*p++)) { 302 case SDP_DATA_EXT8: 303 if (p + 1 > data->end) 304 return false; 305 306 l = *p; 307 p += 1; 308 break; 309 310 case SDP_DATA_EXT16: 311 if (p + 2 > data->end) 312 return false; 313 314 l = be16dec(p); 315 p += 2; 316 break; 317 318 case SDP_DATA_EXT32: 319 if (p + 4 > data->end) 320 return false; 321 322 l = be32dec(p); 323 p += 4; 324 break; 325 326 default: 327 return false; 328 } 329 330 if (p + l > data->end) 331 return false; 332 333 data->next = p + l; 334 ext->next = p; 335 ext->end = p + l; 336 return true; 337 } 338 339 bool 340 sdp_get_seq(sdp_data_t *data, sdp_data_t *seq) 341 { 342 343 return _sdp_get_ext(SDP_DATA_SEQ, data, seq); 344 } 345 346 bool 347 sdp_get_alt(sdp_data_t *data, sdp_data_t *alt) 348 { 349 350 return _sdp_get_ext(SDP_DATA_ALT, data, alt); 351 } 352 353 bool 354 sdp_get_str(sdp_data_t *data, char **str, size_t *len) 355 { 356 sdp_data_t s; 357 358 if (!_sdp_get_ext(SDP_DATA_STR, data, &s)) 359 return false; 360 361 *str = (char *)s.next; 362 *len = s.end - s.next; 363 return true; 364 } 365 366 bool 367 sdp_get_url(sdp_data_t *data, char **url, size_t *len) 368 { 369 sdp_data_t u; 370 371 if (!_sdp_get_ext(SDP_DATA_URL, data, &u)) 372 return false; 373 374 *url = (char *)u.next; 375 *len = u.end - u.next; 376 return true; 377 } 378