service.c revision 1.2 1 1.2 plunky /* $NetBSD: service.c,v 1.2 2010/03/07 10:58:40 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.2 plunky __RCSID("$NetBSD: service.c,v 1.2 2010/03/07 10:58:40 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.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.1 plunky * the data to the sparce 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.1 plunky * The SerivceSearchPattern 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.1 plunky * The attrbute 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