sdpd-request.c revision b5fe14e46c4351fe582f009de2f0b6d6834566e5
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-2009  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 "logging.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_ANY	0xff
90
91/*
92 * Generic data element sequence extractor. Builds
93 * a list whose elements are those found in the
94 * sequence. The data type of elements found in the
95 * sequence is returned in the reference pDataType
96 */
97static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType)
98{
99	uint8_t seqType;
100	int scanned, data_size = 0;
101	short numberOfElements = 0;
102	int seqlen = 0;
103	sdp_list_t *pSeq = NULL;
104	uint8_t dataType;
105	int status = 0;
106	const uint8_t *p;
107	int bufsize;
108
109	scanned = sdp_extract_seqtype(buf, len, &seqType, &data_size);
110
111	SDPDBG("Seq type : %d", seqType);
112	if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) {
113		error("Unknown seq type");
114		return -1;
115	}
116	p = buf + scanned;
117	bufsize = len - scanned;
118
119	SDPDBG("Data size : %d", data_size);
120
121	for (;;) {
122		char *pElem = NULL;
123		int localSeqLength = 0;
124
125		if (bufsize < sizeof(uint8_t)) {
126			SDPDBG("->Unexpected end of buffer");
127			return -1;
128		}
129
130		dataType = *(uint8_t *)p;
131		SDPDBG("Data type: 0x%02x", dataType);
132
133		if (expectedType == SDP_TYPE_UUID) {
134			if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) {
135				SDPDBG("->Unexpected Data type (expected UUID_ANY)");
136				return -1;
137			}
138		} else if (expectedType != SDP_TYPE_ANY && dataType != expectedType) {
139			SDPDBG("->Unexpected Data type (expected 0x%02x)", expectedType);
140			return -1;
141		}
142
143		switch (dataType) {
144		case SDP_UINT16:
145			p += sizeof(uint8_t);
146			seqlen += sizeof(uint8_t);
147			bufsize -= sizeof(uint8_t);
148			if (bufsize < sizeof(uint16_t)) {
149				SDPDBG("->Unexpected end of buffer");
150				return -1;
151			}
152
153			pElem = malloc(sizeof(uint16_t));
154			bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem);
155			p += sizeof(uint16_t);
156			seqlen += sizeof(uint16_t);
157			bufsize -= sizeof(uint16_t);
158			break;
159		case SDP_UINT32:
160			p += sizeof(uint8_t);
161			seqlen += sizeof(uint8_t);
162			bufsize -= sizeof(uint8_t);
163			if (bufsize < (int)sizeof(uint32_t)) {
164				SDPDBG("->Unexpected end of buffer");
165				return -1;
166			}
167
168			pElem = malloc(sizeof(uint32_t));
169			bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem);
170			p += sizeof(uint32_t);
171			seqlen += sizeof(uint32_t);
172			bufsize -= sizeof(uint32_t);
173			break;
174		case SDP_UUID16:
175		case SDP_UUID32:
176		case SDP_UUID128:
177			pElem = malloc(sizeof(uuid_t));
178			status = sdp_uuid_extract(p, bufsize, (uuid_t *) pElem, &localSeqLength);
179			if (status < 0) {
180				free(pElem);
181				return -1;
182			}
183			seqlen += localSeqLength;
184			p += localSeqLength;
185			bufsize -= localSeqLength;
186			break;
187		default:
188			return -1;
189		}
190		if (status == 0) {
191			pSeq = sdp_list_append(pSeq, pElem);
192			numberOfElements++;
193			SDPDBG("No of elements : %d", numberOfElements);
194
195			if (seqlen == data_size)
196				break;
197			else if (seqlen > data_size || seqlen > len)
198				return -1;
199		} else
200			free(pElem);
201	}
202	*svcReqSeq = pSeq;
203	scanned += seqlen;
204	*pDataType = dataType;
205	return scanned;
206}
207
208static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate)
209{
210	uint8_t *pdata = buf->data + buf->data_size;
211	int length = 0;
212
213	if (cstate) {
214		SDPDBG("Non null sdp_cstate_t id : 0x%x", cstate->timestamp);
215		*(uint8_t *)pdata = sizeof(sdp_cont_state_t);
216		pdata += sizeof(uint8_t);
217		length += sizeof(uint8_t);
218		memcpy(pdata, cstate, sizeof(sdp_cont_state_t));
219		length += sizeof(sdp_cont_state_t);
220	} else {
221		// set "null" continuation state
222		*(uint8_t *)pdata = 0;
223		pdata += sizeof(uint8_t);
224		length += sizeof(uint8_t);
225	}
226	buf->data_size += length;
227	return length;
228}
229
230static sdp_cont_state_t *sdp_cstate_get(uint8_t *buffer)
231{
232	uint8_t *pdata = buffer;
233	uint8_t cStateSize = *(uint8_t *)pdata;
234
235	/*
236	 * Check if continuation state exists, if yes attempt
237	 * to get response remainder from cache, else send error
238	 */
239	SDPDBG("Continuation State size : %d", cStateSize);
240
241	pdata += sizeof(uint8_t);
242	if (cStateSize != 0) {
243		sdp_cont_state_t *cstate = malloc(sizeof(sdp_cont_state_t));
244		if (!cstate)
245			return NULL;
246		memcpy(cstate, (sdp_cont_state_t *)pdata, sizeof(sdp_cont_state_t));
247		SDPDBG("Cstate TS : 0x%x", cstate->timestamp);
248		SDPDBG("Bytes sent : %d", cstate->cStateValue.maxBytesSent);
249		return cstate;
250	}
251	return NULL;
252}
253
254/*
255 * The matching process is defined as "each and every UUID
256 * specified in the "search pattern" must be present in the
257 * "target pattern". Here "search pattern" is the set of UUIDs
258 * specified by the service discovery client and "target pattern"
259 * is the set of UUIDs present in a service record.
260 *
261 * Return 1 if each and every UUID in the search
262 * pattern exists in the target pattern, 0 if the
263 * match succeeds and -1 on error.
264 */
265static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern)
266{
267	/*
268	 * The target is a sorted list, so we need not look
269	 * at all elements to confirm existence of an element
270	 * from the search pattern
271	 */
272	int patlen = sdp_list_len(pattern);
273
274	if (patlen < sdp_list_len(search))
275		return -1;
276	for (; search; search = search->next) {
277		uuid_t *uuid128;
278		void *data = search->data;
279		sdp_list_t *list;
280		if (data == NULL)
281			return -1;
282
283		// create 128-bit form of the search UUID
284		uuid128 = sdp_uuid_to_uuid128((uuid_t *)data);
285		list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp);
286		bt_free(uuid128);
287		if (!list)
288			return 0;
289	}
290	return 1;
291}
292
293/*
294 * Service search request PDU. This method extracts the search pattern
295 * (a sequence of UUIDs) and calls the matching function
296 * to find matching services
297 */
298static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
299{
300	int status = 0, i, plen, mlen, mtu, scanned;
301	sdp_list_t *pattern = NULL;
302	uint16_t expected, actual, rsp_count = 0;
303	uint8_t dtd;
304	sdp_cont_state_t *cstate = NULL;
305	uint8_t *pCacheBuffer = NULL;
306	int handleSize = 0;
307	uint32_t cStateId = 0;
308	short *pTotalRecordCount, *pCurrentRecordCount;
309	uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
310
311	scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
312					&pattern, &dtd, SDP_TYPE_UUID);
313
314	if (scanned == -1) {
315		status = SDP_INVALID_SYNTAX;
316		goto done;
317	}
318	pdata += scanned;
319
320	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
321	mlen = scanned + sizeof(uint16_t) + 1;
322	// ensure we don't read past buffer
323	if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) {
324		status = SDP_INVALID_SYNTAX;
325		goto done;
326	}
327
328	expected = ntohs(bt_get_unaligned((uint16_t *)pdata));
329
330	SDPDBG("Expected count: %d", expected);
331	SDPDBG("Bytes scanned : %d", scanned);
332
333	pdata += sizeof(uint16_t);
334
335	/*
336	 * Check if continuation state exists, if yes attempt
337	 * to get rsp remainder from cache, else send error
338	 */
339	cstate = sdp_cstate_get(pdata);
340
341	mtu = req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - SDP_CONT_STATE_SIZE;
342	actual = MIN(expected, mtu >> 2);
343
344	/* make space in the rsp buffer for total and current record counts */
345	pdata = buf->data;
346
347	/* total service record count = 0 */
348	pTotalRecordCount = (short *)pdata;
349	bt_put_unaligned(0, (uint16_t *)pdata);
350	pdata += sizeof(uint16_t);
351	buf->data_size += sizeof(uint16_t);
352
353	/* current service record count = 0 */
354	pCurrentRecordCount = (short *)pdata;
355	bt_put_unaligned(0, (uint16_t *)pdata);
356	pdata += sizeof(uint16_t);
357	buf->data_size += sizeof(uint16_t);
358
359	if (cstate == NULL) {
360		/* for every record in the DB, do a pattern search */
361		sdp_list_t *list = sdp_get_record_list();
362
363		handleSize = 0;
364		for (; list && rsp_count < expected; list = list->next) {
365			sdp_record_t *rec = (sdp_record_t *) list->data;
366
367			SDPDBG("Checking svcRec : 0x%x", rec->handle);
368
369			if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
370					sdp_check_access(rec->handle, &req->device)) {
371				rsp_count++;
372				bt_put_unaligned(htonl(rec->handle), (uint32_t *)pdata);
373				pdata += sizeof(uint32_t);
374				handleSize += sizeof(uint32_t);
375			}
376		}
377
378		SDPDBG("Match count: %d", rsp_count);
379
380		buf->data_size += handleSize;
381		bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
382		bt_put_unaligned(htons(rsp_count), (uint16_t *)pCurrentRecordCount);
383
384		if (rsp_count > actual) {
385			/* cache the rsp and generate a continuation state */
386			cStateId = sdp_cstate_alloc_buf(buf);
387			/*
388			 * subtract handleSize since we now send only
389			 * a subset of handles
390			 */
391			buf->data_size -= handleSize;
392		} else {
393			/* NULL continuation state */
394			sdp_set_cstate_pdu(buf, NULL);
395		}
396	}
397
398	/* under both the conditions below, the rsp buffer is not built yet */
399	if (cstate || cStateId > 0) {
400		short lastIndex = 0;
401
402		if (cstate) {
403			/*
404			 * Get the previous sdp_cont_state_t and obtain
405			 * the cached rsp
406			 */
407			sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
408			if (pCache) {
409				pCacheBuffer = pCache->data;
410				/* get the rsp_count from the cached buffer */
411				rsp_count = ntohs(bt_get_unaligned((uint16_t *)pCacheBuffer));
412
413				/* get index of the last sdp_record_t sent */
414				lastIndex = cstate->cStateValue.lastIndexSent;
415			} else {
416				status = SDP_INVALID_CSTATE;
417				goto done;
418			}
419		} else {
420			pCacheBuffer = buf->data;
421			lastIndex = 0;
422		}
423
424		/*
425		 * Set the local buffer pointer to after the
426		 * current record count and increment the cached
427		 * buffer pointer to beyond the counters
428		 */
429		pdata = (uint8_t *) pCurrentRecordCount + sizeof(uint16_t);
430
431		/* increment beyond the totalCount and the currentCount */
432		pCacheBuffer += 2 * sizeof(uint16_t);
433
434		if (cstate) {
435			handleSize = 0;
436			for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) {
437				bt_put_unaligned(bt_get_unaligned((uint32_t *)(pCacheBuffer + i * sizeof(uint32_t))), (uint32_t *)pdata);
438				pdata += sizeof(uint32_t);
439				handleSize += sizeof(uint32_t);
440			}
441		} else {
442			handleSize = actual << 2;
443			i = actual;
444		}
445
446		buf->data_size += handleSize;
447		bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
448		bt_put_unaligned(htons(i - lastIndex), (uint16_t *)pCurrentRecordCount);
449
450		if (i == rsp_count) {
451			/* set "null" continuationState */
452			sdp_set_cstate_pdu(buf, NULL);
453		} else {
454			/*
455			 * there's more: set lastIndexSent to
456			 * the new value and move on
457			 */
458			sdp_cont_state_t newState;
459
460			SDPDBG("Setting non-NULL sdp_cstate_t");
461
462			if (cstate)
463				memcpy((char *)&newState, cstate, sizeof(sdp_cont_state_t));
464			else {
465				memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
466				newState.timestamp = cStateId;
467			}
468			newState.cStateValue.lastIndexSent = i;
469			sdp_set_cstate_pdu(buf, &newState);
470		}
471	}
472
473done:
474	if (cstate)
475		free(cstate);
476	if (pattern)
477		sdp_list_free(pattern, free);
478
479	return status;
480}
481
482/*
483 * Extract attribute identifiers from the request PDU.
484 * Clients could request a subset of attributes (by id)
485 * from a service record, instead of the whole set. The
486 * requested identifiers are present in the PDU form of
487 * the request
488 */
489static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, uint8_t dtd, sdp_buf_t *buf)
490{
491	if (!rec)
492		return SDP_INVALID_RECORD_HANDLE;
493
494	if (seq) {
495		SDPDBG("Entries in attr seq : %d", sdp_list_len(seq));
496	} else {
497		SDPDBG("NULL attribute descriptor");
498	}
499
500	SDPDBG("AttrDataType : %d", dtd);
501
502	if (seq == NULL) {
503		SDPDBG("Attribute sequence is NULL");
504		return 0;
505	}
506	if (dtd == SDP_UINT16)
507		for (; seq; seq = seq->next) {
508			uint16_t attr = bt_get_unaligned((uint16_t *)seq->data);
509			sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr);
510			if (a)
511				sdp_append_to_pdu(buf, a);
512		}
513	else if (dtd == SDP_UINT32) {
514		sdp_buf_t pdu;
515		sdp_gen_record_pdu(rec, &pdu);
516		for (; seq; seq = seq->next) {
517			uint32_t range = bt_get_unaligned((uint32_t *)seq->data);
518			uint16_t attr;
519			uint16_t low = (0xffff0000 & range) >> 16;
520			uint16_t high = 0x0000ffff & range;
521			sdp_data_t *data;
522
523			SDPDBG("attr range : 0x%x", range);
524			SDPDBG("Low id : 0x%x", low);
525			SDPDBG("High id : 0x%x", high);
526
527			if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) {
528				/* copy it */
529				memcpy(buf->data, pdu.data, pdu.data_size);
530				buf->data_size = pdu.data_size;
531				break;
532			}
533			/* (else) sub-range of attributes */
534			for (attr = low; attr < high; attr++) {
535				data = sdp_data_get(rec, attr);
536				if (data)
537					sdp_append_to_pdu(buf, data);
538			}
539			data = sdp_data_get(rec, high);
540			if (data)
541				sdp_append_to_pdu(buf, data);
542		}
543		free(pdu.data);
544	} else {
545		error("Unexpected data type : 0x%x", dtd);
546		error("Expect uint16_t or uint32_t");
547		return SDP_INVALID_SYNTAX;
548	}
549	return 0;
550}
551
552/*
553 * A request for the attributes of a service record.
554 * First check if the service record (specified by
555 * service record handle) exists, then call the attribute
556 * streaming function
557 */
558static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
559{
560	sdp_cont_state_t *cstate = NULL;
561	uint8_t *pResponse = NULL;
562	short cstate_size = 0;
563	sdp_list_t *seq = NULL;
564	uint8_t dtd = 0;
565	int scanned = 0;
566	int max_rsp_size;
567	int status = 0, plen, mlen;
568	uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
569	uint32_t handle = ntohl(bt_get_unaligned((uint32_t *)pdata));
570
571	pdata += sizeof(uint32_t);
572	max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata));
573	pdata += sizeof(uint16_t);
574
575	/* extract the attribute list */
576	scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
577						&seq, &dtd, SDP_TYPE_ANY);
578	if (scanned == -1) {
579		status = SDP_INVALID_SYNTAX;
580		goto done;
581	}
582	pdata += scanned;
583
584	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
585	mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1;
586	// ensure we don't read past buffer
587	if (plen < mlen || plen != mlen + *(uint8_t *)pdata) {
588		status = SDP_INVALID_SYNTAX;
589		goto done;
590	}
591
592	/*
593	 * if continuation state exists, attempt
594	 * to get rsp remainder from cache, else send error
595	 */
596	cstate = sdp_cstate_get(pdata);
597
598	SDPDBG("SvcRecHandle : 0x%x", handle);
599	SDPDBG("max_rsp_size : %d", max_rsp_size);
600
601	/*
602	 * Calculate Attribute size acording to MTU
603	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
604	 */
605	max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) -
606			sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
607
608	/* pull header for AttributeList byte count */
609	buf->data += sizeof(uint16_t);
610	buf->buf_size -= sizeof(uint16_t);
611
612	if (cstate) {
613		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
614
615		SDPDBG("Obtained cached rsp : %p", pCache);
616
617		if (pCache) {
618			short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent);
619			pResponse = pCache->data;
620			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
621			buf->data_size += sent;
622			cstate->cStateValue.maxBytesSent += sent;
623
624			SDPDBG("Response size : %d sending now : %d bytes sent so far : %d",
625				pCache->data_size, sent, cstate->cStateValue.maxBytesSent);
626			if (cstate->cStateValue.maxBytesSent == pCache->data_size)
627				cstate_size = sdp_set_cstate_pdu(buf, NULL);
628			else
629				cstate_size = sdp_set_cstate_pdu(buf, cstate);
630		} else {
631			status = SDP_INVALID_CSTATE;
632			error("NULL cache buffer and non-NULL continuation state");
633		}
634	} else {
635		sdp_record_t *rec = sdp_record_find(handle);
636		status = extract_attrs(rec, seq, dtd, buf);
637		if (buf->data_size > max_rsp_size) {
638			sdp_cont_state_t newState;
639
640			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
641			newState.timestamp = sdp_cstate_alloc_buf(buf);
642			/*
643			 * Reset the buffer size to the maximum expected and
644			 * set the sdp_cont_state_t
645			 */
646			SDPDBG("Creating continuation state of size : %d", buf->data_size);
647			buf->data_size = max_rsp_size;
648			newState.cStateValue.maxBytesSent = max_rsp_size;
649			cstate_size = sdp_set_cstate_pdu(buf, &newState);
650		} else {
651			if (buf->data_size == 0)
652				sdp_append_to_buf(buf, 0, 0);
653			cstate_size = sdp_set_cstate_pdu(buf, NULL);
654		}
655	}
656
657	// push header
658	buf->data -= sizeof(uint16_t);
659	buf->buf_size += sizeof(uint16_t);
660
661done:
662	if (cstate)
663		free(cstate);
664	if (seq)
665		sdp_list_free(seq, free);
666	if (status)
667		return status;
668
669	/* set attribute list byte count */
670	bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
671	buf->data_size += sizeof(uint16_t);
672	return 0;
673}
674
675/*
676 * combined service search and attribute extraction
677 */
678static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
679{
680	int status = 0, plen, totscanned;
681	uint8_t *pdata, *pResponse = NULL;
682	int scanned, max, rsp_count = 0;
683	sdp_list_t *pattern = NULL, *seq = NULL, *svcList;
684	sdp_cont_state_t *cstate = NULL;
685	short cstate_size = 0;
686	uint8_t dtd = 0;
687	sdp_buf_t tmpbuf;
688
689	tmpbuf.data = NULL;
690	pdata = req->buf + sizeof(sdp_pdu_hdr_t);
691	scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
692					&pattern, &dtd, SDP_TYPE_UUID);
693	if (scanned == -1) {
694		status = SDP_INVALID_SYNTAX;
695		goto done;
696	}
697	totscanned = scanned;
698
699	SDPDBG("Bytes scanned: %d", scanned);
700
701	pdata += scanned;
702	max = ntohs(bt_get_unaligned((uint16_t *)pdata));
703	pdata += sizeof(uint16_t);
704
705	SDPDBG("Max Attr expected: %d", max);
706
707	/* extract the attribute list */
708	scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
709						&seq, &dtd, SDP_TYPE_ANY);
710	if (scanned == -1) {
711		status = SDP_INVALID_SYNTAX;
712		goto done;
713	}
714	pdata += scanned;
715	totscanned += scanned + sizeof(uint16_t) + 1;
716
717	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
718	if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) {
719		status = SDP_INVALID_SYNTAX;
720		goto done;
721	}
722
723	/*
724	 * if continuation state exists attempt
725	 * to get rsp remainder from cache, else send error
726	 */
727	cstate = sdp_cstate_get(pdata);	// continuation information
728
729	svcList = sdp_get_record_list();
730
731	tmpbuf.data = malloc(USHRT_MAX);
732	tmpbuf.data_size = 0;
733	tmpbuf.buf_size = USHRT_MAX;
734	memset(tmpbuf.data, 0, USHRT_MAX);
735
736	/*
737	 * Calculate Attribute size acording to MTU
738	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
739	 */
740	max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
741
742	/* pull header for AttributeList byte count */
743	buf->data += sizeof(uint16_t);
744	buf->buf_size -= sizeof(uint16_t);
745
746	if (cstate == NULL) {
747		/* no continuation state -> create new response */
748		sdp_list_t *p;
749		for (p = svcList; p; p = p->next) {
750			sdp_record_t *rec = (sdp_record_t *) p->data;
751			if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
752					sdp_check_access(rec->handle, &req->device)) {
753				rsp_count++;
754				status = extract_attrs(rec, seq, dtd, &tmpbuf);
755
756				SDPDBG("Response count : %d", rsp_count);
757				SDPDBG("Local PDU size : %d", tmpbuf.data_size);
758				if (status) {
759					SDPDBG("Extract attr from record returns err");
760					break;
761				}
762				if (buf->data_size + tmpbuf.data_size < buf->buf_size) {
763					// to be sure no relocations
764					sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
765					tmpbuf.data_size = 0;
766					memset(tmpbuf.data, 0, USHRT_MAX);
767				} else {
768					error("Relocation needed");
769					break;
770				}
771				SDPDBG("Net PDU size : %d", buf->data_size);
772			}
773		}
774		if (buf->data_size > max) {
775			sdp_cont_state_t newState;
776
777			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
778			newState.timestamp = sdp_cstate_alloc_buf(buf);
779			/*
780			 * Reset the buffer size to the maximum expected and
781			 * set the sdp_cont_state_t
782			 */
783			buf->data_size = max;
784			newState.cStateValue.maxBytesSent = max;
785			cstate_size = sdp_set_cstate_pdu(buf, &newState);
786		} else
787			cstate_size = sdp_set_cstate_pdu(buf, NULL);
788	} else {
789		/* continuation State exists -> get from cache */
790		sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
791		if (pCache) {
792			uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent);
793			pResponse = pCache->data;
794			memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
795			buf->data_size += sent;
796			cstate->cStateValue.maxBytesSent += sent;
797			if (cstate->cStateValue.maxBytesSent == pCache->data_size)
798				cstate_size = sdp_set_cstate_pdu(buf, NULL);
799			else
800				cstate_size = sdp_set_cstate_pdu(buf, cstate);
801		} else {
802			status = SDP_INVALID_CSTATE;
803			SDPDBG("Non-null continuation state, but null cache buffer");
804		}
805	}
806
807	if (!rsp_count && !cstate) {
808		// found nothing
809		buf->data_size = 0;
810		sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
811		sdp_set_cstate_pdu(buf, NULL);
812	}
813
814	// push header
815	buf->data -= sizeof(uint16_t);
816	buf->buf_size += sizeof(uint16_t);
817
818	if (!status) {
819		/* set attribute list byte count */
820		bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
821		buf->data_size += sizeof(uint16_t);
822	}
823
824done:
825	if (cstate)
826		free(cstate);
827	if (tmpbuf.data)
828		free(tmpbuf.data);
829	if (pattern)
830		sdp_list_free(pattern, free);
831	if (seq)
832		sdp_list_free(seq, free);
833	return status;
834}
835
836/*
837 * Top level request processor. Calls the appropriate processing
838 * function based on request type. Handles service registration
839 * client requests also.
840 */
841static void process_request(sdp_req_t *req)
842{
843	sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf;
844	sdp_pdu_hdr_t *rsphdr;
845	sdp_buf_t rsp;
846	uint8_t *buf = malloc(USHRT_MAX);
847	int sent = 0;
848	int status = SDP_INVALID_SYNTAX;
849
850	memset(buf, 0, USHRT_MAX);
851	rsp.data = buf + sizeof(sdp_pdu_hdr_t);
852	rsp.data_size = 0;
853	rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t);
854	rsphdr = (sdp_pdu_hdr_t *)buf;
855
856	if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) {
857		status = SDP_INVALID_PDU_SIZE;
858		goto send_rsp;
859	}
860	switch (reqhdr->pdu_id) {
861	case SDP_SVC_SEARCH_REQ:
862		SDPDBG("Got a svc srch req");
863		status = service_search_req(req, &rsp);
864		rsphdr->pdu_id = SDP_SVC_SEARCH_RSP;
865		break;
866	case SDP_SVC_ATTR_REQ:
867		SDPDBG("Got a svc attr req");
868		status = service_attr_req(req, &rsp);
869		rsphdr->pdu_id = SDP_SVC_ATTR_RSP;
870		break;
871	case SDP_SVC_SEARCH_ATTR_REQ:
872		SDPDBG("Got a svc srch attr req");
873		status = service_search_attr_req(req, &rsp);
874		rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
875		break;
876	/* Following requests are allowed only for local connections */
877	case SDP_SVC_REGISTER_REQ:
878		SDPDBG("Service register request");
879		if (req->local) {
880			status = service_register_req(req, &rsp);
881			rsphdr->pdu_id = SDP_SVC_REGISTER_RSP;
882		}
883		break;
884	case SDP_SVC_UPDATE_REQ:
885		SDPDBG("Service update request");
886		if (req->local) {
887			status = service_update_req(req, &rsp);
888			rsphdr->pdu_id = SDP_SVC_UPDATE_RSP;
889		}
890		break;
891	case SDP_SVC_REMOVE_REQ:
892		SDPDBG("Service removal request");
893		if (req->local) {
894			status = service_remove_req(req, &rsp);
895			rsphdr->pdu_id = SDP_SVC_REMOVE_RSP;
896		}
897		break;
898	default:
899		error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);
900		status = SDP_INVALID_SYNTAX;
901		break;
902	}
903
904send_rsp:
905	if (status) {
906		rsphdr->pdu_id = SDP_ERROR_RSP;
907		bt_put_unaligned(htons(status), (uint16_t *)rsp.data);
908		rsp.data_size = sizeof(uint16_t);
909	}
910
911	SDPDBG("Sending rsp. status %d", status);
912
913	rsphdr->tid  = reqhdr->tid;
914	rsphdr->plen = htons(rsp.data_size);
915
916	/* point back to the real buffer start and set the real rsp length */
917	rsp.data_size += sizeof(sdp_pdu_hdr_t);
918	rsp.data = buf;
919
920	/* stream the rsp PDU */
921	sent = send(req->sock, rsp.data, rsp.data_size, 0);
922
923	SDPDBG("Bytes Sent : %d", sent);
924
925	free(rsp.data);
926	free(req->buf);
927}
928
929void handle_request(int sk, uint8_t *data, int len)
930{
931	struct sockaddr_l2 sa;
932	socklen_t size;
933	sdp_req_t req;
934
935	size = sizeof(sa);
936	if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0)
937		return;
938
939	if (sa.l2_family == AF_BLUETOOTH) {
940		struct l2cap_options lo;
941		memset(&lo, 0, sizeof(lo));
942		size = sizeof(lo);
943		getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size);
944		bacpy(&req.bdaddr, &sa.l2_bdaddr);
945		req.mtu = lo.omtu;
946		req.local = 0;
947		memset(&sa, 0, sizeof(sa));
948		size = sizeof(sa);
949		getsockname(sk, (struct sockaddr *) &sa, &size);
950		bacpy(&req.device, &sa.l2_bdaddr);
951	} else {
952		bacpy(&req.device, BDADDR_ANY);
953		bacpy(&req.bdaddr, BDADDR_LOCAL);
954		req.mtu = 2048;
955		req.local = 1;
956	}
957
958	req.sock = sk;
959	req.buf  = data;
960	req.len  = len;
961
962	process_request(&req);
963}
964