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