/usr.bin/bluetooth/btsockstat/btsockstat.c
https://bitbucket.org/freebsd/freebsd-head/ · C · 645 lines · 460 code · 108 blank · 77 comment · 102 complexity · 64d36a36cd2cbf843c4f1a206fbe8799 MD5 · raw file
- /*
- * 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 */