17551d83pfg/*-
27551d83pfg * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
37551d83pfg *
4d72cb74julian * btsockstat.c
5d72cb74julian *
6d72cb74julian * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7d72cb74julian * All rights reserved.
8d72cb74julian *
9d72cb74julian * Redistribution and use in source and binary forms, with or without
10d72cb74julian * modification, are permitted provided that the following conditions
11d72cb74julian * are met:
12d72cb74julian * 1. Redistributions of source code must retain the above copyright
13d72cb74julian *    notice, this list of conditions and the following disclaimer.
14d72cb74julian * 2. Redistributions in binary form must reproduce the above copyright
15d72cb74julian *    notice, this list of conditions and the following disclaimer in the
16d72cb74julian *    documentation and/or other materials provided with the distribution.
17d72cb74julian *
18d72cb74julian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19d72cb74julian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20d72cb74julian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21d72cb74julian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22d72cb74julian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23d72cb74julian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24d72cb74julian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25d72cb74julian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26d72cb74julian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27d72cb74julian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28d72cb74julian * SUCH DAMAGE.
29d72cb74julian *
3041bb0e8emax * $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $
31d72cb74julian * $FreeBSD$
32d72cb74julian */
33d72cb74julian
34d72cb74julian#include <sys/types.h>
35d72cb74julian#include <sys/callout.h>
36d72cb74julian#include <sys/param.h>
371021fb0emax#include <sys/protosw.h>
38d72cb74julian#include <sys/queue.h>
39d72cb74julian#include <sys/socket.h>
407168facglebius#define	_WANT_SOCKET
41d72cb74julian#include <sys/socketvar.h>
42d72cb74julian
43d72cb74julian#include <net/if.h>
44d72cb74julian
45411a5fdtakawata#define L2CAP_SOCKET_CHECKED
4641bb0e8emax#include <bluetooth.h>
47d72cb74julian#include <err.h>
48d72cb74julian#include <fcntl.h>
49d72cb74julian#include <kvm.h>
50d72cb74julian#include <limits.h>
5147ef5b0bde#include <nlist.h>
52d72cb74julian
5341bb0e8emax#include <netgraph/bluetooth/include/ng_bluetooth.h>
5441bb0e8emax#include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
5541bb0e8emax#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
5641bb0e8emax#include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
57d72cb74julian
58d72cb74julian#include <stdio.h>
59d72cb74julian#include <stdlib.h>
60d72cb74julian#include <string.h>
61d72cb74julian#include <unistd.h>
62d72cb74julian
63d72cb74julianstatic void	hcirawpr   (kvm_t *kvmd, u_long addr);
64d72cb74julianstatic void	l2caprawpr (kvm_t *kvmd, u_long addr);
65d72cb74julianstatic void	l2cappr    (kvm_t *kvmd, u_long addr);
66d72cb74julianstatic void	l2caprtpr  (kvm_t *kvmd, u_long addr);
67dc5734djulianstatic void	rfcommpr   (kvm_t *kvmd, u_long addr);
68dc5734djulianstatic void	rfcommpr_s (kvm_t *kvmd, u_long addr);
69d72cb74julian
7041bb0e8emaxstatic char *	bdaddrpr   (bdaddr_p const ba, char *str, int len);
7141bb0e8emax
72d72cb74julianstatic kvm_t *	kopen      (char const *memf);
73d72cb74julianstatic int	kread      (kvm_t *kvmd, u_long addr, char *buffer, int size);
74d72cb74julian
75d72cb74julianstatic void	usage      (void);
76d72cb74julian
77d72cb74julian/*
78d72cb74julian * List of symbols
79d72cb74julian */
80d72cb74julian
81d72cb74julianstatic struct nlist	nl[] = {
82d72cb74julian#define N_HCI_RAW	0
83d72cb74julian	{ "_ng_btsocket_hci_raw_sockets" },
84d72cb74julian#define N_L2CAP_RAW	1
85d72cb74julian	{ "_ng_btsocket_l2cap_raw_sockets" },
86d72cb74julian#define N_L2CAP		2
87d72cb74julian	{ "_ng_btsocket_l2cap_sockets" },
88d72cb74julian#define N_L2CAP_RAW_RT	3
89d72cb74julian	{ "_ng_btsocket_l2cap_raw_rt" },
90d72cb74julian#define N_L2CAP_RT	4
91d72cb74julian	{ "_ng_btsocket_l2cap_rt" },
92dc5734djulian#define N_RFCOMM	5
93dc5734djulian	{ "_ng_btsocket_rfcomm_sockets" },
94dc5734djulian#define N_RFCOMM_S	6
95dc5734djulian	{ "_ng_btsocket_rfcomm_sessions" },
96d72cb74julian	{ "" },
97d72cb74julian};
98d72cb74julian
99dc5734djulian#define state2str(x) \
100dc5734djulian	(((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
101dc5734djulian
102d72cb74julian/*
103d72cb74julian * Main
104d72cb74julian */
105d72cb74julian
10641bb0e8emaxstatic int	numeric_bdaddr = 0;
10741bb0e8emax
108d72cb74julianint
109d72cb74julianmain(int argc, char *argv[])
110d72cb74julian{
111d72cb74julian	int	 opt, proto = -1, route = 0;
112d72cb74julian	kvm_t	*kvmd = NULL;
113d72cb74julian	char	*memf = NULL;
114d72cb74julian
11541bb0e8emax	while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
116d72cb74julian		switch (opt) {
11741bb0e8emax		case 'n':
11841bb0e8emax			numeric_bdaddr = 1;
11941bb0e8emax			break;
12041bb0e8emax
121d72cb74julian		case 'M':
122d72cb74julian			memf = optarg;
123d72cb74julian			break;
124d72cb74julian
125d72cb74julian		case 'p':
126d72cb74julian			if (strcasecmp(optarg, "hci_raw") == 0)
127d72cb74julian				proto = N_HCI_RAW;
128d72cb74julian			else if (strcasecmp(optarg, "l2cap_raw") == 0)
129d72cb74julian				proto = N_L2CAP_RAW;
130d72cb74julian			else if (strcasecmp(optarg, "l2cap") == 0)
131d72cb74julian				proto = N_L2CAP;
132dc5734djulian			else if (strcasecmp(optarg, "rfcomm") == 0)
133dc5734djulian				proto = N_RFCOMM;
134dc5734djulian			else if (strcasecmp(optarg, "rfcomm_s") == 0)
135dc5734djulian				proto = N_RFCOMM_S;
136d72cb74julian			else
137d72cb74julian				usage();
138d72cb74julian				/* NOT REACHED */
139d72cb74julian			break;
140d72cb74julian
141d72cb74julian		case 'r':
142d72cb74julian			route = 1;
143d72cb74julian			break;
144d72cb74julian
145d72cb74julian		case 'h':
146d72cb74julian		default:
147d72cb74julian			usage();
148d72cb74julian			/* NOT REACHED */
149d72cb74julian		}
150d72cb74julian	}
151d72cb74julian
152dc5734djulian	if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
153d72cb74julian		usage();
154d72cb74julian		/* NOT REACHED */
155d72cb74julian
156dc5734djulian	/*
157dc5734djulian	 * Discard setgid privileges if not the running kernel so that
158dc5734djulian	 * bad guys can't print interesting stuff from kernel memory.
159dc5734djulian	 */
160dc5734djulian	if (memf != NULL)
161061b55cdelphij		if (setgid(getgid()) != 0)
162061b55cdelphij			err(1, "setgid");
163dc5734djulian
164d72cb74julian	kvmd = kopen(memf);
165d72cb74julian	if (kvmd == NULL)
166d72cb74julian		return (1);
167d72cb74julian
168d72cb74julian	switch (proto) {
169d72cb74julian	case N_HCI_RAW:
170d72cb74julian		hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
171d72cb74julian		break;
172d72cb74julian
173d72cb74julian	case N_L2CAP_RAW:
174d72cb74julian		if (route)
175d72cb74julian			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
176d72cb74julian		else
177d72cb74julian			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
178d72cb74julian		break;
179d72cb74julian
180d72cb74julian	case N_L2CAP:
181d72cb74julian		if (route)
182d72cb74julian			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
183d72cb74julian		else
184d72cb74julian			l2cappr(kvmd, nl[N_L2CAP].n_value);
185d72cb74julian		break;
186d72cb74julian
187dc5734djulian	case N_RFCOMM:
188dc5734djulian		rfcommpr(kvmd, nl[N_RFCOMM].n_value);
189dc5734djulian		break;
190dc5734djulian
191dc5734djulian	case N_RFCOMM_S:
192dc5734djulian		rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
193dc5734djulian		break;
194dc5734djulian
195d72cb74julian	default:
196d72cb74julian		if (route) {
197d72cb74julian			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
198d72cb74julian			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
199d72cb74julian		} else {
200d72cb74julian			hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
201d72cb74julian			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
202d72cb74julian			l2cappr(kvmd, nl[N_L2CAP].n_value);
203dc5734djulian			rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
204dc5734djulian			rfcommpr(kvmd, nl[N_RFCOMM].n_value);
205d72cb74julian		}
206d72cb74julian		break;
207d72cb74julian	}
208d72cb74julian
209d72cb74julian	return (kvm_close(kvmd));
210d72cb74julian} /* main */
211d72cb74julian
212d72cb74julian/*
213d72cb74julian * Print raw HCI sockets
214d72cb74julian */
215d72cb74julian
216d72cb74julianstatic void
217d72cb74julianhcirawpr(kvm_t *kvmd, u_long addr)
218d72cb74julian{
219d72cb74julian	ng_btsocket_hci_raw_pcb_p	this = NULL, next = NULL;
220d72cb74julian	ng_btsocket_hci_raw_pcb_t	pcb;
221d72cb74julian	struct socket			so;
222d72cb74julian	int				first = 1;
223d72cb74julian
224d72cb74julian	if (addr == 0)
225d72cb74julian		return;
226d72cb74julian
227d72cb74julian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
228d72cb74julian		return;
229d72cb74julian
230d72cb74julian	for ( ; this != NULL; this = next) {
231d72cb74julian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
232d72cb74julian			return;
233d72cb74julian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
234d72cb74julian			return;
235d72cb74julian
236d72cb74julian		next = LIST_NEXT(&pcb, next);
237d72cb74julian
238d72cb74julian		if (first) {
239d72cb74julian			first = 0;
240d72cb74julian			fprintf(stdout,
241d72cb74julian"Active raw HCI sockets\n" \
242d72cb74julian"%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
243d72cb74julian				"Socket",
244d72cb74julian				"PCB",
245d72cb74julian				"Flags",
246d72cb74julian				"Recv-Q",
247d72cb74julian				"Send-Q",
248d72cb74julian				"Local address");
249d72cb74julian		}
250d72cb74julian
251d72cb74julian		if (pcb.addr.hci_node[0] == 0) {
252d72cb74julian			pcb.addr.hci_node[0] = '*';
253d72cb74julian			pcb.addr.hci_node[1] = 0;
254d72cb74julian		}
255d72cb74julian
256d72cb74julian		fprintf(stdout,
2573513d3aemax"%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n",
2583513d3aemax			(unsigned long) pcb.so,
2593513d3aemax			(unsigned long) this,
260d72cb74julian			pcb.flags,
26125da94eglebius			so.so_rcv.sb_ccc,
26225da94eglebius			so.so_snd.sb_ccc,
263d72cb74julian			pcb.addr.hci_node);
264d72cb74julian	}
265d72cb74julian} /* hcirawpr */
266d72cb74julian
267d72cb74julian/*
268d72cb74julian * Print raw L2CAP sockets
269d72cb74julian */
270d72cb74julian
271d72cb74julianstatic void
272d72cb74julianl2caprawpr(kvm_t *kvmd, u_long addr)
273d72cb74julian{
274d72cb74julian	ng_btsocket_l2cap_raw_pcb_p	this = NULL, next = NULL;
275d72cb74julian	ng_btsocket_l2cap_raw_pcb_t	pcb;
276d72cb74julian	struct socket			so;
277d72cb74julian	int				first = 1;
278d72cb74julian
279d72cb74julian	if (addr == 0)
280d72cb74julian		return;
281d72cb74julian
282d72cb74julian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
283d72cb74julian		return;
284d72cb74julian
285d72cb74julian	for ( ; this != NULL; this = next) {
286d72cb74julian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
287d72cb74julian			return;
288d72cb74julian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
289d72cb74julian			return;
290d72cb74julian
291d72cb74julian		next = LIST_NEXT(&pcb, next);
292d72cb74julian
293d72cb74julian		if (first) {
294d72cb74julian			first = 0;
295d72cb74julian			fprintf(stdout,
296d72cb74julian"Active raw L2CAP sockets\n" \
297dc5734djulian"%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
298d72cb74julian				"Socket",
299d72cb74julian				"PCB",
300d72cb74julian				"Recv-Q",
301d72cb74julian				"Send-Q",
302d72cb74julian				"Local address");
303d72cb74julian		}
304d72cb74julian
305d72cb74julian		fprintf(stdout,
3063513d3aemax"%-8lx %-8lx %6d %6d %-17.17s\n",
3073513d3aemax			(unsigned long) pcb.so,
3083513d3aemax			(unsigned long) this,
30925da94eglebius			so.so_rcv.sb_ccc,
31025da94eglebius			so.so_snd.sb_ccc,
31141bb0e8emax			bdaddrpr(&pcb.src, NULL, 0));
312d72cb74julian	}
313d72cb74julian} /* l2caprawpr */
314d72cb74julian
315d72cb74julian/*
316d72cb74julian * Print L2CAP sockets
317d72cb74julian */
318d72cb74julian
319d72cb74julianstatic void
320d72cb74julianl2cappr(kvm_t *kvmd, u_long addr)
321d72cb74julian{
322d72cb74julian	static char const * const	states[] = {
323d72cb74julian	/* NG_BTSOCKET_L2CAP_CLOSED */		"CLOSED",
324d72cb74julian	/* NG_BTSOCKET_L2CAP_CONNECTING */	"CON",
325d72cb74julian	/* NG_BTSOCKET_L2CAP_CONFIGURING */	"CONFIG",
326d72cb74julian	/* NG_BTSOCKET_L2CAP_OPEN */		"OPEN",
327d72cb74julian	/* NG_BTSOCKET_L2CAP_DISCONNECTING */	"DISCON"
328d72cb74julian	};
329d72cb74julian
330d72cb74julian	ng_btsocket_l2cap_pcb_p	this = NULL, next = NULL;
331d72cb74julian	ng_btsocket_l2cap_pcb_t	pcb;
332d72cb74julian	struct socket		so;
333d72cb74julian	int			first = 1;
33441bb0e8emax	char			local[24], remote[24];
335d72cb74julian
336d72cb74julian	if (addr == 0)
337d72cb74julian		return;
338d72cb74julian
339d72cb74julian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
340d72cb74julian		return;
341d72cb74julian
342d72cb74julian	for ( ; this != NULL; this = next) {
343d72cb74julian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
344d72cb74julian			return;
345d72cb74julian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
346d72cb74julian			return;
347d72cb74julian
348d72cb74julian		next = LIST_NEXT(&pcb, next);
349d72cb74julian
350d72cb74julian		if (first) {
351d72cb74julian			first = 0;
352d72cb74julian			fprintf(stdout,
353d72cb74julian"Active L2CAP sockets\n" \
354dc5734djulian"%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
355d72cb74julian				"PCB",
356d72cb74julian				"Recv-Q",
357d72cb74julian				"Send-Q",
358d72cb74julian				"Local address/PSM",
359d72cb74julian				"Foreign address",
360d72cb74julian				"CID",
361d72cb74julian				"State");
362d72cb74julian		}
363d72cb74julian
364d72cb74julian		fprintf(stdout,
3653513d3aemax"%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
3663513d3aemax			(unsigned long) this,
36725da94eglebius			so.so_rcv.sb_ccc,
36825da94eglebius			so.so_snd.sb_ccc,
36941bb0e8emax			bdaddrpr(&pcb.src, local, sizeof(local)),
37041bb0e8emax			pcb.psm,
37141bb0e8emax			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
372d72cb74julian			pcb.cid,
373d72cb74julian			(so.so_options & SO_ACCEPTCONN)?
374d72cb74julian				"LISTEN" : state2str(pcb.state));
375d72cb74julian	}
376d72cb74julian} /* l2cappr */
377d72cb74julian
378d72cb74julian/*
379d72cb74julian * Print L2CAP routing table
380d72cb74julian */
381d72cb74julian
382d72cb74julianstatic void
383d72cb74julianl2caprtpr(kvm_t *kvmd, u_long addr)
384d72cb74julian{
385d72cb74julian	ng_btsocket_l2cap_rtentry_p	this = NULL, next = NULL;
386d72cb74julian	ng_btsocket_l2cap_rtentry_t	rt;
387d72cb74julian	int				first = 1;
388d72cb74julian
389d72cb74julian	if (addr == 0)
390d72cb74julian		return;
391d72cb74julian
392d72cb74julian	if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
393d72cb74julian		return;
394d72cb74julian
395d72cb74julian	for ( ; this != NULL; this = next) {
396d72cb74julian		if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
397d72cb74julian			return;
398d72cb74julian
399d72cb74julian		next = LIST_NEXT(&rt, next);
400d72cb74julian
401d72cb74julian		if (first) {
402d72cb74julian			first = 0;
403d72cb74julian			fprintf(stdout,
404d72cb74julian"Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)?  "raw " : "");
405d72cb74julian			fprintf(stdout,
406dc5734djulian"%-8.8s %-8.8s %-17.17s\n",	"RTentry",
407d72cb74julian				"Hook",
408d72cb74julian				"BD_ADDR");
409d72cb74julian		}
410d72cb74julian
411d72cb74julian		fprintf(stdout,
4123513d3aemax"%-8lx %-8lx %-17.17s\n",
4133513d3aemax			(unsigned long) this,
4143513d3aemax			(unsigned long) rt.hook,
41541bb0e8emax			bdaddrpr(&rt.src, NULL, 0));
416d72cb74julian	}
417d72cb74julian} /* l2caprtpr */
418d72cb74julian
419d72cb74julian/*
420dc5734djulian * Print RFCOMM sockets
421dc5734djulian */
422dc5734djulian
423dc5734djulianstatic void
424dc5734djulianrfcommpr(kvm_t *kvmd, u_long addr)
425dc5734djulian{
426dc5734djulian	static char const * const	states[] = {
427dc5734djulian	/* NG_BTSOCKET_RFCOMM_DLC_CLOSED */	   "CLOSED",
428dc5734djulian	/* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */	   "W4CON",
429dc5734djulian	/* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */   "CONFIG",
430dc5734djulian	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */    "CONN",
431dc5734djulian	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */     "OPEN",
432dc5734djulian	/* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
433dc5734djulian	};
434dc5734djulian
435dc5734djulian	ng_btsocket_rfcomm_pcb_p	this = NULL, next = NULL;
436dc5734djulian	ng_btsocket_rfcomm_pcb_t	pcb;
437dc5734djulian	struct socket			so;
438dc5734djulian	int				first = 1;
43941bb0e8emax	char				local[24], remote[24];
440dc5734djulian
441dc5734djulian	if (addr == 0)
442dc5734djulian		return;
443dc5734djulian
444dc5734djulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
445dc5734djulian		return;
446dc5734djulian
447dc5734djulian	for ( ; this != NULL; this = next) {
448dc5734djulian		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
449dc5734djulian			return;
450dc5734djulian		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
451dc5734djulian			return;
452dc5734djulian
453dc5734djulian		next = LIST_NEXT(&pcb, next);
454dc5734djulian
455dc5734djulian		if (first) {
456dc5734djulian			first = 0;
457dc5734djulian			fprintf(stdout,
458dc5734djulian"Active RFCOMM sockets\n" \
459dc5734djulian"%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
460dc5734djulian				"PCB",
461dc5734djulian				"Recv-Q",
462dc5734djulian				"Send-Q",
463dc5734djulian				"Local address",
464dc5734djulian				"Foreign address",
465dc5734djulian				"Chan",
466dc5734djulian				"DLCI",
467dc5734djulian				"State");
468dc5734djulian		}
469dc5734djulian
470dc5734djulian		fprintf(stdout,
4713513d3aemax"%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
4723513d3aemax			(unsigned long) this,
47325da94eglebius			so.so_rcv.sb_ccc,
47425da94eglebius			so.so_snd.sb_ccc,
47541bb0e8emax			bdaddrpr(&pcb.src, local, sizeof(local)),
47641bb0e8emax			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
477dc5734djulian			pcb.channel,
478dc5734djulian			pcb.dlci,
479dc5734djulian			(so.so_options & SO_ACCEPTCONN)?
480dc5734djulian				"LISTEN" : state2str(pcb.state));
481dc5734djulian	}
482dc5734djulian} /* rfcommpr */
483dc5734djulian
484dc5734djulian/*
485dc5734djulian * Print RFCOMM sessions
486dc5734djulian */
487dc5734djulian
488dc5734djulianstatic void
489dc5734djulianrfcommpr_s(kvm_t *kvmd, u_long addr)
490dc5734djulian{
491dc5734djulian	static char const * const	states[] = {
492dc5734djulian	/* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */	       "CLOSED",
493dc5734djulian	/* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */     "LISTEN",
494dc5734djulian	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */    "CONNECTING",
495dc5734djulian	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */     "CONNECTED",
496dc5734djulian	/* NG_BTSOCKET_RFCOMM_SESSION_OPEN */          "OPEN",
497dc5734djulian	/* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
498dc5734djulian	};
499dc5734djulian
500dc5734djulian	ng_btsocket_rfcomm_session_p	this = NULL, next = NULL;
501dc5734djulian	ng_btsocket_rfcomm_session_t	s;
502dc5734djulian	struct socket			so;
503dc5734djulian	int				first = 1;
504dc5734djulian
505dc5734djulian	if (addr == 0)
506dc5734djulian		return;
507dc5734djulian
508dc5734djulian        if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
509dc5734djulian		return;
510dc5734djulian
511dc5734djulian	for ( ; this != NULL; this = next) {
512dc5734djulian		if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
513dc5734djulian			return;
514dc5734djulian		if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
515dc5734djulian			return;
516dc5734djulian
517dc5734djulian		next = LIST_NEXT(&s, next);
518dc5734djulian
519dc5734djulian		if (first) {
520dc5734djulian			first = 0;
521dc5734djulian			fprintf(stdout,
522dc5734djulian"Active RFCOMM sessions\n" \
523dc5734djulian"%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
524dc5734djulian				"L2PCB",
525dc5734djulian				"PCB",
526dc5734djulian				"Flags",
527dc5734djulian				"MTU",
528dc5734djulian				"Out-Q",
529dc5734djulian				"DLCs",
530dc5734djulian				"State");
531dc5734djulian		}
532dc5734djulian
533dc5734djulian		fprintf(stdout,
5343513d3aemax"%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
5353513d3aemax			(unsigned long) so.so_pcb,
5363513d3aemax			(unsigned long) this,
537dc5734djulian			s.flags,
538dc5734djulian			s.mtu,
539dc5734djulian			s.outq.len,
540dc5734djulian			LIST_EMPTY(&s.dlcs)? "No" : "Yes",
541dc5734djulian			state2str(s.state));
542dc5734djulian	}
543dc5734djulian} /* rfcommpr_s */
544dc5734djulian
545dc5734djulian/*
54641bb0e8emax * Return BD_ADDR as string
54741bb0e8emax */
54841bb0e8emax
54941bb0e8emaxstatic char *
55041bb0e8emaxbdaddrpr(bdaddr_p const ba, char *str, int len)
55141bb0e8emax{
55241bb0e8emax	static char	 buffer[MAXHOSTNAMELEN];
55341bb0e8emax	struct hostent	*he = NULL;
55441bb0e8emax
55541bb0e8emax	if (str == NULL) {
55641bb0e8emax		str = buffer;
55741bb0e8emax		len = sizeof(buffer);
55841bb0e8emax	}
55941bb0e8emax
56041bb0e8emax	if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
56141bb0e8emax		str[0] = '*';
56241bb0e8emax		str[1] = 0;
56341bb0e8emax
56441bb0e8emax		return (str);
56541bb0e8emax	}
56641bb0e8emax
56741bb0e8emax	if (!numeric_bdaddr &&
56841bb0e8emax	    (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
56941bb0e8emax		strlcpy(str, he->h_name, len);
57041bb0e8emax
57141bb0e8emax		return (str);
57241bb0e8emax	}
57341bb0e8emax
57441bb0e8emax	bt_ntoa(ba, str);
57541bb0e8emax
57641bb0e8emax	return (str);
57741bb0e8emax} /* bdaddrpr */
57841bb0e8emax
57941bb0e8emax/*
580d72cb74julian * Open kvm
581d72cb74julian */
582d72cb74julian
583d72cb74julianstatic kvm_t *
584d72cb74juliankopen(char const *memf)
585d72cb74julian{
586d72cb74julian	kvm_t	*kvmd = NULL;
587d72cb74julian	char	 errbuf[_POSIX2_LINE_MAX];
588d72cb74julian
589d72cb74julian	kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
590061b55cdelphij	if (setgid(getgid()) != 0)
591061b55cdelphij		err(1, "setgid");
592d72cb74julian	if (kvmd == NULL) {
593d72cb74julian		warnx("kvm_openfiles: %s", errbuf);
594d72cb74julian		return (NULL);
595d72cb74julian	}
596d72cb74julian
597d72cb74julian	if (kvm_nlist(kvmd, nl) < 0) {
598d72cb74julian		warnx("kvm_nlist: %s", kvm_geterr(kvmd));
599d72cb74julian		goto fail;
600d72cb74julian	}
601d72cb74julian
602d72cb74julian	if (nl[0].n_type == 0) {
603d72cb74julian		warnx("kvm_nlist: no namelist");
604d72cb74julian		goto fail;
605d72cb74julian	}
606d72cb74julian
607d72cb74julian	return (kvmd);
608d72cb74julianfail:
609d72cb74julian	kvm_close(kvmd);
610d72cb74julian
611d72cb74julian	return (NULL);
612d72cb74julian} /* kopen */
613d72cb74julian
614d72cb74julian/*
615d72cb74julian * Read kvm
616d72cb74julian */
617d72cb74julian
618d72cb74julianstatic int
619d72cb74juliankread(kvm_t *kvmd, u_long addr, char *buffer, int size)
620d72cb74julian{
621d72cb74julian	if (kvmd == NULL || buffer == NULL)
622d72cb74julian		return (-1);
623d72cb74julian
624d72cb74julian	if (kvm_read(kvmd, addr, buffer, size) != size) {
625d72cb74julian		warnx("kvm_read: %s", kvm_geterr(kvmd));
626d72cb74julian		return (-1);
627d72cb74julian	}
628d72cb74julian
629d72cb74julian	return (0);
630d72cb74julian} /* kread */
631d72cb74julian
632d72cb74