diff options
Diffstat (limited to 'sdpd/service.c')
| -rw-r--r-- | sdpd/service.c | 241 | 
1 files changed, 241 insertions, 0 deletions
diff --git a/sdpd/service.c b/sdpd/service.c new file mode 100644 index 00000000..171a086d --- /dev/null +++ b/sdpd/service.c @@ -0,0 +1,241 @@ +/* +   Service Discovery Protocol (SDP) +   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>, Stephen Crane <steve.crane@rococosoft.com> +    +   Based on original SDP implementation by Nokia Corporation. +   Copyright (C) 2001,2002 Nokia Corporation. +   Original author Guruprasad Krishnamurthy <guruprasad.krishnamurthy@nokia.com> +    +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License version 2 as +   published by the Free Software Foundation; +    +   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, +   OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +   RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +   NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE +   USE OR PERFORMANCE OF THIS SOFTWARE. +    +   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, +   TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. +*/ + +/* +   Service registration requests. + +   Fixes: +	Guruprasad Krishnamurthy <guruprasad.krishnamurthy@nokia.com> +*/ + +/* + * $Id$ + */ + +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> +#include <bluetooth/sdp_internal.h> + +#include "sdpd.h" + +extern void update_db_timestamp(void); + +// FIXME: refactor for server-side +static sdp_record_t *extract_pdu_server(char *p, uint32_t handleExpected, int *scanned) +{ +	int extractStatus = -1, localExtractedLength = 0; +	uint8_t dtd; +	int seqlen = 0; +	sdp_record_t *rec = NULL; +	uint16_t attrId, lookAheadAttrId; +	sdp_data_t *pAttr = NULL; +	uint32_t handle = 0xffffffff; + +	*scanned = sdp_extract_seqtype(p, &dtd, &seqlen); +	p += *scanned; +	lookAheadAttrId = ntohs(sdp_get_unaligned((uint16_t *)(p + sizeof(uint8_t)))); + +	SDPDBG("Look ahead attr id : %d\n", lookAheadAttrId); + +	if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) { +		handle = ntohl(sdp_get_unaligned((uint32_t *)(p + +				sizeof(uint8_t) + sizeof(uint16_t) + +				sizeof(uint8_t)))); +		SDPDBG("SvcRecHandle : 0x%x\n", handle); +		rec = sdp_record_find(handle); +	} else if (handleExpected != 0xffffffff) +		rec = sdp_record_find(handleExpected); + +	if (rec == NULL) { +		rec = sdp_record_alloc(); +		rec->attrlist = NULL; +		if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) { +			rec->handle = handle; +			sdp_record_add(rec); +		} else if (handleExpected != 0xffffffff) { +			rec->handle = handleExpected; +			sdp_record_add(rec); +		} +	} + +	while (localExtractedLength < seqlen) { +		int attrSize = sizeof(uint8_t); +		int attrValueLength = 0; + +		SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d", seqlen, localExtractedLength); +		dtd = *(uint8_t *)p; + +		attrId = ntohs(sdp_get_unaligned((uint16_t *)(p + attrSize))); +		attrSize += sizeof(uint16_t); +		 +		SDPDBG("DTD of attrId : %d Attr id : 0x%x \n", dtd, attrId); + +		pAttr = sdp_extract_attr(p + attrSize, &attrValueLength, rec); + +		SDPDBG("Attr id : 0x%x attrValueLength : %d\n", attrId, attrValueLength); + +		attrSize += attrValueLength; +		if (pAttr == NULL) { +			SDPDBG("Terminating extraction of attributes"); +			break; +		} +		localExtractedLength += attrSize; +		p += attrSize; +		sdp_attr_replace(rec, attrId, pAttr); +		extractStatus = 0; +		SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d", +					seqlen, localExtractedLength); +	} + +	if (extractStatus == 0) { +		SDPDBG("Successful extracting of Svc Rec attributes\n"); +#ifdef SDP_DEBUG +		sdp_print_service_attr(rec->attrlist); +#endif +		*scanned += seqlen; +	} +	return rec; +} + +/* + * Add the newly created service record to the service repository + */ +int service_register_req(sdp_req_t *req, sdp_buf_t *rsp) +{ +	int scanned = 0; +	sdp_data_t *handle; +	char *p = req->buf + sizeof(sdp_pdu_hdr_t); +	sdp_record_t *rec; + +	req->flags = *p++; + +	// save image of PDU: we need it when clients request this attribute +	rec = extract_pdu_server(p, 0xffffffff, &scanned); +	if (rec == NULL) { +		sdp_put_unaligned(htons(SDP_INVALID_SYNTAX), (uint16_t *)rsp->data); +		rsp->data_size = sizeof(uint16_t); +		return -1; +	} + +	rec->handle = (uint32_t)rec; +	sdp_record_add(rec); +	if (!(req->flags & SDP_RECORD_PERSIST)) +		sdp_svcdb_set_collectable(rec, req->sock); +	handle = sdp_data_alloc(SDP_UINT32, &rec->handle); +	sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, handle); +	/* +	 * if the browse group descriptor is NULL, +	 * ensure that the record belongs to the ROOT group +	 */ +	if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) { +		 uuid_t uuid; +		 sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP); +		 sdp_pattern_add_uuid(rec, &uuid); +	} +	update_db_timestamp(); + +	/* Build a rsp buffer */ +	sdp_put_unaligned(htonl(rec->handle), (uint32_t *)rsp->data); +	rsp->data_size = sizeof(uint32_t); +	return 0; +} + +/* + * Update a service record + */ +int service_update_req(sdp_req_t *req, sdp_buf_t *rsp) +{ +	sdp_record_t *orec; +	int status = 0, scanned = 0; +	char *p = req->buf + sizeof(sdp_pdu_hdr_t); +	uint32_t handle = ntohl(sdp_get_unaligned((uint32_t *)p)); + +	SDPDBG(""); + +	SDPDBG("Svc Rec Handle: 0x%x\n", handle); +	 +	p += sizeof(uint32_t); + +	orec = sdp_record_find(handle); +	 +	SDPDBG("SvcRecOld: 0x%x\n", (uint32_t)orec); + +	if (orec) { +		sdp_record_t *nrec = extract_pdu_server(p, handle, &scanned); +		if (nrec && handle == nrec->handle) +			update_db_timestamp(); +		else { +			SDPDBG("SvcRecHandle : 0x%x\n", handle); +			SDPDBG("SvcRecHandleNew : 0x%x\n", nrec->handle); +			SDPDBG("SvcRecNew : 0x%x\n", (uint32_t) nrec); +			SDPDBG("SvcRecOld : 0x%x\n", (uint32_t) orec); +			SDPDBG("Failure to update, restore old value\n"); + +			if (nrec) +				sdp_record_free(nrec); +			status = SDP_INVALID_SYNTAX; +		} +	} else +		status = SDP_INVALID_RECORD_HANDLE; + +	p = rsp->data; +	sdp_put_unaligned(htons(status), (uint16_t *)p); +	rsp->data_size = sizeof(uint16_t); +	return status; +} + +/* + * Remove a registered service record + */ +int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp) +{ +	char *p = req->buf + sizeof(sdp_pdu_hdr_t); +	uint32_t handle = ntohl(sdp_get_unaligned((uint32_t *)p)); +	sdp_record_t *rec; +	int status = 0; + +	SDPDBG(""); +	 +	/* extract service record handle */ +	p += sizeof(uint32_t); + +	rec = sdp_record_find(handle); +	if (rec) { +		sdp_svcdb_collect(rec); +		status = sdp_record_remove(handle); +		sdp_record_free(rec); +		if (status == 0) +			update_db_timestamp(); +	} else { +		status = SDP_INVALID_RECORD_HANDLE; +		SDPDBG("Could not find record : 0x%x\n", handle); +	} + +	p = rsp->data; +	sdp_put_unaligned(htons(status), (uint16_t *)p); +	rsp->data_size = sizeof(uint16_t); + +	return status; +}  | 
