xref: /freebsd/usr.bin/bluetooth/btsockstat/btsockstat.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
1 /*
2  * btsockstat.c
3  *
4  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $Id: btsockstat.c,v 1.4 2003/03/29 22:28:18 max Exp $
29  * $FreeBSD$
30  */
31 
32 #include <sys/types.h>
33 #include <sys/callout.h>
34 #include <sys/param.h>
35 #include <sys/queue.h>
36 #include <sys/socket.h>
37 #include <sys/socketvar.h>
38 
39 #include <net/if.h>
40 #include <net/if_var.h>
41 
42 #include <bitstring.h>
43 #include <err.h>
44 #include <fcntl.h>
45 #include <kvm.h>
46 #include <limits.h>
47 
48 #include <ng_bluetooth.h>
49 #include <ng_hci.h>
50 #include <ng_l2cap.h>
51 #include <ng_btsocket.h>
52 #include <ng_btsocket_hci_raw.h>
53 #include <ng_btsocket_l2cap.h>
54 #include <ng_btsocket_rfcomm.h>
55 
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60 
61 static void	hcirawpr   (kvm_t *kvmd, u_long addr);
62 static void	l2caprawpr (kvm_t *kvmd, u_long addr);
63 static void	l2cappr    (kvm_t *kvmd, u_long addr);
64 static void	l2caprtpr  (kvm_t *kvmd, u_long addr);
65 static void	rfcommpr   (kvm_t *kvmd, u_long addr);
66 static void	rfcommpr_s (kvm_t *kvmd, u_long addr);
67 
68 static kvm_t *	kopen      (char const *memf);
69 static int	kread      (kvm_t *kvmd, u_long addr, char *buffer, int size);
70 
71 static void	usage      (void);
72 
73 /*
74  * List of symbols
75  */
76 
77 static struct nlist	nl[] = {
78 #define N_HCI_RAW	0
79 	{ "_ng_btsocket_hci_raw_sockets" },
80 #define N_L2CAP_RAW	1
81 	{ "_ng_btsocket_l2cap_raw_sockets" },
82 #define N_L2CAP		2
83 	{ "_ng_btsocket_l2cap_sockets" },
84 #define N_L2CAP_RAW_RT	3
85 	{ "_ng_btsocket_l2cap_raw_rt" },
86 #define N_L2CAP_RT	4
87 	{ "_ng_btsocket_l2cap_rt" },
88 #define N_RFCOMM	5
89 	{ "_ng_btsocket_rfcomm_sockets" },
90 #define N_RFCOMM_S	6
91 	{ "_ng_btsocket_rfcomm_sessions" },
92 	{ "" },
93 };
94 
95 #define state2str(x) \
96 	(((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
97 
98 /*
99  * Main
100  */
101 
102 int
103 main(int argc, char *argv[])
104 {
105 	int	 opt, proto = -1, route = 0;
106 	kvm_t	*kvmd = NULL;
107 	char	*memf = NULL;
108 
109 	while ((opt = getopt(argc, argv, "hM:p:r")) != -1) {
110 		switch (opt) {
111 		case 'M':
112 			memf = optarg;
113 			break;
114 
115 		case 'p':
116 			if (strcasecmp(optarg, "hci_raw") == 0)
117 				proto = N_HCI_RAW;
118 			else if (strcasecmp(optarg, "l2cap_raw") == 0)
119 				proto = N_L2CAP_RAW;
120 			else if (strcasecmp(optarg, "l2cap") == 0)
121 				proto = N_L2CAP;
122 			else if (strcasecmp(optarg, "rfcomm") == 0)
123 				proto = N_RFCOMM;
124 			else if (strcasecmp(optarg, "rfcomm_s") == 0)
125 				proto = N_RFCOMM_S;
126 			else
127 				usage();
128 				/* NOT REACHED */
129 			break;
130 
131 		case 'r':
132 			route = 1;
133 			break;
134 
135 		case 'h':
136 		default:
137 			usage();
138 			/* NOT REACHED */
139 		}
140 	}
141 
142 	if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
143 		usage();
144 		/* NOT REACHED */
145 
146 	/*
147 	 * Discard setgid privileges if not the running kernel so that
148 	 * bad guys can't print interesting stuff from kernel memory.
149 	 */
150 
151 	if (memf != NULL)
152 		setgid(getgid());
153 
154 	kvmd = kopen(memf);
155 	if (kvmd == NULL)
156 		return (1);
157 
158 	switch (proto) {
159 	case N_HCI_RAW:
160 		hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
161 		break;
162 
163 	case N_L2CAP_RAW:
164 		if (route)
165 			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
166 		else
167 			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
168 		break;
169 
170 	case N_L2CAP:
171 		if (route)
172 			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
173 		else
174 			l2cappr(kvmd, nl[N_L2CAP].n_value);
175 		break;
176 
177 	case N_RFCOMM:
178 		rfcommpr(kvmd, nl[N_RFCOMM].n_value);
179 		break;
180 
181 	case N_RFCOMM_S:
182 		rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
183 		break;
184 
185 	default:
186 		if (route) {
187 			l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
188 			l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
189 		} else {
190 			hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
191 			l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
192 			l2cappr(kvmd, nl[N_L2CAP].n_value);
193 			rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
194 			rfcommpr(kvmd, nl[N_RFCOMM].n_value);
195 		}
196 		break;
197 	}
198 
199 	return (kvm_close(kvmd));
200 } /* main */
201 
202 /*
203  * Print raw HCI sockets
204  */
205 
206 static void
207 hcirawpr(kvm_t *kvmd, u_long addr)
208 {
209 	ng_btsocket_hci_raw_pcb_p	this = NULL, next = NULL;
210 	ng_btsocket_hci_raw_pcb_t	pcb;
211 	struct socket			so;
212 	int				first = 1;
213 
214 	if (addr == 0)
215 		return;
216 
217         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
218 		return;
219 
220 	for ( ; this != NULL; this = next) {
221 		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
222 			return;
223 		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
224 			return;
225 
226 		next = LIST_NEXT(&pcb, next);
227 
228 		if (first) {
229 			first = 0;
230 			fprintf(stdout,
231 "Active raw HCI sockets\n" \
232 "%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
233 				"Socket",
234 				"PCB",
235 				"Flags",
236 				"Recv-Q",
237 				"Send-Q",
238 				"Local address");
239 		}
240 
241 		if (pcb.addr.hci_node[0] == 0) {
242 			pcb.addr.hci_node[0] = '*';
243 			pcb.addr.hci_node[1] = 0;
244 		}
245 
246 		fprintf(stdout,
247 "%-8.8x %-8.8x %-6.6x %6d %6d %-16.16s\n",
248 			(int) pcb.so,
249 			(int) this,
250 			pcb.flags,
251 			so.so_rcv.sb_cc,
252 			so.so_snd.sb_cc,
253 			pcb.addr.hci_node);
254 	}
255 } /* hcirawpr */
256 
257 /*
258  * Print raw L2CAP sockets
259  */
260 
261 static void
262 l2caprawpr(kvm_t *kvmd, u_long addr)
263 {
264 	ng_btsocket_l2cap_raw_pcb_p	this = NULL, next = NULL;
265 	ng_btsocket_l2cap_raw_pcb_t	pcb;
266 	struct socket			so;
267 	int				first = 1;
268 	char				bdaddr[32];
269 
270 	if (addr == 0)
271 		return;
272 
273         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
274 		return;
275 
276 	for ( ; this != NULL; this = next) {
277 		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
278 			return;
279 		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
280 			return;
281 
282 		next = LIST_NEXT(&pcb, next);
283 
284 		if (first) {
285 			first = 0;
286 			fprintf(stdout,
287 "Active raw L2CAP sockets\n" \
288 "%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
289 				"Socket",
290 				"PCB",
291 				"Recv-Q",
292 				"Send-Q",
293 				"Local address");
294 		}
295 
296 		if (memcmp(&pcb.src, NG_HCI_BDADDR_ANY, sizeof(pcb.src)) == 0) {
297 			bdaddr[0] = '*';
298 			bdaddr[1] = 0;
299 		} else
300 			snprintf(bdaddr, sizeof(bdaddr),
301 "%02x:%02x:%02x:%02x:%02x:%02x",
302 				pcb.src.b[5], pcb.src.b[4], pcb.src.b[3],
303 				pcb.src.b[2], pcb.src.b[1], pcb.src.b[0]);
304 
305 		fprintf(stdout,
306 "%-8.8x %-8.8x %6d %6d %-17.17s\n",
307 			(int) pcb.so,
308 			(int) this,
309 			so.so_rcv.sb_cc,
310 			so.so_snd.sb_cc,
311 			bdaddr);
312 	}
313 } /* l2caprawpr */
314 
315 /*
316  * Print L2CAP sockets
317  */
318 
319 static void
320 l2cappr(kvm_t *kvmd, u_long addr)
321 {
322 	static char const * const	states[] = {
323 	/* NG_BTSOCKET_L2CAP_CLOSED */		"CLOSED",
324 	/* NG_BTSOCKET_L2CAP_CONNECTING */	"CON",
325 	/* NG_BTSOCKET_L2CAP_CONFIGURING */	"CONFIG",
326 	/* NG_BTSOCKET_L2CAP_OPEN */		"OPEN",
327 	/* NG_BTSOCKET_L2CAP_DISCONNECTING */	"DISCON"
328 	};
329 
330 	ng_btsocket_l2cap_pcb_p	this = NULL, next = NULL;
331 	ng_btsocket_l2cap_pcb_t	pcb;
332 	struct socket		so;
333 	int			first = 1;
334 	char			local[32], remote[32];
335 
336 	if (addr == 0)
337 		return;
338 
339         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
340 		return;
341 
342 	for ( ; this != NULL; this = next) {
343 		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
344 			return;
345 		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
346 			return;
347 
348 		next = LIST_NEXT(&pcb, next);
349 
350 		if (first) {
351 			first = 0;
352 			fprintf(stdout,
353 "Active L2CAP sockets\n" \
354 "%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
355 				"PCB",
356 				"Recv-Q",
357 				"Send-Q",
358 				"Local address/PSM",
359 				"Foreign address",
360 				"CID",
361 				"State");
362 		}
363 
364 		if (memcmp(&pcb.src, NG_HCI_BDADDR_ANY, sizeof(pcb.src)) == 0)
365 			snprintf(local, sizeof(local), "*/%d", pcb.psm);
366 		else
367 			snprintf(local, sizeof(local),
368 "%02x:%02x:%02x:%02x:%02x:%02x/%d",
369 				pcb.src.b[5], pcb.src.b[4], pcb.src.b[3],
370 				pcb.src.b[2], pcb.src.b[1], pcb.src.b[0],
371 				pcb.psm);
372 
373 		if (memcmp(&pcb.dst, NG_HCI_BDADDR_ANY, sizeof(pcb.dst)) == 0) {
374 			remote[0] = '*';
375 			remote[1] = 0;
376 		} else
377 			snprintf(remote, sizeof(remote),
378 "%02x:%02x:%02x:%02x:%02x:%02x",
379 				pcb.dst.b[5], pcb.dst.b[4], pcb.dst.b[3],
380 				pcb.dst.b[2], pcb.dst.b[1], pcb.dst.b[0]);
381 
382 		fprintf(stdout,
383 "%-8.8x %6d %6d %-23.23s %-17.17s %-5d %s\n",
384 			(int) this,
385 			so.so_rcv.sb_cc,
386 			so.so_snd.sb_cc,
387 			local,
388 			remote,
389 			pcb.cid,
390 			(so.so_options & SO_ACCEPTCONN)?
391 				"LISTEN" : state2str(pcb.state));
392 	}
393 } /* l2cappr */
394 
395 /*
396  * Print L2CAP routing table
397  */
398 
399 static void
400 l2caprtpr(kvm_t *kvmd, u_long addr)
401 {
402 	ng_btsocket_l2cap_rtentry_p	this = NULL, next = NULL;
403 	ng_btsocket_l2cap_rtentry_t	rt;
404 	int				first = 1;
405 	char				bdaddr[32];
406 
407 	if (addr == 0)
408 		return;
409 
410 	if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
411 		return;
412 
413 	for ( ; this != NULL; this = next) {
414 		if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
415 			return;
416 
417 		next = LIST_NEXT(&rt, next);
418 
419 		if (first) {
420 			first = 0;
421 			fprintf(stdout,
422 "Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)?  "raw " : "");
423 			fprintf(stdout,
424 "%-8.8s %-8.8s %-17.17s\n",	"RTentry",
425 				"Hook",
426 				"BD_ADDR");
427 		}
428 
429 		if (memcmp(&rt.src, NG_HCI_BDADDR_ANY, sizeof(rt.src)) == 0) {
430 			bdaddr[0] = '-';
431 			bdaddr[1] = 0;
432 		} else
433 			snprintf(bdaddr, sizeof(bdaddr),
434 "%02x:%02x:%02x:%02x:%02x:%02x", rt.src.b[5], rt.src.b[4], rt.src.b[3],
435 				 rt.src.b[2], rt.src.b[1], rt.src.b[0]);
436 
437 		fprintf(stdout,
438 "%-8.8x %-8.8x %-17.17s\n",
439 			(int) this,
440 			(int) rt.hook,
441 			bdaddr);
442 	}
443 } /* l2caprtpr */
444 
445 /*
446  * Print RFCOMM sockets
447  */
448 
449 static void
450 rfcommpr(kvm_t *kvmd, u_long addr)
451 {
452 	static char const * const	states[] = {
453 	/* NG_BTSOCKET_RFCOMM_DLC_CLOSED */	   "CLOSED",
454 	/* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */	   "W4CON",
455 	/* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */   "CONFIG",
456 	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */    "CONN",
457 	/* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */     "OPEN",
458 	/* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
459 	};
460 
461 	ng_btsocket_rfcomm_pcb_p	this = NULL, next = NULL;
462 	ng_btsocket_rfcomm_pcb_t	pcb;
463 	struct socket			so;
464 	int				first = 1;
465 	char				local[32], remote[32];
466 
467 	if (addr == 0)
468 		return;
469 
470         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
471 		return;
472 
473 	for ( ; this != NULL; this = next) {
474 		if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
475 			return;
476 		if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
477 			return;
478 
479 		next = LIST_NEXT(&pcb, next);
480 
481 		if (first) {
482 			first = 0;
483 			fprintf(stdout,
484 "Active RFCOMM sockets\n" \
485 "%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
486 				"PCB",
487 				"Recv-Q",
488 				"Send-Q",
489 				"Local address",
490 				"Foreign address",
491 				"Chan",
492 				"DLCI",
493 				"State");
494 		}
495 
496 		if (memcmp(&pcb.src, NG_HCI_BDADDR_ANY, sizeof(pcb.src)) == 0) {
497 			local[0] = '*';
498 			local[1] = 0;
499 		} else
500 			snprintf(local, sizeof(local),
501 "%02x:%02x:%02x:%02x:%02x:%02x",
502 				pcb.src.b[5], pcb.src.b[4], pcb.src.b[3],
503 				pcb.src.b[2], pcb.src.b[1], pcb.src.b[0]);
504 
505 		if (memcmp(&pcb.dst, NG_HCI_BDADDR_ANY, sizeof(pcb.dst)) == 0) {
506 			remote[0] = '*';
507 			remote[1] = 0;
508 		} else
509 			snprintf(remote, sizeof(remote),
510 "%02x:%02x:%02x:%02x:%02x:%02x",
511 				pcb.dst.b[5], pcb.dst.b[4], pcb.dst.b[3],
512 				pcb.dst.b[2], pcb.dst.b[1], pcb.dst.b[0]);
513 
514 		fprintf(stdout,
515 "%-8.8x %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
516 			(int) this,
517 			so.so_rcv.sb_cc,
518 			so.so_snd.sb_cc,
519 			local,
520 			remote,
521 			pcb.channel,
522 			pcb.dlci,
523 			(so.so_options & SO_ACCEPTCONN)?
524 				"LISTEN" : state2str(pcb.state));
525 	}
526 } /* rfcommpr */
527 
528 /*
529  * Print RFCOMM sessions
530  */
531 
532 static void
533 rfcommpr_s(kvm_t *kvmd, u_long addr)
534 {
535 	static char const * const	states[] = {
536 	/* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */	       "CLOSED",
537 	/* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */     "LISTEN",
538 	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */    "CONNECTING",
539 	/* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */     "CONNECTED",
540 	/* NG_BTSOCKET_RFCOMM_SESSION_OPEN */          "OPEN",
541 	/* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
542 	};
543 
544 	ng_btsocket_rfcomm_session_p	this = NULL, next = NULL;
545 	ng_btsocket_rfcomm_session_t	s;
546 	struct socket			so;
547 	int				first = 1;
548 
549 	if (addr == 0)
550 		return;
551 
552         if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
553 		return;
554 
555 	for ( ; this != NULL; this = next) {
556 		if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
557 			return;
558 		if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
559 			return;
560 
561 		next = LIST_NEXT(&s, next);
562 
563 		if (first) {
564 			first = 0;
565 			fprintf(stdout,
566 "Active RFCOMM sessions\n" \
567 "%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
568 				"L2PCB",
569 				"PCB",
570 				"Flags",
571 				"MTU",
572 				"Out-Q",
573 				"DLCs",
574 				"State");
575 		}
576 
577 		fprintf(stdout,
578 "%-8.8x %-8.8x %-4x %-5d %-5d %-4s %s\n",
579 			(int) so.so_pcb,
580 			(int) this,
581 			s.flags,
582 			s.mtu,
583 			s.outq.len,
584 			LIST_EMPTY(&s.dlcs)? "No" : "Yes",
585 			state2str(s.state));
586 	}
587 } /* rfcommpr_s */
588 
589 /*
590  * Open kvm
591  */
592 
593 static kvm_t *
594 kopen(char const *memf)
595 {
596 	kvm_t	*kvmd = NULL;
597 	char	 errbuf[_POSIX2_LINE_MAX];
598 
599 	/*
600 	 * Discard setgid privileges if not the running kernel so that
601 	 * bad guys can't print interesting stuff from kernel memory.
602 	 */
603 
604 	if (memf != NULL)
605 		setgid(getgid());
606 
607 	kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
608 	if (kvmd == NULL) {
609 		warnx("kvm_openfiles: %s", errbuf);
610 		return (NULL);
611 	}
612 
613 	if (kvm_nlist(kvmd, nl) < 0) {
614 		warnx("kvm_nlist: %s", kvm_geterr(kvmd));
615 		goto fail;
616 	}
617 
618 	if (nl[0].n_type == 0) {
619 		warnx("kvm_nlist: no namelist");
620 		goto fail;
621 	}
622 
623 	return (kvmd);
624 fail:
625 	kvm_close(kvmd);
626 
627 	return (NULL);
628 } /* kopen */
629 
630 /*
631  * Read kvm
632  */
633 
634 static int
635 kread(kvm_t *kvmd, u_long addr, char *buffer, int size)
636 {
637 	if (kvmd == NULL || buffer == NULL)
638 		return (-1);
639 
640 	if (kvm_read(kvmd, addr, buffer, size) != size) {
641 		warnx("kvm_read: %s", kvm_geterr(kvmd));
642 		return (-1);
643 	}
644 
645 	return (0);
646 } /* kread */
647 
648 /*
649  * Print usage and exit
650  */
651 
652 static void
653 usage(void)
654 {
655 	fprintf(stdout, "Usage: btsockstat [-M core ] [-p proto] [-r]\n");
656 	exit(255);
657 } /* usage */
658 
659