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; +} |