Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/btpand/server.c
103554 views
1
/* $NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $ */
2
3
/*-
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2008 Iain Hibbert
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 ``AS IS'' AND ANY EXPRESS OR
19
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
*/
29
30
31
#include <sys/cdefs.h>
32
__RCSID("$NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $");
33
34
#include <sys/ioctl.h>
35
36
#define L2CAP_SOCKET_CHECKED
37
#include <bluetooth.h>
38
#include <inttypes.h>
39
#include <errno.h>
40
#include <sdp.h>
41
#include <unistd.h>
42
43
#include "btpand.h"
44
#include "bnep.h"
45
46
static struct event server_ev;
47
static int server_fd;
48
static int server_avail;
49
50
static void * server_ss;
51
static uint32_t server_handle;
52
53
static void server_open(void);
54
static void server_close(void);
55
static void server_read(int, short, void *);
56
static void server_register(void);
57
58
void
59
server_init(void)
60
{
61
62
server_fd = -1;
63
}
64
65
/*
66
* The server_update() function is called whenever the channel count is
67
* changed. We maintain the SDP record and open or close the server socket
68
* as required.
69
*/
70
void
71
server_update(int count)
72
{
73
74
if (server_limit == 0)
75
return;
76
77
log_debug("count %d", count);
78
79
server_avail = UINT8_MAX - (count - 1) * UINT8_MAX / server_limit;
80
log_info("Service Availability: %d/%d", server_avail, UINT8_MAX);
81
82
if (server_avail == 0 && server_fd != -1)
83
server_close();
84
85
if (server_avail > 0 && server_fd == -1)
86
server_open();
87
88
if (service_name)
89
server_register();
90
}
91
92
static void
93
server_open(void)
94
{
95
struct sockaddr_l2cap sa;
96
uint16_t mru;
97
98
server_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
99
if (server_fd == -1) {
100
log_err("Could not open L2CAP socket: %m");
101
exit(EXIT_FAILURE);
102
}
103
104
memset(&sa, 0, sizeof(sa));
105
sa.l2cap_family = AF_BLUETOOTH;
106
sa.l2cap_len = sizeof(sa);
107
sa.l2cap_psm = htole16(l2cap_psm);
108
sa.l2cap_bdaddr_type = BDADDR_BREDR;
109
sa.l2cap_cid = 0;
110
111
bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr);
112
if (bind(server_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
113
log_err("Could not bind server socket: %m");
114
exit(EXIT_FAILURE);
115
}
116
117
mru = BNEP_MTU_MIN;
118
if (setsockopt(server_fd, SOL_L2CAP,
119
SO_L2CAP_IMTU, &mru, sizeof(mru)) == -1) {
120
log_err("Could not set L2CAP IMTU (%d): %m", mru);
121
exit(EXIT_FAILURE);
122
}
123
124
if (listen(server_fd, 0) == -1) {
125
log_err("Could not listen on server socket: %m");
126
exit(EXIT_FAILURE);
127
}
128
129
event_set(&server_ev, server_fd, EV_READ | EV_PERSIST, server_read, NULL);
130
if (event_add(&server_ev, NULL) == -1) {
131
log_err("Could not add server event: %m");
132
exit(EXIT_FAILURE);
133
}
134
135
log_info("server socket open");
136
}
137
138
static void
139
server_close(void)
140
{
141
142
event_del(&server_ev);
143
close(server_fd);
144
server_fd = -1;
145
146
log_info("server socket closed");
147
}
148
149
/*
150
* handle connection request
151
*/
152
static void
153
server_read(int s, short ev, void *arg)
154
{
155
struct sockaddr_l2cap ra, la;
156
channel_t *chan;
157
socklen_t len;
158
int fd, n;
159
uint16_t mru, mtu;
160
161
len = sizeof(ra);
162
fd = accept(s, (struct sockaddr *)&ra, &len);
163
if (fd == -1)
164
return;
165
166
n = 1;
167
if (ioctl(fd, FIONBIO, &n) == -1) {
168
log_err("Could not set NonBlocking IO: %m");
169
close(fd);
170
return;
171
}
172
173
len = sizeof(mru);
174
if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, &len) == -1) {
175
log_err("Could not get L2CAP IMTU: %m");
176
close(fd);
177
return;
178
}
179
if(mru < BNEP_MTU_MIN) {
180
log_err("L2CAP IMTU too small (%d)", mru);
181
close(fd);
182
return;
183
}
184
185
len = sizeof(n);
186
if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, &len) == -1) {
187
log_err("Could not read SO_RCVBUF");
188
close(fd);
189
return;
190
}
191
if (n < (mru * 10)) {
192
n = mru * 10;
193
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
194
log_info("Could not increase SO_RCVBUF (from %d)", n);
195
}
196
197
len = sizeof(mtu);
198
if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_OMTU, &mtu, &len) == -1) {
199
log_err("Could not get L2CAP OMTU: %m");
200
close(fd);
201
return;
202
}
203
if (mtu < BNEP_MTU_MIN) {
204
log_err("L2CAP OMTU too small (%d)", mtu);
205
close(fd);
206
return;
207
}
208
209
len = sizeof(n);
210
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, &len) == -1) {
211
log_err("Could not get socket send buffer size: %m");
212
close(fd);
213
return;
214
}
215
216
if (n < (mtu * 2)) {
217
n = mtu * 2;
218
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) == -1) {
219
log_err("Could not set socket send buffer size (%d): %m", n);
220
close(fd);
221
return;
222
}
223
}
224
225
n = mtu;
226
if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &n, sizeof(n)) == -1) {
227
log_err("Could not set socket low water mark (%d): %m", n);
228
close(fd);
229
return;
230
}
231
232
len = sizeof(la);
233
if (getsockname(fd, (struct sockaddr *)&la, &len) == -1) {
234
log_err("Could not get socket address: %m");
235
close(fd);
236
return;
237
}
238
239
log_info("Accepted connection from %s", bt_ntoa(&ra.l2cap_bdaddr, NULL));
240
241
chan = channel_alloc();
242
if (chan == NULL) {
243
close(fd);
244
return;
245
}
246
247
chan->send = bnep_send;
248
chan->recv = bnep_recv;
249
chan->mru = mru;
250
chan->mtu = mtu;
251
b2eaddr(chan->raddr, &ra.l2cap_bdaddr);
252
b2eaddr(chan->laddr, &la.l2cap_bdaddr);
253
chan->state = CHANNEL_WAIT_CONNECT_REQ;
254
channel_timeout(chan, 10);
255
if (!channel_open(chan, fd)) {
256
chan->state = CHANNEL_CLOSED;
257
channel_free(chan);
258
close(fd);
259
return;
260
}
261
}
262
263
static void
264
server_register(void)
265
{
266
sdp_nap_profile_t p;
267
int rv;
268
269
if (server_ss == NULL) {
270
server_ss = sdp_open_local(control_path);
271
if (server_ss == NULL || sdp_error(server_ss) != 0) {
272
log_err("failed to contact SDP server");
273
return;
274
}
275
}
276
277
memset(&p, 0, sizeof(p));
278
p.psm = l2cap_psm;
279
p.load_factor = server_avail;
280
p.security_description = (l2cap_mode == 0 ? 0x0000 : 0x0001);
281
282
if (server_handle)
283
rv = sdp_change_service(server_ss, server_handle,
284
(uint8_t *)&p, sizeof(p));
285
else
286
rv = sdp_register_service(server_ss, service_class,
287
&local_bdaddr, (uint8_t *)&p, sizeof(p), &server_handle);
288
289
if (rv != 0) {
290
errno = sdp_error(server_ss);
291
log_err("%s: %m", service_name);
292
exit(EXIT_FAILURE);
293
}
294
}
295
296