1121054Semax/* 2121054Semax * search.c 3121054Semax * 4121054Semax * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5121054Semax * All rights reserved. 6121054Semax * 7121054Semax * Redistribution and use in source and binary forms, with or without 8121054Semax * modification, are permitted provided that the following conditions 9121054Semax * are met: 10121054Semax * 1. Redistributions of source code must retain the above copyright 11121054Semax * notice, this list of conditions and the following disclaimer. 12121054Semax * 2. Redistributions in binary form must reproduce the above copyright 13121054Semax * notice, this list of conditions and the following disclaimer in the 14121054Semax * documentation and/or other materials provided with the distribution. 15121054Semax * 16121054Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17121054Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18121054Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19121054Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20121054Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21121054Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22121054Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23121054Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24121054Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25121054Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26121054Semax * SUCH DAMAGE. 27121054Semax * 28121054Semax * $Id: search.c,v 1.2 2003/09/04 22:12:13 max Exp $ 29121054Semax * $FreeBSD$ 30121054Semax */ 31121054Semax 32121054Semax#include <sys/uio.h> 33121054Semax#include <netinet/in.h> 34121054Semax#include <arpa/inet.h> 35121054Semax#include <bluetooth.h> 36121054Semax#include <errno.h> 37121054Semax#include <stdio.h> 38121054Semax#include <stdlib.h> 39121054Semax#include <string.h> 40121054Semax#include <unistd.h> 41121054Semax 42121054Semax#include <sdp-int.h> 43121054Semax#include <sdp.h> 44121054Semax 45121054Semaxint32_t 46121054Semaxsdp_search(void *xss, 47124305Semax uint32_t plen, uint16_t const *pp, 48124305Semax uint32_t alen, uint32_t const *ap, 49124305Semax uint32_t vlen, sdp_attr_t *vp) 50121054Semax{ 51121054Semax struct sdp_xpdu { 52124305Semax sdp_pdu_t pdu; 53124305Semax uint16_t len; 54121054Semax } __attribute__ ((packed)) xpdu; 55121054Semax 56121054Semax sdp_session_p ss = (sdp_session_p) xss; 57124305Semax uint8_t *req = NULL, *rsp = NULL, *rsp_tmp = NULL; 58138633Semax int32_t t, len; 59138633Semax uint16_t lo, hi; 60121054Semax 61121054Semax if (ss == NULL) 62121054Semax return (-1); 63121054Semax 64121054Semax if (ss->req == NULL || ss->rsp == NULL || 65121054Semax plen == 0 || pp == NULL || alen == 0 || ap == NULL) { 66121054Semax ss->error = EINVAL; 67121054Semax return (-1); 68121054Semax } 69121054Semax 70121054Semax req = ss->req; 71138633Semax 72138633Semax /* Calculate ServiceSearchPattern length */ 73121054Semax plen = plen * (sizeof(pp[0]) + 1); 74121054Semax 75138633Semax /* Calculate AttributeIDList length */ 76138633Semax for (len = 0, t = 0; t < alen; t ++) { 77138633Semax lo = (uint16_t) (ap[t] >> 16); 78138633Semax hi = (uint16_t) (ap[t]); 79138633Semax 80138633Semax if (lo > hi) { 81138633Semax ss->error = EINVAL; 82138633Semax return (-1); 83138633Semax } 84138633Semax 85138633Semax if (lo != hi) 86138633Semax len += (sizeof(ap[t]) + 1); 87138633Semax else 88138633Semax len += (sizeof(lo) + 1); 89138633Semax } 90138633Semax alen = len; 91138633Semax 92138633Semax /* Calculate length of the request */ 93124305Semax len = plen + sizeof(uint8_t) + sizeof(uint16_t) + 94121054Semax /* ServiceSearchPattern */ 95124305Semax sizeof(uint16_t) + 96121054Semax /* MaximumAttributeByteCount */ 97124305Semax alen + sizeof(uint8_t) + sizeof(uint16_t); 98121054Semax /* AttributeIDList */ 99121054Semax 100121054Semax if (ss->req_e - req < len) { 101121054Semax ss->error = ENOBUFS; 102121054Semax return (-1); 103121054Semax } 104121054Semax 105121054Semax /* Put ServiceSearchPattern */ 106121054Semax SDP_PUT8(SDP_DATA_SEQ16, req); 107121054Semax SDP_PUT16(plen, req); 108121054Semax for (; plen > 0; pp ++, plen -= (sizeof(pp[0]) + 1)) { 109121054Semax SDP_PUT8(SDP_DATA_UUID16, req); 110121054Semax SDP_PUT16(*pp, req); 111121054Semax } 112121054Semax 113121054Semax /* Put MaximumAttributeByteCount */ 114121054Semax SDP_PUT16(0xffff, req); 115121054Semax 116121054Semax /* Put AttributeIDList */ 117121054Semax SDP_PUT8(SDP_DATA_SEQ16, req); 118121054Semax SDP_PUT16(alen, req); 119138633Semax for (; alen > 0; ap ++) { 120138633Semax lo = (uint16_t) (*ap >> 16); 121138633Semax hi = (uint16_t) (*ap); 122138633Semax 123138633Semax if (lo != hi) { 124138633Semax /* Put attribute range */ 125138633Semax SDP_PUT8(SDP_DATA_UINT32, req); 126138633Semax SDP_PUT32(*ap, req); 127138633Semax alen -= (sizeof(ap[0]) + 1); 128138633Semax } else { 129138633Semax /* Put attribute */ 130138633Semax SDP_PUT8(SDP_DATA_UINT16, req); 131138633Semax SDP_PUT16(lo, req); 132138633Semax alen -= (sizeof(lo) + 1); 133138633Semax } 134121054Semax } 135121054Semax 136121054Semax /* Submit ServiceSearchAttributeRequest and wait for response */ 137121054Semax ss->cslen = 0; 138121054Semax rsp = ss->rsp; 139121054Semax 140121054Semax do { 141121054Semax struct iovec iov[2]; 142124305Semax uint8_t *req_cs = req; 143121054Semax 144121054Semax /* Add continuation state (if any) */ 145121054Semax if (ss->req_e - req_cs < ss->cslen + 1) { 146121054Semax ss->error = ENOBUFS; 147121054Semax return (-1); 148121054Semax } 149121054Semax 150121054Semax SDP_PUT8(ss->cslen, req_cs); 151121054Semax if (ss->cslen > 0) { 152121054Semax memcpy(req_cs, ss->cs, ss->cslen); 153121054Semax req_cs += ss->cslen; 154121054Semax } 155121054Semax 156121054Semax /* Prepare SDP PDU header */ 157121054Semax xpdu.pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST; 158121054Semax xpdu.pdu.tid = htons(ss->tid); 159121054Semax xpdu.pdu.len = htons(req_cs - ss->req); 160121054Semax 161121054Semax /* Submit request */ 162121054Semax iov[0].iov_base = (void *) &xpdu; 163121054Semax iov[0].iov_len = sizeof(xpdu.pdu); 164121054Semax iov[1].iov_base = (void *) ss->req; 165121054Semax iov[1].iov_len = req_cs - ss->req; 166121054Semax 167124758Semax do { 168124758Semax len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0])); 169124758Semax } while (len < 0 && errno == EINTR); 170124758Semax 171121054Semax if (len < 0) { 172121054Semax ss->error = errno; 173121054Semax return (-1); 174121054Semax } 175121054Semax 176121054Semax /* Read response */ 177121054Semax iov[0].iov_base = (void *) &xpdu; 178121054Semax iov[0].iov_len = sizeof(xpdu); 179121054Semax iov[1].iov_base = (void *) rsp; 180121054Semax iov[1].iov_len = ss->imtu; 181121054Semax 182124758Semax do { 183124758Semax len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0])); 184124758Semax } while (len < 0 && errno == EINTR); 185124758Semax 186121054Semax if (len < 0) { 187121054Semax ss->error = errno; 188121054Semax return (-1); 189121054Semax } 190121054Semax if (len < sizeof(xpdu)) { 191121054Semax ss->error = ENOMSG; 192121054Semax return (-1); 193121054Semax } 194121054Semax 195121054Semax xpdu.pdu.tid = ntohs(xpdu.pdu.tid); 196121054Semax xpdu.pdu.len = ntohs(xpdu.pdu.len); 197121054Semax xpdu.len = ntohs(xpdu.len); 198121054Semax 199121054Semax if (xpdu.pdu.pid == SDP_PDU_ERROR_RESPONSE || 200121054Semax xpdu.pdu.tid != ss->tid || 201126297Semax xpdu.pdu.len > len || 202121054Semax xpdu.len > xpdu.pdu.len) { 203121054Semax ss->error = EIO; 204121054Semax return (-1); 205121054Semax } 206121054Semax 207173673Semax rsp += xpdu.len; 208173673Semax ss->tid ++; 209173673Semax 210121054Semax /* Save continuation state (if any) */ 211173673Semax ss->cslen = rsp[0]; 212121054Semax if (ss->cslen > 0) { 213121054Semax if (ss->cslen > sizeof(ss->cs)) { 214121054Semax ss->error = ENOBUFS; 215121054Semax return (-1); 216121054Semax } 217121054Semax 218173673Semax memcpy(ss->cs, rsp + 1, ss->cslen); 219121054Semax 220121054Semax /* 221121054Semax * Ensure that we always have ss->imtu bytes 222121054Semax * available in the ss->rsp buffer 223121054Semax */ 224121054Semax 225121054Semax if (ss->rsp_e - rsp <= ss->imtu) { 226124305Semax uint32_t size, offset; 227121054Semax 228121054Semax size = ss->rsp_e - ss->rsp + ss->imtu; 229121054Semax offset = rsp - ss->rsp; 230121054Semax 231121054Semax rsp_tmp = realloc(ss->rsp, size); 232121054Semax if (rsp_tmp == NULL) { 233121054Semax ss->error = ENOMEM; 234121054Semax return (-1); 235121054Semax } 236121054Semax 237121054Semax ss->rsp = rsp_tmp; 238121054Semax ss->rsp_e = ss->rsp + size; 239121054Semax rsp = ss->rsp + offset; 240121054Semax } 241121054Semax } 242121054Semax } while (ss->cslen > 0); 243121054Semax 244121054Semax /* 245121054Semax * If we got here then we have completed SDP transaction and now 246121054Semax * we must populate attribute values into vp array. At this point 247121054Semax * ss->rsp points to the beginning of the response and rsp points 248121054Semax * to the end of the response. 249121054Semax * 250121054Semax * From Bluetooth v1.1 spec page 364 251121054Semax * 252121054Semax * The AttributeLists is a data element sequence where each element 253121054Semax * in turn is a data element sequence representing an attribute list. 254121054Semax * Each attribute list contains attribute IDs and attribute values 255121054Semax * from one service record. The first element in each attribute list 256121054Semax * contains the attribute ID of the first attribute to be returned for 257121054Semax * that service record. The second element in each attribute list 258121054Semax * contains the corresponding attribute value. Successive pairs of 259121054Semax * elements in each attribute list contain additional attribute ID 260121054Semax * and value pairs. Only attributes that have non-null values within 261121054Semax * the service record and whose attribute IDs were specified in the 262121054Semax * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists 263121054Semax * Neither an attribute ID nor attribute value is placed in 264121054Semax * AttributeLists for attributes in the service record that have no 265121054Semax * value. Within each attribute list, the attributes are listed in 266121054Semax * ascending order of attribute ID value. 267121054Semax */ 268121054Semax 269121054Semax if (vp == NULL) 270121054Semax goto done; 271121054Semax 272121054Semax rsp_tmp = ss->rsp; 273121054Semax 274121054Semax /* Skip the first SEQ */ 275138633Semax SDP_GET8(t, rsp_tmp); 276138633Semax switch (t) { 277121054Semax case SDP_DATA_SEQ8: 278121054Semax SDP_GET8(len, rsp_tmp); 279121054Semax break; 280121054Semax 281121054Semax case SDP_DATA_SEQ16: 282121054Semax SDP_GET16(len, rsp_tmp); 283121054Semax break; 284121054Semax 285121054Semax case SDP_DATA_SEQ32: 286121054Semax SDP_GET32(len, rsp_tmp); 287121054Semax break; 288121054Semax 289121054Semax default: 290121054Semax ss->error = ENOATTR; 291121054Semax return (-1); 292121054Semax /* NOT REACHED */ 293121054Semax } 294121054Semax 295121054Semax for (; rsp_tmp < rsp && vlen > 0; ) { 296121054Semax /* Get set of attributes for the next record */ 297138633Semax SDP_GET8(t, rsp_tmp); 298138633Semax switch (t) { 299121054Semax case SDP_DATA_SEQ8: 300121054Semax SDP_GET8(len, rsp_tmp); 301121054Semax break; 302121054Semax 303121054Semax case SDP_DATA_SEQ16: 304121054Semax SDP_GET16(len, rsp_tmp); 305121054Semax break; 306121054Semax 307121054Semax case SDP_DATA_SEQ32: 308121054Semax SDP_GET32(len, rsp_tmp); 309121054Semax break; 310121054Semax 311121054Semax default: 312121054Semax ss->error = ENOATTR; 313121054Semax return (-1); 314121054Semax /* NOT REACHED */ 315121054Semax } 316121054Semax 317121054Semax /* Now rsp_tmp points to list of (attr,value) pairs */ 318121054Semax for (; len > 0 && vlen > 0; vp ++, vlen --) { 319121054Semax /* Attribute */ 320138633Semax SDP_GET8(t, rsp_tmp); 321138633Semax if (t != SDP_DATA_UINT16) { 322121054Semax ss->error = ENOATTR; 323121054Semax return (-1); 324121054Semax } 325121054Semax SDP_GET16(vp->attr, rsp_tmp); 326121054Semax 327121054Semax /* Attribute value */ 328121054Semax switch (rsp_tmp[0]) { 329121054Semax case SDP_DATA_NIL: 330121054Semax alen = 0; 331121054Semax break; 332121054Semax 333121054Semax case SDP_DATA_UINT8: 334121054Semax case SDP_DATA_INT8: 335121054Semax case SDP_DATA_BOOL: 336124305Semax alen = sizeof(uint8_t); 337121054Semax break; 338121054Semax 339121054Semax case SDP_DATA_UINT16: 340121054Semax case SDP_DATA_INT16: 341121054Semax case SDP_DATA_UUID16: 342124305Semax alen = sizeof(uint16_t); 343121054Semax break; 344121054Semax 345121054Semax case SDP_DATA_UINT32: 346121054Semax case SDP_DATA_INT32: 347121054Semax case SDP_DATA_UUID32: 348124305Semax alen = sizeof(uint32_t); 349121054Semax break; 350121054Semax 351121054Semax case SDP_DATA_UINT64: 352121054Semax case SDP_DATA_INT64: 353124305Semax alen = sizeof(uint64_t); 354121054Semax break; 355121054Semax 356121054Semax case SDP_DATA_UINT128: 357121054Semax case SDP_DATA_INT128: 358121054Semax case SDP_DATA_UUID128: 359124305Semax alen = sizeof(uint128_t); 360121054Semax break; 361121054Semax 362121054Semax case SDP_DATA_STR8: 363121054Semax case SDP_DATA_URL8: 364121054Semax case SDP_DATA_SEQ8: 365121054Semax case SDP_DATA_ALT8: 366124305Semax alen = rsp_tmp[1] + sizeof(uint8_t); 367121054Semax break; 368121054Semax 369121054Semax case SDP_DATA_STR16: 370121054Semax case SDP_DATA_URL16: 371121054Semax case SDP_DATA_SEQ16: 372121054Semax case SDP_DATA_ALT16: 373124305Semax alen = ((uint16_t)rsp_tmp[1] << 8) 374124305Semax | ((uint16_t)rsp_tmp[2]); 375124305Semax alen += sizeof(uint16_t); 376121054Semax break; 377121054Semax 378121054Semax case SDP_DATA_STR32: 379121054Semax case SDP_DATA_URL32: 380121054Semax case SDP_DATA_SEQ32: 381121054Semax case SDP_DATA_ALT32: 382124305Semax alen = ((uint32_t)rsp_tmp[1] << 24) 383124305Semax | ((uint32_t)rsp_tmp[2] << 16) 384124305Semax | ((uint32_t)rsp_tmp[3] << 8) 385124305Semax | ((uint32_t)rsp_tmp[4]); 386124305Semax alen += sizeof(uint32_t); 387121054Semax break; 388121054Semax 389121054Semax default: 390121054Semax ss->error = ENOATTR; 391121054Semax return (-1); 392121054Semax /* NOT REACHED */ 393121054Semax } 394121054Semax 395124305Semax alen += sizeof(uint8_t); 396121054Semax 397121054Semax if (vp->value != NULL) { 398121054Semax if (alen <= vp->vlen) { 399121054Semax vp->flags = SDP_ATTR_OK; 400121054Semax vp->vlen = alen; 401121054Semax } else 402121054Semax vp->flags = SDP_ATTR_TRUNCATED; 403121054Semax 404121054Semax memcpy(vp->value, rsp_tmp, vp->vlen); 405121054Semax } else 406121054Semax vp->flags = SDP_ATTR_INVALID; 407121054Semax 408121054Semax len -= ( 409124305Semax sizeof(uint8_t) + sizeof(uint16_t) + 410121054Semax alen 411121054Semax ); 412121054Semax 413121054Semax rsp_tmp += alen; 414121054Semax } 415121054Semax } 416121054Semaxdone: 417121054Semax ss->error = 0; 418121054Semax 419121054Semax return (0); 420121054Semax} 421121054Semax 422