?? hcitool.c
字號(hào):
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2000-2001 Qualcomm Incorporated * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> * Copyright (C) 2002-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: hcitool.c,v 1.76 2005/07/03 13:01:52 holtmann Exp $ */#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 <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 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 ? "<" : ">", ci->type == ACL_LINK ? "ACL" : "SCO", 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 */ 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 char *get_device_name(const bdaddr_t *local, const bdaddr_t *peer){ char filename[PATH_MAX + 1], addr[18]; ba2str(local, addr); snprintf(filename, PATH_MAX, "%s/%s/names", STORAGEDIR, addr); 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' }, { "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 [--flush] flush the inquiry cache\n";static void cmd_inq(int dev_id, int argc, char **argv){ int num_rsp, length, flags; inquiry_info *info = NULL; char addr[18]; int i, 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 'f': flags |= IREQ_CACHE_FLUSH; break; default: printf(inq_help); return; } } printf("Inquiring ...\n"); num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &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]); } free(info);}/* Device scanning */static struct option scan_options[] = { { "help", 0, 0, 'h' }, { "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] [--class] [--info] [--oui]\n";static void cmd_scan(int dev_id, int argc, char **argv){ inquiry_info *info = NULL; 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 extcls = 0, extinf = 0, extoui = 0; int i, n, 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 'f': 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; } } 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, 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); } if (extcls || extinf || extoui) printf("\n"); for (i = 0; i < num_rsp; i++) { memset(name, 0, sizeof(name)); tmp = get_device_name(&di.bdaddr, &(info+i)->bdaddr); if (tmp) { strncpy(name, tmp, 249); free(tmp); nc = 1; } else nc = 0; if (!extcls && !extinf && !extoui) { ba2str(&(info+i)->bdaddr, addr); if (nc) { printf("\t%s\t%s\n", addr, name); continue; } 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"); for (n = 0; n < 248 && name[n]; n++) if (!isprint(name[n])) name[n] = '.'; 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; } } } if (handle > 0 || !nc) { 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) { if (!nc) strcpy(name, "n/a"); } else { for (n = 0; n < 248 && name[n]; n++) if (!isprint(name[n])) name[n] = '.'; nc = 0; } } if (strlen(name) > 0) printf("Device name:\t%s%s\n", name, nc ? " [cached]" : ""); 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); free(info);}/* Remote name */static struct option name_options[] = { { "help", 0, 0, 'h' }, { 0, 0, 0, 0 }};static char *name_help = "Usage:\n" "\tname <bdaddr>\n";static void cmd_name(int dev_id, int argc, char **argv){ bdaddr_t bdaddr; char name[248]; int opt, dd; for_each_opt(opt, name_options, NULL) { switch (opt) { default: printf(name_help); return; } } argc -= optind; argv += optind; if (argc < 1) { printf(name_help); return; } str2ba(argv[0], &bdaddr); if (dev_id < 0) { dev_id = hci_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 (hci_read_remote_name(dd, &bdaddr, sizeof(name), name, 25000) == 0) printf("%s\n", name); close(dd);}/* 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; uint8_t max_page, features[8];
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -