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