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