Blame src/sdpd-request.c

Packit 34410b
/*
Packit 34410b
 *
Packit 34410b
 *  BlueZ - Bluetooth protocol stack for Linux
Packit 34410b
 *
Packit 34410b
 *  Copyright (C) 2001-2002  Nokia Corporation
Packit 34410b
 *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
Packit 34410b
 *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
Packit 34410b
 *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
Packit 34410b
 *
Packit 34410b
 *
Packit 34410b
 *  This program is free software; you can redistribute it and/or modify
Packit 34410b
 *  it under the terms of the GNU General Public License as published by
Packit 34410b
 *  the Free Software Foundation; either version 2 of the License, or
Packit 34410b
 *  (at your option) any later version.
Packit 34410b
 *
Packit 34410b
 *  This program is distributed in the hope that it will be useful,
Packit 34410b
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 34410b
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 34410b
 *  GNU General Public License for more details.
Packit 34410b
 *
Packit 34410b
 *  You should have received a copy of the GNU General Public License
Packit 34410b
 *  along with this program; if not, write to the Free Software
Packit 34410b
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 34410b
 *
Packit 34410b
 */
Packit 34410b
Packit 34410b
#ifdef HAVE_CONFIG_H
Packit 34410b
#include <config.h>
Packit 34410b
#endif
Packit 34410b
Packit 34410b
#include <errno.h>
Packit 34410b
#include <stdlib.h>
Packit 34410b
#include <limits.h>
Packit 34410b
#include <stdbool.h>
Packit 34410b
Packit 34410b
#include "lib/bluetooth.h"
Packit 34410b
#include "lib/l2cap.h"
Packit 34410b
#include "lib/sdp.h"
Packit 34410b
#include "lib/sdp_lib.h"
Packit 34410b
Packit 34410b
#include "src/shared/util.h"
Packit 34410b
Packit 34410b
#include "sdpd.h"
Packit 34410b
#include "log.h"
Packit 34410b
Packit 34410b
typedef struct {
Packit 34410b
	uint32_t timestamp;
Packit 34410b
	union {
Packit 34410b
		uint16_t maxBytesSent;
Packit 34410b
		uint16_t lastIndexSent;
Packit 34410b
	} cStateValue;
Packit 34410b
} sdp_cont_state_t;
Packit 34410b
Packit 34410b
#define SDP_CONT_STATE_SIZE (sizeof(uint8_t) + sizeof(sdp_cont_state_t))
Packit 34410b
Packit 34410b
#define MIN(x, y) ((x) < (y)) ? (x): (y)
Packit 34410b
Packit 34410b
typedef struct _sdp_cstate_list sdp_cstate_list_t;
Packit 34410b
Packit 34410b
struct _sdp_cstate_list {
Packit 34410b
	sdp_cstate_list_t *next;
Packit 34410b
	uint32_t timestamp;
Packit 34410b
	sdp_buf_t buf;
Packit 34410b
};
Packit 34410b
Packit 34410b
static sdp_cstate_list_t *cstates;
Packit 34410b
Packit 34410b
/* FIXME: should probably remove it when it's found */
Packit 34410b
static sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate)
Packit 34410b
{
Packit 34410b
	sdp_cstate_list_t *p;
Packit 34410b
Packit 34410b
	for (p = cstates; p; p = p->next) {
Packit 34410b
		/* Check timestamp */
Packit 34410b
		if (p->timestamp != cstate->timestamp)
Packit 34410b
			continue;
Packit 34410b
Packit 34410b
		/* Check if requesting more than available */
Packit 34410b
		if (cstate->cStateValue.maxBytesSent < p->buf.data_size)
Packit 34410b
			return &p->buf;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
static uint32_t sdp_cstate_alloc_buf(sdp_buf_t *buf)
Packit 34410b
{
Packit 34410b
	sdp_cstate_list_t *cstate = malloc(sizeof(sdp_cstate_list_t));
Packit 34410b
	uint8_t *data = malloc(buf->data_size);
Packit 34410b
Packit 34410b
	memcpy(data, buf->data, buf->data_size);
Packit 34410b
	memset((char *)cstate, 0, sizeof(sdp_cstate_list_t));
Packit 34410b
	cstate->buf.data = data;
Packit 34410b
	cstate->buf.data_size = buf->data_size;
Packit 34410b
	cstate->buf.buf_size = buf->data_size;
Packit 34410b
	cstate->timestamp = sdp_get_time();
Packit 34410b
	cstate->next = cstates;
Packit 34410b
	cstates = cstate;
Packit 34410b
	return cstate->timestamp;
Packit 34410b
}
Packit 34410b
Packit 34410b
/* Additional values for checking datatype (not in spec) */
Packit 34410b
#define SDP_TYPE_UUID	0xfe
Packit 34410b
#define SDP_TYPE_ATTRID	0xff
Packit 34410b
Packit 34410b
struct attrid {
Packit 34410b
	uint8_t dtd;
Packit 34410b
	union {
Packit 34410b
		uint16_t uint16;
Packit 34410b
		uint32_t uint32;
Packit 34410b
	};
Packit 34410b
};
Packit 34410b
Packit 34410b
/*
Packit 34410b
 * Generic data element sequence extractor. Builds
Packit 34410b
 * a list whose elements are those found in the
Packit 34410b
 * sequence. The data type of elements found in the
Packit 34410b
 * sequence is returned in the reference pDataType
Packit 34410b
 */
Packit 34410b
static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType)
Packit 34410b
{
Packit 34410b
	uint8_t seqType;
Packit 34410b
	int scanned, data_size = 0;
Packit 34410b
	short numberOfElements = 0;
Packit 34410b
	int seqlen = 0;
Packit 34410b
	sdp_list_t *pSeq = NULL;
Packit 34410b
	uint8_t dataType;
Packit 34410b
	int status = 0;
Packit 34410b
	const uint8_t *p;
Packit 34410b
	size_t bufsize;
Packit 34410b
Packit 34410b
	scanned = sdp_extract_seqtype(buf, len, &seqType, &data_size);
Packit 34410b
Packit 34410b
	SDPDBG("Seq type : %d", seqType);
Packit 34410b
	if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) {
Packit 34410b
		error("Unknown seq type");
Packit 34410b
		return -1;
Packit 34410b
	}
Packit 34410b
	p = buf + scanned;
Packit 34410b
	bufsize = len - scanned;
Packit 34410b
Packit 34410b
	SDPDBG("Data size : %d", data_size);
Packit 34410b
Packit 34410b
	for (;;) {
Packit 34410b
		char *pElem = NULL;
Packit 34410b
		int localSeqLength = 0;
Packit 34410b
		uuid_t *puuid;
Packit 34410b
Packit 34410b
		if (bufsize < sizeof(uint8_t)) {
Packit 34410b
			SDPDBG("->Unexpected end of buffer");
Packit 34410b
			goto failed;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		dataType = *p;
Packit 34410b
Packit 34410b
		SDPDBG("Data type: 0x%02x", dataType);
Packit 34410b
Packit 34410b
		if (expectedType == SDP_TYPE_UUID) {
Packit 34410b
			if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) {
Packit 34410b
				SDPDBG("->Unexpected Data type (expected UUID_ANY)");
Packit 34410b
				goto failed;
Packit 34410b
			}
Packit 34410b
		} else if (expectedType == SDP_TYPE_ATTRID &&
Packit 34410b
				(dataType != SDP_UINT16 && dataType != SDP_UINT32)) {
Packit 34410b
			SDPDBG("->Unexpected Data type (expected 0x%02x or 0x%02x)",
Packit 34410b
								SDP_UINT16, SDP_UINT32);
Packit 34410b
			goto failed;
Packit 34410b
		} else if (expectedType != SDP_TYPE_ATTRID && dataType != expectedType) {
Packit 34410b
			SDPDBG("->Unexpected Data type (expected 0x%02x)", expectedType);
Packit 34410b
			goto failed;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		switch (dataType) {
Packit 34410b
		case SDP_UINT16:
Packit 34410b
			p += sizeof(uint8_t);
Packit 34410b
			seqlen += sizeof(uint8_t);
Packit 34410b
			bufsize -= sizeof(uint8_t);
Packit 34410b
			if (bufsize < sizeof(uint16_t)) {
Packit 34410b
				SDPDBG("->Unexpected end of buffer");
Packit 34410b
				goto failed;
Packit 34410b
			}
Packit 34410b
Packit 34410b
			if (expectedType == SDP_TYPE_ATTRID) {
Packit 34410b
				struct attrid *aid;
Packit 34410b
				aid = malloc(sizeof(struct attrid));
Packit 34410b
				aid->dtd = dataType;
Packit 34410b
				aid->uint16 = get_be16(p);
Packit 34410b
				pElem = (char *) aid;
Packit 34410b
			} else {
Packit 34410b
				uint16_t tmp;
Packit 34410b
Packit 34410b
				memcpy(&tmp, p, sizeof(tmp));
Packit 34410b
Packit 34410b
				pElem = malloc(sizeof(uint16_t));
Packit 34410b
				put_be16(tmp, pElem);
Packit 34410b
			}
Packit 34410b
			p += sizeof(uint16_t);
Packit 34410b
			seqlen += sizeof(uint16_t);
Packit 34410b
			bufsize -= sizeof(uint16_t);
Packit 34410b
			break;
Packit 34410b
		case SDP_UINT32:
Packit 34410b
			p += sizeof(uint8_t);
Packit 34410b
			seqlen += sizeof(uint8_t);
Packit 34410b
			bufsize -= sizeof(uint8_t);
Packit 34410b
			if (bufsize < (int)sizeof(uint32_t)) {
Packit 34410b
				SDPDBG("->Unexpected end of buffer");
Packit 34410b
				goto failed;
Packit 34410b
			}
Packit 34410b
Packit 34410b
			if (expectedType == SDP_TYPE_ATTRID) {
Packit 34410b
				struct attrid *aid;
Packit 34410b
				aid = malloc(sizeof(struct attrid));
Packit 34410b
				aid->dtd = dataType;
Packit 34410b
				aid->uint32 = get_be32(p);
Packit 34410b
Packit 34410b
				pElem = (char *) aid;
Packit 34410b
			} else {
Packit 34410b
				uint32_t tmp;
Packit 34410b
Packit 34410b
				memcpy(&tmp, p, sizeof(tmp));
Packit 34410b
Packit 34410b
				pElem = malloc(sizeof(uint32_t));
Packit 34410b
				put_be32(tmp, pElem);
Packit 34410b
			}
Packit 34410b
			p += sizeof(uint32_t);
Packit 34410b
			seqlen += sizeof(uint32_t);
Packit 34410b
			bufsize -= sizeof(uint32_t);
Packit 34410b
			break;
Packit 34410b
		case SDP_UUID16:
Packit 34410b
		case SDP_UUID32:
Packit 34410b
		case SDP_UUID128:
Packit 34410b
			puuid = malloc(sizeof(uuid_t));
Packit 34410b
			status = sdp_uuid_extract(p, bufsize, puuid, &localSeqLength);
Packit 34410b
			if (status < 0) {
Packit 34410b
				free(puuid);
Packit 34410b
				goto failed;
Packit 34410b
			}
Packit 34410b
Packit 34410b
			pElem = (char *) puuid;
Packit 34410b
			seqlen += localSeqLength;
Packit 34410b
			p += localSeqLength;
Packit 34410b
			bufsize -= localSeqLength;
Packit 34410b
			break;
Packit 34410b
		default:
Packit 34410b
			return -1;
Packit 34410b
		}
Packit 34410b
		if (status == 0) {
Packit 34410b
			pSeq = sdp_list_append(pSeq, pElem);
Packit 34410b
			numberOfElements++;
Packit 34410b
			SDPDBG("No of elements : %d", numberOfElements);
Packit 34410b
Packit 34410b
			if (seqlen == data_size)
Packit 34410b
				break;
Packit 34410b
			else if (seqlen > data_size || seqlen > len)
Packit 34410b
				goto failed;
Packit 34410b
		} else
Packit 34410b
			free(pElem);
Packit 34410b
	}
Packit 34410b
	*svcReqSeq = pSeq;
Packit 34410b
	scanned += seqlen;
Packit 34410b
	*pDataType = dataType;
Packit 34410b
	return scanned;
Packit 34410b
Packit 34410b
failed:
Packit 34410b
	sdp_list_free(pSeq, free);
Packit 34410b
	return -1;
Packit 34410b
}
Packit 34410b
Packit 34410b
static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate)
Packit 34410b
{
Packit 34410b
	uint8_t *pdata = buf->data + buf->data_size;
Packit 34410b
	int length = 0;
Packit 34410b
Packit 34410b
	if (cstate) {
Packit 34410b
		SDPDBG("Non null sdp_cstate_t id : 0x%x", cstate->timestamp);
Packit 34410b
		*pdata = sizeof(sdp_cont_state_t);
Packit 34410b
		pdata += sizeof(uint8_t);
Packit 34410b
		length += sizeof(uint8_t);
Packit 34410b
		memcpy(pdata, cstate, sizeof(sdp_cont_state_t));
Packit 34410b
		length += sizeof(sdp_cont_state_t);
Packit 34410b
	} else {
Packit 34410b
		/* set "null" continuation state */
Packit 34410b
		*pdata = 0;
Packit 34410b
		length += sizeof(uint8_t);
Packit 34410b
	}
Packit 34410b
	buf->data_size += length;
Packit 34410b
	return length;
Packit 34410b
}
Packit 34410b
Packit 34410b
static int sdp_cstate_get(uint8_t *buffer, size_t len,
Packit 34410b
						sdp_cont_state_t **cstate)
