/*-
* Copyright (c) 2006 Itronix Inc.
* All rights reserved.
*
* Written by Iain Hibbert for Itronix Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of Itronix Inc. may not be used to endorse
* or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc. All rights reserved.");
__RCSID("$NetBSD: btconfig.c,v 1.28 2017/12/21 09:31:22 plunky Exp $");
/*
* write value to device with opcode.
* provide a small response buffer so that the status can be checked
*/
static void
save_value(uint16_t opcode, void *cbuf, size_t clen)
{
uint8_t buf[1];
/*
* read value from device with opcode.
* use our own buffer and only return the value from the response packet
*/
static void
load_value(uint16_t opcode, void *rbuf, size_t rlen)
{
uint8_t buf[UINT8_MAX];
do {
nanosleep(&ts, NULL);
if (ioctl(hci, SIOCGBTINFO, &btr) < 0)
err(EXIT_FAILURE, "%s", btr.btr_name);
} while ((btr.btr_flags & BTF_INIT) != 0);
}
if (opt_master) {
if (opt_master > 0)
btr.btr_flags |= BTF_MASTER;
else
btr.btr_flags &= ~BTF_MASTER;
if (ioctl(hci, SIOCSBTFLAGS, &btr) < 0)
err(EXIT_FAILURE, "SIOCSBTFLAGS");
}
if (opt_switch || opt_hold || opt_sniff || opt_park) {
uint16_t val = btr.btr_link_policy;
if (opt_switch > 0) val |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
if (opt_switch < 0) val &= ~HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
if (opt_hold > 0) val |= HCI_LINK_POLICY_ENABLE_HOLD_MODE;
if (opt_hold < 0) val &= ~HCI_LINK_POLICY_ENABLE_HOLD_MODE;
if (opt_sniff > 0) val |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
if (opt_sniff < 0) val &= ~HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
if (opt_park > 0) val |= HCI_LINK_POLICY_ENABLE_PARK_MODE;
if (opt_park < 0) val &= ~HCI_LINK_POLICY_ENABLE_PARK_MODE;
if (opt_ptype) {
btr.btr_packet_type = ptype;
if (ioctl(hci, SIOCSBTPTYPE, &btr) < 0)
err(EXIT_FAILURE, "SIOCSBTPTYPE");
}
if (opt_pscan || opt_iscan) {
uint8_t val;
load_value(HCI_CMD_READ_SCAN_ENABLE, &val, sizeof(val));
if (opt_pscan > 0) val |= HCI_PAGE_SCAN_ENABLE;
if (opt_pscan < 0) val &= ~HCI_PAGE_SCAN_ENABLE;
if (opt_iscan > 0) val |= HCI_INQUIRY_SCAN_ENABLE;
if (opt_iscan < 0) val &= ~HCI_INQUIRY_SCAN_ENABLE;
save_value(HCI_CMD_WRITE_SCAN_ENABLE, &val, sizeof(val));
}
if (opt_auth) {
uint8_t val = (opt_auth > 0 ? 1 : 0);
if (sflag == 1) {
if (ioctl(hci, SIOCGBTSTATS, &btr) < 0)
err(EXIT_FAILURE, "SIOCGBTSTATS");
} else {
if (ioctl(hci, SIOCZBTSTATS, &btr) < 0)
err(EXIT_FAILURE, "SIOCZBTSTATS");
}
printf( "\tTotal bytes sent %d, received %d\n"
"\tCommands sent %d, Events received %d\n"
"\tACL data packets sent %d, received %d\n"
"\tSCO data packets sent %d, received %d\n"
"\tInput errors %d, Output errors %d\n",
btr.btr_stats.byte_tx, btr.btr_stats.byte_rx,
btr.btr_stats.cmd_tx, btr.btr_stats.evt_rx,
btr.btr_stats.acl_tx, btr.btr_stats.acl_rx,
btr.btr_stats.sco_tx, btr.btr_stats.sco_rx,
btr.btr_stats.err_rx, btr.btr_stats.err_tx);
}
static void
print_features0(uint8_t *f)
{
/* ------------------- byte 0 --------------------*/
if (*f & HCI_LMP_3SLOT) tag("<3 slot>");
if (*f & HCI_LMP_5SLOT) tag("<5 slot>");
if (*f & HCI_LMP_ENCRYPTION) tag("<encryption>");
if (*f & HCI_LMP_SLOT_OFFSET) tag("<slot offset>");
if (*f & HCI_LMP_TIMIACCURACY) tag("<timing accuracy>");
if (*f & HCI_LMP_ROLE_SWITCH) tag("<role switch>");
if (*f & HCI_LMP_HOLD_MODE) tag("<hold mode>");
if (*f & HCI_LMP_SNIFF_MODE) tag("<sniff mode>");
f++;
/* ------------------- byte 1 --------------------*/
if (*f & HCI_LMP_PARK_MODE) tag("<park mode>");
if (*f & HCI_LMP_RSSI) tag("<RSSI>");
if (*f & HCI_LMP_CHANNEL_QUALITY) tag("<channel quality>");
if (*f & HCI_LMP_SCO_LINK) tag("<SCO link>");
if (*f & HCI_LMP_HV2_PKT) tag("<HV2>");
if (*f & HCI_LMP_HV3_PKT) tag("<HV3>");
if (*f & HCI_LMP_ULAW_LOG) tag("<u-Law log>");
if (*f & HCI_LMP_ALAW_LOG) tag("<A-Law log>");
f++;
/* ------------------- byte 1 --------------------*/
if (*f & HCI_LMP_CVSD) tag("<CVSD data>");
if (*f & HCI_LMP_PAGISCHEME) tag("<paging parameter>");
if (*f & HCI_LMP_POWER_CONTROL) tag("<power control>");
if (*f & HCI_LMP_TRANSPARENT_SCO) tag("<transparent SCO>");
if (*f & HCI_LMP_FLOW_CONTROL_LAG0) tag("<flow control lag lsb>");
if (*f & HCI_LMP_FLOW_CONTROL_LAG1) tag("<flow control lag mb>");
if (*f & HCI_LMP_FLOW_CONTROL_LAG2) tag("<flow control lag msb>");
if (*f & HCI_LMP_BC_ENCRYPTION) tag("<broadcast encryption>");
f++;
/* ------------------- byte 3 --------------------*/
if (*f & HCI_LMP_EDR_ACL_2MBPS) tag("<EDR ACL 2Mbps>");
if (*f & HCI_LMP_EDR_ACL_3MBPS) tag("<EDR ACL 3Mbps>");
if (*f & HCI_LMP_ENHANCED_ISCAN) tag("<enhanced inquiry scan>");
if (*f & HCI_LMP_INTERLACED_ISCAN) tag("<interlaced inquiry scan>");
if (*f & HCI_LMP_INTERLACED_PSCAN) tag("<interlaced page scan>");
if (*f & HCI_LMP_RSSI_INQUIRY) tag("<RSSI with inquiry result>");
if (*f & HCI_LMP_EV3_PKT) tag("<EV3 packets>");
f++;
/* ------------------- byte 4 --------------------*/
if (*f & HCI_LMP_EV4_PKT) tag("<EV4 packets>");
if (*f & HCI_LMP_EV5_PKT) tag("<EV5 packets>");
if (*f & HCI_LMP_AFH_CAPABLE_SLAVE) tag("<AFH capable slave>");
if (*f & HCI_LMP_AFH_CLASS_SLAVE) tag("<AFH class slave>");
if (*f & HCI_LMP_BR_EDR_UNSUPPORTED)tag("<BR/EDR not supported>");
if (*f & HCI_LMP_LE_CONTROLLER) tag("<LE (controller)>");
if (*f & HCI_LMP_3SLOT_EDR_ACL) tag("<3 slot EDR ACL>");
f++;
/* ------------------- byte 5 --------------------*/
if (*f & HCI_LMP_5SLOT_EDR_ACL) tag("<5 slot EDR ACL>");
if (*f & HCI_LMP_SNIFF_SUBRATING) tag("<sniff subrating>");
if (*f & HCI_LMP_PAUSE_ENCRYPTION) tag("<pause encryption>");
if (*f & HCI_LMP_AFH_CAPABLE_MASTER)tag("<AFH capable master>");
if (*f & HCI_LMP_AFH_CLASS_MASTER) tag("<AFH class master>");
if (*f & HCI_LMP_EDR_eSCO_2MBPS) tag("<EDR eSCO 2Mbps>");
if (*f & HCI_LMP_EDR_eSCO_3MBPS) tag("<EDR eSCO 3Mbps>");
if (*f & HCI_LMP_3SLOT_EDR_eSCO) tag("<3 slot EDR eSCO>");
f++;
/* ------------------- byte 6 --------------------*/
if (*f & HCI_LMP_EXTENDED_INQUIRY) tag("<extended inquiry>");
if (*f & HCI_LMP_LE_BR_EDR_CONTROLLER)tag("<simultaneous LE & BR/EDR (controller)>");
if (*f & HCI_LMP_SIMPLE_PAIRING) tag("<secure simple pairing>");
if (*f & HCI_LMP_ENCAPSULATED_PDU) tag("<encapsulated PDU>");
if (*f & HCI_LMP_ERRDATA_REPORTING) tag("<errdata reporting>");
if (*f & HCI_LMP_NOFLUSH_PB_FLAG) tag("<no flush PB flag>");
f++;
/* ------------------- byte 7 --------------------*/
if (*f & HCI_LMP_LINK_SUPERVISION_TO)tag("<link supervision timeout changed>");
if (*f & HCI_LMP_INQ_RSP_TX_POWER) tag("<inquiry rsp TX power level>");
if (*f & HCI_LMP_ENHANCED_POWER_CONTROL)tag("<enhanced power control>");
if (*f & HCI_LMP_EXTENDED_FEATURES) tag("<extended features>");
}
static void
print_features1(uint8_t *f)
{
/* ------------------- byte 0 --------------------*/
if (*f & HCI_LMP_SSP) tag("<secure simple pairing (host)>");
if (*f & HCI_LMP_LE_HOST) tag("<LE (host)>");
if (*f & HCI_LMP_LE_BR_EDR_HOST) tag("<simultaneous LE & BR/EDR (host)>");
if (*f & HCI_LMP_SECURE_CONN_HOST) tag("<secure connections (host)>");
}
static void
print_features2(uint8_t *f)
{
/* ------------------- byte 0 --------------------*/
if (*f & HCI_LMP_CONNLESS_MASTER) tag("<connectionless master>");
if (*f & HCI_LMP_CONNLESS_SLAVE) tag("<connectionless slave>");
if (*f & HCI_LMP_SYNC_TRAIN) tag("<synchronization train>");
if (*f & HCI_LMP_SYNC_SCAN) tag("<synchronization scan>");
if (*f & HCI_LMP_INQ_RSP_NOTIFY) tag("<inquiry response notification>");
if (*f & HCI_LMP_INTERLACE_SCAN) tag("<generalized interlace scan>");
if (*f & HCI_LMP_COARSE_CLOCK) tag("<coarse clock adjustment>");
/* ------------------- byte 1 --------------------*/
if (*f & HCI_LMP_SECURE_CONN_CONTROLLER)tag("<secure connections (controller)>");
if (*f & HCI_LMP_PING) tag("<ping>");
if (*f & HCI_LMP_TRAIN_NUDGING) tag("<train nudging>");
}
switch (__SHIFTOUT(class, __BITS(8, 12))) {
case 1: /* Computer */
switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Desktop workstation"); break;
case 2: tag("Server-class computer"); break;
case 3: tag("Laptop"); break;
case 4: tag("Handheld PC/PDA"); break;
case 5: tag("Palm Sized PC/PDA"); break;
case 6: tag("Wearable computer"); break;
default: tag("Computer"); break;
}
break;
case 2: /* Phone */
switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Cellular Phone"); break;
case 2: tag("Cordless Phone"); break;
case 3: tag("Smart Phone"); break;
case 4: tag("Wired Modem/Phone Gateway"); break;
case 5: tag("Common ISDN"); break;
default:tag("Phone"); break;
}
break;
case 3: /* LAN */
tag("LAN");
switch (__SHIFTOUT(class, __BITS(5, 7))) {
case 0: tag("[Fully available]"); break;
case 1: tag("[1-17% utilised]"); break;
case 2: tag("[17-33% utilised]"); break;
case 3: tag("[33-50% utilised]"); break;
case 4: tag("[50-67% utilised]"); break;
case 5: tag("[67-83% utilised]"); break;
case 6: tag("[83-99% utilised]"); break;
case 7: tag("[No service available]"); break;
}
break;
case 4: /* Audio/Visual */
switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Wearable Headset"); break;
case 2: tag("Hands-free Audio"); break;
case 4: tag("Microphone"); break;
case 5: tag("Loudspeaker"); break;
case 6: tag("Headphones"); break;
case 7: tag("Portable Audio"); break;
case 8: tag("Car Audio"); break;
case 9: tag("Set-top Box"); break;
case 10: tag("HiFi Audio"); break;
case 11: tag("VCR"); break;
case 12: tag("Video Camera"); break;
case 13: tag("Camcorder"); break;
case 14: tag("Video Monitor"); break;
case 15: tag("Video Display and Loudspeaker"); break;
case 16: tag("Video Conferencing"); break;
case 18: tag("A/V [Gaming/Toy]"); break;
default: tag("Audio/Visual"); break;
}
break;
case 5: /* Peripheral */
switch (__SHIFTOUT(class, __BITS(2, 5))) {
case 1: tag("Joystick"); break;
case 2: tag("Gamepad"); break;
case 3: tag("Remote Control"); break;
case 4: tag("Sensing Device"); break;
case 5: tag("Digitiser Tablet"); break;
case 6: tag("Card Reader"); break;
default: tag("Peripheral"); break;
}
if (class & __BIT(6)) tag("Keyboard");
if (class & __BIT(7)) tag("Mouse");
break;
case 6: /* Imaging */
if (class & __BIT(4)) tag("Display");
if (class & __BIT(5)) tag("Camera");
if (class & __BIT(6)) tag("Scanner");
if (class & __BIT(7)) tag("Printer");
if ((class & __BITS(4, 7)) == 0) tag("Imaging");
break;
case 7: /* Wearable */
switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Wrist Watch"); break;
case 2: tag("Pager"); break;
case 3: tag("Jacket"); break;
case 4: tag("Helmet"); break;
case 5: tag("Glasses"); break;
default: tag("Wearable"); break;
}
break;
case 8: /* Toy */
switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Robot"); break;
case 2: tag("Vehicle"); break;
case 3: tag("Doll / Action Figure"); break;
case 4: tag("Controller"); break;
case 5: tag("Game"); break;
default: tag("Toy"); break;
}
break;
case 9: /* Health */
switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Blood Pressure Monitor"); break;
case 2: tag("Thermometer"); break;
case 3: tag("Weighing Scale"); break;
case 4: tag("Glucose Meter"); break;
case 5: tag("Pulse Oximeter"); break;
case 6: tag("Heart/Pulse Rate Monitor"); break;
case 7: tag("Health Data Display"); break;
default: tag("Health"); break;
}
break;
default:
break;
}
if (class & __BIT(13)) tag("<Limited Discoverable>");
if (class & __BIT(16)) tag("<Positioning>");
if (class & __BIT(17)) tag("<Networking>");
if (class & __BIT(18)) tag("<Rendering>");
if (class & __BIT(19)) tag("<Capturing>");
if (class & __BIT(20)) tag("<Object Transfer>");
if (class & __BIT(21)) tag("<Audio>");
if (class & __BIT(22)) tag("<Telephony>");
if (class & __BIT(23)) tag("<Information>");
}