xref: /freebsd-src/usr.sbin/bluetooth/sdpd/profile.c (revision fdbf7cab91ae9ae7ca87bd47acb7400813bd7160)
107be7a6cSMaksim Yevmenkin /*
207be7a6cSMaksim Yevmenkin  * profile.c
3f2505d70SMaksim Yevmenkin  */
4f2505d70SMaksim Yevmenkin 
5f2505d70SMaksim Yevmenkin /*-
64d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
71de7b4b8SPedro F. Giffuni  *
807be7a6cSMaksim Yevmenkin  * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
907be7a6cSMaksim Yevmenkin  * All rights reserved.
1007be7a6cSMaksim Yevmenkin  *
1107be7a6cSMaksim Yevmenkin  * Redistribution and use in source and binary forms, with or without
1207be7a6cSMaksim Yevmenkin  * modification, are permitted provided that the following conditions
1307be7a6cSMaksim Yevmenkin  * are met:
1407be7a6cSMaksim Yevmenkin  * 1. Redistributions of source code must retain the above copyright
1507be7a6cSMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer.
1607be7a6cSMaksim Yevmenkin  * 2. Redistributions in binary form must reproduce the above copyright
1707be7a6cSMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer in the
1807be7a6cSMaksim Yevmenkin  *    documentation and/or other materials provided with the distribution.
1907be7a6cSMaksim Yevmenkin  *
2007be7a6cSMaksim Yevmenkin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2107be7a6cSMaksim Yevmenkin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2207be7a6cSMaksim Yevmenkin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2307be7a6cSMaksim Yevmenkin  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2407be7a6cSMaksim Yevmenkin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2507be7a6cSMaksim Yevmenkin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2607be7a6cSMaksim Yevmenkin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2707be7a6cSMaksim Yevmenkin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2807be7a6cSMaksim Yevmenkin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2907be7a6cSMaksim Yevmenkin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3007be7a6cSMaksim Yevmenkin  * SUCH DAMAGE.
3107be7a6cSMaksim Yevmenkin  *
3207be7a6cSMaksim Yevmenkin  * $Id: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $
3307be7a6cSMaksim Yevmenkin  */
3407be7a6cSMaksim Yevmenkin 
35*fdbf7cabSElyes Haouas #include <sys/param.h>
3607be7a6cSMaksim Yevmenkin #include <sys/queue.h>
378d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
3807be7a6cSMaksim Yevmenkin #include <bluetooth.h>
3907be7a6cSMaksim Yevmenkin #include <sdp.h>
4007be7a6cSMaksim Yevmenkin #include <string.h>
4107be7a6cSMaksim Yevmenkin #include "profile.h"
4207be7a6cSMaksim Yevmenkin #include "provider.h"
4307be7a6cSMaksim Yevmenkin 
4407be7a6cSMaksim Yevmenkin /*
4507be7a6cSMaksim Yevmenkin  * Lookup profile descriptor
4607be7a6cSMaksim Yevmenkin  */
4707be7a6cSMaksim Yevmenkin 
4807be7a6cSMaksim Yevmenkin profile_p
profile_get_descriptor(uint16_t uuid)4907be7a6cSMaksim Yevmenkin profile_get_descriptor(uint16_t uuid)
5007be7a6cSMaksim Yevmenkin {
5121be80aeSHans Petter Selasky   	extern	profile_t	audio_sink_profile_descriptor;
5221be80aeSHans Petter Selasky 	extern	profile_t	audio_source_profile_descriptor;
5307be7a6cSMaksim Yevmenkin 	extern	profile_t	dun_profile_descriptor;
5407be7a6cSMaksim Yevmenkin 	extern	profile_t	ftrn_profile_descriptor;
5507be7a6cSMaksim Yevmenkin 	extern	profile_t	irmc_profile_descriptor;
5607be7a6cSMaksim Yevmenkin 	extern	profile_t	irmc_command_profile_descriptor;
5707be7a6cSMaksim Yevmenkin 	extern	profile_t	lan_profile_descriptor;
5807be7a6cSMaksim Yevmenkin 	extern	profile_t	opush_profile_descriptor;
5907be7a6cSMaksim Yevmenkin 	extern	profile_t	sp_profile_descriptor;
60f2505d70SMaksim Yevmenkin 	extern	profile_t	nap_profile_descriptor;
61f2505d70SMaksim Yevmenkin 	extern	profile_t	gn_profile_descriptor;
62f2505d70SMaksim Yevmenkin 	extern	profile_t	panu_profile_descriptor;
6307be7a6cSMaksim Yevmenkin 
6407be7a6cSMaksim Yevmenkin 	static const profile_p	profiles[] = {
6521be80aeSHans Petter Selasky 		&audio_sink_profile_descriptor,
6621be80aeSHans Petter Selasky 		&audio_source_profile_descriptor,
6707be7a6cSMaksim Yevmenkin 		&dun_profile_descriptor,
6807be7a6cSMaksim Yevmenkin 		&ftrn_profile_descriptor,
6907be7a6cSMaksim Yevmenkin 		&irmc_profile_descriptor,
7007be7a6cSMaksim Yevmenkin 		&irmc_command_profile_descriptor,
7107be7a6cSMaksim Yevmenkin 		&lan_profile_descriptor,
7207be7a6cSMaksim Yevmenkin 		&opush_profile_descriptor,
73f2505d70SMaksim Yevmenkin 		&sp_profile_descriptor,
74f2505d70SMaksim Yevmenkin 		&nap_profile_descriptor,
75f2505d70SMaksim Yevmenkin 		&gn_profile_descriptor,
76f2505d70SMaksim Yevmenkin 		&panu_profile_descriptor
7707be7a6cSMaksim Yevmenkin 	};
7807be7a6cSMaksim Yevmenkin 
7907be7a6cSMaksim Yevmenkin 	int32_t			i;
8007be7a6cSMaksim Yevmenkin 
81*fdbf7cabSElyes Haouas 	for (i = 0; i < nitems(profiles); i++)
8207be7a6cSMaksim Yevmenkin 		if (profiles[i]->uuid == uuid)
8307be7a6cSMaksim Yevmenkin 			return (profiles[i]);
8407be7a6cSMaksim Yevmenkin 
8507be7a6cSMaksim Yevmenkin 	return (NULL);
8607be7a6cSMaksim Yevmenkin }
8707be7a6cSMaksim Yevmenkin 
8807be7a6cSMaksim Yevmenkin /*
8907be7a6cSMaksim Yevmenkin  * Look attribute in the profile descripror
9007be7a6cSMaksim Yevmenkin  */
9107be7a6cSMaksim Yevmenkin 
9207be7a6cSMaksim Yevmenkin profile_attr_create_p
profile_get_attr(const profile_p profile,uint16_t attr)9307be7a6cSMaksim Yevmenkin profile_get_attr(const profile_p profile, uint16_t attr)
9407be7a6cSMaksim Yevmenkin {
9507be7a6cSMaksim Yevmenkin 	attr_p	ad = (attr_p) profile->attrs;
9607be7a6cSMaksim Yevmenkin 
9707be7a6cSMaksim Yevmenkin 	for (; ad->create != NULL; ad ++)
9807be7a6cSMaksim Yevmenkin 		if (ad->attr == attr)
9907be7a6cSMaksim Yevmenkin 			return (ad->create);
10007be7a6cSMaksim Yevmenkin 
10107be7a6cSMaksim Yevmenkin 	return (NULL);
10207be7a6cSMaksim Yevmenkin }
10307be7a6cSMaksim Yevmenkin 
10407be7a6cSMaksim Yevmenkin /*
10507be7a6cSMaksim Yevmenkin  * uint32 value32 - 5 bytes
10607be7a6cSMaksim Yevmenkin  */
10707be7a6cSMaksim Yevmenkin 
10807be7a6cSMaksim Yevmenkin int32_t
common_profile_create_service_record_handle(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)10907be7a6cSMaksim Yevmenkin common_profile_create_service_record_handle(
11007be7a6cSMaksim Yevmenkin 	uint8_t *buf, uint8_t const * const eob,
11107be7a6cSMaksim Yevmenkin 	uint8_t const *data, uint32_t datalen)
11207be7a6cSMaksim Yevmenkin {
11307be7a6cSMaksim Yevmenkin 	if (buf + 5 > eob)
11407be7a6cSMaksim Yevmenkin 		return (-1);
11507be7a6cSMaksim Yevmenkin 
11607be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT32, buf);
11707be7a6cSMaksim Yevmenkin 	SDP_PUT32(((provider_p) data)->handle, buf);
11807be7a6cSMaksim Yevmenkin 
11907be7a6cSMaksim Yevmenkin 	return (5);
12007be7a6cSMaksim Yevmenkin }
12107be7a6cSMaksim Yevmenkin 
12207be7a6cSMaksim Yevmenkin /*
12307be7a6cSMaksim Yevmenkin  * seq8 len8			- 2 bytes
12407be7a6cSMaksim Yevmenkin  *	uuid16 value16		- 3 bytes
12507be7a6cSMaksim Yevmenkin  *	[ uuid16 value ]
12607be7a6cSMaksim Yevmenkin  */
12707be7a6cSMaksim Yevmenkin 
12807be7a6cSMaksim Yevmenkin int32_t
common_profile_create_service_class_id_list(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)12907be7a6cSMaksim Yevmenkin common_profile_create_service_class_id_list(
13007be7a6cSMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
13107be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
13207be7a6cSMaksim Yevmenkin {
13307be7a6cSMaksim Yevmenkin 	int32_t	len = 3 * (datalen >>= 1);
13407be7a6cSMaksim Yevmenkin 
13507be7a6cSMaksim Yevmenkin 	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
13607be7a6cSMaksim Yevmenkin 		return (-1);
13707be7a6cSMaksim Yevmenkin 
13807be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
13907be7a6cSMaksim Yevmenkin 	SDP_PUT8(len, buf);
14007be7a6cSMaksim Yevmenkin 
14107be7a6cSMaksim Yevmenkin 	for (; datalen > 0; datalen --) {
14207be7a6cSMaksim Yevmenkin 		SDP_PUT8(SDP_DATA_UUID16, buf);
1431bb0b6deSAlexander Kabaev 		SDP_PUT16(*((uint16_t const *)data), buf);
1441bb0b6deSAlexander Kabaev 		data += sizeof(uint16_t);
14507be7a6cSMaksim Yevmenkin 	}
14607be7a6cSMaksim Yevmenkin 
14707be7a6cSMaksim Yevmenkin 	return (2 + len);
14807be7a6cSMaksim Yevmenkin }
14907be7a6cSMaksim Yevmenkin 
15007be7a6cSMaksim Yevmenkin /*
15107be7a6cSMaksim Yevmenkin  * seq8 len8			- 2 bytes
15207be7a6cSMaksim Yevmenkin  *	seq 8 len8		- 2 bytes
15307be7a6cSMaksim Yevmenkin  *		uuid16 value16	- 3 bytes
15407be7a6cSMaksim Yevmenkin  *		uint16 value16	- 3 bytes
15507be7a6cSMaksim Yevmenkin  *	[ seq 8 len8
15607be7a6cSMaksim Yevmenkin  *		uuid16 value16
15707be7a6cSMaksim Yevmenkin  *		uint16 value16 ]
15807be7a6cSMaksim Yevmenkin  */
15907be7a6cSMaksim Yevmenkin 
16007be7a6cSMaksim Yevmenkin int32_t
common_profile_create_bluetooth_profile_descriptor_list(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)16107be7a6cSMaksim Yevmenkin common_profile_create_bluetooth_profile_descriptor_list(
16207be7a6cSMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
16307be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
16407be7a6cSMaksim Yevmenkin {
16507be7a6cSMaksim Yevmenkin 	int32_t	len = 8 * (datalen >>= 2);
16607be7a6cSMaksim Yevmenkin 
16707be7a6cSMaksim Yevmenkin 	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
16807be7a6cSMaksim Yevmenkin 		return (-1);
16907be7a6cSMaksim Yevmenkin 
17007be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
17107be7a6cSMaksim Yevmenkin 	SDP_PUT8(len, buf);
17207be7a6cSMaksim Yevmenkin 
17307be7a6cSMaksim Yevmenkin 	for (; datalen > 0; datalen --) {
17407be7a6cSMaksim Yevmenkin 		SDP_PUT8(SDP_DATA_SEQ8, buf);
17507be7a6cSMaksim Yevmenkin 		SDP_PUT8(6, buf);
17607be7a6cSMaksim Yevmenkin 		SDP_PUT8(SDP_DATA_UUID16, buf);
1771bb0b6deSAlexander Kabaev 		SDP_PUT16(*((uint16_t const *)data), buf);
1781bb0b6deSAlexander Kabaev 		data += sizeof(uint16_t);
17907be7a6cSMaksim Yevmenkin 		SDP_PUT8(SDP_DATA_UINT16, buf);
1801bb0b6deSAlexander Kabaev 		SDP_PUT16(*((uint16_t const *)data), buf);
1811bb0b6deSAlexander Kabaev 		data += sizeof(uint16_t);
18207be7a6cSMaksim Yevmenkin 	}
18307be7a6cSMaksim Yevmenkin 
18407be7a6cSMaksim Yevmenkin 	return (2 + len);
18507be7a6cSMaksim Yevmenkin }
18607be7a6cSMaksim Yevmenkin 
18707be7a6cSMaksim Yevmenkin /*
18807be7a6cSMaksim Yevmenkin  * seq8 len8		- 2 bytes
18907be7a6cSMaksim Yevmenkin  *	uint16 value16	- 3 bytes
19007be7a6cSMaksim Yevmenkin  *	uint16 value16	- 3 bytes
19107be7a6cSMaksim Yevmenkin  *	uint16 value16	- 3 bytes
19207be7a6cSMaksim Yevmenkin  */
19307be7a6cSMaksim Yevmenkin 
19407be7a6cSMaksim Yevmenkin int32_t
common_profile_create_language_base_attribute_id_list(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)19507be7a6cSMaksim Yevmenkin common_profile_create_language_base_attribute_id_list(
19607be7a6cSMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
19707be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
19807be7a6cSMaksim Yevmenkin {
19907be7a6cSMaksim Yevmenkin 	if (buf + 11 > eob)
20007be7a6cSMaksim Yevmenkin 		return (-1);
20107be7a6cSMaksim Yevmenkin 
20207be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
20307be7a6cSMaksim Yevmenkin 	SDP_PUT8(9, buf);
20407be7a6cSMaksim Yevmenkin 
20507be7a6cSMaksim Yevmenkin 	/*
20607be7a6cSMaksim Yevmenkin 	 * Language code per ISO 639:1988. Use "en".
20707be7a6cSMaksim Yevmenkin 	 */
20807be7a6cSMaksim Yevmenkin 
20907be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT16, buf);
21007be7a6cSMaksim Yevmenkin 	SDP_PUT16(((0x65 << 8) | 0x6e), buf);
21107be7a6cSMaksim Yevmenkin 
21207be7a6cSMaksim Yevmenkin 	/*
21307be7a6cSMaksim Yevmenkin 	 * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106
21407be7a6cSMaksim Yevmenkin 	 * (http://www.iana.org/assignments/character-sets)
21507be7a6cSMaksim Yevmenkin 	 */
21607be7a6cSMaksim Yevmenkin 
21707be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT16, buf);
21807be7a6cSMaksim Yevmenkin 	SDP_PUT16(106, buf);
21907be7a6cSMaksim Yevmenkin 
22007be7a6cSMaksim Yevmenkin 	/*
22107be7a6cSMaksim Yevmenkin 	 * Offset (Primary Language Base is 0x100)
22207be7a6cSMaksim Yevmenkin 	 */
22307be7a6cSMaksim Yevmenkin 
22407be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT16, buf);
22507be7a6cSMaksim Yevmenkin 	SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf);
22607be7a6cSMaksim Yevmenkin 
22707be7a6cSMaksim Yevmenkin 	return (11);
22807be7a6cSMaksim Yevmenkin }
22907be7a6cSMaksim Yevmenkin 
23007be7a6cSMaksim Yevmenkin /*
23107be7a6cSMaksim Yevmenkin  * Common provider name is "FreeBSD"
23207be7a6cSMaksim Yevmenkin  */
23307be7a6cSMaksim Yevmenkin 
23407be7a6cSMaksim Yevmenkin int32_t
common_profile_create_service_provider_name(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)23507be7a6cSMaksim Yevmenkin common_profile_create_service_provider_name(
23607be7a6cSMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
23707be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
23807be7a6cSMaksim Yevmenkin {
23907be7a6cSMaksim Yevmenkin 	char	provider_name[] = "FreeBSD";
24007be7a6cSMaksim Yevmenkin 
24107be7a6cSMaksim Yevmenkin 	return (common_profile_create_string8(buf, eob,
24207be7a6cSMaksim Yevmenkin 			(uint8_t const *) provider_name,
24307be7a6cSMaksim Yevmenkin 			strlen(provider_name)));
24407be7a6cSMaksim Yevmenkin }
24507be7a6cSMaksim Yevmenkin 
24607be7a6cSMaksim Yevmenkin /*
24707be7a6cSMaksim Yevmenkin  * str8 len8 string
24807be7a6cSMaksim Yevmenkin  */
24907be7a6cSMaksim Yevmenkin 
25007be7a6cSMaksim Yevmenkin int32_t
common_profile_create_string8(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)25107be7a6cSMaksim Yevmenkin common_profile_create_string8(
25207be7a6cSMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
25307be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
25407be7a6cSMaksim Yevmenkin {
25507be7a6cSMaksim Yevmenkin 	if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob)
25607be7a6cSMaksim Yevmenkin 		return (-1);
25707be7a6cSMaksim Yevmenkin 
25807be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_STR8, buf);
25907be7a6cSMaksim Yevmenkin 	SDP_PUT8(datalen, buf);
26007be7a6cSMaksim Yevmenkin 	memcpy(buf, data, datalen);
26107be7a6cSMaksim Yevmenkin 
26207be7a6cSMaksim Yevmenkin 	return (2 + datalen);
26307be7a6cSMaksim Yevmenkin }
26407be7a6cSMaksim Yevmenkin 
26507be7a6cSMaksim Yevmenkin /*
26613040bc9SMaksim Yevmenkin  * Service Availability
26713040bc9SMaksim Yevmenkin  */
26813040bc9SMaksim Yevmenkin 
26913040bc9SMaksim Yevmenkin int32_t
common_profile_create_service_availability(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)27013040bc9SMaksim Yevmenkin common_profile_create_service_availability(
27113040bc9SMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
27213040bc9SMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
27313040bc9SMaksim Yevmenkin {
27413040bc9SMaksim Yevmenkin 	if (datalen != 1 || buf + 2 > eob)
27513040bc9SMaksim Yevmenkin 		return (-1);
27613040bc9SMaksim Yevmenkin 
27713040bc9SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT8, buf);
27813040bc9SMaksim Yevmenkin 	SDP_PUT8(data[0], buf);
27913040bc9SMaksim Yevmenkin 
28013040bc9SMaksim Yevmenkin 	return (2);
28113040bc9SMaksim Yevmenkin }
28213040bc9SMaksim Yevmenkin 
28313040bc9SMaksim Yevmenkin /*
28407be7a6cSMaksim Yevmenkin  * seq8 len8			- 2 bytes
28507be7a6cSMaksim Yevmenkin  *	seq8 len8		- 2 bytes
28607be7a6cSMaksim Yevmenkin  *		uuid16 value16	- 3 bytes
28707be7a6cSMaksim Yevmenkin  *	seq8 len8		- 2 bytes
28807be7a6cSMaksim Yevmenkin  *		uuid16 value16	- 3 bytes
28907be7a6cSMaksim Yevmenkin  *		uint8 value8	- 2 bytes
29007be7a6cSMaksim Yevmenkin  */
29107be7a6cSMaksim Yevmenkin 
29207be7a6cSMaksim Yevmenkin int32_t
rfcomm_profile_create_protocol_descriptor_list(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)29307be7a6cSMaksim Yevmenkin rfcomm_profile_create_protocol_descriptor_list(
29407be7a6cSMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
29507be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
29607be7a6cSMaksim Yevmenkin {
29707be7a6cSMaksim Yevmenkin 	if (datalen != 1 || buf + 14 > eob)
29807be7a6cSMaksim Yevmenkin 		return (-1);
29907be7a6cSMaksim Yevmenkin 
30007be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
30107be7a6cSMaksim Yevmenkin 	SDP_PUT8(12, buf);
30207be7a6cSMaksim Yevmenkin 
30307be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
30407be7a6cSMaksim Yevmenkin 	SDP_PUT8(3, buf);
30507be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UUID16, buf);
30607be7a6cSMaksim Yevmenkin 	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
30707be7a6cSMaksim Yevmenkin 
30807be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
30907be7a6cSMaksim Yevmenkin 	SDP_PUT8(5, buf);
31007be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UUID16, buf);
31107be7a6cSMaksim Yevmenkin 	SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
31207be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT8, buf);
31307be7a6cSMaksim Yevmenkin 	SDP_PUT8(*data, buf);
31407be7a6cSMaksim Yevmenkin 
31507be7a6cSMaksim Yevmenkin 	return (14);
31607be7a6cSMaksim Yevmenkin }
31707be7a6cSMaksim Yevmenkin 
31807be7a6cSMaksim Yevmenkin /*
31907be7a6cSMaksim Yevmenkin  * seq8 len8			- 2 bytes
32007be7a6cSMaksim Yevmenkin  *	seq8 len8		- 2 bytes
32107be7a6cSMaksim Yevmenkin  *		uuid16 value16	- 3 bytes
32207be7a6cSMaksim Yevmenkin  *	seq8 len8		- 2 bytes
32307be7a6cSMaksim Yevmenkin  *		uuid16 value16	- 3 bytes
32407be7a6cSMaksim Yevmenkin  *		uint8 value8	- 2 bytes
32507be7a6cSMaksim Yevmenkin  *	seq8 len8		- 2 bytes
32607be7a6cSMaksim Yevmenkin  *		uuid16 value16	- 3 bytes
32707be7a6cSMaksim Yevmenkin  */
32807be7a6cSMaksim Yevmenkin 
32907be7a6cSMaksim Yevmenkin int32_t
obex_profile_create_protocol_descriptor_list(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)33007be7a6cSMaksim Yevmenkin obex_profile_create_protocol_descriptor_list(
33107be7a6cSMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
33207be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
33307be7a6cSMaksim Yevmenkin {
33407be7a6cSMaksim Yevmenkin 	if (datalen != 1 || buf + 19 > eob)
33507be7a6cSMaksim Yevmenkin 		return (-1);
33607be7a6cSMaksim Yevmenkin 
33707be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
33807be7a6cSMaksim Yevmenkin 	SDP_PUT8(17, buf);
33907be7a6cSMaksim Yevmenkin 
34007be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
34107be7a6cSMaksim Yevmenkin 	SDP_PUT8(3, buf);
34207be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UUID16, buf);
34307be7a6cSMaksim Yevmenkin 	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
34407be7a6cSMaksim Yevmenkin 
34507be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
34607be7a6cSMaksim Yevmenkin 	SDP_PUT8(5, buf);
34707be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UUID16, buf);
34807be7a6cSMaksim Yevmenkin 	SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
34907be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT8, buf);
35007be7a6cSMaksim Yevmenkin 	SDP_PUT8(*data, buf);
35107be7a6cSMaksim Yevmenkin 
35207be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
35307be7a6cSMaksim Yevmenkin 	SDP_PUT8(3, buf);
35407be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UUID16, buf);
35507be7a6cSMaksim Yevmenkin 	SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf);
35607be7a6cSMaksim Yevmenkin 
35707be7a6cSMaksim Yevmenkin 	return (19);
35807be7a6cSMaksim Yevmenkin }
35907be7a6cSMaksim Yevmenkin 
36007be7a6cSMaksim Yevmenkin /*
36107be7a6cSMaksim Yevmenkin  * seq8 len8
36207be7a6cSMaksim Yevmenkin  *	uint8 value8	- bytes
36307be7a6cSMaksim Yevmenkin  *	[ uint8 value 8 ]
36407be7a6cSMaksim Yevmenkin  */
36507be7a6cSMaksim Yevmenkin 
36607be7a6cSMaksim Yevmenkin int32_t
obex_profile_create_supported_formats_list(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)36707be7a6cSMaksim Yevmenkin obex_profile_create_supported_formats_list(
36807be7a6cSMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
36907be7a6cSMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
37007be7a6cSMaksim Yevmenkin {
37107be7a6cSMaksim Yevmenkin 	int32_t	len = 2 * datalen;
37207be7a6cSMaksim Yevmenkin 
37307be7a6cSMaksim Yevmenkin 	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
37407be7a6cSMaksim Yevmenkin 		return (-1);
37507be7a6cSMaksim Yevmenkin 
37607be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
37707be7a6cSMaksim Yevmenkin 	SDP_PUT8(len, buf);
37807be7a6cSMaksim Yevmenkin 
37907be7a6cSMaksim Yevmenkin 	for (; datalen > 0; datalen --) {
38007be7a6cSMaksim Yevmenkin 		SDP_PUT8(SDP_DATA_UINT8, buf);
38107be7a6cSMaksim Yevmenkin 		SDP_PUT8(*data++, buf);
38207be7a6cSMaksim Yevmenkin 	}
38307be7a6cSMaksim Yevmenkin 
38407be7a6cSMaksim Yevmenkin 	return (2 + len);
38507be7a6cSMaksim Yevmenkin }
38607be7a6cSMaksim Yevmenkin 
38707be7a6cSMaksim Yevmenkin /*
388f2505d70SMaksim Yevmenkin  * do not check anything
389f2505d70SMaksim Yevmenkin  */
390f2505d70SMaksim Yevmenkin 
391f2505d70SMaksim Yevmenkin int32_t
common_profile_always_valid(uint8_t const * data,uint32_t datalen)392f2505d70SMaksim Yevmenkin common_profile_always_valid(uint8_t const *data, uint32_t datalen)
393f2505d70SMaksim Yevmenkin {
394f2505d70SMaksim Yevmenkin 	return (1);
395f2505d70SMaksim Yevmenkin }
396f2505d70SMaksim Yevmenkin 
397f2505d70SMaksim Yevmenkin /*
39807be7a6cSMaksim Yevmenkin  * verify server channel number (the first byte in the data)
39907be7a6cSMaksim Yevmenkin  */
40007be7a6cSMaksim Yevmenkin 
40107be7a6cSMaksim Yevmenkin int32_t
common_profile_server_channel_valid(uint8_t const * data,uint32_t datalen)40207be7a6cSMaksim Yevmenkin common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen)
40307be7a6cSMaksim Yevmenkin {
40407be7a6cSMaksim Yevmenkin 	if (data[0] < 1 || data[0] > 30)
40507be7a6cSMaksim Yevmenkin 		return (0);
40607be7a6cSMaksim Yevmenkin 
40707be7a6cSMaksim Yevmenkin 	return (1);
40807be7a6cSMaksim Yevmenkin }
40907be7a6cSMaksim Yevmenkin 
41007be7a6cSMaksim Yevmenkin /*
41107be7a6cSMaksim Yevmenkin  * verify server channel number and supported_formats_size
41207be7a6cSMaksim Yevmenkin  * sdp_opush_profile and sdp_irmc_profile
41307be7a6cSMaksim Yevmenkin  */
41407be7a6cSMaksim Yevmenkin 
41507be7a6cSMaksim Yevmenkin int32_t
obex_profile_data_valid(uint8_t const * data,uint32_t datalen)41607be7a6cSMaksim Yevmenkin obex_profile_data_valid(uint8_t const *data, uint32_t datalen)
41707be7a6cSMaksim Yevmenkin {
41807be7a6cSMaksim Yevmenkin 	sdp_opush_profile_p	opush = (sdp_opush_profile_p) data;
41907be7a6cSMaksim Yevmenkin 
42007be7a6cSMaksim Yevmenkin 	if (opush->server_channel < 1 ||
42107be7a6cSMaksim Yevmenkin 	    opush->server_channel > 30 ||
42207be7a6cSMaksim Yevmenkin 	    opush->supported_formats_size == 0 ||
42307be7a6cSMaksim Yevmenkin 	    opush->supported_formats_size > sizeof(opush->supported_formats))
42407be7a6cSMaksim Yevmenkin 		return (0);
42507be7a6cSMaksim Yevmenkin 
42607be7a6cSMaksim Yevmenkin 	return (1);
42707be7a6cSMaksim Yevmenkin }
42807be7a6cSMaksim Yevmenkin 
429f2505d70SMaksim Yevmenkin /*
430f2505d70SMaksim Yevmenkin  * BNEP protocol descriptor
431f2505d70SMaksim Yevmenkin  */
432f2505d70SMaksim Yevmenkin 
433f2505d70SMaksim Yevmenkin int32_t
bnep_profile_create_protocol_descriptor_list(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)434f2505d70SMaksim Yevmenkin bnep_profile_create_protocol_descriptor_list(
435f2505d70SMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
436f2505d70SMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
437f2505d70SMaksim Yevmenkin {
438f2505d70SMaksim Yevmenkin 	/* supported protocol types */
439f2505d70SMaksim Yevmenkin 	uint16_t	 ptype[] = {
440f2505d70SMaksim Yevmenkin 		0x0800,	/* IPv4 */
441f2505d70SMaksim Yevmenkin 		0x0806,	/* ARP */
442f2505d70SMaksim Yevmenkin #ifdef INET6
443f2505d70SMaksim Yevmenkin 		0x86dd,	/* IPv6 */
444f2505d70SMaksim Yevmenkin #endif
445f2505d70SMaksim Yevmenkin 	};
446f2505d70SMaksim Yevmenkin 
44713040bc9SMaksim Yevmenkin 	uint16_t	 i, psm, version = 0x0100,
448*fdbf7cabSElyes Haouas 			 nptypes = nitems(ptype),
449f2505d70SMaksim Yevmenkin 			 nptypes_size = nptypes * 3;
450f2505d70SMaksim Yevmenkin 
45113040bc9SMaksim Yevmenkin 	if (datalen != 2 || 18 + nptypes_size > 255 ||
45213040bc9SMaksim Yevmenkin 	    buf + 20 + nptypes_size > eob)
453f2505d70SMaksim Yevmenkin 		return (-1);
454f2505d70SMaksim Yevmenkin 
45513040bc9SMaksim Yevmenkin 	memcpy(&psm, data, sizeof(psm));
45613040bc9SMaksim Yevmenkin 
457f2505d70SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
458f2505d70SMaksim Yevmenkin 	SDP_PUT8(18 + nptypes_size, buf);
459f2505d70SMaksim Yevmenkin 
460f2505d70SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
461f2505d70SMaksim Yevmenkin 	SDP_PUT8(6, buf);
462f2505d70SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UUID16, buf);
463f2505d70SMaksim Yevmenkin 	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
464f2505d70SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT16, buf);
465f2505d70SMaksim Yevmenkin 	SDP_PUT16(psm, buf);
466f2505d70SMaksim Yevmenkin 
467f2505d70SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
468f2505d70SMaksim Yevmenkin 	SDP_PUT8(8 + nptypes_size, buf);
469f2505d70SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UUID16, buf);
470f2505d70SMaksim Yevmenkin 	SDP_PUT16(SDP_UUID_PROTOCOL_BNEP, buf);
471f2505d70SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT16, buf);
472f2505d70SMaksim Yevmenkin 	SDP_PUT16(version, buf);
473f2505d70SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ8, buf);
474f2505d70SMaksim Yevmenkin 	SDP_PUT8(nptypes_size, buf);
475f2505d70SMaksim Yevmenkin 	for (i = 0; i < nptypes; i ++) {
476f2505d70SMaksim Yevmenkin 		SDP_PUT8(SDP_DATA_UINT16, buf);
477f2505d70SMaksim Yevmenkin 		SDP_PUT16(ptype[i], buf);
478f2505d70SMaksim Yevmenkin 	}
479f2505d70SMaksim Yevmenkin 
480f2505d70SMaksim Yevmenkin 	return (20 + nptypes_size);
481f2505d70SMaksim Yevmenkin }
482f2505d70SMaksim Yevmenkin 
483f2505d70SMaksim Yevmenkin /*
484f2505d70SMaksim Yevmenkin  * BNEP security description
485f2505d70SMaksim Yevmenkin  */
486f2505d70SMaksim Yevmenkin 
487f2505d70SMaksim Yevmenkin int32_t
bnep_profile_create_security_description(uint8_t * buf,uint8_t const * const eob,uint8_t const * data,uint32_t datalen)488f2505d70SMaksim Yevmenkin bnep_profile_create_security_description(
489f2505d70SMaksim Yevmenkin 		uint8_t *buf, uint8_t const * const eob,
490f2505d70SMaksim Yevmenkin 		uint8_t const *data, uint32_t datalen)
491f2505d70SMaksim Yevmenkin {
492f2505d70SMaksim Yevmenkin 	uint16_t	security_descr;
493f2505d70SMaksim Yevmenkin 
494f2505d70SMaksim Yevmenkin 	if (datalen != 2 || buf + 3 > eob)
495f2505d70SMaksim Yevmenkin 		return (-1);
496f2505d70SMaksim Yevmenkin 
497f2505d70SMaksim Yevmenkin 	memcpy(&security_descr, data, sizeof(security_descr));
498f2505d70SMaksim Yevmenkin 
499f2505d70SMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_UINT16, buf);
500f2505d70SMaksim Yevmenkin 	SDP_PUT16(security_descr, buf);
501f2505d70SMaksim Yevmenkin 
502f2505d70SMaksim Yevmenkin         return (3);
503f2505d70SMaksim Yevmenkin }
504f2505d70SMaksim Yevmenkin 
505