1128080Semax/*
2128080Semax * server.c
3162128Semax */
4162128Semax
5162128Semax/*-
6162128Semax * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7128080Semax * All rights reserved.
8128080Semax *
9128080Semax * Redistribution and use in source and binary forms, with or without
10128080Semax * modification, are permitted provided that the following conditions
11128080Semax * are met:
12128080Semax * 1. Redistributions of source code must retain the above copyright
13128080Semax *    notice, this list of conditions and the following disclaimer.
14128080Semax * 2. Redistributions in binary form must reproduce the above copyright
15128080Semax *    notice, this list of conditions and the following disclaimer in the
16128080Semax *    documentation and/or other materials provided with the distribution.
17128080Semax *
18128080Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19128080Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20128080Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21128080Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22128080Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23128080Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24128080Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25128080Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26128080Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27128080Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28128080Semax * SUCH DAMAGE.
29128080Semax *
30162128Semax * $Id: server.c,v 1.9 2006/09/07 21:06:53 max Exp $
31128080Semax * $FreeBSD$
32128080Semax */
33128080Semax
34128080Semax#include <sys/queue.h>
35128080Semax#include <assert.h>
36128080Semax#include <bluetooth.h>
37162128Semax#include <dev/vkbd/vkbd_var.h>
38128080Semax#include <errno.h>
39128080Semax#include <fcntl.h>
40128080Semax#include <stdio.h>
41128080Semax#include <stdlib.h>
42128080Semax#include <string.h>
43128080Semax#include <syslog.h>
44128080Semax#include <unistd.h>
45128080Semax#include <usbhid.h>
46162128Semax#include "bthid_config.h"
47128080Semax#include "bthidd.h"
48137868Semax#include "kbd.h"
49128080Semax
50128080Semax#undef	max
51128080Semax#define	max(x, y)	(((x) > (y))? (x) : (y))
52128080Semax
53162128Semaxstatic int32_t	server_accept (bthid_server_p srv, int32_t fd);
54162128Semaxstatic int32_t	server_process(bthid_server_p srv, int32_t fd);
55128080Semax
56128080Semax/*
57128080Semax * Initialize server
58128080Semax */
59128080Semax
60162128Semaxint32_t
61128080Semaxserver_init(bthid_server_p srv)
62128080Semax{
63128080Semax	struct sockaddr_l2cap	l2addr;
64128080Semax
65128080Semax	assert(srv != NULL);
66128080Semax
67128080Semax	srv->ctrl = srv->intr = -1;
68128080Semax	FD_ZERO(&srv->rfdset);
69128080Semax	FD_ZERO(&srv->wfdset);
70128080Semax	LIST_INIT(&srv->sessions);
71128080Semax
72128080Semax	/* Open /dev/consolectl */
73128080Semax	srv->cons = open("/dev/consolectl", O_RDWR);
74128080Semax	if (srv->cons < 0) {
75128080Semax		syslog(LOG_ERR, "Could not open /dev/consolectl. %s (%d)",
76128080Semax			strerror(errno), errno);
77128080Semax		return (-1);
78128080Semax	}
79128080Semax
80128080Semax	/* Create control socket */
81128080Semax	srv->ctrl = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
82128080Semax	if (srv->ctrl < 0) {
83128080Semax		syslog(LOG_ERR, "Could not create control L2CAP socket. " \
84128080Semax			"%s (%d)", strerror(errno), errno);
85128080Semax		close(srv->cons);
86128080Semax		return (-1);
87128080Semax	}
88128080Semax
89128080Semax	l2addr.l2cap_len = sizeof(l2addr);
90128080Semax	l2addr.l2cap_family = AF_BLUETOOTH;
91128080Semax	memcpy(&l2addr.l2cap_bdaddr, &srv->bdaddr, sizeof(l2addr.l2cap_bdaddr));
92156784Semax	l2addr.l2cap_psm = htole16(0x11);
93128080Semax
94128080Semax	if (bind(srv->ctrl, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
95128080Semax		syslog(LOG_ERR, "Could not bind control L2CAP socket. " \
96128080Semax			"%s (%d)", strerror(errno), errno);
97137868Semax		close(srv->ctrl);
98128080Semax		close(srv->cons);
99128080Semax		return (-1);
100128080Semax	}
101128080Semax
102128080Semax	if (listen(srv->ctrl, 10) < 0) {
103128080Semax		syslog(LOG_ERR, "Could not listen on control L2CAP socket. " \
104128080Semax			"%s (%d)", strerror(errno), errno);
105137868Semax		close(srv->ctrl);
106128080Semax		close(srv->cons);
107128080Semax		return (-1);
108128080Semax	}
109128080Semax
110128080Semax	/* Create intrrupt socket */
111128080Semax	srv->intr = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
112128080Semax	if (srv->intr < 0) {
113128080Semax		syslog(LOG_ERR, "Could not create interrupt L2CAP socket. " \
114128080Semax			"%s (%d)", strerror(errno), errno);
115128080Semax		close(srv->ctrl);
116128080Semax		close(srv->cons);
117128080Semax		return (-1);
118128080Semax	}
119128080Semax
120156784Semax	l2addr.l2cap_psm = htole16(0x13);
121128080Semax
122128080Semax	if (bind(srv->intr, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
123128080Semax		syslog(LOG_ERR, "Could not bind interrupt L2CAP socket. " \
124128080Semax			"%s (%d)", strerror(errno), errno);
125137868Semax		close(srv->intr);
126128080Semax		close(srv->ctrl);
127128080Semax		close(srv->cons);
128128080Semax		return (-1);
129128080Semax	}
130128080Semax
131128080Semax	if (listen(srv->intr, 10) < 0) {
132128080Semax		syslog(LOG_ERR, "Could not listen on interrupt L2CAP socket. "\
133128080Semax			"%s (%d)", strerror(errno), errno);
134137868Semax		close(srv->intr);
135128080Semax		close(srv->ctrl);
136128080Semax		close(srv->cons);
137128080Semax		return (-1);
138128080Semax	}
139128080Semax
140128080Semax	FD_SET(srv->ctrl, &srv->rfdset);
141128080Semax	FD_SET(srv->intr, &srv->rfdset);
142128080Semax	srv->maxfd = max(srv->ctrl, srv->intr);
143128080Semax
144128080Semax	return (0);
145128080Semax}
146128080Semax
147128080Semax/*
148128080Semax * Shutdown server
149128080Semax */
150128080Semax
151128080Semaxvoid
152128080Semaxserver_shutdown(bthid_server_p srv)
153128080Semax{
154128080Semax	assert(srv != NULL);
155128080Semax
156128080Semax	close(srv->cons);
157128080Semax	close(srv->ctrl);
158128080Semax	close(srv->intr);
159128080Semax
160128080Semax	while (!LIST_EMPTY(&srv->sessions))
161128080Semax		session_close(LIST_FIRST(&srv->sessions));
162128080Semax
163128080Semax	memset(srv, 0, sizeof(*srv));
164128080Semax}
165128080Semax
166128080Semax/*
167128080Semax * Do one server iteration
168128080Semax */
169128080Semax
170162128Semaxint32_t
171128080Semaxserver_do(bthid_server_p srv)
172128080Semax{
173128080Semax	struct timeval	tv;
174128080Semax	fd_set		rfdset, wfdset;
175162128Semax	int32_t		n, fd;
176128080Semax
177128080Semax	assert(srv != NULL);
178128080Semax
179128080Semax	tv.tv_sec = 1;
180128080Semax	tv.tv_usec = 0;
181128080Semax
182128080Semax	/* Copy cached version of the fd sets and call select */
183128080Semax	memcpy(&rfdset, &srv->rfdset, sizeof(rfdset));
184128080Semax	memcpy(&wfdset, &srv->wfdset, sizeof(wfdset));
185128080Semax
186128080Semax	n = select(srv->maxfd + 1, &rfdset, &wfdset, NULL, &tv);
187128080Semax	if (n < 0) {
188128080Semax		if (errno == EINTR)
189128080Semax			return (0);
190128080Semax
191128080Semax		syslog(LOG_ERR, "Could not select(%d, %p, %p). %s (%d)",
192128080Semax			srv->maxfd + 1, &rfdset, &wfdset, strerror(errno), errno);
193128080Semax
194128080Semax		return (-1);
195128080Semax	}
196128080Semax
197128080Semax	/* Process descriptors (if any) */
198128080Semax	for (fd = 0; fd < srv->maxfd + 1 && n > 0; fd ++) {
199128080Semax		if (FD_ISSET(fd, &rfdset)) {
200128080Semax			n --;
201128080Semax
202128080Semax			if (fd == srv->ctrl || fd == srv->intr)
203128080Semax				server_accept(srv, fd);
204128080Semax			else
205128080Semax				server_process(srv, fd);
206128080Semax		} else if (FD_ISSET(fd, &wfdset)) {
207128080Semax			n --;
208128080Semax
209128080Semax			client_connect(srv, fd);
210128080Semax		}
211128080Semax	}
212128080Semax
213128080Semax	return (0);
214128080Semax}
215128080Semax
216128080Semax/*
217128080Semax * Accept new connection
218128080Semax */
219128080Semax
220162128Semaxstatic int32_t
221162128Semaxserver_accept(bthid_server_p srv, int32_t fd)
222128080Semax{
223162128Semax	bthid_session_p		s;
224162128Semax	hid_device_p		d;
225128080Semax	struct sockaddr_l2cap	l2addr;
226162494Semax	int32_t			new_fd;
227162494Semax	socklen_t		len;
228128080Semax
229128080Semax	len = sizeof(l2addr);
230128080Semax	if ((new_fd = accept(fd, (struct sockaddr *) &l2addr, &len)) < 0) {
231128080Semax		syslog(LOG_ERR, "Could not accept %s connection. %s (%d)",
232128080Semax			(fd == srv->ctrl)? "control" : "interrupt",
233128080Semax			strerror(errno), errno);
234128080Semax		return (-1);
235128080Semax	}
236128080Semax
237162128Semax	/* Is device configured? */
238162128Semax	if ((d = get_hid_device(&l2addr.l2cap_bdaddr)) == NULL) {
239162128Semax		syslog(LOG_ERR, "Rejecting %s connection from %s. " \
240162128Semax			"Device not configured",
241162128Semax			(fd == srv->ctrl)? "control" : "interrupt",
242162128Semax			bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
243162128Semax		close(new_fd);
244162128Semax		return (-1);
245162128Semax	}
246162128Semax
247128080Semax	/* Check if we have session for the device */
248128080Semax	if ((s = session_by_bdaddr(srv, &l2addr.l2cap_bdaddr)) == NULL) {
249128080Semax		d->new_device = 0; /* reset new device flag */
250128080Semax		write_hids_file();
251128080Semax
252128080Semax		/* Create new inbound session */
253162128Semax		if ((s = session_open(srv, d)) == NULL) {
254162128Semax			syslog(LOG_CRIT, "Could not open inbound session "
255162128Semax				"for %s", bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
256128080Semax			close(new_fd);
257128080Semax			return (-1);
258128080Semax		}
259128080Semax	}
260128080Semax
261128080Semax	/* Update descriptors */
262128080Semax	if (fd == srv->ctrl) {
263128080Semax		assert(s->ctrl == -1);
264128080Semax		s->ctrl = new_fd;
265128080Semax		s->state = (s->intr == -1)? W4INTR : OPEN;
266128080Semax	} else {
267128080Semax		assert(s->intr == -1);
268128080Semax		s->intr = new_fd;
269128080Semax		s->state = (s->ctrl == -1)? W4CTRL : OPEN;
270128080Semax	}
271128080Semax
272128080Semax	FD_SET(new_fd, &srv->rfdset);
273128080Semax	if (new_fd > srv->maxfd)
274128080Semax		srv->maxfd = new_fd;
275128080Semax
276128080Semax	syslog(LOG_NOTICE, "Accepted %s connection from %s",
277128080Semax		(fd == srv->ctrl)? "control" : "interrupt",
278128080Semax		bt_ntoa(&l2addr.l2cap_bdaddr, NULL));
279128080Semax
280162128Semax	/* Register session's vkbd descriptor (if needed) for read */
281162128Semax	if (s->state == OPEN && d->keyboard) {
282162128Semax		assert(s->vkbd != -1);
283162128Semax
284162128Semax		FD_SET(s->vkbd, &srv->rfdset);
285162128Semax		if (s->vkbd > srv->maxfd)
286162128Semax			srv->maxfd = s->vkbd;
287162128Semax	}
288162128Semax
289128080Semax	return (0);
290128080Semax}
291128080Semax
292128080Semax/*
293128080Semax * Process data on the connection
294128080Semax */
295128080Semax
296162128Semaxstatic int32_t
297162128Semaxserver_process(bthid_server_p srv, int32_t fd)
298128080Semax{
299162128Semax	bthid_session_p		s = session_by_fd(srv, fd);
300162128Semax	int32_t			len, to_read;
301162128Semax	int32_t			(*cb)(bthid_session_p, uint8_t *, int32_t);
302162128Semax	union {
303162128Semax		uint8_t		b[1024];
304162128Semax		vkbd_status_t	s;
305162128Semax	}			data;
306128080Semax
307146357Semax	if (s == NULL)
308146357Semax		return (0); /* can happen on device disconnect */
309128080Semax
310162128Semax
311162128Semax	if (fd == s->ctrl) {
312162128Semax		cb = hid_control;
313162128Semax		to_read = sizeof(data.b);
314162128Semax	} else if (fd == s->intr) {
315162128Semax		cb = hid_interrupt;
316162128Semax		to_read = sizeof(data.b);
317162128Semax	} else {
318162128Semax		assert(fd == s->vkbd);
319162128Semax
320162128Semax		cb = kbd_status_changed;
321162128Semax		to_read = sizeof(data.s);
322162128Semax	}
323162128Semax
324128080Semax	do {
325162128Semax		len = read(fd, &data, to_read);
326128080Semax	} while (len < 0 && errno == EINTR);
327128080Semax
328128080Semax	if (len < 0) {
329128080Semax		syslog(LOG_ERR, "Could not read data from %s (%s). %s (%d)",
330128080Semax			bt_ntoa(&s->bdaddr, NULL),
331128080Semax			(fd == s->ctrl)? "control" : "interrupt",
332128080Semax			strerror(errno), errno);
333128080Semax		session_close(s);
334128080Semax		return (0);
335128080Semax	}
336128080Semax
337128080Semax	if (len == 0) {
338128080Semax		syslog(LOG_NOTICE, "Remote device %s has closed %s connection",
339128080Semax			bt_ntoa(&s->bdaddr, NULL),
340128080Semax			(fd == s->ctrl)? "control" : "interrupt");
341128080Semax		session_close(s);
342128080Semax		return (0);
343128080Semax	}
344128080Semax
345162128Semax	(*cb)(s, (uint8_t *) &data, len);
346128080Semax
347128080Semax	return (0);
348128080Semax}
349128080Semax
350