summaryrefslogtreecommitdiffstats
path: root/usr.bin/bluetooth/btsockstat/btsockstat.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/bluetooth/btsockstat/btsockstat.c')
-rw-r--r--usr.bin/bluetooth/btsockstat/btsockstat.c645
1 files changed, 645 insertions, 0 deletions
diff --git a/usr.bin/bluetooth/btsockstat/btsockstat.c b/usr.bin/bluetooth/btsockstat/btsockstat.c
new file mode 100644
index 0000000..f63ee1f
--- /dev/null
+++ b/usr.bin/bluetooth/btsockstat/btsockstat.c
@@ -0,0 +1,645 @@
+/*
+ * btsockstat.c
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/callout.h>
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <bluetooth.h>
+#include <err.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+
+#include <netgraph/bluetooth/include/ng_bluetooth.h>
+#include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
+#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
+#include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void hcirawpr (kvm_t *kvmd, u_long addr);
+static void l2caprawpr (kvm_t *kvmd, u_long addr);
+static void l2cappr (kvm_t *kvmd, u_long addr);
+static void l2caprtpr (kvm_t *kvmd, u_long addr);
+static void rfcommpr (kvm_t *kvmd, u_long addr);
+static void rfcommpr_s (kvm_t *kvmd, u_long addr);
+
+static char * bdaddrpr (bdaddr_p const ba, char *str, int len);
+
+static kvm_t * kopen (char const *memf);
+static int kread (kvm_t *kvmd, u_long addr, char *buffer, int size);
+
+static void usage (void);
+
+/*
+ * List of symbols
+ */
+
+static struct nlist nl[] = {
+#define N_HCI_RAW 0
+ { "_ng_btsocket_hci_raw_sockets" },
+#define N_L2CAP_RAW 1
+ { "_ng_btsocket_l2cap_raw_sockets" },
+#define N_L2CAP 2
+ { "_ng_btsocket_l2cap_sockets" },
+#define N_L2CAP_RAW_RT 3
+ { "_ng_btsocket_l2cap_raw_rt" },
+#define N_L2CAP_RT 4
+ { "_ng_btsocket_l2cap_rt" },
+#define N_RFCOMM 5
+ { "_ng_btsocket_rfcomm_sockets" },
+#define N_RFCOMM_S 6
+ { "_ng_btsocket_rfcomm_sessions" },
+ { "" },
+};
+
+#define state2str(x) \
+ (((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
+
+/*
+ * Main
+ */
+
+static int numeric_bdaddr = 0;
+
+int
+main(int argc, char *argv[])
+{
+ int opt, proto = -1, route = 0;
+ kvm_t *kvmd = NULL;
+ char *memf = NULL;
+
+ while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
+ switch (opt) {
+ case 'n':
+ numeric_bdaddr = 1;
+ break;
+
+ case 'M':
+ memf = optarg;
+ break;
+
+ case 'p':
+ if (strcasecmp(optarg, "hci_raw") == 0)
+ proto = N_HCI_RAW;
+ else if (strcasecmp(optarg, "l2cap_raw") == 0)
+ proto = N_L2CAP_RAW;
+ else if (strcasecmp(optarg, "l2cap") == 0)
+ proto = N_L2CAP;
+ else if (strcasecmp(optarg, "rfcomm") == 0)
+ proto = N_RFCOMM;
+ else if (strcasecmp(optarg, "rfcomm_s") == 0)
+ proto = N_RFCOMM_S;
+ else
+ usage();
+ /* NOT REACHED */
+ break;
+
+ case 'r':
+ route = 1;
+ break;
+
+ case 'h':
+ default:
+ usage();
+ /* NOT REACHED */
+ }
+ }
+
+ if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
+ usage();
+ /* NOT REACHED */
+
+ /*
+ * Discard setgid privileges if not the running kernel so that
+ * bad guys can't print interesting stuff from kernel memory.
+ */
+
+ if (memf != NULL)
+ setgid(getgid());
+
+ kvmd = kopen(memf);
+ if (kvmd == NULL)
+ return (1);
+
+ switch (proto) {
+ case N_HCI_RAW:
+ hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
+ break;
+
+ case N_L2CAP_RAW:
+ if (route)
+ l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
+ else
+ l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
+ break;
+
+ case N_L2CAP:
+ if (route)
+ l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
+ else
+ l2cappr(kvmd, nl[N_L2CAP].n_value);
+ break;
+
+ case N_RFCOMM:
+ rfcommpr(kvmd, nl[N_RFCOMM].n_value);
+ break;
+
+ case N_RFCOMM_S:
+ rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
+ break;
+
+ default:
+ if (route) {
+ l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
+ l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
+ } else {
+ hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
+ l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
+ l2cappr(kvmd, nl[N_L2CAP].n_value);
+ rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
+ rfcommpr(kvmd, nl[N_RFCOMM].n_value);
+ }
+ break;
+ }
+
+ return (kvm_close(kvmd));
+} /* main */
+
+/*
+ * Print raw HCI sockets
+ */
+
+static void
+hcirawpr(kvm_t *kvmd, u_long addr)
+{
+ ng_btsocket_hci_raw_pcb_p this = NULL, next = NULL;
+ ng_btsocket_hci_raw_pcb_t pcb;
+ struct socket so;
+ int first = 1;
+
+ if (addr == 0)
+ return;
+
+ if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+ return;
+
+ for ( ; this != NULL; this = next) {
+ if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
+ return;
+ if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
+ return;
+
+ next = LIST_NEXT(&pcb, next);
+
+ if (first) {
+ first = 0;
+ fprintf(stdout,
+"Active raw HCI sockets\n" \
+"%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
+ "Socket",
+ "PCB",
+ "Flags",
+ "Recv-Q",
+ "Send-Q",
+ "Local address");
+ }
+
+ if (pcb.addr.hci_node[0] == 0) {
+ pcb.addr.hci_node[0] = '*';
+ pcb.addr.hci_node[1] = 0;
+ }
+
+ fprintf(stdout,
+"%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n",
+ (unsigned long) pcb.so,
+ (unsigned long) this,
+ pcb.flags,
+ so.so_rcv.sb_cc,
+ so.so_snd.sb_cc,
+ pcb.addr.hci_node);
+ }
+} /* hcirawpr */
+
+/*
+ * Print raw L2CAP sockets
+ */
+
+static void
+l2caprawpr(kvm_t *kvmd, u_long addr)
+{
+ ng_btsocket_l2cap_raw_pcb_p this = NULL, next = NULL;
+ ng_btsocket_l2cap_raw_pcb_t pcb;
+ struct socket so;
+ int first = 1;
+
+ if (addr == 0)
+ return;
+
+ if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+ return;
+
+ for ( ; this != NULL; this = next) {
+ if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
+ return;
+ if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
+ return;
+
+ next = LIST_NEXT(&pcb, next);
+
+ if (first) {
+ first = 0;
+ fprintf(stdout,
+"Active raw L2CAP sockets\n" \
+"%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
+ "Socket",
+ "PCB",
+ "Recv-Q",
+ "Send-Q",
+ "Local address");
+ }
+
+ fprintf(stdout,
+"%-8lx %-8lx %6d %6d %-17.17s\n",
+ (unsigned long) pcb.so,
+ (unsigned long) this,
+ so.so_rcv.sb_cc,
+ so.so_snd.sb_cc,
+ bdaddrpr(&pcb.src, NULL, 0));
+ }
+} /* l2caprawpr */
+
+/*
+ * Print L2CAP sockets
+ */
+
+static void
+l2cappr(kvm_t *kvmd, u_long addr)
+{
+ static char const * const states[] = {
+ /* NG_BTSOCKET_L2CAP_CLOSED */ "CLOSED",
+ /* NG_BTSOCKET_L2CAP_CONNECTING */ "CON",
+ /* NG_BTSOCKET_L2CAP_CONFIGURING */ "CONFIG",
+ /* NG_BTSOCKET_L2CAP_OPEN */ "OPEN",
+ /* NG_BTSOCKET_L2CAP_DISCONNECTING */ "DISCON"
+ };
+
+ ng_btsocket_l2cap_pcb_p this = NULL, next = NULL;
+ ng_btsocket_l2cap_pcb_t pcb;
+ struct socket so;
+ int first = 1;
+ char local[24], remote[24];
+
+ if (addr == 0)
+ return;
+
+ if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+ return;
+
+ for ( ; this != NULL; this = next) {
+ if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
+ return;
+ if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
+ return;
+
+ next = LIST_NEXT(&pcb, next);
+
+ if (first) {
+ first = 0;
+ fprintf(stdout,
+"Active L2CAP sockets\n" \
+"%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
+ "PCB",
+ "Recv-Q",
+ "Send-Q",
+ "Local address/PSM",
+ "Foreign address",
+ "CID",
+ "State");
+ }
+
+ fprintf(stdout,
+"%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
+ (unsigned long) this,
+ so.so_rcv.sb_cc,
+ so.so_snd.sb_cc,
+ bdaddrpr(&pcb.src, local, sizeof(local)),
+ pcb.psm,
+ bdaddrpr(&pcb.dst, remote, sizeof(remote)),
+ pcb.cid,
+ (so.so_options & SO_ACCEPTCONN)?
+ "LISTEN" : state2str(pcb.state));
+ }
+} /* l2cappr */
+
+/*
+ * Print L2CAP routing table
+ */
+
+static void
+l2caprtpr(kvm_t *kvmd, u_long addr)
+{
+ ng_btsocket_l2cap_rtentry_p this = NULL, next = NULL;
+ ng_btsocket_l2cap_rtentry_t rt;
+ int first = 1;
+
+ if (addr == 0)
+ return;
+
+ if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+ return;
+
+ for ( ; this != NULL; this = next) {
+ if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
+ return;
+
+ next = LIST_NEXT(&rt, next);
+
+ if (first) {
+ first = 0;
+ fprintf(stdout,
+"Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)? "raw " : "");
+ fprintf(stdout,
+"%-8.8s %-8.8s %-17.17s\n", "RTentry",
+ "Hook",
+ "BD_ADDR");
+ }
+
+ fprintf(stdout,
+"%-8lx %-8lx %-17.17s\n",
+ (unsigned long) this,
+ (unsigned long) rt.hook,
+ bdaddrpr(&rt.src, NULL, 0));
+ }
+} /* l2caprtpr */
+
+/*
+ * Print RFCOMM sockets
+ */
+
+static void
+rfcommpr(kvm_t *kvmd, u_long addr)
+{
+ static char const * const states[] = {
+ /* NG_BTSOCKET_RFCOMM_DLC_CLOSED */ "CLOSED",
+ /* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */ "W4CON",
+ /* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */ "CONFIG",
+ /* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */ "CONN",
+ /* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */ "OPEN",
+ /* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
+ };
+
+ ng_btsocket_rfcomm_pcb_p this = NULL, next = NULL;
+ ng_btsocket_rfcomm_pcb_t pcb;
+ struct socket so;
+ int first = 1;
+ char local[24], remote[24];
+
+ if (addr == 0)
+ return;
+
+ if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+ return;
+
+ for ( ; this != NULL; this = next) {
+ if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
+ return;
+ if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
+ return;
+
+ next = LIST_NEXT(&pcb, next);
+
+ if (first) {
+ first = 0;
+ fprintf(stdout,
+"Active RFCOMM sockets\n" \
+"%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
+ "PCB",
+ "Recv-Q",
+ "Send-Q",
+ "Local address",
+ "Foreign address",
+ "Chan",
+ "DLCI",
+ "State");
+ }
+
+ fprintf(stdout,
+"%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
+ (unsigned long) this,
+ so.so_rcv.sb_cc,
+ so.so_snd.sb_cc,
+ bdaddrpr(&pcb.src, local, sizeof(local)),
+ bdaddrpr(&pcb.dst, remote, sizeof(remote)),
+ pcb.channel,
+ pcb.dlci,
+ (so.so_options & SO_ACCEPTCONN)?
+ "LISTEN" : state2str(pcb.state));
+ }
+} /* rfcommpr */
+
+/*
+ * Print RFCOMM sessions
+ */
+
+static void
+rfcommpr_s(kvm_t *kvmd, u_long addr)
+{
+ static char const * const states[] = {
+ /* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */ "CLOSED",
+ /* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */ "LISTEN",
+ /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */ "CONNECTING",
+ /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */ "CONNECTED",
+ /* NG_BTSOCKET_RFCOMM_SESSION_OPEN */ "OPEN",
+ /* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
+ };
+
+ ng_btsocket_rfcomm_session_p this = NULL, next = NULL;
+ ng_btsocket_rfcomm_session_t s;
+ struct socket so;
+ int first = 1;
+
+ if (addr == 0)
+ return;
+
+ if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
+ return;
+
+ for ( ; this != NULL; this = next) {
+ if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
+ return;
+ if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
+ return;
+
+ next = LIST_NEXT(&s, next);
+
+ if (first) {
+ first = 0;
+ fprintf(stdout,
+"Active RFCOMM sessions\n" \
+"%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
+ "L2PCB",
+ "PCB",
+ "Flags",
+ "MTU",
+ "Out-Q",
+ "DLCs",
+ "State");
+ }
+
+ fprintf(stdout,
+"%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
+ (unsigned long) so.so_pcb,
+ (unsigned long) this,
+ s.flags,
+ s.mtu,
+ s.outq.len,
+ LIST_EMPTY(&s.dlcs)? "No" : "Yes",
+ state2str(s.state));
+ }
+} /* rfcommpr_s */
+
+/*
+ * Return BD_ADDR as string
+ */
+
+static char *
+bdaddrpr(bdaddr_p const ba, char *str, int len)
+{
+ static char buffer[MAXHOSTNAMELEN];
+ struct hostent *he = NULL;
+
+ if (str == NULL) {
+ str = buffer;
+ len = sizeof(buffer);
+ }
+
+ if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
+ str[0] = '*';
+ str[1] = 0;
+
+ return (str);
+ }
+
+ if (!numeric_bdaddr &&
+ (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
+ strlcpy(str, he->h_name, len);
+
+ return (str);
+ }
+
+ bt_ntoa(ba, str);
+
+ return (str);
+} /* bdaddrpr */
+
+/*
+ * Open kvm
+ */
+
+static kvm_t *
+kopen(char const *memf)
+{
+ kvm_t *kvmd = NULL;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ /*
+ * Discard setgid privileges if not the running kernel so that
+ * bad guys can't print interesting stuff from kernel memory.
+ */
+
+ if (memf != NULL)
+ setgid(getgid());
+
+ kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
+ if (kvmd == NULL) {
+ warnx("kvm_openfiles: %s", errbuf);
+ return (NULL);
+ }
+
+ if (kvm_nlist(kvmd, nl) < 0) {
+ warnx("kvm_nlist: %s", kvm_geterr(kvmd));
+ goto fail;
+ }
+
+ if (nl[0].n_type == 0) {
+ warnx("kvm_nlist: no namelist");
+ goto fail;
+ }
+
+ return (kvmd);
+fail:
+ kvm_close(kvmd);
+
+ return (NULL);
+} /* kopen */
+
+/*
+ * Read kvm
+ */
+
+static int
+kread(kvm_t *kvmd, u_long addr, char *buffer, int size)
+{
+ if (kvmd == NULL || buffer == NULL)
+ return (-1);
+
+ if (kvm_read(kvmd, addr, buffer, size) != size) {
+ warnx("kvm_read: %s", kvm_geterr(kvmd));
+ return (-1);
+ }
+
+ return (0);
+} /* kread */
+
+/*
+ * Print usage and exit
+ */
+
+static void
+usage(void)
+{
+ fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n");
+ exit(255);
+} /* usage */
+
OpenPOWER on IntegriCloud