Home | History | Annotate | Line # | Download | only in libbluetooth
sdp_service.c revision 1.1
      1 /*	$NetBSD: sdp_service.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_service.c,v 1.1 2009/05/12 10:05:06 plunky Exp $");
     34 
     35 #include <errno.h>
     36 #include <limits.h>
     37 #include <sdp.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <unistd.h>
     41 
     42 #include "sdp-int.h"
     43 
     44 /*
     45  * If AttributeIDList is given as NULL, request all attributes.
     46  */
     47 static uint8_t ail_default[] = { 0x0a, 0x00, 0x00, 0xff, 0xff };
     48 
     49 /*
     50  * This provides the maximum size that the response buffer will be
     51  * allowed to grow to.
     52  *
     53  * Default is UINT16_MAX but it can be overridden at runtime.
     54  */
     55 static size_t
     56 sdp_response_max(void)
     57 {
     58 	static size_t max = UINT16_MAX;
     59 	static bool check = true;
     60 	char *env, *ep;
     61 	unsigned long v;
     62 
     63 	while (check) {
     64 		check = false;	/* only check env once */
     65 
     66 		env = getenv("SDP_RESPONSE_MAX");
     67 		if (env == NULL)
     68 			break;
     69 
     70 		errno = 0;
     71 		v = strtoul(env, &ep, 0);
     72 		if (env[0] == '\0' || *ep != '\0')
     73 			break;
     74 
     75 		if (errno == ERANGE && v == ULONG_MAX)
     76 			break;
     77 
     78 		/* lower limit is arbitrary */
     79 		if (v < UINT8_MAX || v > UINT32_MAX)
     80 			break;
     81 
     82 		max = v;
     83 	}
     84 
     85 	return max;
     86 }
     87 
     88 bool
     89 sdp_service_search(struct sdp_session *ss, const sdp_data_t *ssp,
     90     uint32_t *id, int *num)
     91 {
     92 	struct iovec	req[5];
     93 	sdp_data_t	hdr;
     94 	uint8_t		sdata[5], max[2];
     95 	uint8_t		*ptr, *end;
     96 	ssize_t		len;
     97 	uint16_t	total, count, got;
     98 
     99 	/*
    100 	 * setup ServiceSearchPattern
    101 	 */
    102 	len = ssp->end - ssp->next;
    103 	if (len < 0 || len > UINT16_MAX) {
    104 		errno = EINVAL;
    105 		return false;
    106 	}
    107 
    108 	hdr.next = sdata;
    109 	hdr.end = sdata + sizeof(sdata) + len;
    110 	sdp_put_seq(&hdr, len);
    111 	req[1].iov_base = sdata;
    112 	req[1].iov_len = hdr.next - sdata;
    113 
    114 	req[2].iov_base = ssp->next;
    115 	req[2].iov_len = len;
    116 
    117 	/*
    118 	 * setup MaximumServiceRecordCount
    119 	 */
    120 	if (*num < 0 || *num > UINT16_MAX) {
    121 		errno = EINVAL;
    122 		return false;
    123 	}
    124 	be16enc(max, *num);
    125 	req[3].iov_base = max;
    126 	req[3].iov_len = sizeof(uint16_t);
    127 
    128 	/*
    129 	 * clear ContinuationState
    130 	 */
    131 	ss->cs[0] = 0;
    132 
    133 	/*
    134 	 * ServiceSearch Transaction
    135 	 */
    136 	got = 0;
    137 	for (;;) {
    138 		/*
    139 		 * setup ContinuationState
    140 		 */
    141 		req[4].iov_base = ss->cs;
    142 		req[4].iov_len = ss->cs[0] + 1;
    143 
    144 		if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_REQUEST,
    145 		    req, __arraycount(req)))
    146 			return false;
    147 
    148 		len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_RESPONSE);
    149 		if (len == -1)
    150 			return false;
    151 
    152 		ptr = ss->ibuf;
    153 		end = ss->ibuf + len;
    154 
    155 		/*
    156 		 * extract TotalServiceRecordCount
    157 		 */
    158 		if (ptr + sizeof(uint16_t) > end)
    159 			break;
    160 
    161 		total = be16dec(ptr);
    162 		ptr += sizeof(uint16_t);
    163 		if (total > *num)
    164 			break;
    165 
    166 		/*
    167 		 * extract CurrentServiceRecordCount
    168 		 */
    169 		if (ptr + sizeof(uint16_t) > end)
    170 			break;
    171 
    172 		count = be16dec(ptr);
    173 		ptr += sizeof(uint16_t);
    174 		if (got + count > total)
    175 			break;
    176 
    177 		/*
    178 		 * extract ServiceRecordHandleList
    179 		 */
    180 		if (ptr + count * sizeof(uint32_t) > end)
    181 			break;
    182 
    183 		while (count-- > 0) {
    184 			id[got++] = be32dec(ptr);
    185 			ptr += sizeof(uint32_t);
    186 		}
    187 
    188 		/*
    189 		 * extract ContinuationState
    190 		 */
    191 		if (ptr + 1 > end
    192 		    || ptr[0] > 16
    193 		    || ptr + ptr[0] + 1 != end)
    194 			break;
    195 
    196 		memcpy(ss->cs, ptr, ptr[0] + 1);
    197 
    198 		/*
    199 		 * Complete?
    200 		 */
    201 		if (ss->cs[0] == 0) {
    202 			*num = got;
    203 			return true;
    204 		}
    205 	}
    206 
    207 	errno = EIO;
    208 	return false;
    209 }
    210 
    211 bool
    212 sdp_service_attribute(struct sdp_session *ss, uint32_t id,
    213     const sdp_data_t *ail, sdp_data_t *rsp)
    214 {
    215 	struct iovec	req[6];
    216 	sdp_data_t	hdr;
    217 	uint8_t		adata[5], handle[4], max[2];
    218 	uint8_t		*ptr, *end, *rbuf;
    219 	ssize_t		len;
    220 	size_t		rlen, count;
    221 
    222 	/*
    223 	 * setup ServiceRecordHandle
    224 	 */
    225 	be32enc(handle, id);
    226 	req[1].iov_base = handle;
    227 	req[1].iov_len = sizeof(uint32_t);
    228 
    229 	/*
    230 	 * setup MaximumAttributeByteCount
    231 	 */
    232 	be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs));
    233 	req[2].iov_base = max;
    234 	req[2].iov_len = sizeof(uint16_t);
    235 
    236 	/*
    237 	 * setup AttributeIDList
    238 	 */
    239 	len = (ail == NULL ? sizeof(ail_default) : (ail->end - ail->next));
    240 	if (len < 0 || len > UINT16_MAX) {
    241 		errno = EINVAL;
    242 		return false;
    243 	}
    244 
    245 	hdr.next = adata;
    246 	hdr.end = adata + sizeof(adata) + len;
    247 	sdp_put_seq(&hdr, len);
    248 	req[3].iov_base = adata;
    249 	req[3].iov_len = hdr.next - adata;
    250 
    251 	req[4].iov_base = (ail == NULL ? ail_default : ail->next);
    252 	req[4].iov_len = len;
    253 
    254 	/*
    255 	 * clear ContinuationState
    256 	 */
    257 	ss->cs[0] = 0;
    258 
    259 	/*
    260 	 * ServiceAttribute Transaction
    261 	 */
    262 	rlen = 0;
    263 	for (;;) {
    264 		/*
    265 		 * setup ContinuationState
    266 		 */
    267 		req[5].iov_base = ss->cs;
    268 		req[5].iov_len = ss->cs[0] + 1;
    269 
    270 		if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_REQUEST,
    271 		    req, __arraycount(req)))
    272 			return false;
    273 
    274 		len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE);
    275 		if (len == -1)
    276 			return false;
    277 
    278 		ptr = ss->ibuf;
    279 		end = ss->ibuf + len;
    280 
    281 		/*
    282 		 * extract AttributeListByteCount
    283 		 */
    284 		if (ptr + sizeof(uint16_t) > end)
    285 			break;
    286 
    287 		count = be16dec(ptr);
    288 		ptr += sizeof(uint16_t);
    289 		if (count == 0 || ptr + count > end)
    290 			break;
    291 
    292 		/*
    293 		 * extract AttributeList
    294 		 */
    295 		if (rlen + count > sdp_response_max())
    296 			break;
    297 
    298 		rbuf = realloc(ss->rbuf, rlen + count);
    299 		if (rbuf == NULL)
    300 			return false;
    301 
    302 		ss->rbuf = rbuf;
    303 		memcpy(rbuf + rlen, ptr, count);
    304 		rlen += count;
    305 		ptr += count;
    306 
    307 		/*
    308 		 * extract ContinuationState
    309 		 */
    310 		if (ptr + 1 > end
    311 		    || ptr[0] > 16
    312 		    || ptr + ptr[0] + 1 != end)
    313 			break;
    314 
    315 		memcpy(ss->cs, ptr, ptr[0] + 1);
    316 
    317 		/*
    318 		 * Complete?
    319 		 */
    320 		if (ss->cs[0] == 0) {
    321 			rsp->next = rbuf;
    322 			rsp->end = rbuf + rlen;
    323 			if (sdp_data_size(rsp) != rlen
    324 			    || !sdp_data_valid(rsp)
    325 			    || !sdp_get_seq(rsp, rsp))
    326 				break;
    327 
    328 			return true;
    329 		}
    330 	}
    331 
    332 	errno = EIO;
    333 	return false;
    334 }
    335 
    336 bool
    337 sdp_service_search_attribute(struct sdp_session *ss, const sdp_data_t *ssp,
    338     const sdp_data_t *ail, sdp_data_t *rsp)
    339 {
    340 	struct iovec	req[7];
    341 	sdp_data_t	hdr;
    342 	uint8_t		sdata[5], adata[5], max[2];
    343 	uint8_t		*ptr, *end, *rbuf;
    344 	ssize_t		len;
    345 	size_t		rlen, count;
    346 
    347 	/*
    348 	 * setup ServiceSearchPattern
    349 	 */
    350 	len = ssp->end - ssp->next;
    351 	if (len < 0 || len > UINT16_MAX) {
    352 		errno = EINVAL;
    353 		return false;
    354 	}
    355 
    356 	hdr.next = sdata;
    357 	hdr.end = sdata + sizeof(sdata) + len;
    358 	sdp_put_seq(&hdr, len);
    359 	req[1].iov_base = sdata;
    360 	req[1].iov_len = hdr.next - sdata;
    361 
    362 	req[2].iov_base = ssp->next;
    363 	req[2].iov_len = len;
    364 
    365 	/*
    366 	 * setup MaximumAttributeByteCount
    367 	 */
    368 	be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs));
    369 	req[3].iov_base = max;
    370 	req[3].iov_len = sizeof(uint16_t);
    371 
    372 	/*
    373 	 * setup AttributeIDList
    374 	 */
    375 	len = (ail == NULL ? sizeof(ail_default) : (ail->end - ail->next));
    376 	if (len < 0 || len > UINT16_MAX) {
    377 		errno = EINVAL;
    378 		return false;
    379 	}
    380 
    381 	hdr.next = adata;
    382 	hdr.end = adata + sizeof(adata) + len;
    383 	sdp_put_seq(&hdr, len);
    384 	req[4].iov_base = adata;
    385 	req[4].iov_len = hdr.next - adata;
    386 
    387 	req[5].iov_base = (ail == NULL ? ail_default : ail->next);
    388 	req[5].iov_len = len;
    389 
    390 	/*
    391 	 * clear ContinuationState
    392 	 */
    393 	ss->cs[0] = 0;
    394 
    395 	/*
    396 	 * ServiceSearchAttribute Transaction
    397 	 */
    398 	rlen = 0;
    399 	for (;;) {
    400 		/*
    401 		 * setup ContinuationState
    402 		 */
    403 		req[6].iov_base = ss->cs;
    404 		req[6].iov_len = ss->cs[0] + 1;
    405 
    406 		if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST,
    407 		    req, __arraycount(req)))
    408 			return false;
    409 
    410 		len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE);
    411 		if (len == -1)
    412 			return false;
    413 
    414 		ptr = ss->ibuf;
    415 		end = ss->ibuf + len;
    416 
    417 		/*
    418 		 * extract AttributeListsByteCount
    419 		 */
    420 		if (ptr + sizeof(uint16_t) > end)
    421 			break;
    422 
    423 		count = be16dec(ptr);
    424 		ptr += sizeof(uint16_t);
    425 		if (count == 0 || ptr + count > end)
    426 			break;
    427 
    428 		/*
    429 		 * extract AttributeLists
    430 		 */
    431 		if (rlen + count > sdp_response_max())
    432 			break;
    433 
    434 		rbuf = realloc(ss->rbuf, rlen + count);
    435 		if (rbuf == NULL)
    436 			return false;
    437 
    438 		ss->rbuf = rbuf;
    439 		memcpy(rbuf + rlen, ptr, count);
    440 		rlen += count;
    441 		ptr += count;
    442 
    443 		/*
    444 		 * extract ContinuationState
    445 		 */
    446 		if (ptr + 1 > end
    447 		    || ptr[0] > 16
    448 		    || ptr + ptr[0] + 1 != end)
    449 			break;
    450 
    451 		memcpy(ss->cs, ptr, ptr[0] + 1);
    452 
    453 		/*
    454 		 * Complete?
    455 		 */
    456 		if (ss->cs[0] == 0) {
    457 			rsp->next = rbuf;
    458 			rsp->end = rbuf + rlen;
    459 			if (sdp_data_size(rsp) != rlen
    460 			    || !sdp_data_valid(rsp)
    461 			    || !sdp_get_seq(rsp, rsp))
    462 				break;
    463 
    464 			return true;
    465 		}
    466 	}
    467 
    468 	errno = EIO;
    469 	return false;
    470 }
    471