1/*
2 * profile.c
3 */
4
5/*-
6 * SPDX-License-Identifier: BSD-2-Clause
7 *
8 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $
33 */
34
35#include <sys/param.h>
36#include <sys/queue.h>
37#define L2CAP_SOCKET_CHECKED
38#include <bluetooth.h>
39#include <sdp.h>
40#include <string.h>
41#include "profile.h"
42#include "provider.h"
43
44/*
45 * Lookup profile descriptor
46 */
47
48profile_p
49profile_get_descriptor(uint16_t uuid)
50{
51  	extern	profile_t	audio_sink_profile_descriptor;
52	extern	profile_t	audio_source_profile_descriptor;
53	extern	profile_t	dun_profile_descriptor;
54	extern	profile_t	ftrn_profile_descriptor;
55	extern	profile_t	irmc_profile_descriptor;
56	extern	profile_t	irmc_command_profile_descriptor;
57	extern	profile_t	lan_profile_descriptor;
58	extern	profile_t	opush_profile_descriptor;
59	extern	profile_t	sp_profile_descriptor;
60	extern	profile_t	nap_profile_descriptor;
61	extern	profile_t	gn_profile_descriptor;
62	extern	profile_t	panu_profile_descriptor;
63
64	static const profile_p	profiles[] = {
65		&audio_sink_profile_descriptor,
66		&audio_source_profile_descriptor,
67		&dun_profile_descriptor,
68		&ftrn_profile_descriptor,
69		&irmc_profile_descriptor,
70		&irmc_command_profile_descriptor,
71		&lan_profile_descriptor,
72		&opush_profile_descriptor,
73		&sp_profile_descriptor,
74		&nap_profile_descriptor,
75		&gn_profile_descriptor,
76		&panu_profile_descriptor
77	};
78
79	int32_t			i;
80
81	for (i = 0; i < nitems(profiles); i++)
82		if (profiles[i]->uuid == uuid)
83			return (profiles[i]);
84
85	return (NULL);
86}
87
88/*
89 * Look attribute in the profile descripror
90 */
91
92profile_attr_create_p
93profile_get_attr(const profile_p profile, uint16_t attr)
94{
95	attr_p	ad = (attr_p) profile->attrs;
96
97	for (; ad->create != NULL; ad ++)
98		if (ad->attr == attr)
99			return (ad->create);
100
101	return (NULL);
102}
103
104/*
105 * uint32 value32 - 5 bytes
106 */
107
108int32_t
109common_profile_create_service_record_handle(
110	uint8_t *buf, uint8_t const * const eob,
111	uint8_t const *data, uint32_t datalen)
112{
113	if (buf + 5 > eob)
114		return (-1);
115
116	SDP_PUT8(SDP_DATA_UINT32, buf);
117	SDP_PUT32(((provider_p) data)->handle, buf);
118
119	return (5);
120}
121
122/*
123 * seq8 len8			- 2 bytes
124 *	uuid16 value16		- 3 bytes
125 *	[ uuid16 value ]
126 */
127
128int32_t
129common_profile_create_service_class_id_list(
130		uint8_t *buf, uint8_t const * const eob,
131		uint8_t const *data, uint32_t datalen)
132{
133	int32_t	len = 3 * (datalen >>= 1);
134
135	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
136		return (-1);
137
138	SDP_PUT8(SDP_DATA_SEQ8, buf);
139	SDP_PUT8(len, buf);
140
141	for (; datalen > 0; datalen --) {
142		SDP_PUT8(SDP_DATA_UUID16, buf);
143		SDP_PUT16(*((uint16_t const *)data), buf);
144		data += sizeof(uint16_t);
145	}
146
147	return (2 + len);
148}
149
150/*
151 * seq8 len8			- 2 bytes
152 *	seq 8 len8		- 2 bytes
153 *		uuid16 value16	- 3 bytes
154 *		uint16 value16	- 3 bytes
155 *	[ seq 8 len8
156 *		uuid16 value16
157 *		uint16 value16 ]
158 */
159
160int32_t
161common_profile_create_bluetooth_profile_descriptor_list(
162		uint8_t *buf, uint8_t const * const eob,
163		uint8_t const *data, uint32_t datalen)
164{
165	int32_t	len = 8 * (datalen >>= 2);
166
167	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
168		return (-1);
169
170	SDP_PUT8(SDP_DATA_SEQ8, buf);
171	SDP_PUT8(len, buf);
172
173	for (; datalen > 0; datalen --) {
174		SDP_PUT8(SDP_DATA_SEQ8, buf);
175		SDP_PUT8(6, buf);
176		SDP_PUT8(SDP_DATA_UUID16, buf);
177		SDP_PUT16(*((uint16_t const *)data), buf);
178		data += sizeof(uint16_t);
179		SDP_PUT8(SDP_DATA_UINT16, buf);
180		SDP_PUT16(*((uint16_t const *)data), buf);
181		data += sizeof(uint16_t);
182	}
183
184	return (2 + len);
185}
186
187/*
188 * seq8 len8		- 2 bytes
189 *	uint16 value16	- 3 bytes
190 *	uint16 value16	- 3 bytes
191 *	uint16 value16	- 3 bytes
192 */
193
194int32_t
195common_profile_create_language_base_attribute_id_list(
196		uint8_t *buf, uint8_t const * const eob,
197		uint8_t const *data, uint32_t datalen)
198{
199	if (buf + 11 > eob)
200		return (-1);
201
202	SDP_PUT8(SDP_DATA_SEQ8, buf);
203	SDP_PUT8(9, buf);
204
205	/*
206	 * Language code per ISO 639:1988. Use "en".
207	 */
208
209	SDP_PUT8(SDP_DATA_UINT16, buf);
210	SDP_PUT16(((0x65 << 8) | 0x6e), buf);
211
212	/*
213	 * Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106
214	 * (http://www.iana.org/assignments/character-sets)
215	 */
216
217	SDP_PUT8(SDP_DATA_UINT16, buf);
218	SDP_PUT16(106, buf);
219
220	/*
221	 * Offset (Primary Language Base is 0x100)
222	 */
223
224	SDP_PUT8(SDP_DATA_UINT16, buf);
225	SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf);
226
227	return (11);
228}
229
230/*
231 * Common provider name is "FreeBSD"
232 */
233
234int32_t
235common_profile_create_service_provider_name(
236		uint8_t *buf, uint8_t const * const eob,
237		uint8_t const *data, uint32_t datalen)
238{
239	char	provider_name[] = "FreeBSD";
240
241	return (common_profile_create_string8(buf, eob,
242			(uint8_t const *) provider_name,
243			strlen(provider_name)));
244}
245
246/*
247 * str8 len8 string
248 */
249
250int32_t
251common_profile_create_string8(
252		uint8_t *buf, uint8_t const * const eob,
253		uint8_t const *data, uint32_t datalen)
254{
255	if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob)
256		return (-1);
257
258	SDP_PUT8(SDP_DATA_STR8, buf);
259	SDP_PUT8(datalen, buf);
260	memcpy(buf, data, datalen);
261
262	return (2 + datalen);
263}
264
265/*
266 * Service Availability
267 */
268
269int32_t
270common_profile_create_service_availability(
271		uint8_t *buf, uint8_t const * const eob,
272		uint8_t const *data, uint32_t datalen)
273{
274	if (datalen != 1 || buf + 2 > eob)
275		return (-1);
276
277	SDP_PUT8(SDP_DATA_UINT8, buf);
278	SDP_PUT8(data[0], buf);
279
280	return (2);
281}
282
283/*
284 * seq8 len8			- 2 bytes
285 *	seq8 len8		- 2 bytes
286 *		uuid16 value16	- 3 bytes
287 *	seq8 len8		- 2 bytes
288 *		uuid16 value16	- 3 bytes
289 *		uint8 value8	- 2 bytes
290 */
291
292int32_t
293rfcomm_profile_create_protocol_descriptor_list(
294		uint8_t *buf, uint8_t const * const eob,
295		uint8_t const *data, uint32_t datalen)
296{
297	if (datalen != 1 || buf + 14 > eob)
298		return (-1);
299
300	SDP_PUT8(SDP_DATA_SEQ8, buf);
301	SDP_PUT8(12, buf);
302
303	SDP_PUT8(SDP_DATA_SEQ8, buf);
304	SDP_PUT8(3, buf);
305	SDP_PUT8(SDP_DATA_UUID16, buf);
306	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
307
308	SDP_PUT8(SDP_DATA_SEQ8, buf);
309	SDP_PUT8(5, buf);
310	SDP_PUT8(SDP_DATA_UUID16, buf);
311	SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
312	SDP_PUT8(SDP_DATA_UINT8, buf);
313	SDP_PUT8(*data, buf);
314
315	return (14);
316}
317
318/*
319 * seq8 len8			- 2 bytes
320 *	seq8 len8		- 2 bytes
321 *		uuid16 value16	- 3 bytes
322 *	seq8 len8		- 2 bytes
323 *		uuid16 value16	- 3 bytes
324 *		uint8 value8	- 2 bytes
325 *	seq8 len8		- 2 bytes
326 *		uuid16 value16	- 3 bytes
327 */
328
329int32_t
330obex_profile_create_protocol_descriptor_list(
331		uint8_t *buf, uint8_t const * const eob,
332		uint8_t const *data, uint32_t datalen)
333{
334	if (datalen != 1 || buf + 19 > eob)
335		return (-1);
336
337	SDP_PUT8(SDP_DATA_SEQ8, buf);
338	SDP_PUT8(17, buf);
339
340	SDP_PUT8(SDP_DATA_SEQ8, buf);
341	SDP_PUT8(3, buf);
342	SDP_PUT8(SDP_DATA_UUID16, buf);
343	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
344
345	SDP_PUT8(SDP_DATA_SEQ8, buf);
346	SDP_PUT8(5, buf);
347	SDP_PUT8(SDP_DATA_UUID16, buf);
348	SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);
349	SDP_PUT8(SDP_DATA_UINT8, buf);
350	SDP_PUT8(*data, buf);
351
352	SDP_PUT8(SDP_DATA_SEQ8, buf);
353	SDP_PUT8(3, buf);
354	SDP_PUT8(SDP_DATA_UUID16, buf);
355	SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf);
356
357	return (19);
358}
359
360/*
361 * seq8 len8
362 *	uint8 value8	- bytes
363 *	[ uint8 value 8 ]
364 */
365
366int32_t
367obex_profile_create_supported_formats_list(
368		uint8_t *buf, uint8_t const * const eob,
369		uint8_t const *data, uint32_t datalen)
370{
371	int32_t	len = 2 * datalen;
372
373	if (len <= 0 || len > 0xff || buf + 2 + len > eob)
374		return (-1);
375
376	SDP_PUT8(SDP_DATA_SEQ8, buf);
377	SDP_PUT8(len, buf);
378
379	for (; datalen > 0; datalen --) {
380		SDP_PUT8(SDP_DATA_UINT8, buf);
381		SDP_PUT8(*data++, buf);
382	}
383
384	return (2 + len);
385}
386
387/*
388 * do not check anything
389 */
390
391int32_t
392common_profile_always_valid(uint8_t const *data, uint32_t datalen)
393{
394	return (1);
395}
396
397/*
398 * verify server channel number (the first byte in the data)
399 */
400
401int32_t
402common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen)
403{
404	if (data[0] < 1 || data[0] > 30)
405		return (0);
406
407	return (1);
408}
409
410/*
411 * verify server channel number and supported_formats_size
412 * sdp_opush_profile and sdp_irmc_profile
413 */
414
415int32_t
416obex_profile_data_valid(uint8_t const *data, uint32_t datalen)
417{
418	sdp_opush_profile_p	opush = (sdp_opush_profile_p) data;
419
420	if (opush->server_channel < 1 ||
421	    opush->server_channel > 30 ||
422	    opush->supported_formats_size == 0 ||
423	    opush->supported_formats_size > sizeof(opush->supported_formats))
424		return (0);
425
426	return (1);
427}
428
429/*
430 * BNEP protocol descriptor
431 */
432
433int32_t
434bnep_profile_create_protocol_descriptor_list(
435		uint8_t *buf, uint8_t const * const eob,
436		uint8_t const *data, uint32_t datalen)
437{
438	/* supported protocol types */
439	uint16_t	 ptype[] = {
440		0x0800,	/* IPv4 */
441		0x0806,	/* ARP */
442#ifdef INET6
443		0x86dd,	/* IPv6 */
444#endif
445	};
446
447	uint16_t	 i, psm, version = 0x0100,
448			 nptypes = nitems(ptype),
449			 nptypes_size = nptypes * 3;
450
451	if (datalen != 2 || 18 + nptypes_size > 255 ||
452	    buf + 20 + nptypes_size > eob)
453		return (-1);
454
455	memcpy(&psm, data, sizeof(psm));
456
457	SDP_PUT8(SDP_DATA_SEQ8, buf);
458	SDP_PUT8(18 + nptypes_size, buf);
459
460	SDP_PUT8(SDP_DATA_SEQ8, buf);
461	SDP_PUT8(6, buf);
462	SDP_PUT8(SDP_DATA_UUID16, buf);
463	SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);
464	SDP_PUT8(SDP_DATA_UINT16, buf);
465	SDP_PUT16(psm, buf);
466
467	SDP_PUT8(SDP_DATA_SEQ8, buf);
468	SDP_PUT8(8 + nptypes_size, buf);
469	SDP_PUT8(SDP_DATA_UUID16, buf);
470	SDP_PUT16(SDP_UUID_PROTOCOL_BNEP, buf);
471	SDP_PUT8(SDP_DATA_UINT16, buf);
472	SDP_PUT16(version, buf);
473	SDP_PUT8(SDP_DATA_SEQ8, buf);
474	SDP_PUT8(nptypes_size, buf);
475	for (i = 0; i < nptypes; i ++) {
476		SDP_PUT8(SDP_DATA_UINT16, buf);
477		SDP_PUT16(ptype[i], buf);
478	}
479
480	return (20 + nptypes_size);
481}
482
483/*
484 * BNEP security description
485 */
486
487int32_t
488bnep_profile_create_security_description(
489		uint8_t *buf, uint8_t const * const eob,
490		uint8_t const *data, uint32_t datalen)
491{
492	uint16_t	security_descr;
493
494	if (datalen != 2 || buf + 3 > eob)
495		return (-1);
496
497	memcpy(&security_descr, data, sizeof(security_descr));
498
499	SDP_PUT8(SDP_DATA_UINT16, buf);
500	SDP_PUT16(security_descr, buf);
501
502        return (3);
503}
504
505