1 1.4 plunky /* $NetBSD: sdp_service.c,v 1.4 2010/11/20 12:12:21 plunky Exp $ */ 2 1.1 plunky 3 1.1 plunky /*- 4 1.1 plunky * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 1.1 plunky * All rights reserved. 6 1.1 plunky * 7 1.1 plunky * This code is derived from software contributed to The NetBSD Foundation 8 1.1 plunky * by Iain Hibbert. 9 1.1 plunky * 10 1.1 plunky * Redistribution and use in source and binary forms, with or without 11 1.1 plunky * modification, are permitted provided that the following conditions 12 1.1 plunky * are met: 13 1.1 plunky * 1. Redistributions of source code must retain the above copyright 14 1.1 plunky * notice, this list of conditions and the following disclaimer. 15 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 plunky * notice, this list of conditions and the following disclaimer in the 17 1.1 plunky * documentation and/or other materials provided with the distribution. 18 1.1 plunky * 19 1.1 plunky * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 plunky * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 plunky * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 plunky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 plunky * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 plunky * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 plunky * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 plunky * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 plunky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 plunky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 plunky * POSSIBILITY OF SUCH DAMAGE. 30 1.1 plunky */ 31 1.1 plunky 32 1.1 plunky #include <sys/cdefs.h> 33 1.4 plunky __RCSID("$NetBSD: sdp_service.c,v 1.4 2010/11/20 12:12:21 plunky Exp $"); 34 1.4 plunky 35 1.4 plunky #include <sys/atomic.h> 36 1.1 plunky 37 1.1 plunky #include <errno.h> 38 1.1 plunky #include <limits.h> 39 1.1 plunky #include <sdp.h> 40 1.1 plunky #include <stdlib.h> 41 1.1 plunky #include <string.h> 42 1.1 plunky #include <unistd.h> 43 1.1 plunky 44 1.1 plunky #include "sdp-int.h" 45 1.1 plunky 46 1.1 plunky /* 47 1.1 plunky * If AttributeIDList is given as NULL, request all attributes. 48 1.4 plunky * (this is actually const data but we can't declare it const) 49 1.1 plunky */ 50 1.1 plunky static uint8_t ail_default[] = { 0x0a, 0x00, 0x00, 0xff, 0xff }; 51 1.1 plunky 52 1.1 plunky /* 53 1.1 plunky * This provides the maximum size that the response buffer will be 54 1.1 plunky * allowed to grow to. 55 1.1 plunky * 56 1.1 plunky * Default is UINT16_MAX but it can be overridden at runtime. 57 1.1 plunky */ 58 1.1 plunky static size_t 59 1.1 plunky sdp_response_max(void) 60 1.1 plunky { 61 1.1 plunky static size_t max = UINT16_MAX; 62 1.4 plunky static unsigned int check = 1; 63 1.1 plunky char *env, *ep; 64 1.1 plunky unsigned long v; 65 1.1 plunky 66 1.4 plunky while (atomic_swap_uint(&check, 0)) { /* only check env once */ 67 1.1 plunky env = getenv("SDP_RESPONSE_MAX"); 68 1.1 plunky if (env == NULL) 69 1.1 plunky break; 70 1.1 plunky 71 1.1 plunky errno = 0; 72 1.1 plunky v = strtoul(env, &ep, 0); 73 1.1 plunky if (env[0] == '\0' || *ep != '\0') 74 1.1 plunky break; 75 1.1 plunky 76 1.1 plunky if (errno == ERANGE && v == ULONG_MAX) 77 1.1 plunky break; 78 1.1 plunky 79 1.1 plunky /* lower limit is arbitrary */ 80 1.1 plunky if (v < UINT8_MAX || v > UINT32_MAX) 81 1.1 plunky break; 82 1.1 plunky 83 1.1 plunky max = v; 84 1.1 plunky } 85 1.1 plunky 86 1.1 plunky return max; 87 1.1 plunky } 88 1.1 plunky 89 1.1 plunky bool 90 1.1 plunky sdp_service_search(struct sdp_session *ss, const sdp_data_t *ssp, 91 1.1 plunky uint32_t *id, int *num) 92 1.1 plunky { 93 1.1 plunky struct iovec req[5]; 94 1.1 plunky sdp_data_t hdr; 95 1.1 plunky uint8_t sdata[5], max[2]; 96 1.1 plunky uint8_t *ptr, *end; 97 1.1 plunky ssize_t len; 98 1.1 plunky uint16_t total, count, got; 99 1.1 plunky 100 1.1 plunky /* 101 1.1 plunky * setup ServiceSearchPattern 102 1.1 plunky */ 103 1.1 plunky len = ssp->end - ssp->next; 104 1.1 plunky if (len < 0 || len > UINT16_MAX) { 105 1.1 plunky errno = EINVAL; 106 1.1 plunky return false; 107 1.1 plunky } 108 1.1 plunky 109 1.1 plunky hdr.next = sdata; 110 1.1 plunky hdr.end = sdata + sizeof(sdata) + len; 111 1.1 plunky sdp_put_seq(&hdr, len); 112 1.1 plunky req[1].iov_base = sdata; 113 1.1 plunky req[1].iov_len = hdr.next - sdata; 114 1.1 plunky 115 1.1 plunky req[2].iov_base = ssp->next; 116 1.1 plunky req[2].iov_len = len; 117 1.1 plunky 118 1.1 plunky /* 119 1.1 plunky * setup MaximumServiceRecordCount 120 1.1 plunky */ 121 1.1 plunky if (*num < 0 || *num > UINT16_MAX) { 122 1.1 plunky errno = EINVAL; 123 1.1 plunky return false; 124 1.1 plunky } 125 1.1 plunky be16enc(max, *num); 126 1.1 plunky req[3].iov_base = max; 127 1.1 plunky req[3].iov_len = sizeof(uint16_t); 128 1.1 plunky 129 1.1 plunky /* 130 1.1 plunky * clear ContinuationState 131 1.1 plunky */ 132 1.1 plunky ss->cs[0] = 0; 133 1.1 plunky 134 1.1 plunky /* 135 1.1 plunky * ServiceSearch Transaction 136 1.1 plunky */ 137 1.1 plunky got = 0; 138 1.1 plunky for (;;) { 139 1.1 plunky /* 140 1.1 plunky * setup ContinuationState 141 1.1 plunky */ 142 1.1 plunky req[4].iov_base = ss->cs; 143 1.1 plunky req[4].iov_len = ss->cs[0] + 1; 144 1.1 plunky 145 1.1 plunky if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_REQUEST, 146 1.1 plunky req, __arraycount(req))) 147 1.1 plunky return false; 148 1.1 plunky 149 1.1 plunky len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_RESPONSE); 150 1.1 plunky if (len == -1) 151 1.1 plunky return false; 152 1.1 plunky 153 1.1 plunky ptr = ss->ibuf; 154 1.1 plunky end = ss->ibuf + len; 155 1.1 plunky 156 1.1 plunky /* 157 1.1 plunky * extract TotalServiceRecordCount 158 1.1 plunky */ 159 1.1 plunky if (ptr + sizeof(uint16_t) > end) 160 1.1 plunky break; 161 1.1 plunky 162 1.1 plunky total = be16dec(ptr); 163 1.1 plunky ptr += sizeof(uint16_t); 164 1.1 plunky if (total > *num) 165 1.1 plunky break; 166 1.1 plunky 167 1.1 plunky /* 168 1.1 plunky * extract CurrentServiceRecordCount 169 1.1 plunky */ 170 1.1 plunky if (ptr + sizeof(uint16_t) > end) 171 1.1 plunky break; 172 1.1 plunky 173 1.1 plunky count = be16dec(ptr); 174 1.1 plunky ptr += sizeof(uint16_t); 175 1.1 plunky if (got + count > total) 176 1.1 plunky break; 177 1.1 plunky 178 1.1 plunky /* 179 1.1 plunky * extract ServiceRecordHandleList 180 1.1 plunky */ 181 1.1 plunky if (ptr + count * sizeof(uint32_t) > end) 182 1.1 plunky break; 183 1.1 plunky 184 1.1 plunky while (count-- > 0) { 185 1.1 plunky id[got++] = be32dec(ptr); 186 1.1 plunky ptr += sizeof(uint32_t); 187 1.1 plunky } 188 1.1 plunky 189 1.1 plunky /* 190 1.1 plunky * extract ContinuationState 191 1.1 plunky */ 192 1.1 plunky if (ptr + 1 > end 193 1.1 plunky || ptr[0] > 16 194 1.1 plunky || ptr + ptr[0] + 1 != end) 195 1.1 plunky break; 196 1.1 plunky 197 1.3 plunky memcpy(ss->cs, ptr, (size_t)(ptr[0] + 1)); 198 1.1 plunky 199 1.1 plunky /* 200 1.1 plunky * Complete? 201 1.1 plunky */ 202 1.1 plunky if (ss->cs[0] == 0) { 203 1.1 plunky *num = got; 204 1.1 plunky return true; 205 1.1 plunky } 206 1.1 plunky } 207 1.1 plunky 208 1.1 plunky errno = EIO; 209 1.1 plunky return false; 210 1.1 plunky } 211 1.1 plunky 212 1.1 plunky bool 213 1.1 plunky sdp_service_attribute(struct sdp_session *ss, uint32_t id, 214 1.1 plunky const sdp_data_t *ail, sdp_data_t *rsp) 215 1.1 plunky { 216 1.1 plunky struct iovec req[6]; 217 1.1 plunky sdp_data_t hdr; 218 1.1 plunky uint8_t adata[5], handle[4], max[2]; 219 1.1 plunky uint8_t *ptr, *end, *rbuf; 220 1.1 plunky ssize_t len; 221 1.1 plunky size_t rlen, count; 222 1.1 plunky 223 1.1 plunky /* 224 1.1 plunky * setup ServiceRecordHandle 225 1.1 plunky */ 226 1.1 plunky be32enc(handle, id); 227 1.1 plunky req[1].iov_base = handle; 228 1.1 plunky req[1].iov_len = sizeof(uint32_t); 229 1.1 plunky 230 1.1 plunky /* 231 1.1 plunky * setup MaximumAttributeByteCount 232 1.1 plunky */ 233 1.1 plunky be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs)); 234 1.1 plunky req[2].iov_base = max; 235 1.1 plunky req[2].iov_len = sizeof(uint16_t); 236 1.1 plunky 237 1.1 plunky /* 238 1.1 plunky * setup AttributeIDList 239 1.1 plunky */ 240 1.2 plunky len = (ail == NULL ? (ssize_t)sizeof(ail_default) : (ail->end - ail->next)); 241 1.1 plunky if (len < 0 || len > UINT16_MAX) { 242 1.1 plunky errno = EINVAL; 243 1.1 plunky return false; 244 1.1 plunky } 245 1.1 plunky 246 1.1 plunky hdr.next = adata; 247 1.1 plunky hdr.end = adata + sizeof(adata) + len; 248 1.1 plunky sdp_put_seq(&hdr, len); 249 1.1 plunky req[3].iov_base = adata; 250 1.1 plunky req[3].iov_len = hdr.next - adata; 251 1.1 plunky 252 1.1 plunky req[4].iov_base = (ail == NULL ? ail_default : ail->next); 253 1.1 plunky req[4].iov_len = len; 254 1.1 plunky 255 1.1 plunky /* 256 1.1 plunky * clear ContinuationState 257 1.1 plunky */ 258 1.1 plunky ss->cs[0] = 0; 259 1.1 plunky 260 1.1 plunky /* 261 1.1 plunky * ServiceAttribute Transaction 262 1.1 plunky */ 263 1.1 plunky rlen = 0; 264 1.1 plunky for (;;) { 265 1.1 plunky /* 266 1.1 plunky * setup ContinuationState 267 1.1 plunky */ 268 1.1 plunky req[5].iov_base = ss->cs; 269 1.1 plunky req[5].iov_len = ss->cs[0] + 1; 270 1.1 plunky 271 1.1 plunky if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_REQUEST, 272 1.1 plunky req, __arraycount(req))) 273 1.1 plunky return false; 274 1.1 plunky 275 1.1 plunky len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE); 276 1.1 plunky if (len == -1) 277 1.1 plunky return false; 278 1.1 plunky 279 1.1 plunky ptr = ss->ibuf; 280 1.1 plunky end = ss->ibuf + len; 281 1.1 plunky 282 1.1 plunky /* 283 1.1 plunky * extract AttributeListByteCount 284 1.1 plunky */ 285 1.1 plunky if (ptr + sizeof(uint16_t) > end) 286 1.1 plunky break; 287 1.1 plunky 288 1.1 plunky count = be16dec(ptr); 289 1.1 plunky ptr += sizeof(uint16_t); 290 1.1 plunky if (count == 0 || ptr + count > end) 291 1.1 plunky break; 292 1.1 plunky 293 1.1 plunky /* 294 1.1 plunky * extract AttributeList 295 1.1 plunky */ 296 1.1 plunky if (rlen + count > sdp_response_max()) 297 1.1 plunky break; 298 1.1 plunky 299 1.1 plunky rbuf = realloc(ss->rbuf, rlen + count); 300 1.1 plunky if (rbuf == NULL) 301 1.1 plunky return false; 302 1.1 plunky 303 1.1 plunky ss->rbuf = rbuf; 304 1.1 plunky memcpy(rbuf + rlen, ptr, count); 305 1.1 plunky rlen += count; 306 1.1 plunky ptr += count; 307 1.1 plunky 308 1.1 plunky /* 309 1.1 plunky * extract ContinuationState 310 1.1 plunky */ 311 1.1 plunky if (ptr + 1 > end 312 1.1 plunky || ptr[0] > 16 313 1.1 plunky || ptr + ptr[0] + 1 != end) 314 1.1 plunky break; 315 1.1 plunky 316 1.3 plunky memcpy(ss->cs, ptr, (size_t)(ptr[0] + 1)); 317 1.1 plunky 318 1.1 plunky /* 319 1.1 plunky * Complete? 320 1.1 plunky */ 321 1.1 plunky if (ss->cs[0] == 0) { 322 1.1 plunky rsp->next = rbuf; 323 1.1 plunky rsp->end = rbuf + rlen; 324 1.2 plunky if (sdp_data_size(rsp) != (ssize_t)rlen 325 1.1 plunky || !sdp_data_valid(rsp) 326 1.1 plunky || !sdp_get_seq(rsp, rsp)) 327 1.1 plunky break; 328 1.1 plunky 329 1.1 plunky return true; 330 1.1 plunky } 331 1.1 plunky } 332 1.1 plunky 333 1.1 plunky errno = EIO; 334 1.1 plunky return false; 335 1.1 plunky } 336 1.1 plunky 337 1.1 plunky bool 338 1.1 plunky sdp_service_search_attribute(struct sdp_session *ss, const sdp_data_t *ssp, 339 1.1 plunky const sdp_data_t *ail, sdp_data_t *rsp) 340 1.1 plunky { 341 1.1 plunky struct iovec req[7]; 342 1.1 plunky sdp_data_t hdr; 343 1.1 plunky uint8_t sdata[5], adata[5], max[2]; 344 1.1 plunky uint8_t *ptr, *end, *rbuf; 345 1.1 plunky ssize_t len; 346 1.1 plunky size_t rlen, count; 347 1.1 plunky 348 1.1 plunky /* 349 1.1 plunky * setup ServiceSearchPattern 350 1.1 plunky */ 351 1.1 plunky len = ssp->end - ssp->next; 352 1.1 plunky if (len < 0 || len > UINT16_MAX) { 353 1.1 plunky errno = EINVAL; 354 1.1 plunky return false; 355 1.1 plunky } 356 1.1 plunky 357 1.1 plunky hdr.next = sdata; 358 1.1 plunky hdr.end = sdata + sizeof(sdata) + len; 359 1.1 plunky sdp_put_seq(&hdr, len); 360 1.1 plunky req[1].iov_base = sdata; 361 1.1 plunky req[1].iov_len = hdr.next - sdata; 362 1.1 plunky 363 1.1 plunky req[2].iov_base = ssp->next; 364 1.1 plunky req[2].iov_len = len; 365 1.1 plunky 366 1.1 plunky /* 367 1.1 plunky * setup MaximumAttributeByteCount 368 1.1 plunky */ 369 1.1 plunky be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs)); 370 1.1 plunky req[3].iov_base = max; 371 1.1 plunky req[3].iov_len = sizeof(uint16_t); 372 1.1 plunky 373 1.1 plunky /* 374 1.1 plunky * setup AttributeIDList 375 1.1 plunky */ 376 1.2 plunky len = (ail == NULL ? (ssize_t)sizeof(ail_default) : (ail->end - ail->next)); 377 1.1 plunky if (len < 0 || len > UINT16_MAX) { 378 1.1 plunky errno = EINVAL; 379 1.1 plunky return false; 380 1.1 plunky } 381 1.1 plunky 382 1.1 plunky hdr.next = adata; 383 1.1 plunky hdr.end = adata + sizeof(adata) + len; 384 1.1 plunky sdp_put_seq(&hdr, len); 385 1.1 plunky req[4].iov_base = adata; 386 1.1 plunky req[4].iov_len = hdr.next - adata; 387 1.1 plunky 388 1.1 plunky req[5].iov_base = (ail == NULL ? ail_default : ail->next); 389 1.1 plunky req[5].iov_len = len; 390 1.1 plunky 391 1.1 plunky /* 392 1.1 plunky * clear ContinuationState 393 1.1 plunky */ 394 1.1 plunky ss->cs[0] = 0; 395 1.1 plunky 396 1.1 plunky /* 397 1.1 plunky * ServiceSearchAttribute Transaction 398 1.1 plunky */ 399 1.1 plunky rlen = 0; 400 1.1 plunky for (;;) { 401 1.1 plunky /* 402 1.1 plunky * setup ContinuationState 403 1.1 plunky */ 404 1.1 plunky req[6].iov_base = ss->cs; 405 1.1 plunky req[6].iov_len = ss->cs[0] + 1; 406 1.1 plunky 407 1.1 plunky if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST, 408 1.1 plunky req, __arraycount(req))) 409 1.1 plunky return false; 410 1.1 plunky 411 1.1 plunky len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE); 412 1.1 plunky if (len == -1) 413 1.1 plunky return false; 414 1.1 plunky 415 1.1 plunky ptr = ss->ibuf; 416 1.1 plunky end = ss->ibuf + len; 417 1.1 plunky 418 1.1 plunky /* 419 1.1 plunky * extract AttributeListsByteCount 420 1.1 plunky */ 421 1.1 plunky if (ptr + sizeof(uint16_t) > end) 422 1.1 plunky break; 423 1.1 plunky 424 1.1 plunky count = be16dec(ptr); 425 1.1 plunky ptr += sizeof(uint16_t); 426 1.1 plunky if (count == 0 || ptr + count > end) 427 1.1 plunky break; 428 1.1 plunky 429 1.1 plunky /* 430 1.1 plunky * extract AttributeLists 431 1.1 plunky */ 432 1.1 plunky if (rlen + count > sdp_response_max()) 433 1.1 plunky break; 434 1.1 plunky 435 1.1 plunky rbuf = realloc(ss->rbuf, rlen + count); 436 1.1 plunky if (rbuf == NULL) 437 1.1 plunky return false; 438 1.1 plunky 439 1.1 plunky ss->rbuf = rbuf; 440 1.1 plunky memcpy(rbuf + rlen, ptr, count); 441 1.1 plunky rlen += count; 442 1.1 plunky ptr += count; 443 1.1 plunky 444 1.1 plunky /* 445 1.1 plunky * extract ContinuationState 446 1.1 plunky */ 447 1.1 plunky if (ptr + 1 > end 448 1.1 plunky || ptr[0] > 16 449 1.1 plunky || ptr + ptr[0] + 1 != end) 450 1.1 plunky break; 451 1.1 plunky 452 1.3 plunky memcpy(ss->cs, ptr, (size_t)(ptr[0] + 1)); 453 1.1 plunky 454 1.1 plunky /* 455 1.1 plunky * Complete? 456 1.1 plunky */ 457 1.1 plunky if (ss->cs[0] == 0) { 458 1.1 plunky rsp->next = rbuf; 459 1.1 plunky rsp->end = rbuf + rlen; 460 1.2 plunky if (sdp_data_size(rsp) != (ssize_t)rlen 461 1.1 plunky || !sdp_data_valid(rsp) 462 1.1 plunky || !sdp_get_seq(rsp, rsp)) 463 1.1 plunky break; 464 1.1 plunky 465 1.1 plunky return true; 466 1.1 plunky } 467 1.1 plunky } 468 1.1 plunky 469 1.1 plunky errno = EIO; 470 1.1 plunky return false; 471 1.1 plunky } 472