12281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann/* 22281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann * 32281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann * BlueZ - Bluetooth protocol stack for Linux 42281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann * 59184e2eeb7b97371c6b83b747c8984e2340d2b47Marcel Holtmann * Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org> 62281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann * 72281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann * 82281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann * This program is free software; you can redistribute it and/or modify 9632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * it under the terms of the GNU General Public License as published by 10632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * the Free Software Foundation; either version 2 of the License, or 11632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * (at your option) any later version. 122281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann * 13632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * This program is distributed in the hope that it will be useful, 14632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 15632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * GNU General Public License for more details. 172281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann * 18632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * You should have received a copy of the GNU General Public License 19632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * along with this program; if not, write to the Free Software 20632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 212281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann * 222281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann */ 232281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 242281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#ifdef HAVE_CONFIG_H 252281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <config.h> 262281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#endif 272281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 28a1bc48d15a5d6e78efe744eb7b27b6421cb7222fMarcel Holtmann#define _GNU_SOURCE 292281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <stdio.h> 302281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <errno.h> 312281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <fcntl.h> 322281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <unistd.h> 332281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <stdlib.h> 3445c36dbd276501aa76d9798a8fafe6c202db7276Marcel Holtmann#include <string.h> 352281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <syslog.h> 362281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <signal.h> 372281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <getopt.h> 382281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <sys/poll.h> 392281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <sys/ioctl.h> 402281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <sys/socket.h> 412281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 422281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <bluetooth/bluetooth.h> 432281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <bluetooth/hci.h> 442281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <bluetooth/hci_lib.h> 452281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <bluetooth/l2cap.h> 462281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <bluetooth/sdp.h> 472281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include <bluetooth/hidp.h> 482281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 4940372f9dc3ab115870a10343124216a041e55d17Marcel Holtmann#include "sdp.h" 502281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann#include "hidd.h" 512281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 52a1bc48d15a5d6e78efe744eb7b27b6421cb7222fMarcel Holtmann#ifdef NEED_PPOLL 53a1bc48d15a5d6e78efe744eb7b27b6421cb7222fMarcel Holtmann#include "ppoll.h" 54a1bc48d15a5d6e78efe744eb7b27b6421cb7222fMarcel Holtmann#endif 55a1bc48d15a5d6e78efe744eb7b27b6421cb7222fMarcel Holtmann 569fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmannenum { 579fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann NONE, 589fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann SHOW, 599fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann SERVER, 609fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann SEARCH, 619fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann CONNECT, 629fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann KILL 639fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann}; 649fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann 652281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmannstatic volatile sig_atomic_t __io_canceled = 0; 662281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 672281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmannstatic void sig_hup(int sig) 682281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann{ 692281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann} 702281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 712281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmannstatic void sig_term(int sig) 722281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann{ 732281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann __io_canceled = 1; 742281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann} 752281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 7680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmannstatic int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm) 7780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann{ 7880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann struct sockaddr_l2 addr; 7980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann struct l2cap_options opts; 8080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann int sk; 8180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 8280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) 8380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann return -1; 8480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 85bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann memset(&addr, 0, sizeof(addr)); 8680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann addr.l2_family = AF_BLUETOOTH; 8780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann bacpy(&addr.l2_bdaddr, src); 8880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 8980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 9080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(sk); 9180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann return -1; 9280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 9380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 94bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann memset(&opts, 0, sizeof(opts)); 9580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann opts.imtu = HIDP_DEFAULT_MTU; 9680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann opts.omtu = HIDP_DEFAULT_MTU; 9780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann opts.flush_to = 0xffff; 9880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 9980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)); 10080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 101bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann memset(&addr, 0, sizeof(addr)); 10280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann addr.l2_family = AF_BLUETOOTH; 10380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann bacpy(&addr.l2_bdaddr, dst); 10480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann addr.l2_psm = htobs(psm); 10580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 10680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 10780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(sk); 10880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann return -1; 10980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 11080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 11180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann return sk; 11280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann} 11380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 114462b9676004b39d4852d303b7c66fba7103ea39dMarcel Holtmannstatic int l2cap_listen(const bdaddr_t *bdaddr, unsigned short psm, int lm, int backlog) 1152281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann{ 1162281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann struct sockaddr_l2 addr; 1172281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann struct l2cap_options opts; 118462b9676004b39d4852d303b7c66fba7103ea39dMarcel Holtmann int sk; 1192281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1202281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) 1212281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return -1; 1222281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 123bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann memset(&addr, 0, sizeof(addr)); 1242281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann addr.l2_family = AF_BLUETOOTH; 1252281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann bacpy(&addr.l2_bdaddr, bdaddr); 1262281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann addr.l2_psm = htobs(psm); 1272281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1282281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1292281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann close(sk); 1302281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return -1; 1312281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann } 1322281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1332281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)); 1342281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 135bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann memset(&opts, 0, sizeof(opts)); 1362281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann opts.imtu = HIDP_DEFAULT_MTU; 1372281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann opts.omtu = HIDP_DEFAULT_MTU; 1382281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann opts.flush_to = 0xffff; 1392281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1402281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)); 1412281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1422281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if (listen(sk, backlog) < 0) { 1432281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann close(sk); 1442281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return -1; 1452281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann } 1462281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1472281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return sk; 1482281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann} 1492281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1502281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmannstatic int l2cap_accept(int sk, bdaddr_t *bdaddr) 1512281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann{ 1522281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann struct sockaddr_l2 addr; 1532281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann socklen_t addrlen; 1542281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann int nsk; 1552281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1562281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann memset(&addr, 0, sizeof(addr)); 1572281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann addrlen = sizeof(addr); 1582281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1592281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if ((nsk = accept(sk, (struct sockaddr *) &addr, &addrlen)) < 0) 1602281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return -1; 1612281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1622281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if (bdaddr) 1632281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann bacpy(bdaddr, &addr.l2_bdaddr); 1642281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 1652281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return nsk; 1662281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann} 1672281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 168853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmannstatic int request_authentication(bdaddr_t *src, bdaddr_t *dst) 169853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann{ 170853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann struct hci_conn_info_req *cr; 171853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann char addr[18]; 172853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann int err, dd, dev_id; 173853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 174853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann ba2str(src, addr); 175853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann dev_id = hci_devid(addr); 176853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (dev_id < 0) 177853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return dev_id; 178853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 179853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann dd = hci_open_dev(dev_id); 180853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (dd < 0) 181853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return dd; 182853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 183853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); 184853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (!cr) 185853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return -ENOMEM; 186853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 187853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann bacpy(&cr->bdaddr, dst); 188853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann cr->type = ACL_LINK; 189853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr); 190853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (err < 0) { 191853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann free(cr); 192853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann hci_close_dev(dd); 193853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return err; 194853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann } 195853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 196853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann err = hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000); 197853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 198853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann free(cr); 199853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann hci_close_dev(dd); 200853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 201853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return err; 202853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann} 203853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 204853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmannstatic int request_encryption(bdaddr_t *src, bdaddr_t *dst) 205853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann{ 206853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann struct hci_conn_info_req *cr; 207853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann char addr[18]; 208853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann int err, dd, dev_id; 209853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 210853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann ba2str(src, addr); 211853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann dev_id = hci_devid(addr); 212853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (dev_id < 0) 213853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return dev_id; 214853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 215853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann dd = hci_open_dev(dev_id); 216853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (dd < 0) 217853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return dd; 218853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 219853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); 220853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (!cr) 221853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return -ENOMEM; 222853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 223853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann bacpy(&cr->bdaddr, dst); 224853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann cr->type = ACL_LINK; 225853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr); 226853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (err < 0) { 227853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann free(cr); 228853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann hci_close_dev(dd); 229853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return err; 230853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann } 231853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 232853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann err = hci_encrypt_link(dd, htobs(cr->conn_info->handle), 1, 25000); 233853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 234853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann free(cr); 235853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann hci_close_dev(dd); 236853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 237853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann return err; 238853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann} 239853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 2402076574365b22a211b569a4dcc9a4df6f924f41cJohan Hedbergstatic int enable_sixaxis(int csk) 241e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann{ 242e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann const unsigned char buf[] = { 243e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann 0x53 /*HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE*/, 244e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann 0xf4, 0x42, 0x03, 0x00, 0x00 }; 245e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann 2462076574365b22a211b569a4dcc9a4df6f924f41cJohan Hedberg return write(csk, buf, sizeof(buf)); 247e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann} 248e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann 24934a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmannstatic int create_device(int ctl, int csk, int isk, uint8_t subclass, int nosdp, int nocheck, int bootonly, int encrypt, int timeout) 2502281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann{ 2512281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann struct hidp_connadd_req req; 2522281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann struct sockaddr_l2 addr; 2532281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann socklen_t addrlen; 2542281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann bdaddr_t src, dst; 2552281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann char bda[18]; 2562281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann int err; 2572281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 2582281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann memset(&addr, 0, sizeof(addr)); 2592281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann addrlen = sizeof(addr); 2602281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 2612281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if (getsockname(csk, (struct sockaddr *) &addr, &addrlen) < 0) 2622281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return -1; 2632281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 2642281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann bacpy(&src, &addr.l2_bdaddr); 2652281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 2662281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann memset(&addr, 0, sizeof(addr)); 2672281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann addrlen = sizeof(addr); 2682281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 2692281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if (getpeername(csk, (struct sockaddr *) &addr, &addrlen) < 0) 2702281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return -1; 2712281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 2722281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann bacpy(&dst, &addr.l2_bdaddr); 2732281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 2742281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann memset(&req, 0, sizeof(req)); 2752281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann req.ctrl_sock = csk; 2762281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann req.intr_sock = isk; 2772281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann req.flags = 0; 2782281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann req.idle_to = timeout * 60; 2792281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 280163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann err = get_stored_device_info(&src, &dst, &req); 281163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann if (!err) 282163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann goto create; 283163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann 284b472e4a544004e83d5d71df529ea5f3a649815f2Marcel Holtmann if (!nocheck) { 285b472e4a544004e83d5d71df529ea5f3a649815f2Marcel Holtmann ba2str(&dst, bda); 286b968e79ff86347fd918315807d71a43fb2564171Marcel Holtmann syslog(LOG_ERR, "Rejected connection from unknown device %s", bda); 287b472e4a544004e83d5d71df529ea5f3a649815f2Marcel Holtmann /* Return no error to avoid run_server() complaining too */ 288b472e4a544004e83d5d71df529ea5f3a649815f2Marcel Holtmann return 0; 289b472e4a544004e83d5d71df529ea5f3a649815f2Marcel Holtmann } 290b039c1a971aa2f4d4ca29b8453fbb2a360b5dbf7Marcel Holtmann 29123b788ad7e8009445323f65b3fb94bb6b11717d0Marcel Holtmann if (!nosdp) { 292163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann err = get_sdp_device_info(&src, &dst, &req); 29323b788ad7e8009445323f65b3fb94bb6b11717d0Marcel Holtmann if (err < 0) 29423b788ad7e8009445323f65b3fb94bb6b11717d0Marcel Holtmann goto error; 295bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann } else { 296bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann struct l2cap_conninfo conn; 297bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann socklen_t size; 298bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann uint8_t class[3]; 299bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann 300bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann memset(&conn, 0, sizeof(conn)); 301bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann size = sizeof(conn); 302bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann if (getsockopt(csk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &size) < 0) 303bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann memset(class, 0, 3); 304bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann else 305bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann memcpy(class, conn.dev_class, 3); 306bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann 307bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann if (class[1] == 0x25 && (class[2] == 0x00 || class[2] == 0x01)) 308bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann req.subclass = class[0]; 309bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann else 310bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann req.subclass = 0xc0; 311bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann } 31280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 313163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmanncreate: 314a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann if (subclass != 0x00) 315a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann req.subclass = subclass; 316a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann 31780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann ba2str(&dst, bda); 31880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann syslog(LOG_INFO, "New HID device %s (%s)", bda, req.name); 3192281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 320853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (encrypt && (req.subclass & 0x40)) { 321853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann err = request_authentication(&src, &dst); 322853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (err < 0) { 323853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann syslog(LOG_ERR, "Authentication for %s failed", bda); 324853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann goto error; 325853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann } 326853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann 327853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann err = request_encryption(&src, &dst); 328853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann if (err < 0) 329853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann syslog(LOG_ERR, "Encryption for %s failed", bda); 330dfcfad85283a8835c5b6c7fa906c4752b5e22d77Marcel Holtmann } 331dfcfad85283a8835c5b6c7fa906c4752b5e22d77Marcel Holtmann 33234a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann if (bootonly) { 33334a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann req.rd_size = 0; 33434a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann req.flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); 33534a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann } 33634a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann 337e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann if (req.vendor == 0x054c && req.product == 0x0268) 338e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann enable_sixaxis(csk); 339e10fbef05c562d175a12ab4f25ffcd12dfa871dcMarcel Holtmann 3402281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann err = ioctl(ctl, HIDPCONNADD, &req); 3412281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 342dfcfad85283a8835c5b6c7fa906c4752b5e22d77Marcel Holtmannerror: 34311e433f53e4f16a57fd2dd586d8a41fbfb8ff120Szymon Janc free(req.rd_data); 3442281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 3452281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return err; 3462281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann} 3472281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 34834a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmannstatic void run_server(int ctl, int csk, int isk, uint8_t subclass, int nosdp, int nocheck, int bootonly, int encrypt, int timeout) 3492281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann{ 3502281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann struct pollfd p[2]; 351a1bc48d15a5d6e78efe744eb7b27b6421cb7222fMarcel Holtmann sigset_t sigs; 3522281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann short events; 3532281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann int err, ncsk, nisk; 3542281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 355a1bc48d15a5d6e78efe744eb7b27b6421cb7222fMarcel Holtmann sigfillset(&sigs); 35673b9315e56f5f635eaf82a08271e8f462b731972Marcel Holtmann sigdelset(&sigs, SIGCHLD); 35773b9315e56f5f635eaf82a08271e8f462b731972Marcel Holtmann sigdelset(&sigs, SIGPIPE); 35873b9315e56f5f635eaf82a08271e8f462b731972Marcel Holtmann sigdelset(&sigs, SIGTERM); 35973b9315e56f5f635eaf82a08271e8f462b731972Marcel Holtmann sigdelset(&sigs, SIGINT); 36073b9315e56f5f635eaf82a08271e8f462b731972Marcel Holtmann sigdelset(&sigs, SIGHUP); 361a1bc48d15a5d6e78efe744eb7b27b6421cb7222fMarcel Holtmann 3622281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann p[0].fd = csk; 3632281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann p[0].events = POLLIN | POLLERR | POLLHUP; 3642281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 3652281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann p[1].fd = isk; 3662281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann p[1].events = POLLIN | POLLERR | POLLHUP; 3672281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 3682281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann while (!__io_canceled) { 3692281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann p[0].revents = 0; 3702281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann p[1].revents = 0; 3712281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 372a1bc48d15a5d6e78efe744eb7b27b6421cb7222fMarcel Holtmann if (ppoll(p, 2, NULL, &sigs) < 1) 3732281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann continue; 3742281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 3752281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann events = p[0].revents | p[1].revents; 3762281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 3772281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if (events & POLLIN) { 3782281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann ncsk = l2cap_accept(csk, NULL); 3792281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann nisk = l2cap_accept(isk, NULL); 3802281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 38134a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann err = create_device(ctl, ncsk, nisk, subclass, nosdp, nocheck, bootonly, encrypt, timeout); 3822281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if (err < 0) 3832281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann syslog(LOG_ERR, "HID create error %d (%s)", 3842281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann errno, strerror(errno)); 3852281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 3862281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann close(nisk); 387dfcfad85283a8835c5b6c7fa906c4752b5e22d77Marcel Holtmann sleep(1); 388dfcfad85283a8835c5b6c7fa906c4752b5e22d77Marcel Holtmann close(ncsk); 3892281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann } 3902281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann } 3912281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann} 3922281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 39310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmannstatic char *hidp_state[] = { 39410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "unknown", 39510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "connected", 39610d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "open", 39710d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "bound", 39810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "listening", 39910d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "connecting", 40010d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "connecting", 40110d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "config", 40210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "disconnecting", 40310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "closed" 40410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann}; 40510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 406e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmannstatic char *hidp_flagstostr(uint32_t flags) 407e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann{ 4085bec11bb84e13e200a38798271a7da8924c3f6f7Marcel Holtmann static char str[100]; 4095bec11bb84e13e200a38798271a7da8924c3f6f7Marcel Holtmann str[0] = 0; 410e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann 411e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann strcat(str, "["); 412e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann 413e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann if (flags & (1 << HIDP_BOOT_PROTOCOL_MODE)) 414e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann strcat(str, "boot-protocol"); 415e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann 416e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann strcat(str, "]"); 417e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann 418e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann return str; 419e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann} 420e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann 42110d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmannstatic void do_show(int ctl) 42210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann{ 42310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann struct hidp_connlist_req req; 42410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann struct hidp_conninfo ci[16]; 42510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann char addr[18]; 4269c0b5859e6cc4b7a0e925fde8665990281b265d3Marcel Holtmann unsigned int i; 42710d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 42810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann req.cnum = 16; 42910d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann req.ci = ci; 43010d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 43110d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann if (ioctl(ctl, HIDPGETCONNLIST, &req) < 0) { 43210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann perror("Can't get connection list"); 43310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann close(ctl); 43410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann exit(1); 43510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann } 43610d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 43710d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann for (i = 0; i < req.cnum; i++) { 43810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann ba2str(&ci[i].bdaddr, addr); 439e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann printf("%s %s [%04x:%04x] %s %s\n", addr, ci[i].name, 440e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann ci[i].vendor, ci[i].product, hidp_state[ci[i].state], 441e6d6d06c733bf8055dfdc0f9b585585cc4e450a4Marcel Holtmann ci[i].flags ? hidp_flagstostr(ci[i].flags) : ""); 44210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann } 44310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann} 44410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 44534a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmannstatic void do_connect(int ctl, bdaddr_t *src, bdaddr_t *dst, uint8_t subclass, int fakehid, int bootonly, int encrypt, int timeout) 44680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann{ 447163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann struct hidp_connadd_req req; 4483e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann uint16_t uuid = HID_SVCLASS_ID; 4493e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann uint8_t channel = 0; 4509f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann char name[256]; 45180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann int csk, isk, err; 45280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 453163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann memset(&req, 0, sizeof(req)); 4548232558057813074ce6bdb3317a9fb4888f7b8e3Johan Hedberg name[0] = '\0'; 455163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann 4563e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann err = get_sdp_device_info(src, dst, &req); 4573e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann if (err < 0 && fakehid) 4589f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann err = get_alternate_device_info(src, dst, 4599f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann &uuid, &channel, name, sizeof(name) - 1); 4603e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann 4613e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann if (err < 0) { 462163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann perror("Can't get device information"); 463163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann close(ctl); 464163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann exit(1); 465163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann } 466163d14a25cec4bbe7bf906a3a3487756a47e42cfMarcel Holtmann 4673e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann switch (uuid) { 4683e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann case HID_SVCLASS_ID: 4693e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann goto connect; 4703e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann 4713e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann case SERIAL_PORT_SVCLASS_ID: 4729f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann if (subclass == 0x40 || !strcmp(name, "Cable Replacement")) { 4739f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann if (epox_presenter(src, dst, channel) < 0) { 4749f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann close(ctl); 4759f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann exit(1); 4769f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann } 4779f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann break; 4789f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann } 4799f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann if (subclass == 0x1f || !strcmp(name, "SPP slave")) { 4809f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann if (jthree_keyboard(src, dst, channel) < 0) { 4819f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann close(ctl); 4829f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann exit(1); 4839f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann } 4849f2da763372bb5b64840443b51a02c3861c66d57Marcel Holtmann break; 485670e5ef72176dafc1bf2669d4c5c30e0db26dd71Johan Hedberg } 4866d2c7e465e4a8e3e6bb9595ccfd0f471070eda69Marcel Holtmann if (subclass == 0x02 || !strcmp(name, "Serial Port")) { 4876d2c7e465e4a8e3e6bb9595ccfd0f471070eda69Marcel Holtmann if (celluon_keyboard(src, dst, channel) < 0) { 4886d2c7e465e4a8e3e6bb9595ccfd0f471070eda69Marcel Holtmann close(ctl); 4896d2c7e465e4a8e3e6bb9595ccfd0f471070eda69Marcel Holtmann exit(1); 4906d2c7e465e4a8e3e6bb9595ccfd0f471070eda69Marcel Holtmann } 4916d2c7e465e4a8e3e6bb9595ccfd0f471070eda69Marcel Holtmann break; 4926d2c7e465e4a8e3e6bb9595ccfd0f471070eda69Marcel Holtmann } 4933e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann break; 4943e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann 4953e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann case HEADSET_SVCLASS_ID: 4963e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann case HANDSFREE_SVCLASS_ID: 497670e5ef72176dafc1bf2669d4c5c30e0db26dd71Johan Hedberg if (headset_presenter(src, dst, channel) < 0) { 498670e5ef72176dafc1bf2669d4c5c30e0db26dd71Johan Hedberg close(ctl); 499670e5ef72176dafc1bf2669d4c5c30e0db26dd71Johan Hedberg exit(1); 500670e5ef72176dafc1bf2669d4c5c30e0db26dd71Johan Hedberg } 5013e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann break; 5023e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann } 5033e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann 5043e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann return; 5053e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann 5063e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmannconnect: 50780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann csk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_CTRL); 50880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (csk < 0) { 50980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann perror("Can't create HID control channel"); 51080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(ctl); 51180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann exit(1); 51280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 51380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 51480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann isk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_INTR); 51580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (isk < 0) { 51680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann perror("Can't create HID interrupt channel"); 51780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(csk); 51880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(ctl); 51980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann exit(1); 52080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 52180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 52234a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann err = create_device(ctl, csk, isk, subclass, 1, 1, bootonly, encrypt, timeout); 52380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (err < 0) { 52480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann fprintf(stderr, "HID create error %d (%s)\n", 52580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann errno, strerror(errno)); 52680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(isk); 52780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann sleep(1); 52880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(csk); 52980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(ctl); 53080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann exit(1); 53180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 53280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann} 53380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 53434a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmannstatic void do_search(int ctl, bdaddr_t *bdaddr, uint8_t subclass, int fakehid, int bootonly, int encrypt, int timeout) 53580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann{ 53680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann inquiry_info *info = NULL; 53780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann bdaddr_t src, dst; 53880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann int i, dev_id, num_rsp, length, flags; 53980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann char addr[18]; 54080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann uint8_t class[3]; 54180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 54280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann ba2str(bdaddr, addr); 54380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann dev_id = hci_devid(addr); 54480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (dev_id < 0) { 54580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann dev_id = hci_get_route(NULL); 54680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann hci_devba(dev_id, &src); 54780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } else 54880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann bacpy(&src, bdaddr); 54980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 55080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann length = 8; /* ~10 seconds */ 55180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann num_rsp = 0; 552dfcfad85283a8835c5b6c7fa906c4752b5e22d77Marcel Holtmann flags = IREQ_CACHE_FLUSH; 55380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 55480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann printf("Searching ...\n"); 55580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 55680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags); 55780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 55880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann for (i = 0; i < num_rsp; i++) { 55980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann memcpy(class, (info+i)->dev_class, 3); 560dfcfad85283a8835c5b6c7fa906c4752b5e22d77Marcel Holtmann if (class[1] == 0x25 && (class[2] == 0x00 || class[2] == 0x01)) { 56180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann bacpy(&dst, &(info+i)->bdaddr); 56280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann ba2str(&dst, addr); 56380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 56480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann printf("\tConnecting to device %s\n", addr); 56534a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann do_connect(ctl, &src, &dst, subclass, fakehid, bootonly, encrypt, timeout); 5663e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann } 5673e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann } 5683e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann 5693e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann if (!fakehid) 5703e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann goto done; 5713e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann 5723e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann for (i = 0; i < num_rsp; i++) { 5733e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann memcpy(class, (info+i)->dev_class, 3); 574588f659f3f2f725b10f67c81ad1c5755181f93caJosé Antonio Santos Cadenas if ((class[0] == 0x00 && class[2] == 0x00 && 5756d2c7e465e4a8e3e6bb9595ccfd0f471070eda69Marcel Holtmann (class[1] == 0x40 || class[1] == 0x1f)) || 5766d2c7e465e4a8e3e6bb9595ccfd0f471070eda69Marcel Holtmann (class[0] == 0x10 && class[1] == 0x02 && class[2] == 0x40)) { 5773e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann bacpy(&dst, &(info+i)->bdaddr); 5783e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann ba2str(&dst, addr); 5793e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann 5803e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmann printf("\tConnecting to device %s\n", addr); 58134a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann do_connect(ctl, &src, &dst, subclass, 1, bootonly, 0, timeout); 58280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 58380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 58480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 5853e9d510274d6560e026c76dc3ecf415db0dd7e68Marcel Holtmanndone: 5867ba9b7fda144865222a5d254b36bf484d5af99e7Marcel Holtmann bt_free(info); 58780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 58880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (!num_rsp) { 58980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann fprintf(stderr, "\tNo devices in range or visible\n"); 59080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(ctl); 59180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann exit(1); 59280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 59380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann} 59480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 59510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmannstatic void do_kill(int ctl, bdaddr_t *bdaddr, uint32_t flags) 59610d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann{ 59710d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann struct hidp_conndel_req req; 59810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann struct hidp_connlist_req cl; 59910d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann struct hidp_conninfo ci[16]; 6009c0b5859e6cc4b7a0e925fde8665990281b265d3Marcel Holtmann unsigned int i; 60110d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 60210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann if (!bacmp(bdaddr, BDADDR_ALL)) { 60310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann cl.cnum = 16; 60410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann cl.ci = ci; 60510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 60610d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann if (ioctl(ctl, HIDPGETCONNLIST, &cl) < 0) { 60710d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann perror("Can't get connection list"); 60810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann close(ctl); 60910d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann exit(1); 61010d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann } 61110d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 61210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann for (i = 0; i < cl.cnum; i++) { 61310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann bacpy(&req.bdaddr, &ci[i].bdaddr); 61410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann req.flags = flags; 61510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 61610d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { 61710d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann perror("Can't release connection"); 61810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann close(ctl); 61910d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann exit(1); 62010d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann } 62110d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann } 62210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 62310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann } else { 62410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann bacpy(&req.bdaddr, bdaddr); 62510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann req.flags = flags; 62610d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 62710d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { 62810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann perror("Can't release connection"); 62910d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann close(ctl); 63010d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann exit(1); 63110d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann } 63210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann } 63310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann} 63410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 6352281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmannstatic void usage(void) 6362281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann{ 6374b5556bbbb60803559de24a46a15d7533d397041Marcel Holtmann printf("hidd - Bluetooth HID daemon version %s\n\n", VERSION); 6382281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 6392281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann printf("Usage:\n" 64080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann "\thidd [options] [commands]\n" 6412281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann "\n"); 6422281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 6432281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann printf("Options:\n" 6442281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann "\t-i <hciX|bdaddr> Local HCI device or BD Address\n" 6452281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann "\t-t <timeout> Set idle timeout (in minutes)\n" 646a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann "\t-b <subclass> Overwrite the boot mode subclass\n" 6472281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann "\t-n, --nodaemon Don't fork daemon to background\n" 6482281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann "\t-h, --help Display help\n" 6492281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann "\n"); 65080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 65180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann printf("Commands:\n" 65280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann "\t--server Start HID server\n" 65380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann "\t--search Search for HID devices\n" 65480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann "\t--connect <bdaddr> Connect remote HID device\n" 6557ef1d3ac012443faf2b369aabc3dc209cf5042eaMarcel Holtmann "\t--unplug <bdaddr> Unplug the HID connection\n" 65610d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "\t--kill <bdaddr> Terminate HID connection\n" 65710d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "\t--killall Terminate all connections\n" 65810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann "\t--show List current HID connections\n" 65980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann "\n"); 6602281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann} 6612281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 6622281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmannstatic struct option main_options[] = { 6632281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann { "help", 0, 0, 'h' }, 6642281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann { "nodaemon", 0, 0, 'n' }, 665a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann { "subclass", 1, 0, 'b' }, 6662281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann { "timeout", 1, 0, 't' }, 6672281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann { "device", 1, 0, 'i' }, 668462b9676004b39d4852d303b7c66fba7103ea39dMarcel Holtmann { "master", 0, 0, 'M' }, 669853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann { "encrypt", 0, 0, 'E' }, 67023b788ad7e8009445323f65b3fb94bb6b11717d0Marcel Holtmann { "nosdp", 0, 0, 'D' }, 671b039c1a971aa2f4d4ca29b8453fbb2a360b5dbf7Marcel Holtmann { "nocheck", 0, 0, 'Z' }, 67234a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann { "bootonly", 0, 0, 'B' }, 6739505d0aad9044b60d3a3f8374bf238a68055472aJohan Hedberg { "hidonly", 0, 0, 'H' }, 67410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann { "show", 0, 0, 'l' }, 67510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann { "list", 0, 0, 'l' }, 67680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann { "server", 0, 0, 'd' }, 67780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann { "listen", 0, 0, 'd' }, 67880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann { "search", 0, 0, 's' }, 67910d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann { "create", 1, 0, 'c' }, 68080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann { "connect", 1, 0, 'c' }, 68110d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann { "disconnect", 1, 0, 'k' }, 68210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann { "terminate", 1, 0, 'k' }, 68310d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann { "release", 1, 0, 'k' }, 68410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann { "kill", 1, 0, 'k' }, 685052d647c87405e41604245f2afaee1652457b508Marcel Holtmann { "killall", 0, 0, 'K' }, 6867ef1d3ac012443faf2b369aabc3dc209cf5042eaMarcel Holtmann { "unplug", 1, 0, 'u' }, 6872281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann { 0, 0, 0, 0 } 6882281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann}; 6892281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 6902281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmannint main(int argc, char *argv[]) 6912281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann{ 6922281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann struct sigaction sa; 69380ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann bdaddr_t bdaddr, dev; 6947ef1d3ac012443faf2b369aabc3dc209cf5042eaMarcel Holtmann uint32_t flags = 0; 695a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann uint8_t subclass = 0x00; 6962281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann char addr[18]; 6972281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann int log_option = LOG_NDELAY | LOG_PID; 698b102348e988e4abc5d579ce13c067ce2c885aaf7Marcel Holtmann int opt, ctl, csk, isk; 699b102348e988e4abc5d579ce13c067ce2c885aaf7Marcel Holtmann int mode = SHOW, detach = 1, nosdp = 0, nocheck = 0, bootonly = 0; 700b039c1a971aa2f4d4ca29b8453fbb2a360b5dbf7Marcel Holtmann int fakehid = 1, encrypt = 0, timeout = 30, lm = 0; 7012281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 7022281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann bacpy(&bdaddr, BDADDR_ANY); 7032281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 7049505d0aad9044b60d3a3f8374bf238a68055472aJohan Hedberg while ((opt = getopt_long(argc, argv, "+i:nt:b:MEDZBHldsc:k:Ku:h", main_options, NULL)) != -1) { 7052281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann switch(opt) { 7062281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann case 'i': 7072281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if (!strncasecmp(optarg, "hci", 3)) 7082281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann hci_devba(atoi(optarg + 3), &bdaddr); 7092281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann else 7102281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann str2ba(optarg, &bdaddr); 7112281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann break; 7122281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann case 'n': 713b102348e988e4abc5d579ce13c067ce2c885aaf7Marcel Holtmann detach = 0; 7142281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann break; 7152281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann case 't': 7162281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann timeout = atoi(optarg); 7172281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann break; 718a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann case 'b': 719a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann if (!strncasecmp(optarg, "0x", 2)) 720a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann subclass = (uint8_t) strtol(optarg, NULL, 16); 721a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann else 722a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann subclass = atoi(optarg); 723a488cafcdbd15928f43cbe3096853b894a4cc63fMarcel Holtmann break; 724462b9676004b39d4852d303b7c66fba7103ea39dMarcel Holtmann case 'M': 725462b9676004b39d4852d303b7c66fba7103ea39dMarcel Holtmann lm |= L2CAP_LM_MASTER; 726462b9676004b39d4852d303b7c66fba7103ea39dMarcel Holtmann break; 727853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann case 'E': 728853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann encrypt = 1; 729853ed92c6a6a97a202ca5a4dcb495197b3c3cc9eMarcel Holtmann break; 73023b788ad7e8009445323f65b3fb94bb6b11717d0Marcel Holtmann case 'D': 73123b788ad7e8009445323f65b3fb94bb6b11717d0Marcel Holtmann nosdp = 1; 73223b788ad7e8009445323f65b3fb94bb6b11717d0Marcel Holtmann break; 733b039c1a971aa2f4d4ca29b8453fbb2a360b5dbf7Marcel Holtmann case 'Z': 734b039c1a971aa2f4d4ca29b8453fbb2a360b5dbf7Marcel Holtmann nocheck = 1; 735b039c1a971aa2f4d4ca29b8453fbb2a360b5dbf7Marcel Holtmann break; 73634a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann case 'B': 73734a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann bootonly = 1; 73834a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann break; 7399505d0aad9044b60d3a3f8374bf238a68055472aJohan Hedberg case 'H': 7409505d0aad9044b60d3a3f8374bf238a68055472aJohan Hedberg fakehid = 0; 7419505d0aad9044b60d3a3f8374bf238a68055472aJohan Hedberg break; 74210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann case 'l': 7439fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann mode = SHOW; 74410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann break; 74580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann case 'd': 7469fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann mode = SERVER; 74780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann break; 74880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann case 's': 7499fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann mode = SEARCH; 75080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann break; 75180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann case 'c': 75280ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann str2ba(optarg, &dev); 7539fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann mode = CONNECT; 75480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann break; 75510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann case 'k': 75610d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann str2ba(optarg, &dev); 7579fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann mode = KILL; 75810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann break; 75910d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann case 'K': 76010d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann bacpy(&dev, BDADDR_ALL); 7619fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann mode = KILL; 76210d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann break; 7637ef1d3ac012443faf2b369aabc3dc209cf5042eaMarcel Holtmann case 'u': 7647ef1d3ac012443faf2b369aabc3dc209cf5042eaMarcel Holtmann str2ba(optarg, &dev); 7657ef1d3ac012443faf2b369aabc3dc209cf5042eaMarcel Holtmann flags = (1 << HIDP_VIRTUAL_CABLE_UNPLUG); 7669fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann mode = KILL; 7677ef1d3ac012443faf2b369aabc3dc209cf5042eaMarcel Holtmann break; 7682281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann case 'h': 7692281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann usage(); 7702281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann exit(0); 7712281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann default: 7722281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann exit(0); 7732281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann } 7742281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann } 7752281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 7762281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann ba2str(&bdaddr, addr); 7772281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 77880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); 77980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (ctl < 0) { 78080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann perror("Can't open HIDP control socket"); 7812281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann exit(1); 7822281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann } 7832281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 78480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann switch (mode) { 7859fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann case SERVER: 786462b9676004b39d4852d303b7c66fba7103ea39dMarcel Holtmann csk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_CTRL, lm, 10); 78780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (csk < 0) { 78880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann perror("Can't listen on HID control channel"); 78980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(ctl); 79080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann exit(1); 79180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 7922281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 793462b9676004b39d4852d303b7c66fba7103ea39dMarcel Holtmann isk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_INTR, lm, 10); 79480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann if (isk < 0) { 79580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann perror("Can't listen on HID interrupt channel"); 79680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(ctl); 79780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(csk); 79880ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann exit(1); 79980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann } 80080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann break; 80180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 8029fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann case SEARCH: 80334a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann do_search(ctl, &bdaddr, subclass, fakehid, bootonly, encrypt, timeout); 80480ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(ctl); 80580ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann exit(0); 80680ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 8079fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann case CONNECT: 80834a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann do_connect(ctl, &bdaddr, &dev, subclass, fakehid, bootonly, encrypt, timeout); 80980ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(ctl); 81080ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann exit(0); 81180ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann 8129fb18057b298238f576aa57a95fed56e1743a3e9Marcel Holtmann case KILL: 8137ef1d3ac012443faf2b369aabc3dc209cf5042eaMarcel Holtmann do_kill(ctl, &dev, flags); 81410d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann close(ctl); 81510d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann exit(0); 81610d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann 81780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann default: 81810d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann do_show(ctl); 81910d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann close(ctl); 82010d6e9e4f785f220fb4d95402c56035e8a4dc1d3Marcel Holtmann exit(0); 8212281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann } 8222281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 823b102348e988e4abc5d579ce13c067ce2c885aaf7Marcel Holtmann if (detach) { 824b102348e988e4abc5d579ce13c067ce2c885aaf7Marcel Holtmann if (daemon(0, 0)) { 825b102348e988e4abc5d579ce13c067ce2c885aaf7Marcel Holtmann perror("Can't start daemon"); 826b102348e988e4abc5d579ce13c067ce2c885aaf7Marcel Holtmann exit(1); 827b102348e988e4abc5d579ce13c067ce2c885aaf7Marcel Holtmann } 8282281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann } else 8292281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann log_option |= LOG_PERROR; 8302281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 8312281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann openlog("hidd", log_option, LOG_DAEMON); 8322281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 8332281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann if (bacmp(&bdaddr, BDADDR_ANY)) 8342281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann syslog(LOG_INFO, "Bluetooth HID daemon (%s)", addr); 8352281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann else 8362281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann syslog(LOG_INFO, "Bluetooth HID daemon"); 8372281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 8382281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann memset(&sa, 0, sizeof(sa)); 8392281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann sa.sa_flags = SA_NOCLDSTOP; 8402281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 8412281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann sa.sa_handler = sig_term; 8422281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann sigaction(SIGTERM, &sa, NULL); 8432281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann sigaction(SIGINT, &sa, NULL); 8442281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann sa.sa_handler = sig_hup; 8452281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann sigaction(SIGHUP, &sa, NULL); 8462281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 8472281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann sa.sa_handler = SIG_IGN; 8482281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann sigaction(SIGCHLD, &sa, NULL); 8492281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann sigaction(SIGPIPE, &sa, NULL); 8502281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 85134a99c66c24e032965834fd39ffe9e506bee91a0Marcel Holtmann run_server(ctl, csk, isk, subclass, nosdp, nocheck, bootonly, encrypt, timeout); 8522281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 8532281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann syslog(LOG_INFO, "Exit"); 8542281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 8552281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann close(csk); 8562281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann close(isk); 85780ada658e05a09941ce901be73b0353ac023c32cMarcel Holtmann close(ctl); 8582281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann 8592281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann return 0; 8602281c91ec70741bd49a26f4f5bd92abceca49ed5Marcel Holtmann} 861