xref: /freebsd-src/usr.sbin/bluetooth/bthidd/session.c (revision 42b388439bd3795e09258c57a74ce9eec3651c7b)
16490c2ffSMaksim Yevmenkin /*
26490c2ffSMaksim Yevmenkin  * session.c
37aebfa93SMaksim Yevmenkin  */
47aebfa93SMaksim Yevmenkin 
57aebfa93SMaksim Yevmenkin /*-
6*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
71de7b4b8SPedro F. Giffuni  *
87aebfa93SMaksim Yevmenkin  * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
96490c2ffSMaksim Yevmenkin  * All rights reserved.
106490c2ffSMaksim Yevmenkin  *
116490c2ffSMaksim Yevmenkin  * Redistribution and use in source and binary forms, with or without
126490c2ffSMaksim Yevmenkin  * modification, are permitted provided that the following conditions
136490c2ffSMaksim Yevmenkin  * are met:
146490c2ffSMaksim Yevmenkin  * 1. Redistributions of source code must retain the above copyright
156490c2ffSMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer.
166490c2ffSMaksim Yevmenkin  * 2. Redistributions in binary form must reproduce the above copyright
176490c2ffSMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer in the
186490c2ffSMaksim Yevmenkin  *    documentation and/or other materials provided with the distribution.
196490c2ffSMaksim Yevmenkin  *
206490c2ffSMaksim Yevmenkin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216490c2ffSMaksim Yevmenkin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226490c2ffSMaksim Yevmenkin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236490c2ffSMaksim Yevmenkin  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246490c2ffSMaksim Yevmenkin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256490c2ffSMaksim Yevmenkin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266490c2ffSMaksim Yevmenkin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276490c2ffSMaksim Yevmenkin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286490c2ffSMaksim Yevmenkin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296490c2ffSMaksim Yevmenkin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306490c2ffSMaksim Yevmenkin  * SUCH DAMAGE.
316490c2ffSMaksim Yevmenkin  *
327aebfa93SMaksim Yevmenkin  * $Id: session.c,v 1.3 2006/09/07 21:06:53 max Exp $
336490c2ffSMaksim Yevmenkin  */
346490c2ffSMaksim Yevmenkin 
356490c2ffSMaksim Yevmenkin #include <sys/queue.h>
366490c2ffSMaksim Yevmenkin #include <assert.h>
378d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
386490c2ffSMaksim Yevmenkin #include <bluetooth.h>
397aebfa93SMaksim Yevmenkin #include <errno.h>
407aebfa93SMaksim Yevmenkin #include <fcntl.h>
416490c2ffSMaksim Yevmenkin #include <stdio.h>
426490c2ffSMaksim Yevmenkin #include <stdlib.h>
436490c2ffSMaksim Yevmenkin #include <string.h>
447aebfa93SMaksim Yevmenkin #include <syslog.h>
456490c2ffSMaksim Yevmenkin #include <unistd.h>
467aebfa93SMaksim Yevmenkin #include <usbhid.h>
477aebfa93SMaksim Yevmenkin #include "bthid_config.h"
486490c2ffSMaksim Yevmenkin #include "bthidd.h"
4944af5666SVladimir Kondratyev #include "btuinput.h"
503adfd74aSMaksim Yevmenkin #include "kbd.h"
516490c2ffSMaksim Yevmenkin 
526490c2ffSMaksim Yevmenkin /*
536490c2ffSMaksim Yevmenkin  * Create new session
546490c2ffSMaksim Yevmenkin  */
556490c2ffSMaksim Yevmenkin 
566490c2ffSMaksim Yevmenkin bthid_session_p
session_open(bthid_server_p srv,hid_device_p const d)577aebfa93SMaksim Yevmenkin session_open(bthid_server_p srv, hid_device_p const d)
586490c2ffSMaksim Yevmenkin {
597aebfa93SMaksim Yevmenkin 	bthid_session_p	s;
606490c2ffSMaksim Yevmenkin 
616490c2ffSMaksim Yevmenkin 	assert(srv != NULL);
627aebfa93SMaksim Yevmenkin 	assert(d != NULL);
636490c2ffSMaksim Yevmenkin 
647aebfa93SMaksim Yevmenkin 	if ((s = (bthid_session_p) malloc(sizeof(*s))) == NULL)
657aebfa93SMaksim Yevmenkin 		return (NULL);
667aebfa93SMaksim Yevmenkin 
676490c2ffSMaksim Yevmenkin 	s->srv = srv;
687aebfa93SMaksim Yevmenkin 	memcpy(&s->bdaddr, &d->bdaddr, sizeof(s->bdaddr));
693adfd74aSMaksim Yevmenkin 	s->ctrl = -1;
703adfd74aSMaksim Yevmenkin 	s->intr = -1;
717aebfa93SMaksim Yevmenkin 	s->vkbd = -1;
7244af5666SVladimir Kondratyev 	s->ctx = NULL;
737aebfa93SMaksim Yevmenkin 	s->state = CLOSED;
7444af5666SVladimir Kondratyev 	s->ukbd = -1;
7544af5666SVladimir Kondratyev 	s->umouse = -1;
7644af5666SVladimir Kondratyev 	s->obutt = 0;
777aebfa93SMaksim Yevmenkin 
787aebfa93SMaksim Yevmenkin 	s->keys1 = bit_alloc(kbd_maxkey());
797aebfa93SMaksim Yevmenkin 	if (s->keys1 == NULL) {
807aebfa93SMaksim Yevmenkin 		free(s);
817aebfa93SMaksim Yevmenkin 		return (NULL);
827aebfa93SMaksim Yevmenkin 	}
837aebfa93SMaksim Yevmenkin 
847aebfa93SMaksim Yevmenkin 	s->keys2 = bit_alloc(kbd_maxkey());
857aebfa93SMaksim Yevmenkin 	if (s->keys2 == NULL) {
867aebfa93SMaksim Yevmenkin 		free(s->keys1);
877aebfa93SMaksim Yevmenkin 		free(s);
887aebfa93SMaksim Yevmenkin 		return (NULL);
897aebfa93SMaksim Yevmenkin 	}
907aebfa93SMaksim Yevmenkin 
917aebfa93SMaksim Yevmenkin 	LIST_INSERT_HEAD(&srv->sessions, s, next);
926490c2ffSMaksim Yevmenkin 
936490c2ffSMaksim Yevmenkin 	return (s);
946490c2ffSMaksim Yevmenkin }
956490c2ffSMaksim Yevmenkin 
966490c2ffSMaksim Yevmenkin /*
9744af5666SVladimir Kondratyev  * Initialize virtual keyboard and mouse after both channels are established
9844af5666SVladimir Kondratyev  */
9944af5666SVladimir Kondratyev 
10044af5666SVladimir Kondratyev int32_t
session_run(bthid_session_p s)10144af5666SVladimir Kondratyev session_run(bthid_session_p s)
10244af5666SVladimir Kondratyev {
10344af5666SVladimir Kondratyev 	hid_device_p d = get_hid_device(&s->bdaddr);
10444af5666SVladimir Kondratyev 	struct sockaddr_l2cap   local;
10544af5666SVladimir Kondratyev 	socklen_t               len;
10644af5666SVladimir Kondratyev 
10744af5666SVladimir Kondratyev 	if (d->keyboard) {
10844af5666SVladimir Kondratyev 		/* Open /dev/vkbdctl */
10944af5666SVladimir Kondratyev 		s->vkbd = open("/dev/vkbdctl", O_RDWR);
11044af5666SVladimir Kondratyev 		if (s->vkbd < 0) {
11144af5666SVladimir Kondratyev 			syslog(LOG_ERR, "Could not open /dev/vkbdctl " \
11244af5666SVladimir Kondratyev 				"for %s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
11344af5666SVladimir Kondratyev 				strerror(errno), errno);
11444af5666SVladimir Kondratyev 			return (-1);
11544af5666SVladimir Kondratyev 		}
11644af5666SVladimir Kondratyev 		/* Register session's vkbd descriptor (if needed) for read */
11744af5666SVladimir Kondratyev 		FD_SET(s->vkbd, &s->srv->rfdset);
11844af5666SVladimir Kondratyev 		if (s->vkbd > s->srv->maxfd)
11944af5666SVladimir Kondratyev 			s->srv->maxfd = s->vkbd;
12044af5666SVladimir Kondratyev 	}
12144af5666SVladimir Kondratyev 
12244af5666SVladimir Kondratyev 	/* Pass device for probing */
12344af5666SVladimir Kondratyev 	hid_initialise(s);
12444af5666SVladimir Kondratyev 
12544af5666SVladimir Kondratyev 	/* Take local bdaddr */
12644af5666SVladimir Kondratyev 	len = sizeof(local);
12744af5666SVladimir Kondratyev 	getsockname(s->ctrl, (struct sockaddr *) &local, &len);
12844af5666SVladimir Kondratyev 
12944af5666SVladimir Kondratyev 	if (d->mouse && s->srv->uinput) {
13044af5666SVladimir Kondratyev 		s->umouse = uinput_open_mouse(d, &local.l2cap_bdaddr);
13144af5666SVladimir Kondratyev 		if (s->umouse < 0) {
13244af5666SVladimir Kondratyev 			syslog(LOG_ERR, "Could not open /dev/uinput " \
13344af5666SVladimir Kondratyev 				"for %s. %s (%d)", bt_ntoa(&s->bdaddr,
13444af5666SVladimir Kondratyev 				NULL), strerror(errno), errno);
13544af5666SVladimir Kondratyev 			return (-1);
13644af5666SVladimir Kondratyev 		}
13744af5666SVladimir Kondratyev 	}
13844af5666SVladimir Kondratyev 	if (d->keyboard && s->srv->uinput) {
13944af5666SVladimir Kondratyev 		s->ukbd = uinput_open_keyboard(d, &local.l2cap_bdaddr);
14044af5666SVladimir Kondratyev 		if (s->ukbd < 0) {
14144af5666SVladimir Kondratyev 			syslog(LOG_ERR, "Could not open /dev/uinput " \
14244af5666SVladimir Kondratyev 				"for %s. %s (%d)", bt_ntoa(&s->bdaddr,
14344af5666SVladimir Kondratyev 				NULL), strerror(errno), errno);
14444af5666SVladimir Kondratyev 			return (-1);
14544af5666SVladimir Kondratyev 		}
14644af5666SVladimir Kondratyev 		/* Register session's ukbd descriptor (if needed) for read */
14744af5666SVladimir Kondratyev 		FD_SET(s->ukbd, &s->srv->rfdset);
14844af5666SVladimir Kondratyev 		if (s->ukbd > s->srv->maxfd)
14944af5666SVladimir Kondratyev 			s->srv->maxfd = s->ukbd;
15044af5666SVladimir Kondratyev 	}
15144af5666SVladimir Kondratyev 	return (0);
15244af5666SVladimir Kondratyev }
15344af5666SVladimir Kondratyev 
15444af5666SVladimir Kondratyev /*
1556490c2ffSMaksim Yevmenkin  * Lookup session by bdaddr
1566490c2ffSMaksim Yevmenkin  */
1576490c2ffSMaksim Yevmenkin 
1586490c2ffSMaksim Yevmenkin bthid_session_p
session_by_bdaddr(bthid_server_p srv,bdaddr_p bdaddr)1596490c2ffSMaksim Yevmenkin session_by_bdaddr(bthid_server_p srv, bdaddr_p bdaddr)
1606490c2ffSMaksim Yevmenkin {
1617aebfa93SMaksim Yevmenkin 	bthid_session_p	s;
1626490c2ffSMaksim Yevmenkin 
1636490c2ffSMaksim Yevmenkin 	assert(srv != NULL);
1646490c2ffSMaksim Yevmenkin 	assert(bdaddr != NULL);
1656490c2ffSMaksim Yevmenkin 
1666490c2ffSMaksim Yevmenkin 	LIST_FOREACH(s, &srv->sessions, next)
1676490c2ffSMaksim Yevmenkin 		if (memcmp(&s->bdaddr, bdaddr, sizeof(s->bdaddr)) == 0)
1686490c2ffSMaksim Yevmenkin 			break;
1696490c2ffSMaksim Yevmenkin 
1706490c2ffSMaksim Yevmenkin 	return (s);
1716490c2ffSMaksim Yevmenkin }
1726490c2ffSMaksim Yevmenkin 
1736490c2ffSMaksim Yevmenkin /*
1746490c2ffSMaksim Yevmenkin  * Lookup session by fd
1756490c2ffSMaksim Yevmenkin  */
1766490c2ffSMaksim Yevmenkin 
1776490c2ffSMaksim Yevmenkin bthid_session_p
session_by_fd(bthid_server_p srv,int32_t fd)1787aebfa93SMaksim Yevmenkin session_by_fd(bthid_server_p srv, int32_t fd)
1796490c2ffSMaksim Yevmenkin {
1807aebfa93SMaksim Yevmenkin 	bthid_session_p	s;
1816490c2ffSMaksim Yevmenkin 
1826490c2ffSMaksim Yevmenkin 	assert(srv != NULL);
1836490c2ffSMaksim Yevmenkin 	assert(fd >= 0);
1846490c2ffSMaksim Yevmenkin 
1856490c2ffSMaksim Yevmenkin 	LIST_FOREACH(s, &srv->sessions, next)
18644af5666SVladimir Kondratyev 		if (s->ctrl == fd || s->intr == fd ||
18744af5666SVladimir Kondratyev 		    s->vkbd == fd || s->ukbd == fd)
1886490c2ffSMaksim Yevmenkin 			break;
1896490c2ffSMaksim Yevmenkin 
1906490c2ffSMaksim Yevmenkin 	return (s);
1916490c2ffSMaksim Yevmenkin }
1926490c2ffSMaksim Yevmenkin 
1936490c2ffSMaksim Yevmenkin /*
1946490c2ffSMaksim Yevmenkin  * Close session
1956490c2ffSMaksim Yevmenkin  */
1966490c2ffSMaksim Yevmenkin 
1976490c2ffSMaksim Yevmenkin void
session_close(bthid_session_p s)1986490c2ffSMaksim Yevmenkin session_close(bthid_session_p s)
1996490c2ffSMaksim Yevmenkin {
2006490c2ffSMaksim Yevmenkin 	assert(s != NULL);
2016490c2ffSMaksim Yevmenkin 	assert(s->srv != NULL);
2026490c2ffSMaksim Yevmenkin 
2036490c2ffSMaksim Yevmenkin 	LIST_REMOVE(s, next);
2046490c2ffSMaksim Yevmenkin 
2056490c2ffSMaksim Yevmenkin 	if (s->intr != -1) {
2066490c2ffSMaksim Yevmenkin 		FD_CLR(s->intr, &s->srv->rfdset);
2076490c2ffSMaksim Yevmenkin 		FD_CLR(s->intr, &s->srv->wfdset);
2086490c2ffSMaksim Yevmenkin 		close(s->intr);
2096490c2ffSMaksim Yevmenkin 
2106490c2ffSMaksim Yevmenkin 		if (s->srv->maxfd == s->intr)
2116490c2ffSMaksim Yevmenkin 			s->srv->maxfd --;
2126490c2ffSMaksim Yevmenkin 	}
2136490c2ffSMaksim Yevmenkin 
2146490c2ffSMaksim Yevmenkin 	if (s->ctrl != -1) {
2156490c2ffSMaksim Yevmenkin 		FD_CLR(s->ctrl, &s->srv->rfdset);
2166490c2ffSMaksim Yevmenkin 		FD_CLR(s->ctrl, &s->srv->wfdset);
2176490c2ffSMaksim Yevmenkin 		close(s->ctrl);
2186490c2ffSMaksim Yevmenkin 
2196490c2ffSMaksim Yevmenkin 		if (s->srv->maxfd == s->ctrl)
2206490c2ffSMaksim Yevmenkin 			s->srv->maxfd --;
2216490c2ffSMaksim Yevmenkin 	}
2226490c2ffSMaksim Yevmenkin 
2237aebfa93SMaksim Yevmenkin 	if (s->vkbd != -1) {
2247aebfa93SMaksim Yevmenkin 		FD_CLR(s->vkbd, &s->srv->rfdset);
2257aebfa93SMaksim Yevmenkin 		close(s->vkbd);
2267aebfa93SMaksim Yevmenkin 
2277aebfa93SMaksim Yevmenkin 		if (s->srv->maxfd == s->vkbd)
2287aebfa93SMaksim Yevmenkin 			s->srv->maxfd --;
2297aebfa93SMaksim Yevmenkin 	}
2307aebfa93SMaksim Yevmenkin 
23144af5666SVladimir Kondratyev 	if (s->umouse != -1)
23244af5666SVladimir Kondratyev 		close(s->umouse);
23344af5666SVladimir Kondratyev 
23444af5666SVladimir Kondratyev 	if (s->ukbd != -1) {
23544af5666SVladimir Kondratyev 		FD_CLR(s->ukbd, &s->srv->rfdset);
23644af5666SVladimir Kondratyev 		close(s->ukbd);
23744af5666SVladimir Kondratyev 
23844af5666SVladimir Kondratyev 		if (s->srv->maxfd == s->ukbd)
23944af5666SVladimir Kondratyev 			s->srv->maxfd --;
24044af5666SVladimir Kondratyev 	}
24144af5666SVladimir Kondratyev 
242a9a8884bSVladimir Kondratyev 	free(s->ctx);
2437aebfa93SMaksim Yevmenkin 	free(s->keys1);
2447aebfa93SMaksim Yevmenkin 	free(s->keys2);
2453adfd74aSMaksim Yevmenkin 
2466490c2ffSMaksim Yevmenkin 	memset(s, 0, sizeof(*s));
2476490c2ffSMaksim Yevmenkin 	free(s);
2486490c2ffSMaksim Yevmenkin }
2496490c2ffSMaksim Yevmenkin 
250