xref: /netbsd-src/lib/libbluetooth/sdp_service.c (revision 231f6b581de1ca2826f0c169d7f1b4dea834067f)
1*231f6b58Splunky /*	$NetBSD: sdp_service.c,v 1.4 2010/11/20 12:12:21 plunky Exp $	*/
2dfbf818aSplunky 
3dfbf818aSplunky /*-
4dfbf818aSplunky  * Copyright (c) 2009 The NetBSD Foundation, Inc.
5dfbf818aSplunky  * All rights reserved.
6dfbf818aSplunky  *
7dfbf818aSplunky  * This code is derived from software contributed to The NetBSD Foundation
8dfbf818aSplunky  * by Iain Hibbert.
9dfbf818aSplunky  *
10dfbf818aSplunky  * Redistribution and use in source and binary forms, with or without
11dfbf818aSplunky  * modification, are permitted provided that the following conditions
12dfbf818aSplunky  * are met:
13dfbf818aSplunky  * 1. Redistributions of source code must retain the above copyright
14dfbf818aSplunky  *    notice, this list of conditions and the following disclaimer.
15dfbf818aSplunky  * 2. Redistributions in binary form must reproduce the above copyright
16dfbf818aSplunky  *    notice, this list of conditions and the following disclaimer in the
17dfbf818aSplunky  *    documentation and/or other materials provided with the distribution.
18dfbf818aSplunky  *
19dfbf818aSplunky  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20dfbf818aSplunky  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21dfbf818aSplunky  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22dfbf818aSplunky  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23dfbf818aSplunky  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24dfbf818aSplunky  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25dfbf818aSplunky  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26dfbf818aSplunky  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27dfbf818aSplunky  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28dfbf818aSplunky  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29dfbf818aSplunky  * POSSIBILITY OF SUCH DAMAGE.
30dfbf818aSplunky  */
31dfbf818aSplunky 
32dfbf818aSplunky #include <sys/cdefs.h>
33*231f6b58Splunky __RCSID("$NetBSD: sdp_service.c,v 1.4 2010/11/20 12:12:21 plunky Exp $");
34*231f6b58Splunky 
35*231f6b58Splunky #include <sys/atomic.h>
36dfbf818aSplunky 
37dfbf818aSplunky #include <errno.h>
38dfbf818aSplunky #include <limits.h>
39dfbf818aSplunky #include <sdp.h>
40dfbf818aSplunky #include <stdlib.h>
41dfbf818aSplunky #include <string.h>
42dfbf818aSplunky #include <unistd.h>
43dfbf818aSplunky 
44dfbf818aSplunky #include "sdp-int.h"
45dfbf818aSplunky 
46dfbf818aSplunky /*
47dfbf818aSplunky  * If AttributeIDList is given as NULL, request all attributes.
48*231f6b58Splunky  * (this is actually const data but we can't declare it const)
49dfbf818aSplunky  */
50dfbf818aSplunky static uint8_t ail_default[] = { 0x0a, 0x00, 0x00, 0xff, 0xff };
51dfbf818aSplunky 
52dfbf818aSplunky /*
53dfbf818aSplunky  * This provides the maximum size that the response buffer will be
54dfbf818aSplunky  * allowed to grow to.
55dfbf818aSplunky  *
56dfbf818aSplunky  * Default is UINT16_MAX but it can be overridden at runtime.
57dfbf818aSplunky  */
58dfbf818aSplunky static size_t
sdp_response_max(void)59dfbf818aSplunky sdp_response_max(void)
60dfbf818aSplunky {
61dfbf818aSplunky 	static size_t max = UINT16_MAX;
62*231f6b58Splunky 	static unsigned int check = 1;
63dfbf818aSplunky 	char *env, *ep;
64dfbf818aSplunky 	unsigned long v;
65dfbf818aSplunky 
66*231f6b58Splunky 	while (atomic_swap_uint(&check, 0)) { /* only check env once */
67dfbf818aSplunky 		env = getenv("SDP_RESPONSE_MAX");
68dfbf818aSplunky 		if (env == NULL)
69dfbf818aSplunky 			break;
70dfbf818aSplunky 
71dfbf818aSplunky 		errno = 0;
72dfbf818aSplunky 		v = strtoul(env, &ep, 0);
73dfbf818aSplunky 		if (env[0] == '\0' || *ep != '\0')
74dfbf818aSplunky 			break;
75dfbf818aSplunky 
76dfbf818aSplunky 		if (errno == ERANGE && v == ULONG_MAX)
77dfbf818aSplunky 			break;
78dfbf818aSplunky 
79dfbf818aSplunky 		/* lower limit is arbitrary */
80dfbf818aSplunky 		if (v < UINT8_MAX || v > UINT32_MAX)
81dfbf818aSplunky 			break;
82dfbf818aSplunky 
83dfbf818aSplunky 		max = v;
84dfbf818aSplunky 	}
85dfbf818aSplunky 
86dfbf818aSplunky 	return max;
87dfbf818aSplunky }
88dfbf818aSplunky 
89dfbf818aSplunky bool
sdp_service_search(struct sdp_session * ss,const sdp_data_t * ssp,uint32_t * id,int * num)90dfbf818aSplunky sdp_service_search(struct sdp_session *ss, const sdp_data_t *ssp,
91dfbf818aSplunky     uint32_t *id, int *num)
92dfbf818aSplunky {
93dfbf818aSplunky 	struct iovec	req[5];
94dfbf818aSplunky 	sdp_data_t	hdr;
95dfbf818aSplunky 	uint8_t		sdata[5], max[2];
96dfbf818aSplunky 	uint8_t		*ptr, *end;
97dfbf818aSplunky 	ssize_t		len;
98dfbf818aSplunky 	uint16_t	total, count, got;
99dfbf818aSplunky 
100dfbf818aSplunky 	/*
101dfbf818aSplunky 	 * setup ServiceSearchPattern
102dfbf818aSplunky 	 */
103dfbf818aSplunky 	len = ssp->end - ssp->next;
104dfbf818aSplunky 	if (len < 0 || len > UINT16_MAX) {
105dfbf818aSplunky 		errno = EINVAL;
106dfbf818aSplunky 		return false;
107dfbf818aSplunky 	}
108dfbf818aSplunky 
109dfbf818aSplunky 	hdr.next = sdata;
110dfbf818aSplunky 	hdr.end = sdata + sizeof(sdata) + len;
111dfbf818aSplunky 	sdp_put_seq(&hdr, len);
112dfbf818aSplunky 	req[1].iov_base = sdata;
113dfbf818aSplunky 	req[1].iov_len = hdr.next - sdata;
114dfbf818aSplunky 
115dfbf818aSplunky 	req[2].iov_base = ssp->next;
116dfbf818aSplunky 	req[2].iov_len = len;
117dfbf818aSplunky 
118dfbf818aSplunky 	/*
119dfbf818aSplunky 	 * setup MaximumServiceRecordCount
120dfbf818aSplunky 	 */
121dfbf818aSplunky 	if (*num < 0 || *num > UINT16_MAX) {
122dfbf818aSplunky 		errno = EINVAL;
123dfbf818aSplunky 		return false;
124dfbf818aSplunky 	}
125dfbf818aSplunky 	be16enc(max, *num);
126dfbf818aSplunky 	req[3].iov_base = max;
127dfbf818aSplunky 	req[3].iov_len = sizeof(uint16_t);
128dfbf818aSplunky 
129dfbf818aSplunky 	/*
130dfbf818aSplunky 	 * clear ContinuationState
131dfbf818aSplunky 	 */
132dfbf818aSplunky 	ss->cs[0] = 0;
133dfbf818aSplunky 
134dfbf818aSplunky 	/*
135dfbf818aSplunky 	 * ServiceSearch Transaction
136dfbf818aSplunky 	 */
137dfbf818aSplunky 	got = 0;
138dfbf818aSplunky 	for (;;) {
139dfbf818aSplunky 		/*
140dfbf818aSplunky 		 * setup ContinuationState
141dfbf818aSplunky 		 */
142dfbf818aSplunky 		req[4].iov_base = ss->cs;
143dfbf818aSplunky 		req[4].iov_len = ss->cs[0] + 1;
144dfbf818aSplunky 
145dfbf818aSplunky 		if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_REQUEST,
146dfbf818aSplunky 		    req, __arraycount(req)))
147dfbf818aSplunky 			return false;
148dfbf818aSplunky 
149dfbf818aSplunky 		len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_RESPONSE);
150dfbf818aSplunky 		if (len == -1)
151dfbf818aSplunky 			return false;
152dfbf818aSplunky 
153dfbf818aSplunky 		ptr = ss->ibuf;
154dfbf818aSplunky 		end = ss->ibuf + len;
155dfbf818aSplunky 
156dfbf818aSplunky 		/*
157dfbf818aSplunky 		 * extract TotalServiceRecordCount
158dfbf818aSplunky 		 */
159dfbf818aSplunky 		if (ptr + sizeof(uint16_t) > end)
160dfbf818aSplunky 			break;
161dfbf818aSplunky 
162dfbf818aSplunky 		total = be16dec(ptr);
163dfbf818aSplunky 		ptr += sizeof(uint16_t);
164dfbf818aSplunky 		if (total > *num)
165dfbf818aSplunky 			break;
166dfbf818aSplunky 
167dfbf818aSplunky 		/*
168dfbf818aSplunky 		 * extract CurrentServiceRecordCount
169dfbf818aSplunky 		 */
170dfbf818aSplunky 		if (ptr + sizeof(uint16_t) > end)
171dfbf818aSplunky 			break;
172dfbf818aSplunky 
173dfbf818aSplunky 		count = be16dec(ptr);
174dfbf818aSplunky 		ptr += sizeof(uint16_t);
175dfbf818aSplunky 		if (got + count > total)
176dfbf818aSplunky 			break;
177dfbf818aSplunky 
178dfbf818aSplunky 		/*
179dfbf818aSplunky 		 * extract ServiceRecordHandleList
180dfbf818aSplunky 		 */
181dfbf818aSplunky 		if (ptr + count * sizeof(uint32_t) > end)
182dfbf818aSplunky 			break;
183dfbf818aSplunky 
184dfbf818aSplunky 		while (count-- > 0) {
185dfbf818aSplunky 			id[got++] = be32dec(ptr);
186dfbf818aSplunky 			ptr += sizeof(uint32_t);
187dfbf818aSplunky 		}
188dfbf818aSplunky 
189dfbf818aSplunky 		/*
190dfbf818aSplunky 		 * extract ContinuationState
191dfbf818aSplunky 		 */
192dfbf818aSplunky 		if (ptr + 1 > end
193dfbf818aSplunky 		    || ptr[0] > 16
194dfbf818aSplunky 		    || ptr + ptr[0] + 1 != end)
195dfbf818aSplunky 			break;
196dfbf818aSplunky 
1979dc6fb5cSplunky 		memcpy(ss->cs, ptr, (size_t)(ptr[0] + 1));
198dfbf818aSplunky 
199dfbf818aSplunky 		/*
200dfbf818aSplunky 		 * Complete?
201dfbf818aSplunky 		 */
202dfbf818aSplunky 		if (ss->cs[0] == 0) {
203dfbf818aSplunky 			*num = got;
204dfbf818aSplunky 			return true;
205dfbf818aSplunky 		}
206dfbf818aSplunky 	}
207dfbf818aSplunky 
208dfbf818aSplunky 	errno = EIO;
209dfbf818aSplunky 	return false;
210dfbf818aSplunky }
211dfbf818aSplunky 
212dfbf818aSplunky bool
sdp_service_attribute(struct sdp_session * ss,uint32_t id,const sdp_data_t * ail,sdp_data_t * rsp)213dfbf818aSplunky sdp_service_attribute(struct sdp_session *ss, uint32_t id,
214dfbf818aSplunky     const sdp_data_t *ail, sdp_data_t *rsp)
215dfbf818aSplunky {
216dfbf818aSplunky 	struct iovec	req[6];
217dfbf818aSplunky 	sdp_data_t	hdr;
218dfbf818aSplunky 	uint8_t		adata[5], handle[4], max[2];
219dfbf818aSplunky 	uint8_t		*ptr, *end, *rbuf;
220dfbf818aSplunky 	ssize_t		len;
221dfbf818aSplunky 	size_t		rlen, count;
222dfbf818aSplunky 
223dfbf818aSplunky 	/*
224dfbf818aSplunky 	 * setup ServiceRecordHandle
225dfbf818aSplunky 	 */
226dfbf818aSplunky 	be32enc(handle, id);
227dfbf818aSplunky 	req[1].iov_base = handle;
228dfbf818aSplunky 	req[1].iov_len = sizeof(uint32_t);
229dfbf818aSplunky 
230dfbf818aSplunky 	/*
231dfbf818aSplunky 	 * setup MaximumAttributeByteCount
232dfbf818aSplunky 	 */
233dfbf818aSplunky 	be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs));
234dfbf818aSplunky 	req[2].iov_base = max;
235dfbf818aSplunky 	req[2].iov_len = sizeof(uint16_t);
236dfbf818aSplunky 
237dfbf818aSplunky 	/*
238dfbf818aSplunky 	 * setup AttributeIDList
239dfbf818aSplunky 	 */
2408ebedbbbSplunky 	len = (ail == NULL ? (ssize_t)sizeof(ail_default) : (ail->end - ail->next));
241dfbf818aSplunky 	if (len < 0 || len > UINT16_MAX) {
242dfbf818aSplunky 		errno = EINVAL;
243dfbf818aSplunky 		return false;
244dfbf818aSplunky 	}
245dfbf818aSplunky 
246dfbf818aSplunky 	hdr.next = adata;
247dfbf818aSplunky 	hdr.end = adata + sizeof(adata) + len;
248dfbf818aSplunky 	sdp_put_seq(&hdr, len);
249dfbf818aSplunky 	req[3].iov_base = adata;
250dfbf818aSplunky 	req[3].iov_len = hdr.next - adata;
251dfbf818aSplunky 
252dfbf818aSplunky 	req[4].iov_base = (ail == NULL ? ail_default : ail->next);
253dfbf818aSplunky 	req[4].iov_len = len;
254dfbf818aSplunky 
255dfbf818aSplunky 	/*
256dfbf818aSplunky 	 * clear ContinuationState
257dfbf818aSplunky 	 */
258dfbf818aSplunky 	ss->cs[0] = 0;
259dfbf818aSplunky 
260dfbf818aSplunky 	/*
261dfbf818aSplunky 	 * ServiceAttribute Transaction
262dfbf818aSplunky 	 */
263dfbf818aSplunky 	rlen = 0;
264dfbf818aSplunky 	for (;;) {
265dfbf818aSplunky 		/*
266dfbf818aSplunky 		 * setup ContinuationState
267dfbf818aSplunky 		 */
268dfbf818aSplunky 		req[5].iov_base = ss->cs;
269dfbf818aSplunky 		req[5].iov_len = ss->cs[0] + 1;
270dfbf818aSplunky 
271dfbf818aSplunky 		if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_REQUEST,
272dfbf818aSplunky 		    req, __arraycount(req)))
273dfbf818aSplunky 			return false;
274dfbf818aSplunky 
275dfbf818aSplunky 		len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE);
276dfbf818aSplunky 		if (len == -1)
277dfbf818aSplunky 			return false;
278dfbf818aSplunky 
279dfbf818aSplunky 		ptr = ss->ibuf;
280dfbf818aSplunky 		end = ss->ibuf + len;
281dfbf818aSplunky 
282dfbf818aSplunky 		/*
283dfbf818aSplunky 		 * extract AttributeListByteCount
284dfbf818aSplunky 		 */
285dfbf818aSplunky 		if (ptr + sizeof(uint16_t) > end)
286dfbf818aSplunky 			break;
287dfbf818aSplunky 
288dfbf818aSplunky 		count = be16dec(ptr);
289dfbf818aSplunky 		ptr += sizeof(uint16_t);
290dfbf818aSplunky 		if (count == 0 || ptr + count > end)
291dfbf818aSplunky 			break;
292dfbf818aSplunky 
293dfbf818aSplunky 		/*
294dfbf818aSplunky 		 * extract AttributeList
295dfbf818aSplunky 		 */
296dfbf818aSplunky 		if (rlen + count > sdp_response_max())
297dfbf818aSplunky 			break;
298dfbf818aSplunky 
299dfbf818aSplunky 		rbuf = realloc(ss->rbuf, rlen + count);
300dfbf818aSplunky 		if (rbuf == NULL)
301dfbf818aSplunky 			return false;
302dfbf818aSplunky 
303dfbf818aSplunky 		ss->rbuf = rbuf;
304dfbf818aSplunky 		memcpy(rbuf + rlen, ptr, count);
305dfbf818aSplunky 		rlen += count;
306dfbf818aSplunky 		ptr += count;
307dfbf818aSplunky 
308dfbf818aSplunky 		/*
309dfbf818aSplunky 		 * extract ContinuationState
310dfbf818aSplunky 		 */
311dfbf818aSplunky 		if (ptr + 1 > end
312dfbf818aSplunky 		    || ptr[0] > 16
313dfbf818aSplunky 		    || ptr + ptr[0] + 1 != end)
314dfbf818aSplunky 			break;
315dfbf818aSplunky 
3169dc6fb5cSplunky 		memcpy(ss->cs, ptr, (size_t)(ptr[0] + 1));
317dfbf818aSplunky 
318dfbf818aSplunky 		/*
319dfbf818aSplunky 		 * Complete?
320dfbf818aSplunky 		 */
321dfbf818aSplunky 		if (ss->cs[0] == 0) {
322dfbf818aSplunky 			rsp->next = rbuf;
323dfbf818aSplunky 			rsp->end = rbuf + rlen;
3248ebedbbbSplunky 			if (sdp_data_size(rsp) != (ssize_t)rlen
325dfbf818aSplunky 			    || !sdp_data_valid(rsp)
326dfbf818aSplunky 			    || !sdp_get_seq(rsp, rsp))
327dfbf818aSplunky 				break;
328dfbf818aSplunky 
329dfbf818aSplunky 			return true;
330dfbf818aSplunky 		}
331dfbf818aSplunky 	}
332dfbf818aSplunky 
333dfbf818aSplunky 	errno = EIO;
334dfbf818aSplunky 	return false;
335dfbf818aSplunky }
336dfbf818aSplunky 
337dfbf818aSplunky bool
sdp_service_search_attribute(struct sdp_session * ss,const sdp_data_t * ssp,const sdp_data_t * ail,sdp_data_t * rsp)338dfbf818aSplunky sdp_service_search_attribute(struct sdp_session *ss, const sdp_data_t *ssp,
339dfbf818aSplunky     const sdp_data_t *ail, sdp_data_t *rsp)
340dfbf818aSplunky {
341dfbf818aSplunky 	struct iovec	req[7];
342dfbf818aSplunky 	sdp_data_t	hdr;
343dfbf818aSplunky 	uint8_t		sdata[5], adata[5], max[2];
344dfbf818aSplunky 	uint8_t		*ptr, *end, *rbuf;
345dfbf818aSplunky 	ssize_t		len;
346dfbf818aSplunky 	size_t		rlen, count;
347dfbf818aSplunky 
348dfbf818aSplunky 	/*
349dfbf818aSplunky 	 * setup ServiceSearchPattern
350dfbf818aSplunky 	 */
351dfbf818aSplunky 	len = ssp->end - ssp->next;
352dfbf818aSplunky 	if (len < 0 || len > UINT16_MAX) {
353dfbf818aSplunky 		errno = EINVAL;
354dfbf818aSplunky 		return false;
355dfbf818aSplunky 	}
356dfbf818aSplunky 
357dfbf818aSplunky 	hdr.next = sdata;
358dfbf818aSplunky 	hdr.end = sdata + sizeof(sdata) + len;
359dfbf818aSplunky 	sdp_put_seq(&hdr, len);
360dfbf818aSplunky 	req[1].iov_base = sdata;
361dfbf818aSplunky 	req[1].iov_len = hdr.next - sdata;
362dfbf818aSplunky 
363dfbf818aSplunky 	req[2].iov_base = ssp->next;
364dfbf818aSplunky 	req[2].iov_len = len;
365dfbf818aSplunky 
366dfbf818aSplunky 	/*
367dfbf818aSplunky 	 * setup MaximumAttributeByteCount
368dfbf818aSplunky 	 */
369dfbf818aSplunky 	be16enc(max, ss->imtu - sizeof(uint16_t) - sizeof(ss->cs));
370dfbf818aSplunky 	req[3].iov_base = max;
371dfbf818aSplunky 	req[3].iov_len = sizeof(uint16_t);
372dfbf818aSplunky 
373dfbf818aSplunky 	/*
374dfbf818aSplunky 	 * setup AttributeIDList
375dfbf818aSplunky 	 */
3768ebedbbbSplunky 	len = (ail == NULL ? (ssize_t)sizeof(ail_default) : (ail->end - ail->next));
377dfbf818aSplunky 	if (len < 0 || len > UINT16_MAX) {
378dfbf818aSplunky 		errno = EINVAL;
379dfbf818aSplunky 		return false;
380dfbf818aSplunky 	}
381dfbf818aSplunky 
382dfbf818aSplunky 	hdr.next = adata;
383dfbf818aSplunky 	hdr.end = adata + sizeof(adata) + len;
384dfbf818aSplunky 	sdp_put_seq(&hdr, len);
385dfbf818aSplunky 	req[4].iov_base = adata;
386dfbf818aSplunky 	req[4].iov_len = hdr.next - adata;
387dfbf818aSplunky 
388dfbf818aSplunky 	req[5].iov_base = (ail == NULL ? ail_default : ail->next);
389dfbf818aSplunky 	req[5].iov_len = len;
390dfbf818aSplunky 
391dfbf818aSplunky 	/*
392dfbf818aSplunky 	 * clear ContinuationState
393dfbf818aSplunky 	 */
394dfbf818aSplunky 	ss->cs[0] = 0;
395dfbf818aSplunky 
396dfbf818aSplunky 	/*
397dfbf818aSplunky 	 * ServiceSearchAttribute Transaction
398dfbf818aSplunky 	 */
399dfbf818aSplunky 	rlen = 0;
400dfbf818aSplunky 	for (;;) {
401dfbf818aSplunky 		/*
402dfbf818aSplunky 		 * setup ContinuationState
403dfbf818aSplunky 		 */
404dfbf818aSplunky 		req[6].iov_base = ss->cs;
405dfbf818aSplunky 		req[6].iov_len = ss->cs[0] + 1;
406dfbf818aSplunky 
407dfbf818aSplunky 		if (!_sdp_send_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST,
408dfbf818aSplunky 		    req, __arraycount(req)))
409dfbf818aSplunky 			return false;
410dfbf818aSplunky 
411dfbf818aSplunky 		len = _sdp_recv_pdu(ss, SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE);
412dfbf818aSplunky 		if (len == -1)
413dfbf818aSplunky 			return false;
414dfbf818aSplunky 
415dfbf818aSplunky 		ptr = ss->ibuf;
416dfbf818aSplunky 		end = ss->ibuf + len;
417dfbf818aSplunky 
418dfbf818aSplunky 		/*
419dfbf818aSplunky 		 * extract AttributeListsByteCount
420dfbf818aSplunky 		 */
421dfbf818aSplunky 		if (ptr + sizeof(uint16_t) > end)
422dfbf818aSplunky 			break;
423dfbf818aSplunky 
424dfbf818aSplunky 		count = be16dec(ptr);
425dfbf818aSplunky 		ptr += sizeof(uint16_t);
426dfbf818aSplunky 		if (count == 0 || ptr + count > end)
427dfbf818aSplunky 			break;
428dfbf818aSplunky 
429dfbf818aSplunky 		/*
430dfbf818aSplunky 		 * extract AttributeLists
431dfbf818aSplunky 		 */
432dfbf818aSplunky 		if (rlen + count > sdp_response_max())
433dfbf818aSplunky 			break;
434dfbf818aSplunky 
435dfbf818aSplunky 		rbuf = realloc(ss->rbuf, rlen + count);
436dfbf818aSplunky 		if (rbuf == NULL)
437dfbf818aSplunky 			return false;
438dfbf818aSplunky 
439dfbf818aSplunky 		ss->rbuf = rbuf;
440dfbf818aSplunky 		memcpy(rbuf + rlen, ptr, count);
441dfbf818aSplunky 		rlen += count;
442dfbf818aSplunky 		ptr += count;
443dfbf818aSplunky 
444dfbf818aSplunky 		/*
445dfbf818aSplunky 		 * extract ContinuationState
446dfbf818aSplunky 		 */
447dfbf818aSplunky 		if (ptr + 1 > end
448dfbf818aSplunky 		    || ptr[0] > 16
449dfbf818aSplunky 		    || ptr + ptr[0] + 1 != end)
450dfbf818aSplunky 			break;
451dfbf818aSplunky 
4529dc6fb5cSplunky 		memcpy(ss->cs, ptr, (size_t)(ptr[0] + 1));
453dfbf818aSplunky 
454dfbf818aSplunky 		/*
455dfbf818aSplunky 		 * Complete?
456dfbf818aSplunky 		 */
457dfbf818aSplunky 		if (ss->cs[0] == 0) {
458dfbf818aSplunky 			rsp->next = rbuf;
459dfbf818aSplunky 			rsp->end = rbuf + rlen;
4608ebedbbbSplunky 			if (sdp_data_size(rsp) != (ssize_t)rlen
461dfbf818aSplunky 			    || !sdp_data_valid(rsp)
462dfbf818aSplunky 			    || !sdp_get_seq(rsp, rsp))
463dfbf818aSplunky 				break;
464dfbf818aSplunky 
465dfbf818aSplunky 			return true;
466dfbf818aSplunky 		}
467dfbf818aSplunky 	}
468dfbf818aSplunky 
469dfbf818aSplunky 	errno = EIO;
470dfbf818aSplunky 	return false;
471dfbf818aSplunky }
472