2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
30 * $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $
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>
41 #include <sys/socketvar.h>
45 #define L2CAP_SOCKET_CHECKED
46 #include <bluetooth.h>
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>
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);
70 static char * bdaddrpr (bdaddr_p const ba, char *str, int len);
72 static kvm_t * kopen (char const *memf);
73 static int kread (kvm_t *kvmd, u_long addr, char *buffer, int size);
75 static void usage (void);
81 static struct nlist nl[] = {
83 { "_ng_btsocket_hci_raw_sockets" },
85 { "_ng_btsocket_l2cap_raw_sockets" },
87 { "_ng_btsocket_l2cap_sockets" },
88 #define N_L2CAP_RAW_RT 3
89 { "_ng_btsocket_l2cap_raw_rt" },
91 { "_ng_btsocket_l2cap_rt" },
93 { "_ng_btsocket_rfcomm_sockets" },
95 { "_ng_btsocket_rfcomm_sessions" },
99 #define state2str(x) \
100 (((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
106 static int numeric_bdaddr = 0;
109 main(int argc, char *argv[])
111 int opt, proto = -1, route = 0;
115 while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
126 if (strcasecmp(optarg, "hci_raw") == 0)
128 else if (strcasecmp(optarg, "l2cap_raw") == 0)
130 else if (strcasecmp(optarg, "l2cap") == 0)
132 else if (strcasecmp(optarg, "rfcomm") == 0)
134 else if (strcasecmp(optarg, "rfcomm_s") == 0)
152 if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
157 * Discard setgid privileges if not the running kernel so that
158 * bad guys can't print interesting stuff from kernel memory.
161 if (setgid(getgid()) != 0)
170 hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
175 l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
177 l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
182 l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
184 l2cappr(kvmd, nl[N_L2CAP].n_value);
188 rfcommpr(kvmd, nl[N_RFCOMM].n_value);
192 rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
197 l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
198 l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
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);
209 return (kvm_close(kvmd));
213 * Print raw HCI sockets
217 hcirawpr(kvm_t *kvmd, u_long addr)
219 ng_btsocket_hci_raw_pcb_p this = NULL, next = NULL;
220 ng_btsocket_hci_raw_pcb_t pcb;
227 if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
230 for ( ; this != NULL; this = next) {
231 if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
233 if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
236 next = LIST_NEXT(&pcb, next);
241 "Active raw HCI sockets\n" \
242 "%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
251 if (pcb.addr.hci_node[0] == 0) {
252 pcb.addr.hci_node[0] = '*';
253 pcb.addr.hci_node[1] = 0;
257 "%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n",
258 (unsigned long) pcb.so,
259 (unsigned long) this,
268 * Print raw L2CAP sockets
272 l2caprawpr(kvm_t *kvmd, u_long addr)
274 ng_btsocket_l2cap_raw_pcb_p this = NULL, next = NULL;
275 ng_btsocket_l2cap_raw_pcb_t pcb;
282 if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
285 for ( ; this != NULL; this = next) {
286 if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
288 if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
291 next = LIST_NEXT(&pcb, next);
296 "Active raw L2CAP sockets\n" \
297 "%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
306 "%-8lx %-8lx %6d %6d %-17.17s\n",
307 (unsigned long) pcb.so,
308 (unsigned long) this,
311 bdaddrpr(&pcb.src, NULL, 0));
316 * Print L2CAP sockets
320 l2cappr(kvm_t *kvmd, u_long addr)
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"
330 ng_btsocket_l2cap_pcb_p this = NULL, next = NULL;
331 ng_btsocket_l2cap_pcb_t pcb;
334 char local[24], remote[24];
339 if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
342 for ( ; this != NULL; this = next) {
343 if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
345 if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
348 next = LIST_NEXT(&pcb, next);
353 "Active L2CAP sockets\n" \
354 "%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
365 "%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
366 (unsigned long) this,
369 bdaddrpr(&pcb.src, local, sizeof(local)),
371 bdaddrpr(&pcb.dst, remote, sizeof(remote)),
373 (so.so_options & SO_ACCEPTCONN)?
374 "LISTEN" : state2str(pcb.state));
379 * Print L2CAP routing table
383 l2caprtpr(kvm_t *kvmd, u_long addr)
385 ng_btsocket_l2cap_rtentry_p this = NULL, next = NULL;
386 ng_btsocket_l2cap_rtentry_t rt;
392 if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
395 for ( ; this != NULL; this = next) {
396 if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
399 next = LIST_NEXT(&rt, next);
404 "Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)? "raw " : "");
406 "%-8.8s %-8.8s %-17.17s\n", "RTentry",
412 "%-8lx %-8lx %-17.17s\n",
413 (unsigned long) this,
414 (unsigned long) rt.hook,
415 bdaddrpr(&rt.src, NULL, 0));
420 * Print RFCOMM sockets
424 rfcommpr(kvm_t *kvmd, u_long addr)
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"
435 ng_btsocket_rfcomm_pcb_p this = NULL, next = NULL;
436 ng_btsocket_rfcomm_pcb_t pcb;
439 char local[24], remote[24];
444 if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
447 for ( ; this != NULL; this = next) {
448 if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
450 if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
453 next = LIST_NEXT(&pcb, next);
458 "Active RFCOMM sockets\n" \
459 "%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
471 "%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
472 (unsigned long) this,
475 bdaddrpr(&pcb.src, local, sizeof(local)),
476 bdaddrpr(&pcb.dst, remote, sizeof(remote)),
479 (so.so_options & SO_ACCEPTCONN)?
480 "LISTEN" : state2str(pcb.state));
485 * Print RFCOMM sessions
489 rfcommpr_s(kvm_t *kvmd, u_long addr)
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"
500 ng_btsocket_rfcomm_session_p this = NULL, next = NULL;
501 ng_btsocket_rfcomm_session_t s;
508 if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
511 for ( ; this != NULL; this = next) {
512 if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
514 if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
517 next = LIST_NEXT(&s, next);
522 "Active RFCOMM sessions\n" \
523 "%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
534 "%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
535 (unsigned long) so.so_pcb,
536 (unsigned long) this,
540 LIST_EMPTY(&s.dlcs)? "No" : "Yes",
546 * Return BD_ADDR as string
550 bdaddrpr(bdaddr_p const ba, char *str, int len)
552 static char buffer[MAXHOSTNAMELEN];
553 struct hostent *he = NULL;
557 len = sizeof(buffer);
560 if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
567 if (!numeric_bdaddr &&
568 (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
569 strlcpy(str, he->h_name, len);
584 kopen(char const *memf)
587 char errbuf[_POSIX2_LINE_MAX];
589 kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
590 if (setgid(getgid()) != 0)
593 warnx("kvm_openfiles: %s", errbuf);
597 if (kvm_nlist(kvmd, nl) < 0) {
598 warnx("kvm_nlist: %s", kvm_geterr(kvmd));
602 if (nl[0].n_type == 0) {
603 warnx("kvm_nlist: no namelist");
619 kread(kvm_t *kvmd, u_long addr, char *buffer, int size)
621 if (kvmd == NULL || buffer == NULL)
624 if (kvm_read(kvmd, addr, buffer, size) != size) {
625 warnx("kvm_read: %s", kvm_geterr(kvmd));
633 * Print usage and exit
639 fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n");