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