1124758Semax/*
2124758Semax * profile.c
3177059Semax */
4177059Semax
5177059Semax/*-
6124758Semax * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7124758Semax * All rights reserved.
8124758Semax *
9124758Semax * Redistribution and use in source and binary forms, with or without
10124758Semax * modification, are permitted provided that the following conditions
11124758Semax * are met:
12124758Semax * 1. Redistributions of source code must retain the above copyright
13124758Semax *    notice, this list of conditions and the following disclaimer.
14124758Semax * 2. Redistributions in binary form must reproduce the above copyright
15124758Semax *    notice, this list of conditions and the following disclaimer in the
16124758Semax *    documentation and/or other materials provided with the distribution.
17124758Semax *
18124758Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19124758Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20124758Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21124758Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22124758Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23124758Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24124758Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25124758Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26124758Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27124758Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28124758Semax * SUCH DAMAGE.
29124758Semax *
30124758Semax * $Id: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $
31124758Semax * $FreeBSD$
32124758Semax */
33124758Semax
34124758Semax#include <sys/queue.h>
35124758Semax#include <bluetooth.h>
36124758Semax#include <sdp.h>
37124758Semax#include <string.h>
38124758Semax#include "profile.h"
39124758Semax#include "provider.h"
40124758Semax
41124758Semax/*
42124758Semax * Lookup profile descriptor
43124758Semax */
44124758Semax
45124758Semaxprofile_p
46124758Semaxprofile_get_descriptor(uint16_t uuid)
47124758Semax{
48124758Semax	extern	profile_t	dun_profile_descriptor;
49124758Semax	extern	profile_t	ftrn_profile_descriptor;
50124758Semax	extern	profile_t	irmc_profile_descriptor;
51124758Semax	extern	profile_t	irmc_command_profile_descriptor;
52124758Semax	extern	profile_t	lan_profile_descriptor;
53124758Semax	extern	profile_t	opush_profile_descriptor;
54124758Semax	extern	profile_t	sp_profile_descriptor;
55177059Semax	extern	profile_t	nap_profile_descriptor;
56177059Semax	extern	profile_t	gn_profile_descriptor;
57177059Semax	extern	profile_t	panu_profile_descriptor;
58124758Semax
59124758Semax	static const profile_p	profiles[] = {
60124758Semax		&dun_profile_descriptor,
61124758Semax		&ftrn_profile_descriptor,
62124758Semax		&irmc_profile_descriptor,
63124758Semax		&irmc_command_profile_descriptor,
64124758Semax		&lan_profile_descriptor,
65124758Semax		&opush_profile_descriptor,
66177059Semax		&sp_profile_descriptor,
67177059Semax		&nap_profile_descriptor,
68177059Semax		&gn_profile_descriptor,
69177059Semax		&panu_profile_descriptor
70124758Semax	};
71124758Semax
72124758Semax	int32_t			i;
73124758Semax
74124758Semax	for (i = 0; i < sizeof(profiles)/sizeof(profiles[0]); i++)
75124758Semax		if (profiles[i]->uuid == uuid)
76124758Semax			return (profiles[i]);
77124758Semax
78124758Semax	return (NULL);
79124758Semax}
80124758Semax
81124758Semax/*
82124758Semax * Look attribute in the profile descripror
83124758Semax */
84124758Semax
85124758Semaxprofile_attr_create_p
86124758Semaxprofile_get_attr(const profile_p profile, uint16_t attr)
87124758Semax{
88124758Semax	attr_p	ad = (attr_p) profile->attrs;
89124758Semax
90124758Semax	for (; ad->create != NULL; ad ++)
91124758Semax		if (ad->attr == attr)
92124758Semax			return (ad->create);
93124758Semax
94124758Semax	return (NULL);
95124758Semax}
96124758Semax
97124758Semax/*
98124758Semax * uint32 value32 - 5 bytes
99124758Semax */
100124758Semax
101124758Semaxint32_t
102124758Semaxcommon_profile_create_service_record_handle(
103124758Semax	uint8_t *buf, uint8_t const * const eob,
104124758Semax	uint8_t const *data, uint32_t datalen)
105124758Semax{
106124758Semax	if (buf + 5 > eob)
107124758Semax		return (-1);
108124758Semax
109124758Semax	SDP_PUT8(SDP_DATA_UINT32, buf);
110124758Semax	SDP_PUT32(((provider_p) data)->handle, buf);
111124758Semax
112124758Semax	return (5);
113124758Semax}
114124758Semax
115124758Semax/*
116124758Semax * seq8 len8			- 2 bytes
117124758Semax *	uuid16 value16		- 3 bytes
118124758Semax *	[ uuid16 value ]
119124758Semax */
120124758Semax
121124758Semaxint32_t
122124758Semaxcommon_profile_create_service_class_id_list(
123124758Semax		uint8_t *buf, uint8_t const * const eob,
124124758Semax		uint8_t const *data, uint32_t datalen)
125124758Semax{
126124758Semax	int32_t	len = 3 * (datalen >>= 1);
127124758Semax
128124758Semax	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
129124758Semax		return (-1);
130124758Semax
131124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
132124758Semax	SDP_PUT8(len, buf);
133124758Semax
134124758Semax	for (; datalen > 0; datalen --) {
135124758Semax		SDP_PUT8(SDP_DATA_UUID16, buf);
136132790Skan		SDP_PUT16(*((uint16_t const *)data), buf);
137132790Skan		data += sizeof(uint16_t);
138124758Semax	}
139124758Semax
140124758Semax	return (2 + len);
141124758Semax}
142124758Semax
143124758Semax/*
144124758Semax * seq8 len8			- 2 bytes
145124758Semax *	seq 8 len8		- 2 bytes
146124758Semax *		uuid16 value16	- 3 bytes
147124758Semax *		uint16 value16	- 3 bytes
148124758Semax *	[ seq 8 len8
149124758Semax *		uuid16 value16
150124758Semax *		uint16 value16 ]
151124758Semax */
152124758Semax
153124758Semaxint32_t
154124758Semaxcommon_profile_create_bluetooth_profile_descriptor_list(
155124758Semax		uint8_t *buf, uint8_t const * const eob,
156124758Semax		uint8_t const *data, uint32_t datalen)
157124758Semax{
158124758Semax	int32_t	len = 8 * (datalen >>= 2);
159124758Semax
160124758Semax	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
161124758Semax		return (-1);
162124758Semax
163124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
164124758Semax	SDP_PUT8(len, buf);
165124758Semax
166124758Semax	for (; datalen > 0; datalen --) {
167124758Semax		SDP_PUT8(SDP_DATA_SEQ8, buf);
168124758Semax		SDP_PUT8(6, buf);
169124758Semax		SDP_PUT8(SDP_DATA_UUID16, buf);
170132790Skan		SDP_PUT16(*((uint16_t const *)data), buf);
171132790Skan		data += sizeof(uint16_t);
172124758Semax		SDP_PUT8(SDP_DATA_UINT16, buf);
173132790Skan		SDP_PUT16(*((uint16_t const *)data), buf);
174132790Skan		data += sizeof(uint16_t);
175124758Semax	}
176124758Semax
177124758Semax	return (2 + len);
178124758Semax}
179124758Semax
180124758Semax/*
181124758Semax * seq8 len8		- 2 bytes
182124758Semax *	uint16 value16	- 3 bytes
183124758Semax *	uint16 value16	- 3 bytes
184124758Semax *	uint16 value16	- 3 bytes
185124758Semax */
186124758Semax
187124758Semaxint32_t
188124758Semaxcommon_profile_create_language_base_attribute_id_list(
189124758Semax		uint8_t *buf, uint8_t const * const eob,
190124758Semax		uint8_t const *data, uint32_t datalen)
191124758Semax{
192124758Semax	if (buf + 11 > eob)
193124758Semax		return (-1);
194124758Semax
195124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
196124758Semax	SDP_PUT8(9, buf);
197124758Semax
198124758Semax	/*
199124758Semax	 * Language code per ISO 639:1988. Use "en".
200124758Semax	 */
201124758Semax
202124758Semax	SDP_PUT8(SDP_DATA_UINT16, buf);
203124758Semax	SDP_PUT16(((0x65 << 8) | 0x6e), buf);
204124758Semax
205124758Semax	/*
206124758Semax	 * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106
207124758Semax	 * (http://www.iana.org/assignments/character-sets)
208124758Semax	 */
209124758Semax
210124758Semax	SDP_PUT8(SDP_DATA_UINT16, buf);
211124758Semax	SDP_PUT16(106, buf);
212124758Semax
213124758Semax	/*
214124758Semax	 * Offset (Primary Language Base is 0x100)
215124758Semax	 */
216124758Semax
217124758Semax	SDP_PUT8(SDP_DATA_UINT16, buf);
218124758Semax	SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf);
219124758Semax
220124758Semax	return (11);
221124758Semax}
222124758Semax
223124758Semax/*
224124758Semax * Common provider name is "FreeBSD"
225124758Semax */
226124758Semax
227124758Semaxint32_t
228124758Semaxcommon_profile_create_service_provider_name(
229124758Semax		uint8_t *buf, uint8_t const * const eob,
230124758Semax		uint8_t const *data, uint32_t datalen)
231124758Semax{
232124758Semax	char	provider_name[] = "FreeBSD";
233124758Semax
234124758Semax	return (common_profile_create_string8(buf, eob,
235124758Semax			(uint8_t const *) provider_name,
236124758Semax			strlen(provider_name)));
237124758Semax}
238124758Semax
239124758Semax/*
240124758Semax * str8 len8 string
241124758Semax */
242124758Semax
243124758Semaxint32_t
244124758Semaxcommon_profile_create_string8(
245124758Semax		uint8_t *buf, uint8_t const * const eob,
246124758Semax		uint8_t const *data, uint32_t datalen)
247124758Semax{
248124758Semax	if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob)
249124758Semax		return (-1);
250124758Semax
251124758Semax	SDP_PUT8(SDP_DATA_STR8, buf);
252124758Semax	SDP_PUT8(datalen, buf);
253124758Semax	memcpy(buf, data, datalen);
254124758Semax
255124758Semax	return (2 + datalen);
256124758Semax}
257124758Semax
258124758Semax/*
259177358Semax * Service Availability
260177358Semax */
261177358Semax
262177358Semaxint32_t
263177358Semaxcommon_profile_create_service_availability(
264177358Semax		uint8_t *buf, uint8_t const * const eob,
265177358Semax		uint8_t const *data, uint32_t datalen)
266177358Semax{
267177358Semax	if (datalen != 1 || buf + 2 > eob)
268177358Semax		return (-1);
269177358Semax
270177358Semax	SDP_PUT8(SDP_DATA_UINT8, buf);
271177358Semax	SDP_PUT8(data[0], buf);
272177358Semax
273177358Semax	return (2);
274177358Semax}
275177358Semax
276177358Semax/*
277124758Semax * seq8 len8			- 2 bytes
278124758Semax *	seq8 len8		- 2 bytes
279124758Semax *		uuid16 value16	- 3 bytes
280124758Semax *	seq8 len8		- 2 bytes
281124758Semax *		uuid16 value16	- 3 bytes
282124758Semax *		uint8 value8	- 2 bytes
283124758Semax */
284124758Semax
285124758Semaxint32_t
286124758Semaxrfcomm_profile_create_protocol_descriptor_list(
287124758Semax		uint8_t *buf, uint8_t const * const eob,
288124758Semax		uint8_t const *data, uint32_t datalen)
289124758Semax{
290124758Semax	if (datalen != 1 || buf + 14 > eob)
291124758Semax		return (-1);
292124758Semax
293124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
294124758Semax	SDP_PUT8(12, buf);
295124758Semax
296124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
297124758Semax	SDP_PUT8(3, buf);
298124758Semax	SDP_PUT8(SDP_DATA_UUID16, buf);
299124758Semax	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
300124758Semax
301124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
302124758Semax	SDP_PUT8(5, buf);
303124758Semax	SDP_PUT8(SDP_DATA_UUID16, buf);
304124758Semax	SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
305124758Semax	SDP_PUT8(SDP_DATA_UINT8, buf);
306124758Semax	SDP_PUT8(*data, buf);
307124758Semax
308124758Semax	return (14);
309124758Semax}
310124758Semax
311124758Semax/*
312124758Semax * seq8 len8			- 2 bytes
313124758Semax *	seq8 len8		- 2 bytes
314124758Semax *		uuid16 value16	- 3 bytes
315124758Semax *	seq8 len8		- 2 bytes
316124758Semax *		uuid16 value16	- 3 bytes
317124758Semax *		uint8 value8	- 2 bytes
318124758Semax *	seq8 len8		- 2 bytes
319124758Semax *		uuid16 value16	- 3 bytes
320124758Semax */
321124758Semax
322124758Semaxint32_t
323124758Semaxobex_profile_create_protocol_descriptor_list(
324124758Semax		uint8_t *buf, uint8_t const * const eob,
325124758Semax		uint8_t const *data, uint32_t datalen)
326124758Semax{
327124758Semax	if (datalen != 1 || buf + 19 > eob)
328124758Semax		return (-1);
329124758Semax
330124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
331124758Semax	SDP_PUT8(17, buf);
332124758Semax
333124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
334124758Semax	SDP_PUT8(3, buf);
335124758Semax	SDP_PUT8(SDP_DATA_UUID16, buf);
336124758Semax	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
337124758Semax
338124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
339124758Semax	SDP_PUT8(5, buf);
340124758Semax	SDP_PUT8(SDP_DATA_UUID16, buf);
341124758Semax	SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
342124758Semax	SDP_PUT8(SDP_DATA_UINT8, buf);
343124758Semax	SDP_PUT8(*data, buf);
344124758Semax
345124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
346124758Semax	SDP_PUT8(3, buf);
347124758Semax	SDP_PUT8(SDP_DATA_UUID16, buf);
348124758Semax	SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf);
349124758Semax
350124758Semax	return (19);
351124758Semax}
352124758Semax
353124758Semax/*
354124758Semax * seq8 len8
355124758Semax *	uint8 value8	- bytes
356124758Semax *	[ uint8 value 8 ]
357124758Semax */
358124758Semax
359124758Semaxint32_t
360124758Semaxobex_profile_create_supported_formats_list(
361124758Semax		uint8_t *buf, uint8_t const * const eob,
362124758Semax		uint8_t const *data, uint32_t datalen)
363124758Semax{
364124758Semax	int32_t	len = 2 * datalen;
365124758Semax
366124758Semax	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
367124758Semax		return (-1);
368124758Semax
369124758Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
370124758Semax	SDP_PUT8(len, buf);
371124758Semax
372124758Semax	for (; datalen > 0; datalen --) {
373124758Semax		SDP_PUT8(SDP_DATA_UINT8, buf);
374124758Semax		SDP_PUT8(*data++, buf);
375124758Semax	}
376124758Semax
377124758Semax	return (2 + len);
378124758Semax}
379124758Semax
380124758Semax/*
381177059Semax * do not check anything
382177059Semax */
383177059Semax
384177059Semaxint32_t
385177059Semaxcommon_profile_always_valid(uint8_t const *data, uint32_t datalen)
386177059Semax{
387177059Semax	return (1);
388177059Semax}
389177059Semax
390177059Semax/*
391124758Semax * verify server channel number (the first byte in the data)
392124758Semax */
393124758Semax
394124758Semaxint32_t
395124758Semaxcommon_profile_server_channel_valid(uint8_t const *data, uint32_t datalen)
396124758Semax{
397124758Semax	if (data[0] < 1 || data[0] > 30)
398124758Semax		return (0);
399124758Semax
400124758Semax	return (1);
401124758Semax}
402124758Semax
403124758Semax/*
404124758Semax * verify server channel number and supported_formats_size
405124758Semax * sdp_opush_profile and sdp_irmc_profile
406124758Semax */
407124758Semax
408124758Semaxint32_t
409124758Semaxobex_profile_data_valid(uint8_t const *data, uint32_t datalen)
410124758Semax{
411124758Semax	sdp_opush_profile_p	opush = (sdp_opush_profile_p) data;
412124758Semax
413124758Semax	if (opush->server_channel < 1 ||
414124758Semax	    opush->server_channel > 30 ||
415124758Semax	    opush->supported_formats_size == 0 ||
416124758Semax	    opush->supported_formats_size > sizeof(opush->supported_formats))
417124758Semax		return (0);
418124758Semax
419124758Semax	return (1);
420124758Semax}
421124758Semax
422177059Semax/*
423177059Semax * BNEP protocol descriptor
424177059Semax */
425177059Semax
426177059Semaxint32_t
427177059Semaxbnep_profile_create_protocol_descriptor_list(
428177059Semax		uint8_t *buf, uint8_t const * const eob,
429177059Semax		uint8_t const *data, uint32_t datalen)
430177059Semax{
431177059Semax	/* supported protocol types */
432177059Semax	uint16_t	 ptype[] = {
433177059Semax		0x0800,	/* IPv4 */
434177059Semax		0x0806,	/* ARP */
435177059Semax#ifdef INET6
436177059Semax		0x86dd,	/* IPv6 */
437177059Semax#endif
438177059Semax	};
439177059Semax
440177358Semax	uint16_t	 i, psm, version = 0x0100,
441177059Semax			 nptypes = sizeof(ptype)/sizeof(ptype[0]),
442177059Semax			 nptypes_size = nptypes * 3;
443177059Semax
444177358Semax	if (datalen != 2 || 18 + nptypes_size > 255 ||
445177358Semax	    buf + 20 + nptypes_size > eob)
446177059Semax		return (-1);
447177059Semax
448177358Semax	memcpy(&psm, data, sizeof(psm));
449177358Semax
450177059Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
451177059Semax	SDP_PUT8(18 + nptypes_size, buf);
452177059Semax
453177059Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
454177059Semax	SDP_PUT8(6, buf);
455177059Semax	SDP_PUT8(SDP_DATA_UUID16, buf);
456177059Semax	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
457177059Semax	SDP_PUT8(SDP_DATA_UINT16, buf);
458177059Semax	SDP_PUT16(psm, buf);
459177059Semax
460177059Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
461177059Semax	SDP_PUT8(8 + nptypes_size, buf);
462177059Semax	SDP_PUT8(SDP_DATA_UUID16, buf);
463177059Semax	SDP_PUT16(SDP_UUID_PROTOCOL_BNEP, buf);
464177059Semax	SDP_PUT8(SDP_DATA_UINT16, buf);
465177059Semax	SDP_PUT16(version, buf);
466177059Semax	SDP_PUT8(SDP_DATA_SEQ8, buf);
467177059Semax	SDP_PUT8(nptypes_size, buf);
468177059Semax	for (i = 0; i < nptypes; i ++) {
469177059Semax		SDP_PUT8(SDP_DATA_UINT16, buf);
470177059Semax		SDP_PUT16(ptype[i], buf);
471177059Semax	}
472177059Semax
473177059Semax	return (20 + nptypes_size);
474177059Semax}
475177059Semax
476177059Semax/*
477177059Semax * BNEP security description
478177059Semax */
479177059Semax
480177059Semaxint32_t
481177059Semaxbnep_profile_create_security_description(
482177059Semax		uint8_t *buf, uint8_t const * const eob,
483177059Semax		uint8_t const *data, uint32_t datalen)
484177059Semax{
485177059Semax	uint16_t	security_descr;
486177059Semax
487177059Semax	if (datalen != 2 || buf + 3 > eob)
488177059Semax		return (-1);
489177059Semax
490177059Semax	memcpy(&security_descr, data, sizeof(security_descr));
491177059Semax
492177059Semax	SDP_PUT8(SDP_DATA_UINT16, buf);
493177059Semax	SDP_PUT16(security_descr, buf);
494177059Semax
495177059Semax        return (3);
496177059Semax}
497177059Semax
498