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