diff options
Diffstat (limited to 'tools/hcitool.c')
-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; } |