rfcomm_sdp.c revision 128077
1184054Slulf/*
2186743Slulf * rfcomm_sdp.c
3184054Slulf *
4184054Slulf * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5184054Slulf * All rights reserved.
6184054Slulf *
7184054Slulf * Redistribution and use in source and binary forms, with or without
8184054Slulf * modification, are permitted provided that the following conditions
9184054Slulf * are met:
10184054Slulf * 1. Redistributions of source code must retain the above copyright
11184054Slulf *    notice, this list of conditions and the following disclaimer.
12184054Slulf * 2. Redistributions in binary form must reproduce the above copyright
13184054Slulf *    notice, this list of conditions and the following disclaimer in the
14184054Slulf *    documentation and/or other materials provided with the distribution.
15184054Slulf *
16184054Slulf * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17184054Slulf * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18184054Slulf * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19184054Slulf * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20184054Slulf * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21184054Slulf * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22184054Slulf * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23184054Slulf * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24184054Slulf * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25184054Slulf * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26184054Slulf * SUCH DAMAGE.
27184054Slulf *
28184054Slulf * $Id: rfcomm_sdp.c,v 1.1 2003/09/07 18:15:55 max Exp $
29184054Slulf * $FreeBSD: head/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c 128077 2004-04-09 23:26:16Z emax $
30185134Slulf */
31185134Slulf
32184054Slulf#include <bluetooth.h>
33184054Slulf#include <errno.h>
34184054Slulf#include <sdp.h>
35185134Slulf#include <stdio.h>
36184054Slulf
37185134Slulf#undef	PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE
38184054Slulf#define	PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE	256
39185134Slulf
40185134Slulf#undef	PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE
41184054Slulf#define	PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE	12
42184054Slulf
43184054Slulfstatic int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end,
44184054Slulf					int *channel, int *error);
45185134Slulf
46185134Slulf/*
47184054Slulf * Lookup RFCOMM channel number in the Protocol Descriptor List
48184054Slulf */
49184054Slulf
50184054Slulf#undef	rfcomm_channel_lookup_exit
51184054Slulf#define	rfcomm_channel_lookup_exit(e) { \
52184054Slulf	if (error != NULL) \
53184054Slulf		*error = (e); \
54184054Slulf	if (ss != NULL) { \
55184054Slulf		sdp_close(ss); \
56184054Slulf		ss = NULL; \
57184054Slulf	} \
58184054Slulf	return (((e) == 0)? 0 : -1); \
59184054Slulf}
60184054Slulf
61184054Slulfint
62184054Slulfrfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
63184054Slulf			int service, int *channel, int *error)
64184054Slulf{
65184054Slulf	uint8_t		 buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE];
66184054Slulf	void		*ss    = NULL;
67184054Slulf	uint16_t	 serv  = (uint16_t) service;
68184054Slulf	uint32_t	 attr  = SDP_ATTR_RANGE(
69184054Slulf					SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
70184054Slulf					SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
71184054Slulf	sdp_attr_t	 proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer };
72184054Slulf	uint32_t	 type, len;
73184054Slulf
74184054Slulf	if (local == NULL)
75184054Slulf		local = NG_HCI_BDADDR_ANY;
76184054Slulf	if (remote == NULL || channel == NULL)
77184054Slulf		rfcomm_channel_lookup_exit(EINVAL);
78184054Slulf
79184054Slulf	if ((ss = sdp_open(local, remote)) == NULL)
80184054Slulf		rfcomm_channel_lookup_exit(ENOMEM);
81184054Slulf	if (sdp_error(ss) != 0)
82184054Slulf		rfcomm_channel_lookup_exit(sdp_error(ss));
83184054Slulf
84184054Slulf	if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0)
85184054Slulf		rfcomm_channel_lookup_exit(sdp_error(ss));
86184054Slulf	if (proto.flags != SDP_ATTR_OK)
87184054Slulf		rfcomm_channel_lookup_exit(ENOATTR);
88184054Slulf
89184054Slulf	sdp_close(ss);
90184054Slulf	ss = NULL;
91184054Slulf
92186727Slulf	/*
93184054Slulf	 * If it is possible for more than one kind of protocol stack to be
94184054Slulf	 * used to gain access to the service, the ProtocolDescriptorList
95184054Slulf	 * takes the form of a data element alternative. We always use the
96184054Slulf	 * first protocol stack.
97184054Slulf	 *
98184054Slulf	 * A minimal Protocol Descriptor List for RFCOMM based service would
99184054Slulf	 * look like
100184054Slulf	 *
101184054Slulf	 * seq8 len8			- 2 bytes
102184054Slulf	 *	seq8 len8		- 2 bytes
103186727Slulf	 *		uuid16 value16	- 3 bytes	L2CAP
104184054Slulf	 *	seq8 len8		- 2 bytes
105184054Slulf	 *		uuid16 value16	- 3 bytes	RFCOMM
106184054Slulf	 *		uint8  value8	- 2 bytes	RFCOMM param #1
107184054Slulf	 *				=========
108184054Slulf	 *				 14 bytes
109184054Slulf	 *
110184054Slulf	 * Lets not count first [seq8 len8] wrapper, so the minimal size of
111184054Slulf	 * the Protocol Descriptor List (the data we are actually interested
112184054Slulf	 * in) for RFCOMM based service would be 12 bytes.
113184054Slulf	 */
114184054Slulf
115184054Slulf	if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)
116184054Slulf		rfcomm_channel_lookup_exit(EINVAL);
117184054Slulf
118184054Slulf	SDP_GET8(type, proto.value);
119184054Slulf
120184054Slulf	if (type == SDP_DATA_ALT8) {
121184054Slulf		SDP_GET8(len, proto.value);
122186700Slulf	} else if (type == SDP_DATA_ALT16) {
123184054Slulf		SDP_GET16(len, proto.value);
124184054Slulf	} else if (type == SDP_DATA_ALT32) {
125184054Slulf		SDP_GET32(len, proto.value);
126184054Slulf	} else
127184054Slulf		len = 0;
128184054Slulf
129184054Slulf	if (len > 0)
130184054Slulf		SDP_GET8(type, proto.value);
131184054Slulf
132184054Slulf	switch (type) {
133184054Slulf	case SDP_DATA_SEQ8:
134184054Slulf		SDP_GET8(len, proto.value);
135184054Slulf		break;
136184054Slulf
137184054Slulf	case SDP_DATA_SEQ16:
138184054Slulf		SDP_GET16(len, proto.value);
139184054Slulf		break;
140184054Slulf
141184054Slulf	case SDP_DATA_SEQ32:
142184054Slulf		SDP_GET32(len, proto.value);
143190422Slulf		break;
144186727Slulf
145184054Slulf	default:
146184054Slulf		rfcomm_channel_lookup_exit(ENOATTR);
147184054Slulf		/* NOT REACHED */
148184054Slulf	}
149184054Slulf
150184054Slulf	if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)
151184054Slulf		rfcomm_channel_lookup_exit(EINVAL);
152184054Slulf
153184054Slulf	return (rfcomm_proto_list_parse(proto.value,
154184054Slulf					buffer + proto.vlen, channel, error));
155184054Slulf}
156186700Slulf
157184054Slulf/*
158184054Slulf * Parse protocol descriptor list
159184054Slulf *
160184054Slulf * The ProtocolDescriptorList attribute describes one or more protocol
161184054Slulf * stacks that may be used to gain access to the service described by
162184054Slulf * the service record. If the ProtocolDescriptorList describes a single
163184054Slulf * stack, it takes the form of a data element sequence in which each
164184054Slulf * element of the sequence is a protocol descriptor.
165184054Slulf */
166184054Slulf
167184054Slulf#undef	rfcomm_proto_list_parse_exit
168185134Slulf#define	rfcomm_proto_list_parse_exit(e) { \
169184054Slulf	if (error != NULL) \
170184054Slulf		*error = (e); \
171185134Slulf	return (((e) == 0)? 0 : -1); \
172184054Slulf}
173184054Slulf
174184054Slulfstatic int
175184054Slulfrfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end,
176184054Slulf			int *channel, int *error)
177184054Slulf{
178186700Slulf	int	type, len, value;
179184054Slulf
180185134Slulf	while (start < end) {
181184054Slulf
182184054Slulf		/*
183184054Slulf		 * Parse protocol descriptor
184184054Slulf		 *
185184054Slulf		 * A protocol descriptor identifies a communications protocol
186184054Slulf		 * and provides protocol specific parameters. A protocol
187184054Slulf		 * descriptor is represented as a data element sequence. The
188184054Slulf		 * first data element in the sequence must be the UUID that
189184054Slulf		 * identifies the protocol. Additional data elements optionally
190184054Slulf		 * provide protocol specific information, such as the L2CAP
191184054Slulf		 * protocol/service multiplexer (PSM) and the RFCOMM server
192184054Slulf		 * channel number (CN).
193184054Slulf		 */
194185134Slulf
195184054Slulf		/* We must have at least one byte (type) */
196184054Slulf		if (end - start < 1)
197184054Slulf			rfcomm_proto_list_parse_exit(EINVAL)
198184054Slulf
199184054Slulf		SDP_GET8(type, start);
200184054Slulf		switch (type) {
201184054Slulf		case SDP_DATA_SEQ8:
202184054Slulf			SDP_GET8(len, start);
203184054Slulf			break;
204184054Slulf
205184054Slulf		case SDP_DATA_SEQ16:
206184054Slulf			SDP_GET16(len, start);
207184054Slulf			break;
208185592Slulf
209184054Slulf		case SDP_DATA_SEQ32:
210186700Slulf			SDP_GET32(len, start);
211184054Slulf			break;
212184054Slulf
213184054Slulf		default:
214184054Slulf			rfcomm_proto_list_parse_exit(ENOATTR)
215184054Slulf			/* NOT REACHED */
216184054Slulf		}
217184054Slulf
218186700Slulf		/* We must have at least 3 bytes (type + UUID16) */
219184054Slulf		if (end - start < 3)
220184054Slulf			rfcomm_proto_list_parse_exit(EINVAL);
221184054Slulf
222184054Slulf		/* Get protocol UUID */
223184054Slulf		SDP_GET8(type, start); len -= sizeof(uint8_t);
224184054Slulf		switch (type) {
225184054Slulf		case SDP_DATA_UUID16:
226184054Slulf			SDP_GET16(value, start); len -= sizeof(uint16_t);
227184054Slulf			if (value != SDP_UUID_PROTOCOL_RFCOMM)
228184054Slulf				goto next_protocol;
229184054Slulf			break;
230184054Slulf
231184054Slulf		case SDP_DATA_UUID32:  /* XXX FIXME can we have 32-bit UUID */
232184054Slulf		case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
233184054Slulf		default:
234184054Slulf			rfcomm_proto_list_parse_exit(ENOATTR);
235184054Slulf			/* NOT REACHED */
236184054Slulf		}
237185811Slulf
238184054Slulf		/*
239184054Slulf		 * First protocol specific parameter for RFCOMM procotol must
240184054Slulf		 * be uint8 that represents RFCOMM channel number. So we must
241184054Slulf		 * have at least two bytes.
242184054Slulf		 */
243184054Slulf
244184054Slulf		if (end - start < 2)
245184054Slulf			rfcomm_proto_list_parse_exit(EINVAL);
246184054Slulf
247184054Slulf		SDP_GET8(type, start);
248184054Slulf		if (type != SDP_DATA_UINT8)
249184054Slulf			rfcomm_proto_list_parse_exit(ENOATTR);
250184054Slulf
251184054Slulf		SDP_GET8(*channel, start);
252184054Slulf
253184054Slulf		rfcomm_proto_list_parse_exit(0);
254184054Slulf		/* NOT REACHED */
255184054Slulfnext_protocol:
256184054Slulf		start += len;
257184054Slulf	}
258184054Slulf
259184054Slulf	/*
260184054Slulf	 * If we got here then it means we could not find RFCOMM protocol
261184054Slulf	 * descriptor, but the reply format was actually valid.
262184054Slulf	 */
263184054Slulf
264184054Slulf	rfcomm_proto_list_parse_exit(ENOATTR);
265184054Slulf}
266184054Slulf
267184054Slulf