summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/hcitool.c572
1 files changed, 269 insertions, 303 deletions
diff --git a/tools/hcitool.c b/tools/hcitool.c
index 9c4dc468..9ac890fd 100644
--- a/tools/hcitool.c
+++ b/tools/hcitool.c
@@ -142,6 +142,140 @@ static void hex_dump(char *pref, int width, unsigned char *buf, int len)
printf("\n");
}
+static char *get_minor_device_name(int major, int minor)
+{
+ switch (major) {
+ case 0: /* misc */
+ return "";
+ case 1: /* computer */
+ switch(minor) {
+ case 0:
+ return "Uncategorized";
+ case 1:
+ return "Desktop workstation";
+ case 2:
+ return "Server";
+ case 3:
+ return "Laptop";
+ case 4:
+ return "Handheld";
+ case 5:
+ return "Palm";
+ case 6:
+ return "Wearable";
+ }
+ break;
+ case 2: /* phone */
+ switch(minor) {
+ case 0:
+ return "Uncategorized";
+ case 1:
+ return "Cellular";
+ case 2:
+ return "Cordless";
+ case 3:
+ return "Smart phone";
+ case 4:
+ return "Wired modem or voice gateway";
+ case 5:
+ return "Common ISDN Access";
+ case 6:
+ return "Sim Card Reader";
+ }
+ break;
+ case 3: /* lan access */
+ if (minor == 0)
+ return "Uncategorized";
+ switch(minor / 8) {
+ case 0:
+ return "Fully available";
+ case 1:
+ return "1-17% utilized";
+ case 2:
+ return "17-33% utilized";
+ case 3:
+ return "33-50% utilized";
+ case 4:
+ return "50-67% utilized";
+ case 5:
+ return "67-83% utilized";
+ case 6:
+ return "83-99% utilized";
+ case 7:
+ return "No service available";
+ }
+ break;
+ case 4: /* audio/video */
+ switch(minor) {
+ case 0:
+ return "Uncategorized";
+ case 1:
+ return "Device conforms to the Headset profile";
+ case 2:
+ return "Hands-free";
+ /* 3 is reserved */
+ case 4:
+ return "Microphone";
+ case 5:
+ return "Loudspeaker";
+ case 6:
+ return "Headphones";
+ case 7:
+ return "Portable Audio";
+ case 8:
+ return "Car Audio";
+ case 9:
+ return "Set-top box";
+ case 10:
+ return "HiFi Audio Device";
+ case 11:
+ return "VCR";
+ case 12:
+ return "Video Camera";
+ case 13:
+ return "Camcorder";
+ case 14:
+ return "Video Monitor";
+ case 15:
+ return "Video Display and Loudspeaker";
+ case 16:
+ return "Video Conferencing";
+ /* 17 is reserved */
+ case 18:
+ return "Gaming/Toy";
+ }
+ break;
+ case 5: /* peripheral */
+ switch(minor) {
+ case 16:
+ return "Keyboard";
+ case 32:
+ return "Pointing device";
+ case 48:
+ return "Combo keyboard/pointing device";
+ }
+ break;
+ case 6: /* imaging */
+ if (minor & 4)
+ return "Display";
+ if (minor & 8)
+ return "Camera";
+ if (minor & 16)
+ return "Scanner";
+ if (minor & 32)
+ return "Printer";
+ break;
+ case 63: /* uncategorised */
+ return "";
+ }
+ return "Unknown (reserved) minor device class";
+}
+
+static char *major_classes[] = {
+ "Miscellaneous", "Computer", "Phone", "LAN Access",
+ "Audio/Video", "Peripheral", "Imaging", "Uncategorized"
+};
+
/* Display local devices */
static struct option dev_options[] = {
@@ -240,20 +374,31 @@ static struct option scan_options[] = {
{ "length", 1, 0, 'l' },
{ "numrsp", 1, 0, 'n' },
{ "flush", 0, 0, 'f' },
+ { "class", 0, 0, 'c' },
+ { "info", 0, 0, 'i' },
+ { "oui", 0, 0, 'o' },
+ { "all", 0, 0, 'a' },
+ { "ext", 0, 0, 'a' },
{ 0, 0, 0, 0 }
};
static char *scan_help =
"Usage:\n"
- "\tscan [--length=N] [--numrsp=N] [--flush]\n";
+ "\tscan [--length=N] [--numrsp=N] [--flush] [--class] [--info] [--oui]\n";
static void cmd_scan(int dev_id, int argc, char **argv)
{
inquiry_info *info = NULL;
int num_rsp, length, flags;
- char addr[18];
- char name[249];
- int i, opt, dd;
+ uint8_t cls[3];
+ uint16_t handle;
+ char addr[18], name[249], oui[9], *comp;
+ unsigned char features[8];
+ struct hci_version version;
+ struct hci_dev_info di;
+ struct hci_conn_info_req *cr;
+ int extcls = 0, extinf = 0, extoui = 0;
+ int i, opt, dd, cc;
length = 8; /* ~10 seconds */
num_rsp = 100;
@@ -273,6 +418,24 @@ static void cmd_scan(int dev_id, int argc, char **argv)
flags |= IREQ_CACHE_FLUSH;
break;
+ case 'c':
+ extcls = 1;
+ break;
+
+ case 'i':
+ extinf = 1;
+ break;
+
+ case 'o':
+ extoui = 1;
+ break;
+
+ case 'a':
+ extcls = 1;
+ extinf = 1;
+ extoui = 1;
+ break;
+
default:
printf(scan_help);
return;
@@ -287,6 +450,11 @@ static void cmd_scan(int dev_id, int argc, char **argv)
}
}
+ if (hci_devinfo(dev_id, &di) < 0) {
+ perror("Can't get device info");
+ exit(1);
+ }
+
printf("Scanning ...\n");
num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags);
if (num_rsp < 0) {
@@ -301,15 +469,110 @@ static void cmd_scan(int dev_id, int argc, char **argv)
exit(1);
}
+ if (extcls || extinf || extoui)
+ printf("\n");
+
for (i = 0; i < num_rsp; i++) {
+ if (!extcls && !extinf && !extoui) {
+ memset(name, 0, sizeof(name));
+ if (hci_read_remote_name_with_clock_offset(dd,
+ &(info+i)->bdaddr,
+ (info+i)->pscan_rep_mode,
+ (info+i)->clock_offset | 0x8000,
+ sizeof(name), name, 100000) < 0)
+ strcpy(name, "n/a");
+ ba2str(&(info+i)->bdaddr, addr);
+ printf("\t%s\t%s\n", addr, name);
+ continue;
+ }
+
+ ba2str(&(info+i)->bdaddr, addr);
+ printf("BD Address:\t%s [mode %d, clkoffset 0x%4.4x]\n", addr,
+ (info+i)->pscan_rep_mode, btohs((info+i)->clock_offset));
+
+ if (extoui) {
+ ba2oui(&(info+i)->bdaddr, oui);
+ comp = ouitocomp(oui);
+ if (comp) {
+ printf("OUI company:\t%s (%s)\n", comp, oui);
+ free(comp);
+ }
+ }
+
+ cc = 0;
+
+ if (extinf) {
+ cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
+ if (cr) {
+ bacpy(&cr->bdaddr, &(info+i)->bdaddr);
+ cr->type = ACL_LINK;
+ if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
+ handle = 0;
+ cc = 1;
+ } else {
+ handle = htobs(cr->conn_info->handle);
+ cc = 0;
+ }
+ free(cr);
+ }
+
+ if (cc) {
+ if (hci_create_connection(dd, &(info+i)->bdaddr,
+ htobs(di.pkt_type & ACL_PTYPE_MASK),
+ (info+i)->clock_offset | 0x8000,
+ 0x01, &handle, 25000) < 0) {
+ handle = 0;
+ cc = 0;
+ }
+ }
+ }
+
memset(name, 0, sizeof(name));
if (hci_read_remote_name_with_clock_offset(dd, &(info+i)->bdaddr,
(info+i)->pscan_rep_mode,
(info+i)->clock_offset | 0x8000,
sizeof(name), name, 100000) < 0)
strcpy(name, "n/a");
- ba2str(&(info+i)->bdaddr, addr);
- printf("\t%s\t%s\n", addr, name);
+ printf("Device name:\t%s\n", name);
+
+ if (extcls) {
+ memcpy(cls, (info+i)->dev_class, 3);
+ printf("Device class:\t");
+ if ((cls[1] & 0x1f) > sizeof(*major_classes))
+ printf("Invalid");
+ else
+ printf("%s, %s", major_classes[cls[1] & 0x1f],
+ get_minor_device_name(cls[1] & 0x1f, cls[0] >> 2));
+ printf(" (0x%2.2x%2.2x%2.2x)\n", cls[2], cls[1], cls[0]);
+ }
+
+ if (extinf && handle > 0) {
+ if (hci_read_remote_version(dd, handle, &version, 20000) == 0) {
+ printf("Manufacturer:\t%s (%d)\n",
+ bt_compidtostr(version.manufacturer),
+ version.manufacturer);
+ printf("LMP version:\t%s (0x%x) [subver 0x%x]\n",
+ lmp_vertostr(version.lmp_ver),
+ version.lmp_ver, version.lmp_subver);
+ }
+
+ if (hci_read_remote_features(dd, handle, features, 20000) == 0) {
+ printf("LMP features:\t0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x"
+ " 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
+ features[0], features[1],
+ features[2], features[3],
+ features[4], features[5],
+ features[6], features[7]);
+ printf("%s\n", lmp_featurestostr(features, "\t\t", 63));
+ }
+
+ if (cc) {
+ usleep(10000);
+ hci_disconnect(dd, handle, HCI_OE_USER_ENDED_CONNECTION, 10000);
+ }
+ }
+
+ printf("\n");
}
close(dd);
@@ -491,302 +754,6 @@ static void cmd_info(int dev_id, int argc, char **argv)
close(dd);
}
-/* Find remote devices */
-
-static struct option find_options[] = {
- { "help", 0, 0, 'h' },
- { "length", 1, 0, 'l' },
- { "numrsp", 1, 0, 'n' },
- { "flush", 0, 0, 'f' },
- { 0, 0, 0, 0 }
-};
-
-static char *find_help =
- "Usage:\n"
- "\tfind [--length=N] [--numrsp=N] [--flush]\n";
-
-static char *get_minor_device_name(int major, int minor)
-{
- switch (major) {
- case 0: /* misc */
- return "";
- case 1: /* computer */
- switch(minor) {
- case 0:
- return "Uncategorized";
- case 1:
- return "Desktop workstation";
- case 2:
- return "Server";
- case 3:
- return "Laptop";
- case 4:
- return "Handheld";
- case 5:
- return "Palm";
- case 6:
- return "Wearable";
- }
- break;
- case 2: /* phone */
- switch(minor) {
- case 0:
- return "Uncategorized";
- case 1:
- return "Cellular";
- case 2:
- return "Cordless";
- case 3:
- return "Smart phone";
- case 4:
- return "Wired modem or voice gateway";
- case 5:
- return "Common ISDN Access";
- case 6:
- return "Sim Card Reader";
- }
- break;
- case 3: /* lan access */
- if (minor == 0)
- return "Uncategorized";
- switch(minor / 8) {
- case 0:
- return "Fully available";
- case 1:
- return "1-17% utilized";
- case 2:
- return "17-33% utilized";
- case 3:
- return "33-50% utilized";
- case 4:
- return "50-67% utilized";
- case 5:
- return "67-83% utilized";
- case 6:
- return "83-99% utilized";
- case 7:
- return "No service available";
- }
- break;
- case 4: /* audio/video */
- switch(minor) {
- case 0:
- return "Uncategorized";
- case 1:
- return "Device conforms to the Headset profile";
- case 2:
- return "Hands-free";
- /* 3 is reserved */
- case 4:
- return "Microphone";
- case 5:
- return "Loudspeaker";
- case 6:
- return "Headphones";
- case 7:
- return "Portable Audio";
- case 8:
- return "Car Audio";
- case 9:
- return "Set-top box";
- case 10:
- return "HiFi Audio Device";
- case 11:
- return "VCR";
- case 12:
- return "Video Camera";
- case 13:
- return "Camcorder";
- case 14:
- return "Video Monitor";
- case 15:
- return "Video Display and Loudspeaker";
- case 16:
- return "Video Conferencing";
- /* 17 is reserved */
- case 18:
- return "Gaming/Toy";
- }
- break;
- case 5: /* peripheral */
- switch(minor) {
- case 16:
- return "Keyboard";
- case 32:
- return "Pointing device";
- case 48:
- return "Combo keyboard/pointing device";
- }
- break;
- case 6: /* imaging */
- if (minor & 4)
- return "Display";
- if (minor & 8)
- return "Camera";
- if (minor & 16)
- return "Scanner";
- if (minor & 32)
- return "Printer";
- break;
- case 63: /* uncategorised */
- return "";
- }
- return "Unknown (reserved) minor device class";
-}
-
-static char *major_classes[] = {
- "Miscellaneous", "Computer", "Phone", "LAN Access",
- "Audio/Video", "Peripheral", "Imaging", "Uncategorized"
-};
-
-static void cmd_find(int dev_id, int argc, char **argv)
-{
- inquiry_info *info = NULL;
- int num_rsp, length, flags;
- uint8_t cls[3];
- uint16_t handle;
- char addr[18], name[249], oui[9], *comp;
- unsigned char features[8];
- struct hci_version version;
- struct hci_dev_info di;
- struct hci_conn_info_req *cr;
- int i, opt, dd, cc = 0;
-
- length = 8; /* ~10 seconds */
- num_rsp = 100;
- flags = 0;
-
- for_each_opt(opt, find_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(find_help);
- return;
- }
- }
-
- if (dev_id < 0) {
- dev_id = hci_get_route(NULL);
- if (dev_id < 0) {
- perror("Device is not available");
- exit(1);
- }
- }
-
- if (hci_devinfo(dev_id, &di) < 0) {
- perror("Can't get device info");
- exit(1);
- }
-
- printf("Searching ...\n");
- num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags);
- if (num_rsp < 0) {
- perror("Inquiry failed");
- exit(1);
- }
-
- dd = hci_open_dev(dev_id);
- if (dd < 0) {
- perror("HCI device open failed");
- free(info);
- exit(1);
- }
-
- printf("\n");
-
- for (i = 0; i < num_rsp; i++) {
- ba2str(&(info+i)->bdaddr, addr);
- printf("BD Address:\t%s [mode %d, clkoffset 0x%4.4x]\n", addr,
- (info+i)->pscan_rep_mode, btohs((info+i)->clock_offset));
-
- ba2oui(&(info+i)->bdaddr, oui);
- comp = ouitocomp(oui);
- if (comp) {
- printf("OUI company:\t%s (%s)\n", comp, oui);
- free(comp);
- }
-
- cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
- if (cr) {
- bacpy(&cr->bdaddr, &(info+i)->bdaddr);
- cr->type = ACL_LINK;
- if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
- if (hci_create_connection(dd, &(info+i)->bdaddr,
- htobs(di.pkt_type & ACL_PTYPE_MASK),
- (info+i)->clock_offset | 0x8000,
- 0x01, &handle, 25000) < 0)
- handle = 0;
- else
- cc = 1;
- } else
- handle = htobs(cr->conn_info->handle);
- } else
- handle = 0;
-
- memset(name, 0, sizeof(name));
- if (hci_read_remote_name_with_clock_offset(dd, &(info+i)->bdaddr,
- (info+i)->pscan_rep_mode,
- (info+i)->clock_offset | 0x8000,
- sizeof(name), name, 100000) < 0)
- strcpy(name, "n/a");
- printf("Device name:\t%s\n", name);
-
- memcpy(cls, (info+i)->dev_class, 3);
- printf("Device class:\t");
- if ((cls[1] & 0x1f) > sizeof(*major_classes))
- printf("Invalid");
- else
- printf("%s, %s", major_classes[cls[1] & 0x1f],
- get_minor_device_name(cls[1] & 0x1f, cls[0] >> 2));
- printf(" (0x%2.2x%2.2x%2.2x)\n", cls[2], cls[1], cls[0]);
-
- if (handle > 0) {
- if (hci_read_remote_version(dd, handle, &version, 20000) == 0) {
- printf("Manufacturer:\t%s (%d)\n",
- bt_compidtostr(version.manufacturer),
- version.manufacturer);
- printf("LMP version:\t%s (0x%x) [subver 0x%x]\n",
- lmp_vertostr(version.lmp_ver),
- version.lmp_ver, version.lmp_subver);
- }
-
- if (hci_read_remote_features(dd, handle, features, 20000) == 0) {
- printf("LMP features:\t0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x"
- " 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
- features[0], features[1],
- features[2], features[3],
- features[4], features[5],
- features[6], features[7]);
- printf("%s\n", lmp_featurestostr(features, "\t\t", 63));
- }
-
- if (cc) {
- usleep(10000);
- hci_disconnect(dd, handle, HCI_OE_USER_ENDED_CONNECTION, 10000);
- }
- }
-
- printf("\n");
-
- if (cr)
- free(cr);
- }
-
- close(dd);
- free(info);
-}
-
/* Send arbitrary HCI commands */
static struct option cmd_options[] = {
@@ -1942,7 +1909,6 @@ static struct {
{ "scan", cmd_scan, "Scan for remote devices" },
{ "name", cmd_name, "Get name from remote device" },
{ "info", cmd_info, "Get information from remote device" },
- { "find", cmd_find, "Search for remote devices" },
{ "cmd", cmd_cmd, "Submit arbitrary HCI commands" },
{ "con", cmd_con, "Display active connections" },
{ "cc", cmd_cc, "Create connection to remote device" },