diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2004-05-07 22:32:22 +0000 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2004-05-07 22:32:22 +0000 | 
| commit | 80ada658e05a09941ce901be73b0353ac023c32c (patch) | |
| tree | d7a613c0aba72bffdf584ef8a415b1851a0dfa13 /hidd/main.c | |
| parent | e02418e9d5439bf9f74febd1a98a3769fac98c81 (diff) | |
Add connect and search options to the HID daemon
Diffstat (limited to 'hidd/main.c')
| -rw-r--r-- | hidd/main.c | 205 | 
1 files changed, 178 insertions, 27 deletions
| diff --git a/hidd/main.c b/hidd/main.c index 46b25ec4..aa2a7b1f 100644 --- a/hidd/main.c +++ b/hidd/main.c @@ -63,6 +63,42 @@ static void sig_term(int sig)  	__io_canceled = 1;  } +static int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm) +{ +	struct sockaddr_l2 addr; +	struct l2cap_options opts; +	int sk; + +	if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) +		return -1; + +	addr.l2_family  = AF_BLUETOOTH; +	bacpy(&addr.l2_bdaddr, src); +	addr.l2_psm = 0; + +	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		close(sk); +		return -1; +	} + +	opts.imtu = HIDP_DEFAULT_MTU; +	opts.omtu = HIDP_DEFAULT_MTU; +	opts.flush_to = 0xffff; + +	setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)); + +	addr.l2_family  = AF_BLUETOOTH; +	bacpy(&addr.l2_bdaddr, dst); +	addr.l2_psm = htobs(psm); + +	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		close(sk); +		return -1; +	} + +	return sk; +} +  static int l2cap_listen(const bdaddr_t *bdaddr, unsigned short psm, int backlog)  {  	struct sockaddr_l2 addr; @@ -115,7 +151,7 @@ static int l2cap_accept(int sk, bdaddr_t *bdaddr)  	return nsk;  } -static int create(int ctl, int csk, int isk, int timeout) +static int create_device(int ctl, int csk, int isk, int timeout)  {  	struct hidp_connadd_req req;  	struct sockaddr_l2 addr; @@ -140,16 +176,18 @@ static int create(int ctl, int csk, int isk, int timeout)  	bacpy(&dst, &addr.l2_bdaddr); -	ba2str(&dst, bda); -	syslog(LOG_INFO, "New HID connection from %s", bda); -  	memset(&req, 0, sizeof(req));  	req.ctrl_sock = csk;  	req.intr_sock = isk;  	req.flags     = 0;  	req.idle_to   = timeout * 60; -	get_hid_device_info(&src, &dst, &req); +	err = get_hid_device_info(&src, &dst, &req); +	if (err < 0) +		return err; + +	ba2str(&dst, bda); +	syslog(LOG_INFO, "New HID device %s (%s)", bda, req.name);  	err = ioctl(ctl, HIDPCONNADD, &req); @@ -159,7 +197,7 @@ static int create(int ctl, int csk, int isk, int timeout)  	return err;  } -static void run(int ctl, int csk, int isk, int timeout) +static void run_server(int ctl, int csk, int isk, int timeout)  {  	struct pollfd p[2];  	short events; @@ -185,7 +223,7 @@ static void run(int ctl, int csk, int isk, int timeout)  			ncsk = l2cap_accept(csk, NULL);  			nisk = l2cap_accept(isk, NULL); -			err = create(ctl, ncsk, nisk, timeout); +			err = create_device(ctl, ncsk, nisk, timeout);  			if (err < 0)  				syslog(LOG_ERR, "HID create error %d (%s)",  						errno, strerror(errno)); @@ -196,12 +234,87 @@ static void run(int ctl, int csk, int isk, int timeout)  	}  } +static void do_connect(int ctl, bdaddr_t *src, bdaddr_t *dst, int timeout) +{ +	int csk, isk, err; + +	csk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_CTRL); +	if (csk < 0) { +		perror("Can't create HID control channel"); +		close(ctl); +		exit(1); +	} + +	isk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_INTR); +	if (isk < 0) { +		perror("Can't create HID interrupt channel"); +		close(csk); +		close(ctl); +		exit(1); +	} + +	err = create_device(ctl, csk, isk, timeout); +	if (err < 0) { +		fprintf(stderr, "HID create error %d (%s)\n", +						errno, strerror(errno)); +		close(isk); +		sleep(1); +		close(csk); +		close(ctl); +		exit(1); +	} +} + +static void do_search(int ctl, bdaddr_t *bdaddr, int timeout) +{ +	inquiry_info *info = NULL; +	bdaddr_t src, dst; +	int i, dev_id, num_rsp, length, flags; +	char addr[18]; +	uint8_t class[3]; + +	ba2str(bdaddr, addr); +	dev_id = hci_devid(addr); +	if (dev_id < 0) { +		dev_id = hci_get_route(NULL); +		hci_devba(dev_id, &src); +	} else +		bacpy(&src, bdaddr); + +	length  = 8;	/* ~10 seconds */ +	num_rsp = 0; +	flags   = 0; + +	printf("Searching ...\n"); + +	num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags); + +	for (i = 0; i < num_rsp; i++) { +		memcpy(class, (info+i)->dev_class, 3); +		if (class[1] == 0x25 && class[2] == 0x00) { +			bacpy(&dst, &(info+i)->bdaddr); +			ba2str(&dst, addr); + +			printf("\tConnecting to device %s\n", addr); +			do_connect(ctl, &src, &dst, timeout); +		} +	} + +	free(info); + +	if (!num_rsp) { +		fprintf(stderr, "\tNo devices in range or visible\n"); +		close(ctl); +		exit(1); +	} +} +  static void usage(void)  {  	printf("hidd - Bluetooth HID daemon\n\n");  	printf("Usage:\n" -		"\thidd [options]\n" +		"\thidd [options] [commands]\n"  		"\n");  	printf("Options:\n" @@ -210,6 +323,12 @@ static void usage(void)  		"\t-n, --nodaemon       Don't fork daemon to background\n"  		"\t-h, --help           Display help\n"  		"\n"); + +	printf("Commands:\n" +		"\t--server             Start HID server\n" +		"\t--search             Search for HID devices\n" +		"\t--connect <bdaddr>   Connect remote HID device\n" +		"\n");  }  static struct option main_options[] = { @@ -217,21 +336,25 @@ static struct option main_options[] = {  	{ "nodaemon",	0, 0, 'n' },  	{ "timeout",	1, 0, 't' },  	{ "device",	1, 0, 'i' }, +	{ "server",	0, 0, 'd' }, +	{ "listen",	0, 0, 'd' }, +	{ "search",	0, 0, 's' }, +	{ "connect",	1, 0, 'c' },  	{ 0, 0, 0, 0 }  };  int main(int argc, char *argv[])  {  	struct sigaction sa; -	bdaddr_t bdaddr; +	bdaddr_t bdaddr, dev;  	char addr[18];  	int log_option = LOG_NDELAY | LOG_PID;  	int opt, fd, ctl, csk, isk; -	int daemon = 1, timeout = 30; +	int mode = 0, daemon = 1, timeout = 30;  	bacpy(&bdaddr, BDADDR_ANY); -	while ((opt = getopt_long(argc, argv, "+i:nt:h", main_options, NULL)) != -1) { +	while ((opt = getopt_long(argc, argv, "+i:nt:dsc:h", main_options, NULL)) != -1) {  		switch(opt) {  		case 'i':  			if (!strncasecmp(optarg, "hci", 3)) @@ -245,6 +368,16 @@ int main(int argc, char *argv[])  		case 't':  			timeout = atoi(optarg);  			break; +		case 'd': +			mode = 1; +			break; +		case 's': +			mode = 2; +			break; +		case 'c': +			str2ba(optarg, &dev); +			mode = 3; +			break;  		case 'h':  			usage();  			exit(0); @@ -255,24 +388,42 @@ int main(int argc, char *argv[])  	ba2str(&bdaddr, addr); -	csk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_CTRL, 10); -	if (csk < 0) { -		perror("Can't listen on HID control channel"); +	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); +	if (ctl < 0) { +		perror("Can't open HIDP control socket");  		exit(1);  	} -	isk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_INTR, 10); -	if (isk < 0) { -		perror("Can't listen on HID interrupt channel"); -		close(csk); -		exit(1); -	} +	switch (mode) { +	case 1: +		csk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_CTRL, 10); +		if (csk < 0) { +			perror("Can't listen on HID control channel"); +			close(ctl); +			exit(1); +		} -	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); -	if (ctl < 0) { -		perror("Can't open HIDP control socket"); -		close(csk); -		close(isk); +		isk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_INTR, 10); +		if (isk < 0) { +			perror("Can't listen on HID interrupt channel"); +			close(ctl); +			close(csk); +			exit(1); +		} +		break; + +	case 2: +		do_search(ctl, &bdaddr, timeout); +		close(ctl); +		exit(0); + +	case 3: +		do_connect(ctl, &bdaddr, &dev, timeout); +		close(ctl); +		exit(0); + +	default: +		usage();  		exit(1);  	} @@ -309,13 +460,13 @@ int main(int argc, char *argv[])  	sigaction(SIGCHLD, &sa, NULL);  	sigaction(SIGPIPE, &sa, NULL); -	run(ctl, csk, isk, timeout); +	run_server(ctl, csk, isk, timeout);  	syslog(LOG_INFO, "Exit"); -	close(ctl);  	close(csk);  	close(isk); +	close(ctl);  	return 0;  } | 
