8dc4b645e9b89662c8dac03caa0b9ce985f5b69d
[dragonfly.git] / usr.sbin / btconfig / btconfig.c
1 /* $NetBSD: btconfig.c,v 1.6 2007/09/07 18:40:01 plunky Exp $ */
2 /* $DragonFly: src/usr.sbin/btconfig/btconfig.c,v 1.2 2008/04/20 13:44:26 swildner Exp $ */
3
4 /*-
5  * Copyright (c) 2006 Itronix Inc.
6  * All rights reserved.
7  *
8  * Written by Iain Hibbert for Itronix Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of Itronix Inc. may not be used to endorse
19  *    or promote products derived from this software without specific
20  *    prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
39
40 #include <net/if.h>
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <err.h>
50 #include <bluetooth.h>
51 #include <netbt/hci.h>
52 #include <sys/endian.h>
53
54 /* inquiry results storage */
55 struct result {
56         bdaddr_t        bdaddr;
57         uint8_t         page_scan_rep_mode;
58         uint8_t         uclass[HCI_CLASS_SIZE];
59         uint16_t        clock_offset;
60         int8_t          rssi;
61 };
62
63 int main(int, char *[]);
64 void badarg(const char *);
65 void badparam(const char *);
66 void usage(void);
67 int set_unit(unsigned long);
68 void config_unit(void);
69 void print_info(int);
70 void print_stats(void);
71 void print_class(const char *);
72 void print_voice(int);
73 void tag(const char *);
74 void print_features(const char *, uint8_t *);
75 void do_inquiry(void);
76 void print_result(int, struct result *, int);
77 void printb(uint16_t v, const char *bits);
78
79 void hci_req(uint16_t, uint8_t , void *, size_t, void *, size_t);
80 #define save_value(opcode, cbuf, clen)  hci_req(opcode, 0, cbuf, clen, NULL, 0)
81 #define load_value(opcode, rbuf, rlen)  hci_req(opcode, 0, NULL, 0, rbuf, rlen)
82 #define hci_cmd(opcode, cbuf, clen)     hci_req(opcode, 0, cbuf, clen, NULL, 0)
83
84 #define MAX_STR_SIZE    0xff
85
86 /* print width */
87 int width = 0;
88 #define MAX_WIDTH       70
89
90 /* global variables */
91 int hci;
92 struct btreq btr;
93
94 /* command line flags */
95 int verbose = 0;        /* more info */
96 int lflag = 0;          /* list devices */
97 int sflag = 0;          /* get/zero stats */
98
99 /* device up/down (flag) */
100 int opt_enable = 0;
101 int opt_reset = 0;
102 #define FLAGBITS        "\001UP"                \
103                         "\002RUNNING"           \
104                         "\003XMIT_CMD"          \
105                         "\004XMIT_ACL"          \
106                         "\005XMIT_SCO"          \
107                         "\006INIT_BDADDR"       \
108                         "\007INIT_BUFFER_SIZE"  \
109                         "\010INIT_FEATURES"
110
111 /* authorisation (flag) */
112 int opt_auth = 0;
113
114 /* encryption (flag) */
115 int opt_encrypt = 0;
116
117 /* scan enable options (flags) */
118 int opt_pscan = 0;
119 int opt_iscan = 0;
120
121 /* link policy options (flags) */
122 int opt_switch = 0;
123 int opt_hold = 0;
124 int opt_sniff = 0;
125 int opt_park = 0;
126
127 /* class of device (hex value) */
128 int opt_class = 0;
129 uint32_t class;
130
131 /* packet type mask (hex value) */
132 int opt_ptype = 0;
133 uint32_t ptype;
134
135 /* unit name (string) */
136 int opt_name = 0;
137 char name[MAX_STR_SIZE];
138
139 /* pin type */
140 int opt_pin = 0;
141
142 /* Inquiry */
143 int opt_rssi = 0;                       /* inquiry_with_rssi (flag) */
144 int opt_inquiry = 0;
145 #define INQUIRY_LENGTH          10      /* about 12 seconds */
146 #define INQUIRY_MAX_RESPONSES   10
147
148 /* Voice Settings */
149 int opt_voice = 0;
150 uint32_t voice;
151
152 /* Page Timeout */
153 int opt_pto = 0;
154 uint32_t pto;
155
156 /* set SCO mtu */
157 int opt_scomtu;
158 uint32_t scomtu;
159
160 struct parameter {
161         const char      *name;
162         enum { P_SET, P_CLR, P_STR, P_HEX, P_NUM } type;
163         int             *opt;
164         void            *val;
165 } parameters[] = {
166         { "up",         P_SET,  &opt_enable,    NULL    },
167         { "enable",     P_SET,  &opt_enable,    NULL    },
168         { "down",       P_CLR,  &opt_enable,    NULL    },
169         { "disable",    P_CLR,  &opt_enable,    NULL    },
170         { "name",       P_STR,  &opt_name,      name    },
171         { "pscan",      P_SET,  &opt_pscan,     NULL    },
172         { "-pscan",     P_CLR,  &opt_pscan,     NULL    },
173         { "iscan",      P_SET,  &opt_iscan,     NULL    },
174         { "-iscan",     P_CLR,  &opt_iscan,     NULL    },
175         { "switch",     P_SET,  &opt_switch,    NULL    },
176         { "-switch",    P_CLR,  &opt_switch,    NULL    },
177         { "hold",       P_SET,  &opt_hold,      NULL    },
178         { "-hold",      P_CLR,  &opt_hold,      NULL    },
179         { "sniff",      P_SET,  &opt_sniff,     NULL    },
180         { "-sniff",     P_CLR,  &opt_sniff,     NULL    },
181         { "park",       P_SET,  &opt_park,      NULL    },
182         { "-park",      P_CLR,  &opt_park,      NULL    },
183         { "auth",       P_SET,  &opt_auth,      NULL    },
184         { "-auth",      P_CLR,  &opt_auth,      NULL    },
185         { "encrypt",    P_SET,  &opt_encrypt,   NULL    },
186         { "-encrypt",   P_CLR,  &opt_encrypt,   NULL    },
187         { "ptype",      P_HEX,  &opt_ptype,     &ptype  },
188         { "class",      P_HEX,  &opt_class,     &class  },
189         { "fixed",      P_SET,  &opt_pin,       NULL    },
190         { "variable",   P_CLR,  &opt_pin,       NULL    },
191         { "inq",        P_SET,  &opt_inquiry,   NULL    },
192         { "inquiry",    P_SET,  &opt_inquiry,   NULL    },
193         { "rssi",       P_SET,  &opt_rssi,      NULL    },
194         { "-rssi",      P_CLR,  &opt_rssi,      NULL    },
195         { "reset",      P_SET,  &opt_reset,     NULL    },
196         { "voice",      P_HEX,  &opt_voice,     &voice  },
197         { "pto",        P_NUM,  &opt_pto,       &pto    },
198         { "scomtu",     P_NUM,  &opt_scomtu,    &scomtu },
199         { NULL,         0,      NULL,           NULL    }
200 };
201
202 int
203 main(int ac, char *av[])
204 {
205         int ch;
206         struct parameter *p;
207
208         while ((ch = getopt(ac, av, "hlsvz")) != -1) {
209                 switch(ch) {
210                 case 'l':
211                         lflag = 1;
212                         break;
213
214                 case 's':
215                         sflag = 1;
216                         break;
217
218                 case 'v':
219                         verbose++;
220                         break;
221
222                 case 'z':
223                         sflag = 2;
224                         break;
225
226                 case 'h':
227                 default:
228                         usage();
229                 }
230         }
231         av += optind;
232         ac -= optind;
233
234         if (lflag && sflag)
235                 usage();
236
237
238         hci = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 
239         if (hci == -1)
240                 err(EXIT_FAILURE, "socket");
241
242         if (ac == 0) {
243                 verbose++;
244
245                 memset(&btr, 0, sizeof(btr));
246                 while (set_unit(SIOCNBTINFO) != -1) {
247                         print_info(99);
248                         print_stats();
249                 }
250
251                 tag(NULL);
252         } else {
253                 strlcpy(btr.btr_name, *av, HCI_DEVNAME_SIZE);
254                 av++, ac--;
255
256                 if (set_unit(SIOCGBTINFO) < 0)
257                         err(EXIT_FAILURE, "%s", btr.btr_name);
258
259                 if (ac == 0)
260                         verbose += 2;
261
262                 while (ac > 0) {
263                         for (p = parameters ; ; p++) {
264                                 if (p->name == NULL)
265                                         badparam(*av);
266
267                                 if (strcmp(*av, p->name) == 0)
268                                         break;
269                         }
270
271                         switch(p->type) {
272                         case P_SET:
273                                 *(p->opt) = 1;
274                                 break;
275
276                         case P_CLR:
277                                 *(p->opt) = -1;
278                                 break;
279
280                         case P_STR:
281                                 if (--ac < 1) badarg(p->name);
282                                 strlcpy((char *)(p->val), *++av, MAX_STR_SIZE);
283                                 *(p->opt) = 1;
284                                 break;
285
286                         case P_HEX:
287                                 if (--ac < 1) badarg(p->name);
288                                 *(uint32_t *)(p->val) = strtoul(*++av, NULL, 16);
289                                 *(p->opt) = 1;
290                                 break;
291
292                         case P_NUM:
293                                 if (--ac < 1) badarg(p->name);
294                                 *(uint32_t *)(p->val) = strtoul(*++av, NULL, 10);
295                                 *(p->opt) = 1;
296                                 break;
297                         }
298
299                         av++, ac--;
300                 }
301
302                 config_unit();
303                 print_info(verbose);
304                 print_stats();
305                 do_inquiry();
306         }
307
308         close(hci);
309         return EXIT_SUCCESS;
310 }
311
312 void
313 badparam(const char *param)
314 {
315         fprintf(stderr, "unknown parameter '%s'\n", param);
316         exit(EXIT_FAILURE);
317 }
318
319 void
320 badarg(const char *param)
321 {
322         fprintf(stderr, "parameter '%s' needs argument\n", param);
323         exit(EXIT_FAILURE);
324 }
325
326 void
327 usage(void)
328 {
329         fprintf(stderr, "usage: %s [-svz] [device [parameters]]\n", getprogname());
330         fprintf(stderr, "       %s -l\n", getprogname());
331         exit(EXIT_FAILURE);
332 }
333
334 /*
335  * pretty printing feature
336  */
337 void
338 tag(const char *f)
339 {
340         if (f == NULL) {
341                 if (width > 0)
342                         printf("\n");
343
344                 width = 0;
345         } else {
346                 width += printf("%*s%s",
347                                 (width == 0 ? (lflag ? 0 : 8) : 1),
348                                 "", f);
349
350                 if (width > MAX_WIDTH) {
351                         printf("\n");
352                         width = 0;
353                 }
354         }
355 }
356
357 /*
358  * basic HCI cmd request function with argument return.
359  *
360  * Normally, this will return on COMMAND_STATUS or COMMAND_COMPLETE for the given
361  * opcode, but if event is given then it will ignore COMMAND_STATUS (unless error)
362  * and wait for the specified event.
363  *
364  * if rbuf/rlen is given, results will be copied into the result buffer for
365  * COMMAND_COMPLETE/event responses.
366  */
367 void
368 hci_req(uint16_t opcode, uint8_t event, void *cbuf, size_t clen, void *rbuf, size_t rlen)
369 {
370         uint8_t msg[sizeof(hci_cmd_hdr_t) + HCI_CMD_PKT_SIZE];
371         hci_event_hdr_t *ep;
372         hci_cmd_hdr_t *cp;
373
374         cp = (hci_cmd_hdr_t *)msg;
375         cp->type = HCI_CMD_PKT;
376         cp->opcode = opcode = htole16(opcode);
377         cp->length = clen = MIN(clen, sizeof(msg) - sizeof(hci_cmd_hdr_t));
378
379         if (clen) memcpy((cp + 1), cbuf, clen);
380
381         if (send(hci, msg, sizeof(hci_cmd_hdr_t) + clen, 0) < 0)
382                 err(EXIT_FAILURE, "HCI Send");
383
384         ep = (hci_event_hdr_t *)msg;
385         for(;;) {
386                 if (recv(hci, msg, sizeof(msg), 0) < 0) {
387                         if (errno == EAGAIN || errno == EINTR)
388                                 continue;
389
390                         err(EXIT_FAILURE, "HCI Recv");
391                 }
392
393                 if (ep->event == HCI_EVENT_COMMAND_STATUS) {
394                         hci_command_status_ep *cs;
395
396                         cs = (hci_command_status_ep *)(ep + 1);
397                         if (cs->opcode != opcode)
398                                 continue;
399
400                         if (cs->status)
401                                 errx(EXIT_FAILURE,
402                                     "HCI cmd (%4.4x) failed (status %d)",
403                                     opcode, cs->status);
404
405                         if (event == 0)
406                                 break;
407
408                         continue;
409                 }
410
411                 if (ep->event == HCI_EVENT_COMMAND_COMPL) {
412                         hci_command_compl_ep *cc;
413                         uint8_t *ptr;
414
415                         cc = (hci_command_compl_ep *)(ep + 1);
416                         if (cc->opcode != opcode)
417                                 continue;
418
419                         if (rbuf == NULL)
420                                 break;
421
422                         ptr = (uint8_t *)(cc + 1);
423                         if (*ptr)
424                                 errx(EXIT_FAILURE,
425                                     "HCI cmd (%4.4x) failed (status %d)",
426                                     opcode, *ptr);
427
428                         memcpy(rbuf, ++ptr, rlen);
429                         break;
430                 }
431
432                 if (ep->event == event) {
433                         if (rbuf == NULL)
434                                 break;
435
436                         memcpy(rbuf, (ep + 1), rlen);
437                         break;
438                 }
439         }
440 }
441
442 int
443 set_unit(unsigned long cmd)
444 {
445         if (ioctl(hci, cmd, &btr) == -1)
446                 return -1;
447
448         if (btr.btr_flags & BTF_UP) {
449                 struct sockaddr_bt sa;
450
451                 sa.bt_len = sizeof(sa);
452                 sa.bt_family = AF_BLUETOOTH;
453                 bdaddr_copy(&sa.bt_bdaddr, &btr.btr_bdaddr);
454
455                 if (bind(hci, (struct sockaddr *)&sa, sizeof(sa)) < 0)
456                         err(EXIT_FAILURE, "bind");
457                         
458                 if (connect(hci, (struct sockaddr *)&sa, sizeof(sa)) < 0)
459                         err(EXIT_FAILURE, "connect");
460         }
461
462         return 0;
463 }
464
465 /*
466  * apply configuration parameters to unit
467  */
468 void
469 config_unit(void)
470 {
471         if (opt_enable) {
472                 if (opt_enable > 0)
473                         btr.btr_flags |= BTF_UP;
474                 else
475                         btr.btr_flags &= ~BTF_UP;
476
477                 if (ioctl(hci, SIOCSBTFLAGS, &btr) < 0)
478                         err(EXIT_FAILURE, "SIOCSBTFLAGS");
479
480                 if (set_unit(SIOCGBTINFO) < 0)
481                         err(EXIT_FAILURE, "%s", btr.btr_name);
482         }
483
484         if (opt_reset) {
485                 hci_cmd(HCI_CMD_RESET, NULL, 0);
486
487                 btr.btr_flags |= BTF_INIT;
488                 if (ioctl(hci, SIOCSBTFLAGS, &btr) < 0)
489                         err(EXIT_FAILURE, "SIOCSBTFLAGS");
490
491                 /*
492                  * although the reset command will automatically
493                  * carry out these commands, we do them manually
494                  * just so we can wait for completion.
495                  */
496                 hci_cmd(HCI_CMD_READ_BDADDR, NULL, 0);
497                 hci_cmd(HCI_CMD_READ_BUFFER_SIZE, NULL, 0);
498                 hci_cmd(HCI_CMD_READ_LOCAL_FEATURES, NULL, 0);
499
500                 if (set_unit(SIOCGBTINFO) < 0)
501                         err(EXIT_FAILURE, "%s", btr.btr_name);
502         }
503
504         if (opt_switch || opt_hold || opt_sniff || opt_park) {
505                 uint16_t val = btr.btr_link_policy;
506
507                 if (opt_switch > 0) val |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
508                 if (opt_switch < 0) val &= ~HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
509                 if (opt_hold > 0)   val |= HCI_LINK_POLICY_ENABLE_HOLD_MODE;
510                 if (opt_hold < 0)   val &= ~HCI_LINK_POLICY_ENABLE_HOLD_MODE;
511                 if (opt_sniff > 0)  val |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
512                 if (opt_sniff < 0)  val &= ~HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
513                 if (opt_park > 0)   val |= HCI_LINK_POLICY_ENABLE_PARK_MODE;
514                 if (opt_park < 0)   val &= ~HCI_LINK_POLICY_ENABLE_PARK_MODE;
515
516                 btr.btr_link_policy = val;
517                 if (ioctl(hci, SIOCSBTPOLICY, &btr) < 0)
518                         err(EXIT_FAILURE, "SIOCSBTPOLICY");
519         }
520
521         if (opt_ptype) {
522                 btr.btr_packet_type = ptype;
523                 if (ioctl(hci, SIOCSBTPTYPE, &btr) < 0)
524                         err(EXIT_FAILURE, "SIOCSBTPTYPE");
525         }
526
527         if (opt_pscan || opt_iscan) {
528                 uint8_t val;
529
530                 load_value(HCI_CMD_READ_SCAN_ENABLE, &val, sizeof(val));
531                 if (opt_pscan > 0) val |= HCI_PAGE_SCAN_ENABLE;
532                 if (opt_pscan < 0) val &= ~HCI_PAGE_SCAN_ENABLE;
533                 if (opt_iscan > 0) val |= HCI_INQUIRY_SCAN_ENABLE;
534                 if (opt_iscan < 0) val &= ~HCI_INQUIRY_SCAN_ENABLE;
535                 save_value(HCI_CMD_WRITE_SCAN_ENABLE, &val, sizeof(val));
536         }
537
538         if (opt_auth) {
539                 uint8_t val = (opt_auth > 0 ? 1 : 0);
540
541                 save_value(HCI_CMD_WRITE_AUTH_ENABLE, &val, sizeof(val));
542         }
543
544         if (opt_encrypt) {
545                 uint8_t val = (opt_encrypt > 0 ? 1 : 0);
546
547                 save_value(HCI_CMD_WRITE_ENCRYPTION_MODE, &val, sizeof(val));
548         }
549
550         if (opt_name)
551                 save_value(HCI_CMD_WRITE_LOCAL_NAME, name, HCI_UNIT_NAME_SIZE);
552
553         if (opt_class) {
554                 uint8_t val[HCI_CLASS_SIZE];
555
556                 val[0] = (class >> 0) & 0xff;
557                 val[1] = (class >> 8) & 0xff;
558                 val[2] = (class >> 16) & 0xff;
559
560                 save_value(HCI_CMD_WRITE_UNIT_CLASS, val, HCI_CLASS_SIZE);
561         }
562
563         if (opt_pin) {
564                 uint8_t val;
565
566                 if (opt_pin > 0)        val = 1;
567                 else                    val = 0;
568
569                 save_value(HCI_CMD_WRITE_PIN_TYPE, &val, sizeof(val));
570         }
571
572         if (opt_voice) {
573                 uint16_t val;
574
575                 val = htole16(voice & 0x03ff);
576                 save_value(HCI_CMD_WRITE_VOICE_SETTING, &val, sizeof(val));
577         }
578
579         if (opt_pto) {
580                 uint16_t val;
581
582                 val = htole16(pto * 8 / 5);
583                 save_value(HCI_CMD_WRITE_PAGE_TIMEOUT, &val, sizeof(val));
584         }
585
586         if (opt_scomtu) {
587                 if (scomtu > 0xff) {
588                         warnx("Invalid SCO mtu %d", scomtu);
589                 } else {
590                         btr.btr_sco_mtu = scomtu;
591
592                         if (ioctl(hci, SIOCSBTSCOMTU, &btr) < 0)
593                                 warn("SIOCSBTSCOMTU");
594                 }
595         }
596
597         if (opt_rssi) {
598                 uint8_t val = (opt_rssi > 0 ? 1 : 0);
599
600                 save_value(HCI_CMD_WRITE_INQUIRY_MODE, &val, sizeof(val));
601         }
602 }
603
604 /*
605  * Print info for Bluetooth Device with varying verbosity levels
606  */
607 void
608 print_info(int level)
609 {
610         uint8_t val, buf[MAX_STR_SIZE];
611         uint16_t val16;
612
613         if (lflag) {
614                 tag(btr.btr_name);
615                 return;
616         }
617
618         if (level-- < 1)
619                 return;
620
621         printf("%s: bdaddr %s flags %#x", btr.btr_name,
622                 bt_ntoa(&btr.btr_bdaddr, NULL), btr.btr_flags);
623         printb(btr.btr_flags, FLAGBITS);
624         printf("\n");
625
626         if (level-- < 1)
627                 return;
628
629         printf("\tnum_cmd = %d\n"
630                "\tnum_acl = %d, acl_mtu = %d\n"
631                "\tnum_sco = %d, sco_mtu = %d\n",
632                btr.btr_num_cmd,
633                btr.btr_num_acl, btr.btr_acl_mtu,
634                btr.btr_num_sco, btr.btr_sco_mtu);
635
636         if (level-- < 1 || (btr.btr_flags & BTF_UP) == 0)
637                 return;
638
639         load_value(HCI_CMD_READ_UNIT_CLASS, buf, HCI_CLASS_SIZE);
640         class = (buf[2] << 16) | (buf[1] << 8) | (buf[0]);
641         print_class("\t");
642
643         load_value(HCI_CMD_READ_LOCAL_NAME, buf, HCI_UNIT_NAME_SIZE);
644         printf("\tname: \"%s\"\n", buf);
645
646         load_value(HCI_CMD_READ_VOICE_SETTING, buf, sizeof(uint16_t));
647         voice = (buf[1] << 8) | buf[0];
648         print_voice(level);
649
650         load_value(HCI_CMD_READ_PIN_TYPE, &val, sizeof(val));
651         printf("\tpin: %s\n", val ? "fixed" : "variable");
652
653         width = printf("\toptions:");
654
655         load_value(HCI_CMD_READ_SCAN_ENABLE, &val, sizeof(val));
656         if (val & HCI_INQUIRY_SCAN_ENABLE)      tag("iscan");
657         else if (level > 0)                     tag("-iscan");
658
659         if (val & HCI_PAGE_SCAN_ENABLE)         tag("pscan");
660         else if (level > 0)                     tag("-pscan");
661
662         load_value(HCI_CMD_READ_AUTH_ENABLE, &val, sizeof(val));
663         if (val)                                tag("auth");
664         else if (level > 0)                     tag("-auth");
665
666         load_value(HCI_CMD_READ_ENCRYPTION_MODE, &val, sizeof(val));
667         if (val)                                tag("encrypt");
668         else if (level > 0)                     tag("-encrypt");
669
670         val = btr.btr_link_policy;
671         if (val & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH)   tag("switch");
672         else if (level > 0)                             tag("-switch");
673         if (val & HCI_LINK_POLICY_ENABLE_HOLD_MODE)     tag("hold");
674         else if (level > 0)                             tag("-hold");
675         if (val & HCI_LINK_POLICY_ENABLE_SNIFF_MODE)    tag("sniff");
676         else if (level > 0)                             tag("-sniff");
677         if (val & HCI_LINK_POLICY_ENABLE_PARK_MODE)     tag("park");
678         else if (level > 0)                             tag("-park");
679
680         load_value(HCI_CMD_READ_INQUIRY_MODE, &val, sizeof(val));
681         if (val)                                tag("rssi");
682         else if (level > 0)                     tag("-rssi");
683
684         tag(NULL);
685
686         if (level-- < 1)
687                 return;
688
689         ptype = btr.btr_packet_type;
690         width = printf("\tptype: [0x%04x]", ptype);
691         if (ptype & HCI_PKT_DM1)                tag("DM1");
692         if (ptype & HCI_PKT_DH1)                tag("DH1");
693         if (ptype & HCI_PKT_DM3)                tag("DM3");
694         if (ptype & HCI_PKT_DH3)                tag("DH3");
695         if (ptype & HCI_PKT_DM5)                tag("DM5");
696         if (ptype & HCI_PKT_DH5)                tag("DH5");
697         if ((ptype & HCI_PKT_2MBPS_DH1) == 0)   tag("2-DH1");
698         if ((ptype & HCI_PKT_3MBPS_DH1) == 0)   tag("3-DH1");
699         if ((ptype & HCI_PKT_2MBPS_DH3) == 0)   tag("2-DH3");
700         if ((ptype & HCI_PKT_3MBPS_DH3) == 0)   tag("3-DH3");
701         if ((ptype & HCI_PKT_2MBPS_DH5) == 0)   tag("2-DH5");
702         if ((ptype & HCI_PKT_3MBPS_DH5) == 0)   tag("3-DH5");
703         tag(NULL);
704
705         load_value(HCI_CMD_READ_PAGE_TIMEOUT, &val16, sizeof(val16));
706         printf("\tpage timeout: %d ms\n", val16 * 5 / 8);
707
708         if (level-- < 1)
709                 return;
710
711         load_value(HCI_CMD_READ_LOCAL_FEATURES, buf, HCI_FEATURES_SIZE);
712         print_features("\tfeatures:", buf);
713 }
714
715 void
716 print_stats(void)
717 {
718         if (sflag == 0)
719                 return;
720
721         if (sflag == 1) {
722                 if (ioctl(hci, SIOCGBTSTATS, &btr) < 0)
723                         err(EXIT_FAILURE, "SIOCGBTSTATS");
724         } else  {
725                 if (ioctl(hci, SIOCZBTSTATS, &btr) < 0)
726                         err(EXIT_FAILURE, "SIOCZBTSTATS");
727         }
728
729         printf( "\tTotal bytes sent %d, received %d\n"
730                 "\tCommands sent %d, Events received %d\n"
731                 "\tACL data packets sent %d, received %d\n"
732                 "\tSCO data packets sent %d, received %d\n"
733                 "\tInput errors %d, Output errors %d\n",
734                 btr.btr_stats.byte_tx, btr.btr_stats.byte_rx,
735                 btr.btr_stats.cmd_tx, btr.btr_stats.evt_rx,
736                 btr.btr_stats.acl_tx, btr.btr_stats.acl_rx,
737                 btr.btr_stats.sco_tx, btr.btr_stats.sco_rx,
738                 btr.btr_stats.err_rx, btr.btr_stats.err_tx);
739 }
740
741 void
742 print_features(const char *str, uint8_t *f)
743 {
744         width = printf("%s", str);
745
746         /* ------------------- byte 0 --------------------*/
747         if (*f & HCI_LMP_3SLOT)             tag("<3 slot>");
748         if (*f & HCI_LMP_5SLOT)             tag("<5 slot>");
749         if (*f & HCI_LMP_ENCRYPTION)        tag("<encryption>");
750         if (*f & HCI_LMP_SLOT_OFFSET)       tag("<slot offset>");
751         if (*f & HCI_LMP_TIMIACCURACY)      tag("<timing accuracy>");
752         if (*f & HCI_LMP_ROLE_SWITCH)       tag("<role switch>");
753         if (*f & HCI_LMP_HOLD_MODE)         tag("<hold mode>");
754         if (*f & HCI_LMP_SNIFF_MODE)        tag("<sniff mode>");
755         f++;
756
757         /* ------------------- byte 1 --------------------*/
758         if (*f & HCI_LMP_PARK_MODE)         tag("<park mode>");
759         if (*f & HCI_LMP_RSSI)              tag("<RSSI>");
760         if (*f & HCI_LMP_CHANNEL_QUALITY)   tag("<channel quality>");
761         if (*f & HCI_LMP_SCO_LINK)          tag("<SCO link>");
762         if (*f & HCI_LMP_HV2_PKT)           tag("<HV2>");
763         if (*f & HCI_LMP_HV3_PKT)           tag("<HV3>");
764         if (*f & HCI_LMP_ULAW_LOG)          tag("<u-Law log>");
765         if (*f & HCI_LMP_ALAW_LOG)          tag("<A-Law log>");
766         f++;
767
768         /* ------------------- byte 1 --------------------*/
769         if (*f & HCI_LMP_CVSD)              tag("<CVSD data>");
770         if (*f & HCI_LMP_PAGISCHEME)        tag("<paging parameter>");
771         if (*f & HCI_LMP_POWER_CONTROL)     tag("<power control>");
772         if (*f & HCI_LMP_TRANSPARENT_SCO)   tag("<transparent SCO>");
773         if (*f & HCI_LMP_FLOW_CONTROL_LAG0) tag("<flow control lag 0>");
774         if (*f & HCI_LMP_FLOW_CONTROL_LAG1) tag("<flow control lag 1>");
775         if (*f & HCI_LMP_FLOW_CONTROL_LAG2) tag("<flow control lag 2>");
776         if (*f & HCI_LMP_BC_ENCRYPTION)     tag("<broadcast encryption>");
777         f++;
778
779         /* ------------------- byte 3 --------------------*/
780         if (*f & HCI_LMP_EDR_ACL_2MBPS)     tag("<EDR ACL 2Mbps>");
781         if (*f & HCI_LMP_EDR_ACL_3MBPS)     tag("<EDR ACL 3Mbps>");
782         if (*f & HCI_LMP_ENHANCED_ISCAN)    tag("<enhanced inquiry scan>");
783         if (*f & HCI_LMP_INTERLACED_ISCAN)  tag("<interlaced inquiry scan>");
784         if (*f & HCI_LMP_INTERLACED_PSCAN)  tag("<interlaced page scan>");
785         if (*f & HCI_LMP_RSSI_INQUIRY)      tag("<RSSI with inquiry result>");
786         if (*f & HCI_LMP_EV3_PKT)           tag("<EV3 packets>");
787         f++;
788
789         /* ------------------- byte 4 --------------------*/
790         if (*f & HCI_LMP_EV4_PKT)           tag("<EV4 packets>");
791         if (*f & HCI_LMP_EV5_PKT)           tag("<EV5 packets>");
792         if (*f & HCI_LMP_AFH_CAPABLE_SLAVE) tag("<AFH capable slave>");
793         if (*f & HCI_LMP_AFH_CLASS_SLAVE)   tag("<AFH class slave>");
794         if (*f & HCI_LMP_3SLOT_EDR_ACL)     tag("<3 slot EDR ACL>");
795         f++;
796
797         /* ------------------- byte 5 --------------------*/
798         if (*f & HCI_LMP_5SLOT_EDR_ACL)     tag("<5 slot EDR ACL>");
799         if (*f & HCI_LMP_AFH_CAPABLE_MASTER)tag("<AFH capable master>");
800         if (*f & HCI_LMP_AFH_CLASS_MASTER)  tag("<AFH class master>");
801         if (*f & HCI_LMP_EDR_eSCO_2MBPS)    tag("<EDR eSCO 2Mbps>");
802         if (*f & HCI_LMP_EDR_eSCO_3MBPS)    tag("<EDR eSCO 3Mbps>");
803         if (*f & HCI_LMP_3SLOT_EDR_eSCO)    tag("<3 slot EDR eSCO>");
804         f++;
805
806         /* ------------------- byte 6 --------------------*/
807         f++;
808
809         /* ------------------- byte 7 --------------------*/
810         if (*f & HCI_LMP_EXTENDED_FEATURES) tag("<extended features>");
811
812         tag(NULL);
813 }
814
815 void
816 print_class(const char *str)
817 {
818         int major, minor;
819
820         major = (class & 0x1f00) >> 8;
821         minor = (class & 0x00fc) >> 2;
822
823         width = printf("%sclass: [0x%6.6x]", str, class);
824
825         switch (major) {
826         case 1: /* Computer */
827                 switch (minor) {
828                 case 1: tag("Desktop");                         break;
829                 case 2: tag("Server");                          break;
830                 case 3: tag("Laptop");                          break;
831                 case 4: tag("Handheld");                        break;
832                 case 5: tag("Palm Sized");                      break;
833                 case 6: tag("Wearable");                        break;
834                 }
835                 tag("Computer");
836                 break;
837
838         case 2: /* Phone */
839                 switch (minor) {
840                 case 1: tag("Cellular Phone");                  break;
841                 case 2: tag("Cordless Phone");                  break;
842                 case 3: tag("Smart Phone");                     break;
843                 case 4: tag("Wired Modem/Phone Gateway");       break;
844                 case 5: tag("Common ISDN");                     break;
845                 default:tag("Phone");                           break;
846                 }
847                 break;
848
849         case 3: /* LAN */
850                 tag("LAN");
851                 switch ((minor & 0x38) >> 3) {
852                 case 0: tag("[Fully available]");               break;
853                 case 1: tag("[1-17% utilised]");                break;
854                 case 2: tag("[17-33% utilised]");               break;
855                 case 3: tag("[33-50% utilised]");               break;
856                 case 4: tag("[50-67% utilised]");               break;
857                 case 5: tag("[67-83% utilised]");               break;
858                 case 6: tag("[83-99% utilised]");               break;
859                 case 7: tag("[No service available]");          break;
860                 }
861                 break;
862
863         case 4: /* Audio/Visual */
864                 switch (minor) {
865                 case 1: tag("Wearable Headset");                break;
866                 case 2: tag("Hands-free Audio");                break;
867                 case 4: tag("Microphone");                      break;
868                 case 5: tag("Loudspeaker");                     break;
869                 case 6: tag("Headphones");                      break;
870                 case 7: tag("Portable Audio");                  break;
871                 case 8: tag("Car Audio");                       break;
872                 case 9: tag("Set-top Box");                     break;
873                 case 10: tag("HiFi Audio");                     break;
874                 case 11: tag("VCR");                            break;
875                 case 12: tag("Video Camera");                   break;
876                 case 13: tag("Camcorder");                      break;
877                 case 14: tag("Video Monitor");                  break;
878                 case 15: tag("Video Display and Loudspeaker");  break;
879                 case 16: tag("Video Conferencing");             break;
880                 case 18: tag("A/V [Gaming/Toy]");               break;
881                 default: tag("Audio/Visual");                   break;
882                 }
883                 break;
884
885         case 5: /* Peripheral */
886                 switch (minor & 0x0f) {
887                 case 1: tag("Joystick");                        break;
888                 case 2: tag("Gamepad");                         break;
889                 case 3: tag("Remote Control");                  break;
890                 case 4: tag("Sensing Device");                  break;
891                 case 5: tag("Digitiser Tablet");                break;
892                 case 6: tag("Card Reader");                     break;
893                 default: tag("Peripheral");                     break;
894                 }
895
896                 if (minor & 0x10) tag("Keyboard");
897                 if (minor & 0x20) tag("Mouse");
898                 break;
899
900         case 6: /* Imaging */
901                 if (minor & 0x20) tag("Printer");
902                 if (minor & 0x10) tag("Scanner");
903                 if (minor & 0x08) tag("Camera");
904                 if (minor & 0x04) tag("Display");
905                 if ((minor & 0x3c) == 0) tag("Imaging");
906                 break;
907
908         case 7: /* Wearable */
909                 switch (minor) {
910                 case 1: tag("Wrist Watch");                     break;
911                 case 2: tag("Pager");                           break;
912                 case 3: tag("Jacket");                          break;
913                 case 4: tag("Helmet");                          break;
914                 case 5: tag("Glasses");                         break;
915                 default: tag("Wearable");                       break;
916                 }
917                 break;
918
919         case 8: /* Toy */
920                 switch (minor) {
921                 case 1: tag("Robot");                           break;
922                 case 2: tag("Vehicle");                         break;
923                 case 3: tag("Doll / Action Figure");            break;
924                 case 4: tag("Controller");                      break;
925                 case 5: tag("Game");                            break;
926                 default: tag("Toy");                            break;
927                 }
928                 break;
929
930         default:
931                 break;
932         }
933
934         if (class & 0x002000)   tag("<Limited Discoverable>");
935         if (class & 0x010000)   tag("<Positioning>");
936         if (class & 0x020000)   tag("<Networking>");
937         if (class & 0x040000)   tag("<Rendering>");
938         if (class & 0x080000)   tag("<Capturing>");
939         if (class & 0x100000)   tag("<Object Transfer>");
940         if (class & 0x200000)   tag("<Audio>");
941         if (class & 0x400000)   tag("<Telephony>");
942         if (class & 0x800000)   tag("<Information>");
943         tag(NULL);
944 }
945
946 void
947 print_voice(int level)
948 {
949         printf("\tvoice: [0x%4.4x]\n", voice);
950
951         if (level == 0)
952                 return;
953
954         printf("\t\tInput Coding: ");
955         switch ((voice & 0x0300) >> 8) {
956         case 0x00:      printf("Linear PCM [%d-bit, pos %d]",
957                         (voice & 0x0020 ? 16 : 8),
958                         (voice & 0x001c) >> 2);         break;
959         case 0x01:      printf("u-Law");                break;
960         case 0x02:      printf("A-Law");                break;
961         case 0x03:      printf("unknown");              break;
962         }
963
964         switch ((voice & 0x00c0) >> 6) {
965         case 0x00:      printf(", 1's complement");     break;
966         case 0x01:      printf(", 2's complement");     break;
967         case 0x02:      printf(", sign magnitude");     break;
968         case 0x03:      printf(", unsigned");           break;
969         }
970
971         printf("\n\t\tAir Coding: ");
972         switch (voice & 0x0003) {
973         case 0x00:      printf("CVSD");                 break;
974         case 0x01:      printf("u-Law");                break;
975         case 0x02:      printf("A-Law");                break;
976         case 0x03:      printf("Transparent");          break;
977         }
978
979         printf("\n");
980 }
981
982 void
983 print_result(int num, struct result *r, int rssi)
984 {
985         hci_remote_name_req_cp ncp;
986         hci_remote_name_req_compl_ep nep;
987 #if 0
988         hci_read_remote_features_cp fcp;
989         hci_read_remote_features_compl_ep fep;
990 #endif
991         struct hostent *hp;
992
993         printf("%3d: bdaddr %s",
994                         num,
995                         bt_ntoa(&r->bdaddr, NULL));
996
997         hp = bt_gethostbyaddr((const char *)&r->bdaddr, sizeof(bdaddr_t), AF_BLUETOOTH);
998
999 #if 0
1000         if (hp != NULL)
1001                 printf(" (%s)", hp->h_name);
1002 #endif
1003         printf("\n");
1004
1005         memset(&ncp, 0, sizeof(ncp));
1006         bdaddr_copy(&ncp.bdaddr, &r->bdaddr);
1007         ncp.page_scan_rep_mode = r->page_scan_rep_mode;
1008         ncp.clock_offset = r->clock_offset;
1009
1010         hci_req(HCI_CMD_REMOTE_NAME_REQ,
1011                 HCI_EVENT_REMOTE_NAME_REQ_COMPL,
1012                 &ncp, sizeof(ncp),
1013                 &nep, sizeof(nep));
1014
1015         printf("   : name \"%s\"\n", nep.name);
1016
1017         class = (r->uclass[2] << 16) | (r->uclass[1] << 8) | (r->uclass[0]);
1018         print_class("   : ");
1019
1020 #if 0
1021         hci_req(HCI_CMD_READ_REMOTE_FEATURES,
1022                 HCI_EVENT_READ_REMOTE_FEATURES_COMPL,
1023                 &fcp, sizeof(fcp),
1024                 &fep, sizeof(fep));
1025
1026         print_features("   : features", fep.features);
1027 #endif
1028
1029         printf("   : page scan rep mode 0x%02x\n", r->page_scan_rep_mode);
1030         printf("   : clock offset %d\n", le16toh(r->clock_offset));
1031
1032         if (rssi)
1033                 printf("   : rssi %d\n", r->rssi);
1034
1035         printf("\n");
1036 }
1037
1038 void
1039 do_inquiry(void)
1040 {
1041         uint8_t buf[HCI_EVENT_PKT_SIZE];
1042         struct result result[INQUIRY_MAX_RESPONSES];
1043         hci_inquiry_cp inq;
1044         struct hci_filter f;
1045         hci_event_hdr_t *hh;
1046         int i, j, num, rssi;
1047
1048         if (opt_inquiry == 0)
1049                 return;
1050
1051         printf("Device Discovery from device: %s ...", btr.btr_name);
1052         fflush(stdout);
1053
1054         memset(&f, 0, sizeof(f));
1055         hci_filter_set(HCI_EVENT_COMMAND_STATUS, &f);
1056         hci_filter_set(HCI_EVENT_COMMAND_COMPL, &f);
1057         hci_filter_set(HCI_EVENT_INQUIRY_RESULT, &f);
1058         hci_filter_set(HCI_EVENT_RSSI_RESULT, &f);
1059         hci_filter_set(HCI_EVENT_INQUIRY_COMPL, &f);
1060         hci_filter_set(HCI_EVENT_REMOTE_NAME_REQ_COMPL, &f);
1061         hci_filter_set(HCI_EVENT_READ_REMOTE_FEATURES_COMPL, &f);
1062         if (setsockopt(hci, BTPROTO_HCI, SO_HCI_EVT_FILTER, &f, sizeof(f)) < 0)
1063                 err(EXIT_FAILURE, "Can't set event filter");
1064
1065         /* General Inquiry LAP is 0x9e8b33 */
1066         inq.lap[0] = 0x33;
1067         inq.lap[1] = 0x8b;
1068         inq.lap[2] = 0x9e;
1069         inq.inquiry_length = INQUIRY_LENGTH;
1070         inq.num_responses = INQUIRY_MAX_RESPONSES;
1071
1072         hci_cmd(HCI_CMD_INQUIRY, &inq, sizeof(inq));
1073
1074         num = 0;
1075         rssi = 0;
1076         hh = (hci_event_hdr_t *)buf;
1077
1078         for (;;) {
1079                 if (recv(hci, buf, sizeof(buf), 0) <= 0)
1080                         err(EXIT_FAILURE, "recv");
1081
1082                 if (hh->event == HCI_EVENT_INQUIRY_COMPL)
1083                         break;
1084
1085                 if (hh->event == HCI_EVENT_INQUIRY_RESULT) {
1086                         hci_inquiry_result_ep *ep = (hci_inquiry_result_ep *)(hh + 1);
1087                         hci_inquiry_response *ir = (hci_inquiry_response *)(ep + 1);
1088
1089                         for (i = 0 ; i < ep->num_responses ; i++) {
1090                                 if (num == INQUIRY_MAX_RESPONSES)
1091                                         break;
1092
1093                                 /* some devices keep responding, ignore dupes */
1094                                 for (j = 0 ; j < num ; j++)
1095                                         if (bdaddr_same(&result[j].bdaddr, &ir[i].bdaddr))
1096                                                 break;
1097
1098                                 if (j < num)
1099                                         continue;
1100
1101                                 bdaddr_copy(&result[num].bdaddr, &ir[i].bdaddr);
1102                                 memcpy(&result[num].uclass, &ir[i].uclass, HCI_CLASS_SIZE);
1103                                 result[num].page_scan_rep_mode = ir[i].page_scan_rep_mode;
1104                                 result[num].clock_offset = ir[i].clock_offset;
1105                                 result[num].rssi = 0;
1106                                 num++;
1107                                 printf(".");
1108                                 fflush(stdout);
1109                         }
1110                         continue;
1111                 }
1112 #if 0
1113                 if (hh->event == HCI_EVENT_RSSI_RESULT) {
1114                         hci_rssi_result_ep *ep = (hci_rssi_result_ep *)(hh + 1);
1115                         hci_rssi_response *rr = (hci_rssi_response *)(ep + 1);
1116
1117                         for (i = 0 ; i < ep->num_responses ; i++) {
1118                                 if (num == INQUIRY_MAX_RESPONSES)
1119                                         break;
1120
1121                                 /* some devices keep responding, ignore dupes */
1122                                 for (j = 0 ; j < num ; j++)
1123                                         if (bdaddr_same(&result[j].bdaddr, &rr[i].bdaddr))
1124                                                 break;
1125
1126                                 if (j < num)
1127                                         continue;
1128
1129                                 bdaddr_copy(&result[num].bdaddr, &rr[i].bdaddr);
1130                                 memcpy(&result[num].uclass, &rr[i].uclass, HCI_CLASS_SIZE);
1131                                 result[num].page_scan_rep_mode = rr[i].page_scan_rep_mode;
1132                                 result[num].clock_offset = rr[i].clock_offset;
1133                                 result[num].rssi = rr[i].rssi;
1134                                 rssi = 1;
1135                                 num++;
1136                                 printf(".");
1137                                 fflush(stdout);
1138                         }
1139                         continue;
1140                 }
1141 #endif
1142         }
1143
1144         printf(" %d response%s\n", num, (num == 1 ? "" : "s"));
1145
1146         for (i = 0 ; i < num ; i++)
1147                 print_result(i + 1, &result[i], rssi);
1148 }
1149
1150 /*
1151  * Print a value a la the %b format of the kernel's printf borrowed
1152  * from ifconfig(8).
1153  */
1154 void
1155 printb(uint16_t v, const char *bits)
1156 {
1157         int i, any = 0;
1158         char c;
1159
1160         if (bits) {
1161                 putchar('<');
1162                 while ((i = *bits++) != '\0') {
1163                         if (v & (1 << (i-1))) {
1164                                 if (any)
1165                                         putchar(',');
1166                                 any = 1;
1167                                 for (; (c = *bits) > 32; bits++)
1168                                         putchar(c);
1169                         } else
1170                                 for (; *bits > 32; bits++)
1171                                         ;
1172                 }
1173                 putchar('>');
1174         }
1175 }
1176