diff options
| -rw-r--r-- | tools/hcitool.c | 397 | 
1 files changed, 313 insertions, 84 deletions
| diff --git a/tools/hcitool.c b/tools/hcitool.c index 96448533..35509f22 100644 --- a/tools/hcitool.c +++ b/tools/hcitool.c @@ -36,6 +36,7 @@  #include <termios.h>  #include <fcntl.h> +#include <getopt.h>  #include <sys/ioctl.h>  #include <sys/socket.h>  #include <asm/types.h> @@ -48,6 +49,8 @@  extern int optind,opterr,optopt;  extern char *optarg; +#define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, NULL)) != -1) +  static int ctl;  static void usage(void); @@ -232,29 +235,79 @@ static void hex_dump(char *pref, int width, unsigned char *buf, int len)  		printf("\n");  } -static void cmd_dev(int dev_id, char **opt, int nopt) +/* Display local devices */ + +static struct option dev_options[] = { +	{"help",    0,0, 'h'}, +	{0, 0, 0, 0} +}; + +static char *dev_help =  +	"Usage:\n" +	"\tdev\n"; + +static void cmd_dev(int dev_id, int argc, char **argv)  { +	int opt; +	for_each_opt(opt, dev_options, NULL) { +		switch(opt) { +		default: +			printf(dev_help); +			return; +		} +	} +  	printf("Devices:\n");  	for_each_dev(HCI_UP, dev_info, 0);  } -static void cmd_inq(int dev_id, char **opt, int nopt) +/* Inquiry */ + +static struct option inq_options[] = { +	{"help",    0,0, 'h'}, +	{"length",  1,0, 'l'}, +	{"numrsp",  1,0, 'n'}, +	{"flush",   0,0, 'f'}, +	{0, 0, 0, 0} +}; + +static char *inq_help =  +	"Usage:\n" +	"\tinq [--length=N] [--numrsp=N] [--flush]\n"; + +static void cmd_inq(int dev_id, int argc, char **argv)  { +	int num_rsp, length, flags;  	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 = 8; /* ~ 10 seconds */ +	int i, opt; +	length  = 8;  /* ~10 seconds */ +	num_rsp = 10;  	flags = 0; -	if (nopt >= 2) -		flags |= !strncasecmp("f", opt[1], 1) ? IREQ_CACHE_FLUSH : 0; + +	for_each_opt(opt, inq_options, NULL) { +		switch(opt) { +		case 'l': +			length = atoi(optarg); +			break; +		 +		case 'n': +			num_rsp = atoi(optarg); +			break; + +		case 'f': +			flags |= IREQ_CACHE_FLUSH; +			break; + +		default: +			printf(inq_help); +			return; +		} +	} + +	if (dev_id < 0) +		dev_id = get_route(NULL);  	printf("Inquiring ...\n");  	info = hci_inquiry(dev_id, length, &num_rsp, NULL, flags); @@ -275,25 +328,54 @@ static void cmd_inq(int dev_id, char **opt, int nopt)  	free(info);  } -static void cmd_scan(int dev_id, char **opt, int nopt) +/* Device scanning */ + +static struct option scan_options[] = { +	{"help",    0,0, 'h'}, +	{"length",  1,0, 'l'}, +	{"numrsp",  1,0, 'n'}, +	{"flush",   0,0, 'f'}, +	{0, 0, 0, 0} +}; + +static char *scan_help =  +	"Usage:\n" +	"\tscan [--length=N] [--numrsp=N] [--flush]\n"; + +static void cmd_scan(int dev_id, int argc, char **argv)  {  	inquiry_info *info; -	int i, num_rsp = 0, length, flags; +	int num_rsp, length, flags;  	bdaddr_t bdaddr;  	char name[248]; -	int dd; +	int i, opt, dd; -	if (dev_id < 0) -		dev_id = get_route(NULL); +	length  = 8;  /* ~10 seconds */ +	num_rsp = 10; +	flags = 0; -	if (nopt >= 1) -		length = atoi(opt[0]); -	else -		length = 8; /* ~ 10 seconds */ +	for_each_opt(opt, scan_options, NULL) { +		switch(opt) { +		case 'l': +			length = atoi(optarg); +			break; +		 +		case 'n': +			num_rsp = atoi(optarg); +			break; -	flags = 0; -	if (nopt >= 2) -		flags |= !strncasecmp("f", opt[1], 1) ? IREQ_CACHE_FLUSH : 0; +		case 'f': +			flags |= IREQ_CACHE_FLUSH; +			break; + +		default: +			printf(scan_help); +			return; +		} +	} + +	if (dev_id < 0) +		dev_id = get_route(NULL);  	printf("Scanning ...\n");  	info = hci_inquiry(dev_id, length, &num_rsp, NULL, flags); @@ -315,19 +397,42 @@ static void cmd_scan(int dev_id, char **opt, int nopt)  	free(info);  } -static void cmd_info(int dev_id, char **opt, int nopt) +/* Info about remote device */ + +static struct option info_options[] = { +	{"help",    0,0, 'h'}, +	{0, 0, 0, 0} +}; + +static char *info_help =  +	"Usage:\n" +	"\tinfo <bdaddr>\n"; + +static void cmd_info(int dev_id, int argc, char **argv)  {  	bdaddr_t bdaddr;  	uint16_t handle; -	int dd;  	char name[248];  	unsigned char features[8];  	struct hci_version version; +	int opt, dd; + +	for_each_opt(opt, info_options, NULL) { +		switch(opt) { +		default: +			printf(info_help); +			return; +		} +	} +	argc -= optind; +	argv += optind; -	if (nopt < 1) +	if (argc < 1) { +		printf(info_help);  		return; +	} -	baswap(&bdaddr, strtoba(opt[0])); +	baswap(&bdaddr, strtoba(argv[0]));  	if (dev_id < 0) {  		dev_id = get_route(&bdaddr); @@ -345,7 +450,7 @@ static void cmd_info(int dev_id, char **opt, int nopt)  		exit(1);  	} -	printf("\tBD Address:  %s\n", opt[0]); +	printf("\tBD Address:  %s\n", argv[0]);  	if (hci_create_connection(dd, &bdaddr, 0x0008 | 0x0010, 0, 0, &handle, 25000) < 0) {  		close(dd); @@ -372,17 +477,40 @@ static void cmd_info(int dev_id, char **opt, int nopt)  	close(dd);  } -static void cmd_cmd(int dev_id, char **opt, int nopt) +/* Send arbitrary HCI commands */ + +static struct option cmd_options[] = { +	{"help",    0,0, 'h'}, +	{0, 0, 0, 0} +}; + +static char *cmd_help =  +	"Usage:\n" +	"\tcmd <ogf> <ocf> [parameters]\n" +	"Example:\n" +	"\tcmd 0x03 0x0013 0x41 0x42 0x43 0x44\n"; + +static void cmd_cmd(int dev_id, int argc, char **argv)  {  	char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;  	struct hci_filter flt;  	hci_event_hdr *hdr; -	int i, len, dd; +	int i, opt, len, dd;  	uint16_t ocf;  	uint8_t  ogf; -	if (nopt < 2) { -		usage(); +	for_each_opt(opt, cmd_options, NULL) { +		switch(opt) { +		default: +			printf(cmd_help); +			return; +		} +	} +	argc -= optind; +	argv += optind; + +	if (argc < 2) { +		printf(cmd_help);  		return;  	} @@ -390,15 +518,15 @@ static void cmd_cmd(int dev_id, char **opt, int nopt)  		dev_id = get_route(NULL);  	errno = 0; -	ogf = strtol(opt[0], NULL, 16); -	ocf = strtol(opt[1], NULL, 16); +	ogf = strtol(argv[0], NULL, 16); +	ocf = strtol(argv[1], NULL, 16);  	if (errno == ERANGE || (ogf > 0x3f) || (ocf > 0x3ff)) { -		usage(); +		printf(cmd_help);  		return;  	} -	for (i = 2, len = 0; i < nopt && len < sizeof(buf); i++, len++) -		*ptr++ = (uint8_t) strtol(opt[i], NULL, 16); +	for (i = 2, len = 0; i < argc && len < sizeof(buf); i++, len++) +		*ptr++ = (uint8_t) strtol(argv[i], NULL, 16);  	dd = hci_open_dev(dev_id);  	if (dd < 0) { @@ -440,16 +568,58 @@ static void cmd_cmd(int dev_id, char **opt, int nopt)  	return;  } -static void cmd_rev(int dev_id, char **opt, int nopt) +/* Display revision info */ + +static struct option rev_options[] = { +	{"help",    0,0, 'h'}, +	{0, 0, 0, 0} +}; + +static char *rev_help =  +	"Usage:\n" +	"\trev\n"; + +static void cmd_rev(int dev_id, int argc, char **argv)  { +	int opt; + +	for_each_opt(opt, rev_options, NULL) { +		switch(opt) { +		default: +			printf(rev_help); +			return; +		} +	} +          if (dev_id < 0)                  for_each_dev(HCI_UP, rev_info, 0);          else                  rev_info(dev_id, 0);  } -static void cmd_con(int dev_id, char **opt, int nopt) +/* Display active connections */ + +static struct option con_options[] = { +	{"help",    0,0, 'h'}, +	{0, 0, 0, 0} +}; + +static char *con_help =  +	"Usage:\n" +	"\tcon\n"; + +static void cmd_con(int dev_id, int argc, char **argv)  { +	int opt; + +	for_each_opt(opt, con_options, NULL) { +		switch(opt) { +		default: +			printf(con_help); +			return; +		} +	} +  	printf("Connections:\n");  	if (dev_id < 0)  		for_each_dev(HCI_UP, conn_list, 0); @@ -457,17 +627,56 @@ static void cmd_con(int dev_id, char **opt, int nopt)  		conn_list(dev_id, 0);  } -static void cmd_cc(int dev_id, char **opt, int nopt) +/* Create connection */ + +static struct option cc_options[] = { +	{"help",    0,0, 'h'}, +	{"role",    1,0, 'r'}, +	{"ptype",   1,0, 'p'}, +	{0, 0, 0, 0} +}; + +static char *cc_help =  +	"Usage:\n" +	"\tcc [--role=m|s] [--ptype=pkt_types] <bdaddr>\n" +	"Example:\n" +	"\tcc --ptype=dm1,dh3,dh5 01:02:03:04:05:06\n" +	"\tcc --role=m 01:02:03:04:05:06\n"; + +static void cmd_cc(int dev_id, int argc, char **argv)  {  	bdaddr_t bdaddr; -	int ptype, dd; +	int opt, ptype, dd;  	uint16_t handle;  	uint8_t role; -	if (nopt < 1) +	role = 0; +	ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5; + +	for_each_opt(opt, cc_options, NULL) { +		switch(opt) { +		case 'p': +			hci_strtoptype(optarg, &ptype); +			break; +		 +		case 'r': +			role = optarg[0] == 'm' ? 0 : 1; +			break; + +		default: +			printf(cc_help); +			return; +		} +	} +	argc -= optind; +	argv += optind; + +	if (argc < 1) { +		printf(cc_help);  		return; +	} -	baswap(&bdaddr, strtoba(opt[0])); +	str2ba(argv[0], &bdaddr);  	if (dev_id < 0) {  		dev_id = get_route(&bdaddr); @@ -483,31 +692,43 @@ static void cmd_cc(int dev_id, char **opt, int nopt)  		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, 0, role, &handle, 1000); -  	hci_close_dev(dd);  } -static void cmd_dc(int dev_id, char **opt, int nopt) +/* Close connection */ + +static struct option dc_options[] = { +	{"help",    0,0, 'h'}, +	{0, 0, 0, 0} +}; + +static char *dc_help =  +	"Usage:\n" +	"\tdc <bdaddr>\n"; + +static void cmd_dc(int dev_id, int argc, char **argv)  {  	struct hci_conn_info_req *cr;  	bdaddr_t bdaddr; -	int dd; +	int opt, dd; + +	for_each_opt(opt, dc_options, NULL) { +		switch(opt) { +		default: +			printf(dc_help); +			return; +		} +	} +	argc -= optind; +	argv += optind; -	if (nopt < 1) +	if (argc < 1) { +		printf(dc_help);  		return; +	} -	baswap(&bdaddr, strtoba(*opt)); +	str2ba(argv[0], &bdaddr);  	if (dev_id < 0) {  		dev_id = for_each_dev(HCI_UP, find_conn, (long) &bdaddr); @@ -542,19 +763,18 @@ static void cmd_dc(int dev_id, char **opt, int nopt)  struct {  	char *cmd; -	void (*func)(int dev_id, char **opt, int nopt); -	char *opt; +	void (*func)(int dev_id, int argc, char **argv);  	char *doc;  } command[] = { -	{ "dev",  cmd_dev,  0,                            "Display local devices"              }, -	{ "rev",  cmd_rev,  0,                            "Display revison information"        }, -	{ "inq",  cmd_inq,  "[length] [flush]",           "Inquire remote devices"             }, -	{ "scan", cmd_scan, "[length] [flush]",           "Scan for remote devices"            }, -	{ "info", cmd_info, "<bdaddr>",                   "Get information from remote device" }, -	{ "cmd",  cmd_cmd,  "<ogf> <ocf> [param]",        "Submit arbitrary HCI commands"      }, -	{ "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"      }, +	{ "dev",  cmd_dev,  "Display local devices"              }, +	{ "rev",  cmd_rev,  "Display revison information"        }, +	{ "inq",  cmd_inq,  "Inquire remote devices"             }, +	{ "scan", cmd_scan, "Scan for remote devices"            }, +	{ "info", cmd_info, "Get information from remote device" }, +	{ "cmd",  cmd_cmd,  "Submit arbitrary HCI commands"      }, +	{ "con",  cmd_con,  "Display active connections"         }, +	{ "cc",   cmd_cc,   "Create connection to remote device" }, +	{ "dc",	  cmd_dc,   "Disconnect from remote device"      },  	{ NULL, NULL, 0}  }; @@ -564,24 +784,30 @@ static void usage(void)  	printf("hcitool - HCI Tool\n");  	printf("Usage:\n" -		"\thcitool [-i hciX] [command]\n"); +		"\thcitool [options] <command> [command parameters]\n"); +	printf("Options:\n" +		"\t--help\tDisplay help\n" +		"\t-i dev\tHCI device\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 : " ", +		printf("\t%-4s\t%s\n", command[i].cmd,  		command[i].doc);  } -int main(int argc, char *argv[], char *env[]) +static struct option main_options[] = { +	{"help",        0,0, 'h'}, +	{"device",      1,0, 'i'}, +	{0, 0, 0, 0} +}; + +int main(int argc, char **argv)  {  	int opt, i, dev_id = -1; -	char *dev; -	while ((opt=getopt(argc, argv, "i:h")) != EOF) { +	while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {  		switch(opt) {  		case 'i': -			dev    = strdup(optarg); -			dev_id = atoi(dev + 3); +			dev_id = atoi(optarg + 3);  			break;  		case 'h': @@ -591,22 +817,25 @@ int main(int argc, char *argv[], char *env[])  		}  	} -	if (argc - optind < 1) { +	argc -= optind; +	argv += optind; +	optind = 0; + +	if (argc < 1) {  		usage();  		exit(0);  	} -	/* Open HCI socket  */ +	/* 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))  +		if (strncmp(command[i].cmd, argv[0], 3))  			continue; -		optind++; -		command[i].func(dev_id, argv + optind, argc - optind); +		command[i].func(dev_id, argc, argv);  		break;  	} | 
