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