xref: /freebsd-src/usr.bin/bluetooth/btsockstat/btsockstat.c (revision 42b388439bd3795e09258c57a74ce9eec3651c7b)
11de7b4b8SPedro F. Giffuni /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4878ed226SJulian Elischer  * btsockstat.c
5878ed226SJulian Elischer  *
6878ed226SJulian Elischer  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7878ed226SJulian Elischer  * All rights reserved.
8878ed226SJulian Elischer  *
9878ed226SJulian Elischer  * Redistribution and use in source and binary forms, with or without
10878ed226SJulian Elischer  * modification, are permitted provided that the following conditions
11878ed226SJulian Elischer  * are met:
12878ed226SJulian Elischer  * 1. Redistributions of source code must retain the above copyright
13878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer.
14878ed226SJulian Elischer  * 2. Redistributions in binary form must reproduce the above copyright
15878ed226SJulian Elischer  *    notice, this list of conditions and the following disclaimer in the
16878ed226SJulian Elischer  *    documentation and/or other materials provided with the distribution.
17878ed226SJulian Elischer  *
18878ed226SJulian Elischer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19878ed226SJulian Elischer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20878ed226SJulian Elischer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21878ed226SJulian Elischer  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22878ed226SJulian Elischer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23878ed226SJulian Elischer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24878ed226SJulian Elischer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25878ed226SJulian Elischer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26878ed226SJulian Elischer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27878ed226SJulian Elischer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28878ed226SJulian Elischer  * SUCH DAMAGE.
29878ed226SJulian Elischer  *
300986ab12SMaksim Yevmenkin  * $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $
31878ed226SJulian Elischer  */
32878ed226SJulian Elischer 
33878ed226SJulian Elischer #include <sys/types.h>
34878ed226SJulian Elischer #include <sys/callout.h>
35878ed226SJulian Elischer #include <sys/param.h>
369b501d5aSMaksim Yevmenkin #include <sys/protosw.h>
37878ed226SJulian Elischer #include <sys/queue.h>
38878ed226SJulian Elischer #include <sys/socket.h>
390e229f34SGleb Smirnoff #define	_WANT_SOCKET
40878ed226SJulian Elischer #include <sys/socketvar.h>
41878ed226SJulian Elischer 
42878ed226SJulian Elischer #include <net/if.h>
43878ed226SJulian Elischer 
448d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
450986ab12SMaksim Yevmenkin #include <bluetooth.h>
46878ed226SJulian Elischer #include <err.h>
47878ed226SJulian Elischer #include <fcntl.h>
48878ed226SJulian Elischer #include <kvm.h>
49878ed226SJulian Elischer #include <limits.h>
501f85f715SBruce Evans #include <nlist.h>
51878ed226SJulian Elischer 
520986ab12SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_bluetooth.h>
530986ab12SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
540986ab12SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
550986ab12SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
56878ed226SJulian Elischer 
57878ed226SJulian Elischer #include <stdio.h>
58878ed226SJulian Elischer #include <stdlib.h>
59878ed226SJulian Elischer #include <string.h>
60878ed226SJulian Elischer #include <unistd.h>
61878ed226SJulian Elischer 
62878ed226SJulian Elischer static void	hcirawpr   (kvm_t *kvmd, u_long addr);
63878ed226SJulian Elischer static void	l2caprawpr (kvm_t *kvmd, u_long addr);
64878ed226SJulian Elischer static void	l2cappr    (kvm_t *kvmd, u_long addr);
65878ed226SJulian Elischer static void	l2caprtpr  (kvm_t *kvmd, u_long addr);
66f2bb1caeSJulian Elischer static void	rfcommpr   (kvm_t *kvmd, u_long addr);
67f2bb1caeSJulian Elischer static void	rfcommpr_s (kvm_t *kvmd, u_long addr);
68878ed226SJulian Elischer 
690986ab12SMaksim Yevmenkin static char *	bdaddrpr   (bdaddr_p const ba, char *str, int len);
700986ab12SMaksim Yevmenkin 
71878ed226SJulian Elischer static kvm_t *	kopen      (char const *memf);
72878ed226SJulian Elischer static int	kread      (kvm_t *kvmd, u_long addr, char *buffer, int size);
73878ed226SJulian Elischer 
74878ed226SJulian Elischer static void	usage      (void);
75878ed226SJulian Elischer 
76878ed226SJulian Elischer /*
77878ed226SJulian Elischer  * List of symbols
78878ed226SJulian Elischer  */
79878ed226SJulian Elischer 
80878ed226SJulian Elischer static struct nlist	nl[] = {
81878ed226SJulian Elischer #define N_HCI_RAW	0
82878ed226SJulian Elischer 	{ "_ng_btsocket_hci_raw_sockets" },
83878ed226SJulian Elischer #define N_L2CAP_RAW	1
84878ed226SJulian Elischer 	{ "_ng_btsocket_l2cap_raw_sockets" },
85878ed226SJulian Elischer #define N_L2CAP		2
86878ed226SJulian Elischer 	{ "_ng_btsocket_l2cap_sockets" },
87878ed226SJulian Elischer #define N_L2CAP_RAW_RT	3
88878ed226SJulian Elischer 	{ "_ng_btsocket_l2cap_raw_rt" },
89878ed226SJulian Elischer #define N_L2CAP_RT	4
90878ed226SJulian Elischer 	{ "_ng_btsocket_l2cap_rt" },
91f2bb1caeSJulian Elischer #define N_RFCOMM	5
92f2bb1caeSJulian Elischer 	{ "_ng_btsocket_rfcomm_sockets" },
93f2bb1caeSJulian Elischer #define N_RFCOMM_S	6
94f2bb1caeSJulian Elischer 	{ "_ng_btsocket_rfcomm_sessions" },
95878ed226SJulian Elischer 	{ "" },
96878ed226SJulian Elischer };
97878ed226SJulian Elischer 
98f2bb1caeSJulian Elischer #define state2str(x) \
99f2bb1caeSJulian Elischer 	(((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
100f2bb1caeSJulian Elischer 
101878ed226SJulian Elischer /*
102878ed226SJulian Elischer  * Main
103878ed226SJulian Elischer  */
104878ed226SJulian Elischer 
1050986ab12SMaksim Yevmenkin static int	numeric_bdaddr = 0;
1060986ab12SMaksim Yevmenkin 
107878ed226SJulian Elischer int
main(int argc,char * argv[])108878ed226SJulian Elischer main(int argc, char *argv[])
109878ed226SJulian Elischer {
110878ed226SJulian Elischer 	int	 opt, proto = -1, route = 0;
111878ed226SJulian Elischer 	kvm_t	*kvmd = NULL;
112878ed226SJulian Elischer 	char	*memf = NULL;
113878ed226SJulian Elischer 
1140986ab12SMaksim Yevmenkin 	while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
115878ed226SJulian Elischer 		switch (opt) {
1160986ab12SMaksim Yevmenkin 		case 'n':
1170986ab12SMaksim Yevmenkin 			numeric_bdaddr = 1;
1180986ab12SMaksim Yevmenkin 			break;
1190986ab12SMaksim Yevmenkin 
120878ed226SJulian Elischer 		case 'M':
121878ed226SJulian Elischer 			memf = optarg;
122878ed226SJulian Elischer 			break;
123878ed226SJulian Elischer 
124878ed226SJulian Elischer 		case 'p':
125878ed226SJulian Elischer 			if (strcasecmp(optarg, "hci_raw") == 0)
126878ed226SJulian Elischer 				proto = N_HCI_RAW;
127878ed226SJulian Elischer 			else if (strcasecmp(optarg, "l2cap_raw") == 0)
128878ed226SJulian Elischer 				proto = N_L2CAP_RAW;
129878ed226SJulian Elischer 			else if (strcasecmp(optarg, "l2cap") == 0)
130878ed226SJulian Elischer 				proto = N_L2CAP;
131f2bb1caeSJulian Elischer 			else if (strcasecmp(optarg, "rfcomm") == 0)
132f2bb1caeSJulian Elischer 				proto = N_RFCOMM;
133f2bb1caeSJulian Elischer 			else if (strcasecmp(optarg, "rfcomm_s") == 0)
134f2bb1caeSJulian Elischer 				proto = N_RFCOMM_S;
135878ed226SJulian Elischer 			else
136878ed226SJulian Elischer 				usage();
137878ed226SJulian Elischer 				/* NOT REACHED */
138878ed226SJulian Elischer 			break;
139878ed226SJulian Elischer 
140878ed226SJulian Elischer 		case 'r':
141878ed226SJulian Elischer 			route = 1;
142878ed226SJulian Elischer 			break;
143878ed226SJulian Elischer 
144878ed226SJulian Elischer 		case 'h':
145878ed226SJulian Elischer 		default:
146878ed226SJulian Elischer 			usage();
147878ed226SJulian Elischer 			/* NOT REACHED */
148878ed226SJulian Elischer 		}
149878ed226SJulian Elischer 	}
150878ed226SJulian Elischer 
151f2bb1caeSJulian Elischer 	if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
152878ed226SJulian Elischer 		usage();
153878ed226SJulian Elischer 		/* NOT REACHED */
154878ed226SJulian Elischer 
155f2bb1caeSJulian Elischer 	/*
156f2bb1caeSJulian Elischer 	 * Discard setgid privileges if not the running kernel so that
157f2bb1caeSJulian Elischer 	 * bad guys can't print interesting stuff from kernel memory.
158f2bb1caeSJulian Elischer 	 */
159f2bb1caeSJulian Elischer 	if (memf != NULL)
1600a107dafSXin LI 		if (setgid(getgid()) != 0)
1610a107dafSXin LI 			err(1, "setgid");
162f2bb1caeSJulian Elischer 
163878ed226SJulian Elischer 	kvmd = kopen(memf);
164878ed226SJulian Elischer 	if (kvmd == NULL)
165878ed226SJulian Elischer 		return (1);
166878ed226SJulian Elischer 
167878ed226SJulian Elischer 	switch (proto) {
168878ed226SJulian Elischer 	case N_HCI_RAW:
169878ed226SJulian Elischer 		hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
170878ed226SJulian Elischer 		break;
171878ed226SJulian Elischer 
172878ed226SJulian Elischer 	case N_L2CAP_RAW:
173878ed226SJulian Elischer 		if (route)
174878ed226SJulian Elischer 			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
175878ed226SJulian Elischer 		else
176878ed226SJulian Elischer 			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
177878ed226SJulian Elischer 		break;
178878ed226SJulian Elischer 
179878ed226SJulian Elischer 	case N_L2CAP:
180878ed226SJulian Elischer 		if (route)
181878ed226SJulian Elischer 			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
182878ed226SJulian Elischer 		else
183878ed226SJulian Elischer 			l2cappr(kvmd, nl[N_L2CAP].n_value);
184878ed226SJulian Elischer 		break;
185878ed226SJulian Elischer 
186f2bb1caeSJulian Elischer 	case N_RFCOMM:
187f2bb1caeSJulian Elischer 		rfcommpr(kvmd, nl[N_RFCOMM].n_value);
188f2bb1caeSJulian Elischer 		break;
189f2bb1caeSJulian Elischer 
190f2bb1caeSJulian Elischer 	case N_RFCOMM_S:
191f2bb1caeSJulian Elischer 		rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
192f2bb1caeSJulian Elischer 		break;
193f2bb1caeSJulian Elischer 
194878ed226SJulian Elischer 	default:
195878ed226SJulian Elischer 		if (route) {
196878ed226SJulian Elischer 			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
197878ed226SJulian Elischer 			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
198878ed226SJulian Elischer 		} else {
199878ed226SJulian Elischer 			hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
200878ed226SJulian Elischer 			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
201878ed226SJulian Elischer 			l2cappr(kvmd, nl[N_L2CAP].n_value);
202f2bb1caeSJulian Elischer 			rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
203f2bb1caeSJulian Elischer 			rfcommpr(kvmd, nl[N_RFCOMM].n_value);
204878ed226SJulian Elischer 		}
205878ed226SJulian Elischer 		break;
206878ed226SJulian Elischer 	}
207878ed226SJulian Elischer 
208878ed226SJulian Elischer 	return (kvm_close(kvmd));
209878ed226SJulian Elischer } /* main */
210878ed226SJulian Elischer 
211878ed226SJulian Elischer /*
212878ed226SJulian Elischer  * Print raw HCI sockets
213878ed226SJulian Elischer  */
214878ed226SJulian Elischer 
215878ed226SJulian Elischer static void
hcirawpr(kvm_t * kvmd,u_long addr)216878ed226SJulian Elischer hcirawpr(kvm_t *kvmd, u_long addr)
217878ed226SJulian Elischer {
218878ed226SJulian Elischer 	ng_btsocket_hci_raw_pcb_p	this = NULL, next = NULL;
219878ed226SJulian Elischer 	ng_btsocket_hci_raw_pcb_t	pcb;
220878ed226SJulian Elischer 	struct socket			so;
221878ed226SJulian Elischer 	int				first = 1;
222878ed226SJulian Elischer 
223878ed226SJulian Elischer 	if (addr == 0)
224878ed226SJulian Elischer 		return;
225878ed226SJulian Elischer 
226878ed226SJulian Elischer         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
227878ed226SJulian Elischer 		return;
228878ed226SJulian Elischer 
229878ed226SJulian Elischer 	for ( ; this != NULL; this = next) {
230878ed226SJulian Elischer 		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
231878ed226SJulian Elischer 			return;
232878ed226SJulian Elischer 		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
233878ed226SJulian Elischer 			return;
234878ed226SJulian Elischer 
235878ed226SJulian Elischer 		next = LIST_NEXT(&pcb, next);
236878ed226SJulian Elischer 
237878ed226SJulian Elischer 		if (first) {
238878ed226SJulian Elischer 			first = 0;
239878ed226SJulian Elischer 			fprintf(stdout,
240878ed226SJulian Elischer "Active raw HCI sockets\n" \
241878ed226SJulian Elischer "%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
242878ed226SJulian Elischer 				"Socket",
243878ed226SJulian Elischer 				"PCB",
244878ed226SJulian Elischer 				"Flags",
245878ed226SJulian Elischer 				"Recv-Q",
246878ed226SJulian Elischer 				"Send-Q",
247878ed226SJulian Elischer 				"Local address");
248878ed226SJulian Elischer 		}
249878ed226SJulian Elischer 
250878ed226SJulian Elischer 		if (pcb.addr.hci_node[0] == 0) {
251878ed226SJulian Elischer 			pcb.addr.hci_node[0] = '*';
252878ed226SJulian Elischer 			pcb.addr.hci_node[1] = 0;
253878ed226SJulian Elischer 		}
254878ed226SJulian Elischer 
255878ed226SJulian Elischer 		fprintf(stdout,
2564ae439a3SMaksim Yevmenkin "%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n",
2574ae439a3SMaksim Yevmenkin 			(unsigned long) pcb.so,
2584ae439a3SMaksim Yevmenkin 			(unsigned long) this,
259878ed226SJulian Elischer 			pcb.flags,
2600f9d0a73SGleb Smirnoff 			so.so_rcv.sb_ccc,
2610f9d0a73SGleb Smirnoff 			so.so_snd.sb_ccc,
262878ed226SJulian Elischer 			pcb.addr.hci_node);
263878ed226SJulian Elischer 	}
264878ed226SJulian Elischer } /* hcirawpr */
265878ed226SJulian Elischer 
266878ed226SJulian Elischer /*
267878ed226SJulian Elischer  * Print raw L2CAP sockets
268878ed226SJulian Elischer  */
269878ed226SJulian Elischer 
270878ed226SJulian Elischer static void
l2caprawpr(kvm_t * kvmd,u_long addr)271878ed226SJulian Elischer l2caprawpr(kvm_t *kvmd, u_long addr)
272878ed226SJulian Elischer {
273878ed226SJulian Elischer 	ng_btsocket_l2cap_raw_pcb_p	this = NULL, next = NULL;
274878ed226SJulian Elischer 	ng_btsocket_l2cap_raw_pcb_t	pcb;
275878ed226SJulian Elischer 	struct socket			so;
276878ed226SJulian Elischer 	int				first = 1;
277878ed226SJulian Elischer 
278878ed226SJulian Elischer 	if (addr == 0)
279878ed226SJulian Elischer 		return;
280878ed226SJulian Elischer 
281878ed226SJulian Elischer         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
282878ed226SJulian Elischer 		return;
283878ed226SJulian Elischer 
284878ed226SJulian Elischer 	for ( ; this != NULL; this = next) {
285878ed226SJulian Elischer 		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
286878ed226SJulian Elischer 			return;
287878ed226SJulian Elischer 		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
288878ed226SJulian Elischer 			return;
289878ed226SJulian Elischer 
290878ed226SJulian Elischer 		next = LIST_NEXT(&pcb, next);
291878ed226SJulian Elischer 
292878ed226SJulian Elischer 		if (first) {
293878ed226SJulian Elischer 			first = 0;
294878ed226SJulian Elischer 			fprintf(stdout,
295878ed226SJulian Elischer "Active raw L2CAP sockets\n" \
296f2bb1caeSJulian Elischer "%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
297878ed226SJulian Elischer 				"Socket",
298878ed226SJulian Elischer 				"PCB",
299878ed226SJulian Elischer 				"Recv-Q",
300878ed226SJulian Elischer 				"Send-Q",
301878ed226SJulian Elischer 				"Local address");
302878ed226SJulian Elischer 		}
303878ed226SJulian Elischer 
304878ed226SJulian Elischer 		fprintf(stdout,
3054ae439a3SMaksim Yevmenkin "%-8lx %-8lx %6d %6d %-17.17s\n",
3064ae439a3SMaksim Yevmenkin 			(unsigned long) pcb.so,
3074ae439a3SMaksim Yevmenkin 			(unsigned long) this,
3080f9d0a73SGleb Smirnoff 			so.so_rcv.sb_ccc,
3090f9d0a73SGleb Smirnoff 			so.so_snd.sb_ccc,
3100986ab12SMaksim Yevmenkin 			bdaddrpr(&pcb.src, NULL, 0));
311878ed226SJulian Elischer 	}
312878ed226SJulian Elischer } /* l2caprawpr */
313878ed226SJulian Elischer 
314878ed226SJulian Elischer /*
315878ed226SJulian Elischer  * Print L2CAP sockets
316878ed226SJulian Elischer  */
317878ed226SJulian Elischer 
318878ed226SJulian Elischer static void
l2cappr(kvm_t * kvmd,u_long addr)319878ed226SJulian Elischer l2cappr(kvm_t *kvmd, u_long addr)
320878ed226SJulian Elischer {
321878ed226SJulian Elischer 	static char const * const	states[] = {
322878ed226SJulian Elischer 	/* NG_BTSOCKET_L2CAP_CLOSED */		"CLOSED",
323878ed226SJulian Elischer 	/* NG_BTSOCKET_L2CAP_CONNECTING */	"CON",
324878ed226SJulian Elischer 	/* NG_BTSOCKET_L2CAP_CONFIGURING */	"CONFIG",
325878ed226SJulian Elischer 	/* NG_BTSOCKET_L2CAP_OPEN */		"OPEN",
326878ed226SJulian Elischer 	/* NG_BTSOCKET_L2CAP_DISCONNECTING */	"DISCON"
327878ed226SJulian Elischer 	};
328878ed226SJulian Elischer 
329878ed226SJulian Elischer 	ng_btsocket_l2cap_pcb_p	this = NULL, next = NULL;
330878ed226SJulian Elischer 	ng_btsocket_l2cap_pcb_t	pcb;
331878ed226SJulian Elischer 	struct socket		so;
332878ed226SJulian Elischer 	int			first = 1;
3330986ab12SMaksim Yevmenkin 	char			local[24], remote[24];
334878ed226SJulian Elischer 
335878ed226SJulian Elischer 	if (addr == 0)
336878ed226SJulian Elischer 		return;
337878ed226SJulian Elischer 
338878ed226SJulian Elischer         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
339878ed226SJulian Elischer 		return;
340878ed226SJulian Elischer 
341878ed226SJulian Elischer 	for ( ; this != NULL; this = next) {
342878ed226SJulian Elischer 		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
343878ed226SJulian Elischer 			return;
344878ed226SJulian Elischer 		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
345878ed226SJulian Elischer 			return;
346878ed226SJulian Elischer 
347878ed226SJulian Elischer 		next = LIST_NEXT(&pcb, next);
348878ed226SJulian Elischer 
349878ed226SJulian Elischer 		if (first) {
350878ed226SJulian Elischer 			first = 0;
351878ed226SJulian Elischer 			fprintf(stdout,
352878ed226SJulian Elischer "Active L2CAP sockets\n" \
353f2bb1caeSJulian Elischer "%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
354878ed226SJulian Elischer 				"PCB",
355878ed226SJulian Elischer 				"Recv-Q",
356878ed226SJulian Elischer 				"Send-Q",
357878ed226SJulian Elischer 				"Local address/PSM",
358878ed226SJulian Elischer 				"Foreign address",
359878ed226SJulian Elischer 				"CID",
360878ed226SJulian Elischer 				"State");
361878ed226SJulian Elischer 		}
362878ed226SJulian Elischer 
363878ed226SJulian Elischer 		fprintf(stdout,
3644ae439a3SMaksim Yevmenkin "%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
3654ae439a3SMaksim Yevmenkin 			(unsigned long) this,
3660f9d0a73SGleb Smirnoff 			so.so_rcv.sb_ccc,
3670f9d0a73SGleb Smirnoff 			so.so_snd.sb_ccc,
3680986ab12SMaksim Yevmenkin 			bdaddrpr(&pcb.src, local, sizeof(local)),
3690986ab12SMaksim Yevmenkin 			pcb.psm,
3700986ab12SMaksim Yevmenkin 			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
371878ed226SJulian Elischer 			pcb.cid,
372878ed226SJulian Elischer 			(so.so_options & SO_ACCEPTCONN)?
373878ed226SJulian Elischer 				"LISTEN" : state2str(pcb.state));
374878ed226SJulian Elischer 	}
375878ed226SJulian Elischer } /* l2cappr */
376878ed226SJulian Elischer 
377878ed226SJulian Elischer /*
378878ed226SJulian Elischer  * Print L2CAP routing table
379878ed226SJulian Elischer  */
380878ed226SJulian Elischer 
381878ed226SJulian Elischer static void
l2caprtpr(kvm_t * kvmd,u_long addr)382878ed226SJulian Elischer l2caprtpr(kvm_t *kvmd, u_long addr)
383878ed226SJulian Elischer {
384878ed226SJulian Elischer 	ng_btsocket_l2cap_rtentry_p	this = NULL, next = NULL;
385878ed226SJulian Elischer 	ng_btsocket_l2cap_rtentry_t	rt;
386878ed226SJulian Elischer 	int				first = 1;
387878ed226SJulian Elischer 
388878ed226SJulian Elischer 	if (addr == 0)
389878ed226SJulian Elischer 		return;
390878ed226SJulian Elischer 
391878ed226SJulian Elischer 	if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
392878ed226SJulian Elischer 		return;
393878ed226SJulian Elischer 
394878ed226SJulian Elischer 	for ( ; this != NULL; this = next) {
395878ed226SJulian Elischer 		if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
396878ed226SJulian Elischer 			return;
397878ed226SJulian Elischer 
398878ed226SJulian Elischer 		next = LIST_NEXT(&rt, next);
399878ed226SJulian Elischer 
400878ed226SJulian Elischer 		if (first) {
401878ed226SJulian Elischer 			first = 0;
402878ed226SJulian Elischer 			fprintf(stdout,
403878ed226SJulian Elischer "Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)?  "raw " : "");
404878ed226SJulian Elischer 			fprintf(stdout,
405f2bb1caeSJulian Elischer "%-8.8s %-8.8s %-17.17s\n",	"RTentry",
406878ed226SJulian Elischer 				"Hook",
407878ed226SJulian Elischer 				"BD_ADDR");
408878ed226SJulian Elischer 		}
409878ed226SJulian Elischer 
410878ed226SJulian Elischer 		fprintf(stdout,
4114ae439a3SMaksim Yevmenkin "%-8lx %-8lx %-17.17s\n",
4124ae439a3SMaksim Yevmenkin 			(unsigned long) this,
4134ae439a3SMaksim Yevmenkin 			(unsigned long) rt.hook,
4140986ab12SMaksim Yevmenkin 			bdaddrpr(&rt.src, NULL, 0));
415878ed226SJulian Elischer 	}
416878ed226SJulian Elischer } /* l2caprtpr */
417878ed226SJulian Elischer 
418878ed226SJulian Elischer /*
419f2bb1caeSJulian Elischer  * Print RFCOMM sockets
420f2bb1caeSJulian Elischer  */
421f2bb1caeSJulian Elischer 
422f2bb1caeSJulian Elischer static void
rfcommpr(kvm_t * kvmd,u_long addr)423f2bb1caeSJulian Elischer rfcommpr(kvm_t *kvmd, u_long addr)
424f2bb1caeSJulian Elischer {
425f2bb1caeSJulian Elischer 	static char const * const	states[] = {
426f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_DLC_CLOSED */	   "CLOSED",
427f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */	   "W4CON",
428f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */   "CONFIG",
429f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */    "CONN",
430f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */     "OPEN",
431f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
432f2bb1caeSJulian Elischer 	};
433f2bb1caeSJulian Elischer 
434f2bb1caeSJulian Elischer 	ng_btsocket_rfcomm_pcb_p	this = NULL, next = NULL;
435f2bb1caeSJulian Elischer 	ng_btsocket_rfcomm_pcb_t	pcb;
436f2bb1caeSJulian Elischer 	struct socket			so;
437f2bb1caeSJulian Elischer 	int				first = 1;
4380986ab12SMaksim Yevmenkin 	char				local[24], remote[24];
439f2bb1caeSJulian Elischer 
440f2bb1caeSJulian Elischer 	if (addr == 0)
441f2bb1caeSJulian Elischer 		return;
442f2bb1caeSJulian Elischer 
443f2bb1caeSJulian Elischer         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
444f2bb1caeSJulian Elischer 		return;
445f2bb1caeSJulian Elischer 
446f2bb1caeSJulian Elischer 	for ( ; this != NULL; this = next) {
447f2bb1caeSJulian Elischer 		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
448f2bb1caeSJulian Elischer 			return;
449f2bb1caeSJulian Elischer 		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
450f2bb1caeSJulian Elischer 			return;
451f2bb1caeSJulian Elischer 
452f2bb1caeSJulian Elischer 		next = LIST_NEXT(&pcb, next);
453f2bb1caeSJulian Elischer 
454f2bb1caeSJulian Elischer 		if (first) {
455f2bb1caeSJulian Elischer 			first = 0;
456f2bb1caeSJulian Elischer 			fprintf(stdout,
457f2bb1caeSJulian Elischer "Active RFCOMM sockets\n" \
458f2bb1caeSJulian Elischer "%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
459f2bb1caeSJulian Elischer 				"PCB",
460f2bb1caeSJulian Elischer 				"Recv-Q",
461f2bb1caeSJulian Elischer 				"Send-Q",
462f2bb1caeSJulian Elischer 				"Local address",
463f2bb1caeSJulian Elischer 				"Foreign address",
464f2bb1caeSJulian Elischer 				"Chan",
465f2bb1caeSJulian Elischer 				"DLCI",
466f2bb1caeSJulian Elischer 				"State");
467f2bb1caeSJulian Elischer 		}
468f2bb1caeSJulian Elischer 
469f2bb1caeSJulian Elischer 		fprintf(stdout,
4704ae439a3SMaksim Yevmenkin "%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
4714ae439a3SMaksim Yevmenkin 			(unsigned long) this,
4720f9d0a73SGleb Smirnoff 			so.so_rcv.sb_ccc,
4730f9d0a73SGleb Smirnoff 			so.so_snd.sb_ccc,
4740986ab12SMaksim Yevmenkin 			bdaddrpr(&pcb.src, local, sizeof(local)),
4750986ab12SMaksim Yevmenkin 			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
476f2bb1caeSJulian Elischer 			pcb.channel,
477f2bb1caeSJulian Elischer 			pcb.dlci,
478f2bb1caeSJulian Elischer 			(so.so_options & SO_ACCEPTCONN)?
479f2bb1caeSJulian Elischer 				"LISTEN" : state2str(pcb.state));
480f2bb1caeSJulian Elischer 	}
481f2bb1caeSJulian Elischer } /* rfcommpr */
482f2bb1caeSJulian Elischer 
483f2bb1caeSJulian Elischer /*
484f2bb1caeSJulian Elischer  * Print RFCOMM sessions
485f2bb1caeSJulian Elischer  */
486f2bb1caeSJulian Elischer 
487f2bb1caeSJulian Elischer static void
rfcommpr_s(kvm_t * kvmd,u_long addr)488f2bb1caeSJulian Elischer rfcommpr_s(kvm_t *kvmd, u_long addr)
489f2bb1caeSJulian Elischer {
490f2bb1caeSJulian Elischer 	static char const * const	states[] = {
491f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */	       "CLOSED",
492f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */     "LISTEN",
493f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */    "CONNECTING",
494f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */     "CONNECTED",
495f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_SESSION_OPEN */          "OPEN",
496f2bb1caeSJulian Elischer 	/* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
497f2bb1caeSJulian Elischer 	};
498f2bb1caeSJulian Elischer 
499f2bb1caeSJulian Elischer 	ng_btsocket_rfcomm_session_p	this = NULL, next = NULL;
500f2bb1caeSJulian Elischer 	ng_btsocket_rfcomm_session_t	s;
501f2bb1caeSJulian Elischer 	struct socket			so;
502f2bb1caeSJulian Elischer 	int				first = 1;
503f2bb1caeSJulian Elischer 
504f2bb1caeSJulian Elischer 	if (addr == 0)
505f2bb1caeSJulian Elischer 		return;
506f2bb1caeSJulian Elischer 
507f2bb1caeSJulian Elischer         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
508f2bb1caeSJulian Elischer 		return;
509f2bb1caeSJulian Elischer 
510f2bb1caeSJulian Elischer 	for ( ; this != NULL; this = next) {
511f2bb1caeSJulian Elischer 		if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
512f2bb1caeSJulian Elischer 			return;
513f2bb1caeSJulian Elischer 		if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
514f2bb1caeSJulian Elischer 			return;
515f2bb1caeSJulian Elischer 
516f2bb1caeSJulian Elischer 		next = LIST_NEXT(&s, next);
517f2bb1caeSJulian Elischer 
518f2bb1caeSJulian Elischer 		if (first) {
519f2bb1caeSJulian Elischer 			first = 0;
520f2bb1caeSJulian Elischer 			fprintf(stdout,
521f2bb1caeSJulian Elischer "Active RFCOMM sessions\n" \
522f2bb1caeSJulian Elischer "%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
523f2bb1caeSJulian Elischer 				"L2PCB",
524f2bb1caeSJulian Elischer 				"PCB",
525f2bb1caeSJulian Elischer 				"Flags",
526f2bb1caeSJulian Elischer 				"MTU",
527f2bb1caeSJulian Elischer 				"Out-Q",
528f2bb1caeSJulian Elischer 				"DLCs",
529f2bb1caeSJulian Elischer 				"State");
530f2bb1caeSJulian Elischer 		}
531f2bb1caeSJulian Elischer 
532f2bb1caeSJulian Elischer 		fprintf(stdout,
5334ae439a3SMaksim Yevmenkin "%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
5344ae439a3SMaksim Yevmenkin 			(unsigned long) so.so_pcb,
5354ae439a3SMaksim Yevmenkin 			(unsigned long) this,
536f2bb1caeSJulian Elischer 			s.flags,
537f2bb1caeSJulian Elischer 			s.mtu,
538f2bb1caeSJulian Elischer 			s.outq.len,
539f2bb1caeSJulian Elischer 			LIST_EMPTY(&s.dlcs)? "No" : "Yes",
540f2bb1caeSJulian Elischer 			state2str(s.state));
541f2bb1caeSJulian Elischer 	}
542f2bb1caeSJulian Elischer } /* rfcommpr_s */
543f2bb1caeSJulian Elischer 
544f2bb1caeSJulian Elischer /*
5450986ab12SMaksim Yevmenkin  * Return BD_ADDR as string
5460986ab12SMaksim Yevmenkin  */
5470986ab12SMaksim Yevmenkin 
5480986ab12SMaksim Yevmenkin static char *
bdaddrpr(bdaddr_p const ba,char * str,int len)5490986ab12SMaksim Yevmenkin bdaddrpr(bdaddr_p const ba, char *str, int len)
5500986ab12SMaksim Yevmenkin {
5510986ab12SMaksim Yevmenkin 	static char	 buffer[MAXHOSTNAMELEN];
5520986ab12SMaksim Yevmenkin 	struct hostent	*he = NULL;
5530986ab12SMaksim Yevmenkin 
5540986ab12SMaksim Yevmenkin 	if (str == NULL) {
5550986ab12SMaksim Yevmenkin 		str = buffer;
5560986ab12SMaksim Yevmenkin 		len = sizeof(buffer);
5570986ab12SMaksim Yevmenkin 	}
5580986ab12SMaksim Yevmenkin 
5590986ab12SMaksim Yevmenkin 	if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
5600986ab12SMaksim Yevmenkin 		str[0] = '*';
5610986ab12SMaksim Yevmenkin 		str[1] = 0;
5620986ab12SMaksim Yevmenkin 
5630986ab12SMaksim Yevmenkin 		return (str);
5640986ab12SMaksim Yevmenkin 	}
5650986ab12SMaksim Yevmenkin 
5660986ab12SMaksim Yevmenkin 	if (!numeric_bdaddr &&
5670986ab12SMaksim Yevmenkin 	    (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
5680986ab12SMaksim Yevmenkin 		strlcpy(str, he->h_name, len);
5690986ab12SMaksim Yevmenkin 
5700986ab12SMaksim Yevmenkin 		return (str);
5710986ab12SMaksim Yevmenkin 	}
5720986ab12SMaksim Yevmenkin 
5730986ab12SMaksim Yevmenkin 	bt_ntoa(ba, str);
5740986ab12SMaksim Yevmenkin 
5750986ab12SMaksim Yevmenkin 	return (str);
5760986ab12SMaksim Yevmenkin } /* bdaddrpr */
5770986ab12SMaksim Yevmenkin 
5780986ab12SMaksim Yevmenkin /*
579878ed226SJulian Elischer  * Open kvm
580878ed226SJulian Elischer  */
581878ed226SJulian Elischer 
582878ed226SJulian Elischer static kvm_t *
kopen(char const * memf)583878ed226SJulian Elischer kopen(char const *memf)
584878ed226SJulian Elischer {
585878ed226SJulian Elischer 	kvm_t	*kvmd = NULL;
586878ed226SJulian Elischer 	char	 errbuf[_POSIX2_LINE_MAX];
587878ed226SJulian Elischer 
588878ed226SJulian Elischer 	kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
5890a107dafSXin LI 	if (setgid(getgid()) != 0)
5900a107dafSXin LI 		err(1, "setgid");
591878ed226SJulian Elischer 	if (kvmd == NULL) {
592878ed226SJulian Elischer 		warnx("kvm_openfiles: %s", errbuf);
593878ed226SJulian Elischer 		return (NULL);
594878ed226SJulian Elischer 	}
595878ed226SJulian Elischer 
596878ed226SJulian Elischer 	if (kvm_nlist(kvmd, nl) < 0) {
597878ed226SJulian Elischer 		warnx("kvm_nlist: %s", kvm_geterr(kvmd));
598878ed226SJulian Elischer 		goto fail;
599878ed226SJulian Elischer 	}
600878ed226SJulian Elischer 
601878ed226SJulian Elischer 	if (nl[0].n_type == 0) {
602878ed226SJulian Elischer 		warnx("kvm_nlist: no namelist");
603878ed226SJulian Elischer 		goto fail;
604878ed226SJulian Elischer 	}
605878ed226SJulian Elischer 
606878ed226SJulian Elischer 	return (kvmd);
607878ed226SJulian Elischer fail:
608878ed226SJulian Elischer 	kvm_close(kvmd);
609878ed226SJulian Elischer 
610878ed226SJulian Elischer 	return (NULL);
611878ed226SJulian Elischer } /* kopen */
612878ed226SJulian Elischer 
613878ed226SJulian Elischer /*
614878ed226SJulian Elischer  * Read kvm
615878ed226SJulian Elischer  */
616878ed226SJulian Elischer 
617878ed226SJulian Elischer static int
kread(kvm_t * kvmd,u_long addr,char * buffer,int size)618878ed226SJulian Elischer kread(kvm_t *kvmd, u_long addr, char *buffer, int size)
619878ed226SJulian Elischer {
620878ed226SJulian Elischer 	if (kvmd == NULL || buffer == NULL)
621878ed226SJulian Elischer 		return (-1);
622878ed226SJulian Elischer 
623878ed226SJulian Elischer 	if (kvm_read(kvmd, addr, buffer, size) != size) {
624878ed226SJulian Elischer 		warnx("kvm_read: %s", kvm_geterr(kvmd));
625878ed226SJulian Elischer 		return (-1);
626878ed226SJulian Elischer 	}
627878ed226SJulian Elischer 
628878ed226SJulian Elischer 	return (0);
629878ed226SJulian Elischer } /* kread */
630878ed226SJulian Elischer 
631878ed226SJulian Elischer /*
632878ed226SJulian Elischer  * Print usage and exit
633878ed226SJulian Elischer  */
634878ed226SJulian Elischer 
635878ed226SJulian Elischer static void
usage(void)636878ed226SJulian Elischer usage(void)
637878ed226SJulian Elischer {
6380986ab12SMaksim Yevmenkin 	fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n");
639878ed226SJulian Elischer 	exit(255);
640878ed226SJulian Elischer } /* usage */
641878ed226SJulian Elischer 
642