diff options
| author | plunky <plunky@NetBSD.org> | 2009-10-08 19:25:24 +0000 |
|---|---|---|
| committer | plunky <plunky@NetBSD.org> | 2009-10-08 19:25:24 +0000 |
| commit | ba4cd6cd5e24a45d883958583d10c2a0b0282e66 (patch) | |
| tree | 9b4bd8f9b1c0fcbf5054071c67e67aaf7860e87f /usr.sbin/btconfig | |
| parent | f69ea56c7ac70e25cb80f912cba56d005a00830d (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.c | 399 |
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); } |
