Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/hcitools/hcitool.c
Views: 3959
/*1*2* BlueZ - Bluetooth protocol stack for Linux3*4* Copyright (C) 2000-2001 Qualcomm Incorporated5* Copyright (C) 2002-2003 Maxim Krasnyansky <[email protected]>6* Copyright (C) 2002-2010 Marcel Holtmann <[email protected]>7*8*9* This program is free software; you can redistribute it and/or modify10* it under the terms of the GNU General Public License as published by11* the Free Software Foundation; either version 2 of the License, or12* (at your option) any later version.13*14* This program is distributed in the hope that it will be useful,15* but WITHOUT ANY WARRANTY; without even the implied warranty of16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the17* GNU General Public License for more details.18*19* You should have received a copy of the GNU General Public License20* along with this program; if not, write to the Free Software21* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA22*23*/2425#ifdef HAVE_CONFIG_H26#include <config.h>27#endif2829#include <stdio.h>30#include <errno.h>31#include <ctype.h>32#include <fcntl.h>33#include <unistd.h>34#include <stdlib.h>35#include <string.h>36#include <getopt.h>37#include <sys/param.h>38#include <sys/ioctl.h>39#include <sys/socket.h>40#include <signal.h>4142//#include <glib.h>4344#include <bluetooth/bluetooth.h>45#include <bluetooth/hci.h>46#include <bluetooth/hci_lib.h>4748/* Unofficial value, might still change */49#define LE_LINK 0x035051#define FLAGS_AD_TYPE 0x0152#define FLAGS_LIMITED_MODE_BIT 0x0153#define FLAGS_GENERAL_MODE_BIT 0x025455#define EIR_FLAGS 0x01 /* flags */56#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */57#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */58#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */59#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */60#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */61#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */62#define EIR_NAME_SHORT 0x08 /* shortened local name */63#define EIR_NAME_COMPLETE 0x09 /* complete local name */64#define EIR_TX_POWER 0x0A /* transmit power level */65#define EIR_DEVICE_ID 0x10 /* device ID */6667#define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, NULL)) != -1)6869static volatile int signal_received = 0;7071static void usage(void);7273static char *batocomp(const bdaddr_t *ba)74{75return NULL;76}7778static int dev_info(int s, int dev_id, long arg)79{80struct hci_dev_info di = { .dev_id = dev_id };81char addr[18];8283if (ioctl(s, HCIGETDEVINFO, (void *) &di))84return 0;8586ba2str(&di.bdaddr, addr);87printf("\t%s\t%s\n", di.name, addr);88return 0;89}9091static void helper_arg(int min_num_arg, int max_num_arg, int *argc,92char ***argv, const char *usage)93{94*argc -= optind;95/* too many arguments, but when "max_num_arg < min_num_arg" then no96limiting (prefer "max_num_arg=-1" to gen infinity)97*/98if ( (*argc > max_num_arg) && (max_num_arg >= min_num_arg ) ) {99fprintf(stderr, "%s: too many arguments (maximal: %i)\n",100*argv[0], max_num_arg);101printf("%s", usage);102exit(1);103}104105/* print usage */106if (*argc < min_num_arg) {107fprintf(stderr, "%s: too few arguments (minimal: %i)\n",108*argv[0], min_num_arg);109printf("%s", usage);110exit(0);111}112113*argv += optind;114}115116static char *type2str(uint8_t type)117{118switch (type) {119case SCO_LINK:120return "SCO";121case ACL_LINK:122return "ACL";123case ESCO_LINK:124return "eSCO";125case LE_LINK:126return "LE";127default:128return "Unknown";129}130}131132static int conn_list(int s, int dev_id, long arg)133{134struct hci_conn_list_req *cl;135struct hci_conn_info *ci;136int id = arg;137int i;138139if (id != -1 && dev_id != id)140return 0;141142if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) {143perror("Can't allocate memory");144exit(1);145}146cl->dev_id = dev_id;147cl->conn_num = 10;148ci = cl->conn_info;149150if (ioctl(s, HCIGETCONNLIST, (void *) cl)) {151perror("Can't get connection list");152exit(1);153}154155for (i = 0; i < cl->conn_num; i++, ci++) {156char addr[18];157char *str;158ba2str(&ci->bdaddr, addr);159str = hci_lmtostr(ci->link_mode);160printf("\t%s %s %s handle %d state %d lm %s\n",161ci->out ? "<" : ">", type2str(ci->type),162addr, ci->handle, ci->state, str);163bt_free(str);164}165166free(cl);167return 0;168}169170static int find_conn(int s, int dev_id, long arg)171{172struct hci_conn_list_req *cl;173struct hci_conn_info *ci;174int i;175176if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) {177perror("Can't allocate memory");178exit(1);179}180cl->dev_id = dev_id;181cl->conn_num = 10;182ci = cl->conn_info;183184if (ioctl(s, HCIGETCONNLIST, (void *) cl)) {185perror("Can't get connection list");186exit(1);187}188189for (i = 0; i < cl->conn_num; i++, ci++)190if (!bacmp((bdaddr_t *) arg, &ci->bdaddr)) {191free(cl);192return 1;193}194195free(cl);196return 0;197}198199static void hex_dump(char *pref, int width, unsigned char *buf, int len)200{201register int i,n;202203for (i = 0, n = 1; i < len; i++, n++) {204if (n == 1)205printf("%s", pref);206printf("%2.2X ", buf[i]);207if (n == width) {208printf("\n");209n = 0;210}211}212if (i && n!=1)213printf("\n");214}215216static char *get_minor_device_name(int major, int minor)217{218switch (major) {219case 0: /* misc */220return "";221case 1: /* computer */222switch (minor) {223case 0:224return "Uncategorized";225case 1:226return "Desktop workstation";227case 2:228return "Server";229case 3:230return "Laptop";231case 4:232return "Handheld";233case 5:234return "Palm";235case 6:236return "Wearable";237}238break;239case 2: /* phone */240switch (minor) {241case 0:242return "Uncategorized";243case 1:244return "Cellular";245case 2:246return "Cordless";247case 3:248return "Smart phone";249case 4:250return "Wired modem or voice gateway";251case 5:252return "Common ISDN Access";253case 6:254return "Sim Card Reader";255}256break;257case 3: /* lan access */258if (minor == 0)259return "Uncategorized";260switch (minor / 8) {261case 0:262return "Fully available";263case 1:264return "1-17% utilized";265case 2:266return "17-33% utilized";267case 3:268return "33-50% utilized";269case 4:270return "50-67% utilized";271case 5:272return "67-83% utilized";273case 6:274return "83-99% utilized";275case 7:276return "No service available";277}278break;279case 4: /* audio/video */280switch (minor) {281case 0:282return "Uncategorized";283case 1:284return "Device conforms to the Headset profile";285case 2:286return "Hands-free";287/* 3 is reserved */288case 4:289return "Microphone";290case 5:291return "Loudspeaker";292case 6:293return "Headphones";294case 7:295return "Portable Audio";296case 8:297return "Car Audio";298case 9:299return "Set-top box";300case 10:301return "HiFi Audio Device";302case 11:303return "VCR";304case 12:305return "Video Camera";306case 13:307return "Camcorder";308case 14:309return "Video Monitor";310case 15:311return "Video Display and Loudspeaker";312case 16:313return "Video Conferencing";314/* 17 is reserved */315case 18:316return "Gaming/Toy";317}318break;319case 5: /* peripheral */ {320static char cls_str[48]; cls_str[0] = 0;321322switch (minor & 48) {323case 16:324strncpy(cls_str, "Keyboard", sizeof(cls_str));325break;326case 32:327strncpy(cls_str, "Pointing device", sizeof(cls_str));328break;329case 48:330strncpy(cls_str, "Combo keyboard/pointing device", sizeof(cls_str));331break;332}333if ((minor & 15) && (strlen(cls_str) > 0))334strcat(cls_str, "/");335336switch (minor & 15) {337case 0:338break;339case 1:340strncat(cls_str, "Joystick", sizeof(cls_str) - strlen(cls_str));341break;342case 2:343strncat(cls_str, "Gamepad", sizeof(cls_str) - strlen(cls_str));344break;345case 3:346strncat(cls_str, "Remote control", sizeof(cls_str) - strlen(cls_str));347break;348case 4:349strncat(cls_str, "Sensing device", sizeof(cls_str) - strlen(cls_str));350break;351case 5:352strncat(cls_str, "Digitizer tablet", sizeof(cls_str) - strlen(cls_str));353break;354case 6:355strncat(cls_str, "Card reader", sizeof(cls_str) - strlen(cls_str));356break;357default:358strncat(cls_str, "(reserved)", sizeof(cls_str) - strlen(cls_str));359break;360}361if (strlen(cls_str) > 0)362return cls_str;363}364case 6: /* imaging */365if (minor & 4)366return "Display";367if (minor & 8)368return "Camera";369if (minor & 16)370return "Scanner";371if (minor & 32)372return "Printer";373break;374case 7: /* wearable */375switch (minor) {376case 1:377return "Wrist Watch";378case 2:379return "Pager";380case 3:381return "Jacket";382case 4:383return "Helmet";384case 5:385return "Glasses";386}387break;388case 8: /* toy */389switch (minor) {390case 1:391return "Robot";392case 2:393return "Vehicle";394case 3:395return "Doll / Action Figure";396case 4:397return "Controller";398case 5:399return "Game";400}401break;402case 63: /* uncategorised */403return "";404}405return "Unknown (reserved) minor device class";406}407408static char *major_classes[] = {409"Miscellaneous", "Computer", "Phone", "LAN Access",410"Audio/Video", "Peripheral", "Imaging", "Uncategorized"411};412413static char *get_device_name(const bdaddr_t *local, const bdaddr_t *peer)414{415#if 0416char filename[PATH_MAX + 1];417char local_addr[18], peer_addr[18];418GKeyFile *key_file;419char *str = NULL;420int len;421422ba2str(local, local_addr);423ba2str(peer, peer_addr);424425snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local_addr,426peer_addr);427filename[PATH_MAX] = '\0';428key_file = g_key_file_new();429430if (g_key_file_load_from_file(key_file, filename, 0, NULL)) {431str = g_key_file_get_string(key_file, "General", "Name", NULL);432if (str) {433len = strlen(str);434if (len > HCI_MAX_NAME_LENGTH)435str[HCI_MAX_NAME_LENGTH] = '\0';436}437}438439g_key_file_free(key_file);440441return str;442#endif443return NULL;444}445446/* Display local devices */447448static struct option dev_options[] = {449{ "help", 0, 0, 'h' },450{0, 0, 0, 0 }451};452453static const char *dev_help =454"Usage:\n"455"\tdev\n";456457static void cmd_dev(int dev_id, int argc, char **argv)458{459int opt;460461for_each_opt(opt, dev_options, NULL) {462switch (opt) {463default:464printf("%s", dev_help);465return;466}467}468helper_arg(0, 0, &argc, &argv, dev_help);469470printf("Devices:\n");471472hci_for_each_dev(HCI_UP, dev_info, 0);473}474475/* Inquiry */476477static struct option inq_options[] = {478{ "help", 0, 0, 'h' },479{ "length", 1, 0, 'l' },480{ "numrsp", 1, 0, 'n' },481{ "iac", 1, 0, 'i' },482{ "flush", 0, 0, 'f' },483{ 0, 0, 0, 0 }484};485486static const char *inq_help =487"Usage:\n"488"\tinq [--length=N] maximum inquiry duration in 1.28 s units\n"489"\t [--numrsp=N] specify maximum number of inquiry responses\n"490"\t [--iac=lap] specify the inquiry access code\n"491"\t [--flush] flush the inquiry cache\n";492493static void cmd_inq(int dev_id, int argc, char **argv)494{495inquiry_info *info = NULL;496uint8_t lap[3] = { 0x33, 0x8b, 0x9e };497int num_rsp, length, flags;498char addr[18];499int i, l, opt;500501length = 8; /* ~10 seconds */502num_rsp = 0;503flags = 0;504505for_each_opt(opt, inq_options, NULL) {506switch (opt) {507case 'l':508length = atoi(optarg);509break;510511case 'n':512num_rsp = atoi(optarg);513break;514515case 'i':516l = strtoul(optarg, 0, 16);517if (!strcasecmp(optarg, "giac")) {518l = 0x9e8b33;519} else if (!strcasecmp(optarg, "liac")) {520l = 0x9e8b00;521} if (l < 0x9e8b00 || l > 0x9e8b3f) {522printf("Invalid access code 0x%x\n", l);523exit(1);524}525lap[0] = (l & 0xff);526lap[1] = (l >> 8) & 0xff;527lap[2] = (l >> 16) & 0xff;528break;529530case 'f':531flags |= IREQ_CACHE_FLUSH;532break;533534default:535printf("%s", inq_help);536return;537}538}539helper_arg(0, 0, &argc, &argv, inq_help);540541printf("Inquiring ...\n");542543num_rsp = hci_inquiry(dev_id, length, num_rsp, lap, &info, flags);544if (num_rsp < 0) {545perror("Inquiry failed.");546exit(1);547}548549for (i = 0; i < num_rsp; i++) {550ba2str(&(info+i)->bdaddr, addr);551printf("\t%s\tclock offset: 0x%4.4x\tclass: 0x%2.2x%2.2x%2.2x\n",552addr, btohs((info+i)->clock_offset),553(info+i)->dev_class[2],554(info+i)->dev_class[1],555(info+i)->dev_class[0]);556}557558bt_free(info);559}560561/* Device scanning */562563static struct option scan_options[] = {564{ "help", 0, 0, 'h' },565{ "length", 1, 0, 'l' },566{ "numrsp", 1, 0, 'n' },567{ "iac", 1, 0, 'i' },568{ "flush", 0, 0, 'f' },569{ "refresh", 0, 0, 'r' },570{ "class", 0, 0, 'C' },571{ "info", 0, 0, 'I' },572{ "oui", 0, 0, 'O' },573{ "all", 0, 0, 'A' },574{ "ext", 0, 0, 'A' },575{ 0, 0, 0, 0 }576};577578static const char *scan_help =579"Usage:\n"580"\tscan [--length=N] [--numrsp=N] [--iac=lap] [--flush] [--class] [--info] [--oui] [--refresh]\n";581582static void cmd_scan(int dev_id, int argc, char **argv)583{584inquiry_info *info = NULL;585uint8_t lap[3] = { 0x33, 0x8b, 0x9e };586int num_rsp, length, flags;587uint8_t cls[3], features[8];588char addr[18], name[249], *comp, *tmp;589struct hci_version version;590struct hci_dev_info di;591struct hci_conn_info_req *cr;592int refresh = 0, extcls = 0, extinf = 0, extoui = 0;593int i, n, l, opt, dd, cc, nc;594595length = 8; /* ~10 seconds */596num_rsp = 0;597flags = 0;598599for_each_opt(opt, scan_options, NULL) {600switch (opt) {601case 'l':602length = atoi(optarg);603break;604605case 'n':606num_rsp = atoi(optarg);607break;608609case 'i':610l = strtoul(optarg, 0, 16);611if (!strcasecmp(optarg, "giac")) {612l = 0x9e8b33;613} else if (!strcasecmp(optarg, "liac")) {614l = 0x9e8b00;615} else if (l < 0x9e8b00 || l > 0x9e8b3f) {616printf("Invalid access code 0x%x\n", l);617exit(1);618}619lap[0] = (l & 0xff);620lap[1] = (l >> 8) & 0xff;621lap[2] = (l >> 16) & 0xff;622break;623624case 'f':625flags |= IREQ_CACHE_FLUSH;626break;627628case 'r':629refresh = 1;630break;631632case 'C':633extcls = 1;634break;635636case 'I':637extinf = 1;638break;639640case 'O':641extoui = 1;642break;643644case 'A':645extcls = 1;646extinf = 1;647extoui = 1;648break;649650default:651printf("%s", scan_help);652return;653}654}655helper_arg(0, 0, &argc, &argv, scan_help);656657if (dev_id < 0) {658dev_id = hci_get_route(NULL);659if (dev_id < 0) {660perror("Device is not available");661exit(1);662}663}664665if (hci_devinfo(dev_id, &di) < 0) {666perror("Can't get device info");667exit(1);668}669670printf("Scanning ...\n");671num_rsp = hci_inquiry(dev_id, length, num_rsp, lap, &info, flags);672if (num_rsp < 0) {673perror("Inquiry failed");674exit(1);675}676677dd = hci_open_dev(dev_id);678if (dd < 0) {679perror("HCI device open failed");680free(info);681exit(1);682}683684if (extcls || extinf || extoui)685printf("\n");686687for (i = 0; i < num_rsp; i++) {688uint16_t handle = 0;689690if (!refresh) {691memset(name, 0, sizeof(name));692tmp = get_device_name(&di.bdaddr, &(info+i)->bdaddr);693if (tmp) {694strncpy(name, tmp, 249);695free(tmp);696nc = 1;697} else698nc = 0;699} else700nc = 0;701702if (!extcls && !extinf && !extoui) {703ba2str(&(info+i)->bdaddr, addr);704705if (nc) {706printf("\t%s\t%s\n", addr, name);707continue;708}709710if (hci_read_remote_name_with_clock_offset(dd,711&(info+i)->bdaddr,712(info+i)->pscan_rep_mode,713(info+i)->clock_offset | 0x8000,714sizeof(name), name, 100000) < 0)715strcpy(name, "n/a");716717for (n = 0; n < 248 && name[n]; n++) {718if ((unsigned char) name[i] < 32 || name[i] == 127)719name[i] = '.';720}721722name[248] = '\0';723724printf("\t%s\t%s\n", addr, name);725continue;726}727728ba2str(&(info+i)->bdaddr, addr);729printf("BD Address:\t%s [mode %d, clkoffset 0x%4.4x]\n", addr,730(info+i)->pscan_rep_mode, btohs((info+i)->clock_offset));731732if (extoui) {733comp = batocomp(&(info+i)->bdaddr);734if (comp) {735char oui[9];736ba2oui(&(info+i)->bdaddr, oui);737printf("OUI company:\t%s (%s)\n", comp, oui);738free(comp);739}740}741742cc = 0;743744if (extinf) {745cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));746if (cr) {747bacpy(&cr->bdaddr, &(info+i)->bdaddr);748cr->type = ACL_LINK;749if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {750handle = 0;751cc = 1;752} else {753handle = htobs(cr->conn_info->handle);754cc = 0;755}756free(cr);757}758759if (cc) {760if (hci_create_connection(dd, &(info+i)->bdaddr,761htobs(di.pkt_type & ACL_PTYPE_MASK),762(info+i)->clock_offset | 0x8000,7630x01, &handle, 25000) < 0) {764handle = 0;765cc = 0;766}767}768}769770if (handle > 0 || !nc) {771if (hci_read_remote_name_with_clock_offset(dd,772&(info+i)->bdaddr,773(info+i)->pscan_rep_mode,774(info+i)->clock_offset | 0x8000,775sizeof(name), name, 100000) < 0) {776if (!nc)777strcpy(name, "n/a");778} else {779for (n = 0; n < 248 && name[n]; n++) {780if ((unsigned char) name[i] < 32 || name[i] == 127)781name[i] = '.';782}783784name[248] = '\0';785nc = 0;786}787}788789if (strlen(name) > 0)790printf("Device name:\t%s%s\n", name, nc ? " [cached]" : "");791792if (extcls) {793memcpy(cls, (info+i)->dev_class, 3);794printf("Device class:\t");795if ((cls[1] & 0x1f) > sizeof(major_classes) / sizeof(char *))796printf("Invalid");797else798printf("%s, %s", major_classes[cls[1] & 0x1f],799get_minor_device_name(cls[1] & 0x1f, cls[0] >> 2));800printf(" (0x%2.2x%2.2x%2.2x)\n", cls[2], cls[1], cls[0]);801}802803if (extinf && handle > 0) {804if (hci_read_remote_version(dd, handle, &version, 20000) == 0) {805char *ver = lmp_vertostr(version.lmp_ver);806printf("Manufacturer:\t%s (%d)\n",807bt_compidtostr(version.manufacturer),808version.manufacturer);809printf("LMP version:\t%s (0x%x) [subver 0x%x]\n",810ver ? ver : "n/a",811version.lmp_ver, version.lmp_subver);812if (ver)813bt_free(ver);814}815816if (hci_read_remote_features(dd, handle, features, 20000) == 0) {817char *tmp = lmp_featurestostr(features, "\t\t", 63);818printf("LMP features:\t0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x"819" 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",820features[0], features[1],821features[2], features[3],822features[4], features[5],823features[6], features[7]);824printf("%s\n", tmp);825bt_free(tmp);826}827828if (cc) {829usleep(10000);830hci_disconnect(dd, handle, HCI_OE_USER_ENDED_CONNECTION, 10000);831}832}833834printf("\n");835}836837bt_free(info);838839hci_close_dev(dd);840}841842/* Remote name */843844static struct option name_options[] = {845{ "help", 0, 0, 'h' },846{ 0, 0, 0, 0 }847};848849static const char *name_help =850"Usage:\n"851"\tname <bdaddr>\n";852853static void cmd_name(int dev_id, int argc, char **argv)854{855bdaddr_t bdaddr;856char name[248];857int opt, dd;858859for_each_opt(opt, name_options, NULL) {860switch (opt) {861default:862printf("%s", name_help);863return;864}865}866helper_arg(1, 1, &argc, &argv, name_help);867868str2ba(argv[0], &bdaddr);869870if (dev_id < 0) {871dev_id = hci_get_route(&bdaddr);872if (dev_id < 0) {873fprintf(stderr, "Device is not available.\n");874exit(1);875}876}877878dd = hci_open_dev(dev_id);879if (dd < 0) {880perror("HCI device open failed");881exit(1);882}883884if (hci_read_remote_name(dd, &bdaddr, sizeof(name), name, 25000) == 0)885printf("%s\n", name);886887hci_close_dev(dd);888}889890/* Info about remote device */891892static struct option info_options[] = {893{ "help", 0, 0, 'h' },894{ 0, 0, 0, 0 }895};896897static const char *info_help =898"Usage:\n"899"\tinfo <bdaddr>\n";900901static void cmd_info(int dev_id, int argc, char **argv)902{903bdaddr_t bdaddr;904uint16_t handle;905uint8_t features[8], max_page = 0;906char name[249], *comp, *tmp;907struct hci_version version;908struct hci_dev_info di;909struct hci_conn_info_req *cr;910int i, opt, dd, cc = 0;911912for_each_opt(opt, info_options, NULL) {913switch (opt) {914default:915printf("%s", info_help);916return;917}918}919helper_arg(1, 1, &argc, &argv, info_help);920921str2ba(argv[0], &bdaddr);922923if (dev_id < 0)924dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);925926if (dev_id < 0)927dev_id = hci_get_route(&bdaddr);928929if (dev_id < 0) {930fprintf(stderr, "Device is not available or not connected.\n");931exit(1);932}933934if (hci_devinfo(dev_id, &di) < 0) {935perror("Can't get device info");936exit(1);937}938939printf("Requesting information ...\n");940941dd = hci_open_dev(dev_id);942if (dd < 0) {943perror("HCI device open failed");944exit(1);945}946947cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));948if (!cr) {949perror("Can't get connection info");950close(dd);951exit(1);952}953954bacpy(&cr->bdaddr, &bdaddr);955cr->type = ACL_LINK;956if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {957if (hci_create_connection(dd, &bdaddr,958htobs(di.pkt_type & ACL_PTYPE_MASK),9590, 0x01, &handle, 25000) < 0) {960perror("Can't create connection");961close(dd);962exit(1);963}964sleep(1);965cc = 1;966} else967handle = htobs(cr->conn_info->handle);968969printf("\tBD Address: %s\n", argv[0]);970971comp = batocomp(&bdaddr);972if (comp) {973char oui[9];974ba2oui(&bdaddr, oui);975printf("\tOUI Company: %s (%s)\n", comp, oui);976free(comp);977}978979if (hci_read_remote_name(dd, &bdaddr, sizeof(name), name, 25000) == 0)980printf("\tDevice Name: %s\n", name);981982if (hci_read_remote_version(dd, handle, &version, 20000) == 0) {983char *ver = lmp_vertostr(version.lmp_ver);984printf("\tLMP Version: %s (0x%x) LMP Subversion: 0x%x\n"985"\tManufacturer: %s (%d)\n",986ver ? ver : "n/a",987version.lmp_ver,988version.lmp_subver,989bt_compidtostr(version.manufacturer),990version.manufacturer);991if (ver)992bt_free(ver);993}994995memset(features, 0, sizeof(features));996hci_read_remote_features(dd, handle, features, 20000);997998if ((di.features[7] & LMP_EXT_FEAT) && (features[7] & LMP_EXT_FEAT))999hci_read_remote_ext_features(dd, handle, 0, &max_page,1000features, 20000);10011002printf("\tFeatures%s: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "1003"0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",1004(max_page > 0) ? " page 0" : "",1005features[0], features[1], features[2], features[3],1006features[4], features[5], features[6], features[7]);10071008tmp = lmp_featurestostr(features, "\t\t", 63);1009printf("%s\n", tmp);1010bt_free(tmp);10111012for (i = 1; i <= max_page; i++) {1013if (hci_read_remote_ext_features(dd, handle, i, NULL,1014features, 20000) < 0)1015continue;10161017printf("\tFeatures page %d: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "1018"0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", i,1019features[0], features[1], features[2], features[3],1020features[4], features[5], features[6], features[7]);1021}10221023if (cc) {1024usleep(10000);1025hci_disconnect(dd, handle, HCI_OE_USER_ENDED_CONNECTION, 10000);1026}10271028hci_close_dev(dd);1029}10301031/* Start periodic inquiry */10321033static struct option spinq_options[] = {1034{ "help", 0, 0, 'h' },1035{ 0, 0, 0, 0 }1036};10371038static const char *spinq_help =1039"Usage:\n"1040"\tspinq\n";10411042static void cmd_spinq(int dev_id, int argc, char **argv)1043{1044uint8_t lap[3] = { 0x33, 0x8b, 0x9e };1045struct hci_request rq;1046periodic_inquiry_cp cp;1047int opt, dd;10481049for_each_opt(opt, spinq_options, NULL) {1050switch (opt) {1051default:1052printf("%s", spinq_help);1053return;1054}1055}1056helper_arg(0, 0, &argc, &argv, spinq_help);10571058if (dev_id < 0)1059dev_id = hci_get_route(NULL);10601061dd = hci_open_dev(dev_id);1062if (dd < 0) {1063perror("Device open failed");1064exit(EXIT_FAILURE);1065}10661067memset(&cp, 0, sizeof(cp));1068memcpy(cp.lap, lap, 3);1069cp.max_period = htobs(16);1070cp.min_period = htobs(10);1071cp.length = 8;1072cp.num_rsp = 0;10731074memset(&rq, 0, sizeof(rq));1075rq.ogf = OGF_LINK_CTL;1076rq.ocf = OCF_PERIODIC_INQUIRY;1077rq.cparam = &cp;1078rq.clen = PERIODIC_INQUIRY_CP_SIZE;10791080if (hci_send_req(dd, &rq, 100) < 0) {1081perror("Periodic inquiry failed");1082exit(EXIT_FAILURE);1083}10841085hci_close_dev(dd);1086}10871088/* Exit periodic inquiry */10891090static struct option epinq_options[] = {1091{ "help", 0, 0, 'h' },1092{ 0, 0, 0, 0 }1093};10941095static const char *epinq_help =1096"Usage:\n"1097"\tepinq\n";10981099static void cmd_epinq(int dev_id, int argc, char **argv)1100{1101int opt, dd;11021103for_each_opt(opt, epinq_options, NULL) {1104switch (opt) {1105default:1106printf("%s", epinq_help);1107return;1108}1109}1110helper_arg(0, 0, &argc, &argv, epinq_help);11111112if (dev_id < 0)1113dev_id = hci_get_route(NULL);11141115dd = hci_open_dev(dev_id);1116if (dd < 0) {1117perror("Device open failed");1118exit(EXIT_FAILURE);1119}11201121if (hci_send_cmd(dd, OGF_LINK_CTL,1122OCF_EXIT_PERIODIC_INQUIRY, 0, NULL) < 0) {1123perror("Exit periodic inquiry failed");1124exit(EXIT_FAILURE);1125}11261127hci_close_dev(dd);1128}11291130/* Send arbitrary HCI commands */11311132static struct option cmd_options[] = {1133{ "help", 0, 0, 'h' },1134{ 0, 0, 0, 0 }1135};11361137static const char *cmd_help =1138"Usage:\n"1139"\tcmd <ogf> <ocf> [parameters]\n"1140"Example:\n"1141"\tcmd 0x03 0x0013 0x41 0x42 0x43 0x44\n";11421143static void cmd_cmd(int dev_id, int argc, char **argv)1144{1145unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;1146struct hci_filter flt;1147hci_event_hdr *hdr;1148int i, opt, len, dd;1149uint16_t ocf;1150uint8_t ogf;11511152for_each_opt(opt, cmd_options, NULL) {1153switch (opt) {1154default:1155printf("%s", cmd_help);1156return;1157}1158}1159helper_arg(2, -1, &argc, &argv, cmd_help);11601161if (dev_id < 0)1162dev_id = hci_get_route(NULL);11631164errno = 0;1165ogf = strtol(argv[0], NULL, 16);1166ocf = strtol(argv[1], NULL, 16);1167if (errno == ERANGE || (ogf > 0x3f) || (ocf > 0x3ff)) {1168printf("%s", cmd_help);1169return;1170}11711172for (i = 2, len = 0; i < argc && len < (int) sizeof(buf); i++, len++)1173*ptr++ = (uint8_t) strtol(argv[i], NULL, 16);11741175dd = hci_open_dev(dev_id);1176if (dd < 0) {1177perror("Device open failed");1178exit(EXIT_FAILURE);1179}11801181/* Setup filter */1182hci_filter_clear(&flt);1183hci_filter_set_ptype(HCI_EVENT_PKT, &flt);1184hci_filter_all_events(&flt);1185if (setsockopt(dd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {1186perror("HCI filter setup failed");1187exit(EXIT_FAILURE);1188}11891190printf("< HCI Command: ogf 0x%02x, ocf 0x%04x, plen %d\n", ogf, ocf, len);1191hex_dump(" ", 20, buf, len); fflush(stdout);11921193if (hci_send_cmd(dd, ogf, ocf, len, buf) < 0) {1194perror("Send failed");1195exit(EXIT_FAILURE);1196}11971198len = read(dd, buf, sizeof(buf));1199if (len < 0) {1200perror("Read failed");1201exit(EXIT_FAILURE);1202}12031204hdr = (void *)(buf + 1);1205ptr = buf + (1 + HCI_EVENT_HDR_SIZE);1206len -= (1 + HCI_EVENT_HDR_SIZE);12071208printf("> HCI Event: 0x%02x plen %d\n", hdr->evt, hdr->plen);1209hex_dump(" ", 20, ptr, len); fflush(stdout);12101211hci_close_dev(dd);1212}12131214/* Display active connections */12151216static struct option con_options[] = {1217{ "help", 0, 0, 'h' },1218{ 0, 0, 0, 0 }1219};12201221static const char *con_help =1222"Usage:\n"1223"\tcon\n";12241225static void cmd_con(int dev_id, int argc, char **argv)1226{1227int opt;12281229for_each_opt(opt, con_options, NULL) {1230switch (opt) {1231default:1232printf("%s", con_help);1233return;1234}1235}1236helper_arg(0, 0, &argc, &argv, con_help);12371238printf("Connections:\n");12391240hci_for_each_dev(HCI_UP, conn_list, dev_id);1241}12421243/* Create connection */12441245static struct option cc_options[] = {1246{ "help", 0, 0, 'h' },1247{ "role", 1, 0, 'r' },1248{ "ptype", 1, 0, 'p' },1249{ 0, 0, 0, 0 }1250};12511252static const char *cc_help =1253"Usage:\n"1254"\tcc [--role=m|s] [--ptype=pkt_types] <bdaddr>\n"1255"Example:\n"1256"\tcc --ptype=dm1,dh3,dh5 01:02:03:04:05:06\n"1257"\tcc --role=m 01:02:03:04:05:06\n";12581259static void cmd_cc(int dev_id, int argc, char **argv)1260{1261bdaddr_t bdaddr;1262uint16_t handle;1263uint8_t role;1264unsigned int ptype;1265int dd, opt;12661267role = 0x01;1268ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5;12691270for_each_opt(opt, cc_options, NULL) {1271switch (opt) {1272case 'p':1273hci_strtoptype(optarg, &ptype);1274break;12751276case 'r':1277role = optarg[0] == 'm' ? 0 : 1;1278break;12791280default:1281printf("%s", cc_help);1282return;1283}1284}1285helper_arg(1, 1, &argc, &argv, cc_help);12861287str2ba(argv[0], &bdaddr);12881289if (dev_id < 0) {1290dev_id = hci_get_route(&bdaddr);1291if (dev_id < 0) {1292fprintf(stderr, "Device is not available.\n");1293exit(1);1294}1295}12961297dd = hci_open_dev(dev_id);1298if (dd < 0) {1299perror("HCI device open failed");1300exit(1);1301}13021303if (hci_create_connection(dd, &bdaddr, htobs(ptype),1304htobs(0x0000), role, &handle, 25000) < 0)1305perror("Can't create connection");13061307hci_close_dev(dd);1308}13091310/* Close connection */13111312static struct option dc_options[] = {1313{ "help", 0, 0, 'h' },1314{ 0, 0, 0, 0 }1315};13161317static const char *dc_help =1318"Usage:\n"1319"\tdc <bdaddr> [reason]\n";13201321static void cmd_dc(int dev_id, int argc, char **argv)1322{1323struct hci_conn_info_req *cr;1324bdaddr_t bdaddr;1325uint8_t reason;1326int opt, dd;13271328for_each_opt(opt, dc_options, NULL) {1329switch (opt) {1330default:1331printf("%s", dc_help);1332return;1333}1334}1335helper_arg(1, 2, &argc, &argv, dc_help);13361337str2ba(argv[0], &bdaddr);1338reason = (argc > 1) ? atoi(argv[1]) : HCI_OE_USER_ENDED_CONNECTION;13391340if (dev_id < 0) {1341dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);1342if (dev_id < 0) {1343fprintf(stderr, "Not connected.\n");1344exit(1);1345}1346}13471348dd = hci_open_dev(dev_id);1349if (dd < 0) {1350perror("HCI device open failed");1351exit(1);1352}13531354cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));1355if (!cr) {1356perror("Can't allocate memory");1357exit(1);1358}13591360bacpy(&cr->bdaddr, &bdaddr);1361cr->type = ACL_LINK;1362if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {1363perror("Get connection info failed");1364exit(1);1365}13661367if (hci_disconnect(dd, htobs(cr->conn_info->handle),1368reason, 10000) < 0)1369perror("Disconnect failed");13701371free(cr);13721373hci_close_dev(dd);1374}13751376/* Role switch */13771378static struct option sr_options[] = {1379{ "help", 0, 0, 'h' },1380{ 0, 0, 0, 0 }1381};13821383static const char *sr_help =1384"Usage:\n"1385"\tsr <bdaddr> <role>\n";13861387static void cmd_sr(int dev_id, int argc, char **argv)1388{1389bdaddr_t bdaddr;1390uint8_t role;1391int opt, dd;13921393for_each_opt(opt, sr_options, NULL) {1394switch (opt) {1395default:1396printf("%s", sr_help);1397return;1398}1399}1400helper_arg(2, 2, &argc, &argv, sr_help);14011402str2ba(argv[0], &bdaddr);1403switch (argv[1][0]) {1404case 'm':1405role = 0;1406break;1407case 's':1408role = 1;1409break;1410default:1411role = atoi(argv[1]);1412break;1413}14141415if (dev_id < 0) {1416dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);1417if (dev_id < 0) {1418fprintf(stderr, "Not connected.\n");1419exit(1);1420}1421}14221423dd = hci_open_dev(dev_id);1424if (dd < 0) {1425perror("HCI device open failed");1426exit(1);1427}14281429if (hci_switch_role(dd, &bdaddr, role, 10000) < 0) {1430perror("Switch role request failed");1431exit(1);1432}14331434hci_close_dev(dd);1435}14361437/* Read RSSI */14381439static struct option rssi_options[] = {1440{ "help", 0, 0, 'h' },1441{ 0, 0, 0, 0 }1442};14431444static const char *rssi_help =1445"Usage:\n"1446"\trssi <bdaddr>\n";14471448static void cmd_rssi(int dev_id, int argc, char **argv)1449{1450struct hci_conn_info_req *cr;1451bdaddr_t bdaddr;1452int8_t rssi;1453int opt, dd;14541455for_each_opt(opt, rssi_options, NULL) {1456switch (opt) {1457default:1458printf("%s", rssi_help);1459return;1460}1461}1462helper_arg(1, 1, &argc, &argv, rssi_help);14631464str2ba(argv[0], &bdaddr);14651466if (dev_id < 0) {1467dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);1468if (dev_id < 0) {1469fprintf(stderr, "Not connected.\n");1470exit(1);1471}1472}14731474dd = hci_open_dev(dev_id);1475if (dd < 0) {1476perror("HCI device open failed");1477exit(1);1478}14791480cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));1481if (!cr) {1482perror("Can't allocate memory");1483exit(1);1484}14851486bacpy(&cr->bdaddr, &bdaddr);1487cr->type = ACL_LINK;1488if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {1489perror("Get connection info failed");1490exit(1);1491}14921493if (hci_read_rssi(dd, htobs(cr->conn_info->handle), &rssi, 1000) < 0) {1494perror("Read RSSI failed");1495exit(1);1496}14971498printf("RSSI return value: %d\n", rssi);14991500free(cr);15011502hci_close_dev(dd);1503}15041505/* Get link quality */15061507static struct option lq_options[] = {1508{ "help", 0, 0, 'h' },1509{ 0, 0, 0, 0 }1510};15111512static const char *lq_help =1513"Usage:\n"1514"\tlq <bdaddr>\n";15151516static void cmd_lq(int dev_id, int argc, char **argv)1517{1518struct hci_conn_info_req *cr;1519bdaddr_t bdaddr;1520uint8_t lq;1521int opt, dd;15221523for_each_opt(opt, lq_options, NULL) {1524switch (opt) {1525default:1526printf("%s", lq_help);1527return;1528}1529}1530helper_arg(1, 1, &argc, &argv, lq_help);15311532str2ba(argv[0], &bdaddr);15331534if (dev_id < 0) {1535dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);1536if (dev_id < 0) {1537fprintf(stderr, "Not connected.\n");1538exit(1);1539}1540}15411542dd = hci_open_dev(dev_id);1543if (dd < 0) {1544perror("HCI device open failed");1545exit(1);1546}15471548cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));1549if (!cr) {1550perror("Can't allocate memory");1551exit(1);1552}15531554bacpy(&cr->bdaddr, &bdaddr);1555cr->type = ACL_LINK;1556if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {1557perror("Get connection info failed");1558exit(1);1559}15601561if (hci_read_link_quality(dd, htobs(cr->conn_info->handle), &lq, 1000) < 0) {1562perror("HCI read_link_quality request failed");1563exit(1);1564}15651566printf("Link quality: %d\n", lq);15671568free(cr);15691570hci_close_dev(dd);1571}15721573/* Get transmit power level */15741575static struct option tpl_options[] = {1576{ "help", 0, 0, 'h' },1577{ 0, 0, 0, 0 }1578};15791580static const char *tpl_help =1581"Usage:\n"1582"\ttpl <bdaddr> [type]\n";15831584static void cmd_tpl(int dev_id, int argc, char **argv)1585{1586struct hci_conn_info_req *cr;1587bdaddr_t bdaddr;1588uint8_t type;1589int8_t level;1590int opt, dd;15911592for_each_opt(opt, tpl_options, NULL) {1593switch (opt) {1594default:1595printf("%s", tpl_help);1596return;1597}1598}1599helper_arg(1, 2, &argc, &argv, tpl_help);16001601str2ba(argv[0], &bdaddr);1602type = (argc > 1) ? atoi(argv[1]) : 0;16031604if (dev_id < 0) {1605dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);1606if (dev_id < 0) {1607fprintf(stderr, "Not connected.\n");1608exit(1);1609}1610}16111612dd = hci_open_dev(dev_id);1613if (dd < 0) {1614perror("HCI device open failed");1615exit(1);1616}16171618cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));1619if (!cr) {1620perror("Can't allocate memory");1621exit(1);1622}16231624bacpy(&cr->bdaddr, &bdaddr);1625cr->type = ACL_LINK;1626if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {1627perror("Get connection info failed");1628exit(1);1629}16301631if (hci_read_transmit_power_level(dd, htobs(cr->conn_info->handle), type, &level, 1000) < 0) {1632perror("HCI read transmit power level request failed");1633exit(1);1634}16351636printf("%s transmit power level: %d\n",1637(type == 0) ? "Current" : "Maximum", level);16381639free(cr);16401641hci_close_dev(dd);1642}16431644/* Get AFH channel map */16451646static struct option afh_options[] = {1647{ "help", 0, 0, 'h' },1648{ 0, 0, 0, 0 }1649};16501651static const char *afh_help =1652"Usage:\n"1653"\tafh <bdaddr>\n";16541655static void cmd_afh(int dev_id, int argc, char **argv)1656{1657struct hci_conn_info_req *cr;1658bdaddr_t bdaddr;1659uint16_t handle;1660uint8_t mode, map[10];1661int opt, dd;16621663for_each_opt(opt, afh_options, NULL) {1664switch (opt) {1665default:1666printf("%s", afh_help);1667return;1668}1669}1670helper_arg(1, 1, &argc, &argv, afh_help);16711672str2ba(argv[0], &bdaddr);16731674if (dev_id < 0) {1675dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);1676if (dev_id < 0) {1677fprintf(stderr, "Not connected.\n");1678exit(1);1679}1680}16811682dd = hci_open_dev(dev_id);1683if (dd < 0) {1684perror("HCI device open failed");1685exit(1);1686}16871688cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));1689if (!cr) {1690perror("Can't allocate memory");1691exit(1);1692}16931694bacpy(&cr->bdaddr, &bdaddr);1695cr->type = ACL_LINK;1696if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {1697perror("Get connection info failed");1698exit(1);1699}17001701handle = htobs(cr->conn_info->handle);17021703if (hci_read_afh_map(dd, handle, &mode, map, 1000) < 0) {1704perror("HCI read AFH map request failed");1705exit(1);1706}17071708if (mode == 0x01) {1709int i;1710printf("AFH map: 0x");1711for (i = 0; i < 10; i++)1712printf("%02x", map[i]);1713printf("\n");1714} else1715printf("AFH disabled\n");17161717free(cr);17181719hci_close_dev(dd);1720}17211722/* Set connection packet type */17231724static struct option cpt_options[] = {1725{ "help", 0, 0, 'h' },1726{ 0, 0, 0, 0 }1727};17281729static const char *cpt_help =1730"Usage:\n"1731"\tcpt <bdaddr> <packet_types>\n";17321733static void cmd_cpt(int dev_id, int argc, char **argv)1734{1735struct hci_conn_info_req *cr;1736struct hci_request rq;1737set_conn_ptype_cp cp;1738evt_conn_ptype_changed rp;1739bdaddr_t bdaddr;1740unsigned int ptype;1741int dd, opt;17421743for_each_opt(opt, cpt_options, NULL) {1744switch (opt) {1745default:1746printf("%s", cpt_help);1747return;1748}1749}1750helper_arg(2, 2, &argc, &argv, cpt_help);17511752str2ba(argv[0], &bdaddr);1753hci_strtoptype(argv[1], &ptype);17541755if (dev_id < 0) {1756dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);1757if (dev_id < 0) {1758fprintf(stderr, "Not connected.\n");1759exit(1);1760}1761}17621763dd = hci_open_dev(dev_id);1764if (dd < 0) {1765perror("HCI device open failed");1766exit(1);1767}17681769cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));1770if (!cr) {1771perror("Can't allocate memory");1772exit(1);1773}17741775bacpy(&cr->bdaddr, &bdaddr);1776cr->type = ACL_LINK;1777if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {1778perror("Get connection info failed");1779exit(1);1780}17811782cp.handle = htobs(cr->conn_info->handle);1783cp.pkt_type = ptype;17841785memset(&rq, 0, sizeof(rq));1786rq.ogf = OGF_LINK_CTL;1787rq.ocf = OCF_SET_CONN_PTYPE;1788rq.cparam = &cp;1789rq.clen = SET_CONN_PTYPE_CP_SIZE;1790rq.rparam = &rp;1791rq.rlen = EVT_CONN_PTYPE_CHANGED_SIZE;1792rq.event = EVT_CONN_PTYPE_CHANGED;17931794if (hci_send_req(dd, &rq, 100) < 0) {1795perror("Packet type change failed");1796exit(1);1797}17981799free(cr);18001801hci_close_dev(dd);1802}18031804/* Get/Set link policy settings */18051806static struct option lp_options[] = {1807{ "help", 0, 0, 'h' },1808{ 0, 0, 0, 0 }1809};18101811static const char *lp_help =1812"Usage:\n"1813"\tlp <bdaddr> [link policy]\n";18141815static void cmd_lp(int dev_id, int argc, char **argv)1816{1817struct hci_conn_info_req *cr;1818bdaddr_t bdaddr;1819uint16_t policy;1820int opt, dd;18211822for_each_opt(opt, lp_options, NULL) {1823switch (opt) {1824default:1825printf("%s", lp_help);1826return;1827}1828}1829helper_arg(1, 2, &argc, &argv, lp_help);18301831str2ba(argv[0], &bdaddr);18321833if (dev_id < 0) {1834dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);1835if (dev_id < 0) {1836fprintf(stderr, "Not connected.\n");1837exit(1);1838}1839}18401841dd = hci_open_dev(dev_id);1842if (dd < 0) {1843perror("HCI device open failed");1844exit(1);1845}18461847cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));1848if (!cr) {1849perror("Can't allocate memory");1850exit(1);1851}18521853bacpy(&cr->bdaddr, &bdaddr);1854cr->type = ACL_LINK;1855if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {1856perror("Get connection info failed");1857exit(1);1858}18591860if (argc == 1) {1861char *str;1862if (hci_read_link_policy(dd, htobs(cr->conn_info->handle),1863&policy, 1000) < 0) {1864perror("HCI read_link_policy_settings request failed");1865exit(1);1866}18671868policy = btohs(policy);1869str = hci_lptostr(policy);1870if (str) {1871printf("Link policy settings: %s\n", str);1872bt_free(str);1873} else {1874fprintf(stderr, "Invalig settings\n");1875exit(1);1876}1877} else {1878unsigned int val;1879if (hci_strtolp(argv[1], &val) < 0) {1880fprintf(stderr, "Invalig arguments\n");1881exit(1);1882}1883policy = val;18841885if (hci_write_link_policy(dd, htobs(cr->conn_info->handle),1886htobs(policy), 1000) < 0) {1887perror("HCI write_link_policy_settings request failed");1888exit(1);1889}1890}18911892free(cr);18931894hci_close_dev(dd);1895}18961897/* Get/Set link supervision timeout */18981899static struct option lst_options[] = {1900{ "help", 0, 0, 'h' },1901{ 0, 0, 0, 0 }1902};19031904static const char *lst_help =1905"Usage:\n"1906"\tlst <bdaddr> [new value in slots]\n";19071908static void cmd_lst(int dev_id, int argc, char **argv)1909{1910struct hci_conn_info_req *cr;1911bdaddr_t bdaddr;1912uint16_t timeout;1913int opt, dd;19141915for_each_opt(opt, lst_options, NULL) {1916switch (opt) {1917default:1918printf("%s", lst_help);1919return;1920}1921}1922helper_arg(1, 2, &argc, &argv, lst_help);19231924str2ba(argv[0], &bdaddr);19251926if (dev_id < 0) {1927dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);1928if (dev_id < 0) {1929fprintf(stderr, "Not connected.\n");1930exit(1);1931}1932}19331934dd = hci_open_dev(dev_id);1935if (dd < 0) {1936perror("HCI device open failed");1937exit(1);1938}19391940cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));1941if (!cr) {1942perror("Can't allocate memory");1943exit(1);1944}19451946bacpy(&cr->bdaddr, &bdaddr);1947cr->type = ACL_LINK;1948if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {1949perror("Get connection info failed");1950exit(1);1951}19521953if (argc == 1) {1954if (hci_read_link_supervision_timeout(dd, htobs(cr->conn_info->handle),1955&timeout, 1000) < 0) {1956perror("HCI read_link_supervision_timeout request failed");1957exit(1);1958}19591960timeout = btohs(timeout);19611962if (timeout)1963printf("Link supervision timeout: %u slots (%.2f msec)\n",1964timeout, (float) timeout * 0.625);1965else1966printf("Link supervision timeout never expires\n");1967} else {1968timeout = strtol(argv[1], NULL, 10);19691970if (hci_write_link_supervision_timeout(dd, htobs(cr->conn_info->handle),1971htobs(timeout), 1000) < 0) {1972perror("HCI write_link_supervision_timeout request failed");1973exit(1);1974}1975}19761977free(cr);19781979hci_close_dev(dd);1980}19811982/* Request authentication */19831984static struct option auth_options[] = {1985{ "help", 0, 0, 'h' },1986{ 0, 0, 0, 0 }1987};19881989static const char *auth_help =1990"Usage:\n"1991"\tauth <bdaddr>\n";19921993static void cmd_auth(int dev_id, int argc, char **argv)1994{1995struct hci_conn_info_req *cr;1996bdaddr_t bdaddr;1997int opt, dd;19981999for_each_opt(opt, auth_options, NULL) {2000switch (opt) {2001default:2002printf("%s", auth_help);2003return;2004}2005}2006helper_arg(1, 1, &argc, &argv, auth_help);20072008str2ba(argv[0], &bdaddr);20092010if (dev_id < 0) {2011dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);2012if (dev_id < 0) {2013fprintf(stderr, "Not connected.\n");2014exit(1);2015}2016}20172018dd = hci_open_dev(dev_id);2019if (dd < 0) {2020perror("HCI device open failed");2021exit(1);2022}20232024cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));2025if (!cr) {2026perror("Can't allocate memory");2027exit(1);2028}20292030bacpy(&cr->bdaddr, &bdaddr);2031cr->type = ACL_LINK;2032if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {2033perror("Get connection info failed");2034exit(1);2035}20362037if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000) < 0) {2038perror("HCI authentication request failed");2039exit(1);2040}20412042free(cr);20432044hci_close_dev(dd);2045}20462047/* Activate encryption */20482049static struct option enc_options[] = {2050{ "help", 0, 0, 'h' },2051{ 0, 0, 0, 0 }2052};20532054static const char *enc_help =2055"Usage:\n"2056"\tenc <bdaddr> [encrypt enable]\n";20572058static void cmd_enc(int dev_id, int argc, char **argv)2059{2060struct hci_conn_info_req *cr;2061bdaddr_t bdaddr;2062uint8_t encrypt;2063int opt, dd;20642065for_each_opt(opt, enc_options, NULL) {2066switch (opt) {2067default:2068printf("%s", enc_help);2069return;2070}2071}2072helper_arg(1, 2, &argc, &argv, enc_help);20732074str2ba(argv[0], &bdaddr);20752076if (dev_id < 0) {2077dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);2078if (dev_id < 0) {2079fprintf(stderr, "Not connected.\n");2080exit(1);2081}2082}20832084dd = hci_open_dev(dev_id);2085if (dd < 0) {2086perror("HCI device open failed");2087exit(1);2088}20892090cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));2091if (!cr) {2092perror("Can't allocate memory");2093exit(1);2094}20952096bacpy(&cr->bdaddr, &bdaddr);2097cr->type = ACL_LINK;2098if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {2099perror("Get connection info failed");2100exit(1);2101}21022103encrypt = (argc > 1) ? atoi(argv[1]) : 1;21042105if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), encrypt, 25000) < 0) {2106perror("HCI set encryption request failed");2107exit(1);2108}21092110free(cr);21112112hci_close_dev(dd);2113}21142115/* Change connection link key */21162117static struct option key_options[] = {2118{ "help", 0, 0, 'h' },2119{ 0, 0, 0, 0 }2120};21212122static const char *key_help =2123"Usage:\n"2124"\tkey <bdaddr>\n";21252126static void cmd_key(int dev_id, int argc, char **argv)2127{2128struct hci_conn_info_req *cr;2129bdaddr_t bdaddr;2130int opt, dd;21312132for_each_opt(opt, key_options, NULL) {2133switch (opt) {2134default:2135printf("%s", key_help);2136return;2137}2138}2139helper_arg(1, 1, &argc, &argv, key_help);21402141str2ba(argv[0], &bdaddr);21422143if (dev_id < 0) {2144dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);2145if (dev_id < 0) {2146fprintf(stderr, "Not connected.\n");2147exit(1);2148}2149}21502151dd = hci_open_dev(dev_id);2152if (dd < 0) {2153perror("HCI device open failed");2154exit(1);2155}21562157cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));2158if (!cr) {2159perror("Can't allocate memory");2160exit(1);2161}21622163bacpy(&cr->bdaddr, &bdaddr);2164cr->type = ACL_LINK;2165if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {2166perror("Get connection info failed");2167exit(1);2168}21692170if (hci_change_link_key(dd, htobs(cr->conn_info->handle), 25000) < 0) {2171perror("Changing link key failed");2172exit(1);2173}21742175free(cr);21762177hci_close_dev(dd);2178}21792180/* Read clock offset */21812182static struct option clkoff_options[] = {2183{ "help", 0, 0, 'h' },2184{ 0, 0, 0, 0 }2185};21862187static const char *clkoff_help =2188"Usage:\n"2189"\tclkoff <bdaddr>\n";21902191static void cmd_clkoff(int dev_id, int argc, char **argv)2192{2193struct hci_conn_info_req *cr;2194bdaddr_t bdaddr;2195uint16_t offset;2196int opt, dd;21972198for_each_opt(opt, clkoff_options, NULL) {2199switch (opt) {2200default:2201printf("%s", clkoff_help);2202return;2203}2204}2205helper_arg(1, 1, &argc, &argv, clkoff_help);22062207str2ba(argv[0], &bdaddr);22082209if (dev_id < 0) {2210dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);2211if (dev_id < 0) {2212fprintf(stderr, "Not connected.\n");2213exit(1);2214}2215}22162217dd = hci_open_dev(dev_id);2218if (dd < 0) {2219perror("HCI device open failed");2220exit(1);2221}22222223cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));2224if (!cr) {2225perror("Can't allocate memory");2226exit(1);2227}22282229bacpy(&cr->bdaddr, &bdaddr);2230cr->type = ACL_LINK;2231if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {2232perror("Get connection info failed");2233exit(1);2234}22352236if (hci_read_clock_offset(dd, htobs(cr->conn_info->handle), &offset, 1000) < 0) {2237perror("Reading clock offset failed");2238exit(1);2239}22402241printf("Clock offset: 0x%4.4x\n", btohs(offset));22422243free(cr);22442245hci_close_dev(dd);2246}22472248/* Read clock */22492250static struct option clock_options[] = {2251{ "help", 0, 0, 'h' },2252{ 0, 0, 0, 0 }2253};22542255static const char *clock_help =2256"Usage:\n"2257"\tclock [bdaddr] [which clock]\n";22582259static void cmd_clock(int dev_id, int argc, char **argv)2260{2261struct hci_conn_info_req *cr;2262bdaddr_t bdaddr;2263uint8_t which;2264uint32_t handle, clock;2265uint16_t accuracy;2266int opt, dd;22672268for_each_opt(opt, clock_options, NULL) {2269switch (opt) {2270default:2271printf("%s", clock_help);2272return;2273}2274}2275helper_arg(0, 2, &argc, &argv, clock_help);22762277if (argc > 0)2278str2ba(argv[0], &bdaddr);2279else2280bacpy(&bdaddr, BDADDR_ANY);22812282if (dev_id < 0 && !bacmp(&bdaddr, BDADDR_ANY))2283dev_id = hci_get_route(NULL);22842285if (dev_id < 0) {2286dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);2287if (dev_id < 0) {2288fprintf(stderr, "Not connected.\n");2289exit(1);2290}2291}22922293dd = hci_open_dev(dev_id);2294if (dd < 0) {2295perror("HCI device open failed");2296exit(1);2297}22982299if (bacmp(&bdaddr, BDADDR_ANY)) {2300cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));2301if (!cr) {2302perror("Can't allocate memory");2303exit(1);2304}23052306bacpy(&cr->bdaddr, &bdaddr);2307cr->type = ACL_LINK;2308if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {2309perror("Get connection info failed");2310free(cr);2311exit(1);2312}23132314handle = htobs(cr->conn_info->handle);2315which = (argc > 1) ? atoi(argv[1]) : 0x01;23162317free(cr);2318} else {2319handle = 0x00;2320which = 0x00;2321}23222323if (hci_read_clock(dd, handle, which, &clock, &accuracy, 1000) < 0) {2324perror("Reading clock failed");2325exit(1);2326}23272328accuracy = btohs(accuracy);23292330printf("Clock: 0x%4.4x\n", btohl(clock));2331printf("Accuracy: %.2f msec\n", (float) accuracy * 0.3125);23322333hci_close_dev(dd);2334}23352336static int read_flags(uint8_t *flags, const uint8_t *data, size_t size)2337{2338size_t offset;23392340if (!flags || !data)2341return -EINVAL;23422343offset = 0;2344while (offset < size) {2345uint8_t len = data[offset];2346uint8_t type;23472348/* Check if it is the end of the significant part */2349if (len == 0)2350break;23512352if (len + offset > size)2353break;23542355type = data[offset + 1];23562357if (type == FLAGS_AD_TYPE) {2358*flags = data[offset + 2];2359return 0;2360}23612362offset += 1 + len;2363}23642365return -ENOENT;2366}23672368static int check_report_filter(uint8_t procedure, le_advertising_info *info)2369{2370uint8_t flags;23712372/* If no discovery procedure is set, all reports are treat as valid */2373if (procedure == 0)2374return 1;23752376/* Read flags AD type value from the advertising report if it exists */2377if (read_flags(&flags, info->data, info->length))2378return 0;23792380switch (procedure) {2381case 'l': /* Limited Discovery Procedure */2382if (flags & FLAGS_LIMITED_MODE_BIT)2383return 1;2384break;2385case 'g': /* General Discovery Procedure */2386if (flags & (FLAGS_LIMITED_MODE_BIT | FLAGS_GENERAL_MODE_BIT))2387return 1;2388break;2389default:2390fprintf(stderr, "Unknown discovery procedure\n");2391}23922393return 0;2394}23952396static void sigint_handler(int sig)2397{2398signal_received = sig;2399}24002401static void eir_parse_name(uint8_t *eir, size_t eir_len,2402char *buf, size_t buf_len)2403{2404size_t offset;24052406offset = 0;2407while (offset < eir_len) {2408uint8_t field_len = eir[0];2409size_t name_len;24102411/* Check for the end of EIR */2412if (field_len == 0)2413break;24142415if (offset + field_len > eir_len)2416goto failed;24172418switch (eir[1]) {2419case EIR_NAME_SHORT:2420case EIR_NAME_COMPLETE:2421name_len = field_len - 1;2422if (name_len > buf_len)2423goto failed;24242425memcpy(buf, &eir[2], name_len);2426return;2427}24282429offset += field_len + 1;2430eir += field_len + 1;2431}24322433failed:2434snprintf(buf, buf_len, "(unknown)");2435}24362437static int print_advertising_devices(int dd, uint8_t filter_type)2438{2439unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;2440struct hci_filter nf, of;2441struct sigaction sa;2442socklen_t olen;2443int len;24442445olen = sizeof(of);2446if (getsockopt(dd, SOL_HCI, HCI_FILTER, &of, &olen) < 0) {2447printf("Could not get socket options\n");2448return -1;2449}24502451hci_filter_clear(&nf);2452hci_filter_set_ptype(HCI_EVENT_PKT, &nf);2453hci_filter_set_event(EVT_LE_META_EVENT, &nf);24542455if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) {2456printf("Could not set socket options\n");2457return -1;2458}24592460memset(&sa, 0, sizeof(sa));2461sa.sa_flags = SA_NOCLDSTOP;2462sa.sa_handler = sigint_handler;2463sigaction(SIGINT, &sa, NULL);24642465while (1) {2466evt_le_meta_event *meta;2467le_advertising_info *info;2468char addr[18];24692470while ((len = read(dd, buf, sizeof(buf))) < 0) {2471if (errno == EINTR && signal_received == SIGINT) {2472len = 0;2473goto done;2474}24752476if (errno == EAGAIN || errno == EINTR)2477continue;2478goto done;2479}24802481ptr = buf + (1 + HCI_EVENT_HDR_SIZE);2482len -= (1 + HCI_EVENT_HDR_SIZE);24832484meta = (void *) ptr;24852486if (meta->subevent != 0x02)2487goto done;24882489/* Ignoring multiple reports */2490info = (le_advertising_info *) (meta->data + 1);2491if (check_report_filter(filter_type, info)) {2492char name[30];24932494memset(name, 0, sizeof(name));24952496ba2str(&info->bdaddr, addr);2497eir_parse_name(info->data, info->length,2498name, sizeof(name) - 1);24992500printf("%s %s\n", addr, name);2501}2502}25032504done:2505setsockopt(dd, SOL_HCI, HCI_FILTER, &of, sizeof(of));25062507if (len < 0)2508return -1;25092510return 0;2511}25122513static struct option lescan_options[] = {2514{ "help", 0, 0, 'h' },2515{ "privacy", 0, 0, 'p' },2516{ "passive", 0, 0, 'P' },2517{ "whitelist", 0, 0, 'w' },2518{ "discovery", 1, 0, 'd' },2519{ "duplicates", 0, 0, 'D' },2520{ 0, 0, 0, 0 }2521};25222523static const char *lescan_help =2524"Usage:\n"2525"\tlescan [--privacy] enable privacy\n"2526"\tlescan [--passive] set scan type passive (default active)\n"2527"\tlescan [--whitelist] scan for address in the whitelist only\n"2528"\tlescan [--discovery=g|l] enable general or limited discovery"2529"procedure\n"2530"\tlescan [--duplicates] don't filter duplicates\n";25312532static void cmd_lescan(int dev_id, int argc, char **argv)2533{2534int err, opt, dd;2535uint8_t own_type = 0x00;2536uint8_t scan_type = 0x01;2537uint8_t filter_type = 0;2538uint8_t filter_policy = 0x00;2539uint16_t interval = htobs(0x0010);2540uint16_t window = htobs(0x0010);2541uint8_t filter_dup = 1;25422543for_each_opt(opt, lescan_options, NULL) {2544switch (opt) {2545case 'p':2546own_type = 0x01; /* Random */2547break;2548case 'P':2549scan_type = 0x00; /* Passive */2550break;2551case 'w':2552filter_policy = 0x01; /* Whitelist */2553break;2554case 'd':2555filter_type = optarg[0];2556if (filter_type != 'g' && filter_type != 'l') {2557fprintf(stderr, "Unknown discovery procedure\n");2558exit(1);2559}25602561interval = htobs(0x0012);2562window = htobs(0x0012);2563break;2564case 'D':2565filter_dup = 0x00;2566break;2567default:2568printf("%s", lescan_help);2569return;2570}2571}2572helper_arg(0, 1, &argc, &argv, lescan_help);25732574if (dev_id < 0)2575dev_id = hci_get_route(NULL);25762577dd = hci_open_dev(dev_id);2578if (dd < 0) {2579perror("Could not open device");2580exit(1);2581}25822583err = hci_le_set_scan_parameters(dd, scan_type, interval, window,2584own_type, filter_policy, 1000);2585if (err < 0) {2586perror("Set scan parameters failed");2587exit(1);2588}25892590err = hci_le_set_scan_enable(dd, 0x01, filter_dup, 1000);2591if (err < 0) {2592perror("Enable scan failed");2593exit(1);2594}25952596printf("LE Scan ...\n");25972598err = print_advertising_devices(dd, filter_type);2599if (err < 0) {2600perror("Could not receive advertising events");2601exit(1);2602}26032604err = hci_le_set_scan_enable(dd, 0x00, filter_dup, 1000);2605if (err < 0) {2606perror("Disable scan failed");2607exit(1);2608}26092610hci_close_dev(dd);2611}26122613static struct option lecc_options[] = {2614{ "help", 0, 0, 'h' },2615{ "random", 0, 0, 'r' },2616{ "whitelist", 0, 0, 'w' },2617{ 0, 0, 0, 0 }2618};26192620static const char *lecc_help =2621"Usage:\n"2622"\tlecc [--random] <bdaddr>\n"2623"\tlecc --whitelist\n";26242625static void cmd_lecc(int dev_id, int argc, char **argv)2626{2627int err, opt, dd;2628bdaddr_t bdaddr;2629uint16_t interval, latency, max_ce_length, max_interval, min_ce_length;2630uint16_t min_interval, supervision_timeout, window, handle;2631uint8_t initiator_filter, own_bdaddr_type, peer_bdaddr_type;26322633peer_bdaddr_type = LE_PUBLIC_ADDRESS;2634initiator_filter = 0; /* Use peer address */26352636for_each_opt(opt, lecc_options, NULL) {2637switch (opt) {2638case 'r':2639peer_bdaddr_type = LE_RANDOM_ADDRESS;2640break;2641case 'w':2642initiator_filter = 0x01; /* Use white list */2643break;2644default:2645printf("%s", lecc_help);2646return;2647}2648}2649helper_arg(0, 1, &argc, &argv, lecc_help);26502651if (dev_id < 0)2652dev_id = hci_get_route(NULL);26532654dd = hci_open_dev(dev_id);2655if (dd < 0) {2656perror("Could not open device");2657exit(1);2658}26592660memset(&bdaddr, 0, sizeof(bdaddr_t));2661if (argv[0])2662str2ba(argv[0], &bdaddr);26632664interval = htobs(0x0004);2665window = htobs(0x0004);2666own_bdaddr_type = 0x00;2667min_interval = htobs(0x000F);2668max_interval = htobs(0x000F);2669latency = htobs(0x0000);2670supervision_timeout = htobs(0x0C80);2671min_ce_length = htobs(0x0001);2672max_ce_length = htobs(0x0001);26732674err = hci_le_create_conn(dd, interval, window, initiator_filter,2675peer_bdaddr_type, bdaddr, own_bdaddr_type, min_interval,2676max_interval, latency, supervision_timeout,2677min_ce_length, max_ce_length, &handle, 25000);2678if (err < 0) {2679perror("Could not create connection");2680exit(1);2681}26822683printf("Connection handle %d\n", handle);26842685hci_close_dev(dd);2686}26872688static struct option lewladd_options[] = {2689{ "help", 0, 0, 'h' },2690{ "random", 0, 0, 'r' },2691{ 0, 0, 0, 0 }2692};26932694static const char *lewladd_help =2695"Usage:\n"2696"\tlewladd [--random] <bdaddr>\n";26972698static void cmd_lewladd(int dev_id, int argc, char **argv)2699{2700int err, opt, dd;2701bdaddr_t bdaddr;2702uint8_t bdaddr_type = LE_PUBLIC_ADDRESS;27032704for_each_opt(opt, lewladd_options, NULL) {2705switch (opt) {2706case 'r':2707bdaddr_type = LE_RANDOM_ADDRESS;2708break;2709default:2710printf("%s", lewladd_help);2711return;2712}2713}27142715helper_arg(1, 1, &argc, &argv, lewladd_help);27162717if (dev_id < 0)2718dev_id = hci_get_route(NULL);27192720dd = hci_open_dev(dev_id);2721if (dd < 0) {2722perror("Could not open device");2723exit(1);2724}27252726str2ba(argv[0], &bdaddr);27272728err = hci_le_add_white_list(dd, &bdaddr, bdaddr_type, 1000);2729hci_close_dev(dd);27302731if (err < 0) {2732err = -errno;2733fprintf(stderr, "Can't add to white list: %s(%d)\n",2734strerror(-err), -err);2735exit(1);2736}2737}27382739static struct option lewlrm_options[] = {2740{ "help", 0, 0, 'h' },2741{ 0, 0, 0, 0 }2742};27432744static const char *lewlrm_help =2745"Usage:\n"2746"\tlewlrm <bdaddr>\n";27472748static void cmd_lewlrm(int dev_id, int argc, char **argv)2749{2750int err, opt, dd;2751bdaddr_t bdaddr;27522753for_each_opt(opt, lewlrm_options, NULL) {2754switch (opt) {2755default:2756printf("%s", lewlrm_help);2757return;2758}2759}27602761helper_arg(1, 1, &argc, &argv, lewlrm_help);27622763if (dev_id < 0)2764dev_id = hci_get_route(NULL);27652766dd = hci_open_dev(dev_id);2767if (dd < 0) {2768perror("Could not open device");2769exit(1);2770}27712772str2ba(argv[0], &bdaddr);27732774err = hci_le_rm_white_list(dd, &bdaddr, LE_PUBLIC_ADDRESS, 1000);2775hci_close_dev(dd);27762777if (err < 0) {2778err = errno;2779fprintf(stderr, "Can't remove from white list: %s(%d)\n",2780strerror(err), err);2781exit(1);2782}2783}27842785static struct option lewlsz_options[] = {2786{ "help", 0, 0, 'h' },2787{ 0, 0, 0, 0 }2788};27892790static const char *lewlsz_help =2791"Usage:\n"2792"\tlewlsz\n";27932794static void cmd_lewlsz(int dev_id, int argc, char **argv)2795{2796int err, dd, opt;2797uint8_t size;27982799for_each_opt(opt, lewlsz_options, NULL) {2800switch (opt) {2801default:2802printf("%s", lewlsz_help);2803return;2804}2805}28062807helper_arg(0, 0, &argc, &argv, lewlsz_help);28082809if (dev_id < 0)2810dev_id = hci_get_route(NULL);28112812dd = hci_open_dev(dev_id);2813if (dd < 0) {2814perror("Could not open device");2815exit(1);2816}28172818err = hci_le_read_white_list_size(dd, &size, 1000);2819hci_close_dev(dd);28202821if (err < 0) {2822err = -errno;2823fprintf(stderr, "Can't read white list size: %s(%d)\n",2824strerror(-err), -err);2825exit(1);2826}28272828printf("White list size: %d\n", size);2829}28302831static struct option lewlclr_options[] = {2832{ "help", 0, 0, 'h' },2833{ 0, 0, 0, 0 }2834};28352836static const char *lewlclr_help =2837"Usage:\n"2838"\tlewlclr\n";28392840static void cmd_lewlclr(int dev_id, int argc, char **argv)2841{2842int err, dd, opt;28432844for_each_opt(opt, lewlclr_options, NULL) {2845switch (opt) {2846default:2847printf("%s", lewlclr_help);2848return;2849}2850}28512852helper_arg(0, 0, &argc, &argv, lewlclr_help);28532854if (dev_id < 0)2855dev_id = hci_get_route(NULL);28562857dd = hci_open_dev(dev_id);2858if (dd < 0) {2859perror("Could not open device");2860exit(1);2861}28622863err = hci_le_clear_white_list(dd, 1000);2864hci_close_dev(dd);28652866if (err < 0) {2867err = -errno;2868fprintf(stderr, "Can't clear white list: %s(%d)\n",2869strerror(-err), -err);2870exit(1);2871}2872}28732874static struct option ledc_options[] = {2875{ "help", 0, 0, 'h' },2876{ 0, 0, 0, 0 }2877};28782879static const char *ledc_help =2880"Usage:\n"2881"\tledc <handle> [reason]\n";28822883static void cmd_ledc(int dev_id, int argc, char **argv)2884{2885int err, opt, dd;2886uint16_t handle;2887uint8_t reason;28882889for_each_opt(opt, ledc_options, NULL) {2890switch (opt) {2891default:2892printf("%s", ledc_help);2893return;2894}2895}2896helper_arg(1, 2, &argc, &argv, ledc_help);28972898if (dev_id < 0)2899dev_id = hci_get_route(NULL);29002901dd = hci_open_dev(dev_id);2902if (dd < 0) {2903perror("Could not open device");2904exit(1);2905}29062907handle = atoi(argv[0]);29082909reason = (argc > 1) ? atoi(argv[1]) : HCI_OE_USER_ENDED_CONNECTION;29102911err = hci_disconnect(dd, handle, reason, 10000);2912if (err < 0) {2913perror("Could not disconnect");2914exit(1);2915}29162917hci_close_dev(dd);2918}29192920static struct option lecup_options[] = {2921{ "help", 0, 0, 'h' },2922{ "handle", 1, 0, 'H' },2923{ "min", 1, 0, 'm' },2924{ "max", 1, 0, 'M' },2925{ "latency", 1, 0, 'l' },2926{ "timeout", 1, 0, 't' },2927{ 0, 0, 0, 0 }2928};29292930static const char *lecup_help =2931"Usage:\n"2932"\tlecup <handle> <min> <max> <latency> <timeout>\n"2933"\tOptions:\n"2934"\t -H, --handle <0xXXXX> LE connection handle\n"2935"\t -m, --min <interval> Range: 0x0006 to 0x0C80\n"2936"\t -M, --max <interval> Range: 0x0006 to 0x0C80\n"2937"\t -l, --latency <range> Slave latency. Range: 0x0000 to 0x03E8\n"2938"\t -t, --timeout <time> N * 10ms. Range: 0x000A to 0x0C80\n"2939"\n\t min/max range: 7.5ms to 4s. Multiply factor: 1.25ms"2940"\n\t timeout range: 100ms to 32.0s. Larger than max interval\n";29412942static void cmd_lecup(int dev_id, int argc, char **argv)2943{2944uint16_t handle = 0, min, max, latency, timeout;2945int opt, dd, base;29462947/* Aleatory valid values */2948min = 0x0C8;2949max = 0x0960;2950latency = 0x0007;2951timeout = 0x0C80;29522953for_each_opt(opt, lecup_options, NULL) {2954if (optarg && strncasecmp("0x", optarg, 2) == 0)2955base = 16;2956else2957base = 10;29582959switch (opt) {2960case 'H':2961handle = strtoul(optarg, NULL, base);2962break;2963case 'm':2964min = strtoul(optarg, NULL, base);2965break;2966case 'M':2967max = strtoul(optarg, NULL, base);2968break;2969case 'l':2970latency = strtoul(optarg, NULL, base);2971break;2972case 't':2973timeout = strtoul(optarg, NULL, base);2974break;2975default:2976printf("%s", lecup_help);2977return;2978}2979}29802981if (handle == 0) {2982printf("%s", lecup_help);2983return;2984}29852986if (dev_id < 0)2987dev_id = hci_get_route(NULL);29882989dd = hci_open_dev(dev_id);2990if (dd < 0) {2991fprintf(stderr, "HCI device open failed\n");2992exit(1);2993}29942995if (hci_le_conn_update(dd, htobs(handle), htobs(min), htobs(max),2996htobs(latency), htobs(timeout), 5000) < 0) {2997int err = -errno;2998fprintf(stderr, "Could not change connection params: %s(%d)\n",2999strerror(-err), -err);3000}30013002hci_close_dev(dd);3003}30043005static struct {3006char *cmd;3007void (*func)(int dev_id, int argc, char **argv);3008char *doc;3009} command[] = {3010{ "dev", cmd_dev, "Display local devices" },3011{ "inq", cmd_inq, "Inquire remote devices" },3012{ "scan", cmd_scan, "Scan for remote devices" },3013{ "name", cmd_name, "Get name from remote device" },3014{ "info", cmd_info, "Get information from remote device" },3015{ "spinq", cmd_spinq, "Start periodic inquiry" },3016{ "epinq", cmd_epinq, "Exit periodic inquiry" },3017{ "cmd", cmd_cmd, "Submit arbitrary HCI commands" },3018{ "con", cmd_con, "Display active connections" },3019{ "cc", cmd_cc, "Create connection to remote device" },3020{ "dc", cmd_dc, "Disconnect from remote device" },3021{ "sr", cmd_sr, "Switch master/slave role" },3022{ "cpt", cmd_cpt, "Change connection packet type" },3023{ "rssi", cmd_rssi, "Display connection RSSI" },3024{ "lq", cmd_lq, "Display link quality" },3025{ "tpl", cmd_tpl, "Display transmit power level" },3026{ "afh", cmd_afh, "Display AFH channel map" },3027{ "lp", cmd_lp, "Set/display link policy settings" },3028{ "lst", cmd_lst, "Set/display link supervision timeout" },3029{ "auth", cmd_auth, "Request authentication" },3030{ "enc", cmd_enc, "Set connection encryption" },3031{ "key", cmd_key, "Change connection link key" },3032{ "clkoff", cmd_clkoff, "Read clock offset" },3033{ "clock", cmd_clock, "Read local or remote clock" },3034{ "lescan", cmd_lescan, "Start LE scan" },3035{ "lewladd", cmd_lewladd, "Add device to LE White List" },3036{ "lewlrm", cmd_lewlrm, "Remove device from LE White List" },3037{ "lewlsz", cmd_lewlsz, "Read size of LE White List" },3038{ "lewlclr", cmd_lewlclr, "Clear LE White list" },3039{ "lecc", cmd_lecc, "Create a LE Connection" },3040{ "ledc", cmd_ledc, "Disconnect a LE Connection" },3041{ "lecup", cmd_lecup, "LE Connection Update" },3042{ NULL, NULL, 0 }3043};30443045static void usage(void)3046{3047int i;30483049// printf("hcitool - HCI Tool ver %s\n", VERSION);3050printf("Usage:\n"3051"\thcitool [options] <command> [command parameters]\n");3052printf("Options:\n"3053"\t--help\tDisplay help\n"3054"\t-i dev\tHCI device\n");3055printf("Commands:\n");3056for (i = 0; command[i].cmd; i++)3057printf("\t%-4s\t%s\n", command[i].cmd,3058command[i].doc);3059printf("\n"3060"For more information on the usage of each command use:\n"3061"\thcitool <command> --help\n" );3062}30633064static struct option main_options[] = {3065{ "help", 0, 0, 'h' },3066{ "device", 1, 0, 'i' },3067{ 0, 0, 0, 0 }3068};30693070int main(int argc, char *argv[])3071{3072int opt, i, dev_id = -1;3073bdaddr_t ba;30743075while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {3076switch (opt) {3077case 'i':3078dev_id = hci_devid(optarg);3079if (dev_id < 0) {3080perror("Invalid device");3081exit(1);3082}3083break;30843085case 'h':3086default:3087usage();3088exit(0);3089}3090}30913092argc -= optind;3093argv += optind;3094optind = 0;30953096if (argc < 1) {3097usage();3098exit(0);3099}31003101if (dev_id != -1 && hci_devba(dev_id, &ba) < 0) {3102perror("Device is not available");3103exit(1);3104}31053106for (i = 0; command[i].cmd; i++) {3107if (strncmp(command[i].cmd,3108argv[0], strlen(command[i].cmd)))3109continue;31103111command[i].func(dev_id, argc, argv);3112break;3113}31143115if (command[i].cmd == 0) {3116fprintf(stderr, "Unknown command - \"%s\"\n", *argv);3117exit(1);3118}31193120return 0;3121}312231233124