Path: blob/next/external/cache/sources/hcitools/hciconfig.c
17847 views
/*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 <unistd.h>33#include <stdlib.h>34#include <string.h>35#include <getopt.h>36#include <sys/param.h>37#include <sys/ioctl.h>38#include <sys/socket.h>3940#include <bluetooth/bluetooth.h>41#include <bluetooth/hci.h>42#include <bluetooth/hci_lib.h>4344#include "textfile.h"45#include "csr.h"4647static struct hci_dev_info di;48static int all;4950static void print_dev_hdr(struct hci_dev_info *di);51static void print_dev_info(int ctl, struct hci_dev_info *di);5253static void print_dev_list(int ctl, int flags)54{55struct hci_dev_list_req *dl;56struct hci_dev_req *dr;57int i;5859if (!(dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) +60sizeof(uint16_t)))) {61perror("Can't allocate memory");62exit(1);63}64dl->dev_num = HCI_MAX_DEV;65dr = dl->dev_req;6667if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {68perror("Can't get device list");69if(dl) {70free(dl);71dl = NULL;72}73exit(1);74}7576for (i = 0; i< dl->dev_num; i++) {77di.dev_id = (dr+i)->dev_id;78if (ioctl(ctl, HCIGETDEVINFO, (void *) &di) < 0)79continue;80if (hci_test_bit(HCI_RAW, &di.flags) &&81!bacmp(&di.bdaddr, BDADDR_ANY)) {82int dd = hci_open_dev(di.dev_id);83hci_read_bd_addr(dd, &di.bdaddr, 1000);84hci_close_dev(dd);85}86print_dev_info(ctl, &di);87}88if(dl) {89free(dl);90dl = NULL;91}92}9394static void print_pkt_type(struct hci_dev_info *di)95{96char *str;97str = hci_ptypetostr(di->pkt_type);98printf("\tPacket type: %s\n", str);99bt_free(str);100}101102static void print_link_policy(struct hci_dev_info *di)103{104printf("\tLink policy: %s\n", hci_lptostr(di->link_policy));105}106107static void print_link_mode(struct hci_dev_info *di)108{109char *str;110str = hci_lmtostr(di->link_mode);111printf("\tLink mode: %s\n", str);112bt_free(str);113}114115static void print_dev_features(struct hci_dev_info *di, int format)116{117printf("\tFeatures: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "118"0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",119di->features[0], di->features[1], di->features[2],120di->features[3], di->features[4], di->features[5],121di->features[6], di->features[7]);122123if (format) {124char *tmp = lmp_featurestostr(di->features, "\t\t", 63);125printf("%s\n", tmp);126bt_free(tmp);127}128}129130static void print_le_states(uint64_t states)131{132int i;133const char *le_states[] = {134"Non-connectable Advertising State" ,135"Scannable Advertising State",136"Connectable Advertising State",137"Directed Advertising State",138"Passive Scanning State",139"Active Scanning State",140"Initiating State/Connection State in Master Role",141"Connection State in the Slave Role",142"Non-connectable Advertising State and Passive Scanning State combination",143"Scannable Advertising State and Passive Scanning State combination",144"Connectable Advertising State and Passive Scanning State combination",145"Directed Advertising State and Passive Scanning State combination",146"Non-connectable Advertising State and Active Scanning State combination",147"Scannable Advertising State and Active Scanning State combination",148"Connectable Advertising State and Active Scanning State combination",149"Directed Advertising State and Active Scanning State combination",150"Non-connectable Advertising State and Initiating State combination",151"Scannable Advertising State and Initiating State combination",152"Non-connectable Advertising State and Master Role combination",153"Scannable Advertising State and Master Role combination",154"Non-connectable Advertising State and Slave Role combination",155"Scannable Advertising State and Slave Role combination",156"Passive Scanning State and Initiating State combination",157"Active Scanning State and Initiating State combination",158"Passive Scanning State and Master Role combination",159"Active Scanning State and Master Role combination",160"Passive Scanning State and Slave Role combination",161"Active Scanning State and Slave Role combination",162"Initiating State and Master Role combination/Master Role and Master Role combination",163NULL164};165166printf("Supported link layer states:\n");167for (i = 0; le_states[i]; i++) {168const char *status;169170status = states & (1 << i) ? "YES" : "NO ";171printf("\t%s %s\n", status, le_states[i]);172}173}174175static void cmd_rstat(int ctl, int hdev, char *opt)176{177/* Reset HCI device stat counters */178if (ioctl(ctl, HCIDEVRESTAT, hdev) < 0) {179fprintf(stderr, "Can't reset stats counters hci%d: %s (%d)\n",180hdev, strerror(errno), errno);181exit(1);182}183}184185static void cmd_scan(int ctl, int hdev, char *opt)186{187struct hci_dev_req dr;188189dr.dev_id = hdev;190dr.dev_opt = SCAN_DISABLED;191if (!strcmp(opt, "iscan"))192dr.dev_opt = SCAN_INQUIRY;193else if (!strcmp(opt, "pscan"))194dr.dev_opt = SCAN_PAGE;195else if (!strcmp(opt, "piscan"))196dr.dev_opt = SCAN_PAGE | SCAN_INQUIRY;197198if (ioctl(ctl, HCISETSCAN, (unsigned long) &dr) < 0) {199fprintf(stderr, "Can't set scan mode on hci%d: %s (%d)\n",200hdev, strerror(errno), errno);201exit(1);202}203}204205static void cmd_le_addr(int ctl, int hdev, char *opt)206{207struct hci_request rq;208le_set_random_address_cp cp;209uint8_t status;210int dd, err, ret;211212if (!opt)213return;214215if (hdev < 0)216hdev = hci_get_route(NULL);217218dd = hci_open_dev(hdev);219if (dd < 0) {220err = -errno;221fprintf(stderr, "Could not open device: %s(%d)\n",222strerror(-err), -err);223exit(1);224}225226memset(&cp, 0, sizeof(cp));227228str2ba(opt, &cp.bdaddr);229230memset(&rq, 0, sizeof(rq));231rq.ogf = OGF_LE_CTL;232rq.ocf = OCF_LE_SET_RANDOM_ADDRESS;233rq.cparam = &cp;234rq.clen = LE_SET_RANDOM_ADDRESS_CP_SIZE;235rq.rparam = &status;236rq.rlen = 1;237238ret = hci_send_req(dd, &rq, 1000);239if (status || ret < 0) {240err = -errno;241fprintf(stderr, "Can't set random address for hci%d: "242"%s (%d)\n", hdev, strerror(-err), -err);243}244245hci_close_dev(dd);246}247248static void cmd_le_adv(int ctl, int hdev, char *opt)249{250struct hci_request rq;251le_set_advertise_enable_cp advertise_cp;252le_set_advertising_parameters_cp adv_params_cp;253uint8_t status;254int dd, ret;255256if (hdev < 0)257hdev = hci_get_route(NULL);258259dd = hci_open_dev(hdev);260if (dd < 0) {261perror("Could not open device");262exit(1);263}264265memset(&adv_params_cp, 0, sizeof(adv_params_cp));266adv_params_cp.min_interval = htobs(0x0800);267adv_params_cp.max_interval = htobs(0x0800);268if (opt)269adv_params_cp.advtype = atoi(opt);270adv_params_cp.chan_map = 7;271272memset(&rq, 0, sizeof(rq));273rq.ogf = OGF_LE_CTL;274rq.ocf = OCF_LE_SET_ADVERTISING_PARAMETERS;275rq.cparam = &adv_params_cp;276rq.clen = LE_SET_ADVERTISING_PARAMETERS_CP_SIZE;277rq.rparam = &status;278rq.rlen = 1;279280ret = hci_send_req(dd, &rq, 1000);281if (ret < 0)282goto done;283284memset(&advertise_cp, 0, sizeof(advertise_cp));285advertise_cp.enable = 0x01;286287memset(&rq, 0, sizeof(rq));288rq.ogf = OGF_LE_CTL;289rq.ocf = OCF_LE_SET_ADVERTISE_ENABLE;290rq.cparam = &advertise_cp;291rq.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE;292rq.rparam = &status;293rq.rlen = 1;294295ret = hci_send_req(dd, &rq, 1000);296297done:298hci_close_dev(dd);299300if (ret < 0) {301fprintf(stderr, "Can't set advertise mode on hci%d: %s (%d)\n",302hdev, strerror(errno), errno);303exit(1);304}305306if (status) {307fprintf(stderr,308"LE set advertise enable on hci%d returned status %d\n",309hdev, status);310exit(1);311}312}313314static void cmd_no_le_adv(int ctl, int hdev, char *opt)315{316struct hci_request rq;317le_set_advertise_enable_cp advertise_cp;318uint8_t status;319int dd, ret;320321if (hdev < 0)322hdev = hci_get_route(NULL);323324dd = hci_open_dev(hdev);325if (dd < 0) {326perror("Could not open device");327exit(1);328}329330memset(&advertise_cp, 0, sizeof(advertise_cp));331332memset(&rq, 0, sizeof(rq));333rq.ogf = OGF_LE_CTL;334rq.ocf = OCF_LE_SET_ADVERTISE_ENABLE;335rq.cparam = &advertise_cp;336rq.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE;337rq.rparam = &status;338rq.rlen = 1;339340ret = hci_send_req(dd, &rq, 1000);341342hci_close_dev(dd);343344if (ret < 0) {345fprintf(stderr, "Can't set advertise mode on hci%d: %s (%d)\n",346hdev, strerror(errno), errno);347exit(1);348}349350if (status) {351fprintf(stderr, "LE set advertise enable on hci%d returned status %d\n",352hdev, status);353exit(1);354}355}356357static void cmd_le_states(int ctl, int hdev, char *opt)358{359le_read_supported_states_rp rp;360struct hci_request rq;361int err, dd;362363if (hdev < 0)364hdev = hci_get_route(NULL);365366dd = hci_open_dev(hdev);367if (dd < 0) {368fprintf(stderr, "Can't open device hci%d: %s (%d)\n",369hdev, strerror(errno), errno);370exit(1);371}372373memset(&rp, 0, sizeof(rp));374memset(&rq, 0, sizeof(rq));375376rq.ogf = OGF_LE_CTL;377rq.ocf = OCF_LE_READ_SUPPORTED_STATES;378rq.rparam = &rp;379rq.rlen = LE_READ_SUPPORTED_STATES_RP_SIZE;380381err = hci_send_req(dd, &rq, 1000);382383hci_close_dev(dd);384385if (err < 0) {386fprintf(stderr, "Can't read LE supported states on hci%d:"387" %s(%d)\n", hdev, strerror(errno), errno);388exit(1);389}390391if (rp.status) {392fprintf(stderr, "Read LE supported states on hci%d"393" returned status %d\n", hdev, rp.status);394exit(1);395}396397print_le_states(rp.states);398}399400static void cmd_iac(int ctl, int hdev, char *opt)401{402int s = hci_open_dev(hdev);403404if (s < 0) {405fprintf(stderr, "Can't open device hci%d: %s (%d)\n",406hdev, strerror(errno), errno);407exit(1);408}409if (opt) {410int l = strtoul(opt, 0, 16);411uint8_t lap[3];412if (!strcasecmp(opt, "giac")) {413l = 0x9e8b33;414} else if (!strcasecmp(opt, "liac")) {415l = 0x9e8b00;416} else if (l < 0x9e8b00 || l > 0x9e8b3f) {417printf("Invalid access code 0x%x\n", l);418exit(1);419}420lap[0] = (l & 0xff);421lap[1] = (l >> 8) & 0xff;422lap[2] = (l >> 16) & 0xff;423if (hci_write_current_iac_lap(s, 1, lap, 1000) < 0) {424printf("Failed to set IAC on hci%d: %s\n", hdev, strerror(errno));425exit(1);426}427} else {428uint8_t lap[3 * MAX_IAC_LAP];429int i, j;430uint8_t n;431if (hci_read_current_iac_lap(s, &n, lap, 1000) < 0) {432printf("Failed to read IAC from hci%d: %s\n", hdev, strerror(errno));433exit(1);434}435print_dev_hdr(&di);436printf("\tIAC: ");437for (i = 0; i < n; i++) {438printf("0x");439for (j = 3; j--; )440printf("%02x", lap[j + 3 * i]);441if (i < n - 1)442printf(", ");443}444printf("\n");445}446close(s);447}448449static void cmd_auth(int ctl, int hdev, char *opt)450{451struct hci_dev_req dr;452453dr.dev_id = hdev;454if (!strcmp(opt, "auth"))455dr.dev_opt = AUTH_ENABLED;456else457dr.dev_opt = AUTH_DISABLED;458459if (ioctl(ctl, HCISETAUTH, (unsigned long) &dr) < 0) {460fprintf(stderr, "Can't set auth on hci%d: %s (%d)\n",461hdev, strerror(errno), errno);462exit(1);463}464}465466static void cmd_encrypt(int ctl, int hdev, char *opt)467{468struct hci_dev_req dr;469470dr.dev_id = hdev;471if (!strcmp(opt, "encrypt"))472dr.dev_opt = ENCRYPT_P2P;473else474dr.dev_opt = ENCRYPT_DISABLED;475476if (ioctl(ctl, HCISETENCRYPT, (unsigned long) &dr) < 0) {477fprintf(stderr, "Can't set encrypt on hci%d: %s (%d)\n",478hdev, strerror(errno), errno);479exit(1);480}481}482483static void cmd_up(int ctl, int hdev, char *opt)484{485/* Start HCI device */486if (ioctl(ctl, HCIDEVUP, hdev) < 0) {487if (errno == EALREADY)488return;489fprintf(stderr, "Can't init device hci%d: %s (%d)\n",490hdev, strerror(errno), errno);491exit(1);492}493}494495static void cmd_down(int ctl, int hdev, char *opt)496{497/* Stop HCI device */498if (ioctl(ctl, HCIDEVDOWN, hdev) < 0) {499fprintf(stderr, "Can't down device hci%d: %s (%d)\n",500hdev, strerror(errno), errno);501exit(1);502}503}504505static void cmd_reset(int ctl, int hdev, char *opt)506{507/* Reset HCI device */508#if 0509if (ioctl(ctl, HCIDEVRESET, hdev) < 0 ){510fprintf(stderr, "Reset failed for device hci%d: %s (%d)\n",511hdev, strerror(errno), errno);512exit(1);513}514#endif515cmd_down(ctl, hdev, "down");516cmd_up(ctl, hdev, "up");517}518519static void cmd_ptype(int ctl, int hdev, char *opt)520{521struct hci_dev_req dr;522523dr.dev_id = hdev;524525if (hci_strtoptype(opt, &dr.dev_opt)) {526if (ioctl(ctl, HCISETPTYPE, (unsigned long) &dr) < 0) {527fprintf(stderr, "Can't set pkttype on hci%d: %s (%d)\n",528hdev, strerror(errno), errno);529exit(1);530}531} else {532print_dev_hdr(&di);533print_pkt_type(&di);534}535}536537static void cmd_lp(int ctl, int hdev, char *opt)538{539struct hci_dev_req dr;540541dr.dev_id = hdev;542543if (hci_strtolp(opt, &dr.dev_opt)) {544if (ioctl(ctl, HCISETLINKPOL, (unsigned long) &dr) < 0) {545fprintf(stderr, "Can't set link policy on hci%d: %s (%d)\n",546hdev, strerror(errno), errno);547exit(1);548}549} else {550print_dev_hdr(&di);551print_link_policy(&di);552}553}554555static void cmd_lm(int ctl, int hdev, char *opt)556{557struct hci_dev_req dr;558559dr.dev_id = hdev;560561if (hci_strtolm(opt, &dr.dev_opt)) {562if (ioctl(ctl, HCISETLINKMODE, (unsigned long) &dr) < 0) {563fprintf(stderr, "Can't set default link mode on hci%d: %s (%d)\n",564hdev, strerror(errno), errno);565exit(1);566}567} else {568print_dev_hdr(&di);569print_link_mode(&di);570}571}572573static void cmd_aclmtu(int ctl, int hdev, char *opt)574{575struct hci_dev_req dr = { .dev_id = hdev };576uint16_t mtu, mpkt;577578if (!opt)579return;580581if (sscanf(opt, "%4hu:%4hu", &mtu, &mpkt) != 2)582return;583584dr.dev_opt = htobl(htobs(mpkt) | (htobs(mtu) << 16));585586if (ioctl(ctl, HCISETACLMTU, (unsigned long) &dr) < 0) {587fprintf(stderr, "Can't set ACL mtu on hci%d: %s(%d)\n",588hdev, strerror(errno), errno);589exit(1);590}591}592593static void cmd_scomtu(int ctl, int hdev, char *opt)594{595struct hci_dev_req dr = { .dev_id = hdev };596uint16_t mtu, mpkt;597598if (!opt)599return;600601if (sscanf(opt, "%4hu:%4hu", &mtu, &mpkt) != 2)602return;603604dr.dev_opt = htobl(htobs(mpkt) | (htobs(mtu) << 16));605606if (ioctl(ctl, HCISETSCOMTU, (unsigned long) &dr) < 0) {607fprintf(stderr, "Can't set SCO mtu on hci%d: %s (%d)\n",608hdev, strerror(errno), errno);609exit(1);610}611}612613static void cmd_features(int ctl, int hdev, char *opt)614{615uint8_t features[8], max_page = 0;616char *tmp;617int i, dd;618619if (!(di.features[7] & LMP_EXT_FEAT)) {620print_dev_hdr(&di);621print_dev_features(&di, 1);622return;623}624625dd = hci_open_dev(hdev);626if (dd < 0) {627fprintf(stderr, "Can't open device hci%d: %s (%d)\n",628hdev, strerror(errno), errno);629exit(1);630}631632if (hci_read_local_ext_features(dd, 0, &max_page, features, 1000) < 0) {633fprintf(stderr, "Can't read extended features hci%d: %s (%d)\n",634hdev, strerror(errno), errno);635exit(1);636}637638print_dev_hdr(&di);639printf("\tFeatures%s: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "640"0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",641(max_page > 0) ? " page 0" : "",642features[0], features[1], features[2], features[3],643features[4], features[5], features[6], features[7]);644645tmp = lmp_featurestostr(di.features, "\t\t", 63);646printf("%s\n", tmp);647bt_free(tmp);648649for (i = 1; i <= max_page; i++) {650if (hci_read_local_ext_features(dd, i, NULL,651features, 1000) < 0)652continue;653654printf("\tFeatures page %d: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "655"0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", i,656features[0], features[1], features[2], features[3],657features[4], features[5], features[6], features[7]);658}659660hci_close_dev(dd);661}662663static void cmd_name(int ctl, int hdev, char *opt)664{665int dd;666667dd = hci_open_dev(hdev);668if (dd < 0) {669fprintf(stderr, "Can't open device hci%d: %s (%d)\n",670hdev, strerror(errno), errno);671exit(1);672}673674if (opt) {675if (hci_write_local_name(dd, opt, 2000) < 0) {676fprintf(stderr, "Can't change local name on hci%d: %s (%d)\n",677hdev, strerror(errno), errno);678exit(1);679}680} else {681char name[249];682int i;683684if (hci_read_local_name(dd, sizeof(name), name, 1000) < 0) {685fprintf(stderr, "Can't read local name on hci%d: %s (%d)\n",686hdev, strerror(errno), errno);687exit(1);688}689690for (i = 0; i < 248 && name[i]; i++) {691if ((unsigned char) name[i] < 32 || name[i] == 127)692name[i] = '.';693}694695name[248] = '\0';696697print_dev_hdr(&di);698printf("\tName: '%s'\n", name);699}700701hci_close_dev(dd);702}703704/*705* see http://www.bluetooth.org/assigned-numbers/baseband.htm --- all706* strings are reproduced verbatim707*/708static char *get_minor_device_name(int major, int minor)709{710switch (major) {711case 0: /* misc */712return "";713case 1: /* computer */714switch (minor) {715case 0:716return "Uncategorized";717case 1:718return "Desktop workstation";719case 2:720return "Server";721case 3:722return "Laptop";723case 4:724return "Handheld";725case 5:726return "Palm";727case 6:728return "Wearable";729}730break;731case 2: /* phone */732switch (minor) {733case 0:734return "Uncategorized";735case 1:736return "Cellular";737case 2:738return "Cordless";739case 3:740return "Smart phone";741case 4:742return "Wired modem or voice gateway";743case 5:744return "Common ISDN Access";745case 6:746return "Sim Card Reader";747}748break;749case 3: /* lan access */750if (minor == 0)751return "Uncategorized";752switch (minor / 8) {753case 0:754return "Fully available";755case 1:756return "1-17% utilized";757case 2:758return "17-33% utilized";759case 3:760return "33-50% utilized";761case 4:762return "50-67% utilized";763case 5:764return "67-83% utilized";765case 6:766return "83-99% utilized";767case 7:768return "No service available";769}770break;771case 4: /* audio/video */772switch (minor) {773case 0:774return "Uncategorized";775case 1:776return "Device conforms to the Headset profile";777case 2:778return "Hands-free";779/* 3 is reserved */780case 4:781return "Microphone";782case 5:783return "Loudspeaker";784case 6:785return "Headphones";786case 7:787return "Portable Audio";788case 8:789return "Car Audio";790case 9:791return "Set-top box";792case 10:793return "HiFi Audio Device";794case 11:795return "VCR";796case 12:797return "Video Camera";798case 13:799return "Camcorder";800case 14:801return "Video Monitor";802case 15:803return "Video Display and Loudspeaker";804case 16:805return "Video Conferencing";806/* 17 is reserved */807case 18:808return "Gaming/Toy";809}810break;811case 5: /* peripheral */ {812static char cls_str[48];813814cls_str[0] = '\0';815816switch (minor & 48) {817case 16:818strncpy(cls_str, "Keyboard", sizeof(cls_str));819break;820case 32:821strncpy(cls_str, "Pointing device", sizeof(cls_str));822break;823case 48:824strncpy(cls_str, "Combo keyboard/pointing device", sizeof(cls_str));825break;826}827if ((minor & 15) && (strlen(cls_str) > 0))828strcat(cls_str, "/");829830switch (minor & 15) {831case 0:832break;833case 1:834strncat(cls_str, "Joystick", sizeof(cls_str) - strlen(cls_str));835break;836case 2:837strncat(cls_str, "Gamepad", sizeof(cls_str) - strlen(cls_str));838break;839case 3:840strncat(cls_str, "Remote control", sizeof(cls_str) - strlen(cls_str));841break;842case 4:843strncat(cls_str, "Sensing device", sizeof(cls_str) - strlen(cls_str));844break;845case 5:846strncat(cls_str, "Digitizer tablet", sizeof(cls_str) - strlen(cls_str));847break;848case 6:849strncat(cls_str, "Card reader", sizeof(cls_str) - strlen(cls_str));850break;851default:852strncat(cls_str, "(reserved)", sizeof(cls_str) - strlen(cls_str));853break;854}855if (strlen(cls_str) > 0)856return cls_str;857}858case 6: /* imaging */859if (minor & 4)860return "Display";861if (minor & 8)862return "Camera";863if (minor & 16)864return "Scanner";865if (minor & 32)866return "Printer";867break;868case 7: /* wearable */869switch (minor) {870case 1:871return "Wrist Watch";872case 2:873return "Pager";874case 3:875return "Jacket";876case 4:877return "Helmet";878case 5:879return "Glasses";880}881break;882case 8: /* toy */883switch (minor) {884case 1:885return "Robot";886case 2:887return "Vehicle";888case 3:889return "Doll / Action Figure";890case 4:891return "Controller";892case 5:893return "Game";894}895break;896case 63: /* uncategorised */897return "";898}899return "Unknown (reserved) minor device class";900}901902static void cmd_class(int ctl, int hdev, char *opt)903{904static const char *services[] = { "Positioning",905"Networking",906"Rendering",907"Capturing",908"Object Transfer",909"Audio",910"Telephony",911"Information" };912static const char *major_devices[] = { "Miscellaneous",913"Computer",914"Phone",915"LAN Access",916"Audio/Video",917"Peripheral",918"Imaging",919"Uncategorized" };920int s = hci_open_dev(hdev);921922if (s < 0) {923fprintf(stderr, "Can't open device hci%d: %s (%d)\n",924hdev, strerror(errno), errno);925exit(1);926}927if (opt) {928uint32_t cod = strtoul(opt, NULL, 16);929if (hci_write_class_of_dev(s, cod, 2000) < 0) {930fprintf(stderr, "Can't write local class of device on hci%d: %s (%d)\n",931hdev, strerror(errno), errno);932exit(1);933}934} else {935uint8_t cls[3];936if (hci_read_class_of_dev(s, cls, 1000) < 0) {937fprintf(stderr, "Can't read class of device on hci%d: %s (%d)\n",938hdev, strerror(errno), errno);939exit(1);940}941print_dev_hdr(&di);942printf("\tClass: 0x%02x%02x%02x\n", cls[2], cls[1], cls[0]);943printf("\tService Classes: ");944if (cls[2]) {945unsigned int i;946int first = 1;947for (i = 0; i < (sizeof(services) / sizeof(*services)); i++)948if (cls[2] & (1 << i)) {949if (!first)950printf(", ");951printf("%s", services[i]);952first = 0;953}954} else955printf("Unspecified");956printf("\n\tDevice Class: ");957if ((cls[1] & 0x1f) >= sizeof(major_devices) / sizeof(*major_devices))958printf("Invalid Device Class!\n");959else960printf("%s, %s\n", major_devices[cls[1] & 0x1f],961get_minor_device_name(cls[1] & 0x1f, cls[0] >> 2));962}963}964965static void cmd_voice(int ctl, int hdev, char *opt)966{967static char *icf[] = { "Linear",968"u-Law",969"A-Law",970"Reserved" };971972static char *idf[] = { "1's complement",973"2's complement",974"Sign-Magnitude",975"Reserved" };976977static char *iss[] = { "8 bit",978"16 bit" };979980static char *acf[] = { "CVSD",981"u-Law",982"A-Law",983"Reserved" };984985int s = hci_open_dev(hdev);986987if (s < 0) {988fprintf(stderr, "Can't open device hci%d: %s (%d)\n",989hdev, strerror(errno), errno);990exit(1);991}992if (opt) {993uint16_t vs = htobs(strtoul(opt, NULL, 16));994if (hci_write_voice_setting(s, vs, 2000) < 0) {995fprintf(stderr, "Can't write voice setting on hci%d: %s (%d)\n",996hdev, strerror(errno), errno);997exit(1);998}999} else {1000uint16_t vs;1001uint8_t ic;1002if (hci_read_voice_setting(s, &vs, 1000) < 0) {1003fprintf(stderr, "Can't read voice setting on hci%d: %s (%d)\n",1004hdev, strerror(errno), errno);1005exit(1);1006}1007vs = htobs(vs);1008ic = (vs & 0x0300) >> 8;1009print_dev_hdr(&di);1010printf("\tVoice setting: 0x%04x%s\n", vs,1011((vs & 0x03fc) == 0x0060) ? " (Default Condition)" : "");1012printf("\tInput Coding: %s\n", icf[ic]);1013printf("\tInput Data Format: %s\n", idf[(vs & 0xc0) >> 6]);10141015if (!ic) {1016printf("\tInput Sample Size: %s\n",1017iss[(vs & 0x20) >> 5]);1018printf("\t# of bits padding at MSB: %d\n",1019(vs & 0x1c) >> 2);1020}1021printf("\tAir Coding Format: %s\n", acf[vs & 0x03]);1022}1023}10241025static void cmd_delkey(int ctl, int hdev, char *opt)1026{1027bdaddr_t bdaddr;1028uint8_t all;1029int dd;10301031if (!opt)1032return;10331034dd = hci_open_dev(hdev);1035if (dd < 0) {1036fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1037hdev, strerror(errno), errno);1038exit(1);1039}10401041if (!strcasecmp(opt, "all")) {1042bacpy(&bdaddr, BDADDR_ANY);1043all = 1;1044} else {1045str2ba(opt, &bdaddr);1046all = 0;1047}10481049if (hci_delete_stored_link_key(dd, &bdaddr, all, 1000) < 0) {1050fprintf(stderr, "Can't delete stored link key on hci%d: %s (%d)\n",1051hdev, strerror(errno), errno);1052exit(1);1053}10541055hci_close_dev(dd);1056}10571058static void cmd_oob_data(int ctl, int hdev, char *opt)1059{1060uint8_t hash[16], randomizer[16];1061int i, dd;10621063dd = hci_open_dev(hdev);1064if (dd < 0) {1065fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1066hdev, strerror(errno), errno);1067exit(1);1068}10691070if (hci_read_local_oob_data(dd, hash, randomizer, 1000) < 0) {1071fprintf(stderr, "Can't read local OOB data on hci%d: %s (%d)\n",1072hdev, strerror(errno), errno);1073exit(1);1074}10751076print_dev_hdr(&di);1077printf("\tOOB Hash: ");1078for (i = 0; i < 16; i++)1079printf(" %02x", hash[i]);1080printf("\n\tRandomizer:");1081for (i = 0; i < 16; i++)1082printf(" %02x", randomizer[i]);1083printf("\n");10841085hci_close_dev(dd);1086}10871088static void cmd_commands(int ctl, int hdev, char *opt)1089{1090uint8_t cmds[64];1091char *str;1092int i, n, dd;10931094dd = hci_open_dev(hdev);1095if (dd < 0) {1096fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1097hdev, strerror(errno), errno);1098exit(1);1099}11001101if (hci_read_local_commands(dd, cmds, 1000) < 0) {1102fprintf(stderr, "Can't read support commands on hci%d: %s (%d)\n",1103hdev, strerror(errno), errno);1104exit(1);1105}11061107print_dev_hdr(&di);1108for (i = 0; i < 64; i++) {1109if (!cmds[i])1110continue;11111112printf("%s Octet %-2d = 0x%02x (Bit",1113i ? "\t\t ": "\tCommands:", i, cmds[i]);1114for (n = 0; n < 8; n++)1115if (cmds[i] & (1 << n))1116printf(" %d", n);1117printf(")\n");1118}11191120str = hci_commandstostr(cmds, "\t", 71);1121printf("%s\n", str);1122bt_free(str);11231124hci_close_dev(dd);1125}11261127static void cmd_version(int ctl, int hdev, char *opt)1128{1129struct hci_version ver;1130char *hciver, *lmpver;1131int dd;11321133dd = hci_open_dev(hdev);1134if (dd < 0) {1135fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1136hdev, strerror(errno), errno);1137exit(1);1138}11391140if (hci_read_local_version(dd, &ver, 1000) < 0) {1141fprintf(stderr, "Can't read version info hci%d: %s (%d)\n",1142hdev, strerror(errno), errno);1143exit(1);1144}11451146hciver = hci_vertostr(ver.hci_ver);1147if (((di.type & 0x30) >> 4) == HCI_BREDR)1148lmpver = lmp_vertostr(ver.lmp_ver);1149else1150lmpver = pal_vertostr(ver.lmp_ver);11511152print_dev_hdr(&di);1153printf("\tHCI Version: %s (0x%x) Revision: 0x%x\n"1154"\t%s Version: %s (0x%x) Subversion: 0x%x\n"1155"\tManufacturer: %s (%d)\n",1156hciver ? hciver : "n/a", ver.hci_ver, ver.hci_rev,1157(((di.type & 0x30) >> 4) == HCI_BREDR) ? "LMP" : "PAL",1158lmpver ? lmpver : "n/a", ver.lmp_ver, ver.lmp_subver,1159bt_compidtostr(ver.manufacturer), ver.manufacturer);11601161if (hciver)1162bt_free(hciver);1163if (lmpver)1164bt_free(lmpver);11651166hci_close_dev(dd);1167}11681169static void cmd_inq_tpl(int ctl, int hdev, char *opt)1170{1171int dd;11721173dd = hci_open_dev(hdev);1174if (dd < 0) {1175fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1176hdev, strerror(errno), errno);1177exit(1);1178}11791180if (opt) {1181int8_t level = atoi(opt);11821183if (hci_write_inquiry_transmit_power_level(dd, level, 2000) < 0) {1184fprintf(stderr, "Can't set inquiry transmit power level on hci%d: %s (%d)\n",1185hdev, strerror(errno), errno);1186exit(1);1187}1188} else {1189int8_t level;11901191if (hci_read_inq_response_tx_power_level(dd, &level, 1000) < 0) {1192fprintf(stderr, "Can't read inquiry transmit power level on hci%d: %s (%d)\n",1193hdev, strerror(errno), errno);1194exit(1);1195}11961197print_dev_hdr(&di);1198printf("\tInquiry transmit power level: %d\n", level);1199}12001201hci_close_dev(dd);1202}12031204static void cmd_inq_mode(int ctl, int hdev, char *opt)1205{1206int dd;12071208dd = hci_open_dev(hdev);1209if (dd < 0) {1210fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1211hdev, strerror(errno), errno);1212exit(1);1213}12141215if (opt) {1216uint8_t mode = atoi(opt);12171218if (hci_write_inquiry_mode(dd, mode, 2000) < 0) {1219fprintf(stderr, "Can't set inquiry mode on hci%d: %s (%d)\n",1220hdev, strerror(errno), errno);1221exit(1);1222}1223} else {1224uint8_t mode;12251226if (hci_read_inquiry_mode(dd, &mode, 1000) < 0) {1227fprintf(stderr, "Can't read inquiry mode on hci%d: %s (%d)\n",1228hdev, strerror(errno), errno);1229exit(1);1230}12311232print_dev_hdr(&di);1233printf("\tInquiry mode: ");1234switch (mode) {1235case 0:1236printf("Standard Inquiry\n");1237break;1238case 1:1239printf("Inquiry with RSSI\n");1240break;1241case 2:1242printf("Inquiry with RSSI or Extended Inquiry\n");1243break;1244default:1245printf("Unknown (0x%02x)\n", mode);1246break;1247}1248}12491250hci_close_dev(dd);1251}12521253static void cmd_inq_data(int ctl, int hdev, char *opt)1254{1255int i, dd;12561257dd = hci_open_dev(hdev);1258if (dd < 0) {1259fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1260hdev, strerror(errno), errno);1261exit(1);1262}12631264if (opt) {1265uint8_t fec = 0, data[HCI_MAX_EIR_LENGTH];1266char tmp[3];1267int i, size;12681269memset(data, 0, sizeof(data));12701271memset(tmp, 0, sizeof(tmp));1272size = (strlen(opt) + 1) / 2;1273if (size > HCI_MAX_EIR_LENGTH)1274size = HCI_MAX_EIR_LENGTH;12751276for (i = 0; i < size; i++) {1277memcpy(tmp, opt + (i * 2), 2);1278data[i] = strtol(tmp, NULL, 16);1279}12801281if (hci_write_ext_inquiry_response(dd, fec, data, 2000) < 0) {1282fprintf(stderr, "Can't set extended inquiry response on hci%d: %s (%d)\n",1283hdev, strerror(errno), errno);1284exit(1);1285}1286} else {1287uint8_t fec, data[HCI_MAX_EIR_LENGTH], len, type, *ptr;1288char *str;12891290if (hci_read_ext_inquiry_response(dd, &fec, data, 1000) < 0) {1291fprintf(stderr, "Can't read extended inquiry response on hci%d: %s (%d)\n",1292hdev, strerror(errno), errno);1293exit(1);1294}12951296print_dev_hdr(&di);1297printf("\tFEC %s\n\t\t", fec ? "enabled" : "disabled");1298for (i = 0; i < HCI_MAX_EIR_LENGTH; i++)1299printf("%02x%s%s", data[i], (i + 1) % 8 ? "" : " ",1300(i + 1) % 16 ? " " : (i < 239 ? "\n\t\t" : "\n"));13011302ptr = data;1303while (*ptr) {1304len = *ptr++;1305type = *ptr++;1306switch (type) {1307case 0x01:1308printf("\tFlags:");1309for (i = 0; i < len - 1; i++)1310printf(" 0x%2.2x", *((uint8_t *) (ptr + i)));1311printf("\n");1312break;1313case 0x02:1314case 0x03:1315printf("\t%s service classes:",1316type == 0x02 ? "Shortened" : "Complete");1317for (i = 0; i < (len - 1) / 2; i++) {1318uint16_t val = bt_get_le16((ptr + (i * 2)));1319printf(" 0x%4.4x", val);1320}1321printf("\n");1322break;1323case 0x08:1324case 0x09:1325str = malloc(len);1326if (str) {1327snprintf(str, len, "%s", ptr);1328for (i = 0; i < len - 1; i++) {1329if ((unsigned char) str[i] < 32 || str[i] == 127)1330str[i] = '.';1331}1332printf("\t%s local name: \'%s\'\n",1333type == 0x08 ? "Shortened" : "Complete", str);1334free(str);1335}1336break;1337case 0x0a:1338printf("\tTX power level: %d\n", *((int8_t *) ptr));1339break;1340case 0x10:1341printf("\tDevice ID with %d bytes data\n",1342len - 1);1343break;1344default:1345printf("\tUnknown type 0x%02x with %d bytes data\n",1346type, len - 1);1347break;1348}13491350ptr += (len - 1);1351}13521353printf("\n");1354}13551356hci_close_dev(dd);1357}13581359static void cmd_inq_type(int ctl, int hdev, char *opt)1360{1361int dd;13621363dd = hci_open_dev(hdev);1364if (dd < 0) {1365fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1366hdev, strerror(errno), errno);1367exit(1);1368}13691370if (opt) {1371uint8_t type = atoi(opt);13721373if (hci_write_inquiry_scan_type(dd, type, 2000) < 0) {1374fprintf(stderr, "Can't set inquiry scan type on hci%d: %s (%d)\n",1375hdev, strerror(errno), errno);1376exit(1);1377}1378} else {1379uint8_t type;13801381if (hci_read_inquiry_scan_type(dd, &type, 1000) < 0) {1382fprintf(stderr, "Can't read inquiry scan type on hci%d: %s (%d)\n",1383hdev, strerror(errno), errno);1384exit(1);1385}13861387print_dev_hdr(&di);1388printf("\tInquiry scan type: %s\n",1389type == 1 ? "Interlaced Inquiry Scan" : "Standard Inquiry Scan");1390}13911392hci_close_dev(dd);1393}13941395static void cmd_inq_parms(int ctl, int hdev, char *opt)1396{1397struct hci_request rq;1398int s;13991400if ((s = hci_open_dev(hdev)) < 0) {1401fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1402hdev, strerror(errno), errno);1403exit(1);1404}14051406memset(&rq, 0, sizeof(rq));14071408if (opt) {1409unsigned int window, interval;1410write_inq_activity_cp cp;14111412if (sscanf(opt,"%4u:%4u", &window, &interval) != 2) {1413printf("Invalid argument format\n");1414exit(1);1415}14161417rq.ogf = OGF_HOST_CTL;1418rq.ocf = OCF_WRITE_INQ_ACTIVITY;1419rq.cparam = &cp;1420rq.clen = WRITE_INQ_ACTIVITY_CP_SIZE;14211422cp.window = htobs((uint16_t) window);1423cp.interval = htobs((uint16_t) interval);14241425if (window < 0x12 || window > 0x1000)1426printf("Warning: inquiry window out of range!\n");14271428if (interval < 0x12 || interval > 0x1000)1429printf("Warning: inquiry interval out of range!\n");14301431if (hci_send_req(s, &rq, 2000) < 0) {1432fprintf(stderr, "Can't set inquiry parameters name on hci%d: %s (%d)\n",1433hdev, strerror(errno), errno);1434exit(1);1435}1436} else {1437uint16_t window, interval;1438read_inq_activity_rp rp;14391440rq.ogf = OGF_HOST_CTL;1441rq.ocf = OCF_READ_INQ_ACTIVITY;1442rq.rparam = &rp;1443rq.rlen = READ_INQ_ACTIVITY_RP_SIZE;14441445if (hci_send_req(s, &rq, 1000) < 0) {1446fprintf(stderr, "Can't read inquiry parameters on hci%d: %s (%d)\n",1447hdev, strerror(errno), errno);1448exit(1);1449}1450if (rp.status) {1451printf("Read inquiry parameters on hci%d returned status %d\n",1452hdev, rp.status);1453exit(1);1454}1455print_dev_hdr(&di);14561457window = btohs(rp.window);1458interval = btohs(rp.interval);1459printf("\tInquiry interval: %u slots (%.2f ms), window: %u slots (%.2f ms)\n",1460interval, (float)interval * 0.625, window, (float)window * 0.625);1461}1462}14631464static void cmd_page_parms(int ctl, int hdev, char *opt)1465{1466struct hci_request rq;1467int s;14681469if ((s = hci_open_dev(hdev)) < 0) {1470fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1471hdev, strerror(errno), errno);1472exit(1);1473}14741475memset(&rq, 0, sizeof(rq));14761477if (opt) {1478unsigned int window, interval;1479write_page_activity_cp cp;14801481if (sscanf(opt,"%4u:%4u", &window, &interval) != 2) {1482printf("Invalid argument format\n");1483exit(1);1484}14851486rq.ogf = OGF_HOST_CTL;1487rq.ocf = OCF_WRITE_PAGE_ACTIVITY;1488rq.cparam = &cp;1489rq.clen = WRITE_PAGE_ACTIVITY_CP_SIZE;14901491cp.window = htobs((uint16_t) window);1492cp.interval = htobs((uint16_t) interval);14931494if (window < 0x12 || window > 0x1000)1495printf("Warning: page window out of range!\n");14961497if (interval < 0x12 || interval > 0x1000)1498printf("Warning: page interval out of range!\n");14991500if (hci_send_req(s, &rq, 2000) < 0) {1501fprintf(stderr, "Can't set page parameters name on hci%d: %s (%d)\n",1502hdev, strerror(errno), errno);1503exit(1);1504}1505} else {1506uint16_t window, interval;1507read_page_activity_rp rp;15081509rq.ogf = OGF_HOST_CTL;1510rq.ocf = OCF_READ_PAGE_ACTIVITY;1511rq.rparam = &rp;1512rq.rlen = READ_PAGE_ACTIVITY_RP_SIZE;15131514if (hci_send_req(s, &rq, 1000) < 0) {1515fprintf(stderr, "Can't read page parameters on hci%d: %s (%d)\n",1516hdev, strerror(errno), errno);1517exit(1);1518}1519if (rp.status) {1520printf("Read page parameters on hci%d returned status %d\n",1521hdev, rp.status);1522exit(1);1523}1524print_dev_hdr(&di);15251526window = btohs(rp.window);1527interval = btohs(rp.interval);1528printf("\tPage interval: %u slots (%.2f ms), "1529"window: %u slots (%.2f ms)\n",1530interval, (float)interval * 0.625,1531window, (float)window * 0.625);1532}1533}15341535static void cmd_page_to(int ctl, int hdev, char *opt)1536{1537struct hci_request rq;1538int s;15391540if ((s = hci_open_dev(hdev)) < 0) {1541fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1542hdev, strerror(errno), errno);1543exit(1);1544}15451546memset(&rq, 0, sizeof(rq));15471548if (opt) {1549unsigned int timeout;1550write_page_timeout_cp cp;15511552if (sscanf(opt,"%5u", &timeout) != 1) {1553printf("Invalid argument format\n");1554exit(1);1555}15561557rq.ogf = OGF_HOST_CTL;1558rq.ocf = OCF_WRITE_PAGE_TIMEOUT;1559rq.cparam = &cp;1560rq.clen = WRITE_PAGE_TIMEOUT_CP_SIZE;15611562cp.timeout = htobs((uint16_t) timeout);15631564if (timeout < 0x01 || timeout > 0xFFFF)1565printf("Warning: page timeout out of range!\n");15661567if (hci_send_req(s, &rq, 2000) < 0) {1568fprintf(stderr, "Can't set page timeout on hci%d: %s (%d)\n",1569hdev, strerror(errno), errno);1570exit(1);1571}1572} else {1573uint16_t timeout;1574read_page_timeout_rp rp;15751576rq.ogf = OGF_HOST_CTL;1577rq.ocf = OCF_READ_PAGE_TIMEOUT;1578rq.rparam = &rp;1579rq.rlen = READ_PAGE_TIMEOUT_RP_SIZE;15801581if (hci_send_req(s, &rq, 1000) < 0) {1582fprintf(stderr, "Can't read page timeout on hci%d: %s (%d)\n",1583hdev, strerror(errno), errno);1584exit(1);1585}1586if (rp.status) {1587printf("Read page timeout on hci%d returned status %d\n",1588hdev, rp.status);1589exit(1);1590}1591print_dev_hdr(&di);15921593timeout = btohs(rp.timeout);1594printf("\tPage timeout: %u slots (%.2f ms)\n",1595timeout, (float)timeout * 0.625);1596}1597}15981599static void cmd_afh_mode(int ctl, int hdev, char *opt)1600{1601int dd;16021603dd = hci_open_dev(hdev);1604if (dd < 0) {1605fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1606hdev, strerror(errno), errno);1607exit(1);1608}16091610if (opt) {1611uint8_t mode = atoi(opt);16121613if (hci_write_afh_mode(dd, mode, 2000) < 0) {1614fprintf(stderr, "Can't set AFH mode on hci%d: %s (%d)\n",1615hdev, strerror(errno), errno);1616exit(1);1617}1618} else {1619uint8_t mode;16201621if (hci_read_afh_mode(dd, &mode, 1000) < 0) {1622fprintf(stderr, "Can't read AFH mode on hci%d: %s (%d)\n",1623hdev, strerror(errno), errno);1624exit(1);1625}16261627print_dev_hdr(&di);1628printf("\tAFH mode: %s\n", mode == 1 ? "Enabled" : "Disabled");1629}1630}16311632static void cmd_ssp_mode(int ctl, int hdev, char *opt)1633{1634int dd;16351636dd = hci_open_dev(hdev);1637if (dd < 0) {1638fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1639hdev, strerror(errno), errno);1640exit(1);1641}16421643if (opt) {1644uint8_t mode = atoi(opt);16451646if (hci_write_simple_pairing_mode(dd, mode, 2000) < 0) {1647fprintf(stderr, "Can't set Simple Pairing mode on hci%d: %s (%d)\n",1648hdev, strerror(errno), errno);1649exit(1);1650}1651} else {1652uint8_t mode;16531654if (hci_read_simple_pairing_mode(dd, &mode, 1000) < 0) {1655fprintf(stderr, "Can't read Simple Pairing mode on hci%d: %s (%d)\n",1656hdev, strerror(errno), errno);1657exit(1);1658}16591660print_dev_hdr(&di);1661printf("\tSimple Pairing mode: %s\n",1662mode == 1 ? "Enabled" : "Disabled");1663}1664}16651666static void print_rev_ericsson(int dd)1667{1668struct hci_request rq;1669unsigned char buf[102];16701671memset(&rq, 0, sizeof(rq));1672rq.ogf = OGF_VENDOR_CMD;1673rq.ocf = 0x000f;1674rq.cparam = NULL;1675rq.clen = 0;1676rq.rparam = &buf;1677rq.rlen = sizeof(buf);16781679if (hci_send_req(dd, &rq, 1000) < 0) {1680printf("\nCan't read revision info: %s (%d)\n",1681strerror(errno), errno);1682return;1683}16841685printf("\t%s\n", buf + 1);1686}16871688static void print_rev_csr(int dd, uint16_t rev)1689{1690uint16_t buildid, chipver, chiprev, maxkeylen, mapsco;16911692if (csr_read_varid_uint16(dd, 0, CSR_VARID_BUILDID, &buildid) < 0) {1693printf("\t%s\n", csr_buildidtostr(rev));1694return;1695}16961697printf("\t%s\n", csr_buildidtostr(buildid));16981699if (!csr_read_varid_uint16(dd, 1, CSR_VARID_CHIPVER, &chipver)) {1700if (csr_read_varid_uint16(dd, 2, CSR_VARID_CHIPREV, &chiprev) < 0)1701chiprev = 0;1702printf("\tChip version: %s\n", csr_chipvertostr(chipver, chiprev));1703}17041705if (!csr_read_varid_uint16(dd, 3, CSR_VARID_MAX_CRYPT_KEY_LENGTH, &maxkeylen))1706printf("\tMax key size: %d bit\n", maxkeylen * 8);17071708if (!csr_read_pskey_uint16(dd, 4, CSR_PSKEY_HOSTIO_MAP_SCO_PCM, 0x0000, &mapsco))1709printf("\tSCO mapping: %s\n", mapsco ? "PCM" : "HCI");1710}17111712static void print_rev_digianswer(int dd)1713{1714struct hci_request rq;1715unsigned char req[] = { 0x07 };1716unsigned char buf[102];17171718memset(&rq, 0, sizeof(rq));1719rq.ogf = OGF_VENDOR_CMD;1720rq.ocf = 0x000e;1721rq.cparam = req;1722rq.clen = sizeof(req);1723rq.rparam = &buf;1724rq.rlen = sizeof(buf);17251726if (hci_send_req(dd, &rq, 1000) < 0) {1727printf("\nCan't read revision info: %s (%d)\n",1728strerror(errno), errno);1729return;1730}17311732printf("\t%s\n", buf + 1);1733}17341735static void print_rev_broadcom(uint16_t hci_rev, uint16_t lmp_subver)1736{1737printf("\tFirmware %d.%d / %d\n",1738hci_rev & 0xff, lmp_subver >> 8, lmp_subver & 0xff);1739}17401741static void print_rev_avm(uint16_t hci_rev, uint16_t lmp_subver)1742{1743if (lmp_subver == 0x01)1744printf("\tFirmware 03.%d.%d\n", hci_rev >> 8, hci_rev & 0xff);1745else1746printf("\tUnknown type\n");1747}17481749static void cmd_revision(int ctl, int hdev, char *opt)1750{1751struct hci_version ver;1752int dd;17531754dd = hci_open_dev(hdev);1755if (dd < 0) {1756fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1757hdev, strerror(errno), errno);1758return;1759}17601761if (hci_read_local_version(dd, &ver, 1000) < 0) {1762fprintf(stderr, "Can't read version info for hci%d: %s (%d)\n",1763hdev, strerror(errno), errno);1764return;1765}17661767print_dev_hdr(&di);1768switch (ver.manufacturer) {1769case 0:1770case 37:1771case 48:1772print_rev_ericsson(dd);1773break;1774case 10:1775print_rev_csr(dd, ver.hci_rev);1776break;1777case 12:1778print_rev_digianswer(dd);1779break;1780case 15:1781print_rev_broadcom(ver.hci_rev, ver.lmp_subver);1782break;1783case 31:1784print_rev_avm(ver.hci_rev, ver.lmp_subver);1785break;1786default:1787printf("\tUnsupported manufacturer\n");1788break;1789}1790return;1791}17921793static void cmd_block(int ctl, int hdev, char *opt)1794{1795bdaddr_t bdaddr;1796int dd;17971798if (!opt)1799return;18001801dd = hci_open_dev(hdev);1802if (dd < 0) {1803fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1804hdev, strerror(errno), errno);1805exit(1);1806}18071808str2ba(opt, &bdaddr);18091810if (ioctl(dd, HCIBLOCKADDR, &bdaddr) < 0) {1811perror("ioctl(HCIBLOCKADDR)");1812exit(1);1813}18141815hci_close_dev(dd);1816}18171818static void cmd_unblock(int ctl, int hdev, char *opt)1819{1820bdaddr_t bdaddr;1821int dd;18221823if (!opt)1824return;18251826dd = hci_open_dev(hdev);1827if (dd < 0) {1828fprintf(stderr, "Can't open device hci%d: %s (%d)\n",1829hdev, strerror(errno), errno);1830exit(1);1831}18321833if (!strcasecmp(opt, "all"))1834bacpy(&bdaddr, BDADDR_ANY);1835else1836str2ba(opt, &bdaddr);18371838if (ioctl(dd, HCIUNBLOCKADDR, &bdaddr) < 0) {1839perror("ioctl(HCIUNBLOCKADDR)");1840exit(1);1841}18421843hci_close_dev(dd);1844}18451846static void print_dev_hdr(struct hci_dev_info *di)1847{1848static int hdr = -1;1849char addr[18];18501851if (hdr == di->dev_id)1852return;1853hdr = di->dev_id;18541855ba2str(&di->bdaddr, addr);18561857printf("%s:\tType: %s Bus: %s\n", di->name,1858hci_typetostr((di->type & 0x30) >> 4),1859hci_bustostr(di->type & 0x0f));1860printf("\tBD Address: %s ACL MTU: %d:%d SCO MTU: %d:%d\n",1861addr, di->acl_mtu, di->acl_pkts,1862di->sco_mtu, di->sco_pkts);1863}18641865static void print_dev_info(int ctl, struct hci_dev_info *di)1866{1867struct hci_dev_stats *st = &di->stat;1868char *str;18691870print_dev_hdr(di);18711872str = hci_dflagstostr(di->flags);1873printf("\t%s\n", str);1874bt_free(str);18751876printf("\tRX bytes:%d acl:%d sco:%d events:%d errors:%d\n",1877st->byte_rx, st->acl_rx, st->sco_rx, st->evt_rx, st->err_rx);18781879printf("\tTX bytes:%d acl:%d sco:%d commands:%d errors:%d\n",1880st->byte_tx, st->acl_tx, st->sco_tx, st->cmd_tx, st->err_tx);18811882if (all && !hci_test_bit(HCI_RAW, &di->flags)) {1883print_dev_features(di, 0);18841885if (((di->type & 0x30) >> 4) == HCI_BREDR) {1886print_pkt_type(di);1887print_link_policy(di);1888print_link_mode(di);18891890if (hci_test_bit(HCI_UP, &di->flags)) {1891cmd_name(ctl, di->dev_id, NULL);1892cmd_class(ctl, di->dev_id, NULL);1893}1894}18951896if (hci_test_bit(HCI_UP, &di->flags))1897cmd_version(ctl, di->dev_id, NULL);1898}18991900printf("\n");1901}19021903static struct {1904char *cmd;1905void (*func)(int ctl, int hdev, char *opt);1906char *opt;1907char *doc;1908} command[] = {1909{ "up", cmd_up, 0, "Open and initialize HCI device" },1910{ "down", cmd_down, 0, "Close HCI device" },1911{ "reset", cmd_reset, 0, "Reset HCI device" },1912{ "rstat", cmd_rstat, 0, "Reset statistic counters" },1913{ "auth", cmd_auth, 0, "Enable Authentication" },1914{ "noauth", cmd_auth, 0, "Disable Authentication" },1915{ "encrypt", cmd_encrypt, 0, "Enable Encryption" },1916{ "noencrypt", cmd_encrypt, 0, "Disable Encryption" },1917{ "piscan", cmd_scan, 0, "Enable Page and Inquiry scan" },1918{ "noscan", cmd_scan, 0, "Disable scan" },1919{ "iscan", cmd_scan, 0, "Enable Inquiry scan" },1920{ "pscan", cmd_scan, 0, "Enable Page scan" },1921{ "ptype", cmd_ptype, "[type]", "Get/Set default packet type" },1922{ "lm", cmd_lm, "[mode]", "Get/Set default link mode" },1923{ "lp", cmd_lp, "[policy]", "Get/Set default link policy" },1924{ "name", cmd_name, "[name]", "Get/Set local name" },1925{ "class", cmd_class, "[class]", "Get/Set class of device" },1926{ "voice", cmd_voice, "[voice]", "Get/Set voice setting" },1927{ "iac", cmd_iac, "[iac]", "Get/Set inquiry access code" },1928{ "inqtpl", cmd_inq_tpl, "[level]", "Get/Set inquiry transmit power level" },1929{ "inqmode", cmd_inq_mode, "[mode]", "Get/Set inquiry mode" },1930{ "inqdata", cmd_inq_data, "[data]", "Get/Set inquiry data" },1931{ "inqtype", cmd_inq_type, "[type]", "Get/Set inquiry scan type" },1932{ "inqparms", cmd_inq_parms, "[win:int]", "Get/Set inquiry scan window and interval" },1933{ "pageparms", cmd_page_parms, "[win:int]", "Get/Set page scan window and interval" },1934{ "pageto", cmd_page_to, "[to]", "Get/Set page timeout" },1935{ "afhmode", cmd_afh_mode, "[mode]", "Get/Set AFH mode" },1936{ "sspmode", cmd_ssp_mode, "[mode]", "Get/Set Simple Pairing Mode" },1937{ "aclmtu", cmd_aclmtu, "<mtu:pkt>", "Set ACL MTU and number of packets" },1938{ "scomtu", cmd_scomtu, "<mtu:pkt>", "Set SCO MTU and number of packets" },1939{ "delkey", cmd_delkey, "<bdaddr>", "Delete link key from the device" },1940{ "oobdata", cmd_oob_data, 0, "Get local OOB data" },1941{ "commands", cmd_commands, 0, "Display supported commands" },1942{ "features", cmd_features, 0, "Display device features" },1943{ "version", cmd_version, 0, "Display version information" },1944{ "revision", cmd_revision, 0, "Display revision information" },1945{ "block", cmd_block, "<bdaddr>", "Add a device to the blacklist" },1946{ "unblock", cmd_unblock, "<bdaddr>", "Remove a device from the blacklist" },1947{ "lerandaddr", cmd_le_addr, "<bdaddr>", "Set LE Random Address" },1948{ "leadv", cmd_le_adv, "[type]", "Enable LE advertising"1949"\n\t\t\t0 - Connectable undirected advertising (default)"1950"\n\t\t\t3 - Non connectable undirected advertising"},1951{ "noleadv", cmd_no_le_adv, 0, "Disable LE advertising" },1952{ "lestates", cmd_le_states, 0, "Display the supported LE states" },1953{ NULL, NULL, 0 }1954};19551956static void usage(void)1957{1958int i;19591960printf("hciconfig - HCI device configuration utility\n");1961printf("Usage:\n"1962"\thciconfig\n"1963"\thciconfig [-a] hciX [command ...]\n");1964printf("Commands:\n");1965for (i = 0; command[i].cmd; i++)1966printf("\t%-10s %-8s\t%s\n", command[i].cmd,1967command[i].opt ? command[i].opt : " ",1968command[i].doc);1969}19701971static struct option main_options[] = {1972{ "help", 0, 0, 'h' },1973{ "all", 0, 0, 'a' },1974{ 0, 0, 0, 0 }1975};19761977int main(int argc, char *argv[])1978{1979int opt, ctl, i, cmd = 0;19801981while ((opt = getopt_long(argc, argv, "ah", main_options, NULL)) != -1) {1982switch (opt) {1983case 'a':1984all = 1;1985break;19861987case 'h':1988default:1989usage();1990exit(0);1991}1992}19931994argc -= optind;1995argv += optind;1996optind = 0;19971998/* Open HCI socket */1999if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {2000perror("Can't open HCI socket.");2001exit(1);2002}20032004if (argc < 1) {2005print_dev_list(ctl, 0);2006exit(0);2007}20082009di.dev_id = atoi(argv[0] + 3);2010argc--; argv++;20112012if (ioctl(ctl, HCIGETDEVINFO, (void *) &di)) {2013perror("Can't get device info");2014exit(1);2015}20162017if (hci_test_bit(HCI_RAW, &di.flags) &&2018!bacmp(&di.bdaddr, BDADDR_ANY)) {2019int dd = hci_open_dev(di.dev_id);2020hci_read_bd_addr(dd, &di.bdaddr, 1000);2021hci_close_dev(dd);2022}20232024while (argc > 0) {2025for (i = 0; command[i].cmd; i++) {2026if (strncmp(command[i].cmd,2027*argv, strlen(command[i].cmd)))2028continue;20292030if (command[i].opt) {2031argc--; argv++;2032}20332034command[i].func(ctl, di.dev_id, *argv);2035cmd = 1;2036break;2037}20382039if (command[i].cmd == 0)2040fprintf(stderr, "Warning: unknown command - \"%s\"\n",2041*argv);20422043argc--; argv++;2044}20452046if (!cmd)2047print_dev_info(ctl, &di);20482049close(ctl);2050return 0;2051}205220532054