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