/usr.bin/bluetooth/btsockstat/btsockstat.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 645 lines · 460 code · 108 blank · 77 comment · 102 complexity · 64d36a36cd2cbf843c4f1a206fbe8799 MD5 · raw file

  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.8 2003/05/21 22:40:25 max Exp $
  29. * $FreeBSD$
  30. */
  31. #include <sys/types.h>
  32. #include <sys/callout.h>
  33. #include <sys/param.h>
  34. #include <sys/protosw.h>
  35. #include <sys/queue.h>
  36. #include <sys/socket.h>
  37. #include <sys/socketvar.h>
  38. #include <net/if.h>
  39. #include <net/if_var.h>
  40. #include <bluetooth.h>
  41. #include <err.h>
  42. #include <fcntl.h>
  43. #include <kvm.h>
  44. #include <limits.h>
  45. #include <nlist.h>
  46. #include <netgraph/bluetooth/include/ng_bluetooth.h>
  47. #include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
  48. #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
  49. #include <netgraph/bluetooth/include/ng_btsocket_rfcomm.h>
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <string.h>
  53. #include <unistd.h>
  54. static void hcirawpr (kvm_t *kvmd, u_long addr);
  55. static void l2caprawpr (kvm_t *kvmd, u_long addr);
  56. static void l2cappr (kvm_t *kvmd, u_long addr);
  57. static void l2caprtpr (kvm_t *kvmd, u_long addr);
  58. static void rfcommpr (kvm_t *kvmd, u_long addr);
  59. static void rfcommpr_s (kvm_t *kvmd, u_long addr);
  60. static char * bdaddrpr (bdaddr_p const ba, char *str, int len);
  61. static kvm_t * kopen (char const *memf);
  62. static int kread (kvm_t *kvmd, u_long addr, char *buffer, int size);
  63. static void usage (void);
  64. /*
  65. * List of symbols
  66. */
  67. static struct nlist nl[] = {
  68. #define N_HCI_RAW 0
  69. { "_ng_btsocket_hci_raw_sockets" },
  70. #define N_L2CAP_RAW 1
  71. { "_ng_btsocket_l2cap_raw_sockets" },
  72. #define N_L2CAP 2
  73. { "_ng_btsocket_l2cap_sockets" },
  74. #define N_L2CAP_RAW_RT 3
  75. { "_ng_btsocket_l2cap_raw_rt" },
  76. #define N_L2CAP_RT 4
  77. { "_ng_btsocket_l2cap_rt" },
  78. #define N_RFCOMM 5
  79. { "_ng_btsocket_rfcomm_sockets" },
  80. #define N_RFCOMM_S 6
  81. { "_ng_btsocket_rfcomm_sessions" },
  82. { "" },
  83. };
  84. #define state2str(x) \
  85. (((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)])
  86. /*
  87. * Main
  88. */
  89. static int numeric_bdaddr = 0;
  90. int
  91. main(int argc, char *argv[])
  92. {
  93. int opt, proto = -1, route = 0;
  94. kvm_t *kvmd = NULL;
  95. char *memf = NULL;
  96. while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) {
  97. switch (opt) {
  98. case 'n':
  99. numeric_bdaddr = 1;
  100. break;
  101. case 'M':
  102. memf = optarg;
  103. break;
  104. case 'p':
  105. if (strcasecmp(optarg, "hci_raw") == 0)
  106. proto = N_HCI_RAW;
  107. else if (strcasecmp(optarg, "l2cap_raw") == 0)
  108. proto = N_L2CAP_RAW;
  109. else if (strcasecmp(optarg, "l2cap") == 0)
  110. proto = N_L2CAP;
  111. else if (strcasecmp(optarg, "rfcomm") == 0)
  112. proto = N_RFCOMM;
  113. else if (strcasecmp(optarg, "rfcomm_s") == 0)
  114. proto = N_RFCOMM_S;
  115. else
  116. usage();
  117. /* NOT REACHED */
  118. break;
  119. case 'r':
  120. route = 1;
  121. break;
  122. case 'h':
  123. default:
  124. usage();
  125. /* NOT REACHED */
  126. }
  127. }
  128. if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route)
  129. usage();
  130. /* NOT REACHED */
  131. /*
  132. * Discard setgid privileges if not the running kernel so that
  133. * bad guys can't print interesting stuff from kernel memory.
  134. */
  135. if (memf != NULL)
  136. setgid(getgid());
  137. kvmd = kopen(memf);
  138. if (kvmd == NULL)
  139. return (1);
  140. switch (proto) {
  141. case N_HCI_RAW:
  142. hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
  143. break;
  144. case N_L2CAP_RAW:
  145. if (route)
  146. l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
  147. else
  148. l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
  149. break;
  150. case N_L2CAP:
  151. if (route)
  152. l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
  153. else
  154. l2cappr(kvmd, nl[N_L2CAP].n_value);
  155. break;
  156. case N_RFCOMM:
  157. rfcommpr(kvmd, nl[N_RFCOMM].n_value);
  158. break;
  159. case N_RFCOMM_S:
  160. rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
  161. break;
  162. default:
  163. if (route) {
  164. l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value);
  165. l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value);
  166. } else {
  167. hcirawpr(kvmd, nl[N_HCI_RAW].n_value);
  168. l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value);
  169. l2cappr(kvmd, nl[N_L2CAP].n_value);
  170. rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value);
  171. rfcommpr(kvmd, nl[N_RFCOMM].n_value);
  172. }
  173. break;
  174. }
  175. return (kvm_close(kvmd));
  176. } /* main */
  177. /*
  178. * Print raw HCI sockets
  179. */
  180. static void
  181. hcirawpr(kvm_t *kvmd, u_long addr)
  182. {
  183. ng_btsocket_hci_raw_pcb_p this = NULL, next = NULL;
  184. ng_btsocket_hci_raw_pcb_t pcb;
  185. struct socket so;
  186. int first = 1;
  187. if (addr == 0)
  188. return;
  189. if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
  190. return;
  191. for ( ; this != NULL; this = next) {
  192. if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
  193. return;
  194. if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
  195. return;
  196. next = LIST_NEXT(&pcb, next);
  197. if (first) {
  198. first = 0;
  199. fprintf(stdout,
  200. "Active raw HCI sockets\n" \
  201. "%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n",
  202. "Socket",
  203. "PCB",
  204. "Flags",
  205. "Recv-Q",
  206. "Send-Q",
  207. "Local address");
  208. }
  209. if (pcb.addr.hci_node[0] == 0) {
  210. pcb.addr.hci_node[0] = '*';
  211. pcb.addr.hci_node[1] = 0;
  212. }
  213. fprintf(stdout,
  214. "%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n",
  215. (unsigned long) pcb.so,
  216. (unsigned long) this,
  217. pcb.flags,
  218. so.so_rcv.sb_cc,
  219. so.so_snd.sb_cc,
  220. pcb.addr.hci_node);
  221. }
  222. } /* hcirawpr */
  223. /*
  224. * Print raw L2CAP sockets
  225. */
  226. static void
  227. l2caprawpr(kvm_t *kvmd, u_long addr)
  228. {
  229. ng_btsocket_l2cap_raw_pcb_p this = NULL, next = NULL;
  230. ng_btsocket_l2cap_raw_pcb_t pcb;
  231. struct socket so;
  232. int first = 1;
  233. if (addr == 0)
  234. return;
  235. if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
  236. return;
  237. for ( ; this != NULL; this = next) {
  238. if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
  239. return;
  240. if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
  241. return;
  242. next = LIST_NEXT(&pcb, next);
  243. if (first) {
  244. first = 0;
  245. fprintf(stdout,
  246. "Active raw L2CAP sockets\n" \
  247. "%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n",
  248. "Socket",
  249. "PCB",
  250. "Recv-Q",
  251. "Send-Q",
  252. "Local address");
  253. }
  254. fprintf(stdout,
  255. "%-8lx %-8lx %6d %6d %-17.17s\n",
  256. (unsigned long) pcb.so,
  257. (unsigned long) this,
  258. so.so_rcv.sb_cc,
  259. so.so_snd.sb_cc,
  260. bdaddrpr(&pcb.src, NULL, 0));
  261. }
  262. } /* l2caprawpr */
  263. /*
  264. * Print L2CAP sockets
  265. */
  266. static void
  267. l2cappr(kvm_t *kvmd, u_long addr)
  268. {
  269. static char const * const states[] = {
  270. /* NG_BTSOCKET_L2CAP_CLOSED */ "CLOSED",
  271. /* NG_BTSOCKET_L2CAP_CONNECTING */ "CON",
  272. /* NG_BTSOCKET_L2CAP_CONFIGURING */ "CONFIG",
  273. /* NG_BTSOCKET_L2CAP_OPEN */ "OPEN",
  274. /* NG_BTSOCKET_L2CAP_DISCONNECTING */ "DISCON"
  275. };
  276. ng_btsocket_l2cap_pcb_p this = NULL, next = NULL;
  277. ng_btsocket_l2cap_pcb_t pcb;
  278. struct socket so;
  279. int first = 1;
  280. char local[24], remote[24];
  281. if (addr == 0)
  282. return;
  283. if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
  284. return;
  285. for ( ; this != NULL; this = next) {
  286. if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
  287. return;
  288. if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
  289. return;
  290. next = LIST_NEXT(&pcb, next);
  291. if (first) {
  292. first = 0;
  293. fprintf(stdout,
  294. "Active L2CAP sockets\n" \
  295. "%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n",
  296. "PCB",
  297. "Recv-Q",
  298. "Send-Q",
  299. "Local address/PSM",
  300. "Foreign address",
  301. "CID",
  302. "State");
  303. }
  304. fprintf(stdout,
  305. "%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
  306. (unsigned long) this,
  307. so.so_rcv.sb_cc,
  308. so.so_snd.sb_cc,
  309. bdaddrpr(&pcb.src, local, sizeof(local)),
  310. pcb.psm,
  311. bdaddrpr(&pcb.dst, remote, sizeof(remote)),
  312. pcb.cid,
  313. (so.so_options & SO_ACCEPTCONN)?
  314. "LISTEN" : state2str(pcb.state));
  315. }
  316. } /* l2cappr */
  317. /*
  318. * Print L2CAP routing table
  319. */
  320. static void
  321. l2caprtpr(kvm_t *kvmd, u_long addr)
  322. {
  323. ng_btsocket_l2cap_rtentry_p this = NULL, next = NULL;
  324. ng_btsocket_l2cap_rtentry_t rt;
  325. int first = 1;
  326. if (addr == 0)
  327. return;
  328. if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
  329. return;
  330. for ( ; this != NULL; this = next) {
  331. if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0)
  332. return;
  333. next = LIST_NEXT(&rt, next);
  334. if (first) {
  335. first = 0;
  336. fprintf(stdout,
  337. "Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)? "raw " : "");
  338. fprintf(stdout,
  339. "%-8.8s %-8.8s %-17.17s\n", "RTentry",
  340. "Hook",
  341. "BD_ADDR");
  342. }
  343. fprintf(stdout,
  344. "%-8lx %-8lx %-17.17s\n",
  345. (unsigned long) this,
  346. (unsigned long) rt.hook,
  347. bdaddrpr(&rt.src, NULL, 0));
  348. }
  349. } /* l2caprtpr */
  350. /*
  351. * Print RFCOMM sockets
  352. */
  353. static void
  354. rfcommpr(kvm_t *kvmd, u_long addr)
  355. {
  356. static char const * const states[] = {
  357. /* NG_BTSOCKET_RFCOMM_DLC_CLOSED */ "CLOSED",
  358. /* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */ "W4CON",
  359. /* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */ "CONFIG",
  360. /* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */ "CONN",
  361. /* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */ "OPEN",
  362. /* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON"
  363. };
  364. ng_btsocket_rfcomm_pcb_p this = NULL, next = NULL;
  365. ng_btsocket_rfcomm_pcb_t pcb;
  366. struct socket so;
  367. int first = 1;
  368. char local[24], remote[24];
  369. if (addr == 0)
  370. return;
  371. if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
  372. return;
  373. for ( ; this != NULL; this = next) {
  374. if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0)
  375. return;
  376. if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0)
  377. return;
  378. next = LIST_NEXT(&pcb, next);
  379. if (first) {
  380. first = 0;
  381. fprintf(stdout,
  382. "Active RFCOMM sockets\n" \
  383. "%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n",
  384. "PCB",
  385. "Recv-Q",
  386. "Send-Q",
  387. "Local address",
  388. "Foreign address",
  389. "Chan",
  390. "DLCI",
  391. "State");
  392. }
  393. fprintf(stdout,
  394. "%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
  395. (unsigned long) this,
  396. so.so_rcv.sb_cc,
  397. so.so_snd.sb_cc,
  398. bdaddrpr(&pcb.src, local, sizeof(local)),
  399. bdaddrpr(&pcb.dst, remote, sizeof(remote)),
  400. pcb.channel,
  401. pcb.dlci,
  402. (so.so_options & SO_ACCEPTCONN)?
  403. "LISTEN" : state2str(pcb.state));
  404. }
  405. } /* rfcommpr */
  406. /*
  407. * Print RFCOMM sessions
  408. */
  409. static void
  410. rfcommpr_s(kvm_t *kvmd, u_long addr)
  411. {
  412. static char const * const states[] = {
  413. /* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */ "CLOSED",
  414. /* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */ "LISTEN",
  415. /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */ "CONNECTING",
  416. /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */ "CONNECTED",
  417. /* NG_BTSOCKET_RFCOMM_SESSION_OPEN */ "OPEN",
  418. /* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING"
  419. };
  420. ng_btsocket_rfcomm_session_p this = NULL, next = NULL;
  421. ng_btsocket_rfcomm_session_t s;
  422. struct socket so;
  423. int first = 1;
  424. if (addr == 0)
  425. return;
  426. if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0)
  427. return;
  428. for ( ; this != NULL; this = next) {
  429. if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0)
  430. return;
  431. if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0)
  432. return;
  433. next = LIST_NEXT(&s, next);
  434. if (first) {
  435. first = 0;
  436. fprintf(stdout,
  437. "Active RFCOMM sessions\n" \
  438. "%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n",
  439. "L2PCB",
  440. "PCB",
  441. "Flags",
  442. "MTU",
  443. "Out-Q",
  444. "DLCs",
  445. "State");
  446. }
  447. fprintf(stdout,
  448. "%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n",
  449. (unsigned long) so.so_pcb,
  450. (unsigned long) this,
  451. s.flags,
  452. s.mtu,
  453. s.outq.len,
  454. LIST_EMPTY(&s.dlcs)? "No" : "Yes",
  455. state2str(s.state));
  456. }
  457. } /* rfcommpr_s */
  458. /*
  459. * Return BD_ADDR as string
  460. */
  461. static char *
  462. bdaddrpr(bdaddr_p const ba, char *str, int len)
  463. {
  464. static char buffer[MAXHOSTNAMELEN];
  465. struct hostent *he = NULL;
  466. if (str == NULL) {
  467. str = buffer;
  468. len = sizeof(buffer);
  469. }
  470. if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) {
  471. str[0] = '*';
  472. str[1] = 0;
  473. return (str);
  474. }
  475. if (!numeric_bdaddr &&
  476. (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) {
  477. strlcpy(str, he->h_name, len);
  478. return (str);
  479. }
  480. bt_ntoa(ba, str);
  481. return (str);
  482. } /* bdaddrpr */
  483. /*
  484. * Open kvm
  485. */
  486. static kvm_t *
  487. kopen(char const *memf)
  488. {
  489. kvm_t *kvmd = NULL;
  490. char errbuf[_POSIX2_LINE_MAX];
  491. /*
  492. * Discard setgid privileges if not the running kernel so that
  493. * bad guys can't print interesting stuff from kernel memory.
  494. */
  495. if (memf != NULL)
  496. setgid(getgid());
  497. kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf);
  498. if (kvmd == NULL) {
  499. warnx("kvm_openfiles: %s", errbuf);
  500. return (NULL);
  501. }
  502. if (kvm_nlist(kvmd, nl) < 0) {
  503. warnx("kvm_nlist: %s", kvm_geterr(kvmd));
  504. goto fail;
  505. }
  506. if (nl[0].n_type == 0) {
  507. warnx("kvm_nlist: no namelist");
  508. goto fail;
  509. }
  510. return (kvmd);
  511. fail:
  512. kvm_close(kvmd);
  513. return (NULL);
  514. } /* kopen */
  515. /*
  516. * Read kvm
  517. */
  518. static int
  519. kread(kvm_t *kvmd, u_long addr, char *buffer, int size)
  520. {
  521. if (kvmd == NULL || buffer == NULL)
  522. return (-1);
  523. if (kvm_read(kvmd, addr, buffer, size) != size) {
  524. warnx("kvm_read: %s", kvm_geterr(kvmd));
  525. return (-1);
  526. }
  527. return (0);
  528. } /* kread */
  529. /*
  530. * Print usage and exit
  531. */
  532. static void
  533. usage(void)
  534. {
  535. fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n");
  536. exit(255);
  537. } /* usage */