1330449Seadler/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
4107120Sjulian * btsockstat.c
5107120Sjulian *
6107120Sjulian * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7107120Sjulian * All rights reserved.
8107120Sjulian *
9107120Sjulian * Redistribution and use in source and binary forms, with or without
10107120Sjulian * modification, are permitted provided that the following conditions
11107120Sjulian * are met:
12107120Sjulian * 1. Redistributions of source code must retain the above copyright
13107120Sjulian *    notice, this list of conditions and the following disclaimer.
14107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright
15107120Sjulian *    notice, this list of conditions and the following disclaimer in the
16107120Sjulian *    documentation and/or other materials provided with the distribution.
17107120Sjulian *
18107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28107120Sjulian * SUCH DAMAGE.
29107120Sjulian *
30121054Semax * $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $
31107120Sjulian * $FreeBSD: stable/11/usr.bin/bluetooth/btsockstat/btsockstat.c 330449 2018-03-05 07:26:05Z eadler $
32107120Sjulian */
33107120Sjulian
34107120Sjulian#include <sys/types.h>
35107120Sjulian#include <sys/callout.h>
36107120Sjulian#include <sys/param.h>
37180964Semax#include <sys/protosw.h>
38107120Sjulian#include <sys/queue.h>
39107120Sjulian#include <sys/socket.h>
40107120Sjulian#include <sys/socketvar.h>
41107120Sjulian
42107120Sjulian#include <net/if.h>
43107120Sjulian
44281210Stakawata#define L2CAP_SOCKET_CHECKED
45121054Semax#include <bluetooth.h>
46107120Sjulian#include <err.h>
47107120Sjulian#include <fcntl.h>
48107120Sjulian#include <kvm.h>
49107120Sjulian#include <limits.h>
50121064Sbde#include <nlist.h>
51107120Sjulian
52121054Semax#include <netgraph/bluetooth/include/ng_bluetooth.h>
53121054Semax#include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
54121054Semax#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
55121054Semax#include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
56107120Sjulian
57107120Sjulian#include <stdio.h>
58107120Sjulian#include <stdlib.h>
59107120Sjulian#include <string.h>
60107120Sjulian#include <unistd.h>
61107120Sjulian
62107120Sjulianstatic void	hcirawpr   (kvm_t *kvmd, u_long addr);
63107120Sjulianstatic void	l2caprawpr (kvm_t *kvmd, u_long addr);
64107120Sjulianstatic void	l2cappr    (kvm_t *kvmd, u_long addr);
65107120Sjulianstatic void	l2caprtpr  (kvm_t *kvmd, u_long addr);
66114878Sjulianstatic void	rfcommpr   (kvm_t *kvmd, u_long addr);
67114878Sjulianstatic void	rfcommpr_s (kvm_t *kvmd, u_long addr);
68107120Sjulian
69121054Semaxstatic char *	bdaddrpr   (bdaddr_p const ba, char *str, int len);
70121054Semax
71107120Sjulianstatic kvm_t *	kopen      (char const *memf);
72107120Sjulianstatic int	kread      (kvm_t *kvmd, u_long addr, char *buffer, int size);
73107120Sjulian
74107120Sjulianstatic void	usage      (void);
75107120Sjulian
76107120Sjulian/*
77107120Sjulian * List of symbols
78107120Sjulian */
79107120Sjulian
80107120Sjulianstatic struct nlist	nl[] = {
81107120Sjulian#define N_HCI_RAW	0
82107120Sjulian	{ "_ng_btsocket_hci_raw_sockets" },
83107120Sjulian#define N_L2CAP_RAW	1
84107120Sjulian	{ "_ng_btsocket_l2cap_raw_sockets" },
85107120Sjulian#define N_L2CAP		2
86107120Sjulian	{ "_ng_btsocket_l2cap_sockets" },
87107120Sjulian#define N_L2CAP_RAW_RT	3
88107120Sjulian	{ "_ng_btsocket_l2cap_raw_rt" },
89107120Sjulian#define N_L2CAP_RT	4
90107120Sjulian	{ "_ng_btsocket_l2cap_rt" },
91114878Sjulian#define N_RFCOMM	5
92114878Sjulian	{ "_ng_btsocket_rfcomm_sockets" },
93114878Sjulian#define N_RFCOMM_S	6
94114878Sjulian	{ "_ng_btsocket_rfcomm_sessions" },
95107120Sjulian	{ "" },
96107120Sjulian};
97107120Sjulian
98114878Sjulian#define state2str(x) \
99114878Sjulian	(((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
100114878Sjulian
101107120Sjulian/*
102107120Sjulian * Main
103107120Sjulian */
104107120Sjulian
105121054Semaxstatic int	numeric_bdaddr = 0;
106121054Semax
107107120Sjulianint
108107120Sjulianmain(int argc, char *argv[])
109107120Sjulian{
110107120Sjulian	int	 opt, proto = -1, route = 0;
111107120Sjulian	kvm_t	*kvmd = NULL;
112107120Sjulian	char	*memf = NULL;
113107120Sjulian
114121054Semax	while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
115107120Sjulian		switch (opt) {
116121054Semax		case 'n':
117121054Semax			numeric_bdaddr = 1;
118121054Semax			break;
119121054Semax
120107120Sjulian		case 'M':
121107120Sjulian			memf = optarg;
122107120Sjulian			break;
123107120Sjulian
124107120Sjulian		case 'p':
125107120Sjulian			if (strcasecmp(optarg, "hci_raw") == 0)
126107120Sjulian				proto = N_HCI_RAW;
127107120Sjulian			else if (strcasecmp(optarg, "l2cap_raw") == 0)
128107120Sjulian				proto = N_L2CAP_RAW;
129107120Sjulian			else if (strcasecmp(optarg, "l2cap") == 0)
130107120Sjulian				proto = N_L2CAP;
131114878Sjulian			else if (strcasecmp(optarg, "rfcomm") == 0)
132114878Sjulian				proto = N_RFCOMM;
133114878Sjulian			else if (strcasecmp(optarg, "rfcomm_s") == 0)
134114878Sjulian				proto = N_RFCOMM_S;
135107120Sjulian			else
136107120Sjulian				usage();
137107120Sjulian				/* NOT REACHED */
138107120Sjulian			break;
139107120Sjulian
140107120Sjulian		case 'r':
141107120Sjulian			route = 1;
142107120Sjulian			break;
143107120Sjulian
144107120Sjulian		case 'h':
145107120Sjulian		default:
146107120Sjulian			usage();
147107120Sjulian			/* NOT REACHED */
148107120Sjulian		}
149107120Sjulian	}
150107120Sjulian
151114878Sjulian	if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
152107120Sjulian		usage();
153107120Sjulian		/* NOT REACHED */
154107120Sjulian
155114878Sjulian	/*
156114878Sjulian	 * Discard setgid privileges if not the running kernel so that
157114878Sjulian	 * bad guys can't print interesting stuff from kernel memory.
158114878Sjulian	 */
159114878Sjulian	if (memf != NULL)
160287345Sdelphij		if (setgid(getgid()) != 0)
161287345Sdelphij			err(1, "setgid");
162114878Sjulian
163107120Sjulian	kvmd = kopen(memf);
164107120Sjulian	if (kvmd == NULL)
165107120Sjulian		return (1);
166107120Sjulian
167107120Sjulian	switch (proto) {
168107120Sjulian	case N_HCI_RAW:
169107120Sjulian		hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
170107120Sjulian		break;
171107120Sjulian
172107120Sjulian	case N_L2CAP_RAW:
173107120Sjulian		if (route)
174107120Sjulian			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
175107120Sjulian		else
176107120Sjulian			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
177107120Sjulian		break;
178107120Sjulian
179107120Sjulian	case N_L2CAP:
180107120Sjulian		if (route)
181107120Sjulian			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
182107120Sjulian		else
183107120Sjulian			l2cappr(kvmd, nl[N_L2CAP].n_value);
184107120Sjulian		break;
185107120Sjulian
186114878Sjulian	case N_RFCOMM:
187114878Sjulian		rfcommpr(kvmd, nl[N_RFCOMM].n_value);
188114878Sjulian		break;
189114878Sjulian
190114878Sjulian	case N_RFCOMM_S:
191114878Sjulian		rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
192114878Sjulian		break;
193114878Sjulian
194107120Sjulian	default:
195107120Sjulian		if (route) {
196107120Sjulian			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
197107120Sjulian			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
198107120Sjulian		} else {
199107120Sjulian			hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
200107120Sjulian			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
201107120Sjulian			l2cappr(kvmd, nl[N_L2CAP].n_value);
202114878Sjulian			rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
203114878Sjulian			rfcommpr(kvmd, nl[N_RFCOMM].n_value);
204107120Sjulian		}
205107120Sjulian		break;
206107120Sjulian	}
207107120Sjulian
208107120Sjulian	return (kvm_close(kvmd));
209107120Sjulian} /* main */
210107120Sjulian
211107120Sjulian/*
212107120Sjulian * Print raw HCI sockets
213107120Sjulian */
214107120Sjulian
215107120Sjulianstatic void
216107120Sjulianhcirawpr(kvm_t *kvmd, u_long addr)
217107120Sjulian{
218107120Sjulian	ng_btsocket_hci_raw_pcb_p	this = NULL, next = NULL;
219107120Sjulian	ng_btsocket_hci_raw_pcb_t	pcb;
220107120Sjulian	struct socket			so;
221107120Sjulian	int				first = 1;
222107120Sjulian
223107120Sjulian	if (addr == 0)
224107120Sjulian		return;
225107120Sjulian
226107120Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
227107120Sjulian		return;
228107120Sjulian
229107120Sjulian	for ( ; this != NULL; this = next) {
230107120Sjulian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
231107120Sjulian			return;
232107120Sjulian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
233107120Sjulian			return;
234107120Sjulian
235107120Sjulian		next = LIST_NEXT(&pcb, next);
236107120Sjulian
237107120Sjulian		if (first) {
238107120Sjulian			first = 0;
239107120Sjulian			fprintf(stdout,
240107120Sjulian"Active raw HCI sockets\n" \
241107120Sjulian"%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
242107120Sjulian				"Socket",
243107120Sjulian				"PCB",
244107120Sjulian				"Flags",
245107120Sjulian				"Recv-Q",
246107120Sjulian				"Send-Q",
247107120Sjulian				"Local address");
248107120Sjulian		}
249107120Sjulian
250107120Sjulian		if (pcb.addr.hci_node[0] == 0) {
251107120Sjulian			pcb.addr.hci_node[0] = '*';
252107120Sjulian			pcb.addr.hci_node[1] = 0;
253107120Sjulian		}
254107120Sjulian
255107120Sjulian		fprintf(stdout,
256128076Semax"%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n",
257128076Semax			(unsigned long) pcb.so,
258128076Semax			(unsigned long) this,
259107120Sjulian			pcb.flags,
260275326Sglebius			so.so_rcv.sb_ccc,
261275326Sglebius			so.so_snd.sb_ccc,
262107120Sjulian			pcb.addr.hci_node);
263107120Sjulian	}
264107120Sjulian} /* hcirawpr */
265107120Sjulian
266107120Sjulian/*
267107120Sjulian * Print raw L2CAP sockets
268107120Sjulian */
269107120Sjulian
270107120Sjulianstatic void
271107120Sjulianl2caprawpr(kvm_t *kvmd, u_long addr)
272107120Sjulian{
273107120Sjulian	ng_btsocket_l2cap_raw_pcb_p	this = NULL, next = NULL;
274107120Sjulian	ng_btsocket_l2cap_raw_pcb_t	pcb;
275107120Sjulian	struct socket			so;
276107120Sjulian	int				first = 1;
277107120Sjulian
278107120Sjulian	if (addr == 0)
279107120Sjulian		return;
280107120Sjulian
281107120Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
282107120Sjulian		return;
283107120Sjulian
284107120Sjulian	for ( ; this != NULL; this = next) {
285107120Sjulian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
286107120Sjulian			return;
287107120Sjulian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
288107120Sjulian			return;
289107120Sjulian
290107120Sjulian		next = LIST_NEXT(&pcb, next);
291107120Sjulian
292107120Sjulian		if (first) {
293107120Sjulian			first = 0;
294107120Sjulian			fprintf(stdout,
295107120Sjulian"Active raw L2CAP sockets\n" \
296114878Sjulian"%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
297107120Sjulian				"Socket",
298107120Sjulian				"PCB",
299107120Sjulian				"Recv-Q",
300107120Sjulian				"Send-Q",
301107120Sjulian				"Local address");
302107120Sjulian		}
303107120Sjulian
304107120Sjulian		fprintf(stdout,
305128076Semax"%-8lx %-8lx %6d %6d %-17.17s\n",
306128076Semax			(unsigned long) pcb.so,
307128076Semax			(unsigned long) this,
308275326Sglebius			so.so_rcv.sb_ccc,
309275326Sglebius			so.so_snd.sb_ccc,
310121054Semax			bdaddrpr(&pcb.src, NULL, 0));
311107120Sjulian	}
312107120Sjulian} /* l2caprawpr */
313107120Sjulian
314107120Sjulian/*
315107120Sjulian * Print L2CAP sockets
316107120Sjulian */
317107120Sjulian
318107120Sjulianstatic void
319107120Sjulianl2cappr(kvm_t *kvmd, u_long addr)
320107120Sjulian{
321107120Sjulian	static char const * const	states[] = {
322107120Sjulian	/* NG_BTSOCKET_L2CAP_CLOSED */		"CLOSED",
323107120Sjulian	/* NG_BTSOCKET_L2CAP_CONNECTING */	"CON",
324107120Sjulian	/* NG_BTSOCKET_L2CAP_CONFIGURING */	"CONFIG",
325107120Sjulian	/* NG_BTSOCKET_L2CAP_OPEN */		"OPEN",
326107120Sjulian	/* NG_BTSOCKET_L2CAP_DISCONNECTING */	"DISCON"
327107120Sjulian	};
328107120Sjulian
329107120Sjulian	ng_btsocket_l2cap_pcb_p	this = NULL, next = NULL;
330107120Sjulian	ng_btsocket_l2cap_pcb_t	pcb;
331107120Sjulian	struct socket		so;
332107120Sjulian	int			first = 1;
333121054Semax	char			local[24], remote[24];
334107120Sjulian
335107120Sjulian	if (addr == 0)
336107120Sjulian		return;
337107120Sjulian
338107120Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
339107120Sjulian		return;
340107120Sjulian
341107120Sjulian	for ( ; this != NULL; this = next) {
342107120Sjulian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
343107120Sjulian			return;
344107120Sjulian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
345107120Sjulian			return;
346107120Sjulian
347107120Sjulian		next = LIST_NEXT(&pcb, next);
348107120Sjulian
349107120Sjulian		if (first) {
350107120Sjulian			first = 0;
351107120Sjulian			fprintf(stdout,
352107120Sjulian"Active L2CAP sockets\n" \
353114878Sjulian"%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
354107120Sjulian				"PCB",
355107120Sjulian				"Recv-Q",
356107120Sjulian				"Send-Q",
357107120Sjulian				"Local address/PSM",
358107120Sjulian				"Foreign address",
359107120Sjulian				"CID",
360107120Sjulian				"State");
361107120Sjulian		}
362107120Sjulian
363107120Sjulian		fprintf(stdout,
364128076Semax"%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
365128076Semax			(unsigned long) this,
366275326Sglebius			so.so_rcv.sb_ccc,
367275326Sglebius			so.so_snd.sb_ccc,
368121054Semax			bdaddrpr(&pcb.src, local, sizeof(local)),
369121054Semax			pcb.psm,
370121054Semax			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
371107120Sjulian			pcb.cid,
372107120Sjulian			(so.so_options & SO_ACCEPTCONN)?
373107120Sjulian				"LISTEN" : state2str(pcb.state));
374107120Sjulian	}
375107120Sjulian} /* l2cappr */
376107120Sjulian
377107120Sjulian/*
378107120Sjulian * Print L2CAP routing table
379107120Sjulian */
380107120Sjulian
381107120Sjulianstatic void
382107120Sjulianl2caprtpr(kvm_t *kvmd, u_long addr)
383107120Sjulian{
384107120Sjulian	ng_btsocket_l2cap_rtentry_p	this = NULL, next = NULL;
385107120Sjulian	ng_btsocket_l2cap_rtentry_t	rt;
386107120Sjulian	int				first = 1;
387107120Sjulian
388107120Sjulian	if (addr == 0)
389107120Sjulian		return;
390107120Sjulian
391107120Sjulian	if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
392107120Sjulian		return;
393107120Sjulian
394107120Sjulian	for ( ; this != NULL; this = next) {
395107120Sjulian		if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
396107120Sjulian			return;
397107120Sjulian
398107120Sjulian		next = LIST_NEXT(&rt, next);
399107120Sjulian
400107120Sjulian		if (first) {
401107120Sjulian			first = 0;
402107120Sjulian			fprintf(stdout,
403107120Sjulian"Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)?  "raw " : "");
404107120Sjulian			fprintf(stdout,
405114878Sjulian"%-8.8s %-8.8s %-17.17s\n",	"RTentry",
406107120Sjulian				"Hook",
407107120Sjulian				"BD_ADDR");
408107120Sjulian		}
409107120Sjulian
410107120Sjulian		fprintf(stdout,
411128076Semax"%-8lx %-8lx %-17.17s\n",
412128076Semax			(unsigned long) this,
413128076Semax			(unsigned long) rt.hook,
414121054Semax			bdaddrpr(&rt.src, NULL, 0));
415107120Sjulian	}
416107120Sjulian} /* l2caprtpr */
417107120Sjulian
418107120Sjulian/*
419114878Sjulian * Print RFCOMM sockets
420114878Sjulian */
421114878Sjulian
422114878Sjulianstatic void
423114878Sjulianrfcommpr(kvm_t *kvmd, u_long addr)
424114878Sjulian{
425114878Sjulian	static char const * const	states[] = {
426114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_CLOSED */	   "CLOSED",
427114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */	   "W4CON",
428114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */   "CONFIG",
429114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */    "CONN",
430114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */     "OPEN",
431114878Sjulian	/* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
432114878Sjulian	};
433114878Sjulian
434114878Sjulian	ng_btsocket_rfcomm_pcb_p	this = NULL, next = NULL;
435114878Sjulian	ng_btsocket_rfcomm_pcb_t	pcb;
436114878Sjulian	struct socket			so;
437114878Sjulian	int				first = 1;
438121054Semax	char				local[24], remote[24];
439114878Sjulian
440114878Sjulian	if (addr == 0)
441114878Sjulian		return;
442114878Sjulian
443114878Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
444114878Sjulian		return;
445114878Sjulian
446114878Sjulian	for ( ; this != NULL; this = next) {
447114878Sjulian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
448114878Sjulian			return;
449114878Sjulian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
450114878Sjulian			return;
451114878Sjulian
452114878Sjulian		next = LIST_NEXT(&pcb, next);
453114878Sjulian
454114878Sjulian		if (first) {
455114878Sjulian			first = 0;
456114878Sjulian			fprintf(stdout,
457114878Sjulian"Active RFCOMM sockets\n" \
458114878Sjulian"%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
459114878Sjulian				"PCB",
460114878Sjulian				"Recv-Q",
461114878Sjulian				"Send-Q",
462114878Sjulian				"Local address",
463114878Sjulian				"Foreign address",
464114878Sjulian				"Chan",
465114878Sjulian				"DLCI",
466114878Sjulian				"State");
467114878Sjulian		}
468114878Sjulian
469114878Sjulian		fprintf(stdout,
470128076Semax"%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
471128076Semax			(unsigned long) this,
472275326Sglebius			so.so_rcv.sb_ccc,
473275326Sglebius			so.so_snd.sb_ccc,
474121054Semax			bdaddrpr(&pcb.src, local, sizeof(local)),
475121054Semax			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
476114878Sjulian			pcb.channel,
477114878Sjulian			pcb.dlci,
478114878Sjulian			(so.so_options & SO_ACCEPTCONN)?
479114878Sjulian				"LISTEN" : state2str(pcb.state));
480114878Sjulian	}
481114878Sjulian} /* rfcommpr */
482114878Sjulian
483114878Sjulian/*
484114878Sjulian * Print RFCOMM sessions
485114878Sjulian */
486114878Sjulian
487114878Sjulianstatic void
488114878Sjulianrfcommpr_s(kvm_t *kvmd, u_long addr)
489114878Sjulian{
490114878Sjulian	static char const * const	states[] = {
491114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */	       "CLOSED",
492114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */     "LISTEN",
493114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */    "CONNECTING",
494114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */     "CONNECTED",
495114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_OPEN */          "OPEN",
496114878Sjulian	/* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
497114878Sjulian	};
498114878Sjulian
499114878Sjulian	ng_btsocket_rfcomm_session_p	this = NULL, next = NULL;
500114878Sjulian	ng_btsocket_rfcomm_session_t	s;
501114878Sjulian	struct socket			so;
502114878Sjulian	int				first = 1;
503114878Sjulian
504114878Sjulian	if (addr == 0)
505114878Sjulian		return;
506114878Sjulian
507114878Sjulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
508114878Sjulian		return;
509114878Sjulian
510114878Sjulian	for ( ; this != NULL; this = next) {
511114878Sjulian		if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
512114878Sjulian			return;
513114878Sjulian		if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
514114878Sjulian			return;
515114878Sjulian
516114878Sjulian		next = LIST_NEXT(&s, next);
517114878Sjulian
518114878Sjulian		if (first) {
519114878Sjulian			first = 0;
520114878Sjulian			fprintf(stdout,
521114878Sjulian"Active RFCOMM sessions\n" \
522114878Sjulian"%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
523114878Sjulian				"L2PCB",
524114878Sjulian				"PCB",
525114878Sjulian				"Flags",
526114878Sjulian				"MTU",
527114878Sjulian				"Out-Q",
528114878Sjulian				"DLCs",
529114878Sjulian				"State");
530114878Sjulian		}
531114878Sjulian
532114878Sjulian		fprintf(stdout,
533128076Semax"%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
534128076Semax			(unsigned long) so.so_pcb,
535128076Semax			(unsigned long) this,
536114878Sjulian			s.flags,
537114878Sjulian			s.mtu,
538114878Sjulian			s.outq.len,
539114878Sjulian			LIST_EMPTY(&s.dlcs)? "No" : "Yes",
540114878Sjulian			state2str(s.state));
541114878Sjulian	}
542114878Sjulian} /* rfcommpr_s */
543114878Sjulian
544114878Sjulian/*
545121054Semax * Return BD_ADDR as string
546121054Semax */
547121054Semax
548121054Semaxstatic char *
549121054Semaxbdaddrpr(bdaddr_p const ba, char *str, int len)
550121054Semax{
551121054Semax	static char	 buffer[MAXHOSTNAMELEN];
552121054Semax	struct hostent	*he = NULL;
553121054Semax
554121054Semax	if (str == NULL) {
555121054Semax		str = buffer;
556121054Semax		len = sizeof(buffer);
557121054Semax	}
558121054Semax
559121054Semax	if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
560121054Semax		str[0] = '*';
561121054Semax		str[1] = 0;
562121054Semax
563121054Semax		return (str);
564121054Semax	}
565121054Semax
566121054Semax	if (!numeric_bdaddr &&
567121054Semax	    (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
568121054Semax		strlcpy(str, he->h_name, len);
569121054Semax
570121054Semax		return (str);
571121054Semax	}
572121054Semax
573121054Semax	bt_ntoa(ba, str);
574121054Semax
575121054Semax	return (str);
576121054Semax} /* bdaddrpr */
577121054Semax
578121054Semax/*
579107120Sjulian * Open kvm
580107120Sjulian */
581107120Sjulian
582107120Sjulianstatic kvm_t *
583107120Sjuliankopen(char const *memf)
584107120Sjulian{
585107120Sjulian	kvm_t	*kvmd = NULL;
586107120Sjulian	char	 errbuf[_POSIX2_LINE_MAX];
587107120Sjulian
588107120Sjulian	kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
589287345Sdelphij	if (setgid(getgid()) != 0)
590287345Sdelphij		err(1, "setgid");
591107120Sjulian	if (kvmd == NULL) {
592107120Sjulian		warnx("kvm_openfiles: %s", errbuf);
593107120Sjulian		return (NULL);
594107120Sjulian	}
595107120Sjulian
596107120Sjulian	if (kvm_nlist(kvmd, nl) < 0) {
597107120Sjulian		warnx("kvm_nlist: %s", kvm_geterr(kvmd));
598107120Sjulian		goto fail;
599107120Sjulian	}
600107120Sjulian
601107120Sjulian	if (nl[0].n_type == 0) {
602107120Sjulian		warnx("kvm_nlist: no namelist");
603107120Sjulian		goto fail;
604107120Sjulian	}
605107120Sjulian
606107120Sjulian	return (kvmd);
607107120Sjulianfail:
608107120Sjulian	kvm_close(kvmd);
609107120Sjulian
610107120Sjulian	return (NULL);
611107120Sjulian} /* kopen */
612107120Sjulian
613107120Sjulian/*
614107120Sjulian * Read kvm
615107120Sjulian */
616107120Sjulian
617107120Sjulianstatic int
618107120Sjuliankread(kvm_t *kvmd, u_long addr, char *buffer, int size)
619107120Sjulian{
620107120Sjulian	if (kvmd == NULL || buffer == NULL)
621107120Sjulian		return (-1);
622107120Sjulian
623107120Sjulian	if (kvm_read(kvmd, addr, buffer, size) != size) {
624107120Sjulian		warnx("kvm_read: %s", kvm_geterr(kvmd));
625107120Sjulian		return (-1);
626107120Sjulian	}
627107120Sjulian
628107120Sjulian	return (0);
629107120Sjulian} /* kread */
630107120Sjulian
631107120Sjulian/*
632107120Sjulian * Print usage and exit
633107120Sjulian */
634107120Sjulian
635107120Sjulianstatic void
636107120Sjulianusage(void)
637107120Sjulian{
638121054Semax	fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n");
639107120Sjulian	exit(255);
640107120Sjulian} /* usage */
641107120Sjulian
642