Packit 34410b
{
Packit 34410b
	uint8_t cStateSize = *buffer;
Packit 34410b
Packit 34410b
	SDPDBG("Continuation State size : %d", cStateSize);
Packit 34410b
Packit 34410b
	if (cStateSize == 0) {
Packit 34410b
		*cstate = NULL;
Packit 34410b
		return 0;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	buffer++;
Packit 34410b
	len--;
Packit 34410b
Packit 34410b
	if (len < sizeof(sdp_cont_state_t))
Packit 34410b
		return -EINVAL;
Packit 34410b
Packit 34410b
	/*
Packit 34410b
	 * Check if continuation state exists, if yes attempt
Packit 34410b
	 * to get response remainder from cache, else send error
Packit 34410b
	 */
Packit 34410b
Packit 34410b
	*cstate = malloc(sizeof(sdp_cont_state_t));
Packit 34410b
	if (!(*cstate))
Packit 34410b
		return -ENOMEM;
Packit 34410b
Packit 34410b
	memcpy(*cstate, buffer, sizeof(sdp_cont_state_t));
Packit 34410b
Packit 34410b
	SDPDBG("Cstate TS : 0x%x", (*cstate)->timestamp);
Packit 34410b
	SDPDBG("Bytes sent : %d", (*cstate)->cStateValue.maxBytesSent);
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
/*
Packit 34410b
 * The matching process is defined as "each and every UUID
Packit 34410b
 * specified in the "search pattern" must be present in the
Packit 34410b
 * "target pattern". Here "search pattern" is the set of UUIDs
Packit 34410b
 * specified by the service discovery client and "target pattern"
Packit 34410b
 * is the set of UUIDs present in a service record.
Packit 34410b
 *
Packit 34410b
 * Return 1 if each and every UUID in the search
Packit 34410b
 * pattern exists in the target pattern, 0 if the
Packit 34410b
 * match succeeds and -1 on error.
Packit 34410b
 */
Packit 34410b
static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern)
Packit 34410b
{
Packit 34410b
	/*
Packit 34410b
	 * The target is a sorted list, so we need not look
Packit 34410b
	 * at all elements to confirm existence of an element
Packit 34410b
	 * from the search pattern
Packit 34410b
	 */
Packit 34410b
	int patlen = sdp_list_len(pattern);
Packit 34410b
Packit 34410b
	if (patlen < sdp_list_len(search))
Packit 34410b
		return -1;
Packit 34410b
	for (; search; search = search->next) {
Packit 34410b
		uuid_t *uuid128;
Packit 34410b
		void *data = search->data;
Packit 34410b
		sdp_list_t *list;
Packit 34410b
		if (data == NULL)
Packit 34410b
			return -1;
Packit 34410b
Packit 34410b
		/* create 128-bit form of the search UUID */
Packit 34410b
		uuid128 = sdp_uuid_to_uuid128((uuid_t *)data);
Packit 34410b
		list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp);
Packit 34410b
		bt_free(uuid128);
Packit 34410b
		if (!list)
Packit 34410b
			return 0;
Packit 34410b
	}
Packit 34410b
	return 1;
Packit 34410b
}
Packit 34410b
Packit 34410b
/*
Packit 34410b
 * Service search request PDU. This method extracts the search pattern
Packit 34410b
 * (a sequence of UUIDs) and calls the matching function
Packit 34410b
 * to find matching services
Packit 34410b
 */
