search.c revision 121472
1/* 2 * search.c 3 * 4 * Copyright (c) 2001-2003 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: search.c,v 1.2 2003/09/04 22:12:13 max Exp $ 29 * $FreeBSD: head/lib/libsdp/search.c 121472 2003-10-24 18:26:30Z ume $ 30 */ 31 32#include <sys/types.h> 33#include <sys/uio.h> 34#include <netinet/in.h> 35#include <arpa/inet.h> 36#include <bluetooth.h> 37#include <errno.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <unistd.h> 42 43#include <sdp-int.h> 44#include <sdp.h> 45 46int32_t 47sdp_search(void *xss, 48 u_int32_t plen, u_int16_t const *pp, 49 u_int32_t alen, u_int32_t const *ap, 50 u_int32_t vlen, sdp_attr_t *vp) 51{ 52 struct sdp_xpdu { 53 sdp_pdu_t pdu; 54 u_int16_t len; 55 } __attribute__ ((packed)) xpdu; 56 57 sdp_session_p ss = (sdp_session_p) xss; 58 u_int8_t *req = NULL, *rsp = NULL, *rsp_tmp = NULL; 59 int32_t type, len; 60 61 if (ss == NULL) 62 return (-1); 63 64 if (ss->req == NULL || ss->rsp == NULL || 65 plen == 0 || pp == NULL || alen == 0 || ap == NULL) { 66 ss->error = EINVAL; 67 return (-1); 68 } 69 70 /* Calculate length of the request */ 71 req = ss->req; 72 plen = plen * (sizeof(pp[0]) + 1); 73 alen = alen * (sizeof(ap[0]) + 1); 74 75 len = plen + sizeof(u_int8_t) + sizeof(u_int16_t) + 76 /* ServiceSearchPattern */ 77 sizeof(u_int16_t) + 78 /* MaximumAttributeByteCount */ 79 alen + sizeof(u_int8_t) + sizeof(u_int16_t); 80 /* AttributeIDList */ 81 82 if (ss->req_e - req < len) { 83 ss->error = ENOBUFS; 84 return (-1); 85 } 86 87 /* Put ServiceSearchPattern */ 88 SDP_PUT8(SDP_DATA_SEQ16, req); 89 SDP_PUT16(plen, req); 90 for (; plen > 0; pp ++, plen -= (sizeof(pp[0]) + 1)) { 91 SDP_PUT8(SDP_DATA_UUID16, req); 92 SDP_PUT16(*pp, req); 93 } 94 95 /* Put MaximumAttributeByteCount */ 96 SDP_PUT16(0xffff, req); 97 98 /* Put AttributeIDList */ 99 SDP_PUT8(SDP_DATA_SEQ16, req); 100 SDP_PUT16(alen, req); 101 for (; alen > 0; ap ++, alen -= (sizeof(ap[0]) + 1)) { 102 SDP_PUT8(SDP_DATA_UINT32, req); 103 SDP_PUT32(*ap, req); 104 } 105 106 /* Submit ServiceSearchAttributeRequest and wait for response */ 107 ss->cslen = 0; 108 rsp = ss->rsp; 109 110 do { 111 struct iovec iov[2]; 112 u_int8_t *req_cs = req; 113 114 /* Add continuation state (if any) */ 115 if (ss->req_e - req_cs < ss->cslen + 1) { 116 ss->error = ENOBUFS; 117 return (-1); 118 } 119 120 SDP_PUT8(ss->cslen, req_cs); 121 if (ss->cslen > 0) { 122 memcpy(req_cs, ss->cs, ss->cslen); 123 req_cs += ss->cslen; 124 } 125 126 /* Prepare SDP PDU header */ 127 xpdu.pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST; 128 xpdu.pdu.tid = htons(ss->tid); 129 xpdu.pdu.len = htons(req_cs - ss->req); 130 131 /* Submit request */ 132 iov[0].iov_base = (void *) &xpdu; 133 iov[0].iov_len = sizeof(xpdu.pdu); 134 iov[1].iov_base = (void *) ss->req; 135 iov[1].iov_len = req_cs - ss->req; 136 137 len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0])); 138 if (len < 0) { 139 ss->error = errno; 140 return (-1); 141 } 142 143 /* Read response */ 144 iov[0].iov_base = (void *) &xpdu; 145 iov[0].iov_len = sizeof(xpdu); 146 iov[1].iov_base = (void *) rsp; 147 iov[1].iov_len = ss->imtu; 148 149 len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0])); 150 if (len < 0) { 151 ss->error = errno; 152 return (-1); 153 } 154 if (len < sizeof(xpdu)) { 155 ss->error = ENOMSG; 156 return (-1); 157 } 158 159 xpdu.pdu.tid = ntohs(xpdu.pdu.tid); 160 xpdu.pdu.len = ntohs(xpdu.pdu.len); 161 xpdu.len = ntohs(xpdu.len); 162 163 if (xpdu.pdu.pid == SDP_PDU_ERROR_RESPONSE || 164 xpdu.pdu.tid != ss->tid || 165 xpdu.len > xpdu.pdu.len) { 166 ss->error = EIO; 167 return (-1); 168 } 169 170 /* Save continuation state (if any) */ 171 ss->cslen = rsp[xpdu.len]; 172 if (ss->cslen > 0) { 173 if (ss->cslen > sizeof(ss->cs)) { 174 ss->error = ENOBUFS; 175 return (-1); 176 } 177 178 memcpy(ss->cs, rsp + xpdu.len + 1, ss->cslen); 179 180 /* 181 * Ensure that we always have ss->imtu bytes 182 * available in the ss->rsp buffer 183 */ 184 185 if (ss->rsp_e - rsp <= ss->imtu) { 186 u_int32_t size, offset; 187 188 size = ss->rsp_e - ss->rsp + ss->imtu; 189 offset = rsp - ss->rsp; 190 191 rsp_tmp = realloc(ss->rsp, size); 192 if (rsp_tmp == NULL) { 193 ss->error = ENOMEM; 194 return (-1); 195 } 196 197 ss->rsp = rsp_tmp; 198 ss->rsp_e = ss->rsp + size; 199 rsp = ss->rsp + offset; 200 } 201 } 202 203 rsp += xpdu.len; 204 ss->tid ++; 205 } while (ss->cslen > 0); 206 207 /* 208 * If we got here then we have completed SDP transaction and now 209 * we must populate attribute values into vp array. At this point 210 * ss->rsp points to the beginning of the response and rsp points 211 * to the end of the response. 212 * 213 * From Bluetooth v1.1 spec page 364 214 * 215 * The AttributeLists is a data element sequence where each element 216 * in turn is a data element sequence representing an attribute list. 217 * Each attribute list contains attribute IDs and attribute values 218 * from one service record. The first element in each attribute list 219 * contains the attribute ID of the first attribute to be returned for 220 * that service record. The second element in each attribute list 221 * contains the corresponding attribute value. Successive pairs of 222 * elements in each attribute list contain additional attribute ID 223 * and value pairs. Only attributes that have non-null values within 224 * the service record and whose attribute IDs were specified in the 225 * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists 226 * Neither an attribute ID nor attribute value is placed in 227 * AttributeLists for attributes in the service record that have no 228 * value. Within each attribute list, the attributes are listed in 229 * ascending order of attribute ID value. 230 */ 231 232 if (vp == NULL) 233 goto done; 234 235 rsp_tmp = ss->rsp; 236 237 /* Skip the first SEQ */ 238 SDP_GET8(type, rsp_tmp); 239 switch (type) { 240 case SDP_DATA_SEQ8: 241 SDP_GET8(len, rsp_tmp); 242 break; 243 244 case SDP_DATA_SEQ16: 245 SDP_GET16(len, rsp_tmp); 246 break; 247 248 case SDP_DATA_SEQ32: 249 SDP_GET32(len, rsp_tmp); 250 break; 251 252 default: 253 ss->error = ENOATTR; 254 return (-1); 255 /* NOT REACHED */ 256 } 257 258 for (; rsp_tmp < rsp && vlen > 0; ) { 259 /* Get set of attributes for the next record */ 260 SDP_GET8(type, rsp_tmp); 261 switch (type) { 262 case SDP_DATA_SEQ8: 263 SDP_GET8(len, rsp_tmp); 264 break; 265 266 case SDP_DATA_SEQ16: 267 SDP_GET16(len, rsp_tmp); 268 break; 269 270 case SDP_DATA_SEQ32: 271 SDP_GET32(len, rsp_tmp); 272 break; 273 274 default: 275 ss->error = ENOATTR; 276 return (-1); 277 /* NOT REACHED */ 278 } 279 280 /* Now rsp_tmp points to list of (attr,value) pairs */ 281 for (; len > 0 && vlen > 0; vp ++, vlen --) { 282 /* Attribute */ 283 SDP_GET8(type, rsp_tmp); 284 if (type != SDP_DATA_UINT16) { 285 ss->error = ENOATTR; 286 return (-1); 287 } 288 SDP_GET16(vp->attr, rsp_tmp); 289 290 /* Attribute value */ 291 switch (rsp_tmp[0]) { 292 case SDP_DATA_NIL: 293 alen = 0; 294 break; 295 296 case SDP_DATA_UINT8: 297 case SDP_DATA_INT8: 298 case SDP_DATA_BOOL: 299 alen = sizeof(u_int8_t); 300 break; 301 302 case SDP_DATA_UINT16: 303 case SDP_DATA_INT16: 304 case SDP_DATA_UUID16: 305 alen = sizeof(u_int16_t); 306 break; 307 308 case SDP_DATA_UINT32: 309 case SDP_DATA_INT32: 310 case SDP_DATA_UUID32: 311 alen = sizeof(u_int32_t); 312 break; 313 314 case SDP_DATA_UINT64: 315 case SDP_DATA_INT64: 316 alen = sizeof(u_int64_t); 317 break; 318 319 case SDP_DATA_UINT128: 320 case SDP_DATA_INT128: 321 case SDP_DATA_UUID128: 322 alen = sizeof(u_int128_t); 323 break; 324 325 case SDP_DATA_STR8: 326 case SDP_DATA_URL8: 327 case SDP_DATA_SEQ8: 328 case SDP_DATA_ALT8: 329 alen = rsp_tmp[1] + sizeof(u_int8_t); 330 break; 331 332 case SDP_DATA_STR16: 333 case SDP_DATA_URL16: 334 case SDP_DATA_SEQ16: 335 case SDP_DATA_ALT16: 336 alen = ((u_int16_t)rsp_tmp[1] << 8) 337 | ((u_int16_t)rsp_tmp[2]); 338 alen += sizeof(u_int16_t); 339 break; 340 341 case SDP_DATA_STR32: 342 case SDP_DATA_URL32: 343 case SDP_DATA_SEQ32: 344 case SDP_DATA_ALT32: 345 alen = ((u_int32_t)rsp_tmp[1] << 24) 346 | ((u_int32_t)rsp_tmp[2] << 16) 347 | ((u_int32_t)rsp_tmp[3] << 8) 348 | ((u_int32_t)rsp_tmp[4]); 349 alen += sizeof(u_int32_t); 350 break; 351 352 default: 353 ss->error = ENOATTR; 354 return (-1); 355 /* NOT REACHED */ 356 } 357 358 alen += sizeof(u_int8_t); 359 360 if (vp->value != NULL) { 361 if (alen <= vp->vlen) { 362 vp->flags = SDP_ATTR_OK; 363 vp->vlen = alen; 364 } else 365 vp->flags = SDP_ATTR_TRUNCATED; 366 367 memcpy(vp->value, rsp_tmp, vp->vlen); 368 } else 369 vp->flags = SDP_ATTR_INVALID; 370 371 len -= ( 372 sizeof(u_int8_t) + sizeof(u_int16_t) + 373 alen 374 ); 375 376 rsp_tmp += alen; 377 } 378 } 379done: 380 ss->error = 0; 381 382 return (0); 383} 384 385