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