Packit 34410b
static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
Packit 34410b
{
Packit 34410b
	int status = 0, i, plen, mlen, mtu, scanned;
Packit 34410b
	sdp_list_t *pattern = NULL;
Packit 34410b
	uint16_t expected, actual, rsp_count = 0;
Packit 34410b
	uint8_t dtd;
Packit 34410b
	sdp_cont_state_t *cstate = NULL;
Packit 34410b
	uint8_t *pCacheBuffer = NULL;
Packit 34410b
	int handleSize = 0;
Packit 34410b
	uint32_t cStateId = 0;
Packit 34410b
	uint8_t *pTotalRecordCount, *pCurrentRecordCount;
Packit 34410b
	uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
Packit 34410b
	size_t data_left = req->len - sizeof(sdp_pdu_hdr_t);
Packit 34410b
Packit 34410b
	scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID);
Packit 34410b
Packit 34410b
	if (scanned == -1) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
	pdata += scanned;
Packit 34410b
	data_left -= scanned;
Packit 34410b
Packit 34410b
	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
Packit 34410b
	mlen = scanned + sizeof(uint16_t) + 1;
Packit 34410b
	/* ensure we don't read past buffer */
Packit 34410b
	if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (data_left < sizeof(uint16_t)) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	expected = get_be16(pdata);
Packit 34410b
Packit 34410b
	SDPDBG("Expected count: %d", expected);
Packit 34410b
	SDPDBG("Bytes scanned : %d", scanned);
Packit 34410b
Packit 34410b
	pdata += sizeof(uint16_t);
Packit 34410b
	data_left -= sizeof(uint16_t);
