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