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