1/*
2 * session.c
3 */
4
5/*-
6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
7 *
8 * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: session.c,v 1.3 2006/09/07 21:06:53 max Exp $
33 * $FreeBSD$
34 */
35
36#include <sys/queue.h>
37#include <assert.h>
38#define L2CAP_SOCKET_CHECKED
39#include <bluetooth.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <syslog.h>
46#include <unistd.h>
47#include <usbhid.h>
48#include "bthid_config.h"
49#include "bthidd.h"
50#include "btuinput.h"
51#include "kbd.h"
52
53/*
54 * Create new session
55 */
56
57bthid_session_p
58session_open(bthid_server_p srv, hid_device_p const d)
59{
60	bthid_session_p	s;
61
62	assert(srv != NULL);
63	assert(d != NULL);
64
65	if ((s = (bthid_session_p) malloc(sizeof(*s))) == NULL)
66		return (NULL);
67
68	s->srv = srv;
69	memcpy(&s->bdaddr, &d->bdaddr, sizeof(s->bdaddr));
70	s->ctrl = -1;
71	s->intr = -1;
72	s->vkbd = -1;
73	s->ctx = NULL;
74	s->state = CLOSED;
75	s->ukbd = -1;
76	s->umouse = -1;
77	s->obutt = 0;
78
79	s->keys1 = bit_alloc(kbd_maxkey());
80	if (s->keys1 == NULL) {
81		free(s);
82		return (NULL);
83	}
84
85	s->keys2 = bit_alloc(kbd_maxkey());
86	if (s->keys2 == NULL) {
87		free(s->keys1);
88		free(s);
89		return (NULL);
90	}
91
92	LIST_INSERT_HEAD(&srv->sessions, s, next);
93
94	return (s);
95}
96
97/*
98 * Initialize virtual keyboard and mouse after both channels are established
99 */
100
101int32_t
102session_run(bthid_session_p s)
103{
104	hid_device_p d = get_hid_device(&s->bdaddr);
105	struct sockaddr_l2cap   local;
106	socklen_t               len;
107
108	if (d->keyboard) {
109		/* Open /dev/vkbdctl */
110		s->vkbd = open("/dev/vkbdctl", O_RDWR);
111		if (s->vkbd < 0) {
112			syslog(LOG_ERR, "Could not open /dev/vkbdctl " \
113				"for %s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
114				strerror(errno), errno);
115			return (-1);
116		}
117		/* Register session's vkbd descriptor (if needed) for read */
118		FD_SET(s->vkbd, &s->srv->rfdset);
119		if (s->vkbd > s->srv->maxfd)
120			s->srv->maxfd = s->vkbd;
121	}
122
123	/* Pass device for probing */
124	hid_initialise(s);
125
126	/* Take local bdaddr */
127	len = sizeof(local);
128	getsockname(s->ctrl, (struct sockaddr *) &local, &len);
129
130	if (d->mouse && s->srv->uinput) {
131		s->umouse = uinput_open_mouse(d, &local.l2cap_bdaddr);
132		if (s->umouse < 0) {
133			syslog(LOG_ERR, "Could not open /dev/uinput " \
134				"for %s. %s (%d)", bt_ntoa(&s->bdaddr,
135				NULL), strerror(errno), errno);
136			return (-1);
137		}
138	}
139	if (d->keyboard && s->srv->uinput) {
140		s->ukbd = uinput_open_keyboard(d, &local.l2cap_bdaddr);
141		if (s->ukbd < 0) {
142			syslog(LOG_ERR, "Could not open /dev/uinput " \
143				"for %s. %s (%d)", bt_ntoa(&s->bdaddr,
144				NULL), strerror(errno), errno);
145			return (-1);
146		}
147		/* Register session's ukbd descriptor (if needed) for read */
148		FD_SET(s->ukbd, &s->srv->rfdset);
149		if (s->ukbd > s->srv->maxfd)
150			s->srv->maxfd = s->ukbd;
151	}
152	return (0);
153}
154
155/*
156 * Lookup session by bdaddr
157 */
158
159bthid_session_p
160session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr)
161{
162	bthid_session_p	s;
163
164	assert(srv != NULL);
165	assert(bdaddr != NULL);
166
167	LIST_FOREACH(s, &srv->sessions, next)
168		if (memcmp(&s->bdaddr, bdaddr, sizeof(s->bdaddr)) == 0)
169			break;
170
171	return (s);
172}
173
174/*
175 * Lookup session by fd
176 */
177
178bthid_session_p
179session_by_fd(bthid_server_p srv, int32_t fd)
180{
181	bthid_session_p	s;
182
183	assert(srv != NULL);
184	assert(fd >= 0);
185
186	LIST_FOREACH(s, &srv->sessions, next)
187		if (s->ctrl == fd || s->intr == fd ||
188		    s->vkbd == fd || s->ukbd == fd)
189			break;
190
191	return (s);
192}
193
194/*
195 * Close session
196 */
197
198void
199session_close(bthid_session_p s)
200{
201	assert(s != NULL);
202	assert(s->srv != NULL);
203
204	LIST_REMOVE(s, next);
205
206	if (s->intr != -1) {
207		FD_CLR(s->intr, &s->srv->rfdset);
208		FD_CLR(s->intr, &s->srv->wfdset);
209		close(s->intr);
210
211		if (s->srv->maxfd == s->intr)
212			s->srv->maxfd --;
213	}
214
215	if (s->ctrl != -1) {
216		FD_CLR(s->ctrl, &s->srv->rfdset);
217		FD_CLR(s->ctrl, &s->srv->wfdset);
218		close(s->ctrl);
219
220		if (s->srv->maxfd == s->ctrl)
221			s->srv->maxfd --;
222	}
223
224	if (s->vkbd != -1) {
225		FD_CLR(s->vkbd, &s->srv->rfdset);
226		close(s->vkbd);
227
228		if (s->srv->maxfd == s->vkbd)
229			s->srv->maxfd --;
230	}
231
232	if (s->umouse != -1)
233		close(s->umouse);
234
235	if (s->ukbd != -1) {
236		FD_CLR(s->ukbd, &s->srv->rfdset);
237		close(s->ukbd);
238
239		if (s->srv->maxfd == s->ukbd)
240			s->srv->maxfd --;
241	}
242
243	free(s->ctx);
244	free(s->keys1);
245	free(s->keys2);
246
247	memset(s, 0, sizeof(*s));
248	free(s);
249}
250
251