3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2009-2010 Marcel Holtmann <marcel@holtmann.org>
6 * Copyright (C) 2009-2010 Nokia Corporation
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.
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.
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
35 #define DEFAULT_ACCEPT_TIMEOUT 2
36 static gint opt_update_sec = 0;
47 static void io_data_unref(struct io_data *data)
55 g_io_channel_unref(data->io);
60 static struct io_data *io_data_ref(struct io_data *data)
66 static struct io_data *io_data_new(GIOChannel *io, BtIOType type, gint reject,
67 gint disconn, gint accept)
71 data = g_new0(struct io_data, 1);
74 data->reject = reject;
75 data->disconn = disconn;
76 data->accept = accept;
78 return io_data_ref(data);
81 static gboolean io_watch(GIOChannel *io, GIOCondition cond, gpointer user_data)
83 printf("Disconnected\n");
87 static gboolean disconn_timeout(gpointer user_data)
89 struct io_data *data = user_data;
91 printf("Disconnecting\n");
93 g_io_channel_shutdown(data->io, TRUE, NULL);
98 static void update_sec_level(struct io_data *data)
103 if (!bt_io_get(data->io, data->type, &err,
104 BT_IO_OPT_SEC_LEVEL, &sec_level,
105 BT_IO_OPT_INVALID)) {
106 printf("bt_io_get(OPT_SEC_LEVEL): %s\n", err->message);
111 printf("sec_level=%d\n", sec_level);
113 if (opt_update_sec == sec_level)
116 if (!bt_io_set(data->io, data->type, &err,
117 BT_IO_OPT_SEC_LEVEL, opt_update_sec,
118 BT_IO_OPT_INVALID)) {
119 printf("bt_io_set(OPT_SEC_LEVEL): %s\n", err->message);
124 static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
126 struct io_data *data = user_data;
133 printf("Connecting failed: %s\n", err->message);
137 if (!bt_io_get(io, data->type, &err,
138 BT_IO_OPT_DEST, addr,
139 BT_IO_OPT_HANDLE, &handle,
140 BT_IO_OPT_CLASS, cls,
141 BT_IO_OPT_INVALID)) {
142 printf("Unable to get destination address: %s\n",
145 strcpy(addr, "(unknown)");
148 printf("Successfully connected to %s. handle=%u, class=%02x%02x%02x\n",
149 addr, handle, cls[0], cls[1], cls[2]);
151 if (data->type == BT_IO_L2CAP || data->type == BT_IO_SCO) {
154 if (!bt_io_get(io, data->type, &err,
155 BT_IO_OPT_OMTU, &omtu,
156 BT_IO_OPT_IMTU, &imtu,
157 BT_IO_OPT_INVALID)) {
158 printf("Unable to get L2CAP MTU sizes: %s\n",
162 printf("imtu=%u, omtu=%u\n", imtu, omtu);
165 if (data->type == BT_IO_L2CAP) {
168 if (!bt_io_get(io, data->type, &err,
169 BT_IO_OPT_KEY_SIZE, &key_size,
170 BT_IO_OPT_INVALID)) {
171 printf("Unable to get L2CAP Key size: %s\n",
175 printf("key_size=%u\n", key_size);
178 if (data->disconn == 0) {
179 g_io_channel_shutdown(io, TRUE, NULL);
180 printf("Disconnected\n");
184 if (data->io == NULL)
185 data->io = g_io_channel_ref(io);
187 if (data->disconn > 0) {
189 g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, data->disconn,
190 disconn_timeout, data,
191 (GDestroyNotify) io_data_unref);
197 if (opt_update_sec > 0)
198 update_sec_level(data);
200 cond = G_IO_NVAL | G_IO_HUP | G_IO_ERR;
201 g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, io_watch, data,
202 (GDestroyNotify) io_data_unref);
205 static gboolean confirm_timeout(gpointer user_data)
207 struct io_data *data = user_data;
209 if (data->reject >= 0) {
210 printf("Rejecting connection\n");
211 g_io_channel_shutdown(data->io, TRUE, NULL);
215 printf("Accepting connection\n");
219 if (opt_update_sec > 0)
220 update_sec_level(data);
222 if (!bt_io_accept(data->io, connect_cb, data,
223 (GDestroyNotify) io_data_unref, NULL)) {
224 printf("bt_io_accept() failed\n");
231 static void confirm_cb(GIOChannel *io, gpointer user_data)
234 struct io_data *data = user_data;
237 if (!bt_io_get(io, data->type, &err, BT_IO_OPT_DEST, addr,
238 BT_IO_OPT_INVALID)) {
239 printf("bt_io_get(OPT_DEST): %s\n", err->message);
242 printf("Got confirmation request for %s\n", addr);
244 if (data->accept < 0 && data->reject < 0)
247 if (data->reject == 0) {
248 printf("Rejecting connection\n");
249 g_io_channel_shutdown(io, TRUE, NULL);
253 data->io = g_io_channel_ref(io);
256 if (data->accept == 0) {
257 if (!bt_io_accept(io, connect_cb, data,
258 (GDestroyNotify) io_data_unref,
260 printf("bt_io_accept() failed: %s\n", err->message);
266 gint seconds = (data->reject > 0) ?
267 data->reject : data->accept;
268 g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, seconds,
269 confirm_timeout, data,
270 (GDestroyNotify) io_data_unref);
274 static void l2cap_connect(const char *src, const char *dst, uint16_t psm,
275 uint16_t cid, gint disconn,
278 struct io_data *data;
281 printf("Connecting to %s L2CAP PSM %u\n", dst, psm);
283 data = io_data_new(NULL, BT_IO_L2CAP, -1, disconn, -1);
286 data->io = bt_io_connect(BT_IO_L2CAP, connect_cb, data,
287 (GDestroyNotify) io_data_unref,
289 BT_IO_OPT_SOURCE, src,
293 BT_IO_OPT_SEC_LEVEL, sec,
294 BT_IO_OPT_PRIORITY, prio,
297 data->io = bt_io_connect(BT_IO_L2CAP, connect_cb, data,
298 (GDestroyNotify) io_data_unref,
303 BT_IO_OPT_SEC_LEVEL, sec,
304 BT_IO_OPT_PRIORITY, prio,
308 printf("Connecting to %s failed: %s\n", dst, err->message);
314 static void l2cap_listen(const char *src, uint16_t psm, gint defer,
315 gint reject, gint disconn, gint accept,
316 gint sec, gboolean master)
318 struct io_data *data;
332 printf("Listening on L2CAP PSM %u\n", psm);
334 data = io_data_new(NULL, BT_IO_L2CAP, reject, disconn, accept);
337 l2_srv = bt_io_listen(BT_IO_L2CAP, conn, cfm,
338 data, (GDestroyNotify) io_data_unref,
340 BT_IO_OPT_SOURCE, src,
342 BT_IO_OPT_SEC_LEVEL, sec,
343 BT_IO_OPT_MASTER, master,
346 l2_srv = bt_io_listen(BT_IO_L2CAP, conn, cfm,
347 data, (GDestroyNotify) io_data_unref,
350 BT_IO_OPT_SEC_LEVEL, sec,
351 BT_IO_OPT_MASTER, master,
355 printf("Listening failed: %s\n", err->message);
360 g_io_channel_unref(l2_srv);
363 static void rfcomm_connect(const char *src, const char *dst, uint8_t ch,
364 gint disconn, gint sec)
366 struct io_data *data;
369 printf("Connecting to %s RFCOMM channel %u\n", dst, ch);
371 data = io_data_new(NULL, BT_IO_RFCOMM, -1, disconn, -1);
374 data->io = bt_io_connect(BT_IO_RFCOMM, connect_cb, data,
375 (GDestroyNotify) io_data_unref,
377 BT_IO_OPT_SOURCE, src,
379 BT_IO_OPT_CHANNEL, ch,
380 BT_IO_OPT_SEC_LEVEL, sec,
383 data->io = bt_io_connect(BT_IO_RFCOMM, connect_cb, data,
384 (GDestroyNotify) io_data_unref,
387 BT_IO_OPT_CHANNEL, ch,
388 BT_IO_OPT_SEC_LEVEL, sec,
392 printf("Connecting to %s failed: %s\n", dst, err->message);
398 static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer,
399 gint reject, gint disconn, gint accept,
400 gint sec, gboolean master)
402 struct io_data *data;
416 data = io_data_new(NULL, BT_IO_RFCOMM, reject, disconn, accept);
419 rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm,
420 data, (GDestroyNotify) io_data_unref,
422 BT_IO_OPT_SOURCE, src,
423 BT_IO_OPT_CHANNEL, ch,
424 BT_IO_OPT_SEC_LEVEL, sec,
425 BT_IO_OPT_MASTER, master,
428 rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm,
429 data, (GDestroyNotify) io_data_unref,
431 BT_IO_OPT_CHANNEL, ch,
432 BT_IO_OPT_SEC_LEVEL, sec,
433 BT_IO_OPT_MASTER, master,
437 printf("Listening failed: %s\n", err->message);
442 bt_io_get(rc_srv, BT_IO_RFCOMM, &err,
443 BT_IO_OPT_CHANNEL, &ch,
446 printf("Listening on RFCOMM channel %u\n", ch);
448 g_io_channel_unref(rc_srv);
451 static void sco_connect(const char *src, const char *dst, gint disconn)
453 struct io_data *data;
456 printf("Connecting SCO to %s\n", dst);
458 data = io_data_new(NULL, BT_IO_SCO, -1, disconn, -1);
461 data->io = bt_io_connect(BT_IO_SCO, connect_cb, data,
462 (GDestroyNotify) io_data_unref,
464 BT_IO_OPT_SOURCE, src,
468 data->io = bt_io_connect(BT_IO_SCO, connect_cb, data,
469 (GDestroyNotify) io_data_unref,
475 printf("Connecting to %s failed: %s\n", dst, err->message);
481 static void sco_listen(const char *src, gint disconn)
483 struct io_data *data;
487 printf("Listening for SCO connections\n");
489 data = io_data_new(NULL, BT_IO_SCO, -1, disconn, -1);
492 sco_srv = bt_io_listen(BT_IO_SCO, connect_cb, NULL,
493 data, (GDestroyNotify) io_data_unref,
495 BT_IO_OPT_SOURCE, src,
498 sco_srv = bt_io_listen(BT_IO_SCO, connect_cb, NULL,
499 data, (GDestroyNotify) io_data_unref,
500 &err, BT_IO_OPT_INVALID);
503 printf("Listening failed: %s\n", err->message);
508 g_io_channel_unref(sco_srv);
511 static gint opt_channel = -1;
512 static gint opt_psm = 0;
513 static gboolean opt_sco = FALSE;
514 static gboolean opt_defer = FALSE;
515 static char *opt_dev = NULL;
516 static gint opt_reject = -1;
517 static gint opt_disconn = -1;
518 static gint opt_accept = DEFAULT_ACCEPT_TIMEOUT;
519 static gint opt_sec = 0;
520 static gboolean opt_master = FALSE;
521 static gint opt_priority = 0;
522 static gint opt_cid = 0;
524 static GMainLoop *main_loop;
526 static GOptionEntry options[] = {
527 { "channel", 'c', 0, G_OPTION_ARG_INT, &opt_channel,
529 { "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm,
531 { "cid", 'j', 0, G_OPTION_ARG_INT, &opt_cid,
533 { "sco", 's', 0, G_OPTION_ARG_NONE, &opt_sco,
535 { "defer", 'd', 0, G_OPTION_ARG_NONE, &opt_defer,
536 "Use DEFER_SETUP for incoming connections" },
537 { "sec-level", 'S', 0, G_OPTION_ARG_INT, &opt_sec,
539 { "update-sec-level", 'U', 0, G_OPTION_ARG_INT, &opt_update_sec,
540 "Update security level" },
541 { "dev", 'i', 0, G_OPTION_ARG_STRING, &opt_dev,
542 "Which HCI device to use" },
543 { "reject", 'r', 0, G_OPTION_ARG_INT, &opt_reject,
544 "Reject connection after N seconds" },
545 { "disconnect", 'D', 0, G_OPTION_ARG_INT, &opt_disconn,
546 "Disconnect connection after N seconds" },
547 { "accept", 'a', 0, G_OPTION_ARG_INT, &opt_accept,
548 "Accept connection after N seconds" },
549 { "master", 'm', 0, G_OPTION_ARG_NONE, &opt_master,
550 "Master role switch (incoming connections)" },
551 { "priority", 'P', 0, G_OPTION_ARG_INT, &opt_priority,
552 "Transmission priority: Setting a priority "
553 "outside the range 0 to 6 requires the"
554 "CAP_NET_ADMIN capability." },
558 static void sig_term(int sig)
560 g_main_loop_quit(main_loop);
563 int main(int argc, char *argv[])
565 GOptionContext *context;
567 context = g_option_context_new(NULL);
568 g_option_context_add_main_entries(context, options, NULL);
570 if (!g_option_context_parse(context, &argc, &argv, NULL))
573 g_option_context_free(context);
575 printf("accept=%d, reject=%d, discon=%d, defer=%d, sec=%d,"
576 " update_sec=%d, prio=%d\n", opt_accept, opt_reject,
577 opt_disconn, opt_defer, opt_sec, opt_update_sec, opt_priority);
579 if (opt_psm || opt_cid) {
581 l2cap_connect(opt_dev, argv[1], opt_psm, opt_cid,
582 opt_disconn, opt_sec, opt_priority);
584 l2cap_listen(opt_dev, opt_psm, opt_defer, opt_reject,
585 opt_disconn, opt_accept, opt_sec,
589 if (opt_channel != -1) {
591 rfcomm_connect(opt_dev, argv[1], opt_channel,
592 opt_disconn, opt_sec);
594 rfcomm_listen(opt_dev, opt_channel, opt_defer,
595 opt_reject, opt_disconn, opt_accept,
596 opt_sec, opt_master);
601 sco_connect(opt_dev, argv[1], opt_disconn);
603 sco_listen(opt_dev, opt_disconn);
606 signal(SIGTERM, sig_term);
607 signal(SIGINT, sig_term);
609 main_loop = g_main_loop_new(NULL, FALSE);
611 g_main_loop_run(main_loop);
613 g_main_loop_unref(main_loop);