btiotest.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
  7. * Copyright (C) 2009-2010 Nokia Corporation
  8. *
  9. *
  10. */
  11. #ifdef HAVE_CONFIG_H
  12. #include <config.h>
  13. #endif
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdint.h>
  17. #include <errno.h>
  18. #include <string.h>
  19. #include <signal.h>
  20. #include <glib.h>
  21. #include "lib/bluetooth.h"
  22. #include "btio/btio.h"
  23. #define DEFAULT_ACCEPT_TIMEOUT 2
  24. static int opt_update_sec = 0;
  25. struct io_data {
  26. guint ref;
  27. GIOChannel *io;
  28. int reject;
  29. int disconn;
  30. int accept;
  31. int voice;
  32. };
  33. static void io_data_unref(struct io_data *data)
  34. {
  35. data->ref--;
  36. if (data->ref)
  37. return;
  38. if (data->io)
  39. g_io_channel_unref(data->io);
  40. g_free(data);
  41. }
  42. static struct io_data *io_data_ref(struct io_data *data)
  43. {
  44. data->ref++;
  45. return data;
  46. }
  47. static struct io_data *io_data_new(GIOChannel *io, int reject, int disconn,
  48. int accept)
  49. {
  50. struct io_data *data;
  51. data = g_new0(struct io_data, 1);
  52. data->io = io;
  53. data->reject = reject;
  54. data->disconn = disconn;
  55. data->accept = accept;
  56. return io_data_ref(data);
  57. }
  58. static gboolean io_watch(GIOChannel *io, GIOCondition cond, gpointer user_data)
  59. {
  60. printf("Disconnected\n");
  61. return FALSE;
  62. }
  63. static gboolean disconn_timeout(gpointer user_data)
  64. {
  65. struct io_data *data = user_data;
  66. printf("Disconnecting\n");
  67. g_io_channel_shutdown(data->io, TRUE, NULL);
  68. return FALSE;
  69. }
  70. static void update_sec_level(struct io_data *data)
  71. {
  72. GError *err = NULL;
  73. int sec_level;
  74. if (!bt_io_get(data->io, &err, BT_IO_OPT_SEC_LEVEL, &sec_level,
  75. BT_IO_OPT_INVALID)) {
  76. printf("bt_io_get(OPT_SEC_LEVEL): %s\n", err->message);
  77. g_clear_error(&err);
  78. return;
  79. }
  80. printf("sec_level=%d\n", sec_level);
  81. if (opt_update_sec == sec_level)
  82. return;
  83. if (!bt_io_set(data->io, &err, BT_IO_OPT_SEC_LEVEL, opt_update_sec,
  84. BT_IO_OPT_INVALID)) {
  85. printf("bt_io_set(OPT_SEC_LEVEL): %s\n", err->message);
  86. g_clear_error(&err);
  87. }
  88. }
  89. static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
  90. {
  91. struct io_data *data = user_data;
  92. GIOCondition cond;
  93. char addr[18];
  94. uint16_t handle, omtu, imtu;
  95. uint8_t cls[3], key_size;
  96. if (err) {
  97. printf("Connecting failed: %s\n", err->message);
  98. return;
  99. }
  100. if (!bt_io_get(io, &err,
  101. BT_IO_OPT_DEST, addr,
  102. BT_IO_OPT_HANDLE, &handle,
  103. BT_IO_OPT_CLASS, cls,
  104. BT_IO_OPT_INVALID)) {
  105. printf("Unable to get destination address: %s\n",
  106. err->message);
  107. g_clear_error(&err);
  108. strcpy(addr, "(unknown)");
  109. }
  110. printf("Successfully connected to %s. handle=%u, class=%02x%02x%02x\n",
  111. addr, handle, cls[0], cls[1], cls[2]);
  112. if (!bt_io_get(io, &err, BT_IO_OPT_OMTU, &omtu,
  113. BT_IO_OPT_IMTU, &imtu,
  114. BT_IO_OPT_INVALID)) {
  115. printf("Unable to get MTU sizes: %s\n", err->message);
  116. g_clear_error(&err);
  117. } else
  118. printf("imtu=%u, omtu=%u\n", imtu, omtu);
  119. if (!bt_io_get(io, &err, BT_IO_OPT_KEY_SIZE, &key_size,
  120. BT_IO_OPT_INVALID)) {
  121. printf("Unable to get Key size: %s\n", err->message);
  122. g_clear_error(&err);
  123. } else
  124. printf("key_size=%u\n", key_size);
  125. if (data->disconn == 0) {
  126. g_io_channel_shutdown(io, TRUE, NULL);
  127. printf("Disconnected\n");
  128. return;
  129. }
  130. if (data->io == NULL)
  131. data->io = g_io_channel_ref(io);
  132. if (data->disconn > 0) {
  133. io_data_ref(data);
  134. g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, data->disconn,
  135. disconn_timeout, data,
  136. (GDestroyNotify) io_data_unref);
  137. }
  138. io_data_ref(data);
  139. if (opt_update_sec > 0)
  140. update_sec_level(data);
  141. cond = G_IO_NVAL | G_IO_HUP | G_IO_ERR;
  142. g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, io_watch, data,
  143. (GDestroyNotify) io_data_unref);
  144. }
  145. static gboolean confirm_timeout(gpointer user_data)
  146. {
  147. struct io_data *data = user_data;
  148. if (data->reject >= 0) {
  149. printf("Rejecting connection\n");
  150. g_io_channel_shutdown(data->io, TRUE, NULL);
  151. return FALSE;
  152. }
  153. printf("Accepting connection\n");
  154. io_data_ref(data);
  155. if (opt_update_sec > 0)
  156. update_sec_level(data);
  157. if (!bt_io_accept(data->io, connect_cb, data,
  158. (GDestroyNotify) io_data_unref, NULL)) {
  159. printf("bt_io_accept() failed\n");
  160. io_data_unref(data);
  161. }
  162. return FALSE;
  163. }
  164. static void confirm_cb(GIOChannel *io, gpointer user_data)
  165. {
  166. char addr[18];
  167. struct io_data *data = user_data;
  168. GError *err = NULL;
  169. if (!bt_io_get(io, &err, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID)) {
  170. printf("bt_io_get(OPT_DEST): %s\n", err->message);
  171. g_clear_error(&err);
  172. } else
  173. printf("Got confirmation request for %s\n", addr);
  174. if (data->accept < 0 && data->reject < 0)
  175. return;
  176. if (data->reject == 0) {
  177. printf("Rejecting connection\n");
  178. g_io_channel_shutdown(io, TRUE, NULL);
  179. return;
  180. }
  181. if (data->voice) {
  182. if (!bt_io_set(io, &err, BT_IO_OPT_VOICE, data->voice,
  183. BT_IO_OPT_INVALID)) {
  184. printf("bt_io_set(OPT_VOICE): %s\n", err->message);
  185. g_clear_error(&err);
  186. }
  187. }
  188. data->io = g_io_channel_ref(io);
  189. io_data_ref(data);
  190. if (data->accept == 0) {
  191. if (!bt_io_accept(io, connect_cb, data,
  192. (GDestroyNotify) io_data_unref,
  193. &err)) {
  194. printf("bt_io_accept() failed: %s\n", err->message);
  195. g_clear_error(&err);
  196. io_data_unref(data);
  197. return;
  198. }
  199. } else {
  200. int seconds = (data->reject > 0) ?
  201. data->reject : data->accept;
  202. g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, seconds,
  203. confirm_timeout, data,
  204. (GDestroyNotify) io_data_unref);
  205. }
  206. }
  207. static void l2cap_connect(const char *src, const char *dst, uint8_t addr_type,
  208. uint16_t psm, uint16_t cid, int disconn,
  209. int sec, int prio)
  210. {
  211. struct io_data *data;
  212. GError *err = NULL;
  213. uint8_t src_type;
  214. printf("Connecting to %s L2CAP PSM %u\n", dst, psm);
  215. data = io_data_new(NULL, -1, disconn, -1);
  216. if (addr_type != BDADDR_BREDR)
  217. src_type = BDADDR_LE_PUBLIC;
  218. else
  219. src_type = BDADDR_BREDR;
  220. if (src)
  221. data->io = bt_io_connect(connect_cb, data,
  222. (GDestroyNotify) io_data_unref,
  223. &err,
  224. BT_IO_OPT_SOURCE, src,
  225. BT_IO_OPT_SOURCE_TYPE, src_type,
  226. BT_IO_OPT_DEST, dst,
  227. BT_IO_OPT_DEST_TYPE, addr_type,
  228. BT_IO_OPT_PSM, psm,
  229. BT_IO_OPT_CID, cid,
  230. BT_IO_OPT_SEC_LEVEL, sec,
  231. BT_IO_OPT_PRIORITY, prio,
  232. BT_IO_OPT_INVALID);
  233. else
  234. data->io = bt_io_connect(connect_cb, data,
  235. (GDestroyNotify) io_data_unref,
  236. &err,
  237. BT_IO_OPT_SOURCE_TYPE, src_type,
  238. BT_IO_OPT_DEST, dst,
  239. BT_IO_OPT_DEST_TYPE, addr_type,
  240. BT_IO_OPT_PSM, psm,
  241. BT_IO_OPT_CID, cid,
  242. BT_IO_OPT_SEC_LEVEL, sec,
  243. BT_IO_OPT_PRIORITY, prio,
  244. BT_IO_OPT_INVALID);
  245. if (!data->io) {
  246. printf("Connecting to %s failed: %s\n", dst, err->message);
  247. g_error_free(err);
  248. exit(EXIT_FAILURE);
  249. }
  250. }
  251. static void l2cap_listen(const char *src, uint8_t addr_type, uint16_t psm,
  252. uint16_t cid, int defer, int reject,
  253. int disconn, int accept, int sec,
  254. gboolean central)
  255. {
  256. struct io_data *data;
  257. BtIOConnect conn;
  258. BtIOConfirm cfm;
  259. GIOChannel *l2_srv;
  260. GError *err = NULL;
  261. if (defer) {
  262. conn = NULL;
  263. cfm = confirm_cb;
  264. } else {
  265. conn = connect_cb;
  266. cfm = NULL;
  267. }
  268. if (cid)
  269. printf("Listening on L2CAP CID 0x%04x (%u)\n", cid, cid);
  270. else
  271. printf("Listening on L2CAP PSM 0x%04x (%u)\n", psm, psm);
  272. data = io_data_new(NULL, reject, disconn, accept);
  273. if (src)
  274. l2_srv = bt_io_listen(conn, cfm, data,
  275. (GDestroyNotify) io_data_unref,
  276. &err,
  277. BT_IO_OPT_SOURCE, src,
  278. BT_IO_OPT_SOURCE_TYPE, addr_type,
  279. BT_IO_OPT_PSM, psm,
  280. BT_IO_OPT_CID, cid,
  281. BT_IO_OPT_SEC_LEVEL, sec,
  282. BT_IO_OPT_CENTRAL, central,
  283. BT_IO_OPT_INVALID);
  284. else
  285. l2_srv = bt_io_listen(conn, cfm, data,
  286. (GDestroyNotify) io_data_unref,
  287. &err,
  288. BT_IO_OPT_SOURCE_TYPE, addr_type,
  289. BT_IO_OPT_PSM, psm,
  290. BT_IO_OPT_CID, cid,
  291. BT_IO_OPT_SEC_LEVEL, sec,
  292. BT_IO_OPT_CENTRAL, central,
  293. BT_IO_OPT_INVALID);
  294. if (!l2_srv) {
  295. printf("Listening failed: %s\n", err->message);
  296. g_error_free(err);
  297. exit(EXIT_FAILURE);
  298. }
  299. g_io_channel_unref(l2_srv);
  300. }
  301. static void rfcomm_connect(const char *src, const char *dst, uint8_t ch,
  302. int disconn, int sec)
  303. {
  304. struct io_data *data;
  305. GError *err = NULL;
  306. printf("Connecting to %s RFCOMM channel %u\n", dst, ch);
  307. data = io_data_new(NULL, -1, disconn, -1);
  308. if (src)
  309. data->io = bt_io_connect(connect_cb, data,
  310. (GDestroyNotify) io_data_unref,
  311. &err,
  312. BT_IO_OPT_SOURCE, src,
  313. BT_IO_OPT_DEST, dst,
  314. BT_IO_OPT_CHANNEL, ch,
  315. BT_IO_OPT_SEC_LEVEL, sec,
  316. BT_IO_OPT_INVALID);
  317. else
  318. data->io = bt_io_connect(connect_cb, data,
  319. (GDestroyNotify) io_data_unref,
  320. &err,
  321. BT_IO_OPT_DEST, dst,
  322. BT_IO_OPT_CHANNEL, ch,
  323. BT_IO_OPT_SEC_LEVEL, sec,
  324. BT_IO_OPT_INVALID);
  325. if (!data->io) {
  326. printf("Connecting to %s failed: %s\n", dst, err->message);
  327. g_error_free(err);
  328. exit(EXIT_FAILURE);
  329. }
  330. }
  331. static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer,
  332. int reject, int disconn, int accept,
  333. int sec, gboolean central)
  334. {
  335. struct io_data *data;
  336. BtIOConnect conn;
  337. BtIOConfirm cfm;
  338. GIOChannel *rc_srv;
  339. GError *err = NULL;
  340. if (defer) {
  341. conn = NULL;
  342. cfm = confirm_cb;
  343. } else {
  344. conn = connect_cb;
  345. cfm = NULL;
  346. }
  347. data = io_data_new(NULL, reject, disconn, accept);
  348. if (src)
  349. rc_srv = bt_io_listen(conn, cfm,
  350. data, (GDestroyNotify) io_data_unref,
  351. &err,
  352. BT_IO_OPT_SOURCE, src,
  353. BT_IO_OPT_CHANNEL, ch,
  354. BT_IO_OPT_SEC_LEVEL, sec,
  355. BT_IO_OPT_CENTRAL, central,
  356. BT_IO_OPT_INVALID);
  357. else
  358. rc_srv = bt_io_listen(conn, cfm,
  359. data, (GDestroyNotify) io_data_unref,
  360. &err,
  361. BT_IO_OPT_CHANNEL, ch,
  362. BT_IO_OPT_SEC_LEVEL, sec,
  363. BT_IO_OPT_CENTRAL, central,
  364. BT_IO_OPT_INVALID);
  365. if (!rc_srv) {
  366. printf("Listening failed: %s\n", err->message);
  367. g_error_free(err);
  368. exit(EXIT_FAILURE);
  369. }
  370. bt_io_get(rc_srv, &err, BT_IO_OPT_CHANNEL, &ch, BT_IO_OPT_INVALID);
  371. printf("Listening on RFCOMM channel %u\n", ch);
  372. g_io_channel_unref(rc_srv);
  373. }
  374. static void sco_connect(const char *src, const char *dst, int disconn,
  375. int voice)
  376. {
  377. struct io_data *data;
  378. GError *err = NULL;
  379. printf("Connecting SCO to %s\n", dst);
  380. data = io_data_new(NULL, -1, disconn, -1);
  381. if (src)
  382. data->io = bt_io_connect(connect_cb, data,
  383. (GDestroyNotify) io_data_unref,
  384. &err,
  385. BT_IO_OPT_SOURCE, src,
  386. BT_IO_OPT_DEST, dst,
  387. BT_IO_OPT_VOICE, voice,
  388. BT_IO_OPT_INVALID);
  389. else
  390. data->io = bt_io_connect(connect_cb, data,
  391. (GDestroyNotify) io_data_unref,
  392. &err,
  393. BT_IO_OPT_DEST, dst,
  394. BT_IO_OPT_VOICE, voice,
  395. BT_IO_OPT_INVALID);
  396. if (!data->io) {
  397. printf("Connecting to %s failed: %s\n", dst, err->message);
  398. g_error_free(err);
  399. exit(EXIT_FAILURE);
  400. }
  401. }
  402. static void sco_listen(const char *src, gboolean defer, int reject,
  403. int disconn, int accept, int voice)
  404. {
  405. struct io_data *data;
  406. BtIOConnect conn;
  407. BtIOConfirm cfm;
  408. GIOChannel *sco_srv;
  409. GError *err = NULL;
  410. printf("Listening for SCO connections\n");
  411. if (defer) {
  412. conn = NULL;
  413. cfm = confirm_cb;
  414. } else {
  415. conn = connect_cb;
  416. cfm = NULL;
  417. }
  418. data = io_data_new(NULL, reject, disconn, accept);
  419. data->voice = voice;
  420. if (src)
  421. sco_srv = bt_io_listen(conn, cfm, data,
  422. (GDestroyNotify) io_data_unref,
  423. &err,
  424. BT_IO_OPT_SOURCE, src,
  425. BT_IO_OPT_VOICE, voice,
  426. BT_IO_OPT_INVALID);
  427. else
  428. sco_srv = bt_io_listen(conn, cfm, data,
  429. (GDestroyNotify) io_data_unref,
  430. &err,
  431. BT_IO_OPT_VOICE, voice,
  432. BT_IO_OPT_INVALID);
  433. if (!sco_srv) {
  434. printf("Listening failed: %s\n", err->message);
  435. g_error_free(err);
  436. exit(EXIT_FAILURE);
  437. }
  438. g_io_channel_unref(sco_srv);
  439. }
  440. static int opt_channel = -1;
  441. static int opt_psm = 0;
  442. static gboolean opt_sco = FALSE;
  443. static gboolean opt_defer = FALSE;
  444. static gint opt_voice = 0;
  445. static char *opt_dev = NULL;
  446. static int opt_reject = -1;
  447. static int opt_disconn = -1;
  448. static int opt_accept = DEFAULT_ACCEPT_TIMEOUT;
  449. static int opt_sec = 0;
  450. static gboolean opt_central = FALSE;
  451. static int opt_priority = 0;
  452. static int opt_cid = 0;
  453. static guint8 opt_addr_type = 0;
  454. static GMainLoop *main_loop;
  455. static GOptionEntry options[] = {
  456. { "channel", 'c', 0, G_OPTION_ARG_INT, &opt_channel,
  457. "RFCOMM channel" },
  458. { "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm,
  459. "L2CAP PSM" },
  460. { "cid", 'j', 0, G_OPTION_ARG_INT, &opt_cid,
  461. "L2CAP CID" },
  462. { "addr-type", 't', 0, G_OPTION_ARG_INT, &opt_addr_type,
  463. "Address type "
  464. "(0 BR/EDR 1 LE Public 2 LE Random" },
  465. { "sco", 's', 0, G_OPTION_ARG_NONE, &opt_sco,
  466. "Use SCO" },
  467. { "defer", 'd', 0, G_OPTION_ARG_NONE, &opt_defer,
  468. "Use DEFER_SETUP for incoming connections" },
  469. { "voice", 'V', 0, G_OPTION_ARG_INT, &opt_voice,
  470. "Voice setting "
  471. "(0x0060 CVSD, 0x0003 Transparent)" },
  472. { "sec-level", 'S', 0, G_OPTION_ARG_INT, &opt_sec,
  473. "Security level" },
  474. { "update-sec-level", 'U', 0, G_OPTION_ARG_INT, &opt_update_sec,
  475. "Update security level" },
  476. { "dev", 'i', 0, G_OPTION_ARG_STRING, &opt_dev,
  477. "Which HCI device to use" },
  478. { "reject", 'r', 0, G_OPTION_ARG_INT, &opt_reject,
  479. "Reject connection after N seconds" },
  480. { "disconnect", 'D', 0, G_OPTION_ARG_INT, &opt_disconn,
  481. "Disconnect connection after N seconds" },
  482. { "accept", 'a', 0, G_OPTION_ARG_INT, &opt_accept,
  483. "Accept connection after N seconds" },
  484. { "central", 'C', 0, G_OPTION_ARG_NONE, &opt_central,
  485. "Central role switch (incoming connections)" },
  486. { "master", 'm', 0, G_OPTION_ARG_NONE, &opt_central,
  487. "Deprecated. Use central instead." },
  488. { "priority", 'P', 0, G_OPTION_ARG_INT, &opt_priority,
  489. "Transmission priority: Setting a priority "
  490. "outside the range 0 to 6 requires the"
  491. "CAP_NET_ADMIN capability." },
  492. { NULL },
  493. };
  494. static void sig_term(int sig)
  495. {
  496. g_main_loop_quit(main_loop);
  497. }
  498. int main(int argc, char *argv[])
  499. {
  500. GOptionContext *context;
  501. context = g_option_context_new(NULL);
  502. g_option_context_add_main_entries(context, options, NULL);
  503. if (!g_option_context_parse(context, &argc, &argv, NULL))
  504. exit(EXIT_FAILURE);
  505. g_option_context_free(context);
  506. printf("accept=%d reject=%d discon=%d defer=%d sec=%d update_sec=%d"
  507. " prio=%d voice=0x%04x\n", opt_accept, opt_reject, opt_disconn,
  508. opt_defer, opt_sec, opt_update_sec, opt_priority, opt_voice);
  509. if (opt_psm || opt_cid) {
  510. if (argc > 1)
  511. l2cap_connect(opt_dev, argv[1], opt_addr_type,
  512. opt_psm, opt_cid, opt_disconn,
  513. opt_sec, opt_priority);
  514. else
  515. l2cap_listen(opt_dev, opt_addr_type, opt_psm, opt_cid,
  516. opt_defer, opt_reject, opt_disconn,
  517. opt_accept, opt_sec, opt_central);
  518. }
  519. if (opt_channel != -1) {
  520. if (argc > 1)
  521. rfcomm_connect(opt_dev, argv[1], opt_channel,
  522. opt_disconn, opt_sec);
  523. else
  524. rfcomm_listen(opt_dev, opt_channel, opt_defer,
  525. opt_reject, opt_disconn, opt_accept,
  526. opt_sec, opt_central);
  527. }
  528. if (opt_sco) {
  529. if (argc > 1)
  530. sco_connect(opt_dev, argv[1], opt_disconn, opt_voice);
  531. else
  532. sco_listen(opt_dev, opt_defer, opt_reject,
  533. opt_disconn, opt_accept, opt_voice);
  534. }
  535. signal(SIGTERM, sig_term);
  536. signal(SIGINT, sig_term);
  537. main_loop = g_main_loop_new(NULL, FALSE);
  538. g_main_loop_run(main_loop);
  539. g_main_loop_unref(main_loop);
  540. printf("Exiting\n");
  541. exit(EXIT_SUCCESS);
  542. }