📄 hcitool.c
字号:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2000-2001 Qualcomm Incorporated * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> * Copyright (C) 2002-2008 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 as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <ctype.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <getopt.h>#include <sys/param.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include "textfile.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);static int dev_info(int s, int dev_id, long arg){ struct hci_dev_info di = { dev_id: dev_id }; char addr[18]; if (ioctl(s, HCIGETDEVINFO, (void *) &di)) return 0; ba2str(&di.bdaddr, addr); printf("\t%s\t%s\n", di.name, addr); return 0;}static char *type2str(uint8_t type){ switch (type) { case SCO_LINK: return "SCO"; case ACL_LINK: return "ACL"; case ESCO_LINK: return "eSCO"; default: return "Unknown"; }}static int conn_list(int s, int dev_id, long arg){ struct hci_conn_list_req *cl; struct hci_conn_info *ci; int id = arg; int i; if (id != -1 && dev_id != id) return 0; 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(s, HCIGETCONNLIST, (void *) cl)) { perror("Can't get connection list"); exit(1); } for (i = 0; i < cl->conn_num; i++, ci++) { char addr[18]; ba2str(&ci->bdaddr, addr); printf("\t%s %s %s handle %d state %d lm %s\n", ci->out ? "<" : ">", type2str(ci->type), addr, ci->handle, ci->state, hci_lmtostr(ci->link_mode)); } return 0;}static int find_conn(int s, 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(s, 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 hex_dump(char *pref, int width, unsigned char *buf, int len){ register int i,n; for (i = 0, n = 1; i < len; i++, n++) { if (n == 1) printf("%s", pref); printf("%2.2X ", buf[i]); if (n == width) { printf("\n"); n = 0; } } if (i && n!=1) 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 */ { static char cls_str[48]; cls_str[0] = 0; switch(minor & 48) { case 16: strncpy(cls_str, "Keyboard", sizeof(cls_str)); break; case 32: strncpy(cls_str, "Pointing device", sizeof(cls_str)); break; case 48: strncpy(cls_str, "Combo keyboard/pointing device", sizeof(cls_str)); break; } if((minor & 15) && (strlen(cls_str) > 0)) strcat(cls_str, "/"); switch(minor & 15) { case 0: break; case 1: strncat(cls_str, "Joystick", sizeof(cls_str) - strlen(cls_str)); break; case 2: strncat(cls_str, "Gamepad", sizeof(cls_str) - strlen(cls_str)); break; case 3: strncat(cls_str, "Remote control", sizeof(cls_str) - strlen(cls_str)); break; case 4: strncat(cls_str, "Sensing device", sizeof(cls_str) - strlen(cls_str)); break; case 5: strncat(cls_str, "Digitizer tablet", sizeof(cls_str) - strlen(cls_str)); break; case 6: strncat(cls_str, "Card reader", sizeof(cls_str) - strlen(cls_str)); break; default: strncat(cls_str, "(reserved)", sizeof(cls_str) - strlen(cls_str)); break; } if(strlen(cls_str) > 0) return cls_str; } 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 7: /* wearable */ switch(minor) { case 1: return "Wrist Watch"; case 2: return "Pager"; case 3: return "Jacket"; case 4: return "Helmet"; case 5: return "Glasses"; } break; case 8: /* toy */ switch(minor) { case 1: return "Robot"; case 2: return "Vehicle"; case 3: return "Doll / Action Figure"; case 4: return "Controller"; case 5: return "Game"; } 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 char *get_device_name(const bdaddr_t *local, const bdaddr_t *peer){ char filename[PATH_MAX + 1], addr[18]; ba2str(local, addr); create_name(filename, PATH_MAX, STORAGEDIR, addr, "names"); ba2str(peer, addr); return textfile_get(filename, addr);}/* 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"); hci_for_each_dev(HCI_UP, dev_info, 0);}/* Inquiry */static struct option inq_options[] = { { "help", 0, 0, 'h' }, { "length", 1, 0, 'l' }, { "numrsp", 1, 0, 'n' }, { "iac", 1, 0, 'i' }, { "flush", 0, 0, 'f' }, { 0, 0, 0, 0 }};static char *inq_help = "Usage:\n" "\tinq [--length=N] maximum inquiry duration in 1.28 s units\n" "\t [--numrsp=N] specify maximum number of inquiry responses\n" "\t [--iac=lap] specify the inquiry access code\n" "\t [--flush] flush the inquiry cache\n";static void cmd_inq(int dev_id, int argc, char **argv){ inquiry_info *info = NULL; uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; int num_rsp, length, flags; char addr[18]; int i, l, opt; length = 8; /* ~10 seconds */ num_rsp = 0; flags = 0; for_each_opt(opt, inq_options, NULL) { switch (opt) { case 'l': length = atoi(optarg); break; case 'n': num_rsp = atoi(optarg); break; case 'i': l = strtoul(optarg, 0, 16); if (!strcasecmp(optarg, "giac")) { l = 0x9e8b33; } else if (!strcasecmp(optarg, "liac")) { l = 0x9e8b00; } if (l < 0x9e8b00 || l > 0x9e8b3f) { printf("Invalid access code 0x%x\n", l); exit(1); } lap[0] = (l & 0xff); lap[1] = (l >> 8) & 0xff; lap[2] = (l >> 16) & 0xff; break; case 'f': flags |= IREQ_CACHE_FLUSH; break; default: printf(inq_help); return; } } printf("Inquiring ...\n"); num_rsp = hci_inquiry(dev_id, length, num_rsp, lap, &info, flags); if (num_rsp < 0) { perror("Inquiry failed."); exit(1); } for (i = 0; i < num_rsp; i++) { 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[0]); } bt_free(info);}/* Device scanning */static struct option scan_options[] = { { "help", 0, 0, 'h' }, { "length", 1, 0, 'l' }, { "numrsp", 1, 0, 'n' }, { "iac", 1, 0, 'i' }, { "flush", 0, 0, 'f' }, { "refresh", 0, 0, 'r' }, { "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] [--iac=lap] [--flush] [--class] [--info] [--oui] [--refresh]\n";static void cmd_scan(int dev_id, int argc, char **argv){ inquiry_info *info = NULL; uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; int num_rsp, length, flags; uint8_t cls[3], features[8]; uint16_t handle; char addr[18], name[249], oui[9], *comp, *tmp; struct hci_version version; struct hci_dev_info di; struct hci_conn_info_req *cr; int refresh = 0, extcls = 0, extinf = 0, extoui = 0; int i, n, l, opt, dd, cc, nc; length = 8; /* ~10 seconds */ num_rsp = 0; flags = 0; for_each_opt(opt, scan_options, NULL) { switch (opt) { case 'l': length = atoi(optarg); break; case 'n': num_rsp = atoi(optarg); break; case 'i': l = strtoul(optarg, 0, 16); if (!strcasecmp(optarg, "giac")) { l = 0x9e8b33; } else if (!strcasecmp(optarg, "liac")) { l = 0x9e8b00; } else if (l < 0x9e8b00 || l > 0x9e8b3f) { printf("Invalid access code 0x%x\n", l); exit(1); } lap[0] = (l & 0xff); lap[1] = (l >> 8) & 0xff; lap[2] = (l >> 16) & 0xff; break; case 'f': flags |= IREQ_CACHE_FLUSH; break; case 'r': refresh = 1; 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; } } 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("Scanning ...\n"); num_rsp = hci_inquiry(dev_id, length, num_rsp, lap, &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); } if (extcls || extinf || extoui) printf("\n"); for (i = 0; i < num_rsp; i++) { if (!refresh) { memset(name, 0, sizeof(name)); tmp = get_device_name(&di.bdaddr, &(info+i)->bdaddr); if (tmp) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -