diff options
| author | Max Krasnyansky <maxk@qualcomm.com> | 2002-03-08 21:12:35 +0000 | 
|---|---|---|
| committer | Max Krasnyansky <maxk@qualcomm.com> | 2002-03-08 21:12:35 +0000 | 
| commit | c98b2f82a4e532ca61592b08e3ad60749eb9f8d7 (patch) | |
| tree | 19a3df72d2cd6a8d64b7d98473261c7e07e306a0 /tools/hcitool.c | |
Initial revision
Diffstat (limited to 'tools/hcitool.c')
| -rw-r--r-- | tools/hcitool.c | 368 | 
1 files changed, 368 insertions, 0 deletions
| diff --git a/tools/hcitool.c b/tools/hcitool.c new file mode 100644 index 00000000..4d6380fb --- /dev/null +++ b/tools/hcitool.c @@ -0,0 +1,368 @@ +/*  +	BlueZ - Bluetooth protocol stack for Linux +	Copyright (C) 2000-2001 Qualcomm Incorporated + +	Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + +	This program is free software; you can redistribute it and/or modify +	it under the terms of the GNU General Public License version 2 as +	published by the Free Software Foundation; + +	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +	IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, +	OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +	RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +	NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE +	USE OR PERFORMANCE OF THIS SOFTWARE. + +	ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, +	TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id$ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <fcntl.h> +#include <errno.h> + +#include <termios.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <asm/types.h> + +#include <bluetooth.h> +#include <hci.h> +#include <hci_lib.h> + +extern int optind,opterr,optopt; +extern char *optarg; + +static int ctl; + +static int for_each_dev(int flag, int(*func)(int d, long arg), long arg) +{ +	struct hci_dev_list_req *dl; +	struct hci_dev_req *dr; +	int i; + +	dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t)); +	if (!dl) { +		perror("Can't allocate memory"); +		return -1; +	} +	dl->dev_num = HCI_MAX_DEV; +	dr = dl->dev_req; + +	if (ioctl(ctl, HCIGETDEVLIST, (void*)dl)) { +		perror("Can't get device list"); +		return -1; +	} +	 +	if (!dl->dev_num) +		return -1; + +	for (i=0; i < dl->dev_num; i++, dr++) { +		if (dr->dev_opt & (1<<flag)) { +			if (!func || func(dr->dev_id, arg)) +				return dr->dev_id; +		} +	} +	return -1; +} + +static int other_bdaddr(int dev_id, long arg) +{ +	struct hci_dev_info di = {dev_id: dev_id}; +	if (ioctl(ctl, HCIGETDEVINFO, (void*) &di)) +		return 0; +	return bacmp((bdaddr_t *)arg, &di.bdaddr); +} + +static int get_route(bdaddr_t *bdaddr) +{ +	if (bdaddr) +		return for_each_dev(HCI_UP, other_bdaddr, (long) bdaddr); +	else +		return for_each_dev(HCI_UP, NULL, 0); +} + +static int dev_info(int dev_id, long arg) +{ +	struct hci_dev_info di = {dev_id: dev_id}; +	bdaddr_t bdaddr; +	if (ioctl(ctl, HCIGETDEVINFO, (void*) &di)) +		return 0; +	 +	baswap(&bdaddr, &di.bdaddr); +	printf("\t%s\t%s\n", di.name, batostr(&bdaddr)); +	return 0; +} + +static int conn_list(int dev_id, long arg) +{ +	struct hci_conn_list_req *cl; +	struct hci_conn_info *ci; +	int i; + +	if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) { +		perror("Can't allocate memory"); +		exit(1); +	} +	cl->dev_id = dev_id; +	cl->conn_num = 10; +	ci = cl->conn_info; + +	if (ioctl(ctl, HCIGETCONNLIST, (void*)cl)) { +		perror("Can't get connection list"); +		exit(1); +	} + +	for (i=0; i < cl->conn_num; i++, ci++) { +		bdaddr_t bdaddr; +		baswap(&bdaddr, &ci->bdaddr); +		printf("\t%s %s %s handle %d state %d lm %s\n", +			ci->out ? "<" : ">", +			ci->type == ACL_LINK ? "ACL" : "SCO", +			batostr(&bdaddr), ci->handle, +		     	ci->state, +			hci_lmtostr(ci->link_mode)); +	} +	return 0; +} + +static int find_conn(int dev_id, long arg) +{ +	struct hci_conn_list_req *cl; +	struct hci_conn_info *ci; +	int i; + +	if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) { +		perror("Can't allocate memory"); +		exit(1); +	} +	cl->dev_id = dev_id; +	cl->conn_num = 10; +	ci = cl->conn_info; + +	if (ioctl(ctl, HCIGETCONNLIST, (void*)cl)) { +		perror("Can't get connection list"); +		exit(1); +	} + +	for (i=0; i < cl->conn_num; i++, ci++) +		if (!bacmp((bdaddr_t *)arg, &ci->bdaddr)) +			return 1; +	return 0; +} + +static void cmd_dev(int dev_id, char **opt, int nopt) +{ +	printf("Devices:\n"); +	for_each_dev(HCI_UP, dev_info, 0);	 +} + +static void cmd_inq(int dev_id, char **opt, int nopt) +{ +	inquiry_info *info; +	int i, num_rsp = 0, length, flags; +	bdaddr_t bdaddr; +	 +	if (dev_id < 0) +		dev_id = get_route(NULL); +	 +	if (nopt >= 1) +		length = atoi(opt[0]); +	else +		length = 10; /* 10 seconds */ + +	flags = 0; +	if (nopt >= 2) +		flags |= !strncasecmp("f", opt[1], 1) ? IREQ_CACHE_FLUSH : 0; +		 +	printf("Inquiring ...\n"); +	info = hci_inquiry(dev_id, length, &num_rsp, NULL, flags); + +	if (!info) { +		perror("Inquiry failed."); +		exit(1); +	} + +	for (i = 0; i < num_rsp; i++) { +		baswap(&bdaddr, &(info+i)->bdaddr); +		printf("\t%s\tclock offset: 0x%4.4x\tclass: 0x%2.2x%2.2x%2.2x\n", +			batostr(&bdaddr), (info+i)->clock_offset, +			(info+i)->dev_class[2],  +			(info+i)->dev_class[1],  +			(info+i)->dev_class[0]); +	} +	free(info); +} + +static void cmd_con(int dev_id, char **opt, int nopt) +{ +	printf("Connections:\n"); +	if (dev_id < 0) +		for_each_dev(HCI_UP, conn_list, 0); +	else +		conn_list(dev_id, 0); +} + +static void cmd_cc(int dev_id, char **opt, int nopt) +{ +	bdaddr_t bdaddr; +	int dd, ptype, role; + +	if (nopt < 1) +		return; + +	baswap(&bdaddr, strtoba(opt[0])); + +	if (dev_id < 0) { +		dev_id = get_route(&bdaddr); +		if (dev_id < 0) { +			fprintf(stderr, "Device is not available.\n"); +			exit(1); +		} +	} + +	dd = hci_open_dev(dev_id); +	if (dd < 0) { +		perror("HCI device open failed"); +		exit(1); +	} + +	if (nopt >= 2) +		hci_strtoptype(opt[1], &ptype); +	else +		ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5; + +	if (nopt >= 3) +		role = !strncasecmp("m", opt[2], 1) ? 0 : 1; +	else +		role = 0; +	 +	hci_create_connection(dd, &bdaddr, ptype, role, 1000); + +	hci_close_dev(dd); +} + +static void cmd_dc(int dev_id, char **opt, int nopt) +{ +	struct hci_conn_info_req *cr; +	bdaddr_t bdaddr; +	int dd; + +	if (nopt < 1) +		return; + +	baswap(&bdaddr, strtoba(*opt)); + +	if (dev_id < 0) { +		dev_id = for_each_dev(HCI_UP, find_conn, (long) &bdaddr); +		if (dev_id < 0) { +			fprintf(stderr, "Not connected.\n"); +			exit(1); +		} +	} +  +	dd = hci_open_dev(dev_id); +	if (dd < 0) { +		perror("HCI device open failed"); +		exit(1); +	} + +        cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); +        if (!cr) +                return; + +        bacpy(&cr->bdaddr, &bdaddr); +        cr->type = ACL_LINK; +        if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { +		perror("Get connection info failed"); +                exit(1); +        } + +	hci_disconnect(dd, cr->conn_info->handle, 0, 100); + +	close(dd); +	free(cr); +} + +struct { +	char *cmd; +	void (*func)(int dev_id, char **opt, int nopt); +	char *opt; +	char *doc; +} command[] = { +	{ "dev",  cmd_dev,  0,          "Display local devices"      }, +	{ "inq",  cmd_inq,  "[lenght] [flush]", "Inquire remote devices"     }, +	{ "con",  cmd_con,  0,          "Display active connections" }, +	{ "cc",   cmd_cc,   "<bdaddr> [pkt type] [role]", "Create connection to remote device" }, +	{ "dc",	  cmd_dc,   "<bdaddr>", "Disconnect from remote device" }, +	{ NULL, NULL, 0} +}; + +static void usage(void) +{ +	int i; + +	printf("hcitool - HCI Tool\n"); +	printf("Usage:\n" +		"\thcitool [-i hciX] [command]\n"); +	printf("Commands:\n"); +	for (i=0; command[i].cmd; i++) +		printf("\t%-4s %-20s\t%s\n", command[i].cmd, +		command[i].opt ? command[i].opt : " ", +		command[i].doc); +} + +int main(int argc, char *argv[], char *env[]) +{ +	int opt, i, dev_id = -1; +	char *dev; + +	while ((opt=getopt(argc, argv, "i:h")) != EOF) { +		switch(opt) { +		case 'i': +			dev    = strdup(optarg); +			dev_id = atoi(dev + 3); +			break; + +		case 'h': +		default: +			usage(); +			exit(0); +		} +	} + +	if (argc - optind < 1) { +		usage(); +		exit(0); +	} + +	/* Open HCI socket  */ +	if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) { +		perror("Can't open HCI socket."); +		exit(1); +	} + +	for (i=0; command[i].cmd; i++) { +		if (strncmp(command[i].cmd, argv[optind], 3))  +			continue; +		optind++; +		command[i].func(dev_id, argv + optind, argc - optind); +		break; +	} + +	close(ctl); +	return 0; +} | 
