sdpd-request.c revision 3094ec7008735c80d35bd255ffc41e7bea2d3a3c
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_SYNTAX;
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	 * Calculate Attribute size acording to MTU
688	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
689	 */
690	max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) -
691			sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
692
693	/* pull header for AttributeList byte count */
694	buf->data += sizeof(uint16_t);
695	buf->buf_size -= sizeof(uint16_t);
696
697	if (cstate) {
698		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
699
700		SDPDBG("Obtained cached rsp : %p", pCache);
701
702		if (pCache) {
703			short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent);
704			pResponse = pCache->data;
705			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
706			buf->data_size += sent;
707			cstate->cStateValue.maxBytesSent += sent;
708
709			SDPDBG("Response size : %d sending now : %d bytes sent so far : %d",
710				pCache->data_size, sent, cstate->cStateValue.maxBytesSent);
711			if (cstate->cStateValue.maxBytesSent == pCache->data_size)
712				cstate_size = sdp_set_cstate_pdu(buf, NULL);
713			else
714				cstate_size = sdp_set_cstate_pdu(buf, cstate);
715		} else {
716			status = SDP_INVALID_CSTATE;
717			error("NULL cache buffer and non-NULL continuation state");
718		}
719	} else {
720		sdp_record_t *rec = sdp_record_find(handle);
721		status = extract_attrs(rec, seq, buf);
722		if (buf->data_size > max_rsp_size) {
723			sdp_cont_state_t newState;
724
725			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
726			newState.timestamp = sdp_cstate_alloc_buf(buf);
727			/*
728			 * Reset the buffer size to the maximum expected and
729			 * set the sdp_cont_state_t
730			 */
731			SDPDBG("Creating continuation state of size : %d", buf->data_size);
732			buf->data_size = max_rsp_size;
733			newState.cStateValue.maxBytesSent = max_rsp_size;
734			cstate_size = sdp_set_cstate_pdu(buf, &newState);
735		} else {
736			if (buf->data_size == 0)
737				sdp_append_to_buf(buf, 0, 0);
738			cstate_size = sdp_set_cstate_pdu(buf, NULL);
739		}
740	}
741
742	// push header
743	buf->data -= sizeof(uint16_t);
744	buf->buf_size += sizeof(uint16_t);
745
746done:
747	free(cstate);
748	if (seq)
749		sdp_list_free(seq, free);
750	if (status)
751		return status;
752
753	/* set attribute list byte count */
754	bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
755	buf->data_size += sizeof(uint16_t);
756	return 0;
757}
758
759/*
760 * combined service search and attribute extraction
761 */
762static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
763{
764	int status = 0, plen, totscanned;
765	uint8_t *pdata, *pResponse = NULL;
766	unsigned int max;
767	int scanned, rsp_count = 0;
768	sdp_list_t *pattern = NULL, *seq = NULL, *svcList;
769	sdp_cont_state_t *cstate = NULL;
770	short cstate_size = 0;
771	uint8_t dtd = 0;
772	sdp_buf_t tmpbuf;
773	size_t data_left = req->len;
774
775	tmpbuf.data = NULL;
776	pdata = req->buf + sizeof(sdp_pdu_hdr_t);
777	data_left = req->len - sizeof(sdp_pdu_hdr_t);
778	scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID);
779	if (scanned == -1) {
780		status = SDP_INVALID_SYNTAX;
781		goto done;
782	}
783	totscanned = scanned;
784
785	SDPDBG("Bytes scanned: %d", scanned);
786
787	pdata += scanned;
788	data_left -= scanned;
789
790	if (data_left < sizeof(uint16_t)) {
791		status = SDP_INVALID_SYNTAX;
792		goto done;
793	}
794
795	max = ntohs(bt_get_unaligned((uint16_t *)pdata));
796
797	pdata += sizeof(uint16_t);
798	data_left -= sizeof(uint16_t);
799
800	SDPDBG("Max Attr expected: %d", max);
801
802	if (data_left < sizeof(sdp_pdu_hdr_t)) {
803		status = SDP_INVALID_SYNTAX;
804		goto done;
805	}
806
807	/* extract the attribute list */
808	scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID);
809	if (scanned == -1) {
810		status = SDP_INVALID_SYNTAX;
811		goto done;
812	}
813
814	pdata += scanned;
815	data_left -= scanned;
816
817	totscanned += scanned + sizeof(uint16_t) + 1;
818
819	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
820	if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) {
821		status = SDP_INVALID_SYNTAX;
822		goto done;
823	}
824
825	/*
826	 * if continuation state exists attempt
827	 * to get rsp remainder from cache, else send error
828	 */
829	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
830		status = SDP_INVALID_SYNTAX;
831		goto done;
832	}
833
834	svcList = sdp_get_record_list();
835
836	tmpbuf.data = malloc(USHRT_MAX);
837	tmpbuf.data_size = 0;
838	tmpbuf.buf_size = USHRT_MAX;
839	memset(tmpbuf.data, 0, USHRT_MAX);
840
841	/*
842	 * Calculate Attribute size acording to MTU
843	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
844	 */
845	max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
846
847	/* pull header for AttributeList byte count */
848	buf->data += sizeof(uint16_t);
849	buf->buf_size -= sizeof(uint16_t);
850
851	if (cstate == NULL) {
852		/* no continuation state -> create new response */
853		sdp_list_t *p;
854		for (p = svcList; p; p = p->next) {
855			sdp_record_t *rec = (sdp_record_t *) p->data;
856			if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
857					sdp_check_access(rec->handle, &req->device)) {
858				rsp_count++;
859				status = extract_attrs(rec, seq, &tmpbuf);
860
861				SDPDBG("Response count : %d", rsp_count);
862				SDPDBG("Local PDU size : %d", tmpbuf.data_size);
863				if (status) {
864					SDPDBG("Extract attr from record returns err");
865					break;
866				}
867				if (buf->data_size + tmpbuf.data_size < buf->buf_size) {
868					// to be sure no relocations
869					sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
870					tmpbuf.data_size = 0;
871					memset(tmpbuf.data, 0, USHRT_MAX);
872				} else {
873					error("Relocation needed");
874					break;
875				}
876				SDPDBG("Net PDU size : %d", buf->data_size);
877			}
878		}
879		if (buf->data_size > max) {
880			sdp_cont_state_t newState;
881
882			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
883			newState.timestamp = sdp_cstate_alloc_buf(buf);
884			/*
885			 * Reset the buffer size to the maximum expected and
886			 * set the sdp_cont_state_t
887			 */
888			buf->data_size = max;
889			newState.cStateValue.maxBytesSent = max;
890			cstate_size = sdp_set_cstate_pdu(buf, &newState);
891		} else
892			cstate_size = sdp_set_cstate_pdu(buf, NULL);
893	} else {
894		/* continuation State exists -> get from cache */
895		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
896		if (pCache) {
897			uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent);
898			pResponse = pCache->data;
899			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
900			buf->data_size += sent;
901			cstate->cStateValue.maxBytesSent += sent;
902			if (cstate->cStateValue.maxBytesSent == pCache->data_size)
903				cstate_size = sdp_set_cstate_pdu(buf, NULL);
904			else
905				cstate_size = sdp_set_cstate_pdu(buf, cstate);
906		} else {
907			status = SDP_INVALID_CSTATE;
908			SDPDBG("Non-null continuation state, but null cache buffer");
909		}
910	}
911
912	if (!rsp_count && !cstate) {
913		// found nothing
914		buf->data_size = 0;
915		sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
916		sdp_set_cstate_pdu(buf, NULL);
917	}
918
919	// push header
920	buf->data -= sizeof(uint16_t);
921	buf->buf_size += sizeof(uint16_t);
922
923	if (!status) {
924		/* set attribute list byte count */
925		bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
926		buf->data_size += sizeof(uint16_t);
927	}
928
929done:
930	free(cstate);
931	free(tmpbuf.data);
932	if (pattern)
933		sdp_list_free(pattern, free);
934	if (seq)
935		sdp_list_free(seq, free);
936	return status;
937}
938
939/*
940 * Top level request processor. Calls the appropriate processing
941 * function based on request type. Handles service registration
942 * client requests also.
943 */
944static void process_request(sdp_req_t *req)
945{
946	sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf;
947	sdp_pdu_hdr_t *rsphdr;
948	sdp_buf_t rsp;
949	uint8_t *buf = malloc(USHRT_MAX);
950	int sent = 0;
951	int status = SDP_INVALID_SYNTAX;
952
953	memset(buf, 0, USHRT_MAX);
954	rsp.data = buf + sizeof(sdp_pdu_hdr_t);
955	rsp.data_size = 0;
956	rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t);
957	rsphdr = (sdp_pdu_hdr_t *)buf;
958
959	if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) {
960		status = SDP_INVALID_PDU_SIZE;
961		goto send_rsp;
962	}
963	switch (reqhdr->pdu_id) {
964	case SDP_SVC_SEARCH_REQ:
965		SDPDBG("Got a svc srch req");
966		status = service_search_req(req, &rsp);
967		rsphdr->pdu_id = SDP_SVC_SEARCH_RSP;
968		break;
969	case SDP_SVC_ATTR_REQ:
970		SDPDBG("Got a svc attr req");
971		status = service_attr_req(req, &rsp);
972		rsphdr->pdu_id = SDP_SVC_ATTR_RSP;
973		break;
974	case SDP_SVC_SEARCH_ATTR_REQ:
975		SDPDBG("Got a svc srch attr req");
976		status = service_search_attr_req(req, &rsp);
977		rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
978		break;
979	/* Following requests are allowed only for local connections */
980	case SDP_SVC_REGISTER_REQ:
981		SDPDBG("Service register request");
982		if (req->local) {
983			status = service_register_req(req, &rsp);
984			rsphdr->pdu_id = SDP_SVC_REGISTER_RSP;
985		}
986		break;
987	case SDP_SVC_UPDATE_REQ:
988		SDPDBG("Service update request");
989		if (req->local) {
990			status = service_update_req(req, &rsp);
991			rsphdr->pdu_id = SDP_SVC_UPDATE_RSP;
992		}
993		break;
994	case SDP_SVC_REMOVE_REQ:
995		SDPDBG("Service removal request");
996		if (req->local) {
997			status = service_remove_req(req, &rsp);
998			rsphdr->pdu_id = SDP_SVC_REMOVE_RSP;
999		}
1000		break;
1001	default:
1002		error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);
1003		status = SDP_INVALID_SYNTAX;
1004		break;
1005	}
1006
1007send_rsp:
1008	if (status) {
1009		rsphdr->pdu_id = SDP_ERROR_RSP;
1010		bt_put_unaligned(htons(status), (uint16_t *)rsp.data);
1011		rsp.data_size = sizeof(uint16_t);
1012	}
1013
1014	SDPDBG("Sending rsp. status %d", status);
1015
1016	rsphdr->tid  = reqhdr->tid;
1017	rsphdr->plen = htons(rsp.data_size);
1018
1019	/* point back to the real buffer start and set the real rsp length */
1020	rsp.data_size += sizeof(sdp_pdu_hdr_t);
1021	rsp.data = buf;
1022
1023	/* stream the rsp PDU */
1024	sent = send(req->sock, rsp.data, rsp.data_size, 0);
1025
1026	SDPDBG("Bytes Sent : %d", sent);
1027
1028	free(rsp.data);
1029	free(req->buf);
1030}
1031
1032void handle_request(int sk, uint8_t *data, int len)
1033{
1034	struct sockaddr_l2 sa;
1035	socklen_t size;
1036	sdp_req_t req;
1037
1038	size = sizeof(sa);
1039	if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) {
1040		error("getpeername: %s", strerror(errno));
1041		return;
1042	}
1043
1044	if (sa.l2_family == AF_BLUETOOTH) {
1045		struct l2cap_options lo;
1046
1047		memset(&lo, 0, sizeof(lo));
1048		size = sizeof(lo);
1049
1050		if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size) < 0) {
1051			error("getsockopt: %s", strerror(errno));
1052			return;
1053		}
1054
1055		bacpy(&req.bdaddr, &sa.l2_bdaddr);
1056		req.mtu = lo.omtu;
1057		req.local = 0;
1058		memset(&sa, 0, sizeof(sa));
1059		size = sizeof(sa);
1060
1061		if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) {
1062			error("getsockname: %s", strerror(errno));
1063			return;
1064		}
1065
1066		bacpy(&req.device, &sa.l2_bdaddr);
1067	} else {
1068		bacpy(&req.device, BDADDR_ANY);
1069		bacpy(&req.bdaddr, BDADDR_LOCAL);
1070		req.mtu = 2048;
1071		req.local = 1;
1072	}
1073
1074	req.sock = sk;
1075	req.buf  = data;
1076	req.len  = len;
1077
1078	process_request(&req);
1079}
1080