Packit 34410b
Packit 34410b
	/*
Packit 34410b
	 * Check if continuation state exists, if yes attempt
Packit 34410b
	 * to get rsp remainder from cache, else send error
Packit 34410b
	 */
Packit 34410b
	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	mtu = req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - SDP_CONT_STATE_SIZE;
Packit 34410b
	actual = MIN(expected, mtu >> 2);
Packit 34410b
Packit 34410b
	/* make space in the rsp buffer for total and current record counts */
Packit 34410b
	pdata = buf->data;
Packit 34410b
Packit 34410b
	/* total service record count = 0 */
Packit 34410b
	pTotalRecordCount = pdata;
Packit 34410b
	put_be16(0, pdata);
Packit 34410b
	pdata += sizeof(uint16_t);
Packit 34410b
	buf->data_size += sizeof(uint16_t);
Packit 34410b
Packit 34410b
	/* current service record count = 0 */
Packit 34410b
	pCurrentRecordCount = pdata;
Packit 34410b
	put_be16(0, pdata);
Packit 34410b
	pdata += sizeof(uint16_t);
Packit 34410b
	buf->data_size += sizeof(uint16_t);
Packit 34410b
Packit 34410b
	if (cstate == NULL) {
Packit 34410b
		/* for every record in the DB, do a pattern search */
Packit 34410b
		sdp_list_t *list = sdp_get_record_list();
Packit 34410b
Packit 34410b
		handleSize = 0;
Packit 34410b
		for (; list && rsp_count < expected; list = list->next) {
Packit 34410b
			sdp_record_t *rec = list->data;
Packit 34410b
Packit 34410b
			SDPDBG("Checking svcRec : 0x%x", rec->handle);
Packit 34410b
Packit 34410b
			if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
Packit 34410b
					sdp_check_access(rec->handle, &req->device)) {
Packit 34410b
				rsp_count++;
Packit 34410b
				put_be32(rec->handle, pdata);
Packit 34410b
				pdata += sizeof(uint32_t);
Packit 34410b
				handleSize += sizeof(uint32_t);
Packit 34410b
			}
Packit 34410b
		}
Packit 34410b
Packit 34410b
		SDPDBG("Match count: %d", rsp_count);
Packit 34410b
Packit 34410b
		buf->data_size += handleSize;
Packit 34410b
		put_be16(rsp_count, pTotalRecordCount);
Packit 34410b
		put_be16(rsp_count, pCurrentRecordCount);
