summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/hcitool.c314
-rw-r--r--tools/oui.c100
-rw-r--r--tools/oui.h30
3 files changed, 440 insertions, 4 deletions
diff --git a/tools/hcitool.c b/tools/hcitool.c
index 27ac78b7..9c4dc468 100644
--- a/tools/hcitool.c
+++ b/tools/hcitool.c
@@ -44,6 +44,8 @@
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
+#include "oui.h"
+
#define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, NULL)) != -1)
static void usage(void);
@@ -224,8 +226,8 @@ static void cmd_inq(int dev_id, int argc, char **argv)
ba2str(&(info+i)->bdaddr, addr);
printf("\t%s\tclock offset: 0x%4.4x\tclass: 0x%2.2x%2.2x%2.2x\n",
addr, btohs((info+i)->clock_offset),
- (info+i)->dev_class[2],
- (info+i)->dev_class[1],
+ (info+i)->dev_class[2],
+ (info+i)->dev_class[1],
(info+i)->dev_class[0]);
}
free(info);
@@ -250,7 +252,7 @@ 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[248];
+ char name[249];
int i, opt, dd;
length = 8; /* ~10 seconds */
@@ -383,7 +385,7 @@ static void cmd_info(int dev_id, int argc, char **argv)
{
bdaddr_t bdaddr;
uint16_t handle;
- char name[248];
+ char name[249], oui[9], *comp;
unsigned char features[8];
struct hci_version version;
struct hci_dev_info di;
@@ -454,6 +456,13 @@ static void cmd_info(int dev_id, int argc, char **argv)
printf("\tBD Address: %s\n", argv[0]);
+ ba2oui(&bdaddr, oui);
+ comp = ouitocomp(oui);
+ if (comp) {
+ printf("\tOUI Company: %s (%s)\n", comp, oui);
+ free(comp);
+ }
+
if (hci_read_remote_name(dd, &bdaddr, sizeof(name), name, 25000) == 0)
printf("\tDevice Name: %s\n", name);
@@ -482,6 +491,302 @@ 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[] = {
@@ -1637,6 +1942,7 @@ 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" },
diff --git a/tools/oui.c b/tools/oui.c
new file mode 100644
index 00000000..7dff358b
--- /dev/null
+++ b/tools/oui.c
@@ -0,0 +1,100 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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$
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <malloc.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "oui.h"
+
+/* http://standards.ieee.org/regauth/oui/oui.txt */
+
+#define OUIFILE "/usr/share/misc/oui.txt"
+
+#define AWKCMD "/usr/bin/awk"
+#define TRCMD "/usr/bin/tr"
+
+char *ouitocomp(const char *oui)
+{
+ struct stat st;
+ FILE *input;
+ char cmd[512];
+ char *str;
+ size_t len;
+
+ if (stat(OUIFILE, &st) < 0)
+ return NULL;
+
+ if (stat(AWKCMD, &st) < 0)
+ return NULL;
+
+ if (stat(TRCMD, &st) < 0)
+ return NULL;
+
+ str = malloc(128);
+ if (!str)
+ return NULL;
+
+ memset(str, 0, 128);
+
+ snprintf(cmd, sizeof(cmd) - 1, "%s -F'\\t' '/^"
+ "%s.*\\(hex\\).*/{ print $3 }' %s"
+ " | %s -d '\\n\\r'", AWKCMD, oui, OUIFILE, TRCMD);
+
+ input = popen(cmd, "r");
+ if (!input) {
+ free(str);
+ return NULL;
+ }
+
+ len = fread(str, 127, 1, input);
+ pclose(input);
+
+ return str;
+}
+
+int oui2comp(const char *oui, char *comp, size_t size)
+{
+ char *tmp;
+
+ tmp = ouitocomp(oui);
+ if (!tmp)
+ return -1;
+
+ snprintf(comp, size, "%s", tmp);
+
+ free(tmp);
+
+ return 0;
+}
diff --git a/tools/oui.h b/tools/oui.h
new file mode 100644
index 00000000..918a248b
--- /dev/null
+++ b/tools/oui.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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$
+ */
+
+char *ouitocomp(const char *oui);
+int oui2comp(const char *oui, char *comp, size_t size);