]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/bluetooth/btsockstat/btsockstat.c
Upgrade to OpenSSH 7.7p1.
[FreeBSD/FreeBSD.git] / usr.bin / bluetooth / btsockstat / btsockstat.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * btsockstat.c
5  *
6  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7  * All rights reserved.
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  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $
31  * $FreeBSD$
32  */
33
34 #include <sys/types.h>
35 #include <sys/callout.h>
36 #include <sys/param.h>
37 #include <sys/protosw.h>
38 #include <sys/queue.h>
39 #include <sys/socket.h>
40 #define _WANT_SOCKET
41 #include <sys/socketvar.h>
42
43 #include <net/if.h>
44
45 #define L2CAP_SOCKET_CHECKED
46 #include <bluetooth.h>
47 #include <err.h>
48 #include <fcntl.h>
49 #include <kvm.h>
50 #include <limits.h>
51 #include <nlist.h>
52
53 #include <netgraph/bluetooth/include/ng_bluetooth.h>
54 #include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
55 #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
56 #include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
57
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62
63 static void     hcirawpr   (kvm_t *kvmd, u_long addr);
64 static void     l2caprawpr (kvm_t *kvmd, u_long addr);
65 static void     l2cappr    (kvm_t *kvmd, u_long addr);
66 static void     l2caprtpr  (kvm_t *kvmd, u_long addr);
67 static void     rfcommpr   (kvm_t *kvmd, u_long addr);
68 static void     rfcommpr_s (kvm_t *kvmd, u_long addr);
69
70 static char *   bdaddrpr   (bdaddr_p const ba, char *str, int len);
71
72 static kvm_t *  kopen      (char const *memf);
73 static int      kread      (kvm_t *kvmd, u_long addr, char *buffer, int size);
74
75 static void     usage      (void);
76
77 /*
78  * List of symbols
79  */
80
81 static struct nlist     nl[] = {
82 #define N_HCI_RAW       0
83         { "_ng_btsocket_hci_raw_sockets" },
84 #define N_L2CAP_RAW     1
85         { "_ng_btsocket_l2cap_raw_sockets" },
86 #define N_L2CAP         2
87         { "_ng_btsocket_l2cap_sockets" },
88 #define N_L2CAP_RAW_RT  3
89         { "_ng_btsocket_l2cap_raw_rt" },
90 #define N_L2CAP_RT      4
91         { "_ng_btsocket_l2cap_rt" },
92 #define N_RFCOMM        5
93         { "_ng_btsocket_rfcomm_sockets" },
94 #define N_RFCOMM_S      6
95         { "_ng_btsocket_rfcomm_sessions" },
96         { "" },
97 };
98
99 #define state2str(x) \
100         (((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
101
102 /*
103  * Main
104  */
105
106 static int      numeric_bdaddr = 0;
107
108 int
109 main(int argc, char *argv[])
110 {
111         int      opt, proto = -1, route = 0;
112         kvm_t   *kvmd = NULL;
113         char    *memf = NULL;
114
115         while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
116                 switch (opt) {
117                 case 'n':
118                         numeric_bdaddr = 1;
119                         break;
120
121                 case 'M':
122                         memf = optarg;
123                         break;
124
125                 case 'p':
126                         if (strcasecmp(optarg, "hci_raw") == 0)
127                                 proto = N_HCI_RAW;
128                         else if (strcasecmp(optarg, "l2cap_raw") == 0)
129                                 proto = N_L2CAP_RAW;
130                         else if (strcasecmp(optarg, "l2cap") == 0)
131                                 proto = N_L2CAP;
132                         else if (strcasecmp(optarg, "rfcomm") == 0)
133                                 proto = N_RFCOMM;
134                         else if (strcasecmp(optarg, "rfcomm_s") == 0)
135                                 proto = N_RFCOMM_S; 
136                         else
137                                 usage();
138                                 /* NOT REACHED */
139                         break;
140
141                 case 'r':
142                         route = 1;
143                         break;
144
145                 case 'h':
146                 default:
147                         usage();
148                         /* NOT REACHED */
149                 }
150         }
151
152         if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
153                 usage();
154                 /* NOT REACHED */
155
156         /*
157          * Discard setgid privileges if not the running kernel so that
158          * bad guys can't print interesting stuff from kernel memory.
159          */
160         if (memf != NULL)
161                 if (setgid(getgid()) != 0)
162                         err(1, "setgid");
163
164         kvmd = kopen(memf);
165         if (kvmd == NULL)
166                 return (1);
167
168         switch (proto) {
169         case N_HCI_RAW:
170                 hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
171                 break;
172
173         case N_L2CAP_RAW:
174                 if (route)
175                         l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
176                 else
177                         l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
178                 break;
179
180         case N_L2CAP:
181                 if (route) 
182                         l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
183                 else
184                         l2cappr(kvmd, nl[N_L2CAP].n_value);
185                 break;
186
187         case N_RFCOMM:
188                 rfcommpr(kvmd, nl[N_RFCOMM].n_value);
189                 break;
190
191         case N_RFCOMM_S:
192                 rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
193                 break;
194
195         default:
196                 if (route) {
197                         l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
198                         l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
199                 } else {
200                         hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
201                         l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
202                         l2cappr(kvmd, nl[N_L2CAP].n_value);
203                         rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
204                         rfcommpr(kvmd, nl[N_RFCOMM].n_value);
205                 }
206                 break;
207         }
208
209         return (kvm_close(kvmd));
210 } /* main */
211
212 /*
213  * Print raw HCI sockets
214  */
215
216 static void
217 hcirawpr(kvm_t *kvmd, u_long addr)
218 {
219         ng_btsocket_hci_raw_pcb_p       this = NULL, next = NULL;
220         ng_btsocket_hci_raw_pcb_t       pcb;
221         struct socket                   so;
222         int                             first = 1;
223
224         if (addr == 0)
225                 return;
226
227         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
228                 return;
229
230         for ( ; this != NULL; this = next) {
231                 if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
232                         return;
233                 if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
234                         return;
235
236                 next = LIST_NEXT(&pcb, next);
237
238                 if (first) {
239                         first = 0;
240                         fprintf(stdout,
241 "Active raw HCI sockets\n" \
242 "%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
243                                 "Socket",
244                                 "PCB",
245                                 "Flags",
246                                 "Recv-Q",
247                                 "Send-Q",
248                                 "Local address");
249                 }
250
251                 if (pcb.addr.hci_node[0] == 0) {
252                         pcb.addr.hci_node[0] = '*';
253                         pcb.addr.hci_node[1] = 0;
254                 }
255
256                 fprintf(stdout,
257 "%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n",
258                         (unsigned long) pcb.so,
259                         (unsigned long) this,
260                         pcb.flags,
261                         so.so_rcv.sb_ccc,
262                         so.so_snd.sb_ccc,
263                         pcb.addr.hci_node);
264         }
265 } /* hcirawpr */
266
267 /*
268  * Print raw L2CAP sockets
269  */
270
271 static void
272 l2caprawpr(kvm_t *kvmd, u_long addr)
273 {
274         ng_btsocket_l2cap_raw_pcb_p     this = NULL, next = NULL;
275         ng_btsocket_l2cap_raw_pcb_t     pcb;
276         struct socket                   so;
277         int                             first = 1;
278
279         if (addr == 0)
280                 return;
281
282         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
283                 return;
284
285         for ( ; this != NULL; this = next) {
286                 if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
287                         return;
288                 if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
289                         return;
290
291                 next = LIST_NEXT(&pcb, next);
292
293                 if (first) {
294                         first = 0;
295                         fprintf(stdout, 
296 "Active raw L2CAP sockets\n" \
297 "%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
298                                 "Socket",
299                                 "PCB",
300                                 "Recv-Q",
301                                 "Send-Q",
302                                 "Local address");
303                 }
304
305                 fprintf(stdout,
306 "%-8lx %-8lx %6d %6d %-17.17s\n",
307                         (unsigned long) pcb.so,
308                         (unsigned long) this,
309                         so.so_rcv.sb_ccc,
310                         so.so_snd.sb_ccc,
311                         bdaddrpr(&pcb.src, NULL, 0));
312         }
313 } /* l2caprawpr */
314
315 /*
316  * Print L2CAP sockets
317  */
318
319 static void
320 l2cappr(kvm_t *kvmd, u_long addr)
321 {
322         static char const * const       states[] = {
323         /* NG_BTSOCKET_L2CAP_CLOSED */          "CLOSED",
324         /* NG_BTSOCKET_L2CAP_CONNECTING */      "CON",
325         /* NG_BTSOCKET_L2CAP_CONFIGURING */     "CONFIG",
326         /* NG_BTSOCKET_L2CAP_OPEN */            "OPEN",
327         /* NG_BTSOCKET_L2CAP_DISCONNECTING */   "DISCON"
328         };
329
330         ng_btsocket_l2cap_pcb_p this = NULL, next = NULL;
331         ng_btsocket_l2cap_pcb_t pcb;
332         struct socket           so;
333         int                     first = 1;
334         char                    local[24], remote[24];
335
336         if (addr == 0)
337                 return;
338
339         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
340                 return;
341
342         for ( ; this != NULL; this = next) {
343                 if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
344                         return;
345                 if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
346                         return;
347
348                 next = LIST_NEXT(&pcb, next);
349
350                 if (first) {
351                         first = 0;
352                         fprintf(stdout,
353 "Active L2CAP sockets\n" \
354 "%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
355                                 "PCB",
356                                 "Recv-Q",
357                                 "Send-Q",
358                                 "Local address/PSM",
359                                 "Foreign address",
360                                 "CID",
361                                 "State");
362                 }
363
364                 fprintf(stdout,
365 "%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
366                         (unsigned long) this,
367                         so.so_rcv.sb_ccc,
368                         so.so_snd.sb_ccc,
369                         bdaddrpr(&pcb.src, local, sizeof(local)),
370                         pcb.psm,
371                         bdaddrpr(&pcb.dst, remote, sizeof(remote)),
372                         pcb.cid,
373                         (so.so_options & SO_ACCEPTCONN)?
374                                 "LISTEN" : state2str(pcb.state));
375         }
376 } /* l2cappr */
377
378 /*
379  * Print L2CAP routing table
380  */
381
382 static void
383 l2caprtpr(kvm_t *kvmd, u_long addr)
384 {
385         ng_btsocket_l2cap_rtentry_p     this = NULL, next = NULL;
386         ng_btsocket_l2cap_rtentry_t     rt;
387         int                             first = 1;
388
389         if (addr == 0)
390                 return;
391
392         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
393                 return;
394
395         for ( ; this != NULL; this = next) {
396                 if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
397                         return;
398
399                 next = LIST_NEXT(&rt, next);
400
401                 if (first) {
402                         first = 0;
403                         fprintf(stdout,
404 "Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)?  "raw " : "");
405                         fprintf(stdout,
406 "%-8.8s %-8.8s %-17.17s\n",     "RTentry",
407                                 "Hook",
408                                 "BD_ADDR");
409                 }
410
411                 fprintf(stdout,
412 "%-8lx %-8lx %-17.17s\n",
413                         (unsigned long) this,
414                         (unsigned long) rt.hook,
415                         bdaddrpr(&rt.src, NULL, 0));
416         }
417 } /* l2caprtpr */
418
419 /*
420  * Print RFCOMM sockets
421  */
422
423 static void
424 rfcommpr(kvm_t *kvmd, u_long addr)
425 {
426         static char const * const       states[] = {
427         /* NG_BTSOCKET_RFCOMM_DLC_CLOSED */        "CLOSED",
428         /* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */    "W4CON",
429         /* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */   "CONFIG",
430         /* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */    "CONN",
431         /* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */     "OPEN",
432         /* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
433         };
434
435         ng_btsocket_rfcomm_pcb_p        this = NULL, next = NULL;
436         ng_btsocket_rfcomm_pcb_t        pcb;
437         struct socket                   so;
438         int                             first = 1;
439         char                            local[24], remote[24];
440
441         if (addr == 0)
442                 return;
443
444         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
445                 return;
446
447         for ( ; this != NULL; this = next) {
448                 if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
449                         return;
450                 if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
451                         return;
452
453                 next = LIST_NEXT(&pcb, next);
454
455                 if (first) {
456                         first = 0;
457                         fprintf(stdout,
458 "Active RFCOMM sockets\n" \
459 "%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
460                                 "PCB",
461                                 "Recv-Q",
462                                 "Send-Q",
463                                 "Local address",
464                                 "Foreign address",
465                                 "Chan",
466                                 "DLCI",
467                                 "State");
468                 }
469
470                 fprintf(stdout,
471 "%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
472                         (unsigned long) this,
473                         so.so_rcv.sb_ccc,
474                         so.so_snd.sb_ccc,
475                         bdaddrpr(&pcb.src, local, sizeof(local)),
476                         bdaddrpr(&pcb.dst, remote, sizeof(remote)),
477                         pcb.channel,
478                         pcb.dlci,
479                         (so.so_options & SO_ACCEPTCONN)?
480                                 "LISTEN" : state2str(pcb.state));
481         }
482 } /* rfcommpr */
483
484 /*
485  * Print RFCOMM sessions
486  */
487
488 static void
489 rfcommpr_s(kvm_t *kvmd, u_long addr)
490 {
491         static char const * const       states[] = {
492         /* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */        "CLOSED",
493         /* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */     "LISTEN",
494         /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */    "CONNECTING",
495         /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */     "CONNECTED",
496         /* NG_BTSOCKET_RFCOMM_SESSION_OPEN */          "OPEN",
497         /* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
498         };
499
500         ng_btsocket_rfcomm_session_p    this = NULL, next = NULL;
501         ng_btsocket_rfcomm_session_t    s;
502         struct socket                   so;
503         int                             first = 1;
504
505         if (addr == 0)
506                 return;
507
508         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
509                 return;
510
511         for ( ; this != NULL; this = next) {
512                 if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
513                         return;
514                 if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
515                         return;
516
517                 next = LIST_NEXT(&s, next);
518
519                 if (first) {
520                         first = 0;
521                         fprintf(stdout,
522 "Active RFCOMM sessions\n" \
523 "%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
524                                 "L2PCB",
525                                 "PCB",
526                                 "Flags",
527                                 "MTU",
528                                 "Out-Q",
529                                 "DLCs",
530                                 "State");
531                 }
532
533                 fprintf(stdout,
534 "%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
535                         (unsigned long) so.so_pcb,
536                         (unsigned long) this,
537                         s.flags,
538                         s.mtu,
539                         s.outq.len,
540                         LIST_EMPTY(&s.dlcs)? "No" : "Yes",
541                         state2str(s.state));
542         }
543 } /* rfcommpr_s */
544
545 /*
546  * Return BD_ADDR as string
547  */
548
549 static char *
550 bdaddrpr(bdaddr_p const ba, char *str, int len)
551 {
552         static char      buffer[MAXHOSTNAMELEN];
553         struct hostent  *he = NULL;
554
555         if (str == NULL) {
556                 str = buffer;
557                 len = sizeof(buffer);
558         }
559
560         if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
561                 str[0] = '*';
562                 str[1] = 0;
563
564                 return (str);
565         }
566
567         if (!numeric_bdaddr &&
568             (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
569                 strlcpy(str, he->h_name, len);
570
571                 return (str);
572         }
573
574         bt_ntoa(ba, str);
575
576         return (str);
577 } /* bdaddrpr */
578
579 /*
580  * Open kvm
581  */
582
583 static kvm_t *
584 kopen(char const *memf)
585 {
586         kvm_t   *kvmd = NULL;
587         char     errbuf[_POSIX2_LINE_MAX];
588
589         kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
590         if (setgid(getgid()) != 0)
591                 err(1, "setgid");
592         if (kvmd == NULL) {
593                 warnx("kvm_openfiles: %s", errbuf);
594                 return (NULL);
595         }
596
597         if (kvm_nlist(kvmd, nl) < 0) {
598                 warnx("kvm_nlist: %s", kvm_geterr(kvmd));
599                 goto fail;
600         }
601
602         if (nl[0].n_type == 0) {
603                 warnx("kvm_nlist: no namelist");
604                 goto fail;
605         }
606
607         return (kvmd);
608 fail:
609         kvm_close(kvmd);
610
611         return (NULL);
612 } /* kopen */
613
614 /*
615  * Read kvm
616  */
617
618 static int
619 kread(kvm_t *kvmd, u_long addr, char *buffer, int size)
620 {
621         if (kvmd == NULL || buffer == NULL)
622                 return (-1);
623
624         if (kvm_read(kvmd, addr, buffer, size) != size) {
625                 warnx("kvm_read: %s", kvm_geterr(kvmd));
626                 return (-1);
627         }
628
629         return (0);
630 } /* kread */
631
632 /*
633  * Print usage and exit
634  */
635
636 static void
637 usage(void)
638 {
639         fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n");
640         exit(255);
641 } /* usage */
642