Packit 34410b
Packit 34410b
		if (rsp_count > actual) {
Packit 34410b
			/* cache the rsp and generate a continuation state */
Packit 34410b
			cStateId = sdp_cstate_alloc_buf(buf);
Packit 34410b
			/*
Packit 34410b
			 * subtract handleSize since we now send only
Packit 34410b
			 * a subset of handles
Packit 34410b
			 */
Packit 34410b
			buf->data_size -= handleSize;
Packit 34410b
		} else {
Packit 34410b
			/* NULL continuation state */
Packit 34410b
			sdp_set_cstate_pdu(buf, NULL);
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/* under both the conditions below, the rsp buffer is not built yet */
Packit 34410b
	if (cstate || cStateId > 0) {
Packit 34410b
		short lastIndex = 0;
Packit 34410b
Packit 34410b
		if (cstate) {
Packit 34410b
			/*
Packit 34410b
			 * Get the previous sdp_cont_state_t and obtain
Packit 34410b
			 * the cached rsp
Packit 34410b
			 */
Packit 34410b
			sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
Packit 34410b
			if (pCache) {
Packit 34410b
				pCacheBuffer = pCache->data;
Packit 34410b
				/* get the rsp_count from the cached buffer */
Packit 34410b
				rsp_count = get_be16(pCacheBuffer);
Packit 34410b
Packit 34410b
				/* get index of the last sdp_record_t sent */
Packit 34410b
				lastIndex = cstate->cStateValue.lastIndexSent;
Packit 34410b
			} else {
Packit 34410b
				status = SDP_INVALID_CSTATE;
Packit 34410b
				goto done;
Packit 34410b
			}
Packit 34410b
		} else {
Packit 34410b
			pCacheBuffer = buf->data;
Packit 34410b
			lastIndex = 0;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		/*
Packit 34410b
		 * Set the local buffer pointer to after the
Packit 34410b
		 * current record count and increment the cached
Packit 34410b
		 * buffer pointer to beyond the counters
Packit 34410b
		 */
Packit 34410b
		pdata = pCurrentRecordCount + sizeof(uint16_t);
Packit 34410b
Packit 34410b
		/* increment beyond the totalCount and the currentCount */
Packit 34410b
		pCacheBuffer += 2 * sizeof(uint16_t);
Packit 34410b
Packit 34410b
		if (cstate) {
Packit 34410b
			handleSize = 0;
Packit 34410b
			for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) {
Packit 34410b
				memcpy(pdata, pCacheBuffer + i * sizeof(uint32_t), sizeof(uint32_t));
Packit 34410b
				pdata += sizeof(uint32_t);
Packit 34410b
				handleSize += sizeof(uint32_t);
Packit 34410b
			}
Packit 34410b
		} else {
Packit 34410b
			handleSize = actual << 2;
Packit 34410b
			i = actual;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		buf->data_size += handleSize;
Packit 34410b
		put_be16(rsp_count, pTotalRecordCount);
Packit 34410b
		put_be16(i - lastIndex, pCurrentRecordCount);
Packit 34410b
Packit 34410b
		if (i == rsp_count) {
Packit 34410b
			/* set "null" continuationState */
Packit 34410b
			sdp_set_cstate_pdu(buf, NULL);
Packit 34410b
		} else {
Packit 34410b
			/*
Packit 34410b
			 * there's more: set lastIndexSent to
Packit 34410b
			 * the new value and move on
Packit 34410b
			 */
Packit 34410b
			sdp_cont_state_t newState;
Packit 34410b
Packit 34410b
			SDPDBG("Setting non-NULL sdp_cstate_t");
Packit 34410b
Packit 34410b
			if (cstate)
Packit 34410b
				memcpy(&newState, cstate, sizeof(sdp_cont_state_t));
Packit 34410b
			else {
Packit 34410b
				memset(&newState, 0, sizeof(sdp_cont_state_t));
Packit 34410b
				newState.timestamp = cStateId;
Packit 34410b
			}
Packit 34410b
			newState.cStateValue.lastIndexSent = i;
Packit 34410b
			sdp_set_cstate_pdu(buf, &newState);
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
done:
Packit 34410b
	free(cstate);
Packit 34410b
	if (pattern)
Packit 34410b
		sdp_list_free(pattern, free);
Packit 34410b
Packit 34410b
	return status;
Packit 34410b
}
Packit 34410b
Packit 34410b
/*
Packit 34410b
 * Extract attribute identifiers from the request PDU.
Packit 34410b
 * Clients could request a subset of attributes (by id)
Packit 34410b
 * from a service record, instead of the whole set. The
Packit 34410b
 * requested identifiers are present in the PDU form of
Packit 34410b
 * the request
Packit 34410b
 */
Packit 34410b
static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, sdp_buf_t *buf)
Packit 34410b
{
Packit 34410b
	sdp_buf_t pdu;
Packit 34410b
Packit 34410b
	if (!rec)
Packit 34410b
		return SDP_INVALID_RECORD_HANDLE;
Packit 34410b
Packit 34410b
	if (seq == NULL) {
Packit 34410b
		SDPDBG("Attribute sequence is NULL");
Packit 34410b
		return 0;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	SDPDBG("Entries in attr seq : %d", sdp_list_len(seq));
Packit 34410b
Packit 34410b
	sdp_gen_record_pdu(rec, &pdu);
Packit 34410b
Packit 34410b
	for (; seq; seq = seq->next) {
Packit 34410b
		struct attrid *aid = seq->data;
Packit 34410b
Packit 34410b
		SDPDBG("AttrDataType : %d", aid->dtd);
Packit 34410b
Packit 34410b
		if (aid->dtd == SDP_UINT16) {
Packit 34410b
			uint16_t attr = aid->uint16;
Packit 34410b
			sdp_data_t *a = sdp_data_get(rec, attr);
Packit 34410b
			if (a)
Packit 34410b
				sdp_append_to_pdu(buf, a);
Packit 34410b
		} else if (aid->dtd == SDP_UINT32) {
Packit 34410b
			uint32_t range = aid->uint32;
Packit 34410b
			uint16_t attr;
Packit 34410b
			uint16_t low = (0xffff0000 & range) >> 16;
Packit 34410b
			uint16_t high = 0x0000ffff & range;
Packit 34410b
			sdp_data_t *data;
Packit 34410b
Packit 34410b
			SDPDBG("attr range : 0x%x", range);
Packit 34410b
			SDPDBG("Low id : 0x%x", low);
Packit 34410b
			SDPDBG("High id : 0x%x", high);
Packit 34410b
Packit 34410b
			if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) {
Packit 34410b
				/* copy it */
Packit 34410b
				memcpy(buf->data, pdu.data, pdu.data_size);
Packit 34410b
				buf->data_size = pdu.data_size;
Packit 34410b
				break;
Packit 34410b
			}
Packit 34410b
			/* (else) sub-range of attributes */
Packit 34410b
			for (attr = low; attr < high; attr++) {
Packit 34410b
				data = sdp_data_get(rec, attr);
Packit 34410b
				if (data)
Packit 34410b
					sdp_append_to_pdu(buf, data);
Packit 34410b
			}
Packit 34410b
			data = sdp_data_get(rec, high);
Packit 34410b
			if (data)
Packit 34410b
				sdp_append_to_pdu(buf, data);
Packit 34410b
		} else {
Packit 34410b
			error("Unexpected data type : 0x%x", aid->dtd);
Packit 34410b
			error("Expect uint16_t or uint32_t");
Packit 34410b
			free(pdu.data);
Packit 34410b
			return SDP_INVALID_SYNTAX;
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
	free(pdu.data);
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
/* Build cstate response */
Packit 34410b
static int sdp_cstate_rsp(sdp_cont_state_t *cstate, sdp_buf_t *buf,
Packit 34410b
							uint16_t max)
Packit 34410b
{
Packit 34410b
	/* continuation State exists -> get from cache */
Packit 34410b
	sdp_buf_t *cache = sdp_get_cached_rsp(cstate);
Packit 34410b
	uint16_t sent;
Packit 34410b
Packit 34410b
	if (!cache)
Packit 34410b
		return 0;
Packit 34410b
Packit 34410b
	sent = MIN(max, cache->data_size - cstate->cStateValue.maxBytesSent);
Packit 34410b
	memcpy(buf->data, cache->data + cstate->cStateValue.maxBytesSent, sent);
Packit 34410b
	buf->data_size += sent;
Packit 34410b
	cstate->cStateValue.maxBytesSent += sent;
Packit 34410b
Packit 34410b
	SDPDBG("Response size : %d sending now : %d bytes sent so far : %d",
Packit 34410b
		cache->data_size, sent, cstate->cStateValue.maxBytesSent);
Packit 34410b
Packit 34410b
	if (cstate->cStateValue.maxBytesSent == cache->data_size)
Packit 34410b
		return sdp_set_cstate_pdu(buf, NULL);
Packit 34410b
Packit 34410b
	return sdp_set_cstate_pdu(buf, cstate);
Packit 34410b
}
Packit 34410b
Packit 34410b
/*
Packit 34410b
 * A request for the attributes of a service record.
Packit 34410b
 * First check if the service record (specified by
Packit 34410b
 * service record handle) exists, then call the attribute
Packit 34410b
 * streaming function
Packit 34410b
 */
Packit 34410b
static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
Packit 34410b
{
Packit 34410b
	sdp_cont_state_t *cstate = NULL;
Packit 34410b
	short cstate_size = 0;
Packit 34410b
	sdp_list_t *seq = NULL;
Packit 34410b
	uint8_t dtd = 0;
Packit 34410b
	int scanned = 0;
Packit 34410b
	unsigned int max_rsp_size;
Packit 34410b
	int status = 0, plen, mlen;
Packit 34410b
	uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
Packit 34410b
	size_t data_left = req->len - sizeof(sdp_pdu_hdr_t);
Packit 34410b
	uint32_t handle;
Packit 34410b
Packit 34410b
	if (data_left < sizeof(uint32_t)) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	handle = get_be32(pdata);
Packit 34410b
Packit 34410b
	pdata += sizeof(uint32_t);
Packit 34410b
	data_left -= sizeof(uint32_t);
Packit 34410b
Packit 34410b
	if (data_left < sizeof(uint16_t)) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	max_rsp_size = get_be16(pdata);
Packit 34410b
Packit 34410b
	pdata += sizeof(uint16_t);
Packit 34410b
	data_left -= sizeof(uint16_t);
Packit 34410b
Packit 34410b
	if (data_left < sizeof(sdp_pdu_hdr_t)) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/* extract the attribute list */
Packit 34410b
	scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID);
Packit 34410b
	if (scanned == -1) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
	pdata += scanned;
Packit 34410b
	data_left -= scanned;
Packit 34410b
Packit 34410b
	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
Packit 34410b
	mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1;
Packit 34410b
	/* ensure we don't read past buffer */
Packit 34410b
	if (plen < mlen || plen != mlen + *(uint8_t *)pdata) {
Packit 34410b
		status = SDP_INVALID_PDU_SIZE;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/*
Packit 34410b
	 * if continuation state exists, attempt
Packit 34410b
	 * to get rsp remainder from cache, else send error
Packit 34410b
	 */
Packit 34410b
	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	SDPDBG("SvcRecHandle : 0x%x", handle);
Packit 34410b
	SDPDBG("max_rsp_size : %d", max_rsp_size);
Packit 34410b
Packit 34410b
	/*
Packit 34410b
	 * Check that max_rsp_size is within valid range
Packit 34410b
	 * a minimum size of 0x0007 has to be used for data field
Packit 34410b
	 */
Packit 34410b
	if (max_rsp_size < 0x0007) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/*
Packit 34410b
	 * Calculate Attribute size according to MTU
Packit 34410b
	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
Packit 34410b
	 */
Packit 34410b
	max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) -
Packit 34410b
			sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
Packit 34410b
Packit 34410b
	/* pull header for AttributeList byte count */
Packit 34410b
	buf->data += sizeof(uint16_t);
Packit 34410b
	buf->buf_size -= sizeof(uint16_t);
Packit 34410b
Packit 34410b
	if (cstate) {
Packit 34410b
		cstate_size = sdp_cstate_rsp(cstate, buf, max_rsp_size);
Packit 34410b
		if (!cstate_size) {
Packit 34410b
			status = SDP_INVALID_CSTATE;
Packit 34410b
			error("NULL cache buffer and non-NULL continuation state");
Packit 34410b
		}
Packit 34410b
	} else {
Packit 34410b
		sdp_record_t *rec = sdp_record_find(handle);
Packit 34410b
		status = extract_attrs(rec, seq, buf);
Packit 34410b
		if (buf->data_size > max_rsp_size) {
Packit 34410b
			sdp_cont_state_t newState;
Packit 34410b
Packit 34410b
			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
Packit 34410b
			newState.timestamp = sdp_cstate_alloc_buf(buf);
Packit 34410b
			/*
Packit 34410b
			 * Reset the buffer size to the maximum expected and
Packit 34410b
			 * set the sdp_cont_state_t
Packit 34410b
			 */
Packit 34410b
			SDPDBG("Creating continuation state of size : %d", buf->data_size);
Packit 34410b
			buf->data_size = max_rsp_size;
Packit 34410b
			newState.cStateValue.maxBytesSent = max_rsp_size;
Packit 34410b
			cstate_size = sdp_set_cstate_pdu(buf, &newState);
Packit 34410b
		} else {
Packit 34410b
			if (buf->data_size == 0)
Packit 34410b
				sdp_append_to_buf(buf, NULL, 0);
Packit 34410b
			cstate_size = sdp_set_cstate_pdu(buf, NULL);
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/* push header */
Packit 34410b
	buf->data -= sizeof(uint16_t);
Packit 34410b
	buf->buf_size += sizeof(uint16_t);
Packit 34410b
Packit 34410b
done:
Packit 34410b
	free(cstate);
Packit 34410b
	if (seq)
Packit 34410b
		sdp_list_free(seq, free);
Packit 34410b
	if (status)
Packit 34410b
		return status;
Packit 34410b
Packit 34410b
	/* set attribute list byte count */
Packit 34410b
	put_be16(buf->data_size - cstate_size, buf->data);
Packit 34410b
	buf->data_size += sizeof(uint16_t);
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
/*
Packit 34410b
 * combined service search and attribute extraction
Packit 34410b
 */
Packit 34410b
static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
Packit 34410b
{
Packit 34410b
	int status = 0, plen, totscanned;
Packit 34410b
	uint8_t *pdata;
Packit 34410b
	unsigned int max;
Packit 34410b
	int scanned, rsp_count = 0;
Packit 34410b
	sdp_list_t *pattern = NULL, *seq = NULL, *svcList;
Packit 34410b
	sdp_cont_state_t *cstate = NULL;
Packit 34410b
	short cstate_size = 0;
Packit 34410b
	uint8_t dtd = 0;
Packit 34410b
	sdp_buf_t tmpbuf;
Packit 34410b
	size_t data_left;
Packit 34410b
Packit 34410b
	tmpbuf.data = NULL;
Packit 34410b
	pdata = req->buf + sizeof(sdp_pdu_hdr_t);
Packit 34410b
	data_left = req->len - sizeof(sdp_pdu_hdr_t);
Packit 34410b
	scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID);
Packit 34410b
	if (scanned == -1) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
	totscanned = scanned;
Packit 34410b
Packit 34410b
	SDPDBG("Bytes scanned: %d", scanned);
Packit 34410b
Packit 34410b
	pdata += scanned;
Packit 34410b
	data_left -= scanned;
Packit 34410b
Packit 34410b
	if (data_left < sizeof(uint16_t)) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	max = get_be16(pdata);
Packit 34410b
Packit 34410b
	pdata += sizeof(uint16_t);
Packit 34410b
	data_left -= sizeof(uint16_t);
Packit 34410b
Packit 34410b
	SDPDBG("Max Attr expected: %d", max);
Packit 34410b
Packit 34410b
	if (data_left < sizeof(sdp_pdu_hdr_t)) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/* extract the attribute list */
Packit 34410b
	scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID);
Packit 34410b
	if (scanned == -1) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	pdata += scanned;
Packit 34410b
	data_left -= scanned;
Packit 34410b
Packit 34410b
	totscanned += scanned + sizeof(uint16_t) + 1;
Packit 34410b
Packit 34410b
	plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
Packit 34410b
	if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) {
Packit 34410b
		status = SDP_INVALID_PDU_SIZE;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/*
Packit 34410b
	 * if continuation state exists attempt
Packit 34410b
	 * to get rsp remainder from cache, else send error
Packit 34410b
	 */
Packit 34410b
	if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	svcList = sdp_get_record_list();
Packit 34410b
Packit 34410b
	tmpbuf.data = malloc(USHRT_MAX);
Packit 34410b
	tmpbuf.data_size = 0;
Packit 34410b
	tmpbuf.buf_size = USHRT_MAX;
Packit 34410b
	memset(tmpbuf.data, 0, USHRT_MAX);
Packit 34410b
Packit 34410b
	/*
Packit 34410b
	 * Calculate Attribute size according to MTU
Packit 34410b
	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
Packit 34410b
	 */
Packit 34410b
	max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
Packit 34410b
Packit 34410b
	/* pull header for AttributeList byte count */
Packit 34410b
	buf->data += sizeof(uint16_t);
Packit 34410b
	buf->buf_size -= sizeof(uint16_t);
Packit 34410b
Packit 34410b
	if (cstate == NULL) {
Packit 34410b
		/* no continuation state -> create new response */
Packit 34410b
		sdp_list_t *p;
Packit 34410b
		for (p = svcList; p; p = p->next) {
Packit 34410b
			sdp_record_t *rec = p->data;
Packit 34410b
			if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
Packit 34410b
					sdp_check_access(rec->handle, &req->device)) {
Packit 34410b
				rsp_count++;
Packit 34410b
				status = extract_attrs(rec, seq, &tmpbuf);
Packit 34410b
Packit 34410b
				SDPDBG("Response count : %d", rsp_count);
Packit 34410b
				SDPDBG("Local PDU size : %d", tmpbuf.data_size);
Packit 34410b
				if (status) {
Packit 34410b
					SDPDBG("Extract attr from record returns err");
Packit 34410b
					break;
Packit 34410b
				}
Packit 34410b
				if (buf->data_size + tmpbuf.data_size < buf->buf_size) {
Packit 34410b
					/* to be sure no relocations */
Packit 34410b
					sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
Packit 34410b
					tmpbuf.data_size = 0;
Packit 34410b
					memset(tmpbuf.data, 0, USHRT_MAX);
Packit 34410b
				} else {
Packit 34410b
					error("Relocation needed");
Packit 34410b
					break;
Packit 34410b
				}
Packit 34410b
				SDPDBG("Net PDU size : %d", buf->data_size);
Packit 34410b
			}
Packit 34410b
		}
Packit 34410b
		if (buf->data_size > max) {
Packit 34410b
			sdp_cont_state_t newState;
Packit 34410b
Packit 34410b
			memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
Packit 34410b
			newState.timestamp = sdp_cstate_alloc_buf(buf);
Packit 34410b
			/*
Packit 34410b
			 * Reset the buffer size to the maximum expected and
Packit 34410b
			 * set the sdp_cont_state_t
Packit 34410b
			 */
Packit 34410b
			buf->data_size = max;
Packit 34410b
			newState.cStateValue.maxBytesSent = max;
Packit 34410b
			cstate_size = sdp_set_cstate_pdu(buf, &newState);
Packit 34410b
		} else
Packit 34410b
			cstate_size = sdp_set_cstate_pdu(buf, NULL);
Packit 34410b
	} else {
Packit 34410b
		cstate_size = sdp_cstate_rsp(cstate, buf, max);
Packit 34410b
		if (!cstate_size) {
Packit 34410b
			status = SDP_INVALID_CSTATE;
Packit 34410b
			SDPDBG("Non-null continuation state, but null cache buffer");
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (!rsp_count && !cstate) {
Packit 34410b
		/* found nothing */
Packit 34410b
		buf->data_size = 0;
Packit 34410b
		sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
Packit 34410b
		sdp_set_cstate_pdu(buf, NULL);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	/* push header */
Packit 34410b
	buf->data -= sizeof(uint16_t);
Packit 34410b
	buf->buf_size += sizeof(uint16_t);
Packit 34410b
Packit 34410b
	if (!status) {
Packit 34410b
		/* set attribute list byte count */
Packit 34410b
		put_be16(buf->data_size - cstate_size, buf->data);
Packit 34410b
		buf->data_size += sizeof(uint16_t);
Packit 34410b
	}
Packit 34410b
Packit 34410b
done:
Packit 34410b
	free(cstate);
Packit 34410b
	free(tmpbuf.data);
Packit 34410b
	if (pattern)
Packit 34410b
		sdp_list_free(pattern, free);
Packit 34410b
	if (seq)
Packit 34410b
		sdp_list_free(seq, free);
Packit 34410b
	return status;
Packit 34410b
}
Packit 34410b
Packit 34410b
/*
Packit 34410b
 * Top level request processor. Calls the appropriate processing
Packit 34410b
 * function based on request type. Handles service registration
Packit 34410b
 * client requests also.
Packit 34410b
 */
Packit 34410b
static void process_request(sdp_req_t *req)
Packit 34410b
{
Packit 34410b
	sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf;
Packit 34410b
	sdp_pdu_hdr_t *rsphdr;
Packit 34410b
	sdp_buf_t rsp;
Packit 34410b
	uint8_t *buf = malloc(USHRT_MAX);
Packit 34410b
	int status = SDP_INVALID_SYNTAX;
Packit 34410b
Packit 34410b
	memset(buf, 0, USHRT_MAX);
Packit 34410b
	rsp.data = buf + sizeof(sdp_pdu_hdr_t);
Packit 34410b
	rsp.data_size = 0;
Packit 34410b
	rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t);
Packit 34410b
	rsphdr = (sdp_pdu_hdr_t *)buf;
Packit 34410b
Packit 34410b
	if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) {
Packit 34410b
		status = SDP_INVALID_PDU_SIZE;
Packit 34410b
		goto send_rsp;
Packit 34410b
	}
Packit 34410b
	switch (reqhdr->pdu_id) {
Packit 34410b
	case SDP_SVC_SEARCH_REQ:
Packit 34410b
		SDPDBG("Got a svc srch req");
Packit 34410b
		status = service_search_req(req, &rsp;;
Packit 34410b
		rsphdr->pdu_id = SDP_SVC_SEARCH_RSP;
Packit 34410b
		break;
Packit 34410b
	case SDP_SVC_ATTR_REQ:
Packit 34410b
		SDPDBG("Got a svc attr req");
Packit 34410b
		status = service_attr_req(req, &rsp;;
Packit 34410b
		rsphdr->pdu_id = SDP_SVC_ATTR_RSP;
Packit 34410b
		break;
Packit 34410b
	case SDP_SVC_SEARCH_ATTR_REQ:
Packit 34410b
		SDPDBG("Got a svc srch attr req");
Packit 34410b
		status = service_search_attr_req(req, &rsp;;
Packit 34410b
		rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
Packit 34410b
		break;
Packit 34410b
	/* Following requests are allowed only for local connections */
Packit 34410b
	case SDP_SVC_REGISTER_REQ:
Packit 34410b
		SDPDBG("Service register request");
Packit 34410b
		if (req->local) {
Packit 34410b
			status = service_register_req(req, &rsp;;
Packit 34410b
			rsphdr->pdu_id = SDP_SVC_REGISTER_RSP;
Packit 34410b
		}
Packit 34410b
		break;
Packit 34410b
	case SDP_SVC_UPDATE_REQ:
Packit 34410b
		SDPDBG("Service update request");
Packit 34410b
		if (req->local) {
Packit 34410b
			status = service_update_req(req, &rsp;;
Packit 34410b
			rsphdr->pdu_id = SDP_SVC_UPDATE_RSP;
Packit 34410b
		}
Packit 34410b
		break;
Packit 34410b
	case SDP_SVC_REMOVE_REQ:
Packit 34410b
		SDPDBG("Service removal request");
Packit 34410b
		if (req->local) {
Packit 34410b
			status = service_remove_req(req, &rsp;;
Packit 34410b
			rsphdr->pdu_id = SDP_SVC_REMOVE_RSP;
Packit 34410b
		}
Packit 34410b
		break;
Packit 34410b
	default:
Packit 34410b
		error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);
Packit 34410b
		status = SDP_INVALID_SYNTAX;
Packit 34410b
		break;
Packit 34410b
	}
Packit 34410b
Packit 34410b
send_rsp:
Packit 34410b
	if (status) {
Packit 34410b
		rsphdr->pdu_id = SDP_ERROR_RSP;
Packit 34410b
		put_be16(status, rsp.data);
Packit 34410b
		rsp.data_size = sizeof(uint16_t);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	SDPDBG("Sending rsp. status %d", status);
Packit 34410b
Packit 34410b
	rsphdr->tid  = reqhdr->tid;
Packit 34410b
	rsphdr->plen = htons(rsp.data_size);
Packit 34410b
Packit 34410b
	/* point back to the real buffer start and set the real rsp length */
Packit 34410b
	rsp.data_size += sizeof(sdp_pdu_hdr_t);
Packit 34410b
	rsp.data = buf;
Packit 34410b
Packit 34410b
	/* stream the rsp PDU */
Packit 34410b
	if (send(req->sock, rsp.data, rsp.data_size, 0) < 0)
Packit 34410b
		error("send: %s (%d)", strerror(errno), errno);
Packit 34410b
Packit 34410b
	SDPDBG("Bytes Sent : %d", rsp.data_size);
Packit 34410b
Packit 34410b
	free(rsp.data);
Packit 34410b
	free(req->buf);
Packit 34410b
}
Packit 34410b
Packit 34410b
void handle_internal_request(int sk, int mtu, void *data, int len)
Packit 34410b
{
Packit 34410b
	sdp_req_t req;
Packit 34410b
Packit 34410b
	bacpy(&req.device, BDADDR_ANY);
Packit 34410b
	bacpy(&req.bdaddr, BDADDR_LOCAL);
Packit 34410b
	req.local = 0;
Packit 34410b
	req.sock = sk;
Packit 34410b
	req.mtu = mtu;
Packit 34410b
	req.flags = 0;
Packit 34410b
	req.buf = data;
Packit 34410b
	req.len = len;
Packit 34410b
Packit 34410b
	process_request(&req;;
Packit 34410b
}
Packit 34410b
Packit 34410b
void handle_request(int sk, uint8_t *data, int len)
Packit 34410b
{
Packit 34410b
	struct sockaddr_l2 sa;
Packit 34410b
	socklen_t size;
Packit 34410b
	sdp_req_t req;
Packit 34410b
Packit 34410b
	size = sizeof(sa);
Packit 34410b
	if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) {
Packit 34410b
		error("getpeername: %s", strerror(errno));
Packit 34410b
		return;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (sa.l2_family == AF_BLUETOOTH) {
Packit 34410b
		struct l2cap_options lo;
Packit 34410b
Packit 34410b
		memset(&lo, 0, sizeof(lo));
Packit 34410b
		size = sizeof(lo);
Packit 34410b
Packit 34410b
		if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size) < 0) {
Packit 34410b
			error("getsockopt: %s", strerror(errno));
Packit 34410b
			return;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		bacpy(&req.bdaddr, &sa.l2_bdaddr);
Packit 34410b
		req.mtu = lo.omtu;
Packit 34410b
		req.local = 0;
Packit 34410b
		memset(&sa, 0, sizeof(sa));
Packit 34410b
		size = sizeof(sa);
Packit 34410b
Packit 34410b
		if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) {
Packit 34410b
			error("getsockname: %s", strerror(errno));
Packit 34410b
			return;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		bacpy(&req.device, &sa.l2_bdaddr);
Packit 34410b
	} else {
Packit 34410b
		bacpy(&req.device, BDADDR_ANY);
Packit 34410b
		bacpy(&req.bdaddr, BDADDR_LOCAL);
Packit 34410b
		req.mtu = 2048;
Packit 34410b
		req.local = 1;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	req.sock = sk;
Packit 34410b
	req.buf  = data;
Packit 34410b
	req.len  = len;
Packit 34410b
Packit 34410b
	process_request(&req;;
Packit 34410b
}