search.c revision 121054
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: head/lib/libsdp/search.c 121054 2003-10-12 22:04:24Z emax $ 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, 47121054Semax u_int32_t plen, u_int16_t const *pp, 48121054Semax u_int32_t alen, u_int32_t const *ap, 49121054Semax u_int32_t vlen, sdp_attr_t *vp) 50121054Semax{ 51121054Semax struct sdp_xpdu { 52121054Semax sdp_pdu_t pdu; 53121054Semax u_int16_t len; 54121054Semax } __attribute__ ((packed)) xpdu; 55121054Semax 56121054Semax sdp_session_p ss = (sdp_session_p) xss; 57121054Semax u_int8_t *req = NULL, *rsp = NULL, *rsp_tmp = NULL; 58121054Semax int32_t type, len; 59121054Semax 60121054Semax if (ss == NULL) 61121054Semax return (-1); 62121054Semax 63121054Semax if (ss->req == NULL || ss->rsp == NULL || 64121054Semax plen == 0 || pp == NULL || alen == 0 || ap == NULL) { 65121054Semax ss->error = EINVAL; 66121054Semax return (-1); 67121054Semax } 68121054Semax 69121054Semax /* Calculate length of the request */ 70121054Semax req = ss->req; 71121054Semax plen = plen * (sizeof(pp[0]) + 1); 72121054Semax alen = alen * (sizeof(ap[0]) + 1); 73121054Semax 74121054Semax len = plen + sizeof(u_int8_t) + sizeof(u_int16_t) + 75121054Semax /* ServiceSearchPattern */ 76121054Semax sizeof(u_int16_t) + 77121054Semax /* MaximumAttributeByteCount */ 78121054Semax alen + sizeof(u_int8_t) + sizeof(u_int16_t); 79121054Semax /* AttributeIDList */ 80121054Semax 81121054Semax if (ss->req_e - req < len) { 82121054Semax ss->error = ENOBUFS; 83121054Semax return (-1); 84121054Semax } 85121054Semax 86121054Semax /* Put ServiceSearchPattern */ 87121054Semax SDP_PUT8(SDP_DATA_SEQ16, req); 88121054Semax SDP_PUT16(plen, req); 89121054Semax for (; plen > 0; pp ++, plen -= (sizeof(pp[0]) + 1)) { 90121054Semax SDP_PUT8(SDP_DATA_UUID16, req); 91121054Semax SDP_PUT16(*pp, req); 92121054Semax } 93121054Semax 94121054Semax /* Put MaximumAttributeByteCount */ 95121054Semax SDP_PUT16(0xffff, req); 96121054Semax 97121054Semax /* Put AttributeIDList */ 98121054Semax SDP_PUT8(SDP_DATA_SEQ16, req); 99121054Semax SDP_PUT16(alen, req); 100121054Semax for (; alen > 0; ap ++, alen -= (sizeof(ap[0]) + 1)) { 101121054Semax SDP_PUT8(SDP_DATA_UINT32, req); 102121054Semax SDP_PUT32(*ap, req); 103121054Semax } 104121054Semax 105121054Semax /* Submit ServiceSearchAttributeRequest and wait for response */ 106121054Semax ss->cslen = 0; 107121054Semax rsp = ss->rsp; 108121054Semax 109121054Semax do { 110121054Semax struct iovec iov[2]; 111121054Semax u_int8_t *req_cs = req; 112121054Semax 113121054Semax /* Add continuation state (if any) */ 114121054Semax if (ss->req_e - req_cs < ss->cslen + 1) { 115121054Semax ss->error = ENOBUFS; 116121054Semax return (-1); 117121054Semax } 118121054Semax 119121054Semax SDP_PUT8(ss->cslen, req_cs); 120121054Semax if (ss->cslen > 0) { 121121054Semax memcpy(req_cs, ss->cs, ss->cslen); 122121054Semax req_cs += ss->cslen; 123121054Semax } 124121054Semax 125121054Semax /* Prepare SDP PDU header */ 126121054Semax xpdu.pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST; 127121054Semax xpdu.pdu.tid = htons(ss->tid); 128121054Semax xpdu.pdu.len = htons(req_cs - ss->req); 129121054Semax 130121054Semax /* Submit request */ 131121054Semax iov[0].iov_base = (void *) &xpdu; 132121054Semax iov[0].iov_len = sizeof(xpdu.pdu); 133121054Semax iov[1].iov_base = (void *) ss->req; 134121054Semax iov[1].iov_len = req_cs - ss->req; 135121054Semax 136121054Semax len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0])); 137121054Semax if (len < 0) { 138121054Semax ss->error = errno; 139121054Semax return (-1); 140121054Semax } 141121054Semax 142121054Semax /* Read response */ 143121054Semax iov[0].iov_base = (void *) &xpdu; 144121054Semax iov[0].iov_len = sizeof(xpdu); 145121054Semax iov[1].iov_base = (void *) rsp; 146121054Semax iov[1].iov_len = ss->imtu; 147121054Semax 148121054Semax len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0])); 149121054Semax if (len < 0) { 150121054Semax ss->error = errno; 151121054Semax return (-1); 152121054Semax } 153121054Semax if (len < sizeof(xpdu)) { 154121054Semax ss->error = ENOMSG; 155121054Semax return (-1); 156121054Semax } 157121054Semax 158121054Semax xpdu.pdu.tid = ntohs(xpdu.pdu.tid); 159121054Semax xpdu.pdu.len = ntohs(xpdu.pdu.len); 160121054Semax xpdu.len = ntohs(xpdu.len); 161121054Semax 162121054Semax if (xpdu.pdu.pid == SDP_PDU_ERROR_RESPONSE || 163121054Semax xpdu.pdu.tid != ss->tid || 164121054Semax xpdu.len > xpdu.pdu.len) { 165121054Semax ss->error = EIO; 166121054Semax return (-1); 167121054Semax } 168121054Semax 169121054Semax /* Save continuation state (if any) */ 170121054Semax ss->cslen = rsp[xpdu.len]; 171121054Semax if (ss->cslen > 0) { 172121054Semax if (ss->cslen > sizeof(ss->cs)) { 173121054Semax ss->error = ENOBUFS; 174121054Semax return (-1); 175121054Semax } 176121054Semax 177121054Semax memcpy(ss->cs, rsp + xpdu.len + 1, ss->cslen); 178121054Semax 179121054Semax /* 180121054Semax * Ensure that we always have ss->imtu bytes 181121054Semax * available in the ss->rsp buffer 182121054Semax */ 183121054Semax 184121054Semax if (ss->rsp_e - rsp <= ss->imtu) { 185121054Semax u_int32_t size, offset; 186121054Semax 187121054Semax size = ss->rsp_e - ss->rsp + ss->imtu; 188121054Semax offset = rsp - ss->rsp; 189121054Semax 190121054Semax rsp_tmp = realloc(ss->rsp, size); 191121054Semax if (rsp_tmp == NULL) { 192121054Semax ss->error = ENOMEM; 193121054Semax return (-1); 194121054Semax } 195121054Semax 196121054Semax ss->rsp = rsp_tmp; 197121054Semax ss->rsp_e = ss->rsp + size; 198121054Semax rsp = ss->rsp + offset; 199121054Semax } 200121054Semax } 201121054Semax 202121054Semax rsp += xpdu.len; 203121054Semax ss->tid ++; 204121054Semax } while (ss->cslen > 0); 205121054Semax 206121054Semax /* 207121054Semax * If we got here then we have completed SDP transaction and now 208121054Semax * we must populate attribute values into vp array. At this point 209121054Semax * ss->rsp points to the beginning of the response and rsp points 210121054Semax * to the end of the response. 211121054Semax * 212121054Semax * From Bluetooth v1.1 spec page 364 213121054Semax * 214121054Semax * The AttributeLists is a data element sequence where each element 215121054Semax * in turn is a data element sequence representing an attribute list. 216121054Semax * Each attribute list contains attribute IDs and attribute values 217121054Semax * from one service record. The first element in each attribute list 218121054Semax * contains the attribute ID of the first attribute to be returned for 219121054Semax * that service record. The second element in each attribute list 220121054Semax * contains the corresponding attribute value. Successive pairs of 221121054Semax * elements in each attribute list contain additional attribute ID 222121054Semax * and value pairs. Only attributes that have non-null values within 223121054Semax * the service record and whose attribute IDs were specified in the 224121054Semax * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists 225121054Semax * Neither an attribute ID nor attribute value is placed in 226121054Semax * AttributeLists for attributes in the service record that have no 227121054Semax * value. Within each attribute list, the attributes are listed in 228121054Semax * ascending order of attribute ID value. 229121054Semax */ 230121054Semax 231121054Semax if (vp == NULL) 232121054Semax goto done; 233121054Semax 234121054Semax rsp_tmp = ss->rsp; 235121054Semax 236121054Semax /* Skip the first SEQ */ 237121054Semax SDP_GET8(type, rsp_tmp); 238121054Semax switch (type) { 239121054Semax case SDP_DATA_SEQ8: 240121054Semax SDP_GET8(len, rsp_tmp); 241121054Semax break; 242121054Semax 243121054Semax case SDP_DATA_SEQ16: 244121054Semax SDP_GET16(len, rsp_tmp); 245121054Semax break; 246121054Semax 247121054Semax case SDP_DATA_SEQ32: 248121054Semax SDP_GET32(len, rsp_tmp); 249121054Semax break; 250121054Semax 251121054Semax default: 252121054Semax ss->error = ENOATTR; 253121054Semax return (-1); 254121054Semax /* NOT REACHED */ 255121054Semax } 256121054Semax 257121054Semax for (; rsp_tmp < rsp && vlen > 0; ) { 258121054Semax /* Get set of attributes for the next record */ 259121054Semax SDP_GET8(type, rsp_tmp); 260121054Semax switch (type) { 261121054Semax case SDP_DATA_SEQ8: 262121054Semax SDP_GET8(len, rsp_tmp); 263121054Semax break; 264121054Semax 265121054Semax case SDP_DATA_SEQ16: 266121054Semax SDP_GET16(len, rsp_tmp); 267121054Semax break; 268121054Semax 269121054Semax case SDP_DATA_SEQ32: 270121054Semax SDP_GET32(len, rsp_tmp); 271121054Semax break; 272121054Semax 273121054Semax default: 274121054Semax ss->error = ENOATTR; 275121054Semax return (-1); 276121054Semax /* NOT REACHED */ 277121054Semax } 278121054Semax 279121054Semax /* Now rsp_tmp points to list of (attr,value) pairs */ 280121054Semax for (; len > 0 && vlen > 0; vp ++, vlen --) { 281121054Semax /* Attribute */ 282121054Semax SDP_GET8(type, rsp_tmp); 283121054Semax if (type != SDP_DATA_UINT16) { 284121054Semax ss->error = ENOATTR; 285121054Semax return (-1); 286121054Semax } 287121054Semax SDP_GET16(vp->attr, rsp_tmp); 288121054Semax 289121054Semax /* Attribute value */ 290121054Semax switch (rsp_tmp[0]) { 291121054Semax case SDP_DATA_NIL: 292121054Semax alen = 0; 293121054Semax break; 294121054Semax 295121054Semax case SDP_DATA_UINT8: 296121054Semax case SDP_DATA_INT8: 297121054Semax case SDP_DATA_BOOL: 298121054Semax alen = sizeof(u_int8_t); 299121054Semax break; 300121054Semax 301121054Semax case SDP_DATA_UINT16: 302121054Semax case SDP_DATA_INT16: 303121054Semax case SDP_DATA_UUID16: 304121054Semax alen = sizeof(u_int16_t); 305121054Semax break; 306121054Semax 307121054Semax case SDP_DATA_UINT32: 308121054Semax case SDP_DATA_INT32: 309121054Semax case SDP_DATA_UUID32: 310121054Semax alen = sizeof(u_int32_t); 311121054Semax break; 312121054Semax 313121054Semax case SDP_DATA_UINT64: 314121054Semax case SDP_DATA_INT64: 315121054Semax alen = sizeof(u_int64_t); 316121054Semax break; 317121054Semax 318121054Semax case SDP_DATA_UINT128: 319121054Semax case SDP_DATA_INT128: 320121054Semax case SDP_DATA_UUID128: 321121054Semax alen = sizeof(u_int128_t); 322121054Semax break; 323121054Semax 324121054Semax case SDP_DATA_STR8: 325121054Semax case SDP_DATA_URL8: 326121054Semax case SDP_DATA_SEQ8: 327121054Semax case SDP_DATA_ALT8: 328121054Semax alen = rsp_tmp[1] + sizeof(u_int8_t); 329121054Semax break; 330121054Semax 331121054Semax case SDP_DATA_STR16: 332121054Semax case SDP_DATA_URL16: 333121054Semax case SDP_DATA_SEQ16: 334121054Semax case SDP_DATA_ALT16: 335121054Semax alen = ((u_int16_t)rsp_tmp[1] << 8) 336121054Semax | ((u_int16_t)rsp_tmp[2]); 337121054Semax alen += sizeof(u_int16_t); 338121054Semax break; 339121054Semax 340121054Semax case SDP_DATA_STR32: 341121054Semax case SDP_DATA_URL32: 342121054Semax case SDP_DATA_SEQ32: 343121054Semax case SDP_DATA_ALT32: 344121054Semax alen = ((u_int32_t)rsp_tmp[1] << 24) 345121054Semax | ((u_int32_t)rsp_tmp[2] << 16) 346121054Semax | ((u_int32_t)rsp_tmp[3] << 8) 347121054Semax | ((u_int32_t)rsp_tmp[4]); 348121054Semax alen += sizeof(u_int32_t); 349121054Semax break; 350121054Semax 351121054Semax default: 352121054Semax ss->error = ENOATTR; 353121054Semax return (-1); 354121054Semax /* NOT REACHED */ 355121054Semax } 356121054Semax 357121054Semax alen += sizeof(u_int8_t); 358121054Semax 359121054Semax if (vp->value != NULL) { 360121054Semax if (alen <= vp->vlen) { 361121054Semax vp->flags = SDP_ATTR_OK; 362121054Semax vp->vlen = alen; 363121054Semax } else 364121054Semax vp->flags = SDP_ATTR_TRUNCATED; 365121054Semax 366121054Semax memcpy(vp->value, rsp_tmp, vp->vlen); 367121054Semax } else 368121054Semax vp->flags = SDP_ATTR_INVALID; 369121054Semax 370121054Semax len -= ( 371121054Semax sizeof(u_int8_t) + sizeof(u_int16_t) + 372121054Semax alen 373121054Semax ); 374121054Semax 375121054Semax rsp_tmp += alen; 376121054Semax } 377121054Semax } 378121054Semaxdone: 379121054Semax ss->error = 0; 380121054Semax 381121054Semax return (0); 382121054Semax} 383121054Semax 384