xref: /freebsd/usr.sbin/bluetooth/sdpd/profile.c (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
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 
48 profile_p
49 profile_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 
92 profile_attr_create_p
93 profile_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 
108 int32_t
109 common_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 
128 int32_t
129 common_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 
160 int32_t
161 common_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 
194 int32_t
195 common_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 
234 int32_t
235 common_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 
250 int32_t
251 common_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 
269 int32_t
270 common_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 
292 int32_t
293 rfcomm_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 
329 int32_t
330 obex_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 
366 int32_t
367 obex_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 
391 int32_t
392 common_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 
401 int32_t
402 common_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 
415 int32_t
416 obex_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 
433 int32_t
434 bnep_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 
487 int32_t
488 bnep_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