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