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