Home | History | Annotate | Line # | Download | only in sdpd
service.c revision 1.1
      1  1.1  plunky /*	$NetBSD: service.c,v 1.1 2009/05/12 10:05:07 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.1  plunky __RCSID("$NetBSD: service.c,v 1.1 2009/05/12 10:05:07 plunky Exp $");
     34  1.1  plunky 
     35  1.1  plunky #include <bluetooth.h>
     36  1.1  plunky #include <sdp.h>
     37  1.1  plunky 
     38  1.1  plunky #include "sdpd.h"
     39  1.1  plunky 
     40  1.1  plunky /*
     41  1.1  plunky  * This structure is a collection of pointers describing an output
     42  1.1  plunky  * buffer for sdpd_put_byte(), below. bytes are written at next when
     43  1.1  plunky  * it falls inside the range [start .. end - 1]
     44  1.1  plunky  */
     45  1.1  plunky typedef struct {
     46  1.1  plunky 	uint8_t *start;	/* start of buffer window */
     47  1.1  plunky 	uint8_t	*next;	/* current write position */
     48  1.1  plunky 	uint8_t *end;	/* end of buffer window */
     49  1.1  plunky } sdpd_data_t;
     50  1.1  plunky 
     51  1.1  plunky static bool sdpd_valid_ssp(sdp_data_t *);
     52  1.1  plunky static bool sdpd_valid_ail(sdp_data_t *);
     53  1.1  plunky static bool sdpd_match_ail(record_t *, sdp_data_t, sdpd_data_t *);
     54  1.1  plunky static void sdpd_put_byte(sdpd_data_t *, uint8_t);
     55  1.1  plunky static void sdpd_put_attr(sdpd_data_t *, uint16_t, sdp_data_t *);
     56  1.1  plunky static void sdpd_open_seq(sdpd_data_t *);
     57  1.1  plunky static void sdpd_close_seq(sdpd_data_t *, uint8_t *);
     58  1.1  plunky 
     59  1.1  plunky uint16_t
     60  1.1  plunky service_search_request(server_t *srv, int fd)
     61  1.1  plunky {
     62  1.1  plunky 	record_t	*r;
     63  1.1  plunky 	sdp_data_t	d, s;
     64  1.1  plunky 	int		max, total, count;
     65  1.1  plunky 
     66  1.1  plunky 	d.next = srv->ibuf;
     67  1.1  plunky 	d.end = srv->ibuf + srv->pdu.len;
     68  1.1  plunky 
     69  1.1  plunky 	/*
     70  1.1  plunky 	 * extract ServiceSearchPattern
     71  1.1  plunky 	 */
     72  1.1  plunky 	if (!sdp_get_seq(&d, &s)
     73  1.1  plunky 	    || !sdpd_valid_ssp(&s))
     74  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
     75  1.1  plunky 
     76  1.1  plunky 	/*
     77  1.1  plunky 	 * extract MaximumServiceRecordCount
     78  1.1  plunky 	 */
     79  1.1  plunky 	if (d.next + sizeof(uint16_t) > d.end)
     80  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
     81  1.1  plunky 
     82  1.1  plunky 	max = be16dec(d.next);
     83  1.1  plunky 	d.next += sizeof(uint16_t);
     84  1.1  plunky 	if (max < 0x0001)
     85  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
     86  1.1  plunky 
     87  1.1  plunky 	/*
     88  1.1  plunky 	 * validate ContinuationState
     89  1.1  plunky 	 * If none given, this is a new request
     90  1.1  plunky 	 */
     91  1.1  plunky 	if (d.next + 1 > d.end
     92  1.1  plunky 	    || d.next[0] > 16
     93  1.1  plunky 	    || d.next + 1 + d.next[0] != d.end)
     94  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
     95  1.1  plunky 
     96  1.1  plunky 	if (d.next[0] == 0) {
     97  1.1  plunky 		srv->fdidx[fd].offset = 0;
     98  1.1  plunky 		db_unselect(srv, fd);
     99  1.1  plunky 		db_select_ssp(srv, fd, &s);
    100  1.1  plunky 	} else if (srv->fdidx[fd].offset == 0
    101  1.1  plunky 	    || d.next[0] != sizeof(uint16_t)
    102  1.1  plunky 	    || be16dec(d.next + 1) != srv->fdidx[fd].offset)
    103  1.1  plunky 		return SDP_ERROR_CODE_INVALID_CONTINUATION_STATE;
    104  1.1  plunky 
    105  1.1  plunky 	/*
    106  1.1  plunky 	 * Ready our output buffer. We leave space at the start for
    107  1.1  plunky 	 * TotalServiceRecordCount and CurrentServiceRecordCount and
    108  1.1  plunky 	 * at the end for ContinuationState, and we must have space
    109  1.1  plunky 	 * for at least one ServiceRecordHandle. Then, step through
    110  1.1  plunky 	 * selected records and write as many handles that will fit
    111  1.1  plunky 	 * into the data space
    112  1.1  plunky 	 */
    113  1.1  plunky 	d.next = srv->obuf + sizeof(uint16_t) + sizeof(uint16_t);
    114  1.1  plunky 	d.end = srv->obuf + srv->fdidx[fd].omtu - 1 - sizeof(uint16_t);
    115  1.1  plunky 	count = total = 0;
    116  1.1  plunky 
    117  1.1  plunky 	if (d.next + sizeof(uint32_t) > d.end)
    118  1.1  plunky 		return SDP_ERROR_CODE_INSUFFICIENT_RESOURCES;
    119  1.1  plunky 
    120  1.1  plunky 	r = NULL;
    121  1.1  plunky 	while (db_next(srv, fd, &r) && total < max) {
    122  1.1  plunky 		if (total >= srv->fdidx[fd].offset
    123  1.1  plunky 		    && d.next + sizeof(uint32_t) <= d.end) {
    124  1.1  plunky 			be32enc(d.next, r->handle);
    125  1.1  plunky 			d.next += sizeof(uint32_t);
    126  1.1  plunky 			count++;
    127  1.1  plunky 		}
    128  1.1  plunky 
    129  1.1  plunky 		total++;
    130  1.1  plunky 	}
    131  1.1  plunky 
    132  1.1  plunky 	/*
    133  1.1  plunky 	 * encode TotalServiceRecordCount and CurrentServiceRecordCount
    134  1.1  plunky 	 */
    135  1.1  plunky 	be16enc(srv->obuf, total);
    136  1.1  plunky 	be16enc(srv->obuf + sizeof(uint16_t), count);
    137  1.1  plunky 
    138  1.1  plunky 	/*
    139  1.1  plunky 	 * encode ContinuationState which in this case will be the
    140  1.1  plunky 	 * number of ServiceRecordHandles already sent.
    141  1.1  plunky 	 */
    142  1.1  plunky 	if (r == NULL || total == max) {
    143  1.1  plunky 		srv->fdidx[fd].offset = 0;
    144  1.1  plunky 		db_unselect(srv, fd);
    145  1.1  plunky 		d.next[0] = 0;
    146  1.1  plunky 		d.next += 1;
    147  1.1  plunky 	} else {
    148  1.1  plunky 		srv->fdidx[fd].offset += count;
    149  1.1  plunky 		d.next[0] = sizeof(uint16_t);
    150  1.1  plunky 		be16enc(d.next + 1, srv->fdidx[fd].offset);
    151  1.1  plunky 		d.next += 1 + sizeof(uint16_t);
    152  1.1  plunky 	}
    153  1.1  plunky 
    154  1.1  plunky 	/*
    155  1.1  plunky 	 * fill in PDU header and we are done
    156  1.1  plunky 	 */
    157  1.1  plunky 	srv->pdu.pid = SDP_PDU_SERVICE_SEARCH_RESPONSE;
    158  1.1  plunky 	srv->pdu.len = d.next - srv->obuf;
    159  1.1  plunky 	return 0;
    160  1.1  plunky }
    161  1.1  plunky 
    162  1.1  plunky uint16_t
    163  1.1  plunky service_attribute_request(server_t *srv, int fd)
    164  1.1  plunky {
    165  1.1  plunky 	record_t	*r;
    166  1.1  plunky 	sdp_data_t	a, d;
    167  1.1  plunky 	sdpd_data_t	b;
    168  1.1  plunky 	uint8_t		*tmp;
    169  1.1  plunky 	uint32_t	handle;
    170  1.1  plunky 	int		max;
    171  1.1  plunky 
    172  1.1  plunky 	d.next = srv->ibuf;
    173  1.1  plunky 	d.end = srv->ibuf + srv->pdu.len;
    174  1.1  plunky 
    175  1.1  plunky 	/*
    176  1.1  plunky 	 * extract ServiceRecordHandle
    177  1.1  plunky 	 */
    178  1.1  plunky 	if (d.next + sizeof(uint32_t) > d.end)
    179  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    180  1.1  plunky 
    181  1.1  plunky 	handle = be32dec(d.next);
    182  1.1  plunky 	d.next += sizeof(uint32_t);
    183  1.1  plunky 
    184  1.1  plunky 	/*
    185  1.1  plunky 	 * extract MaximumAttributeByteCount
    186  1.1  plunky 	 */
    187  1.1  plunky 	if (d.next + sizeof(uint16_t) > d.end)
    188  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    189  1.1  plunky 
    190  1.1  plunky 	max = be16dec(d.next);
    191  1.1  plunky 	d.next += sizeof(uint16_t);
    192  1.1  plunky 	if (max < 0x0007)
    193  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    194  1.1  plunky 
    195  1.1  plunky 	/*
    196  1.1  plunky 	 * extract AttributeIDList
    197  1.1  plunky 	 */
    198  1.1  plunky 	if (!sdp_get_seq(&d, &a)
    199  1.1  plunky 	    || !sdpd_valid_ail(&a))
    200  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    201  1.1  plunky 
    202  1.1  plunky 	/*
    203  1.1  plunky 	 * validate ContinuationState
    204  1.1  plunky 	 * If none given, this is a new request
    205  1.1  plunky 	 */
    206  1.1  plunky 	if (d.next + 1 > d.end
    207  1.1  plunky 	    || d.next[0] > 16
    208  1.1  plunky 	    || d.next + 1 + d.next[0] != d.end)
    209  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    210  1.1  plunky 
    211  1.1  plunky 	if (d.next[0] == 0) {
    212  1.1  plunky 		srv->fdidx[fd].offset = 0;
    213  1.1  plunky 		db_unselect(srv, fd);
    214  1.1  plunky 		db_select_handle(srv, fd, handle);
    215  1.1  plunky 	} else if (srv->fdidx[fd].offset == 0
    216  1.1  plunky 	    || d.next[0] != sizeof(uint16_t)
    217  1.1  plunky 	    || be16dec(d.next + 1) != srv->fdidx[fd].offset)
    218  1.1  plunky 		return SDP_ERROR_CODE_INVALID_CONTINUATION_STATE;
    219  1.1  plunky 
    220  1.1  plunky 	/*
    221  1.1  plunky 	 * Set up the buffer window and write pointer, leaving space at
    222  1.1  plunky 	 * buffer start for AttributeListByteCount and for ContinuationState
    223  1.1  plunky 	 * at the end
    224  1.1  plunky 	 */
    225  1.1  plunky 	b.start = srv->obuf + sizeof(uint16_t);
    226  1.1  plunky 	b.next = b.start - srv->fdidx[fd].offset;
    227  1.1  plunky 	b.end = srv->obuf + srv->fdidx[fd].omtu - 1;
    228  1.1  plunky 	if (b.start + max < b.end)
    229  1.1  plunky 		b.end = b.start + max;
    230  1.1  plunky 
    231  1.1  plunky 	/*
    232  1.1  plunky 	 * Match the selected record against AttributeIDList, writing
    233  1.1  plunky 	 * the data to the sparce buffer.
    234  1.1  plunky 	 */
    235  1.1  plunky 	r = NULL;
    236  1.1  plunky 	db_next(srv, fd, &r);
    237  1.1  plunky 	if (r == NULL)
    238  1.1  plunky 		return SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE;
    239  1.1  plunky 
    240  1.1  plunky 	sdpd_match_ail(r, a, &b);
    241  1.1  plunky 
    242  1.1  plunky 	if (b.next > b.end) {
    243  1.1  plunky 		/*
    244  1.1  plunky 		 * b.end is the limit of AttributeList that we are allowed
    245  1.1  plunky 		 * to send so if we have exceeded that we need to adjust our
    246  1.1  plunky 		 * response downwards. Recalculate the new cut off to allow
    247  1.1  plunky 		 * writing the ContinuationState offset and ensure we don't
    248  1.1  plunky 		 * exceed MaximumAttributeByteCount. Also, make sure that
    249  1.1  plunky 		 * the continued length is not too short.
    250  1.1  plunky 		 */
    251  1.1  plunky 		tmp = b.next;
    252  1.1  plunky 		b.next = srv->obuf + srv->fdidx[fd].omtu - 1 - sizeof(uint16_t);
    253  1.1  plunky 		if (b.next > b.end)
    254  1.1  plunky 			b.next = b.end;
    255  1.1  plunky 
    256  1.1  plunky 		if (tmp - b.next < 0x0002)
    257  1.1  plunky 			b.next = tmp - 0x0002;
    258  1.1  plunky 
    259  1.1  plunky 		/* encode AttributeListByteCount */
    260  1.1  plunky 		be16enc(srv->obuf, (b.next - b.start));
    261  1.1  plunky 
    262  1.1  plunky 		/* calculate & append ContinuationState */
    263  1.1  plunky 		srv->fdidx[fd].offset += (b.next - b.start);
    264  1.1  plunky 		b.next[0] = sizeof(uint16_t);
    265  1.1  plunky 		be16enc(b.next + 1, srv->fdidx[fd].offset);
    266  1.1  plunky 		b.next += 1 + sizeof(uint16_t);
    267  1.1  plunky 	} else {
    268  1.1  plunky 		/* encode AttributeListByteCount */
    269  1.1  plunky 		be16enc(srv->obuf, (b.next - b.start));
    270  1.1  plunky 
    271  1.1  plunky 		/* reset & append ContinuationState */
    272  1.1  plunky 		srv->fdidx[fd].offset = 0;
    273  1.1  plunky 		db_unselect(srv, fd);
    274  1.1  plunky 		b.next[0] = 0;
    275  1.1  plunky 		b.next += 1;
    276  1.1  plunky 	}
    277  1.1  plunky 
    278  1.1  plunky 	/*
    279  1.1  plunky 	 * fill in PDU header and we are done
    280  1.1  plunky 	 */
    281  1.1  plunky 	srv->pdu.pid = SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE;
    282  1.1  plunky 	srv->pdu.len = b.next - srv->obuf;
    283  1.1  plunky 	return 0;
    284  1.1  plunky }
    285  1.1  plunky 
    286  1.1  plunky uint16_t
    287  1.1  plunky service_search_attribute_request(server_t *srv, int fd)
    288  1.1  plunky {
    289  1.1  plunky 	record_t	*r;
    290  1.1  plunky 	sdpd_data_t	b;
    291  1.1  plunky 	sdp_data_t	a, d, s;
    292  1.1  plunky 	uint8_t		*tmp;
    293  1.1  plunky 	int		max;
    294  1.1  plunky 
    295  1.1  plunky 	d.next = srv->ibuf;
    296  1.1  plunky 	d.end = srv->ibuf + srv->pdu.len;
    297  1.1  plunky 
    298  1.1  plunky 	/*
    299  1.1  plunky 	 * extract ServiceSearchPattern
    300  1.1  plunky 	 */
    301  1.1  plunky 	if (!sdp_get_seq(&d, &s)
    302  1.1  plunky 	    || !sdpd_valid_ssp(&s))
    303  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    304  1.1  plunky 
    305  1.1  plunky 	/*
    306  1.1  plunky 	 * extract MaximumAttributeByteCount
    307  1.1  plunky 	 */
    308  1.1  plunky 	if (d.next + sizeof(uint16_t) > d.end)
    309  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    310  1.1  plunky 
    311  1.1  plunky 	max = be16dec(d.next);
    312  1.1  plunky 	d.next += sizeof(uint16_t);
    313  1.1  plunky 	if (max < 0x0007)
    314  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    315  1.1  plunky 
    316  1.1  plunky 	/*
    317  1.1  plunky 	 * extract AttributeIDList
    318  1.1  plunky 	 */
    319  1.1  plunky 	if (!sdp_get_seq(&d, &a)
    320  1.1  plunky 	    || !sdpd_valid_ail(&a))
    321  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    322  1.1  plunky 
    323  1.1  plunky 	/*
    324  1.1  plunky 	 * validate ContinuationState
    325  1.1  plunky 	 * If none given, this is a new request
    326  1.1  plunky 	 */
    327  1.1  plunky 	if (d.next + 1 > d.end
    328  1.1  plunky 	    || d.next[0] > 16
    329  1.1  plunky 	    || d.next + 1 + d.next[0] != d.end)
    330  1.1  plunky 		return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
    331  1.1  plunky 
    332  1.1  plunky 	if (d.next[0] == 0) {
    333  1.1  plunky 		srv->fdidx[fd].offset = 0;
    334  1.1  plunky 		db_unselect(srv, fd);
    335  1.1  plunky 		db_select_ssp(srv, fd, &s);
    336  1.1  plunky 	} else if (srv->fdidx[fd].offset == 0
    337  1.1  plunky 	    || d.next[0] != sizeof(uint16_t)
    338  1.1  plunky 	    || be16dec(d.next + 1) != srv->fdidx[fd].offset)
    339  1.1  plunky 		return SDP_ERROR_CODE_INVALID_CONTINUATION_STATE;
    340  1.1  plunky 
    341  1.1  plunky 	/*
    342  1.1  plunky 	 * Set up the buffer window and write pointer, leaving space at
    343  1.1  plunky 	 * buffer start for AttributeListByteCount and for ContinuationState
    344  1.1  plunky 	 * at the end.
    345  1.1  plunky 	 */
    346  1.1  plunky 	b.start = srv->obuf + sizeof(uint16_t);
    347  1.1  plunky 	b.end = srv->obuf + srv->fdidx[fd].omtu - 1;
    348  1.1  plunky 	b.next = b.start - srv->fdidx[fd].offset;
    349  1.1  plunky 	if (b.start + max < b.end)
    350  1.1  plunky 		b.end = b.start + max;
    351  1.1  plunky 
    352  1.1  plunky 	/*
    353  1.1  plunky 	 * match all selected records against the AttributeIDList,
    354  1.1  plunky 	 * wrapping the whole in a sequence. Where a record does
    355  1.1  plunky 	 * not match any attributes, delete the empty sequence.
    356  1.1  plunky 	 */
    357  1.1  plunky 	sdpd_open_seq(&b);
    358  1.1  plunky 
    359  1.1  plunky 	r = NULL;
    360  1.1  plunky 	while (db_next(srv, fd, &r)) {
    361  1.1  plunky 		tmp = b.next;
    362  1.1  plunky 		if (!sdpd_match_ail(r, a, &b))
    363  1.1  plunky 			b.next = tmp;
    364  1.1  plunky 	}
    365  1.1  plunky 
    366  1.1  plunky 	sdpd_close_seq(&b, b.start - srv->fdidx[fd].offset);
    367  1.1  plunky 
    368  1.1  plunky 	if (b.next > b.end) {
    369  1.1  plunky 		/*
    370  1.1  plunky 		 * b.end is the limit of AttributeLists that we are allowed
    371  1.1  plunky 		 * to send so if we have exceeded that we need to adjust our
    372  1.1  plunky 		 * response downwards. Recalculate the new cut off to allow
    373  1.1  plunky 		 * writing the ContinuationState offset and ensure we don't
    374  1.1  plunky 		 * exceed MaximumAttributeByteCount. Also, make sure that
    375  1.1  plunky 		 * the continued length is not too short.
    376  1.1  plunky 		 */
    377  1.1  plunky 		tmp = b.next;
    378  1.1  plunky 		b.next = srv->obuf + srv->fdidx[fd].omtu - 1 - sizeof(uint16_t);
    379  1.1  plunky 		if (b.next > b.end)
    380  1.1  plunky 			b.next = b.end;
    381  1.1  plunky 
    382  1.1  plunky 		if (tmp - b.next < 0x0002)
    383  1.1  plunky 			b.next = tmp - 0x0002;
    384  1.1  plunky 
    385  1.1  plunky 		/* encode AttributeListsByteCount */
    386  1.1  plunky 		be16enc(srv->obuf, (b.next - b.start));
    387  1.1  plunky 
    388  1.1  plunky 		/* calculate & append ContinuationState */
    389  1.1  plunky 		srv->fdidx[fd].offset += (b.next - b.start);
    390  1.1  plunky 		b.next[0] = sizeof(uint16_t);
    391  1.1  plunky 		be16enc(b.next + 1, srv->fdidx[fd].offset);
    392  1.1  plunky 		b.next += 1 + sizeof(uint16_t);
    393  1.1  plunky 	} else {
    394  1.1  plunky 		/* encode AttributeListsByteCount */
    395  1.1  plunky 		be16enc(srv->obuf, (b.next - b.start));
    396  1.1  plunky 
    397  1.1  plunky 		/* reset & append ContinuationState */
    398  1.1  plunky 		srv->fdidx[fd].offset = 0;
    399  1.1  plunky 		db_unselect(srv, fd);
    400  1.1  plunky 		b.next[0] = 0;
    401  1.1  plunky 		b.next += 1;
    402  1.1  plunky 	}
    403  1.1  plunky 
    404  1.1  plunky 	/*
    405  1.1  plunky 	 * fill in PDU header and we are done
    406  1.1  plunky 	 */
    407  1.1  plunky 	srv->pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE;
    408  1.1  plunky 	srv->pdu.len = b.next - srv->obuf;
    409  1.1  plunky 	return 0;
    410  1.1  plunky }
    411  1.1  plunky 
    412  1.1  plunky /*
    413  1.1  plunky  * validate ServiceSearchPattern
    414  1.1  plunky  *
    415  1.1  plunky  * The SerivceSearchPattern is a list of data elements, where each element
    416  1.1  plunky  * is a UUID. The list must contain at least one UUID and the maximum number
    417  1.1  plunky  * of UUIDs is 12
    418  1.1  plunky  */
    419  1.1  plunky static bool
    420  1.1  plunky sdpd_valid_ssp(sdp_data_t *ssp)
    421  1.1  plunky {
    422  1.1  plunky 	sdp_data_t	s = *ssp;
    423  1.1  plunky 	uuid_t		u;
    424  1.1  plunky 	int		n;
    425  1.1  plunky 
    426  1.1  plunky 	if (!sdp_data_valid(&s))
    427  1.1  plunky 		return false;
    428  1.1  plunky 
    429  1.1  plunky 	n = 0;
    430  1.1  plunky 	while (sdp_get_uuid(&s, &u))
    431  1.1  plunky 		n++;
    432  1.1  plunky 
    433  1.1  plunky 	if (n < 1 || n > 12 || s.next != s.end)
    434  1.1  plunky 		return false;
    435  1.1  plunky 
    436  1.1  plunky 	return true;
    437  1.1  plunky }
    438  1.1  plunky 
    439  1.1  plunky /*
    440  1.1  plunky  * validate AttributeIDList
    441  1.1  plunky  *
    442  1.1  plunky  * The AttributeIDList is a list of data elements, where each element is
    443  1.1  plunky  * either an attribute ID encoded as an unsigned 16-bit integer or a range
    444  1.1  plunky  * of attribute IDs encoded as an unsigned 32-bit integer where the high
    445  1.1  plunky  * order 16-bits are the beginning of the range and the low order 16-bits
    446  1.1  plunky  * are the ending
    447  1.1  plunky  *
    448  1.1  plunky  * The attrbute IDs should be listed in ascending order without duplication
    449  1.1  plunky  * of any attribute ID values but we don't worry about that, since if the
    450  1.1  plunky  * remote party messes up, their results will be messed up
    451  1.1  plunky  */
    452  1.1  plunky static bool
    453  1.1  plunky sdpd_valid_ail(sdp_data_t *ail)
    454  1.1  plunky {
    455  1.1  plunky 	sdp_data_t	a = *ail;
    456  1.1  plunky 	sdp_data_t	d;
    457  1.1  plunky 
    458  1.1  plunky 	if (!sdp_data_valid(&a))
    459  1.1  plunky 		return false;
    460  1.1  plunky 
    461  1.1  plunky 	while (sdp_get_data(&a, &d)) {
    462  1.1  plunky 		if (sdp_data_type(&d) != SDP_DATA_UINT16
    463  1.1  plunky 		    && sdp_data_type(&d) != SDP_DATA_UINT32)
    464  1.1  plunky 			return false;
    465  1.1  plunky 	}
    466  1.1  plunky 
    467  1.1  plunky 	return true;
    468  1.1  plunky }
    469  1.1  plunky 
    470  1.1  plunky /*
    471  1.1  plunky  * compare attributes in the ServiceRecord with the AttributeIDList
    472  1.1  plunky  * and copy any matches to a sequence in the output buffer.
    473  1.1  plunky  */
    474  1.1  plunky static bool
    475  1.1  plunky sdpd_match_ail(record_t *rec, sdp_data_t ail, sdpd_data_t *buf)
    476  1.1  plunky {
    477  1.1  plunky 	sdp_data_t	r, v;
    478  1.1  plunky 	uint16_t	a;
    479  1.1  plunky 	uintmax_t	ui;
    480  1.1  plunky 	uint8_t		*f;
    481  1.1  plunky 	int		lo, hi;
    482  1.1  plunky 	bool		rv;
    483  1.1  plunky 
    484  1.1  plunky 	r = rec->data;
    485  1.1  plunky 	f = buf->next;
    486  1.1  plunky 	lo = hi = -1;
    487  1.1  plunky 	rv = false;
    488  1.1  plunky 
    489  1.1  plunky 	sdpd_open_seq(buf);
    490  1.1  plunky 
    491  1.1  plunky 	while (sdp_get_attr(&r, &a, &v)) {
    492  1.1  plunky 		while (a > hi) {
    493  1.1  plunky 			if (ail.next == ail.end)
    494  1.1  plunky 				goto done;
    495  1.1  plunky 
    496  1.1  plunky 			if (sdp_data_type(&ail) == SDP_DATA_UINT16) {
    497  1.1  plunky 				sdp_get_uint(&ail, &ui);
    498  1.1  plunky 				lo = hi = ui;
    499  1.1  plunky 			} else {
    500  1.1  plunky 				sdp_get_uint(&ail, &ui);
    501  1.1  plunky 				lo = (uint16_t)(ui >> 16);
    502  1.1  plunky 				hi = (uint16_t)(ui);
    503  1.1  plunky 			}
    504  1.1  plunky 		}
    505  1.1  plunky 
    506  1.1  plunky 		if (a < lo)
    507  1.1  plunky 			continue;
    508  1.1  plunky 
    509  1.1  plunky 		sdpd_put_attr(buf, a, &v);
    510  1.1  plunky 		rv = true;
    511  1.1  plunky 	}
    512  1.1  plunky 
    513  1.1  plunky done:
    514  1.1  plunky 	sdpd_close_seq(buf, f);
    515  1.1  plunky 	return rv;
    516  1.1  plunky }
    517  1.1  plunky 
    518  1.1  plunky /*
    519  1.1  plunky  * output data. We only actually store the bytes when the
    520  1.1  plunky  * pointer is within the valid window.
    521  1.1  plunky  */
    522  1.1  plunky static void
    523  1.1  plunky sdpd_put_byte(sdpd_data_t *buf, uint8_t byte)
    524  1.1  plunky {
    525  1.1  plunky 
    526  1.1  plunky 	if (buf->next >= buf->start && buf->next < buf->end)
    527  1.1  plunky 		buf->next[0] = byte;
    528  1.1  plunky 
    529  1.1  plunky 	buf->next++;
    530  1.1  plunky }
    531  1.1  plunky 
    532  1.1  plunky static void
    533  1.1  plunky sdpd_put_attr(sdpd_data_t *buf, uint16_t attr, sdp_data_t *data)
    534  1.1  plunky {
    535  1.1  plunky 	uint8_t	*p;
    536  1.1  plunky 
    537  1.1  plunky 	sdpd_put_byte(buf, SDP_DATA_UINT16);
    538  1.1  plunky 	sdpd_put_byte(buf, (uint8_t)(attr >> 8));
    539  1.1  plunky 	sdpd_put_byte(buf, (uint8_t)(attr));
    540  1.1  plunky 
    541  1.1  plunky 	for (p = data->next; p < data->end; p++)
    542  1.1  plunky 		sdpd_put_byte(buf, *p);
    543  1.1  plunky }
    544  1.1  plunky 
    545  1.1  plunky /*
    546  1.1  plunky  * Since we always use a seq16 and never check the length, we will send
    547  1.1  plunky  * an invalid header if it grows too large. We could always use a seq32
    548  1.1  plunky  * but the chance of overflow is small so ignore it for now.
    549  1.1  plunky  */
    550  1.1  plunky static void
    551  1.1  plunky sdpd_open_seq(sdpd_data_t *buf)
    552  1.1  plunky {
    553  1.1  plunky 
    554  1.1  plunky 	buf->next += 3;
    555  1.1  plunky }
    556  1.1  plunky 
    557  1.1  plunky static void
    558  1.1  plunky sdpd_close_seq(sdpd_data_t *buf, uint8_t *first)
    559  1.1  plunky {
    560  1.1  plunky 	uint8_t	*next;
    561  1.1  plunky 	size_t	len;
    562  1.1  plunky 
    563  1.1  plunky 	next = buf->next;
    564  1.1  plunky 	buf->next = first;
    565  1.1  plunky 	len = next - first - 3;
    566  1.1  plunky 
    567  1.1  plunky 	sdpd_put_byte(buf, SDP_DATA_SEQ16);
    568  1.1  plunky 	sdpd_put_byte(buf, 0xff & (len >> 8));
    569  1.1  plunky 	sdpd_put_byte(buf, 0xff & (len >> 0));
    570  1.1  plunky 	buf->next = next;
    571  1.1  plunky }
    572