sdpd-request.c revision 5bdbbb44d612746b5c19932f9da15a3ced57ff05
1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2001-2002  Nokia Corporation
6 *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
7 *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
8 *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
9 *
10 *
11 *  This program is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation; either version 2 of the License, or
14 *  (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License
22 *  along with this program; if not, write to the Free Software
23 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24 *
25 */
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30
31#include <stdio.h>
32#include <errno.h>
33#include <stdlib.h>
34#include <string.h>
35#include <limits.h>
36#include <sys/socket.h>
37
38#include <bluetooth/bluetooth.h>
39#include <bluetooth/l2cap.h>
40#include <bluetooth/sdp.h>
41#include <bluetooth/sdp_lib.h>
42
43#include <netinet/in.h>
44
45#include "sdpd.h"
46#include "log.h"
47
48#define MIN(x, y) ((x) < (y)) ? (x): (y)
49
50typedef struct _sdp_cstate_list sdp_cstate_list_t;
51
52struct _sdp_cstate_list {
53	sdp_cstate_list_t *next;
54	uint32_t timestamp;
55	sdp_buf_t buf;
56};
57
58static sdp_cstate_list_t *cstates;
59
60// FIXME: should probably remove it when it's found
61sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate)
62{
63	sdp_cstate_list_t *p;
64
65	for (p = cstates; p; p = p->next)
66		if (p->timestamp == cstate->timestamp)
67			return &p->buf;
68	return 0;
69}
70
71static uint32_t sdp_cstate_alloc_buf(sdp_buf_t *buf)
72{
73	sdp_cstate_list_t *cstate = malloc(sizeof(sdp_cstate_list_t));
74	uint8_t *data = malloc(buf->data_size);
75
76	memcpy(data, buf->data, buf->data_size);
77	memset((char *)cstate, 0, sizeof(sdp_cstate_list_t));
78	cstate->buf.data = data;
79	cstate->buf.data_size = buf->data_size;
80	cstate->buf.buf_size = buf->data_size;
81	cstate->timestamp = sdp_get_time();
82	cstate->next = cstates;
83	cstates = cstate;
84	return cstate->timestamp;
85}
86
87/* Additional values for checking datatype (not in spec) */
88#define SDP_TYPE_UUID	0xfe
89#define SDP_TYPE_ATTRID	0xff
90
91struct attrid {
92	uint8_t dtd;
93	union {
94		uint16_t uint16;
95		uint32_t uint32;
96	};
97};
98
99/*
100 * Generic data element sequence extractor. Builds
101 * a list whose elements are those found in the
102 * sequence. The data type of elements found in the
103 * sequence is returned in the reference pDataType
104 */
105static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType)
106{
107	uint8_t seqType;
108	int scanned, data_size = 0;
109	short numberOfElements = 0;
110	int seqlen = 0;
111	sdp_list_t *pSeq = NULL;
112	uint8_t dataType;
113	int status = 0;
114	const uint8_t *p;
115	size_t bufsize;
116
117	scanned = sdp_extract_seqtype(buf, len, &seqType, &data_size);
118
119	SDPDBG("Seq type : %d", seqType);
120	if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) {
121		error("Unknown seq type");
122		return -1;
123	}
124	p = buf + scanned;
125	bufsize = len - scanned;
126
127	SDPDBG("Data size : %d", data_size);
128
129	for (;;) {
130		char *pElem = NULL;
131		int localSeqLength = 0;
132
133		if (bufsize < sizeof(uint8_t)) {
134			SDPDBG("->Unexpected end of buffer");
135			goto failed;
136		}
137
138		dataType = *p;
139
140		SDPDBG("Data type: 0x%02x", dataType);
141
142		if (expectedType == SDP_TYPE_UUID) {
143			if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) {
144				SDPDBG("->Unexpected Data type (expected UUID_ANY)");
145				goto failed;
146			}
147		} else if (expectedType == SDP_TYPE_ATTRID &&
148				(dataType != SDP_UINT16 && dataType != SDP_UINT32)) {
149			SDPDBG("->Unexpected Data type (expected 0x%02x or 0x%02x)",
150								SDP_UINT16, SDP_UINT32);
151			goto failed;
152		} else if (expectedType != SDP_TYPE_ATTRID && dataType != expectedType) {
153			SDPDBG("->Unexpected Data type (expected 0x%02x)", expectedType);
154			goto failed;
155		}
156
157		switch (dataType) {
158		case SDP_UINT16:
159			p += sizeof(uint8_t);
160			seqlen += sizeof(uint8_t);
161			bufsize -= sizeof(uint8_t);
162			if (bufsize < sizeof(uint16_t)) {
163				SDPDBG("->Unexpected end of buffer");
164				goto failed;
165			}
166
167			if (expectedType == SDP_TYPE_ATTRID) {
168				struct attrid *aid;
169				aid = malloc(sizeof(struct attrid));
170				aid->dtd = dataType;
171				bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)&aid->uint16);
172				pElem = (char *) aid;
173			} else {
174				pElem = malloc(sizeof(uint16_t));
175				bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem);
176			}
177			p += sizeof(uint16_t);
178			seqlen += sizeof(uint16_t);
179			bufsize -= sizeof(uint16_t);
180			break;
181		case SDP_UINT32:
182			p += sizeof(uint8_t);
183			seqlen += sizeof(uint8_t);
184			bufsize -= sizeof(uint8_t);
185			if (bufsize < (int)sizeof(uint32_t)) {
186				SDPDBG("->Unexpected end of buffer");
187				goto failed;
188			}
189
190			if (expectedType == SDP_TYPE_ATTRID) {
191				struct attrid *aid;
192				aid = malloc(sizeof(struct attrid));
193				aid->dtd = dataType;
194				bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)&aid->uint32);
195				pElem = (char *) aid;
196			} else {
197				pElem = malloc(sizeof(uint32_t));
198				bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem);
199			}
200			p += sizeof(uint32_t);
201			seqlen += sizeof(uint32_t);
202			bufsize -= sizeof(uint32_t);
203			break;
204		case SDP_UUID16:
205		case SDP_UUID32:
206		case SDP_UUID128:
207			pElem = malloc(sizeof(uuid_t));
208			status = sdp_uuid_extract(p, bufsize, (uuid_t *) pElem, &localSeqLength);
209			if (status < 0) {
210				free(pElem);
211				goto failed;
212			}
213			seqlen += localSeqLength;
214			p += localSeqLength;
215			bufsize -= localSeqLength;
216			break;
217		default:
218			return -1;
219		}
220		if (status == 0) {
221			pSeq = sdp_list_append(pSeq, pElem);
222			numberOfElements++;
223			SDPDBG("No of elements : %d", numberOfElements);
224
225			if (seqlen == data_size)
226				break;
227			else if (seqlen > data_size || seqlen > len)
228				goto failed;
229		} else
230			free(pElem);
231	}
232	*svcReqSeq = pSeq;
233	scanned += seqlen;
234	*pDataType = dataType;
235	return scanned;
236
237failed:
238	sdp_list_free(pSeq, free);
239	return -1;
240}
241
242static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate)
243{
244	uint8_t *pdata = buf->data + buf->data_size;
245	int length = 0;
246
247	if (cstate) {
248		SDPDBG("Non null sdp_cstate_t id : 0x%x", cstate->timestamp);
249		*(uint8_t *)pdata = sizeof(sdp_cont_state_t);
250		pdata += sizeof(uint8_t);
251		length += sizeof(uint8_t);
252		memcpy(pdata, cstate, sizeof(sdp_cont_state_t));
253		length += sizeof(sdp_cont_state_t);
254	} else {
255		// set "null" continuation state
256		*(uint8_t *)pdata = 0;
257		pdata += sizeof(uint8_t);
258		length += sizeof(uint8_t);
259	}
260	buf->data_size += length;
261	return length;
262}
263
264static int sdp_cstate_get(uint8_t *buffer, size_t len,
265						sdp_cont_state_t **cstate)
266{
267	uint8_t cStateSize = *buffer;
268
269	SDPDBG("Continuation State size : %d", cStateSize);
270
271	if (cStateSize == 0) {
272		*cstate = NULL;
273		return 0;
274	}
275
276	buffer++;
277	len--;
278
279	if (len < sizeof(sdp_cont_state_t))
280		return -EINVAL;
281
282	/*
283	 * Check if continuation state exists, if yes attempt
284	 * to get response remainder from cache, else send error
285	 */
286
287	*cstate = malloc(sizeof(sdp_cont_state_t));
288	if (!(*cstate))
289		return -ENOMEM;
290
291	memcpy(*cstate, buffer, sizeof(sdp_cont_state_t));
292
293	SDPDBG("Cstate TS : 0x%x", (*cstate)->timestamp);
294	SDPDBG("Bytes sent : %d", (*cstate)->cStateValue.maxBytesSent);
295
296	return 0;
297}
298
299/*
300 * The matching process is defined as "each and every UUID
301 * specified in the "search pattern" must be present in the
302 * "target pattern". Here "search pattern" is the set of UUIDs
303 * specified by the service discovery client and "target pattern"
304 * is the set of UUIDs present in a service record.
305 *
306 * Return 1 if each and every UUID in the search
307 * pattern exists in the target pattern, 0 if the
308 * match succeeds and -1 on error.
309 */
310static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern)
311{
312	/*
313	 * The target is a sorted list, so we need not look
314	 * at all elements to confirm existence of an element
315	 * from the search pattern
316	 */
317	int patlen = sdp_list_len(pattern);
318
319	if (patlen < sdp_list_len(search))
320		return -1;
321	for (; search; search = search->next) {
322		uuid_t *uuid128;
323		void *data = search->data;
324		sdp_list_t *list;
325		if (data == NULL)
326			return -1;
327
328		// create 128-bit form of the search UUID
329		uuid128 = sdp_uuid_to_uuid128((uuid_t *)data);
330		list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp);
331		bt_free(uuid128);
332		if (!list)
333			return 0;
334	}
335	return 1;
336}
337
338/*
339 * Service search request PDU. This method extracts the search pattern
340 * (a sequence of UUIDs) and calls the matching function
341 * to find matching services
342 */
343static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
344{
345	int status = 0, i, plen, mlen, mtu, scanned;
346	sdp_list_t *pattern = NULL;
347	uint16_t expected, actual, rsp_count = 0;
348	uint8_t dtd;
349	sdp_cont_state_t *cstate = NULL;
350	uint8_t *pCacheBuffer = NULL;
351	int handleSize = 0;
352	uint32_t cStateId = 0;
353	short *pTotalRecordCount, *pCurrentRecordCount;
354	uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
355	size_t data_left = req->len - sizeof(sdp_pdu_hdr_t);
356
357	scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID);
358
359	if (scanned == -1) {
360		status = SDP_INVALID_SYNTAX;
361		goto done;
362	}
363	pdata += scanned;
364	data_left -= scanned;
365
366	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
367	mlen = scanned + sizeof(uint16_t) + 1;
368	// ensure we don't read past buffer
369	if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) {
370		status = SDP_INVALID_PDU_SIZE;
371		goto done;
372	}
373
374	if (data_left < sizeof(uint16_t)) {
375		status = SDP_INVALID_SYNTAX;
376		goto done;
377	}
378
379	expected = ntohs(bt_get_unaligned((uint16_t *)pdata));
380
381	SDPDBG("Expected count: %d", expected);
382	SDPDBG("Bytes scanned : %d", scanned);
383
384	pdata += sizeof(uint16_t);
385	data_left -= sizeof(uint16_t);
386
387	/*
388	 * Check if continuation state exists, if yes attempt
389	 * to get rsp remainder from cache, else send error
390	 */
391	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
392		status = SDP_INVALID_SYNTAX;
393		goto done;
394	}
395
396	mtu = req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - SDP_CONT_STATE_SIZE;
397	actual = MIN(expected, mtu >> 2);
398
399	/* make space in the rsp buffer for total and current record counts */
400	pdata = buf->data;
401
402	/* total service record count = 0 */
403	pTotalRecordCount = (short *)pdata;
404	bt_put_unaligned(0, (uint16_t *)pdata);
405	pdata += sizeof(uint16_t);
406	buf->data_size += sizeof(uint16_t);
407
408	/* current service record count = 0 */
409	pCurrentRecordCount = (short *)pdata;
410	bt_put_unaligned(0, (uint16_t *)pdata);
411	pdata += sizeof(uint16_t);
412	buf->data_size += sizeof(uint16_t);
413
414	if (cstate == NULL) {
415		/* for every record in the DB, do a pattern search */
416		sdp_list_t *list = sdp_get_record_list();
417
418		handleSize = 0;
419		for (; list && rsp_count < expected; list = list->next) {
420			sdp_record_t *rec = (sdp_record_t *) list->data;
421
422			SDPDBG("Checking svcRec : 0x%x", rec->handle);
423
424			if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
425					sdp_check_access(rec->handle, &req->device)) {
426				rsp_count++;
427				bt_put_unaligned(htonl(rec->handle), (uint32_t *)pdata);
428				pdata += sizeof(uint32_t);
429				handleSize += sizeof(uint32_t);
430			}
431		}
432
433		SDPDBG("Match count: %d", rsp_count);
434
435		buf->data_size += handleSize;
436		bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
437		bt_put_unaligned(htons(rsp_count), (uint16_t *)pCurrentRecordCount);
438
439		if (rsp_count > actual) {
440			/* cache the rsp and generate a continuation state */
441			cStateId = sdp_cstate_alloc_buf(buf);
442			/*
443			 * subtract handleSize since we now send only
444			 * a subset of handles
445			 */
446			buf->data_size -= handleSize;
447		} else {
448			/* NULL continuation state */
449			sdp_set_cstate_pdu(buf, NULL);
450		}
451	}
452
453	/* under both the conditions below, the rsp buffer is not built yet */
454	if (cstate || cStateId > 0) {
455		short lastIndex = 0;
456
457		if (cstate) {
458			/*
459			 * Get the previous sdp_cont_state_t and obtain
460			 * the cached rsp
461			 */
462			sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
463			if (pCache) {
464				pCacheBuffer = pCache->data;
465				/* get the rsp_count from the cached buffer */
466				rsp_count = ntohs(bt_get_unaligned((uint16_t *)pCacheBuffer));
467
468				/* get index of the last sdp_record_t sent */
469				lastIndex = cstate->cStateValue.lastIndexSent;
470			} else {
471				status = SDP_INVALID_CSTATE;
472				goto done;
473			}
474		} else {
475			pCacheBuffer = buf->data;
476			lastIndex = 0;
477		}
478
479		/*
480		 * Set the local buffer pointer to after the
481		 * current record count and increment the cached
482		 * buffer pointer to beyond the counters
483		 */
484		pdata = (uint8_t *) pCurrentRecordCount + sizeof(uint16_t);
485
486		/* increment beyond the totalCount and the currentCount */
487		pCacheBuffer += 2 * sizeof(uint16_t);
488
489		if (cstate) {
490			handleSize = 0;
491			for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) {
492				bt_put_unaligned(bt_get_unaligned((uint32_t *)(pCacheBuffer + i * sizeof(uint32_t))), (uint32_t *)pdata);
493				pdata += sizeof(uint32_t);
494				handleSize += sizeof(uint32_t);
495			}
496		} else {
497			handleSize = actual << 2;
498			i = actual;
499		}
500
501		buf->data_size += handleSize;
502		bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
503		bt_put_unaligned(htons(i - lastIndex), (uint16_t *)pCurrentRecordCount);
504
505		if (i == rsp_count) {
506			/* set "null" continuationState */
507			sdp_set_cstate_pdu(buf, NULL);
508		} else {
509			/*
510			 * there's more: set lastIndexSent to
511			 * the new value and move on
512			 */
513			sdp_cont_state_t newState;
514
515			SDPDBG("Setting non-NULL sdp_cstate_t");
516
517			if (cstate)
518				memcpy(&newState, cstate, sizeof(sdp_cont_state_t));
519			else {
520				memset(&newState, 0, sizeof(sdp_cont_state_t));
521				newState.timestamp = cStateId;
522			}
523			newState.cStateValue.lastIndexSent = i;
524			sdp_set_cstate_pdu(buf, &newState);
525		}
526	}
527
528done:
529	free(cstate);
530	if (pattern)
531		sdp_list_free(pattern, free);
532
533	return status;
534}
535
536/*
537 * Extract attribute identifiers from the request PDU.
538 * Clients could request a subset of attributes (by id)
539 * from a service record, instead of the whole set. The
540 * requested identifiers are present in the PDU form of
541 * the request
542 */
543static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, sdp_buf_t *buf)
544{
545	sdp_buf_t pdu;
546
547	if (!rec)
548		return SDP_INVALID_RECORD_HANDLE;
549
550	if (seq) {
551		SDPDBG("Entries in attr seq : %d", sdp_list_len(seq));
552	} else {
553		SDPDBG("NULL attribute descriptor");
554	}
555
556	if (seq == NULL) {
557		SDPDBG("Attribute sequence is NULL");
558		return 0;
559	}
560
561	sdp_gen_record_pdu(rec, &pdu);
562
563	for (; seq; seq = seq->next) {
564		struct attrid *aid = seq->data;
565
566		SDPDBG("AttrDataType : %d", aid->dtd);
567
568		if (aid->dtd == SDP_UINT16) {
569			uint16_t attr = bt_get_unaligned((uint16_t *)&aid->uint16);
570			sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr);
571			if (a)
572				sdp_append_to_pdu(buf, a);
573		} else if (aid->dtd == SDP_UINT32) {
574			uint32_t range = bt_get_unaligned((uint32_t *)&aid->uint32);
575			uint16_t attr;
576			uint16_t low = (0xffff0000 & range) >> 16;
577			uint16_t high = 0x0000ffff & range;
578			sdp_data_t *data;
579
580			SDPDBG("attr range : 0x%x", range);
581			SDPDBG("Low id : 0x%x", low);
582			SDPDBG("High id : 0x%x", high);
583
584			if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) {
585				/* copy it */
586				memcpy(buf->data, pdu.data, pdu.data_size);
587				buf->data_size = pdu.data_size;
588				break;
589			}
590			/* (else) sub-range of attributes */
591			for (attr = low; attr < high; attr++) {
592				data = sdp_data_get(rec, attr);
593				if (data)
594					sdp_append_to_pdu(buf, data);
595			}
596			data = sdp_data_get(rec, high);
597			if (data)
598				sdp_append_to_pdu(buf, data);
599		} else {
600			error("Unexpected data type : 0x%x", aid->dtd);
601			error("Expect uint16_t or uint32_t");
602			free(pdu.data);
603			return SDP_INVALID_SYNTAX;
604		}
605	}
606
607	free(pdu.data);
608
609	return 0;
610}
611
612/*
613 * A request for the attributes of a service record.
614 * First check if the service record (specified by
615 * service record handle) exists, then call the attribute
616 * streaming function
617 */
618static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
619{
620	sdp_cont_state_t *cstate = NULL;
621	uint8_t *pResponse = NULL;
622	short cstate_size = 0;
623	sdp_list_t *seq = NULL;
624	uint8_t dtd = 0;
625	int scanned = 0;
626	unsigned int max_rsp_size;
627	int status = 0, plen, mlen;
628	uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
629	size_t data_left = req->len - sizeof(sdp_pdu_hdr_t);
630	uint32_t handle;
631
632	if (data_left < sizeof(uint32_t)) {
633		status = SDP_INVALID_SYNTAX;
634		goto done;
635	}
636
637	handle = ntohl(bt_get_unaligned((uint32_t *)pdata));
638
639	pdata += sizeof(uint32_t);
640	data_left -= sizeof(uint32_t);
641
642	if (data_left < sizeof(uint16_t)) {
643		status = SDP_INVALID_SYNTAX;
644		goto done;
645	}
646
647	max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata));
648
649	pdata += sizeof(uint16_t);
650	data_left -= sizeof(uint16_t);
651
652	if (data_left < sizeof(sdp_pdu_hdr_t)) {
653		status = SDP_INVALID_SYNTAX;
654		goto done;
655	}
656
657	/* extract the attribute list */
658	scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID);
659	if (scanned == -1) {
660		status = SDP_INVALID_SYNTAX;
661		goto done;
662	}
663	pdata += scanned;
664	data_left -= scanned;
665
666	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
667	mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1;
668	// ensure we don't read past buffer
669	if (plen < mlen || plen != mlen + *(uint8_t *)pdata) {
670		status = SDP_INVALID_PDU_SIZE;
671		goto done;
672	}
673
674	/*
675	 * if continuation state exists, attempt
676	 * to get rsp remainder from cache, else send error
677	 */
678	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
679		status = SDP_INVALID_SYNTAX;
680		goto done;
681	}
682
683	SDPDBG("SvcRecHandle : 0x%x", handle);
684	SDPDBG("max_rsp_size : %d", max_rsp_size);
685
686	/*
687	 * Check that max_rsp_size is within valid range
688	 * a minimum size of 0x0007 has to be used for data field
689	 */
690	if (max_rsp_size < 0x0007) {
691		status = SDP_INVALID_SYNTAX;
692		goto done;
693	}
694
695	/*
696	 * Calculate Attribute size acording to MTU
697	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
698	 */
699	max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) -
700			sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
701
702	/* pull header for AttributeList byte count */
703	buf->data += sizeof(uint16_t);
704	buf->buf_size -= sizeof(uint16_t);
705
706	if (cstate) {
707		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
708
709		SDPDBG("Obtained cached rsp : %p", pCache);
710
711		if (pCache) {
712			short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent);
713			pResponse = pCache->data;
714			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
715			buf->data_size += sent;
716			cstate->cStateValue.maxBytesSent += sent;
717
718			SDPDBG("Response size : %d sending now : %d bytes sent so far : %d",
719				pCache->data_size, sent, cstate->cStateValue.maxBytesSent);
720			if (cstate->cStateValue.maxBytesSent == pCache->data_size)
721				cstate_size = sdp_set_cstate_pdu(buf, NULL);
722			else
723				cstate_size = sdp_set_cstate_pdu(buf, cstate);
724		} else {
725			status = SDP_INVALID_CSTATE;
726			error("NULL cache buffer and non-NULL continuation state");
727		}
728	} else {
729		sdp_record_t *rec = sdp_record_find(handle);
730		status = extract_attrs(rec, seq, buf);
731		if (buf->data_size > max_rsp_size) {
732			sdp_cont_state_t newState;
733
734			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
735			newState.timestamp = sdp_cstate_alloc_buf(buf);
736			/*
737			 * Reset the buffer size to the maximum expected and
738			 * set the sdp_cont_state_t
739			 */
740			SDPDBG("Creating continuation state of size : %d", buf->data_size);
741			buf->data_size = max_rsp_size;
742			newState.cStateValue.maxBytesSent = max_rsp_size;
743			cstate_size = sdp_set_cstate_pdu(buf, &newState);
744		} else {
745			if (buf->data_size == 0)
746				sdp_append_to_buf(buf, 0, 0);
747			cstate_size = sdp_set_cstate_pdu(buf, NULL);
748		}
749	}
750
751	// push header
752	buf->data -= sizeof(uint16_t);
753	buf->buf_size += sizeof(uint16_t);
754
755done:
756	free(cstate);
757	if (seq)
758		sdp_list_free(seq, free);
759	if (status)
760		return status;
761
762	/* set attribute list byte count */
763	bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
764	buf->data_size += sizeof(uint16_t);
765	return 0;
766}
767
768/*
769 * combined service search and attribute extraction
770 */
771static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
772{
773	int status = 0, plen, totscanned;
774	uint8_t *pdata, *pResponse = NULL;
775	unsigned int max;
776	int scanned, rsp_count = 0;
777	sdp_list_t *pattern = NULL, *seq = NULL, *svcList;
778	sdp_cont_state_t *cstate = NULL;
779	short cstate_size = 0;
780	uint8_t dtd = 0;
781	sdp_buf_t tmpbuf;
782	size_t data_left = req->len;
783
784	tmpbuf.data = NULL;
785	pdata = req->buf + sizeof(sdp_pdu_hdr_t);
786	data_left = req->len - sizeof(sdp_pdu_hdr_t);
787	scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID);
788	if (scanned == -1) {
789		status = SDP_INVALID_SYNTAX;
790		goto done;
791	}
792	totscanned = scanned;
793
794	SDPDBG("Bytes scanned: %d", scanned);
795
796	pdata += scanned;
797	data_left -= scanned;
798
799	if (data_left < sizeof(uint16_t)) {
800		status = SDP_INVALID_SYNTAX;
801		goto done;
802	}
803
804	max = ntohs(bt_get_unaligned((uint16_t *)pdata));
805
806	pdata += sizeof(uint16_t);
807	data_left -= sizeof(uint16_t);
808
809	SDPDBG("Max Attr expected: %d", max);
810
811	if (data_left < sizeof(sdp_pdu_hdr_t)) {
812		status = SDP_INVALID_SYNTAX;
813		goto done;
814	}
815
816	/* extract the attribute list */
817	scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID);
818	if (scanned == -1) {
819		status = SDP_INVALID_SYNTAX;
820		goto done;
821	}
822
823	pdata += scanned;
824	data_left -= scanned;
825
826	totscanned += scanned + sizeof(uint16_t) + 1;
827
828	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
829	if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) {
830		status = SDP_INVALID_PDU_SIZE;
831		goto done;
832	}
833
834	/*
835	 * if continuation state exists attempt
836	 * to get rsp remainder from cache, else send error
837	 */
838	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
839		status = SDP_INVALID_SYNTAX;
840		goto done;
841	}
842
843	svcList = sdp_get_record_list();
844
845	tmpbuf.data = malloc(USHRT_MAX);
846	tmpbuf.data_size = 0;
847	tmpbuf.buf_size = USHRT_MAX;
848	memset(tmpbuf.data, 0, USHRT_MAX);
849
850	/*
851	 * Calculate Attribute size acording to MTU
852	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
853	 */
854	max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
855
856	/* pull header for AttributeList byte count */
857	buf->data += sizeof(uint16_t);
858	buf->buf_size -= sizeof(uint16_t);
859
860	if (cstate == NULL) {
861		/* no continuation state -> create new response */
862		sdp_list_t *p;
863		for (p = svcList; p; p = p->next) {
864			sdp_record_t *rec = (sdp_record_t *) p->data;
865			if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
866					sdp_check_access(rec->handle, &req->device)) {
867				rsp_count++;
868				status = extract_attrs(rec, seq, &tmpbuf);
869
870				SDPDBG("Response count : %d", rsp_count);
871				SDPDBG("Local PDU size : %d", tmpbuf.data_size);
872				if (status) {
873					SDPDBG("Extract attr from record returns err");
874					break;
875				}
876				if (buf->data_size + tmpbuf.data_size < buf->buf_size) {
877					// to be sure no relocations
878					sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
879					tmpbuf.data_size = 0;
880					memset(tmpbuf.data, 0, USHRT_MAX);
881				} else {
882					error("Relocation needed");
883					break;
884				}
885				SDPDBG("Net PDU size : %d", buf->data_size);
886			}
887		}
888		if (buf->data_size > max) {
889			sdp_cont_state_t newState;
890
891			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
892			newState.timestamp = sdp_cstate_alloc_buf(buf);
893			/*
894			 * Reset the buffer size to the maximum expected and
895			 * set the sdp_cont_state_t
896			 */
897			buf->data_size = max;
898			newState.cStateValue.maxBytesSent = max;
899			cstate_size = sdp_set_cstate_pdu(buf, &newState);
900		} else
901			cstate_size = sdp_set_cstate_pdu(buf, NULL);
902	} else {
903		/* continuation State exists -> get from cache */
904		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
905		if (pCache) {
906			uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent);
907			pResponse = pCache->data;
908			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
909			buf->data_size += sent;
910			cstate->cStateValue.maxBytesSent += sent;
911			if (cstate->cStateValue.maxBytesSent == pCache->data_size)
912				cstate_size = sdp_set_cstate_pdu(buf, NULL);
913			else
914				cstate_size = sdp_set_cstate_pdu(buf, cstate);
915		} else {
916			status = SDP_INVALID_CSTATE;
917			SDPDBG("Non-null continuation state, but null cache buffer");
918		}
919	}
920
921	if (!rsp_count && !cstate) {
922		// found nothing
923		buf->data_size = 0;
924		sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
925		sdp_set_cstate_pdu(buf, NULL);
926	}
927
928	// push header
929	buf->data -= sizeof(uint16_t);
930	buf->buf_size += sizeof(uint16_t);
931
932	if (!status) {
933		/* set attribute list byte count */
934		bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
935		buf->data_size += sizeof(uint16_t);
936	}
937
938done:
939	free(cstate);
940	free(tmpbuf.data);
941	if (pattern)
942		sdp_list_free(pattern, free);
943	if (seq)
944		sdp_list_free(seq, free);
945	return status;
946}
947
948/*
949 * Top level request processor. Calls the appropriate processing
950 * function based on request type. Handles service registration
951 * client requests also.
952 */
953static void process_request(sdp_req_t *req)
954{
955	sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf;
956	sdp_pdu_hdr_t *rsphdr;
957	sdp_buf_t rsp;
958	uint8_t *buf = malloc(USHRT_MAX);
959	int sent = 0;
960	int status = SDP_INVALID_SYNTAX;
961
962	memset(buf, 0, USHRT_MAX);
963	rsp.data = buf + sizeof(sdp_pdu_hdr_t);
964	rsp.data_size = 0;
965	rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t);
966	rsphdr = (sdp_pdu_hdr_t *)buf;
967
968	if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) {
969		status = SDP_INVALID_PDU_SIZE;
970		goto send_rsp;
971	}
972	switch (reqhdr->pdu_id) {
973	case SDP_SVC_SEARCH_REQ:
974		SDPDBG("Got a svc srch req");
975		status = service_search_req(req, &rsp);
976		rsphdr->pdu_id = SDP_SVC_SEARCH_RSP;
977		break;
978	case SDP_SVC_ATTR_REQ:
979		SDPDBG("Got a svc attr req");
980		status = service_attr_req(req, &rsp);
981		rsphdr->pdu_id = SDP_SVC_ATTR_RSP;
982		break;
983	case SDP_SVC_SEARCH_ATTR_REQ:
984		SDPDBG("Got a svc srch attr req");
985		status = service_search_attr_req(req, &rsp);
986		rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
987		break;
988	/* Following requests are allowed only for local connections */
989	case SDP_SVC_REGISTER_REQ:
990		SDPDBG("Service register request");
991		if (req->local) {
992			status = service_register_req(req, &rsp);
993			rsphdr->pdu_id = SDP_SVC_REGISTER_RSP;
994		}
995		break;
996	case SDP_SVC_UPDATE_REQ:
997		SDPDBG("Service update request");
998		if (req->local) {
999			status = service_update_req(req, &rsp);
1000			rsphdr->pdu_id = SDP_SVC_UPDATE_RSP;
1001		}
1002		break;
1003	case SDP_SVC_REMOVE_REQ:
1004		SDPDBG("Service removal request");
1005		if (req->local) {
1006			status = service_remove_req(req, &rsp);
1007			rsphdr->pdu_id = SDP_SVC_REMOVE_RSP;
1008		}
1009		break;
1010	default:
1011		error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);
1012		status = SDP_INVALID_SYNTAX;
1013		break;
1014	}
1015
1016send_rsp:
1017	if (status) {
1018		rsphdr->pdu_id = SDP_ERROR_RSP;
1019		bt_put_unaligned(htons(status), (uint16_t *)rsp.data);
1020		rsp.data_size = sizeof(uint16_t);
1021	}
1022
1023	SDPDBG("Sending rsp. status %d", status);
1024
1025	rsphdr->tid  = reqhdr->tid;
1026	rsphdr->plen = htons(rsp.data_size);
1027
1028	/* point back to the real buffer start and set the real rsp length */
1029	rsp.data_size += sizeof(sdp_pdu_hdr_t);
1030	rsp.data = buf;
1031
1032	/* stream the rsp PDU */
1033	sent = send(req->sock, rsp.data, rsp.data_size, 0);
1034
1035	SDPDBG("Bytes Sent : %d", sent);
1036
1037	free(rsp.data);
1038	free(req->buf);
1039}
1040
1041void handle_request(int sk, uint8_t *data, int len)
1042{
1043	struct sockaddr_l2 sa;
1044	socklen_t size;
1045	sdp_req_t req;
1046
1047	size = sizeof(sa);
1048	if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) {
1049		error("getpeername: %s", strerror(errno));
1050		return;
1051	}
1052
1053	if (sa.l2_family == AF_BLUETOOTH) {
1054		struct l2cap_options lo;
1055
1056		memset(&lo, 0, sizeof(lo));
1057		size = sizeof(lo);
1058
1059		if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size) < 0) {
1060			error("getsockopt: %s", strerror(errno));
1061			return;
1062		}
1063
1064		bacpy(&req.bdaddr, &sa.l2_bdaddr);
1065		req.mtu = lo.omtu;
1066		req.local = 0;
1067		memset(&sa, 0, sizeof(sa));
1068		size = sizeof(sa);
1069
1070		if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) {
1071			error("getsockname: %s", strerror(errno));
1072			return;
1073		}
1074
1075		bacpy(&req.device, &sa.l2_bdaddr);
1076	} else {
1077		bacpy(&req.device, BDADDR_ANY);
1078		bacpy(&req.bdaddr, BDADDR_LOCAL);
1079		req.mtu = 2048;
1080		req.local = 1;
1081	}
1082
1083	req.sock = sk;
1084	req.buf  = data;
1085	req.len  = len;
1086
1087	process_request(&req);
1088}
1089