Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/sdpd/ssr.c
105171 views
1
/*-
2
* ssr.c
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2004 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: ssr.c,v 1.5 2004/01/13 01:54:39 max Exp $
31
*/
32
33
#include <sys/param.h>
34
#include <sys/queue.h>
35
#include <sys/uio.h>
36
#include <netinet/in.h>
37
#include <arpa/inet.h>
38
#include <assert.h>
39
#define L2CAP_SOCKET_CHECKED
40
#include <bluetooth.h>
41
#include <errno.h>
42
#include <sdp.h>
43
#include <string.h>
44
#include "profile.h"
45
#include "provider.h"
46
#include "server.h"
47
#include "uuid-private.h"
48
49
/*
50
* Prepare SDP Service Search Response
51
*/
52
53
int32_t
54
server_prepare_service_search_response(server_p srv, int32_t fd)
55
{
56
uint8_t const *req = srv->req + sizeof(sdp_pdu_t);
57
uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len;
58
uint8_t *rsp = srv->fdidx[fd].rsp;
59
uint8_t const *rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
60
61
uint8_t *ptr = NULL;
62
provider_t *provider = NULL;
63
int32_t type, ssplen, rsp_limit, rcount, cslen, cs;
64
uint128_t uuid, puuid;
65
66
/*
67
* Minimal SDP Service Search Request
68
*
69
* seq8 len8 - 2 bytes
70
* uuid16 value16 - 3 bytes ServiceSearchPattern
71
* value16 - 2 bytes MaximumServiceRecordCount
72
* value8 - 1 byte ContinuationState
73
*/
74
75
if (req_end - req < 8)
76
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
77
78
/* Get size of ServiceSearchPattern */
79
ssplen = 0;
80
SDP_GET8(type, req);
81
switch (type) {
82
case SDP_DATA_SEQ8:
83
SDP_GET8(ssplen, req);
84
break;
85
86
case SDP_DATA_SEQ16:
87
SDP_GET16(ssplen, req);
88
break;
89
90
case SDP_DATA_SEQ32:
91
SDP_GET32(ssplen, req);
92
break;
93
}
94
if (ssplen <= 0)
95
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
96
97
ptr = (uint8_t *) req + ssplen;
98
99
/* Get MaximumServiceRecordCount */
100
if (ptr + 2 > req_end)
101
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
102
103
SDP_GET16(rsp_limit, ptr);
104
if (rsp_limit <= 0)
105
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
106
107
/* Get ContinuationState */
108
if (ptr + 1 > req_end)
109
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
110
111
SDP_GET8(cslen, ptr);
112
if (cslen != 0) {
113
if (cslen != 2 || req_end - ptr != 2)
114
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
115
116
SDP_GET16(cs, ptr);
117
} else
118
cs = 0;
119
120
/* Process the request. First, check continuation state */
121
if (srv->fdidx[fd].rsp_cs != cs)
122
return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
123
if (srv->fdidx[fd].rsp_size > 0)
124
return (0);
125
126
/*
127
* Service Search Response format
128
*
129
* value16 - 2 bytes TotalServiceRecordCount (not incl.)
130
* value16 - 2 bytes CurrentServiceRecordCount (not incl.)
131
* value32 - 4 bytes handle
132
* [ value32 ]
133
*
134
* Calculate how many record handles we can fit
135
* in our reply buffer and adjust rlimit.
136
*/
137
138
ptr = rsp;
139
rcount = (rsp_end - ptr) / 4;
140
if (rcount < rsp_limit)
141
rsp_limit = rcount;
142
143
/* Look for the record handles */
144
for (rcount = 0; ssplen > 0 && rcount < rsp_limit; ) {
145
SDP_GET8(type, req);
146
ssplen --;
147
148
switch (type) {
149
case SDP_DATA_UUID16:
150
if (ssplen < 2)
151
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
152
153
memcpy(&uuid, &uuid_base, sizeof(uuid));
154
uuid.b[2] = *req ++;
155
uuid.b[3] = *req ++;
156
ssplen -= 2;
157
break;
158
159
case SDP_DATA_UUID32:
160
if (ssplen < 4)
161
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
162
163
memcpy(&uuid, &uuid_base, sizeof(uuid));
164
uuid.b[0] = *req ++;
165
uuid.b[1] = *req ++;
166
uuid.b[2] = *req ++;
167
uuid.b[3] = *req ++;
168
ssplen -= 4;
169
break;
170
171
case SDP_DATA_UUID128:
172
if (ssplen < 16)
173
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
174
175
memcpy(uuid.b, req, 16);
176
req += 16;
177
ssplen -= 16;
178
break;
179
180
default:
181
return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
182
/* NOT REACHED */
183
}
184
185
for (provider = provider_get_first();
186
provider != NULL && rcount < rsp_limit;
187
provider = provider_get_next(provider)) {
188
if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
189
continue;
190
191
memcpy(&puuid, &uuid_base, sizeof(puuid));
192
puuid.b[2] = provider->profile->uuid >> 8;
193
puuid.b[3] = provider->profile->uuid;
194
195
if (memcmp(&uuid, &puuid, sizeof(uuid)) == 0 ||
196
memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) == 0) {
197
SDP_PUT32(provider->handle, ptr);
198
rcount ++;
199
}
200
}
201
}
202
203
/* Set reply size (not counting PDU header and continuation state) */
204
srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 4;
205
srv->fdidx[fd].rsp_size = ptr - rsp;
206
srv->fdidx[fd].rsp_cs = 0;
207
208
return (0);
209
}
210
211
/*
212
* Send SDP Service Search Response
213
*/
214
215
int32_t
216
server_send_service_search_response(server_p srv, int32_t fd)
217
{
218
uint8_t *rsp = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_cs;
219
uint8_t *rsp_end = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_size;
220
221
struct iovec iov[4];
222
sdp_pdu_t pdu;
223
uint16_t rcounts[2];
224
uint8_t cs[3];
225
int32_t size;
226
227
/* First update continuation state (assume we will send all data) */
228
size = rsp_end - rsp;
229
srv->fdidx[fd].rsp_cs += size;
230
231
if (size + 1 > srv->fdidx[fd].rsp_limit) {
232
/*
233
* We need to split out response. Add 3 more bytes for the
234
* continuation state and move rsp_end and rsp_cs backwards.
235
*/
236
237
while ((rsp_end - rsp) + 3 > srv->fdidx[fd].rsp_limit) {
238
rsp_end -= 4;
239
srv->fdidx[fd].rsp_cs -= 4;
240
}
241
242
cs[0] = 2;
243
cs[1] = srv->fdidx[fd].rsp_cs >> 8;
244
cs[2] = srv->fdidx[fd].rsp_cs & 0xff;
245
} else
246
cs[0] = 0;
247
248
assert(rsp_end >= rsp);
249
250
rcounts[0] = srv->fdidx[fd].rsp_size / 4; /* TotalServiceRecordCount */
251
rcounts[1] = (rsp_end - rsp) / 4; /* CurrentServiceRecordCount */
252
253
pdu.pid = SDP_PDU_SERVICE_SEARCH_RESPONSE;
254
pdu.tid = ((sdp_pdu_p)(srv->req))->tid;
255
pdu.len = htons(sizeof(rcounts) + rcounts[1] * 4 + 1 + cs[0]);
256
257
rcounts[0] = htons(rcounts[0]);
258
rcounts[1] = htons(rcounts[1]);
259
260
iov[0].iov_base = &pdu;
261
iov[0].iov_len = sizeof(pdu);
262
263
iov[1].iov_base = rcounts;
264
iov[1].iov_len = sizeof(rcounts);
265
266
iov[2].iov_base = rsp;
267
iov[2].iov_len = rsp_end - rsp;
268
269
iov[3].iov_base = cs;
270
iov[3].iov_len = 1 + cs[0];
271
272
do {
273
size = writev(fd, (struct iovec const *) &iov, nitems(iov));
274
} while (size < 0 && errno == EINTR);
275
276
/* Check if we have sent (or failed to sent) last response chunk */
277
if (srv->fdidx[fd].rsp_cs == srv->fdidx[fd].rsp_size) {
278
srv->fdidx[fd].rsp_cs = 0;
279
srv->fdidx[fd].rsp_size = 0;
280
srv->fdidx[fd].rsp_limit = 0;
281
}
282
283
return ((size < 0)? errno : 0);
284
}
285
286
287