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 56 bthid_session_p 57 session_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 100 int32_t 101 session_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 158 bthid_session_p 159 session_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 177 bthid_session_p 178 session_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 197 void 198 session_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