1*86d7f5d3SJohn Marino /* $NetBSD: rfcomm_sdp.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */
2*86d7f5d3SJohn Marino /* $DragonFly: src/usr.bin/rfcomm_sppd/rfcomm_sdp.c,v 1.1 2008/02/08 14:06:25 hasso Exp $ */
3*86d7f5d3SJohn Marino
4*86d7f5d3SJohn Marino /*-
5*86d7f5d3SJohn Marino * Copyright (c) 2006 Itronix Inc.
6*86d7f5d3SJohn Marino * All rights reserved.
7*86d7f5d3SJohn Marino *
8*86d7f5d3SJohn Marino * Redistribution and use in source and binary forms, with or without
9*86d7f5d3SJohn Marino * modification, are permitted provided that the following conditions
10*86d7f5d3SJohn Marino * are met:
11*86d7f5d3SJohn Marino * 1. Redistributions of source code must retain the above copyright
12*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer.
13*86d7f5d3SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
14*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer in the
15*86d7f5d3SJohn Marino * documentation and/or other materials provided with the distribution.
16*86d7f5d3SJohn Marino * 3. The name of Itronix Inc. may not be used to endorse
17*86d7f5d3SJohn Marino * or promote products derived from this software without specific
18*86d7f5d3SJohn Marino * prior written permission.
19*86d7f5d3SJohn Marino *
20*86d7f5d3SJohn Marino * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21*86d7f5d3SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22*86d7f5d3SJohn Marino * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23*86d7f5d3SJohn Marino * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24*86d7f5d3SJohn Marino * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25*86d7f5d3SJohn Marino * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26*86d7f5d3SJohn Marino * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27*86d7f5d3SJohn Marino * ON ANY THEORY OF LIABILITY, WHETHER IN
28*86d7f5d3SJohn Marino * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*86d7f5d3SJohn Marino * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30*86d7f5d3SJohn Marino * POSSIBILITY OF SUCH DAMAGE.
31*86d7f5d3SJohn Marino */
32*86d7f5d3SJohn Marino /*
33*86d7f5d3SJohn Marino * rfcomm_sdp.c
34*86d7f5d3SJohn Marino *
35*86d7f5d3SJohn Marino * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
36*86d7f5d3SJohn Marino * All rights reserved.
37*86d7f5d3SJohn Marino *
38*86d7f5d3SJohn Marino * Redistribution and use in source and binary forms, with or without
39*86d7f5d3SJohn Marino * modification, are permitted provided that the following conditions
40*86d7f5d3SJohn Marino * are met:
41*86d7f5d3SJohn Marino * 1. Redistributions of source code must retain the above copyright
42*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer.
43*86d7f5d3SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
44*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer in the
45*86d7f5d3SJohn Marino * documentation and/or other materials provided with the distribution.
46*86d7f5d3SJohn Marino *
47*86d7f5d3SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
48*86d7f5d3SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49*86d7f5d3SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50*86d7f5d3SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
51*86d7f5d3SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52*86d7f5d3SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53*86d7f5d3SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54*86d7f5d3SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55*86d7f5d3SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56*86d7f5d3SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57*86d7f5d3SJohn Marino * SUCH DAMAGE.
58*86d7f5d3SJohn Marino *
59*86d7f5d3SJohn Marino * $Id: rfcomm_sdp.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $
60*86d7f5d3SJohn Marino * $FreeBSD: src/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c,v 1.2 2004/04/09 23:26:16 emax Exp $
61*86d7f5d3SJohn Marino */
62*86d7f5d3SJohn Marino
63*86d7f5d3SJohn Marino #include <bluetooth.h>
64*86d7f5d3SJohn Marino #include <errno.h>
65*86d7f5d3SJohn Marino #include <sdp.h>
66*86d7f5d3SJohn Marino #include <stdio.h>
67*86d7f5d3SJohn Marino
68*86d7f5d3SJohn Marino #include "rfcomm_sdp.h"
69*86d7f5d3SJohn Marino
70*86d7f5d3SJohn Marino #undef PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE
71*86d7f5d3SJohn Marino #define PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 256
72*86d7f5d3SJohn Marino
73*86d7f5d3SJohn Marino #undef PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE
74*86d7f5d3SJohn Marino #define PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 12
75*86d7f5d3SJohn Marino
76*86d7f5d3SJohn Marino static int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end,
77*86d7f5d3SJohn Marino uint8_t *channel, int *error);
78*86d7f5d3SJohn Marino
79*86d7f5d3SJohn Marino /*
80*86d7f5d3SJohn Marino * Lookup RFCOMM channel number in the Protocol Descriptor List
81*86d7f5d3SJohn Marino */
82*86d7f5d3SJohn Marino
83*86d7f5d3SJohn Marino #undef rfcomm_channel_lookup_exit
84*86d7f5d3SJohn Marino #define rfcomm_channel_lookup_exit(e) { \
85*86d7f5d3SJohn Marino if (error != NULL) \
86*86d7f5d3SJohn Marino *error = (e); \
87*86d7f5d3SJohn Marino if (ss != NULL) { \
88*86d7f5d3SJohn Marino sdp_close(ss); \
89*86d7f5d3SJohn Marino ss = NULL; \
90*86d7f5d3SJohn Marino } \
91*86d7f5d3SJohn Marino return (((e) == 0)? 0 : -1); \
92*86d7f5d3SJohn Marino }
93*86d7f5d3SJohn Marino
94*86d7f5d3SJohn Marino int
rfcomm_channel_lookup(bdaddr_t const * local,bdaddr_t const * remote,int service,uint8_t * channel,int * error)95*86d7f5d3SJohn Marino rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,
96*86d7f5d3SJohn Marino int service, uint8_t *channel, int *error)
97*86d7f5d3SJohn Marino {
98*86d7f5d3SJohn Marino uint8_t buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE];
99*86d7f5d3SJohn Marino void *ss = NULL;
100*86d7f5d3SJohn Marino uint16_t serv = (uint16_t) service;
101*86d7f5d3SJohn Marino uint32_t attr = SDP_ATTR_RANGE(
102*86d7f5d3SJohn Marino SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
103*86d7f5d3SJohn Marino SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
104*86d7f5d3SJohn Marino sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer };
105*86d7f5d3SJohn Marino uint32_t type, len;
106*86d7f5d3SJohn Marino
107*86d7f5d3SJohn Marino if (local == NULL)
108*86d7f5d3SJohn Marino local = BDADDR_ANY;
109*86d7f5d3SJohn Marino if (remote == NULL || channel == NULL)
110*86d7f5d3SJohn Marino rfcomm_channel_lookup_exit(EINVAL);
111*86d7f5d3SJohn Marino
112*86d7f5d3SJohn Marino if ((ss = sdp_open(local, remote)) == NULL)
113*86d7f5d3SJohn Marino rfcomm_channel_lookup_exit(ENOMEM);
114*86d7f5d3SJohn Marino if (sdp_error(ss) != 0)
115*86d7f5d3SJohn Marino rfcomm_channel_lookup_exit(sdp_error(ss));
116*86d7f5d3SJohn Marino
117*86d7f5d3SJohn Marino if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0)
118*86d7f5d3SJohn Marino rfcomm_channel_lookup_exit(sdp_error(ss));
119*86d7f5d3SJohn Marino if (proto.flags != SDP_ATTR_OK)
120*86d7f5d3SJohn Marino rfcomm_channel_lookup_exit(ENOATTR);
121*86d7f5d3SJohn Marino
122*86d7f5d3SJohn Marino sdp_close(ss);
123*86d7f5d3SJohn Marino ss = NULL;
124*86d7f5d3SJohn Marino
125*86d7f5d3SJohn Marino /*
126*86d7f5d3SJohn Marino * If it is possible for more than one kind of protocol stack to be
127*86d7f5d3SJohn Marino * used to gain access to the service, the ProtocolDescriptorList
128*86d7f5d3SJohn Marino * takes the form of a data element alternative. We always use the
129*86d7f5d3SJohn Marino * first protocol stack.
130*86d7f5d3SJohn Marino *
131*86d7f5d3SJohn Marino * A minimal Protocol Descriptor List for RFCOMM based service would
132*86d7f5d3SJohn Marino * look like
133*86d7f5d3SJohn Marino *
134*86d7f5d3SJohn Marino * seq8 len8 - 2 bytes
135*86d7f5d3SJohn Marino * seq8 len8 - 2 bytes
136*86d7f5d3SJohn Marino * uuid16 value16 - 3 bytes L2CAP
137*86d7f5d3SJohn Marino * seq8 len8 - 2 bytes
138*86d7f5d3SJohn Marino * uuid16 value16 - 3 bytes RFCOMM
139*86d7f5d3SJohn Marino * uint8 value8 - 2 bytes RFCOMM param #1
140*86d7f5d3SJohn Marino * =========
141*86d7f5d3SJohn Marino * 14 bytes
142*86d7f5d3SJohn Marino *
143*86d7f5d3SJohn Marino * Lets not count first [seq8 len8] wrapper, so the minimal size of
144*86d7f5d3SJohn Marino * the Protocol Descriptor List (the data we are actually interested
145*86d7f5d3SJohn Marino * in) for RFCOMM based service would be 12 bytes.
146*86d7f5d3SJohn Marino */
147*86d7f5d3SJohn Marino
148*86d7f5d3SJohn Marino if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)
149*86d7f5d3SJohn Marino rfcomm_channel_lookup_exit(EINVAL);
150*86d7f5d3SJohn Marino
151*86d7f5d3SJohn Marino SDP_GET8(type, proto.value);
152*86d7f5d3SJohn Marino
153*86d7f5d3SJohn Marino if (type == SDP_DATA_ALT8) {
154*86d7f5d3SJohn Marino SDP_GET8(len, proto.value);
155*86d7f5d3SJohn Marino } else if (type == SDP_DATA_ALT16) {
156*86d7f5d3SJohn Marino SDP_GET16(len, proto.value);
157*86d7f5d3SJohn Marino } else if (type == SDP_DATA_ALT32) {
158*86d7f5d3SJohn Marino SDP_GET32(len, proto.value);
159*86d7f5d3SJohn Marino } else
160*86d7f5d3SJohn Marino len = 0;
161*86d7f5d3SJohn Marino
162*86d7f5d3SJohn Marino if (len > 0)
163*86d7f5d3SJohn Marino SDP_GET8(type, proto.value);
164*86d7f5d3SJohn Marino
165*86d7f5d3SJohn Marino switch (type) {
166*86d7f5d3SJohn Marino case SDP_DATA_SEQ8:
167*86d7f5d3SJohn Marino SDP_GET8(len, proto.value);
168*86d7f5d3SJohn Marino break;
169*86d7f5d3SJohn Marino
170*86d7f5d3SJohn Marino case SDP_DATA_SEQ16:
171*86d7f5d3SJohn Marino SDP_GET16(len, proto.value);
172*86d7f5d3SJohn Marino break;
173*86d7f5d3SJohn Marino
174*86d7f5d3SJohn Marino case SDP_DATA_SEQ32:
175*86d7f5d3SJohn Marino SDP_GET32(len, proto.value);
176*86d7f5d3SJohn Marino break;
177*86d7f5d3SJohn Marino
178*86d7f5d3SJohn Marino default:
179*86d7f5d3SJohn Marino rfcomm_channel_lookup_exit(ENOATTR);
180*86d7f5d3SJohn Marino /* NOT REACHED */
181*86d7f5d3SJohn Marino }
182*86d7f5d3SJohn Marino
183*86d7f5d3SJohn Marino if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)
184*86d7f5d3SJohn Marino rfcomm_channel_lookup_exit(EINVAL);
185*86d7f5d3SJohn Marino
186*86d7f5d3SJohn Marino return (rfcomm_proto_list_parse(proto.value,
187*86d7f5d3SJohn Marino buffer + proto.vlen, channel, error));
188*86d7f5d3SJohn Marino }
189*86d7f5d3SJohn Marino
190*86d7f5d3SJohn Marino /*
191*86d7f5d3SJohn Marino * Parse protocol descriptor list
192*86d7f5d3SJohn Marino *
193*86d7f5d3SJohn Marino * The ProtocolDescriptorList attribute describes one or more protocol
194*86d7f5d3SJohn Marino * stacks that may be used to gain access to the service described by
195*86d7f5d3SJohn Marino * the service record. If the ProtocolDescriptorList describes a single
196*86d7f5d3SJohn Marino * stack, it takes the form of a data element sequence in which each
197*86d7f5d3SJohn Marino * element of the sequence is a protocol descriptor.
198*86d7f5d3SJohn Marino */
199*86d7f5d3SJohn Marino
200*86d7f5d3SJohn Marino #undef rfcomm_proto_list_parse_exit
201*86d7f5d3SJohn Marino #define rfcomm_proto_list_parse_exit(e) { \
202*86d7f5d3SJohn Marino if (error != NULL) \
203*86d7f5d3SJohn Marino *error = (e); \
204*86d7f5d3SJohn Marino return (((e) == 0)? 0 : -1); \
205*86d7f5d3SJohn Marino }
206*86d7f5d3SJohn Marino
207*86d7f5d3SJohn Marino static int
rfcomm_proto_list_parse(uint8_t const * start,uint8_t const * end,uint8_t * channel,int * error)208*86d7f5d3SJohn Marino rfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end,
209*86d7f5d3SJohn Marino uint8_t *channel, int *error)
210*86d7f5d3SJohn Marino {
211*86d7f5d3SJohn Marino int type, len, value;
212*86d7f5d3SJohn Marino
213*86d7f5d3SJohn Marino while (start < end) {
214*86d7f5d3SJohn Marino
215*86d7f5d3SJohn Marino /*
216*86d7f5d3SJohn Marino * Parse protocol descriptor
217*86d7f5d3SJohn Marino *
218*86d7f5d3SJohn Marino * A protocol descriptor identifies a communications protocol
219*86d7f5d3SJohn Marino * and provides protocol specific parameters. A protocol
220*86d7f5d3SJohn Marino * descriptor is represented as a data element sequence. The
221*86d7f5d3SJohn Marino * first data element in the sequence must be the UUID that
222*86d7f5d3SJohn Marino * identifies the protocol. Additional data elements optionally
223*86d7f5d3SJohn Marino * provide protocol specific information, such as the L2CAP
224*86d7f5d3SJohn Marino * protocol/service multiplexer (PSM) and the RFCOMM server
225*86d7f5d3SJohn Marino * channel number (CN).
226*86d7f5d3SJohn Marino */
227*86d7f5d3SJohn Marino
228*86d7f5d3SJohn Marino /* We must have at least one byte (type) */
229*86d7f5d3SJohn Marino if (end - start < 1)
230*86d7f5d3SJohn Marino rfcomm_proto_list_parse_exit(EINVAL)
231*86d7f5d3SJohn Marino
232*86d7f5d3SJohn Marino SDP_GET8(type, start);
233*86d7f5d3SJohn Marino switch (type) {
234*86d7f5d3SJohn Marino case SDP_DATA_SEQ8:
235*86d7f5d3SJohn Marino SDP_GET8(len, start);
236*86d7f5d3SJohn Marino break;
237*86d7f5d3SJohn Marino
238*86d7f5d3SJohn Marino case SDP_DATA_SEQ16:
239*86d7f5d3SJohn Marino SDP_GET16(len, start);
240*86d7f5d3SJohn Marino break;
241*86d7f5d3SJohn Marino
242*86d7f5d3SJohn Marino case SDP_DATA_SEQ32:
243*86d7f5d3SJohn Marino SDP_GET32(len, start);
244*86d7f5d3SJohn Marino break;
245*86d7f5d3SJohn Marino
246*86d7f5d3SJohn Marino default:
247*86d7f5d3SJohn Marino rfcomm_proto_list_parse_exit(ENOATTR)
248*86d7f5d3SJohn Marino /* NOT REACHED */
249*86d7f5d3SJohn Marino }
250*86d7f5d3SJohn Marino
251*86d7f5d3SJohn Marino /* We must have at least 3 bytes (type + UUID16) */
252*86d7f5d3SJohn Marino if (end - start < 3)
253*86d7f5d3SJohn Marino rfcomm_proto_list_parse_exit(EINVAL);
254*86d7f5d3SJohn Marino
255*86d7f5d3SJohn Marino /* Get protocol UUID */
256*86d7f5d3SJohn Marino SDP_GET8(type, start); len -= sizeof(uint8_t);
257*86d7f5d3SJohn Marino switch (type) {
258*86d7f5d3SJohn Marino case SDP_DATA_UUID16:
259*86d7f5d3SJohn Marino SDP_GET16(value, start); len -= sizeof(uint16_t);
260*86d7f5d3SJohn Marino if (value != SDP_UUID_PROTOCOL_RFCOMM)
261*86d7f5d3SJohn Marino goto next_protocol;
262*86d7f5d3SJohn Marino break;
263*86d7f5d3SJohn Marino
264*86d7f5d3SJohn Marino case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
265*86d7f5d3SJohn Marino case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
266*86d7f5d3SJohn Marino default:
267*86d7f5d3SJohn Marino rfcomm_proto_list_parse_exit(ENOATTR);
268*86d7f5d3SJohn Marino /* NOT REACHED */
269*86d7f5d3SJohn Marino }
270*86d7f5d3SJohn Marino
271*86d7f5d3SJohn Marino /*
272*86d7f5d3SJohn Marino * First protocol specific parameter for RFCOMM procotol must
273*86d7f5d3SJohn Marino * be uint8 that represents RFCOMM channel number. So we must
274*86d7f5d3SJohn Marino * have at least two bytes.
275*86d7f5d3SJohn Marino */
276*86d7f5d3SJohn Marino
277*86d7f5d3SJohn Marino if (end - start < 2)
278*86d7f5d3SJohn Marino rfcomm_proto_list_parse_exit(EINVAL);
279*86d7f5d3SJohn Marino
280*86d7f5d3SJohn Marino SDP_GET8(type, start);
281*86d7f5d3SJohn Marino if (type != SDP_DATA_UINT8)
282*86d7f5d3SJohn Marino rfcomm_proto_list_parse_exit(ENOATTR);
283*86d7f5d3SJohn Marino
284*86d7f5d3SJohn Marino SDP_GET8(*channel, start);
285*86d7f5d3SJohn Marino
286*86d7f5d3SJohn Marino rfcomm_proto_list_parse_exit(0);
287*86d7f5d3SJohn Marino /* NOT REACHED */
288*86d7f5d3SJohn Marino next_protocol:
289*86d7f5d3SJohn Marino start += len;
290*86d7f5d3SJohn Marino }
291*86d7f5d3SJohn Marino
292*86d7f5d3SJohn Marino /*
293*86d7f5d3SJohn Marino * If we got here then it means we could not find RFCOMM protocol
294*86d7f5d3SJohn Marino * descriptor, but the reply format was actually valid.
295*86d7f5d3SJohn Marino */
296*86d7f5d3SJohn Marino
297*86d7f5d3SJohn Marino rfcomm_proto_list_parse_exit(ENOATTR);
298*86d7f5d3SJohn Marino }
299