btsockstat.c revision 281210
1107120Sjulian/*
2107120Sjulian * btsockstat.c
3107120Sjulian *
4107120Sjulian * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5107120Sjulian * All rights reserved.
6107120Sjulian *
7107120Sjulian * Redistribution and use in source and binary forms, with or without
8107120Sjulian * modification, are permitted provided that the following conditions
9107120Sjulian * are met:
10107120Sjulian * 1. Redistributions of source code must retain the above copyright
11107120Sjulian *    notice, this list of conditions and the following disclaimer.
12107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright
13107120Sjulian *    notice, this list of conditions and the following disclaimer in the
14107120Sjulian *    documentation and/or other materials provided with the distribution.
15107120Sjulian *
16107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26107120Sjulian * SUCH DAMAGE.
27107120Sjulian *
28121054Semax * $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $
29107120Sjulian * $FreeBSD: head/usr.bin/bluetooth/btsockstat/btsockstat.c 281210 2015-04-07 16:48:23Z takawata $
30107120Sjulian */
31107120Sjulian
32107120Sjulian#include <sys/types.h>
33107120Sjulian#include <sys/callout.h>
34107120Sjulian#include <sys/param.h>
35180964Semax#include <sys/protosw.h>
36107120Sjulian#include <sys/queue.h>
37107120Sjulian#include <sys/socket.h>
38107120Sjulian#include <sys/socketvar.h>
39107120Sjulian
40107120Sjulian#include <net/if.h>
41107120Sjulian
42281210Stakawata#define L2CAP_SOCKET_CHECKED
43121054Semax#include <bluetooth.h>
44107120Sjulian#include <err.h>
45107120Sjulian#include <fcntl.h>
46107120Sjulian#include <kvm.h>
47107120Sjulian#include <limits.h>
48121064Sbde#include <nlist.h>
49107120Sjulian
50121054Semax#include <netgraph/bluetooth/include/ng_bluetooth.h>
51121054Semax#include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
52121054Semax#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
53121054Semax#include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
54107120Sjulian
55107120Sjulian#include <stdio.h>
56107120Sjulian#include <stdlib.h>
57107120Sjulian#include <string.h>
58107120Sjulian#include <unistd.h>
59107120Sjulian
60107120Sjulianstatic void	hcirawpr   (kvm_t *kvmd, u_long addr);
61107120Sjulianstatic void	l2caprawpr (kvm_t *kvmd, u_long addr);
62107120Sjulianstatic void	l2cappr    (kvm_t *kvmd, u_long addr);
63107120Sjulianstatic void	l2caprtpr  (kvm_t *kvmd, u_long addr);
64114878Sjulianstatic void	rfcommpr   (kvm_t *kvmd, u_long addr);
65114878Sjulianstatic void	rfcommpr_s (kvm_t *kvmd, u_long addr);
66107120Sjulian
67121054Semaxstatic char *	bdaddrpr   (bdaddr_p const ba, char *str, int len);
68121054Semax
69107120Sjulianstatic kvm_t *	kopen      (char const *memf);
70107120Sjulianstatic int	kread      (kvm_t *kvmd, u_long addr, char *buffer, int size);
71107120Sjulian
72107120Sjulianstatic void	usage      (void);
73107120Sjulian
74107120Sjulian/*
75107120Sjulian * List of symbols
76107120Sjulian */
77107120Sjulian
78107120Sjulianstatic struct nlist	nl[] = {
79107120Sjulian#define N_HCI_RAW	0
80107120Sjulian	{ "_ng_btsocket_hci_raw_sockets" },
81107120Sjulian#define N_L2CAP_RAW	1
82107120Sjulian	{ "_ng_btsocket_l2cap_raw_sockets" },
83107120Sjulian#define N_L2CAP		2
84107120Sjulian	{ "_ng_btsocket_l2cap_sockets" },
85107120Sjulian#define N_L2CAP_RAW_RT	3
86107120Sjulian	{ "_ng_btsocket_l2cap_raw_rt" },
87107120Sjulian#define N_L2CAP_RT	4
88107120Sjulian	{ "_ng_btsocket_l2cap_rt" },
89114878Sjulian#define N_RFCOMM	5
90114878Sjulian	{ "_ng_btsocket_rfcomm_sockets" },
91114878Sjulian#define N_RFCOMM_S	6
92114878Sjulian	{ "_ng_btsocket_rfcomm_sessions" },
93107120Sjulian	{ "" },
94107120Sjulian};
95107120Sjulian
96114878Sjulian#define state2str(x) \
97114878Sjulian	(((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
98114878Sjulian
99107120Sjulian/*
100107120Sjulian * Main
101107120Sjulian */
102107120Sjulian
103121054Semaxstatic int	numeric_bdaddr = 0;
104121054Semax
105107120Sjulianint
106107120Sjulianmain(int argc, char *argv[])
107107120Sjulian{
108107120Sjulian	int	 opt, proto = -1, route = 0;
109107120Sjulian	kvm_t	*kvmd = NULL;
110107120Sjulian	char	*memf = NULL;
111107120Sjulian
112121054Semax	while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
113107120Sjulian		switch (opt) {
114121054Semax		case 'n':
115121054Semax			numeric_bdaddr = 1;
116121054Semax			break;
117121054Semax
118107120Sjulian		case 'M':
119107120Sjulian			memf = optarg;
120107120Sjulian			break;
121107120Sjulian
122107120Sjulian		case 'p':
123107120Sjulian			if (strcasecmp(optarg, "hci_raw") == 0)
124107120Sjulian				proto = N_HCI_RAW;
125107120Sjulian			else if (strcasecmp(optarg, "l2cap_raw") == 0)
126107120Sjulian				proto = N_L2CAP_RAW;
127107120Sjulian			else if (strcasecmp(optarg, "l2cap") == 0)
128107120Sjulian				proto = N_L2CAP;
129114878Sjulian			else if (strcasecmp(optarg, "rfcomm") == 0)
130114878Sjulian				proto = N_RFCOMM;
131114878Sjulian			else if (strcasecmp(optarg, "rfcomm_s") == 0)
132114878Sjulian				proto = N_RFCOMM_S;
133107120Sjulian			else
134107120Sjulian				usage();
135107120Sjulian				/* NOT REACHED */
136107120Sjulian			break;
137107120Sjulian
138107120Sjulian		case 'r':
139107120Sjulian			route = 1;
140107120Sjulian			break;
141107120Sjulian
142107120Sjulian		case 'h':
143107120Sjulian		default:
144107120Sjulian			usage();
145107120Sjulian			/* NOT REACHED */
146107120Sjulian		}
147107120Sjulian	}
148107120Sjulian
149114878Sjulian	if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
150107120Sjulian		usage();
151107120Sjulian		/* NOT REACHED */
152107120Sjulian
153114878Sjulian	/*
154114878Sjulian	 * Discard setgid privileges if not the running kernel so that
155114878Sjulian	 * bad guys can't print interesting stuff from kernel memory.
156114878Sjulian	 */
157114878Sjulian
158114878Sjulian	if (memf != NULL)
159114878Sjulian		setgid(getgid());
160114878Sjulian
161107120Sjulian	kvmd = kopen(memf);
162107120Sjulian	if (kvmd == NULL)
163107120Sjulian		return (1);
164107120Sjulian
165107120Sjulian	switch (proto) {
166107120Sjulian	case N_HCI_RAW:
167107120Sjulian		hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
168107120Sjulian		break;
169107120Sjulian
170107120Sjulian	case N_L2CAP_RAW:
171107120Sjulian		if (route)
172107120Sjulian			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
173107120Sjulian		else
174107120Sjulian			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
175107120Sjulian		break;
176107120Sjulian
177107120Sjulian	case N_L2CAP:
178107120Sjulian		if (route)
179107120Sjulian			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
180107120Sjulian		else
181107120Sjulian			l2cappr(kvmd, nl[N_L2CAP].n_value);
182107120Sjulian		break;
183107120Sjulian
184114878Sjulian	case N_RFCOMM:
185114878Sjulian		rfcommpr(kvmd, nl[N_RFCOMM].n_value);
186114878Sjulian		break;
187114878Sjulian
188114878Sjulian	case N_RFCOMM_S:
189114878Sjulian		rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
190114878Sjulian		break;
191114878Sjulian
192107120Sjulian	default:
193107120Sjulian		if (route) {
194107120Sjulian			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
195107120Sjulian			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
196107120Sjulian		} else {
197107120Sjulian			hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
198107120Sjulian			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
199107120Sjulian			l2cappr(kvmd, nl[N_L2CAP].n_value);
200114878Sjulian			rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
201114878Sjulian			rfcommpr(kvmd, nl[N_RFCOMM].n_value);
202107120Sjulian		}
203107120Sjulian		break;
204107120Sjulian	}
205107120Sjulian
206107120Sjulian	return (kvm_close(kvmd));
207107120Sjulian} /* main */
208107120Sjulian
209107120Sjulian/*
210107120Sjulian * Print raw HCI sockets
211107120Sjulian */
212107120Sjulian
213107120Sjulianstatic void
214107120Sjulianhcirawpr(kvm_t *kvmd, u_long addr)
215107120Sjulian{
216107120Sjulian	ng_btsocket_hci_raw_pcb_p	this = NULL, next = NULL;
217107120Sjulian	ng_btsocket_hci_raw_pcb_t	pcb;
218107120Sjulian	struct socket			so;
219107120Sjulian	int				first = 1;
220107120Sjulian
221107120Sjulian	if (addr == 0)
222107120Sjulian		return;
223107120Sjulian
224107120Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
225107120Sjulian		return;
226107120Sjulian
227107120Sjulian	for ( ; this != NULL; this = next) {
228107120Sjulian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
229107120Sjulian			return;
230107120Sjulian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
231107120Sjulian			return;
232107120Sjulian
233107120Sjulian		next = LIST_NEXT(&pcb, next);
234107120Sjulian
235107120Sjulian		if (first) {
236107120Sjulian			first = 0;
237107120Sjulian			fprintf(stdout,
238107120Sjulian"Active raw HCI sockets\n" \
239107120Sjulian"%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
240107120Sjulian				"Socket",
241107120Sjulian				"PCB",
242107120Sjulian				"Flags",
243107120Sjulian				"Recv-Q",
244107120Sjulian				"Send-Q",
245107120Sjulian				"Local address");
246107120Sjulian		}
247107120Sjulian
248107120Sjulian		if (pcb.addr.hci_node[0] == 0) {
249107120Sjulian			pcb.addr.hci_node[0] = '*';
250107120Sjulian			pcb.addr.hci_node[1] = 0;
251107120Sjulian		}
252107120Sjulian
253107120Sjulian		fprintf(stdout,
254128076Semax"%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n",
255128076Semax			(unsigned long) pcb.so,
256128076Semax			(unsigned long) this,
257107120Sjulian			pcb.flags,
258275326Sglebius			so.so_rcv.sb_ccc,
259275326Sglebius			so.so_snd.sb_ccc,
260107120Sjulian			pcb.addr.hci_node);
261107120Sjulian	}
262107120Sjulian} /* hcirawpr */
263107120Sjulian
264107120Sjulian/*
265107120Sjulian * Print raw L2CAP sockets
266107120Sjulian */
267107120Sjulian
268107120Sjulianstatic void
269107120Sjulianl2caprawpr(kvm_t *kvmd, u_long addr)
270107120Sjulian{
271107120Sjulian	ng_btsocket_l2cap_raw_pcb_p	this = NULL, next = NULL;
272107120Sjulian	ng_btsocket_l2cap_raw_pcb_t	pcb;
273107120Sjulian	struct socket			so;
274107120Sjulian	int				first = 1;
275107120Sjulian
276107120Sjulian	if (addr == 0)
277107120Sjulian		return;
278107120Sjulian
279107120Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
280107120Sjulian		return;
281107120Sjulian
282107120Sjulian	for ( ; this != NULL; this = next) {
283107120Sjulian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
284107120Sjulian			return;
285107120Sjulian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
286107120Sjulian			return;
287107120Sjulian
288107120Sjulian		next = LIST_NEXT(&pcb, next);
289107120Sjulian
290107120Sjulian		if (first) {
291107120Sjulian			first = 0;
292107120Sjulian			fprintf(stdout,
293107120Sjulian"Active raw L2CAP sockets\n" \
294114878Sjulian"%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
295107120Sjulian				"Socket",
296107120Sjulian				"PCB",
297107120Sjulian				"Recv-Q",
298107120Sjulian				"Send-Q",
299107120Sjulian				"Local address");
300107120Sjulian		}
301107120Sjulian
302107120Sjulian		fprintf(stdout,
303128076Semax"%-8lx %-8lx %6d %6d %-17.17s\n",
304128076Semax			(unsigned long) pcb.so,
305128076Semax			(unsigned long) this,
306275326Sglebius			so.so_rcv.sb_ccc,
307275326Sglebius			so.so_snd.sb_ccc,
308121054Semax			bdaddrpr(&pcb.src, NULL, 0));
309107120Sjulian	}
310107120Sjulian} /* l2caprawpr */
311107120Sjulian
312107120Sjulian/*
313107120Sjulian * Print L2CAP sockets
314107120Sjulian */
315107120Sjulian
316107120Sjulianstatic void
317107120Sjulianl2cappr(kvm_t *kvmd, u_long addr)
318107120Sjulian{
319107120Sjulian	static char const * const	states[] = {
320107120Sjulian	/* NG_BTSOCKET_L2CAP_CLOSED */		"CLOSED",
321107120Sjulian	/* NG_BTSOCKET_L2CAP_CONNECTING */	"CON",
322107120Sjulian	/* NG_BTSOCKET_L2CAP_CONFIGURING */	"CONFIG",
323107120Sjulian	/* NG_BTSOCKET_L2CAP_OPEN */		"OPEN",
324107120Sjulian	/* NG_BTSOCKET_L2CAP_DISCONNECTING */	"DISCON"
325107120Sjulian	};
326107120Sjulian
327107120Sjulian	ng_btsocket_l2cap_pcb_p	this = NULL, next = NULL;
328107120Sjulian	ng_btsocket_l2cap_pcb_t	pcb;
329107120Sjulian	struct socket		so;
330107120Sjulian	int			first = 1;
331121054Semax	char			local[24], remote[24];
332107120Sjulian
333107120Sjulian	if (addr == 0)
334107120Sjulian		return;
335107120Sjulian
336107120Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
337107120Sjulian		return;
338107120Sjulian
339107120Sjulian	for ( ; this != NULL; this = next) {
340107120Sjulian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
341107120Sjulian			return;
342107120Sjulian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
343107120Sjulian			return;
344107120Sjulian
345107120Sjulian		next = LIST_NEXT(&pcb, next);
346107120Sjulian
347107120Sjulian		if (first) {
348107120Sjulian			first = 0;
349107120Sjulian			fprintf(stdout,
350107120Sjulian"Active L2CAP sockets\n" \
351114878Sjulian"%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
352107120Sjulian				"PCB",
353107120Sjulian				"Recv-Q",
354107120Sjulian				"Send-Q",
355107120Sjulian				"Local address/PSM",
356107120Sjulian				"Foreign address",
357107120Sjulian				"CID",
358107120Sjulian				"State");
359107120Sjulian		}
360107120Sjulian
361107120Sjulian		fprintf(stdout,
362128076Semax"%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
363128076Semax			(unsigned long) this,
364275326Sglebius			so.so_rcv.sb_ccc,
365275326Sglebius			so.so_snd.sb_ccc,
366121054Semax			bdaddrpr(&pcb.src, local, sizeof(local)),
367121054Semax			pcb.psm,
368121054Semax			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
369107120Sjulian			pcb.cid,
370107120Sjulian			(so.so_options & SO_ACCEPTCONN)?
371107120Sjulian				"LISTEN" : state2str(pcb.state));
372107120Sjulian	}
373107120Sjulian} /* l2cappr */
374107120Sjulian
375107120Sjulian/*
376107120Sjulian * Print L2CAP routing table
377107120Sjulian */
378107120Sjulian
379107120Sjulianstatic void
380107120Sjulianl2caprtpr(kvm_t *kvmd, u_long addr)
381107120Sjulian{
382107120Sjulian	ng_btsocket_l2cap_rtentry_p	this = NULL, next = NULL;
383107120Sjulian	ng_btsocket_l2cap_rtentry_t	rt;
384107120Sjulian	int				first = 1;
385107120Sjulian
386107120Sjulian	if (addr == 0)
387107120Sjulian		return;
388107120Sjulian
389107120Sjulian	if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
390107120Sjulian		return;
391107120Sjulian
392107120Sjulian	for ( ; this != NULL; this = next) {
393107120Sjulian		if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
394107120Sjulian			return;
395107120Sjulian
396107120Sjulian		next = LIST_NEXT(&rt, next);
397107120Sjulian
398107120Sjulian		if (first) {
399107120Sjulian			first = 0;
400107120Sjulian			fprintf(stdout,
401107120Sjulian"Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)?  "raw " : "");
402107120Sjulian			fprintf(stdout,
403114878Sjulian"%-8.8s %-8.8s %-17.17s\n",	"RTentry",
404107120Sjulian				"Hook",
405107120Sjulian				"BD_ADDR");
406107120Sjulian		}
407107120Sjulian
408107120Sjulian		fprintf(stdout,
409128076Semax"%-8lx %-8lx %-17.17s\n",
410128076Semax			(unsigned long) this,
411128076Semax			(unsigned long) rt.hook,
412121054Semax			bdaddrpr(&rt.src, NULL, 0));
413107120Sjulian	}
414107120Sjulian} /* l2caprtpr */
415107120Sjulian
416107120Sjulian/*
417114878Sjulian * Print RFCOMM sockets
418114878Sjulian */
419114878Sjulian
420114878Sjulianstatic void
421114878Sjulianrfcommpr(kvm_t *kvmd, u_long addr)
422114878Sjulian{
423114878Sjulian	static char const * const	states[] = {
424114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_CLOSED */	   "CLOSED",
425114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */	   "W4CON",
426114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */   "CONFIG",
427114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */    "CONN",
428114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */     "OPEN",
429114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
430114878Sjulian	};
431114878Sjulian
432114878Sjulian	ng_btsocket_rfcomm_pcb_p	this = NULL, next = NULL;
433114878Sjulian	ng_btsocket_rfcomm_pcb_t	pcb;
434114878Sjulian	struct socket			so;
435114878Sjulian	int				first = 1;
436121054Semax	char				local[24], remote[24];
437114878Sjulian
438114878Sjulian	if (addr == 0)
439114878Sjulian		return;
440114878Sjulian
441114878Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
442114878Sjulian		return;
443114878Sjulian
444114878Sjulian	for ( ; this != NULL; this = next) {
445114878Sjulian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
446114878Sjulian			return;
447114878Sjulian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
448114878Sjulian			return;
449114878Sjulian
450114878Sjulian		next = LIST_NEXT(&pcb, next);
451114878Sjulian
452114878Sjulian		if (first) {
453114878Sjulian			first = 0;
454114878Sjulian			fprintf(stdout,
455114878Sjulian"Active RFCOMM sockets\n" \
456114878Sjulian"%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
457114878Sjulian				"PCB",
458114878Sjulian				"Recv-Q",
459114878Sjulian				"Send-Q",
460114878Sjulian				"Local address",
461114878Sjulian				"Foreign address",
462114878Sjulian				"Chan",
463114878Sjulian				"DLCI",
464114878Sjulian				"State");
465114878Sjulian		}
466114878Sjulian
467114878Sjulian		fprintf(stdout,
468128076Semax"%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
469128076Semax			(unsigned long) this,
470275326Sglebius			so.so_rcv.sb_ccc,
471275326Sglebius			so.so_snd.sb_ccc,
472121054Semax			bdaddrpr(&pcb.src, local, sizeof(local)),
473121054Semax			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
474114878Sjulian			pcb.channel,
475114878Sjulian			pcb.dlci,
476114878Sjulian			(so.so_options & SO_ACCEPTCONN)?
477114878Sjulian				"LISTEN" : state2str(pcb.state));
478114878Sjulian	}
479114878Sjulian} /* rfcommpr */
480114878Sjulian
481114878Sjulian/*
482114878Sjulian * Print RFCOMM sessions
483114878Sjulian */
484114878Sjulian
485114878Sjulianstatic void
486114878Sjulianrfcommpr_s(kvm_t *kvmd, u_long addr)
487114878Sjulian{
488114878Sjulian	static char const * const	states[] = {
489114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */	       "CLOSED",
490114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */     "LISTEN",
491114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */    "CONNECTING",
492114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */     "CONNECTED",
493114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_OPEN */          "OPEN",
494114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
495114878Sjulian	};
496114878Sjulian
497114878Sjulian	ng_btsocket_rfcomm_session_p	this = NULL, next = NULL;
498114878Sjulian	ng_btsocket_rfcomm_session_t	s;
499114878Sjulian	struct socket			so;
500114878Sjulian	int				first = 1;
501114878Sjulian
502114878Sjulian	if (addr == 0)
503114878Sjulian		return;
504114878Sjulian
505114878Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
506114878Sjulian		return;
507114878Sjulian
508114878Sjulian	for ( ; this != NULL; this = next) {
509114878Sjulian		if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
510114878Sjulian			return;
511114878Sjulian		if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
512114878Sjulian			return;
513114878Sjulian
514114878Sjulian		next = LIST_NEXT(&s, next);
515114878Sjulian
516114878Sjulian		if (first) {
517114878Sjulian			first = 0;
518114878Sjulian			fprintf(stdout,
519114878Sjulian"Active RFCOMM sessions\n" \
520114878Sjulian"%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
521114878Sjulian				"L2PCB",
522114878Sjulian				"PCB",
523114878Sjulian				"Flags",
524114878Sjulian				"MTU",
525114878Sjulian				"Out-Q",
526114878Sjulian				"DLCs",
527114878Sjulian				"State");
528114878Sjulian		}
529114878Sjulian
530114878Sjulian		fprintf(stdout,
531128076Semax"%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
532128076Semax			(unsigned long) so.so_pcb,
533128076Semax			(unsigned long) this,
534114878Sjulian			s.flags,
535114878Sjulian			s.mtu,
536114878Sjulian			s.outq.len,
537114878Sjulian			LIST_EMPTY(&s.dlcs)? "No" : "Yes",
538114878Sjulian			state2str(s.state));
539114878Sjulian	}
540114878Sjulian} /* rfcommpr_s */
541114878Sjulian
542114878Sjulian/*
543121054Semax * Return BD_ADDR as string
544121054Semax */
545121054Semax
546121054Semaxstatic char *
547121054Semaxbdaddrpr(bdaddr_p const ba, char *str, int len)
548121054Semax{
549121054Semax	static char	 buffer[MAXHOSTNAMELEN];
550121054Semax	struct hostent	*he = NULL;
551121054Semax
552121054Semax	if (str == NULL) {
553121054Semax		str = buffer;
554121054Semax		len = sizeof(buffer);
555121054Semax	}
556121054Semax
557121054Semax	if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
558121054Semax		str[0] = '*';
559121054Semax		str[1] = 0;
560121054Semax
561121054Semax		return (str);
562121054Semax	}
563121054Semax
564121054Semax	if (!numeric_bdaddr &&
565121054Semax	    (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
566121054Semax		strlcpy(str, he->h_name, len);
567121054Semax
568121054Semax		return (str);
569121054Semax	}
570121054Semax
571121054Semax	bt_ntoa(ba, str);
572121054Semax
573121054Semax	return (str);
574121054Semax} /* bdaddrpr */
575121054Semax
576121054Semax/*
577107120Sjulian * Open kvm
578107120Sjulian */
579107120Sjulian
580107120Sjulianstatic kvm_t *
581107120Sjuliankopen(char const *memf)
582107120Sjulian{
583107120Sjulian	kvm_t	*kvmd = NULL;
584107120Sjulian	char	 errbuf[_POSIX2_LINE_MAX];
585107120Sjulian
586107120Sjulian	/*
587107120Sjulian	 * Discard setgid privileges if not the running kernel so that
588107120Sjulian	 * bad guys can't print interesting stuff from kernel memory.
589107120Sjulian	 */
590107120Sjulian
591107120Sjulian	if (memf != NULL)
592107120Sjulian		setgid(getgid());
593107120Sjulian
594107120Sjulian	kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
595107120Sjulian	if (kvmd == NULL) {
596107120Sjulian		warnx("kvm_openfiles: %s", errbuf);
597107120Sjulian		return (NULL);
598107120Sjulian	}
599107120Sjulian
600107120Sjulian	if (kvm_nlist(kvmd, nl) < 0) {
601107120Sjulian		warnx("kvm_nlist: %s", kvm_geterr(kvmd));
602107120Sjulian		goto fail;
603107120Sjulian	}
604107120Sjulian
605107120Sjulian	if (nl[0].n_type == 0) {
606107120Sjulian		warnx("kvm_nlist: no namelist");
607107120Sjulian		goto fail;
608107120Sjulian	}
609107120Sjulian
610107120Sjulian	return (kvmd);
611107120Sjulianfail:
612107120Sjulian	kvm_close(kvmd);
613107120Sjulian
614107120Sjulian	return (NULL);
615107120Sjulian} /* kopen */
616107120Sjulian
617107120Sjulian/*
618107120Sjulian * Read kvm
619107120Sjulian */
620107120Sjulian
621107120Sjulianstatic int
622107120Sjuliankread(kvm_t *kvmd, u_long addr, char *buffer, int size)
623107120Sjulian{
624107120Sjulian	if (kvmd == NULL || buffer == NULL)
625107120Sjulian		return (-1);
626107120Sjulian
627107120Sjulian	if (kvm_read(kvmd, addr, buffer, size) != size) {
628107120Sjulian		warnx("kvm_read: %s", kvm_geterr(kvmd));
629107120Sjulian		return (-1);
630107120Sjulian	}
631107120Sjulian
632107120Sjulian	return (0);
633107120Sjulian} /* kread */
634107120Sjulian
635107120Sjulian/*
636107120Sjulian * Print usage and exit
637107120Sjulian */
638107120Sjulian
639107120Sjulianstatic void
640107120Sjulianusage(void)
641107120Sjulian{
642121054Semax	fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n");
643107120Sjulian	exit(255);
644107120Sjulian} /* usage */
645107120Sjulian
646