1/*
2 * session.c
3 */
4
5/*-
6 * SPDX-License-Identifier: BSD-2-Clause
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 */
34
35#include <sys/queue.h>
36#include <assert.h>
37#define L2CAP_SOCKET_CHECKED
38#include <bluetooth.h>
39#include <errno.h>
40#include <fcntl.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <syslog.h>
45#include <unistd.h>
46#include <usbhid.h>
47#include "bthid_config.h"
48#include "bthidd.h"
49#include "btuinput.h"
50#include "kbd.h"
51
52/*
53 * Create new session
54 */
55
56bthid_session_p
57session_open(bthid_server_p srv, hid_device_p const d)
58{
59	bthid_session_p	s;
60
61	assert(srv != NULL);
62	assert(d != NULL);
63
64	if ((s = (bthid_session_p) malloc(sizeof(*s))) == NULL)
65		return (NULL);
66
67	s->srv = srv;
68	memcpy(&s->bdaddr, &d->bdaddr, sizeof(s->bdaddr));
69	s->ctrl = -1;
70	s->intr = -1;
71	s->vkbd = -1;
72	s->ctx = NULL;
73	s->state = CLOSED;
74	s->ukbd = -1;
75	s->umouse = -1;
76	s->obutt = 0;
77
78	s->keys1 = bit_alloc(kbd_maxkey());
79	if (s->keys1 == NULL) {
80		free(s);
81		return (NULL);
82	}
83
84	s->keys2 = bit_alloc(kbd_maxkey());
85	if (s->keys2 == NULL) {
86		free(s->keys1);
87		free(s);
88		return (NULL);
89	}
90
91	LIST_INSERT_HEAD(&srv->sessions, s, next);
92
93	return (s);
94}
95
96/*
97 * Initialize virtual keyboard and mouse after both channels are established
98 */
99
100int32_t
101session_run(bthid_session_p s)
102{
103	hid_device_p d = get_hid_device(&s->bdaddr);
104	struct sockaddr_l2cap   local;
105	socklen_t               len;
106
107	if (d->keyboard) {
108		/* Open /dev/vkbdctl */
109		s->vkbd = open("/dev/vkbdctl", O_RDWR);
110		if (s->vkbd < 0) {
111			syslog(LOG_ERR, "Could not open /dev/vkbdctl " \
112				"for %s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
113				strerror(errno), errno);
114			return (-1);
115		}
116		/* Register session's vkbd descriptor (if needed) for read */
117		FD_SET(s->vkbd, &s->srv->rfdset);
118		if (s->vkbd > s->srv->maxfd)
119			s->srv->maxfd = s->vkbd;
120	}
121
122	/* Pass device for probing */
123	hid_initialise(s);
124
125	/* Take local bdaddr */
126	len = sizeof(local);
127	getsockname(s->ctrl, (struct sockaddr *) &local, &len);
128
129	if (d->mouse && s->srv->uinput) {
130		s->umouse = uinput_open_mouse(d, &local.l2cap_bdaddr);
131		if (s->umouse < 0) {
132			syslog(LOG_ERR, "Could not open /dev/uinput " \
133				"for %s. %s (%d)", bt_ntoa(&s->bdaddr,
134				NULL), strerror(errno), errno);
135			return (-1);
136		}
137	}
138	if (d->keyboard && s->srv->uinput) {
139		s->ukbd = uinput_open_keyboard(d, &local.l2cap_bdaddr);
140		if (s->ukbd < 0) {
141			syslog(LOG_ERR, "Could not open /dev/uinput " \
142				"for %s. %s (%d)", bt_ntoa(&s->bdaddr,
143				NULL), strerror(errno), errno);
144			return (-1);
145		}
146		/* Register session's ukbd descriptor (if needed) for read */
147		FD_SET(s->ukbd, &s->srv->rfdset);
148		if (s->ukbd > s->srv->maxfd)
149			s->srv->maxfd = s->ukbd;
150	}
151	return (0);
152}
153
154/*
155 * Lookup session by bdaddr
156 */
157
158bthid_session_p
159session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr)
160{
161	bthid_session_p	s;
162
163	assert(srv != NULL);
164	assert(bdaddr != NULL);
165
166	LIST_FOREACH(s, &srv->sessions, next)
167		if (memcmp(&s->bdaddr, bdaddr, sizeof(s->bdaddr)) == 0)
168			break;
169
170	return (s);
171}
172
173/*
174 * Lookup session by fd
175 */
176
177bthid_session_p
178session_by_fd(bthid_server_p srv, int32_t fd)
179{
180	bthid_session_p	s;
181
182	assert(srv != NULL);
183	assert(fd >= 0);
184
185	LIST_FOREACH(s, &srv->sessions, next)
186		if (s->ctrl == fd || s->intr == fd ||
187		    s->vkbd == fd || s->ukbd == fd)
188			break;
189
190	return (s);
191}
192
193/*
194 * Close session
195 */
196
197void
198session_close(bthid_session_p s)
199{
200	assert(s != NULL);
201	assert(s->srv != NULL);
202
203	LIST_REMOVE(s, next);
204
205	if (s->intr != -1) {
206		FD_CLR(s->intr, &s->srv->rfdset);
207		FD_CLR(s->intr, &s->srv->wfdset);
208		close(s->intr);
209
210		if (s->srv->maxfd == s->intr)
211			s->srv->maxfd --;
212	}
213
214	if (s->ctrl != -1) {
215		FD_CLR(s->ctrl, &s->srv->rfdset);
216		FD_CLR(s->ctrl, &s->srv->wfdset);
217		close(s->ctrl);
218
219		if (s->srv->maxfd == s->ctrl)
220			s->srv->maxfd --;
221	}
222
223	if (s->vkbd != -1) {
224		FD_CLR(s->vkbd, &s->srv->rfdset);
225		close(s->vkbd);
226
227		if (s->srv->maxfd == s->vkbd)
228			s->srv->maxfd --;
229	}
230
231	if (s->umouse != -1)
232		close(s->umouse);
233
234	if (s->ukbd != -1) {
235		FD_CLR(s->ukbd, &s->srv->rfdset);
236		close(s->ukbd);
237
238		if (s->srv->maxfd == s->ukbd)
239			s->srv->maxfd --;
240	}
241
242	free(s->ctx);
243	free(s->keys1);
244	free(s->keys2);
245
246	memset(s, 0, sizeof(*s));
247	free(s);
248}
249
250