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