1188013Semax/*	$NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $	*/
2187938Semax
3187938Semax/*-
4330449Seadler * SPDX-License-Identifier: BSD-2-Clause-NetBSD
5330449Seadler *
6187938Semax * Copyright (c) 2008 Iain Hibbert
7187938Semax * All rights reserved.
8187938Semax *
9187938Semax * Redistribution and use in source and binary forms, with or without
10187938Semax * modification, are permitted provided that the following conditions
11187938Semax * are met:
12187938Semax * 1. Redistributions of source code must retain the above copyright
13187938Semax *    notice, this list of conditions and the following disclaimer.
14187938Semax * 2. Redistributions in binary form must reproduce the above copyright
15187938Semax *    notice, this list of conditions and the following disclaimer in the
16187938Semax *    documentation and/or other materials provided with the distribution.
17187938Semax *
18187938Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19187938Semax * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20187938Semax * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21187938Semax * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22187938Semax * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23187938Semax * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24187938Semax * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25187938Semax * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26187938Semax * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27187938Semax * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28187938Semax */
29187938Semax
30187938Semax/* $FreeBSD: stable/11/usr.sbin/bluetooth/btpand/server.c 330449 2018-03-05 07:26:05Z eadler $ */
31187938Semax
32187938Semax#include <sys/cdefs.h>
33188013Semax__RCSID("$NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $");
34187938Semax
35187938Semax#include <sys/ioctl.h>
36187938Semax
37281210Stakawata#define L2CAP_SOCKET_CHECKED
38187938Semax#include <bluetooth.h>
39188013Semax#include <inttypes.h>
40187938Semax#include <errno.h>
41187938Semax#include <sdp.h>
42187938Semax#include <unistd.h>
43187938Semax
44187938Semax#include "btpand.h"
45187938Semax#include "bnep.h"
46187938Semax
47187938Semaxstatic struct event	server_ev;
48187938Semaxstatic int		server_fd;
49188013Semaxstatic int		server_avail;
50187938Semax
51187938Semaxstatic void *		server_ss;
52187938Semaxstatic uint32_t		server_handle;
53187938Semax
54187938Semaxstatic void server_open(void);
55187938Semaxstatic void server_close(void);
56187938Semaxstatic void server_read(int, short, void *);
57187938Semaxstatic void server_register(void);
58187938Semax
59187938Semaxvoid
60187938Semaxserver_init(void)
61187938Semax{
62187938Semax
63187938Semax	server_fd = -1;
64187938Semax}
65187938Semax
66187938Semax/*
67187938Semax * The server_update() function is called whenever the channel count is
68187938Semax * changed. We maintain the SDP record and open or close the server socket
69187938Semax * as required.
70187938Semax */
71187938Semaxvoid
72187938Semaxserver_update(int count)
73187938Semax{
74187938Semax
75187938Semax	if (server_limit == 0)
76187938Semax		return;
77187938Semax
78187938Semax	log_debug("count %d", count);
79187938Semax
80188013Semax	server_avail = UINT8_MAX - (count - 1) * UINT8_MAX / server_limit;
81188013Semax	log_info("Service Availability: %d/%d", server_avail, UINT8_MAX);
82187938Semax
83188013Semax	if (server_avail == 0 && server_fd != -1)
84187938Semax		server_close();
85187938Semax
86188013Semax	if (server_avail > 0 && server_fd == -1)
87187938Semax		server_open();
88187938Semax
89187938Semax	if (service_name)
90187938Semax		server_register();
91187938Semax}
92187938Semax
93187938Semaxstatic void
94187938Semaxserver_open(void)
95187938Semax{
96187938Semax	struct sockaddr_l2cap sa;
97187938Semax	uint16_t mru;
98187938Semax
99187938Semax	server_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
100187938Semax	if (server_fd == -1) {
101187938Semax		log_err("Could not open L2CAP socket: %m");
102187938Semax		exit(EXIT_FAILURE);
103187938Semax	}
104187938Semax
105187938Semax	memset(&sa, 0, sizeof(sa));
106187938Semax	sa.l2cap_family = AF_BLUETOOTH;
107187938Semax	sa.l2cap_len = sizeof(sa);
108187938Semax	sa.l2cap_psm = htole16(l2cap_psm);
109281210Stakawata	sa.l2cap_bdaddr_type = BDADDR_BREDR;
110281210Stakawata	sa.l2cap_cid = 0;
111281210Stakawata
112187938Semax	bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr);
113187938Semax	if (bind(server_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
114187938Semax		log_err("Could not bind server socket: %m");
115187938Semax		exit(EXIT_FAILURE);
116187938Semax	}
117187938Semax
118187938Semax	mru = BNEP_MTU_MIN;
119187938Semax	if (setsockopt(server_fd, SOL_L2CAP,
120187938Semax	    SO_L2CAP_IMTU, &mru, sizeof(mru)) == -1) {
121187938Semax		log_err("Could not set L2CAP IMTU (%d): %m", mru);
122187938Semax		exit(EXIT_FAILURE);
123187938Semax	}
124187938Semax
125187938Semax	if (listen(server_fd, 0) == -1) {
126187938Semax		log_err("Could not listen on server socket: %m");
127187938Semax		exit(EXIT_FAILURE);
128187938Semax	}
129187938Semax
130187938Semax	event_set(&server_ev, server_fd, EV_READ | EV_PERSIST, server_read, NULL);
131187938Semax	if (event_add(&server_ev, NULL) == -1) {
132187938Semax		log_err("Could not add server event: %m");
133187938Semax		exit(EXIT_FAILURE);
134187938Semax	}
135187938Semax
136187938Semax	log_info("server socket open");
137187938Semax}
138187938Semax
139187938Semaxstatic void
140187938Semaxserver_close(void)
141187938Semax{
142187938Semax
143187938Semax	event_del(&server_ev);
144187938Semax	close(server_fd);
145187938Semax	server_fd = -1;
146187938Semax
147187938Semax	log_info("server socket closed");
148187938Semax}
149187938Semax
150187938Semax/*
151187938Semax * handle connection request
152187938Semax */
153187938Semaxstatic void
154187938Semaxserver_read(int s, short ev, void *arg)
155187938Semax{
156187938Semax	struct sockaddr_l2cap ra, la;
157187938Semax	channel_t *chan;
158187938Semax	socklen_t len;
159187938Semax	int fd, n;
160187938Semax	uint16_t mru, mtu;
161187938Semax
162187938Semax	len = sizeof(ra);
163187938Semax	fd = accept(s, (struct sockaddr *)&ra, &len);
164187938Semax	if (fd == -1)
165187938Semax		return;
166187938Semax
167187938Semax	n = 1;
168187938Semax	if (ioctl(fd, FIONBIO, &n) == -1) {
169187938Semax		log_err("Could not set NonBlocking IO: %m");
170187938Semax		close(fd);
171187938Semax		return;
172187938Semax	}
173187938Semax
174187938Semax	len = sizeof(mru);
175187938Semax	if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, &len) == -1) {
176187938Semax		log_err("Could not get L2CAP IMTU: %m");
177187938Semax		close(fd);
178187938Semax		return;
179187938Semax	}
180187938Semax	if(mru < BNEP_MTU_MIN) {
181187938Semax		log_err("L2CAP IMTU too small (%d)", mru);
182187938Semax		close(fd);
183187938Semax		return;
184187938Semax	}
185187938Semax
186241699Semax	len = sizeof(n);
187241699Semax	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, &len) == -1) {
188241699Semax		log_err("Could not read SO_RCVBUF");
189241699Semax		close(fd);
190241699Semax		return;
191241699Semax	}
192241699Semax	if (n < (mru * 10)) {
193241699Semax		n = mru * 10;
194241699Semax		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
195241699Semax			log_info("Could not increase SO_RCVBUF (from %d)", n);
196241699Semax	}
197241699Semax
198187938Semax	len = sizeof(mtu);
199187938Semax	if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_OMTU, &mtu, &len) == -1) {
200187938Semax		log_err("Could not get L2CAP OMTU: %m");
201187938Semax		close(fd);
202187938Semax		return;
203187938Semax	}
204187938Semax	if (mtu < BNEP_MTU_MIN) {
205187938Semax		log_err("L2CAP OMTU too small (%d)", mtu);
206187938Semax		close(fd);
207187938Semax		return;
208187938Semax	}
209187938Semax
210187938Semax	len = sizeof(n);
211187938Semax	if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, &len) == -1) {
212187938Semax		log_err("Could not get socket send buffer size: %m");
213187938Semax		close(fd);
214187938Semax		return;
215187938Semax	}
216187938Semax
217187938Semax	if (n < (mtu * 2)) {
218187938Semax		n = mtu * 2;
219187938Semax		if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) == -1) {
220187938Semax			log_err("Could not set socket send buffer size (%d): %m", n);
221187938Semax			close(fd);
222187938Semax			return;
223187938Semax		}
224187938Semax	}
225187938Semax
226187938Semax	n = mtu;
227187938Semax	if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &n, sizeof(n)) == -1) {
228187938Semax		log_err("Could not set socket low water mark (%d): %m", n);
229187938Semax		close(fd);
230187938Semax		return;
231187938Semax	}
232187938Semax
233187938Semax	len = sizeof(la);
234187938Semax	if (getsockname(fd, (struct sockaddr *)&la, &len) == -1) {
235187938Semax		log_err("Could not get socket address: %m");
236187938Semax		close(fd);
237187938Semax		return;
238187938Semax	}
239187938Semax
240187938Semax	log_info("Accepted connection from %s", bt_ntoa(&ra.l2cap_bdaddr, NULL));
241187938Semax
242187938Semax	chan = channel_alloc();
243187938Semax	if (chan == NULL) {
244187938Semax		close(fd);
245187938Semax		return;
246187938Semax	}
247187938Semax
248187938Semax	chan->send = bnep_send;
249187938Semax	chan->recv = bnep_recv;
250187938Semax	chan->mru = mru;
251187938Semax	chan->mtu = mtu;
252187938Semax	b2eaddr(chan->raddr, &ra.l2cap_bdaddr);
253187938Semax	b2eaddr(chan->laddr, &la.l2cap_bdaddr);
254187938Semax	chan->state = CHANNEL_WAIT_CONNECT_REQ;
255187938Semax	channel_timeout(chan, 10);
256187938Semax	if (!channel_open(chan, fd)) {
257187938Semax		chan->state = CHANNEL_CLOSED;
258187938Semax		channel_free(chan);
259187938Semax		close(fd);
260187938Semax		return;
261187938Semax	}
262187938Semax}
263187938Semax
264187938Semaxstatic void
265187938Semaxserver_register(void)
266187938Semax{
267187938Semax	sdp_nap_profile_t p;
268187938Semax	int rv;
269187938Semax
270187938Semax	if (server_ss == NULL) {
271187938Semax		server_ss = sdp_open_local(control_path);
272187938Semax		if (server_ss == NULL || sdp_error(server_ss) != 0) {
273187938Semax			log_err("failed to contact SDP server");
274187938Semax			return;
275187938Semax		}
276187938Semax	}
277187938Semax
278187938Semax	memset(&p, 0, sizeof(p));
279187938Semax	p.psm = l2cap_psm;
280188013Semax	p.load_factor = server_avail;
281188013Semax	p.security_description = (l2cap_mode == 0 ? 0x0000 : 0x0001);
282187938Semax
283187938Semax	if (server_handle)
284187938Semax		rv = sdp_change_service(server_ss, server_handle,
285187938Semax		    (uint8_t *)&p, sizeof(p));
286187938Semax	else
287187938Semax		rv = sdp_register_service(server_ss, service_class,
288187938Semax		    &local_bdaddr, (uint8_t *)&p, sizeof(p), &server_handle);
289187938Semax
290187938Semax	if (rv != 0) {
291187938Semax		errno = sdp_error(server_ss);
292187938Semax		log_err("%s: %m", service_name);
293187938Semax		exit(EXIT_FAILURE);
294187938Semax	}
295187938Semax}
296