summaryrefslogtreecommitdiff
path: root/usr.sbin/btconfig
diff options
context:
space:
mode:
authorplunky <plunky@NetBSD.org>2009-10-08 19:25:24 +0000
committerplunky <plunky@NetBSD.org>2009-10-08 19:25:24 +0000
commitba4cd6cd5e24a45d883958583d10c2a0b0282e66 (patch)
tree9b4bd8f9b1c0fcbf5054071c67e67aaf7860e87f /usr.sbin/btconfig
parentf69ea56c7ac70e25cb80f912cba56d005a00830d (diff)
fiddle with printing of "Class of Device" information
- pass the octet stream pointer to the function - only print where the format is known (we only know format #0) - use language from the Baseband Assigned numbers document - use bit numbers from the Baseband Assigned numbers document - add Health device major class
Diffstat (limited to 'usr.sbin/btconfig')
-rw-r--r--usr.sbin/btconfig/btconfig.c399
1 files changed, 137 insertions, 262 deletions
diff --git a/usr.sbin/btconfig/btconfig.c b/usr.sbin/btconfig/btconfig.c
index 96eafa2a1b2..2105dc56bc3 100644
--- a/usr.sbin/btconfig/btconfig.c
+++ b/usr.sbin/btconfig/btconfig.c
@@ -1,4 +1,4 @@
-/* $NetBSD: btconfig.c,v 1.17 2009/09/11 19:22:15 plunky Exp $ */
+/* $NetBSD: btconfig.c,v 1.18 2009/10/08 19:25:24 plunky Exp $ */
/*-
* Copyright (c) 2006 Itronix Inc.
@@ -33,7 +33,7 @@
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc. All rights reserved.");
-__RCSID("$NetBSD: btconfig.c,v 1.17 2009/09/11 19:22:15 plunky Exp $");
+__RCSID("$NetBSD: btconfig.c,v 1.18 2009/10/08 19:25:24 plunky Exp $");
#include <sys/ioctl.h>
#include <sys/param.h>
@@ -48,15 +48,6 @@ __RCSID("$NetBSD: btconfig.c,v 1.17 2009/09/11 19:22:15 plunky Exp $");
#include <unistd.h>
#include <util.h>
-/* inquiry results storage */
-struct result {
- bdaddr_t bdaddr;
- uint8_t page_scan_rep_mode;
- uint8_t uclass[HCI_CLASS_SIZE];
- uint16_t clock_offset;
- int8_t rssi;
-};
-
int main(int, char *[]);
void badarg(const char *);
void badparam(const char *);
@@ -67,19 +58,19 @@ void config_unit(void);
void print_val(const char *, const char **, int);
void print_info(int);
void print_stats(void);
-void print_class(const char *);
+void print_class(const char *, uint8_t *);
+void print_class0(void);
void print_voice(int);
void tag(const char *);
void print_features(const char *, uint8_t, uint8_t *);
void print_features0(uint8_t *);
void print_features1(uint8_t *);
+void print_result(int, struct bt_devinquiry *);
void do_inquiry(void);
-void print_result(int, struct result *, int);
void hci_req(uint16_t, uint8_t , void *, size_t, void *, size_t);
-#define save_value(opcode, cbuf, clen) hci_req(opcode, 0, cbuf, clen, NULL, 0)
-#define load_value(opcode, rbuf, rlen) hci_req(opcode, 0, NULL, 0, rbuf, rlen)
-#define hci_cmd(opcode, cbuf, clen) hci_req(opcode, 0, cbuf, clen, NULL, 0)
+void save_value(uint16_t, void *, size_t);
+void load_value(uint16_t, void *, size_t);
#define MAX_STR_SIZE 0xff
@@ -151,7 +142,7 @@ int opt_pin = 0;
int opt_rssi = 0; /* inquiry_with_rssi (obsolete flag) */
int opt_imode = 0; /* inquiry mode */
int opt_inquiry = 0;
-#define INQUIRY_LENGTH 10 /* about 12 seconds */
+#define INQUIRY_LENGTH 10 /* seconds */
#define INQUIRY_MAX_RESPONSES 10
const char *imodes[] = { "std", "rssi", "ext", NULL };
@@ -390,88 +381,53 @@ tag(const char *f)
}
/*
- * basic HCI cmd request function with argument return.
- *
- * Normally, this will return on COMMAND_STATUS or COMMAND_COMPLETE for the given
- * opcode, but if event is given then it will ignore COMMAND_STATUS (unless error)
- * and wait for the specified event.
- *
- * if rbuf/rlen is given, results will be copied into the result buffer for
- * COMMAND_COMPLETE/event responses.
+ * basic HCI request wrapper with error check
*/
void
-hci_req(uint16_t opcode, uint8_t event, void *cbuf, size_t clen, void *rbuf, size_t rlen)
+hci_req(uint16_t opcode, uint8_t event, void *cbuf, size_t clen,
+ void *rbuf, size_t rlen)
{
- uint8_t msg[sizeof(hci_cmd_hdr_t) + HCI_CMD_PKT_SIZE];
- hci_event_hdr_t *ep;
- hci_cmd_hdr_t *cp;
-
- cp = (hci_cmd_hdr_t *)msg;
- cp->type = HCI_CMD_PKT;
- cp->opcode = opcode = htole16(opcode);
- cp->length = clen = MIN(clen, sizeof(msg) - sizeof(hci_cmd_hdr_t));
-
- if (clen) memcpy((cp + 1), cbuf, clen);
-
- if (send(hci, msg, sizeof(hci_cmd_hdr_t) + clen, 0) < 0)
- err(EXIT_FAILURE, "HCI Send");
-
- ep = (hci_event_hdr_t *)msg;
- for(;;) {
- if (recv(hci, msg, sizeof(msg), 0) < 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
-
- err(EXIT_FAILURE, "HCI Recv");
- }
-
- if (ep->event == HCI_EVENT_COMMAND_STATUS) {
- hci_command_status_ep *cs;
-
- cs = (hci_command_status_ep *)(ep + 1);
- if (cs->opcode != opcode)
- continue;
-
- if (cs->status)
- errx(EXIT_FAILURE,
- "HCI cmd (%4.4x) failed (status %d)",
- opcode, cs->status);
-
- if (event == 0)
- break;
-
- continue;
- }
-
- if (ep->event == HCI_EVENT_COMMAND_COMPL) {
- hci_command_compl_ep *cc;
- uint8_t *ptr;
-
- cc = (hci_command_compl_ep *)(ep + 1);
- if (cc->opcode != opcode)
- continue;
-
- if (rbuf == NULL)
- break;
+ struct bt_devreq req;
+
+ req.opcode = opcode;
+ req.event = event;
+ req.cparam = cbuf;
+ req.clen = clen;
+ req.rparam = rbuf;
+ req.rlen = rlen;
+
+ if (bt_devreq(hci, &req, 10) == -1)
+ err(EXIT_FAILURE, "cmd (%02x|%03x)",
+ HCI_OGF(opcode), HCI_OCF(opcode));
+
+ if (event == 0 && rlen > 0 && ((uint8_t *)rbuf)[0] != 0)
+ errx(EXIT_FAILURE, "cmd (%02x|%03x): status 0x%02x",
+ HCI_OGF(opcode), HCI_OCF(opcode), ((uint8_t *)rbuf)[0]);
+}
- ptr = (uint8_t *)(cc + 1);
- if (*ptr)
- errx(EXIT_FAILURE,
- "HCI cmd (%4.4x) failed (status %d)",
- opcode, *ptr);
+/*
+ * write value to device with opcode.
+ * provide a small response buffer so that the status can be checked
+ */
+void
+save_value(uint16_t opcode, void *cbuf, size_t clen)
+{
+ uint8_t buf[1];
- memcpy(rbuf, ++ptr, rlen);
- break;
- }
+ hci_req(opcode, 0, cbuf, clen, buf, sizeof(buf));
+}
- if (ep->event == event) {
- if (rbuf == NULL)
- break;
+/*
+ * read value from device with opcode.
+ * use our own buffer and only return the value from the response packet
+ */
+void
+load_value(uint16_t opcode, void *rbuf, size_t rlen)
+{
+ uint8_t buf[UINT8_MAX];
- memcpy(rbuf, (ep + 1), rlen);
- break;
- }
- }
+ hci_req(opcode, 0, NULL, 0, buf, sizeof(buf));
+ memcpy(rbuf, buf + 1, rlen);
}
int
@@ -505,11 +461,8 @@ void
config_unit(void)
{
- if (opt_enable) {
- if (opt_enable > 0)
- btr.btr_flags |= BTF_UP;
- else
- btr.btr_flags &= ~BTF_UP;
+ if (opt_enable < 0 || opt_reset) {
+ btr.btr_flags &= ~BTF_UP;
if (ioctl(hci, SIOCSBTFLAGS, &btr) < 0)
err(EXIT_FAILURE, "SIOCSBTFLAGS");
@@ -518,22 +471,12 @@ config_unit(void)
err(EXIT_FAILURE, "%s", btr.btr_name);
}
- if (opt_reset) {
- hci_cmd(HCI_CMD_RESET, NULL, 0);
+ if (opt_enable > 0 || opt_reset) {
+ btr.btr_flags |= BTF_UP;
- btr.btr_flags |= BTF_INIT;
if (ioctl(hci, SIOCSBTFLAGS, &btr) < 0)
err(EXIT_FAILURE, "SIOCSBTFLAGS");
- /*
- * although the reset command will automatically
- * carry out these commands, we do them manually
- * just so we can wait for completion.
- */
- hci_cmd(HCI_CMD_READ_BDADDR, NULL, 0);
- hci_cmd(HCI_CMD_READ_BUFFER_SIZE, NULL, 0);
- hci_cmd(HCI_CMD_READ_LOCAL_FEATURES, NULL, 0);
-
if (set_unit(SIOCGBTINFO) < 0)
err(EXIT_FAILURE, "%s", btr.btr_name);
}
@@ -713,8 +656,7 @@ print_info(int level)
}
load_value(HCI_CMD_READ_UNIT_CLASS, buf, HCI_CLASS_SIZE);
- class = (buf[2] << 16) | (buf[1] << 8) | (buf[0]);
- print_class("\t");
+ print_class("\tclass:", buf);
load_value(HCI_CMD_READ_LOCAL_NAME, buf, HCI_UNIT_NAME_SIZE);
printf("\tname: \"%s\"\n", buf);
@@ -790,15 +732,17 @@ print_info(int level)
if ((buf[7] & HCI_LMP_EXTENDED_FEATURES) == 0) {
print_features("\tfeatures:", 0, buf);
} else {
- buf[0] = 0;
+ hci_read_local_extended_features_rp rp;
+
+ rp.page = 0;
do {
hci_req(HCI_CMD_READ_LOCAL_EXTENDED_FEATURES, 0,
- buf, 1,
- buf, HCI_FEATURES_SIZE + 2);
+ &rp.page, sizeof(rp.page), &rp, sizeof(rp));
- print_features("\tfeatures page#%d:", buf[0], buf + 2);
- } while (buf[0]++ < buf[1]);
+ print_features("\tfeatures (page %d):",
+ rp.page, rp.features);
+ } while (rp.page++ < rp.max_page);
}
}
@@ -934,30 +878,39 @@ print_features1(uint8_t *f)
}
void
-print_class(const char *str)
+print_class(const char *str, uint8_t *uclass)
{
- int major, minor;
- major = (class & 0x1f00) >> 8;
- minor = (class & 0x00fc) >> 2;
+ class = (uclass[2] << 16) | (uclass[1] << 8) | uclass[0];
+ width = printf("%s [0x%06x]", str, class);
+
+ switch(__SHIFTOUT(class, __BITS(0, 1))) {
+ case 0: print_class0(); break;
+ default: break;
+ }
+
+ tag(NULL);
+}
- width = printf("%sclass: [0x%6.6x]", str, class);
+void
+print_class0(void)
+{
- switch (major) {
+ switch (__SHIFTOUT(class, __BITS(8, 12))) {
case 1: /* Computer */
- switch (minor) {
- case 1: tag("Desktop"); break;
- case 2: tag("Server"); break;
+ 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"); break;
- case 5: tag("Palm Sized"); break;
- case 6: tag("Wearable"); 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;
}
- tag("Computer");
break;
case 2: /* Phone */
- switch (minor) {
+ switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Cellular Phone"); break;
case 2: tag("Cordless Phone"); break;
case 3: tag("Smart Phone"); break;
@@ -969,7 +922,7 @@ print_class(const char *str)
case 3: /* LAN */
tag("LAN");
- switch ((minor & 0x38) >> 3) {
+ 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;
@@ -982,7 +935,7 @@ print_class(const char *str)
break;
case 4: /* Audio/Visual */
- switch (minor) {
+ switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Wearable Headset"); break;
case 2: tag("Hands-free Audio"); break;
case 4: tag("Microphone"); break;
@@ -1004,7 +957,7 @@ print_class(const char *str)
break;
case 5: /* Peripheral */
- switch (minor & 0x0f) {
+ switch (__SHIFTOUT(class, __BITS(2, 5))) {
case 1: tag("Joystick"); break;
case 2: tag("Gamepad"); break;
case 3: tag("Remote Control"); break;
@@ -1014,20 +967,20 @@ print_class(const char *str)
default: tag("Peripheral"); break;
}
- if (minor & 0x10) tag("Keyboard");
- if (minor & 0x20) tag("Mouse");
+ if (class & __BIT(6)) tag("Keyboard");
+ if (class & __BIT(7)) tag("Mouse");
break;
case 6: /* Imaging */
- if (minor & 0x20) tag("Printer");
- if (minor & 0x10) tag("Scanner");
- if (minor & 0x08) tag("Camera");
- if (minor & 0x04) tag("Display");
- if ((minor & 0x3c) == 0) tag("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 (minor) {
+ switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Wrist Watch"); break;
case 2: tag("Pager"); break;
case 3: tag("Jacket"); break;
@@ -1038,7 +991,7 @@ print_class(const char *str)
break;
case 8: /* Toy */
- switch (minor) {
+ switch (__SHIFTOUT(class, __BITS(2, 7))) {
case 1: tag("Robot"); break;
case 2: tag("Vehicle"); break;
case 3: tag("Doll / Action Figure"); break;
@@ -1048,26 +1001,39 @@ print_class(const char *str)
}
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 & 0x002000) tag("<Limited Discoverable>");
- if (class & 0x010000) tag("<Positioning>");
- if (class & 0x020000) tag("<Networking>");
- if (class & 0x040000) tag("<Rendering>");
- if (class & 0x080000) tag("<Capturing>");
- if (class & 0x100000) tag("<Object Transfer>");
- if (class & 0x200000) tag("<Audio>");
- if (class & 0x400000) tag("<Telephony>");
- if (class & 0x800000) tag("<Information>");
- tag(NULL);
+ 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>");
}
void
print_voice(int level)
{
- printf("\tvoice: [0x%4.4x]\n", voice);
+
+ printf("\tvoice: [0x%04x]\n", voice);
if (level == 0)
return;
@@ -1075,8 +1041,8 @@ print_voice(int level)
printf("\t\tInput Coding: ");
switch ((voice & 0x0300) >> 8) {
case 0x00: printf("Linear PCM [%d-bit, pos %d]",
- (voice & 0x0020 ? 16 : 8),
- (voice & 0x001c) >> 2); break;
+ (voice & 0x0020 ? 16 : 8),
+ (voice & 0x001c) >> 2); break;
case 0x01: printf("u-Law"); break;
case 0x02: printf("A-Law"); break;
case 0x03: printf("unknown"); break;
@@ -1101,15 +1067,13 @@ print_voice(int level)
}
void
-print_result(int num, struct result *r, int rssi)
+print_result(int num, struct bt_devinquiry *r)
{
hci_remote_name_req_cp ncp;
hci_remote_name_req_compl_ep nep;
struct hostent *hp;
- printf("%3d: bdaddr %s",
- num,
- bt_ntoa(&r->bdaddr, NULL));
+ printf("%3d: bdaddr %s", num, bt_ntoa(&r->bdaddr, NULL));
hp = bt_gethostbyaddr((const char *)&r->bdaddr, sizeof(bdaddr_t), AF_BLUETOOTH);
if (hp != NULL)
@@ -1119,7 +1083,7 @@ print_result(int num, struct result *r, int rssi)
memset(&ncp, 0, sizeof(ncp));
bdaddr_copy(&ncp.bdaddr, &r->bdaddr);
- ncp.page_scan_rep_mode = r->page_scan_rep_mode;
+ ncp.page_scan_rep_mode = r->pscan_rep_mode;
ncp.clock_offset = r->clock_offset;
hci_req(HCI_CMD_REMOTE_NAME_REQ,
@@ -1128,28 +1092,18 @@ print_result(int num, struct result *r, int rssi)
&nep, sizeof(nep));
printf(" : name \"%s\"\n", nep.name);
-
- class = (r->uclass[2] << 16) | (r->uclass[1] << 8) | (r->uclass[0]);
- print_class(" : ");
-
- printf(" : page scan rep mode 0x%02x\n", r->page_scan_rep_mode);
+ print_class(" : class", r->dev_class);
+ printf(" : page scan rep mode 0x%02x\n", r->pscan_rep_mode);
printf(" : clock offset %d\n", le16toh(r->clock_offset));
-
- if (rssi)
- printf(" : rssi %d\n", r->rssi);
-
+ printf(" : rssi %d\n", r->rssi);
printf("\n");
}
void
do_inquiry(void)
{
- uint8_t buf[HCI_EVENT_PKT_SIZE];
- struct result result[INQUIRY_MAX_RESPONSES];
- hci_inquiry_cp inq;
- struct hci_filter f;
- hci_event_hdr_t *hh;
- int i, j, num, rssi;
+ struct bt_devinquiry *result;
+ int i, num;
if (opt_inquiry == 0)
return;
@@ -1157,97 +1111,18 @@ do_inquiry(void)
printf("Device Discovery from device: %s ...", btr.btr_name);
fflush(stdout);
- memset(&f, 0, sizeof(f));
- hci_filter_set(HCI_EVENT_COMMAND_STATUS, &f);
- hci_filter_set(HCI_EVENT_COMMAND_COMPL, &f);
- hci_filter_set(HCI_EVENT_INQUIRY_RESULT, &f);
- hci_filter_set(HCI_EVENT_RSSI_RESULT, &f);
- hci_filter_set(HCI_EVENT_INQUIRY_COMPL, &f);
- hci_filter_set(HCI_EVENT_REMOTE_NAME_REQ_COMPL, &f);
- hci_filter_set(HCI_EVENT_READ_REMOTE_FEATURES_COMPL, &f);
- if (setsockopt(hci, BTPROTO_HCI, SO_HCI_EVT_FILTER, &f, sizeof(f)) < 0)
- err(EXIT_FAILURE, "Can't set event filter");
-
- /* General Inquiry LAP is 0x9e8b33 */
- inq.lap[0] = 0x33;
- inq.lap[1] = 0x8b;
- inq.lap[2] = 0x9e;
- inq.inquiry_length = INQUIRY_LENGTH;
- inq.num_responses = INQUIRY_MAX_RESPONSES;
-
- hci_cmd(HCI_CMD_INQUIRY, &inq, sizeof(inq));
-
- num = 0;
- rssi = 0;
- hh = (hci_event_hdr_t *)buf;
-
- for (;;) {
- if (recv(hci, buf, sizeof(buf), 0) <= 0)
- err(EXIT_FAILURE, "recv");
-
- if (hh->event == HCI_EVENT_INQUIRY_COMPL)
- break;
+ num = bt_devinquiry(btr.btr_name, INQUIRY_LENGTH,
+ INQUIRY_MAX_RESPONSES, &result);
- if (hh->event == HCI_EVENT_INQUIRY_RESULT) {
- hci_inquiry_result_ep *ep = (hci_inquiry_result_ep *)(hh + 1);
- hci_inquiry_response *ir = (hci_inquiry_response *)(ep + 1);
-
- for (i = 0 ; i < ep->num_responses ; i++) {
- if (num == INQUIRY_MAX_RESPONSES)
- break;
-
- /* some devices keep responding, ignore dupes */
- for (j = 0 ; j < num ; j++)
- if (bdaddr_same(&result[j].bdaddr, &ir[i].bdaddr))
- break;
-
- if (j < num)
- continue;
-
- bdaddr_copy(&result[num].bdaddr, &ir[i].bdaddr);
- memcpy(&result[num].uclass, &ir[i].uclass, HCI_CLASS_SIZE);
- result[num].page_scan_rep_mode = ir[i].page_scan_rep_mode;
- result[num].clock_offset = ir[i].clock_offset;
- result[num].rssi = 0;
- num++;
- printf(".");
- fflush(stdout);
- }
- continue;
- }
-
- if (hh->event == HCI_EVENT_RSSI_RESULT) {
- hci_rssi_result_ep *ep = (hci_rssi_result_ep *)(hh + 1);
- hci_rssi_response *rr = (hci_rssi_response *)(ep + 1);
-
- for (i = 0 ; i < ep->num_responses ; i++) {
- if (num == INQUIRY_MAX_RESPONSES)
- break;
-
- /* some devices keep responding, ignore dupes */
- for (j = 0 ; j < num ; j++)
- if (bdaddr_same(&result[j].bdaddr, &rr[i].bdaddr))
- break;
-
- if (j < num)
- continue;
-
- bdaddr_copy(&result[num].bdaddr, &rr[i].bdaddr);
- memcpy(&result[num].uclass, &rr[i].uclass, HCI_CLASS_SIZE);
- result[num].page_scan_rep_mode = rr[i].page_scan_rep_mode;
- result[num].clock_offset = rr[i].clock_offset;
- result[num].rssi = rr[i].rssi;
- rssi = 1;
- num++;
- printf(".");
- fflush(stdout);
- }
- continue;
- }
+ if (num == -1) {
+ printf("failed\n");
+ err(EXIT_FAILURE, "%s", btr.btr_name);
}
printf(" %d response%s\n", num, (num == 1 ? "" : "s"));
for (i = 0 ; i < num ; i++)
- print_result(i + 1, &result[i], rssi);
+ print_result(i + 1, &result[i]);
+
+ free(result);
}