2010-09-09 09:41:19

by Zhenhua Zhang

[permalink] [raw]
Subject: obex: isolate btio.[ch] as a library and do some cleanup

Hi,

These patches move obexd/src/btio.[ch] out from source directory and make it identical with bluez's btio.[ch]. So we can freely copy them among bluez, obex and ofono.

Regards,
Zhenhua



2010-09-10 00:11:35

by Zhenhua Zhang

[permalink] [raw]
Subject: RE: [PATCH 3/4] btio: Remove unused bt_io_set function

Hi Johan,

Johan Hedberg wrote:
> Hi,
>
> On Thu, Sep 09, 2010, Zhenhua Zhang wrote:
>> It is not used by either obex or bluez.
>> ---
>> btio/btio.c | 33 --------------------------------- btio/btio.h |
>> 3 --- 2 files changed, 0 insertions(+), 36 deletions(-)
>
> I don't think removing this feature is a good idea. Even though there
> aren't any current users of bt_io_set doesn't mean that there
> wont be in
> the future. I remember e.g. discussions regarding AMP about
> applications needing the ability to request a switch from BR/EDR to
> WLAN for an active connection. This could e.g. be accomplished
> through a setsockopt call. Other uses for setsockopt while a
> connection is open, or even changing settings for an existing server
> socket might exist too.
>
> Johan

That's fine for me. I don't see any current function call so I have this patch. I will resend them and remove patch 3/4. Let me know if you have other suggestiosn.

Regards,
Zhenhua


2010-09-09 10:38:42

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH 3/4] btio: Remove unused bt_io_set function

Hi,

On Thu, Sep 09, 2010, Zhenhua Zhang wrote:
> It is not used by either obex or bluez.
> ---
> btio/btio.c | 33 ---------------------------------
> btio/btio.h | 3 ---
> 2 files changed, 0 insertions(+), 36 deletions(-)

I don't think removing this feature is a good idea. Even though there
aren't any current users of bt_io_set doesn't mean that there wont be in
the future. I remember e.g. discussions regarding AMP about applications
needing the ability to request a switch from BR/EDR to WLAN for an
active connection. This could e.g. be accomplished through a setsockopt
call. Other uses for setsockopt while a connection is open, or even
changing settings for an existing server socket might exist too.

Johan

2010-09-09 09:41:23

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 4/4] btio: Replace void * with gpointer

TO make it consistent with bluez btio.c.
---
btio/btio.c | 24 ++++++++++++------------
btio/btio.h | 10 +++++-----
2 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/btio/btio.c b/btio/btio.c
index d4969e5..41b698f 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -62,20 +62,20 @@ struct set_opts {

struct connect {
BtIOConnect connect;
- void *user_data;
+ gpointer user_data;
GDestroyNotify destroy;
};

struct accept {
BtIOConnect connect;
- void *user_data;
+ gpointer user_data;
GDestroyNotify destroy;
};

struct server {
BtIOConnect connect;
BtIOConfirm confirm;
- void *user_data;
+ gpointer user_data;
GDestroyNotify destroy;
};

@@ -115,7 +115,7 @@ static gboolean check_nval(GIOChannel *io)
}

static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
+ gpointer user_data)
{
struct accept *accept = user_data;
GError *err = NULL;
@@ -136,7 +136,7 @@ static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
}

static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
+ gpointer user_data)
{
struct connect *conn = user_data;
GError *gerr = NULL;
@@ -169,7 +169,7 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
}

static gboolean server_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
+ gpointer user_data)
{
struct server *server = user_data;
int srv_sock, cli_sock;
@@ -201,7 +201,7 @@ static gboolean server_cb(GIOChannel *io, GIOCondition cond,
}

static void server_add(GIOChannel *io, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
+ BtIOConfirm confirm, gpointer user_data,
GDestroyNotify destroy)
{
struct server *server;
@@ -219,7 +219,7 @@ static void server_add(GIOChannel *io, BtIOConnect connect,
}

static void connect_add(GIOChannel *io, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy)
+ gpointer user_data, GDestroyNotify destroy)
{
struct connect *conn;
GIOCondition cond;
@@ -234,7 +234,7 @@ static void connect_add(GIOChannel *io, BtIOConnect connect,
(GDestroyNotify) connect_remove);
}

-static void accept_add(GIOChannel *io, BtIOConnect connect, void *user_data,
+static void accept_add(GIOChannel *io, BtIOConnect connect, gpointer user_data,
GDestroyNotify destroy)
{
struct accept *accept;
@@ -1046,7 +1046,7 @@ static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
return FALSE;
}

-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
GDestroyNotify destroy, GError **err)
{
int sock;
@@ -1162,7 +1162,7 @@ failed:
}

GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
+ gpointer user_data, GDestroyNotify destroy,
GError **gerr, BtIOOption opt1, ...)
{
GIOChannel *io;
@@ -1216,7 +1216,7 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
}

GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
+ BtIOConfirm confirm, gpointer user_data,
GDestroyNotify destroy, GError **err,
BtIOOption opt1, ...)
{
diff --git a/btio/btio.h b/btio/btio.h
index 3c5db2a..5f2911a 100644
--- a/btio/btio.h
+++ b/btio/btio.h
@@ -72,22 +72,22 @@ typedef enum {
BT_IO_SEC_HIGH,
} BtIOSecLevel;

-typedef void (*BtIOConfirm)(GIOChannel *io, void *user_data);
+typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data);

-typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
+typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);

-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
GDestroyNotify destroy, GError **err);

gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
BtIOOption opt1, ...);

GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
+ gpointer user_data, GDestroyNotify destroy,
GError **err, BtIOOption opt1, ...);

GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
+ BtIOConfirm confirm, gpointer user_data,
GDestroyNotify destroy, GError **err,
BtIOOption opt1, ...);

--
1.7.0.4


2010-09-09 09:41:21

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 2/4] btio: Seperate btio.[ch] into btio directory

Seperate btio.[ch] from src directory to btio sub-folder.
---
Makefile.am | 19 +-
btio/btio.c | 1299 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
btio/btio.h | 97 +++++
src/btio.c | 1299 -----------------------------------------------------------
src/btio.h | 97 -----
5 files changed, 1406 insertions(+), 1405 deletions(-)
create mode 100644 btio/btio.c
create mode 100644 btio/btio.h
delete mode 100644 src/btio.c
delete mode 100644 src/btio.h

diff --git a/Makefile.am b/Makefile.am
index 07fc27d..961a375 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,6 +18,8 @@ gwobex_sources = gwobex/gw-obex.h gwobex/gw-obex.c \
gwobex/obex-xfer.h gwobex/obex-xfer.c \
gwobex/utils.h gwobex/utils.c gwobex/log.h

+btio_sources = btio/btio.h btio/btio.c
+
libexec_PROGRAMS =

if SERVER
@@ -65,11 +67,10 @@ builtin_nodist += plugins/phonebook.c

libexec_PROGRAMS += src/obexd

-src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) \
+src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) $(btio_sources) \
src/main.c src/obexd.h src/plugin.h src/plugin.c \
- src/log.h src/log.c src/btio.h src/btio.c \
- src/dbus.h src/manager.c src/obex.h src/obex.c \
- src/obex-priv.h \
+ src/log.h src/log.c src/dbus.h src/manager.c \
+ src/obex.h src/obex.c src/obex-priv.h \
src/mimetype.h src/mimetype.c \
src/service.h src/service.c \
src/transport.h src/transport.c \
@@ -107,13 +108,12 @@ service_in_files += client/obex-client.service.in

libexec_PROGRAMS += client/obex-client

-client_obex_client_SOURCES = $(gdbus_sources) $(gwobex_sources) client/main.c \
- client/session.h client/session.c \
+client_obex_client_SOURCES = $(gdbus_sources) $(gwobex_sources) $(btio_sources) \
+ client/main.c client/session.h client/session.c \
src/log.h src/log.c \
client/pbap.h client/pbap.c \
client/sync.h client/sync.c \
- client/transfer.h client/transfer.c \
- src/btio.c src/btio.h
+ client/transfer.h client/transfer.c

client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @OPENOBEX_LIBS@ @BLUEZ_LIBS@
endif
@@ -126,7 +126,8 @@ AM_CFLAGS = @OPENOBEX_CFLAGS@ @BLUEZ_CFLAGS@ @EBOOK_CFLAGS@ \
-DOBEX_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"

INCLUDES = -I$(builddir)/src -I$(srcdir)/src -I$(srcdir)/plugins \
- -I$(srcdir)/gdbus -I$(srcdir)/gwobex
+ -I$(srcdir)/gdbus -I$(srcdir)/gwobex \
+ -I$(srcdir)/btio

CLEANFILES = $(service_DATA) $(builtin_files)

diff --git a/btio/btio.c b/btio/btio.c
new file mode 100644
index 0000000..42a3bcd
--- /dev/null
+++ b/btio/btio.c
@@ -0,0 +1,1299 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009-2010 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include <glib.h>
+
+#include "btio.h"
+
+#define ERROR_FAILED(gerr, str, err) \
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+ str ": %s (%d)", strerror(err), err)
+
+#define DEFAULT_DEFER_TIMEOUT 30
+
+struct set_opts {
+ bdaddr_t src;
+ bdaddr_t dst;
+ int defer;
+ int sec_level;
+ uint8_t channel;
+ uint16_t psm;
+ uint16_t mtu;
+ uint16_t imtu;
+ uint16_t omtu;
+ int master;
+ uint8_t mode;
+};
+
+struct connect {
+ BtIOConnect connect;
+ void *user_data;
+ GDestroyNotify destroy;
+};
+
+struct accept {
+ BtIOConnect connect;
+ void *user_data;
+ GDestroyNotify destroy;
+};
+
+struct server {
+ BtIOConnect connect;
+ BtIOConfirm confirm;
+ void *user_data;
+ GDestroyNotify destroy;
+};
+
+static void server_remove(struct server *server)
+{
+ if (server->destroy)
+ server->destroy(server->user_data);
+ g_free(server);
+}
+
+static void connect_remove(struct connect *conn)
+{
+ if (conn->destroy)
+ conn->destroy(conn->user_data);
+ g_free(conn);
+}
+
+static void accept_remove(struct accept *accept)
+{
+ if (accept->destroy)
+ accept->destroy(accept->user_data);
+ g_free(accept);
+}
+
+static gboolean check_nval(GIOChannel *io)
+{
+ struct pollfd fds;
+
+ memset(&fds, 0, sizeof(fds));
+ fds.fd = g_io_channel_unix_get_fd(io);
+ fds.events = POLLNVAL;
+
+ if (poll(&fds, 1, 0) > 0 && (fds.revents & POLLNVAL))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
+ void *user_data)
+{
+ struct accept *accept = user_data;
+ GError *err = NULL;
+
+ /* If the user aborted this accept attempt */
+ if ((cond & G_IO_NVAL) || check_nval(io))
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
+ "HUP or ERR on socket");
+
+ accept->connect(io, err, accept->user_data);
+
+ g_clear_error(&err);
+
+ return FALSE;
+}
+
+static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
+ void *user_data)
+{
+ struct connect *conn = user_data;
+ GError *gerr = NULL;
+
+ /* If the user aborted this connect attempt */
+ if ((cond & G_IO_NVAL) || check_nval(io))
+ return FALSE;
+
+ if (cond & G_IO_OUT) {
+ int err = 0, sock = g_io_channel_unix_get_fd(io);
+ socklen_t len = sizeof(err);
+
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
+ err = errno;
+
+ if (err)
+ g_set_error(&gerr, BT_IO_ERROR,
+ BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
+ strerror(err), err);
+ } else if (cond & (G_IO_HUP | G_IO_ERR))
+ g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
+ "HUP or ERR on socket");
+
+ conn->connect(io, gerr, conn->user_data);
+
+ if (gerr)
+ g_error_free(gerr);
+
+ return FALSE;
+}
+
+static gboolean server_cb(GIOChannel *io, GIOCondition cond,
+ void *user_data)
+{
+ struct server *server = user_data;
+ int srv_sock, cli_sock;
+ GIOChannel *cli_io;
+
+ /* If the user closed the server */
+ if ((cond & G_IO_NVAL) || check_nval(io))
+ return FALSE;
+
+ srv_sock = g_io_channel_unix_get_fd(io);
+
+ cli_sock = accept(srv_sock, NULL, NULL);
+ if (cli_sock < 0)
+ return TRUE;
+
+ cli_io = g_io_channel_unix_new(cli_sock);
+
+ g_io_channel_set_close_on_unref(cli_io, TRUE);
+ g_io_channel_set_flags(cli_io, G_IO_FLAG_NONBLOCK, NULL);
+
+ if (server->confirm)
+ server->confirm(cli_io, server->user_data);
+ else
+ server->connect(cli_io, NULL, server->user_data);
+
+ g_io_channel_unref(cli_io);
+
+ return TRUE;
+}
+
+static void server_add(GIOChannel *io, BtIOConnect connect,
+ BtIOConfirm confirm, void *user_data,
+ GDestroyNotify destroy)
+{
+ struct server *server;
+ GIOCondition cond;
+
+ server = g_new0(struct server, 1);
+ server->connect = connect;
+ server->confirm = confirm;
+ server->user_data = user_data;
+ server->destroy = destroy;
+
+ cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, server_cb, server,
+ (GDestroyNotify) server_remove);
+}
+
+static void connect_add(GIOChannel *io, BtIOConnect connect,
+ void *user_data, GDestroyNotify destroy)
+{
+ struct connect *conn;
+ GIOCondition cond;
+
+ conn = g_new0(struct connect, 1);
+ conn->connect = connect;
+ conn->user_data = user_data;
+ conn->destroy = destroy;
+
+ cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, connect_cb, conn,
+ (GDestroyNotify) connect_remove);
+}
+
+static void accept_add(GIOChannel *io, BtIOConnect connect, void *user_data,
+ GDestroyNotify destroy)
+{
+ struct accept *accept;
+ GIOCondition cond;
+
+ accept = g_new0(struct accept, 1);
+ accept->connect = connect;
+ accept->user_data = user_data;
+ accept->destroy = destroy;
+
+ cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, accept_cb, accept,
+ (GDestroyNotify) accept_remove);
+}
+
+static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm, GError **err)
+{
+ struct sockaddr_l2 addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, src);
+ addr.l2_psm = htobs(psm);
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "l2cap_bind", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int l2cap_connect(int sock, const bdaddr_t *dst, uint16_t psm)
+{
+ int err;
+ struct sockaddr_l2 addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(psm);
+
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return err;
+
+ return 0;
+}
+
+static int l2cap_set_master(int sock, int master)
+{
+ int flags;
+ socklen_t len;
+
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len) < 0)
+ return -errno;
+
+ if (master) {
+ if (flags & L2CAP_LM_MASTER)
+ return 0;
+ flags |= L2CAP_LM_MASTER;
+ } else {
+ if (!(flags & L2CAP_LM_MASTER))
+ return 0;
+ flags &= ~L2CAP_LM_MASTER;
+ }
+
+ if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, sizeof(flags)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int rfcomm_set_master(int sock, int master)
+{
+ int flags;
+ socklen_t len;
+
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, &len) < 0)
+ return -errno;
+
+ if (master) {
+ if (flags & RFCOMM_LM_MASTER)
+ return 0;
+ flags |= RFCOMM_LM_MASTER;
+ } else {
+ if (!(flags & RFCOMM_LM_MASTER))
+ return 0;
+ flags &= ~RFCOMM_LM_MASTER;
+ }
+
+ if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, sizeof(flags)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int l2cap_set_lm(int sock, int level)
+{
+ int lm_map[] = {
+ 0,
+ L2CAP_LM_AUTH,
+ L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT,
+ L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE,
+ }, opt = lm_map[level];
+
+ if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int rfcomm_set_lm(int sock, int level)
+{
+ int lm_map[] = {
+ 0,
+ RFCOMM_LM_AUTH,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE,
+ }, opt = lm_map[level];
+
+ if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
+{
+ struct bt_security sec;
+ int ret;
+
+ if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Valid security level range is %d-%d",
+ BT_SECURITY_LOW, BT_SECURITY_HIGH);
+ return FALSE;
+ }
+
+ memset(&sec, 0, sizeof(sec));
+ sec.level = level;
+
+ if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec,
+ sizeof(sec)) == 0)
+ return TRUE;
+
+ if (errno != ENOPROTOOPT) {
+ ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno);
+ return FALSE;
+ }
+
+ if (type == BT_IO_L2CAP)
+ ret = l2cap_set_lm(sock, level);
+ else
+ ret = rfcomm_set_lm(sock, level);
+
+ if (ret < 0) {
+ ERROR_FAILED(err, "setsockopt(LM)", -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int l2cap_get_lm(int sock, int *sec_level)
+{
+ int opt;
+ socklen_t len;
+
+ len = sizeof(opt);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, &len) < 0)
+ return -errno;
+
+ *sec_level = 0;
+
+ if (opt & L2CAP_LM_AUTH)
+ *sec_level = BT_SECURITY_LOW;
+ if (opt & L2CAP_LM_ENCRYPT)
+ *sec_level = BT_SECURITY_MEDIUM;
+ if (opt & L2CAP_LM_SECURE)
+ *sec_level = BT_SECURITY_HIGH;
+
+ return 0;
+}
+
+static int rfcomm_get_lm(int sock, int *sec_level)
+{
+ int opt;
+ socklen_t len;
+
+ len = sizeof(opt);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, &len) < 0)
+ return -errno;
+
+ *sec_level = 0;
+
+ if (opt & RFCOMM_LM_AUTH)
+ *sec_level = BT_SECURITY_LOW;
+ if (opt & RFCOMM_LM_ENCRYPT)
+ *sec_level = BT_SECURITY_MEDIUM;
+ if (opt & RFCOMM_LM_SECURE)
+ *sec_level = BT_SECURITY_HIGH;
+
+ return 0;
+}
+
+static gboolean get_sec_level(int sock, BtIOType type, int *level,
+ GError **err)
+{
+ struct bt_security sec;
+ socklen_t len;
+ int ret;
+
+ memset(&sec, 0, sizeof(sec));
+ len = sizeof(sec);
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) {
+ *level = sec.level;
+ return TRUE;
+ }
+
+ if (errno != ENOPROTOOPT) {
+ ERROR_FAILED(err, "getsockopt(BT_SECURITY)", errno);
+ return FALSE;
+ }
+
+ if (type == BT_IO_L2CAP)
+ ret = l2cap_get_lm(sock, level);
+ else
+ ret = rfcomm_get_lm(sock, level);
+
+ if (ret < 0) {
+ ERROR_FAILED(err, "getsockopt(LM)", -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu,
+ uint8_t mode, int master, GError **err)
+{
+ if (imtu || omtu || mode) {
+ struct l2cap_options l2o;
+ socklen_t len;
+
+ memset(&l2o, 0, sizeof(l2o));
+ len = sizeof(l2o);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
+ &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ if (imtu)
+ l2o.imtu = imtu;
+ if (omtu)
+ l2o.omtu = omtu;
+ if (mode)
+ l2o.mode = mode;
+
+ if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
+ sizeof(l2o)) < 0) {
+ ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno);
+ return FALSE;
+ }
+ }
+
+ if (master >= 0 && l2cap_set_master(sock, master) < 0) {
+ ERROR_FAILED(err, "l2cap_set_master", errno);
+ return FALSE;
+ }
+
+ if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err))
+ return FALSE;
+
+ return TRUE;
+}
+
+static int rfcomm_bind(int sock,
+ const bdaddr_t *src, uint8_t channel, GError **err)
+{
+ struct sockaddr_rc addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+ addr.rc_channel = channel;
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "rfcomm_bind", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel)
+{
+ int err;
+ struct sockaddr_rc addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, dst);
+ addr.rc_channel = channel;
+
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return err;
+
+ return 0;
+}
+
+static gboolean rfcomm_set(int sock, int sec_level, int master, GError **err)
+{
+ if (sec_level && !set_sec_level(sock, BT_IO_RFCOMM, sec_level, err))
+ return FALSE;
+
+ if (master >= 0 && rfcomm_set_master(sock, master) < 0) {
+ ERROR_FAILED(err, "rfcomm_set_master", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int sco_bind(int sock, const bdaddr_t *src, GError **err)
+{
+ struct sockaddr_sco addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, src);
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ ERROR_FAILED(err, "sco_bind", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sco_connect(int sock, const bdaddr_t *dst)
+{
+ struct sockaddr_sco addr;
+ int err;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, dst);
+
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ return err;
+
+ return 0;
+}
+
+static gboolean sco_set(int sock, uint16_t mtu, GError **err)
+{
+ struct sco_options sco_opt;
+ socklen_t len;
+
+ if (!mtu)
+ return TRUE;
+
+ len = sizeof(sco_opt);
+ memset(&sco_opt, 0, len);
+ if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ sco_opt.mtu = mtu;
+ if (setsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt,
+ sizeof(sco_opt)) < 0) {
+ ERROR_FAILED(err, "setsockopt(SCO_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean parse_set_opts(struct set_opts *opts, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ BtIOOption opt = opt1;
+ const char *str;
+
+ memset(opts, 0, sizeof(*opts));
+
+ /* Set defaults */
+ opts->defer = DEFAULT_DEFER_TIMEOUT;
+ opts->master = -1;
+ opts->sec_level = BT_IO_SEC_MEDIUM;
+ opts->mode = L2CAP_MODE_BASIC;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ str = va_arg(args, const char *);
+ if (strncasecmp(str, "hci", 3) == 0)
+ hci_devba(atoi(str + 3), &opts->src);
+ else
+ str2ba(str, &opts->src);
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(&opts->src, va_arg(args, const bdaddr_t *));
+ break;
+ case BT_IO_OPT_DEST:
+ str2ba(va_arg(args, const char *), &opts->dst);
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(&opts->dst, va_arg(args, const bdaddr_t *));
+ break;
+ case BT_IO_OPT_DEFER_TIMEOUT:
+ opts->defer = va_arg(args, int);
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ opts->sec_level = va_arg(args, int);
+ break;
+ case BT_IO_OPT_CHANNEL:
+ opts->channel = va_arg(args, int);
+ break;
+ case BT_IO_OPT_PSM:
+ opts->psm = va_arg(args, int);
+ break;
+ case BT_IO_OPT_MTU:
+ opts->mtu = va_arg(args, int);
+ opts->imtu = opts->mtu;
+ opts->omtu = opts->mtu;
+ break;
+ case BT_IO_OPT_OMTU:
+ opts->omtu = va_arg(args, int);
+ if (!opts->mtu)
+ opts->mtu = opts->omtu;
+ break;
+ case BT_IO_OPT_IMTU:
+ opts->imtu = va_arg(args, int);
+ if (!opts->mtu)
+ opts->mtu = opts->imtu;
+ break;
+ case BT_IO_OPT_MASTER:
+ opts->master = va_arg(args, gboolean);
+ break;
+ case BT_IO_OPT_MODE:
+ opts->mode = va_arg(args, int);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst,
+ socklen_t len, GError **err)
+{
+ socklen_t olen;
+
+ memset(src, 0, len);
+ olen = len;
+ if (getsockname(sock, src, &olen) < 0) {
+ ERROR_FAILED(err, "getsockname", errno);
+ return FALSE;
+ }
+
+ memset(dst, 0, len);
+ olen = len;
+ if (getpeername(sock, dst, &olen) < 0) {
+ ERROR_FAILED(err, "getpeername", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int l2cap_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
+{
+ struct l2cap_conninfo info;
+ socklen_t len;
+
+ len = sizeof(info);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_CONNINFO, &info, &len) < 0)
+ return -errno;
+
+ if (handle)
+ *handle = info.hci_handle;
+
+ if (dev_class)
+ memcpy(dev_class, info.dev_class, 3);
+
+ return 0;
+}
+
+static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
+ va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_l2 src, dst;
+ struct l2cap_options l2o;
+ int flags;
+ uint8_t dev_class[3];
+ uint16_t handle;
+ socklen_t len;
+
+ len = sizeof(l2o);
+ memset(&l2o, 0, len);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.l2_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &src.l2_bdaddr);
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.l2_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
+ break;
+ case BT_IO_OPT_DEFER_TIMEOUT:
+ len = sizeof(int);
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
+ va_arg(args, int *), &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
+ errno);
+ return FALSE;
+ }
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ if (!get_sec_level(sock, BT_IO_L2CAP,
+ va_arg(args, int *), err))
+ return FALSE;
+ break;
+ case BT_IO_OPT_PSM:
+ *(va_arg(args, uint16_t *)) = src.l2_psm ?
+ src.l2_psm : dst.l2_psm;
+ break;
+ case BT_IO_OPT_OMTU:
+ *(va_arg(args, uint16_t *)) = l2o.omtu;
+ break;
+ case BT_IO_OPT_IMTU:
+ *(va_arg(args, uint16_t *)) = l2o.imtu;
+ break;
+ case BT_IO_OPT_MASTER:
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags,
+ &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(L2CAP_LM)",
+ errno);
+ return FALSE;
+ }
+ *(va_arg(args, gboolean *)) =
+ (flags & L2CAP_LM_MASTER) ? TRUE : FALSE;
+ break;
+ case BT_IO_OPT_HANDLE:
+ if (l2cap_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
+ return FALSE;
+ }
+ *(va_arg(args, uint16_t *)) = handle;
+ break;
+ case BT_IO_OPT_CLASS:
+ if (l2cap_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
+ return FALSE;
+ }
+ memcpy(va_arg(args, uint8_t *), dev_class, 3);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static int rfcomm_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
+{
+ struct rfcomm_conninfo info;
+ socklen_t len;
+
+ len = sizeof(info);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_CONNINFO, &info, &len) < 0)
+ return -errno;
+
+ if (handle)
+ *handle = info.hci_handle;
+
+ if (dev_class)
+ memcpy(dev_class, info.dev_class, 3);
+
+ return 0;
+}
+
+static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
+ va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_rc src, dst;
+ int flags;
+ socklen_t len;
+ uint8_t dev_class[3];
+ uint16_t handle;
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &src.rc_bdaddr);
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &dst.rc_bdaddr);
+ break;
+ case BT_IO_OPT_DEFER_TIMEOUT:
+ len = sizeof(int);
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
+ va_arg(args, int *), &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
+ errno);
+ return FALSE;
+ }
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ if (!get_sec_level(sock, BT_IO_RFCOMM,
+ va_arg(args, int *), err))
+ return FALSE;
+ break;
+ case BT_IO_OPT_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel ?
+ src.rc_channel : dst.rc_channel;
+ break;
+ case BT_IO_OPT_SOURCE_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel;
+ break;
+ case BT_IO_OPT_DEST_CHANNEL:
+ *(va_arg(args, uint8_t *)) = dst.rc_channel;
+ break;
+ case BT_IO_OPT_MASTER:
+ len = sizeof(flags);
+ if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags,
+ &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(RFCOMM_LM)",
+ errno);
+ return FALSE;
+ }
+ *(va_arg(args, gboolean *)) =
+ (flags & RFCOMM_LM_MASTER) ? TRUE : FALSE;
+ break;
+ case BT_IO_OPT_HANDLE:
+ if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ *(va_arg(args, uint16_t *)) = handle;
+ break;
+ case BT_IO_OPT_CLASS:
+ if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ memcpy(va_arg(args, uint8_t *), dev_class, 3);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static int sco_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
+{
+ struct sco_conninfo info;
+ socklen_t len;
+
+ len = sizeof(info);
+ if (getsockopt(sock, SOL_SCO, SCO_CONNINFO, &info, &len) < 0)
+ return -errno;
+
+ if (handle)
+ *handle = info.hci_handle;
+
+ if (dev_class)
+ memcpy(dev_class, info.dev_class, 3);
+
+ return 0;
+}
+
+static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_sco src, dst;
+ struct sco_options sco_opt;
+ socklen_t len;
+ uint8_t dev_class[3];
+ uint16_t handle;
+
+ len = sizeof(sco_opt);
+ memset(&sco_opt, 0, len);
+ if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
+ return FALSE;
+ }
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.sco_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_SOURCE_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &src.sco_bdaddr);
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.sco_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST_BDADDR:
+ bacpy(va_arg(args, bdaddr_t *), &dst.sco_bdaddr);
+ break;
+ case BT_IO_OPT_MTU:
+ case BT_IO_OPT_IMTU:
+ case BT_IO_OPT_OMTU:
+ *(va_arg(args, uint16_t *)) = sco_opt.mtu;
+ break;
+ case BT_IO_OPT_HANDLE:
+ if (sco_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ *(va_arg(args, uint16_t *)) = handle;
+ break;
+ case BT_IO_OPT_CLASS:
+ if (sco_get_info(sock, &handle, dev_class) < 0) {
+ ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
+ return FALSE;
+ }
+ memcpy(va_arg(args, uint8_t *), dev_class, 3);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ int sock;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ case BT_IO_L2CAP:
+ return l2cap_get(sock, err, opt1, args);
+ case BT_IO_RFCOMM:
+ return rfcomm_get(sock, err, opt1, args);
+ case BT_IO_SCO:
+ return sco_get(sock, err, opt1, args);
+ }
+
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return FALSE;
+}
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+ GDestroyNotify destroy, GError **err)
+{
+ int sock;
+ char c;
+ struct pollfd pfd;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = POLLOUT;
+
+ if (poll(&pfd, 1, 0) < 0) {
+ ERROR_FAILED(err, "poll", errno);
+ return FALSE;
+ }
+
+ if (!(pfd.revents & POLLOUT)) {
+ int ret;
+ ret = read(sock, &c, 1);
+ }
+
+ accept_add(io, connect, user_data, destroy);
+
+ return TRUE;
+}
+
+gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...)
+{
+ va_list args;
+ gboolean ret;
+ struct set_opts opts;
+ int sock;
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, err, opt1, args);
+ va_end(args);
+
+ if (!ret)
+ return ret;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ case BT_IO_L2CAP:
+ return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
+ opts.mode, opts.master, err);
+ case BT_IO_RFCOMM:
+ return rfcomm_set(sock, opts.sec_level, opts.master, err);
+ case BT_IO_SCO:
+ return sco_set(sock, opts.mtu, err);
+ }
+
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return FALSE;
+}
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...)
+{
+ va_list args;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = get_valist(io, type, err, opt1, args);
+ va_end(args);
+
+ return ret;
+}
+
+static GIOChannel *create_io(BtIOType type, gboolean server,
+ struct set_opts *opts, GError **err)
+{
+ int sock;
+ GIOChannel *io;
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
+ return NULL;
+ }
+ if (l2cap_bind(sock, &opts->src,
+ server ? opts->psm : 0, err) < 0)
+ goto failed;
+ if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, err))
+ goto failed;
+ break;
+ case BT_IO_L2CAP:
+ sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);
+ return NULL;
+ }
+ if (l2cap_bind(sock, &opts->src,
+ server ? opts->psm : 0, err) < 0)
+ goto failed;
+ if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
+ opts->mode, opts->master, err))
+ goto failed;
+ break;
+ case BT_IO_RFCOMM:
+ sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno);
+ return NULL;
+ }
+ if (rfcomm_bind(sock, &opts->src,
+ server ? opts->channel : 0, err) < 0)
+ goto failed;
+ if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
+ goto failed;
+ break;
+ case BT_IO_SCO:
+ sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno);
+ return NULL;
+ }
+ if (sco_bind(sock, &opts->src, err) < 0)
+ goto failed;
+ if (!sco_set(sock, opts->mtu, err))
+ goto failed;
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return NULL;
+ }
+
+ io = g_io_channel_unix_new(sock);
+
+ g_io_channel_set_close_on_unref(io, TRUE);
+ g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+
+ return io;
+
+failed:
+ close(sock);
+
+ return NULL;
+}
+
+GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
+ void *user_data, GDestroyNotify destroy,
+ GError **gerr, BtIOOption opt1, ...)
+{
+ GIOChannel *io;
+ va_list args;
+ struct set_opts opts;
+ int err, sock;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, gerr, opt1, args);
+ va_end(args);
+
+ if (ret == FALSE)
+ return NULL;
+
+ io = create_io(type, FALSE, &opts, gerr);
+ if (io == NULL)
+ return NULL;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ switch (type) {
+ case BT_IO_L2RAW:
+ err = l2cap_connect(sock, &opts.dst, 0);
+ break;
+ case BT_IO_L2CAP:
+ err = l2cap_connect(sock, &opts.dst, opts.psm);
+ break;
+ case BT_IO_RFCOMM:
+ err = rfcomm_connect(sock, &opts.dst, opts.channel);
+ break;
+ case BT_IO_SCO:
+ err = sco_connect(sock, &opts.dst);
+ break;
+ default:
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return NULL;
+ }
+
+ if (err < 0) {
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
+ "connect: %s (%d)", strerror(-err), -err);
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ connect_add(io, connect, user_data, destroy);
+
+ return io;
+}
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, void *user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...)
+{
+ GIOChannel *io;
+ va_list args;
+ struct set_opts opts;
+ int sock;
+ gboolean ret;
+
+ if (type == BT_IO_L2RAW) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Server L2CAP RAW sockets not supported");
+ return NULL;
+ }
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, err, opt1, args);
+ va_end(args);
+
+ if (ret == FALSE)
+ return NULL;
+
+ io = create_io(type, TRUE, &opts, err);
+ if (io == NULL)
+ return NULL;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ if (confirm)
+ setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer,
+ sizeof(opts.defer));
+
+ if (listen(sock, 5) < 0) {
+ ERROR_FAILED(err, "listen", errno);
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ server_add(io, connect, confirm, user_data, destroy);
+
+ return io;
+}
+
+GQuark bt_io_error_quark(void)
+{
+ return g_quark_from_static_string("bt-io-error-quark");
+}
diff --git a/btio/btio.h b/btio/btio.h
new file mode 100644
index 0000000..e9dcc9f
--- /dev/null
+++ b/btio/btio.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009-2010 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifndef BT_IO_H
+#define BT_IO_H
+
+#include <glib.h>
+
+typedef enum {
+ BT_IO_ERROR_DISCONNECTED,
+ BT_IO_ERROR_CONNECT_FAILED,
+ BT_IO_ERROR_FAILED,
+ BT_IO_ERROR_INVALID_ARGS,
+} BtIOError;
+
+#define BT_IO_ERROR bt_io_error_quark()
+
+GQuark bt_io_error_quark(void);
+
+typedef enum {
+ BT_IO_L2RAW,
+ BT_IO_L2CAP,
+ BT_IO_RFCOMM,
+ BT_IO_SCO,
+} BtIOType;
+
+typedef enum {
+ BT_IO_OPT_INVALID = 0,
+ BT_IO_OPT_SOURCE,
+ BT_IO_OPT_SOURCE_BDADDR,
+ BT_IO_OPT_DEST,
+ BT_IO_OPT_DEST_BDADDR,
+ BT_IO_OPT_DEFER_TIMEOUT,
+ BT_IO_OPT_SEC_LEVEL,
+ BT_IO_OPT_CHANNEL,
+ BT_IO_OPT_SOURCE_CHANNEL,
+ BT_IO_OPT_DEST_CHANNEL,
+ BT_IO_OPT_PSM,
+ BT_IO_OPT_MTU,
+ BT_IO_OPT_OMTU,
+ BT_IO_OPT_IMTU,
+ BT_IO_OPT_MASTER,
+ BT_IO_OPT_HANDLE,
+ BT_IO_OPT_CLASS,
+ BT_IO_OPT_MODE,
+} BtIOOption;
+
+typedef enum {
+ BT_IO_SEC_SDP = 0,
+ BT_IO_SEC_LOW,
+ BT_IO_SEC_MEDIUM,
+ BT_IO_SEC_HIGH,
+} BtIOSecLevel;
+
+typedef void (*BtIOConfirm)(GIOChannel *io, void *user_data);
+
+typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
+ GDestroyNotify destroy, GError **err);
+
+gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...);
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...);
+
+GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
+ void *user_data, GDestroyNotify destroy,
+ GError **err, BtIOOption opt1, ...);
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, void *user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...);
+
+#endif
diff --git a/src/btio.c b/src/btio.c
deleted file mode 100644
index 42a3bcd..0000000
--- a/src/btio.c
+++ /dev/null
@@ -1,1299 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2009-2010 Marcel Holtmann <[email protected]>
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sco.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-
-#include <glib.h>
-
-#include "btio.h"
-
-#define ERROR_FAILED(gerr, str, err) \
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
- str ": %s (%d)", strerror(err), err)
-
-#define DEFAULT_DEFER_TIMEOUT 30
-
-struct set_opts {
- bdaddr_t src;
- bdaddr_t dst;
- int defer;
- int sec_level;
- uint8_t channel;
- uint16_t psm;
- uint16_t mtu;
- uint16_t imtu;
- uint16_t omtu;
- int master;
- uint8_t mode;
-};
-
-struct connect {
- BtIOConnect connect;
- void *user_data;
- GDestroyNotify destroy;
-};
-
-struct accept {
- BtIOConnect connect;
- void *user_data;
- GDestroyNotify destroy;
-};
-
-struct server {
- BtIOConnect connect;
- BtIOConfirm confirm;
- void *user_data;
- GDestroyNotify destroy;
-};
-
-static void server_remove(struct server *server)
-{
- if (server->destroy)
- server->destroy(server->user_data);
- g_free(server);
-}
-
-static void connect_remove(struct connect *conn)
-{
- if (conn->destroy)
- conn->destroy(conn->user_data);
- g_free(conn);
-}
-
-static void accept_remove(struct accept *accept)
-{
- if (accept->destroy)
- accept->destroy(accept->user_data);
- g_free(accept);
-}
-
-static gboolean check_nval(GIOChannel *io)
-{
- struct pollfd fds;
-
- memset(&fds, 0, sizeof(fds));
- fds.fd = g_io_channel_unix_get_fd(io);
- fds.events = POLLNVAL;
-
- if (poll(&fds, 1, 0) > 0 && (fds.revents & POLLNVAL))
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
-{
- struct accept *accept = user_data;
- GError *err = NULL;
-
- /* If the user aborted this accept attempt */
- if ((cond & G_IO_NVAL) || check_nval(io))
- return FALSE;
-
- if (cond & (G_IO_HUP | G_IO_ERR))
- g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
- "HUP or ERR on socket");
-
- accept->connect(io, err, accept->user_data);
-
- g_clear_error(&err);
-
- return FALSE;
-}
-
-static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
-{
- struct connect *conn = user_data;
- GError *gerr = NULL;
-
- /* If the user aborted this connect attempt */
- if ((cond & G_IO_NVAL) || check_nval(io))
- return FALSE;
-
- if (cond & G_IO_OUT) {
- int err = 0, sock = g_io_channel_unix_get_fd(io);
- socklen_t len = sizeof(err);
-
- if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
- err = errno;
-
- if (err)
- g_set_error(&gerr, BT_IO_ERROR,
- BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
- strerror(err), err);
- } else if (cond & (G_IO_HUP | G_IO_ERR))
- g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
- "HUP or ERR on socket");
-
- conn->connect(io, gerr, conn->user_data);
-
- if (gerr)
- g_error_free(gerr);
-
- return FALSE;
-}
-
-static gboolean server_cb(GIOChannel *io, GIOCondition cond,
- void *user_data)
-{
- struct server *server = user_data;
- int srv_sock, cli_sock;
- GIOChannel *cli_io;
-
- /* If the user closed the server */
- if ((cond & G_IO_NVAL) || check_nval(io))
- return FALSE;
-
- srv_sock = g_io_channel_unix_get_fd(io);
-
- cli_sock = accept(srv_sock, NULL, NULL);
- if (cli_sock < 0)
- return TRUE;
-
- cli_io = g_io_channel_unix_new(cli_sock);
-
- g_io_channel_set_close_on_unref(cli_io, TRUE);
- g_io_channel_set_flags(cli_io, G_IO_FLAG_NONBLOCK, NULL);
-
- if (server->confirm)
- server->confirm(cli_io, server->user_data);
- else
- server->connect(cli_io, NULL, server->user_data);
-
- g_io_channel_unref(cli_io);
-
- return TRUE;
-}
-
-static void server_add(GIOChannel *io, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
- GDestroyNotify destroy)
-{
- struct server *server;
- GIOCondition cond;
-
- server = g_new0(struct server, 1);
- server->connect = connect;
- server->confirm = confirm;
- server->user_data = user_data;
- server->destroy = destroy;
-
- cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, server_cb, server,
- (GDestroyNotify) server_remove);
-}
-
-static void connect_add(GIOChannel *io, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy)
-{
- struct connect *conn;
- GIOCondition cond;
-
- conn = g_new0(struct connect, 1);
- conn->connect = connect;
- conn->user_data = user_data;
- conn->destroy = destroy;
-
- cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, connect_cb, conn,
- (GDestroyNotify) connect_remove);
-}
-
-static void accept_add(GIOChannel *io, BtIOConnect connect, void *user_data,
- GDestroyNotify destroy)
-{
- struct accept *accept;
- GIOCondition cond;
-
- accept = g_new0(struct accept, 1);
- accept->connect = connect;
- accept->user_data = user_data;
- accept->destroy = destroy;
-
- cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, accept_cb, accept,
- (GDestroyNotify) accept_remove);
-}
-
-static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm, GError **err)
-{
- struct sockaddr_l2 addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, src);
- addr.l2_psm = htobs(psm);
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- ERROR_FAILED(err, "l2cap_bind", errno);
- return -1;
- }
-
- return 0;
-}
-
-static int l2cap_connect(int sock, const bdaddr_t *dst, uint16_t psm)
-{
- int err;
- struct sockaddr_l2 addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, dst);
- addr.l2_psm = htobs(psm);
-
- err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
- return err;
-
- return 0;
-}
-
-static int l2cap_set_master(int sock, int master)
-{
- int flags;
- socklen_t len;
-
- len = sizeof(flags);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len) < 0)
- return -errno;
-
- if (master) {
- if (flags & L2CAP_LM_MASTER)
- return 0;
- flags |= L2CAP_LM_MASTER;
- } else {
- if (!(flags & L2CAP_LM_MASTER))
- return 0;
- flags &= ~L2CAP_LM_MASTER;
- }
-
- if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, sizeof(flags)) < 0)
- return -errno;
-
- return 0;
-}
-
-static int rfcomm_set_master(int sock, int master)
-{
- int flags;
- socklen_t len;
-
- len = sizeof(flags);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, &len) < 0)
- return -errno;
-
- if (master) {
- if (flags & RFCOMM_LM_MASTER)
- return 0;
- flags |= RFCOMM_LM_MASTER;
- } else {
- if (!(flags & RFCOMM_LM_MASTER))
- return 0;
- flags &= ~RFCOMM_LM_MASTER;
- }
-
- if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, sizeof(flags)) < 0)
- return -errno;
-
- return 0;
-}
-
-static int l2cap_set_lm(int sock, int level)
-{
- int lm_map[] = {
- 0,
- L2CAP_LM_AUTH,
- L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT,
- L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE,
- }, opt = lm_map[level];
-
- if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0)
- return -errno;
-
- return 0;
-}
-
-static int rfcomm_set_lm(int sock, int level)
-{
- int lm_map[] = {
- 0,
- RFCOMM_LM_AUTH,
- RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT,
- RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE,
- }, opt = lm_map[level];
-
- if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0)
- return -errno;
-
- return 0;
-}
-
-static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
-{
- struct bt_security sec;
- int ret;
-
- if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Valid security level range is %d-%d",
- BT_SECURITY_LOW, BT_SECURITY_HIGH);
- return FALSE;
- }
-
- memset(&sec, 0, sizeof(sec));
- sec.level = level;
-
- if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec,
- sizeof(sec)) == 0)
- return TRUE;
-
- if (errno != ENOPROTOOPT) {
- ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno);
- return FALSE;
- }
-
- if (type == BT_IO_L2CAP)
- ret = l2cap_set_lm(sock, level);
- else
- ret = rfcomm_set_lm(sock, level);
-
- if (ret < 0) {
- ERROR_FAILED(err, "setsockopt(LM)", -ret);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int l2cap_get_lm(int sock, int *sec_level)
-{
- int opt;
- socklen_t len;
-
- len = sizeof(opt);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, &len) < 0)
- return -errno;
-
- *sec_level = 0;
-
- if (opt & L2CAP_LM_AUTH)
- *sec_level = BT_SECURITY_LOW;
- if (opt & L2CAP_LM_ENCRYPT)
- *sec_level = BT_SECURITY_MEDIUM;
- if (opt & L2CAP_LM_SECURE)
- *sec_level = BT_SECURITY_HIGH;
-
- return 0;
-}
-
-static int rfcomm_get_lm(int sock, int *sec_level)
-{
- int opt;
- socklen_t len;
-
- len = sizeof(opt);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, &len) < 0)
- return -errno;
-
- *sec_level = 0;
-
- if (opt & RFCOMM_LM_AUTH)
- *sec_level = BT_SECURITY_LOW;
- if (opt & RFCOMM_LM_ENCRYPT)
- *sec_level = BT_SECURITY_MEDIUM;
- if (opt & RFCOMM_LM_SECURE)
- *sec_level = BT_SECURITY_HIGH;
-
- return 0;
-}
-
-static gboolean get_sec_level(int sock, BtIOType type, int *level,
- GError **err)
-{
- struct bt_security sec;
- socklen_t len;
- int ret;
-
- memset(&sec, 0, sizeof(sec));
- len = sizeof(sec);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) {
- *level = sec.level;
- return TRUE;
- }
-
- if (errno != ENOPROTOOPT) {
- ERROR_FAILED(err, "getsockopt(BT_SECURITY)", errno);
- return FALSE;
- }
-
- if (type == BT_IO_L2CAP)
- ret = l2cap_get_lm(sock, level);
- else
- ret = rfcomm_get_lm(sock, level);
-
- if (ret < 0) {
- ERROR_FAILED(err, "getsockopt(LM)", -ret);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu,
- uint8_t mode, int master, GError **err)
-{
- if (imtu || omtu || mode) {
- struct l2cap_options l2o;
- socklen_t len;
-
- memset(&l2o, 0, sizeof(l2o));
- len = sizeof(l2o);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
- &len) < 0) {
- ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
- return FALSE;
- }
-
- if (imtu)
- l2o.imtu = imtu;
- if (omtu)
- l2o.omtu = omtu;
- if (mode)
- l2o.mode = mode;
-
- if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
- sizeof(l2o)) < 0) {
- ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno);
- return FALSE;
- }
- }
-
- if (master >= 0 && l2cap_set_master(sock, master) < 0) {
- ERROR_FAILED(err, "l2cap_set_master", errno);
- return FALSE;
- }
-
- if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err))
- return FALSE;
-
- return TRUE;
-}
-
-static int rfcomm_bind(int sock,
- const bdaddr_t *src, uint8_t channel, GError **err)
-{
- struct sockaddr_rc addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, src);
- addr.rc_channel = channel;
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- ERROR_FAILED(err, "rfcomm_bind", errno);
- return -1;
- }
-
- return 0;
-}
-
-static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel)
-{
- int err;
- struct sockaddr_rc addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, dst);
- addr.rc_channel = channel;
-
- err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
- return err;
-
- return 0;
-}
-
-static gboolean rfcomm_set(int sock, int sec_level, int master, GError **err)
-{
- if (sec_level && !set_sec_level(sock, BT_IO_RFCOMM, sec_level, err))
- return FALSE;
-
- if (master >= 0 && rfcomm_set_master(sock, master) < 0) {
- ERROR_FAILED(err, "rfcomm_set_master", errno);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int sco_bind(int sock, const bdaddr_t *src, GError **err)
-{
- struct sockaddr_sco addr;
-
- memset(&addr, 0, sizeof(addr));
- addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, src);
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- ERROR_FAILED(err, "sco_bind", errno);
- return -1;
- }
-
- return 0;
-}
-
-static int sco_connect(int sock, const bdaddr_t *dst)
-{
- struct sockaddr_sco addr;
- int err;
-
- memset(&addr, 0, sizeof(addr));
- addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, dst);
-
- err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
- return err;
-
- return 0;
-}
-
-static gboolean sco_set(int sock, uint16_t mtu, GError **err)
-{
- struct sco_options sco_opt;
- socklen_t len;
-
- if (!mtu)
- return TRUE;
-
- len = sizeof(sco_opt);
- memset(&sco_opt, 0, len);
- if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
- ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
- return FALSE;
- }
-
- sco_opt.mtu = mtu;
- if (setsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt,
- sizeof(sco_opt)) < 0) {
- ERROR_FAILED(err, "setsockopt(SCO_OPTIONS)", errno);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean parse_set_opts(struct set_opts *opts, GError **err,
- BtIOOption opt1, va_list args)
-{
- BtIOOption opt = opt1;
- const char *str;
-
- memset(opts, 0, sizeof(*opts));
-
- /* Set defaults */
- opts->defer = DEFAULT_DEFER_TIMEOUT;
- opts->master = -1;
- opts->sec_level = BT_IO_SEC_MEDIUM;
- opts->mode = L2CAP_MODE_BASIC;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- str = va_arg(args, const char *);
- if (strncasecmp(str, "hci", 3) == 0)
- hci_devba(atoi(str + 3), &opts->src);
- else
- str2ba(str, &opts->src);
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(&opts->src, va_arg(args, const bdaddr_t *));
- break;
- case BT_IO_OPT_DEST:
- str2ba(va_arg(args, const char *), &opts->dst);
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(&opts->dst, va_arg(args, const bdaddr_t *));
- break;
- case BT_IO_OPT_DEFER_TIMEOUT:
- opts->defer = va_arg(args, int);
- break;
- case BT_IO_OPT_SEC_LEVEL:
- opts->sec_level = va_arg(args, int);
- break;
- case BT_IO_OPT_CHANNEL:
- opts->channel = va_arg(args, int);
- break;
- case BT_IO_OPT_PSM:
- opts->psm = va_arg(args, int);
- break;
- case BT_IO_OPT_MTU:
- opts->mtu = va_arg(args, int);
- opts->imtu = opts->mtu;
- opts->omtu = opts->mtu;
- break;
- case BT_IO_OPT_OMTU:
- opts->omtu = va_arg(args, int);
- if (!opts->mtu)
- opts->mtu = opts->omtu;
- break;
- case BT_IO_OPT_IMTU:
- opts->imtu = va_arg(args, int);
- if (!opts->mtu)
- opts->mtu = opts->imtu;
- break;
- case BT_IO_OPT_MASTER:
- opts->master = va_arg(args, gboolean);
- break;
- case BT_IO_OPT_MODE:
- opts->mode = va_arg(args, int);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst,
- socklen_t len, GError **err)
-{
- socklen_t olen;
-
- memset(src, 0, len);
- olen = len;
- if (getsockname(sock, src, &olen) < 0) {
- ERROR_FAILED(err, "getsockname", errno);
- return FALSE;
- }
-
- memset(dst, 0, len);
- olen = len;
- if (getpeername(sock, dst, &olen) < 0) {
- ERROR_FAILED(err, "getpeername", errno);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int l2cap_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
-{
- struct l2cap_conninfo info;
- socklen_t len;
-
- len = sizeof(info);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_CONNINFO, &info, &len) < 0)
- return -errno;
-
- if (handle)
- *handle = info.hci_handle;
-
- if (dev_class)
- memcpy(dev_class, info.dev_class, 3);
-
- return 0;
-}
-
-static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
- va_list args)
-{
- BtIOOption opt = opt1;
- struct sockaddr_l2 src, dst;
- struct l2cap_options l2o;
- int flags;
- uint8_t dev_class[3];
- uint16_t handle;
- socklen_t len;
-
- len = sizeof(l2o);
- memset(&l2o, 0, len);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
- ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);
- return FALSE;
- }
-
- if (!get_peers(sock, (struct sockaddr *) &src,
- (struct sockaddr *) &dst, sizeof(src), err))
- return FALSE;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- ba2str(&src.l2_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &src.l2_bdaddr);
- break;
- case BT_IO_OPT_DEST:
- ba2str(&dst.l2_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
- break;
- case BT_IO_OPT_DEFER_TIMEOUT:
- len = sizeof(int);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
- va_arg(args, int *), &len) < 0) {
- ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
- errno);
- return FALSE;
- }
- break;
- case BT_IO_OPT_SEC_LEVEL:
- if (!get_sec_level(sock, BT_IO_L2CAP,
- va_arg(args, int *), err))
- return FALSE;
- break;
- case BT_IO_OPT_PSM:
- *(va_arg(args, uint16_t *)) = src.l2_psm ?
- src.l2_psm : dst.l2_psm;
- break;
- case BT_IO_OPT_OMTU:
- *(va_arg(args, uint16_t *)) = l2o.omtu;
- break;
- case BT_IO_OPT_IMTU:
- *(va_arg(args, uint16_t *)) = l2o.imtu;
- break;
- case BT_IO_OPT_MASTER:
- len = sizeof(flags);
- if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags,
- &len) < 0) {
- ERROR_FAILED(err, "getsockopt(L2CAP_LM)",
- errno);
- return FALSE;
- }
- *(va_arg(args, gboolean *)) =
- (flags & L2CAP_LM_MASTER) ? TRUE : FALSE;
- break;
- case BT_IO_OPT_HANDLE:
- if (l2cap_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
- return FALSE;
- }
- *(va_arg(args, uint16_t *)) = handle;
- break;
- case BT_IO_OPT_CLASS:
- if (l2cap_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "L2CAP_CONNINFO", errno);
- return FALSE;
- }
- memcpy(va_arg(args, uint8_t *), dev_class, 3);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static int rfcomm_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
-{
- struct rfcomm_conninfo info;
- socklen_t len;
-
- len = sizeof(info);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_CONNINFO, &info, &len) < 0)
- return -errno;
-
- if (handle)
- *handle = info.hci_handle;
-
- if (dev_class)
- memcpy(dev_class, info.dev_class, 3);
-
- return 0;
-}
-
-static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
- va_list args)
-{
- BtIOOption opt = opt1;
- struct sockaddr_rc src, dst;
- int flags;
- socklen_t len;
- uint8_t dev_class[3];
- uint16_t handle;
-
- if (!get_peers(sock, (struct sockaddr *) &src,
- (struct sockaddr *) &dst, sizeof(src), err))
- return FALSE;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- ba2str(&src.rc_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &src.rc_bdaddr);
- break;
- case BT_IO_OPT_DEST:
- ba2str(&dst.rc_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &dst.rc_bdaddr);
- break;
- case BT_IO_OPT_DEFER_TIMEOUT:
- len = sizeof(int);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
- va_arg(args, int *), &len) < 0) {
- ERROR_FAILED(err, "getsockopt(DEFER_SETUP)",
- errno);
- return FALSE;
- }
- break;
- case BT_IO_OPT_SEC_LEVEL:
- if (!get_sec_level(sock, BT_IO_RFCOMM,
- va_arg(args, int *), err))
- return FALSE;
- break;
- case BT_IO_OPT_CHANNEL:
- *(va_arg(args, uint8_t *)) = src.rc_channel ?
- src.rc_channel : dst.rc_channel;
- break;
- case BT_IO_OPT_SOURCE_CHANNEL:
- *(va_arg(args, uint8_t *)) = src.rc_channel;
- break;
- case BT_IO_OPT_DEST_CHANNEL:
- *(va_arg(args, uint8_t *)) = dst.rc_channel;
- break;
- case BT_IO_OPT_MASTER:
- len = sizeof(flags);
- if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags,
- &len) < 0) {
- ERROR_FAILED(err, "getsockopt(RFCOMM_LM)",
- errno);
- return FALSE;
- }
- *(va_arg(args, gboolean *)) =
- (flags & RFCOMM_LM_MASTER) ? TRUE : FALSE;
- break;
- case BT_IO_OPT_HANDLE:
- if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- *(va_arg(args, uint16_t *)) = handle;
- break;
- case BT_IO_OPT_CLASS:
- if (rfcomm_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- memcpy(va_arg(args, uint8_t *), dev_class, 3);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static int sco_get_info(int sock, uint16_t *handle, uint8_t *dev_class)
-{
- struct sco_conninfo info;
- socklen_t len;
-
- len = sizeof(info);
- if (getsockopt(sock, SOL_SCO, SCO_CONNINFO, &info, &len) < 0)
- return -errno;
-
- if (handle)
- *handle = info.hci_handle;
-
- if (dev_class)
- memcpy(dev_class, info.dev_class, 3);
-
- return 0;
-}
-
-static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)
-{
- BtIOOption opt = opt1;
- struct sockaddr_sco src, dst;
- struct sco_options sco_opt;
- socklen_t len;
- uint8_t dev_class[3];
- uint16_t handle;
-
- len = sizeof(sco_opt);
- memset(&sco_opt, 0, len);
- if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) {
- ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);
- return FALSE;
- }
-
- if (!get_peers(sock, (struct sockaddr *) &src,
- (struct sockaddr *) &dst, sizeof(src), err))
- return FALSE;
-
- while (opt != BT_IO_OPT_INVALID) {
- switch (opt) {
- case BT_IO_OPT_SOURCE:
- ba2str(&src.sco_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_SOURCE_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &src.sco_bdaddr);
- break;
- case BT_IO_OPT_DEST:
- ba2str(&dst.sco_bdaddr, va_arg(args, char *));
- break;
- case BT_IO_OPT_DEST_BDADDR:
- bacpy(va_arg(args, bdaddr_t *), &dst.sco_bdaddr);
- break;
- case BT_IO_OPT_MTU:
- case BT_IO_OPT_IMTU:
- case BT_IO_OPT_OMTU:
- *(va_arg(args, uint16_t *)) = sco_opt.mtu;
- break;
- case BT_IO_OPT_HANDLE:
- if (sco_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- *(va_arg(args, uint16_t *)) = handle;
- break;
- case BT_IO_OPT_CLASS:
- if (sco_get_info(sock, &handle, dev_class) < 0) {
- ERROR_FAILED(err, "RFCOMM_CONNINFO", errno);
- return FALSE;
- }
- memcpy(va_arg(args, uint8_t *), dev_class, 3);
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown option %d", opt);
- return FALSE;
- }
-
- opt = va_arg(args, int);
- }
-
- return TRUE;
-}
-
-static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, va_list args)
-{
- int sock;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- case BT_IO_L2CAP:
- return l2cap_get(sock, err, opt1, args);
- case BT_IO_RFCOMM:
- return rfcomm_get(sock, err, opt1, args);
- case BT_IO_SCO:
- return sco_get(sock, err, opt1, args);
- }
-
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return FALSE;
-}
-
-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
- GDestroyNotify destroy, GError **err)
-{
- int sock;
- char c;
- struct pollfd pfd;
-
- sock = g_io_channel_unix_get_fd(io);
-
- memset(&pfd, 0, sizeof(pfd));
- pfd.fd = sock;
- pfd.events = POLLOUT;
-
- if (poll(&pfd, 1, 0) < 0) {
- ERROR_FAILED(err, "poll", errno);
- return FALSE;
- }
-
- if (!(pfd.revents & POLLOUT)) {
- int ret;
- ret = read(sock, &c, 1);
- }
-
- accept_add(io, connect, user_data, destroy);
-
- return TRUE;
-}
-
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...)
-{
- va_list args;
- gboolean ret;
- struct set_opts opts;
- int sock;
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, err, opt1, args);
- va_end(args);
-
- if (!ret)
- return ret;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- case BT_IO_L2CAP:
- return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
- opts.mode, opts.master, err);
- case BT_IO_RFCOMM:
- return rfcomm_set(sock, opts.sec_level, opts.master, err);
- case BT_IO_SCO:
- return sco_set(sock, opts.mtu, err);
- }
-
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return FALSE;
-}
-
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...)
-{
- va_list args;
- gboolean ret;
-
- va_start(args, opt1);
- ret = get_valist(io, type, err, opt1, args);
- va_end(args);
-
- return ret;
-}
-
-static GIOChannel *create_io(BtIOType type, gboolean server,
- struct set_opts *opts, GError **err)
-{
- int sock;
- GIOChannel *io;
-
- switch (type) {
- case BT_IO_L2RAW:
- sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
- return NULL;
- }
- if (l2cap_bind(sock, &opts->src,
- server ? opts->psm : 0, err) < 0)
- goto failed;
- if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, err))
- goto failed;
- break;
- case BT_IO_L2CAP:
- sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);
- return NULL;
- }
- if (l2cap_bind(sock, &opts->src,
- server ? opts->psm : 0, err) < 0)
- goto failed;
- if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
- opts->mode, opts->master, err))
- goto failed;
- break;
- case BT_IO_RFCOMM:
- sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno);
- return NULL;
- }
- if (rfcomm_bind(sock, &opts->src,
- server ? opts->channel : 0, err) < 0)
- goto failed;
- if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
- goto failed;
- break;
- case BT_IO_SCO:
- sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
- if (sock < 0) {
- ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno);
- return NULL;
- }
- if (sco_bind(sock, &opts->src, err) < 0)
- goto failed;
- if (!sco_set(sock, opts->mtu, err))
- goto failed;
- break;
- default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return NULL;
- }
-
- io = g_io_channel_unix_new(sock);
-
- g_io_channel_set_close_on_unref(io, TRUE);
- g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
-
- return io;
-
-failed:
- close(sock);
-
- return NULL;
-}
-
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
- GError **gerr, BtIOOption opt1, ...)
-{
- GIOChannel *io;
- va_list args;
- struct set_opts opts;
- int err, sock;
- gboolean ret;
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, gerr, opt1, args);
- va_end(args);
-
- if (ret == FALSE)
- return NULL;
-
- io = create_io(type, FALSE, &opts, gerr);
- if (io == NULL)
- return NULL;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- err = l2cap_connect(sock, &opts.dst, 0);
- break;
- case BT_IO_L2CAP:
- err = l2cap_connect(sock, &opts.dst, opts.psm);
- break;
- case BT_IO_RFCOMM:
- err = rfcomm_connect(sock, &opts.dst, opts.channel);
- break;
- case BT_IO_SCO:
- err = sco_connect(sock, &opts.dst);
- break;
- default:
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return NULL;
- }
-
- if (err < 0) {
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
- "connect: %s (%d)", strerror(-err), -err);
- g_io_channel_unref(io);
- return NULL;
- }
-
- connect_add(io, connect, user_data, destroy);
-
- return io;
-}
-
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
- GDestroyNotify destroy, GError **err,
- BtIOOption opt1, ...)
-{
- GIOChannel *io;
- va_list args;
- struct set_opts opts;
- int sock;
- gboolean ret;
-
- if (type == BT_IO_L2RAW) {
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Server L2CAP RAW sockets not supported");
- return NULL;
- }
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, err, opt1, args);
- va_end(args);
-
- if (ret == FALSE)
- return NULL;
-
- io = create_io(type, TRUE, &opts, err);
- if (io == NULL)
- return NULL;
-
- sock = g_io_channel_unix_get_fd(io);
-
- if (confirm)
- setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer,
- sizeof(opts.defer));
-
- if (listen(sock, 5) < 0) {
- ERROR_FAILED(err, "listen", errno);
- g_io_channel_unref(io);
- return NULL;
- }
-
- server_add(io, connect, confirm, user_data, destroy);
-
- return io;
-}
-
-GQuark bt_io_error_quark(void)
-{
- return g_quark_from_static_string("bt-io-error-quark");
-}
diff --git a/src/btio.h b/src/btio.h
deleted file mode 100644
index e9dcc9f..0000000
--- a/src/btio.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2009-2010 Marcel Holtmann <[email protected]>
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-#ifndef BT_IO_H
-#define BT_IO_H
-
-#include <glib.h>
-
-typedef enum {
- BT_IO_ERROR_DISCONNECTED,
- BT_IO_ERROR_CONNECT_FAILED,
- BT_IO_ERROR_FAILED,
- BT_IO_ERROR_INVALID_ARGS,
-} BtIOError;
-
-#define BT_IO_ERROR bt_io_error_quark()
-
-GQuark bt_io_error_quark(void);
-
-typedef enum {
- BT_IO_L2RAW,
- BT_IO_L2CAP,
- BT_IO_RFCOMM,
- BT_IO_SCO,
-} BtIOType;
-
-typedef enum {
- BT_IO_OPT_INVALID = 0,
- BT_IO_OPT_SOURCE,
- BT_IO_OPT_SOURCE_BDADDR,
- BT_IO_OPT_DEST,
- BT_IO_OPT_DEST_BDADDR,
- BT_IO_OPT_DEFER_TIMEOUT,
- BT_IO_OPT_SEC_LEVEL,
- BT_IO_OPT_CHANNEL,
- BT_IO_OPT_SOURCE_CHANNEL,
- BT_IO_OPT_DEST_CHANNEL,
- BT_IO_OPT_PSM,
- BT_IO_OPT_MTU,
- BT_IO_OPT_OMTU,
- BT_IO_OPT_IMTU,
- BT_IO_OPT_MASTER,
- BT_IO_OPT_HANDLE,
- BT_IO_OPT_CLASS,
- BT_IO_OPT_MODE,
-} BtIOOption;
-
-typedef enum {
- BT_IO_SEC_SDP = 0,
- BT_IO_SEC_LOW,
- BT_IO_SEC_MEDIUM,
- BT_IO_SEC_HIGH,
-} BtIOSecLevel;
-
-typedef void (*BtIOConfirm)(GIOChannel *io, void *user_data);
-
-typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
-
-gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
- GDestroyNotify destroy, GError **err);
-
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...);
-
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...);
-
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
- void *user_data, GDestroyNotify destroy,
- GError **err, BtIOOption opt1, ...);
-
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
- BtIOConfirm confirm, void *user_data,
- GDestroyNotify destroy, GError **err,
- BtIOOption opt1, ...);
-
-#endif
--
1.7.0.4


2010-09-09 09:41:22

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 3/4] btio: Remove unused bt_io_set function

It is not used by either obex or bluez.
---
btio/btio.c | 33 ---------------------------------
btio/btio.h | 3 ---
2 files changed, 0 insertions(+), 36 deletions(-)

diff --git a/btio/btio.c b/btio/btio.c
index 42a3bcd..d4969e5 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -1074,39 +1074,6 @@ gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
return TRUE;
}

-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...)
-{
- va_list args;
- gboolean ret;
- struct set_opts opts;
- int sock;
-
- va_start(args, opt1);
- ret = parse_set_opts(&opts, err, opt1, args);
- va_end(args);
-
- if (!ret)
- return ret;
-
- sock = g_io_channel_unix_get_fd(io);
-
- switch (type) {
- case BT_IO_L2RAW:
- case BT_IO_L2CAP:
- return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
- opts.mode, opts.master, err);
- case BT_IO_RFCOMM:
- return rfcomm_set(sock, opts.sec_level, opts.master, err);
- case BT_IO_SCO:
- return sco_set(sock, opts.mtu, err);
- }
-
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
- "Unknown BtIO type %d", type);
- return FALSE;
-}
-
gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
BtIOOption opt1, ...)
{
diff --git a/btio/btio.h b/btio/btio.h
index e9dcc9f..3c5db2a 100644
--- a/btio/btio.h
+++ b/btio/btio.h
@@ -79,9 +79,6 @@ typedef void (*BtIOConnect)(GIOChannel *io, GError *err, void *user_data);
gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, void *user_data,
GDestroyNotify destroy, GError **err);

-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
- BtIOOption opt1, ...);
-
gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
BtIOOption opt1, ...);

--
1.7.0.4


2010-09-09 09:41:20

by Zhenhua Zhang

[permalink] [raw]
Subject: [PATCH 1/4] btio: Remove blank line at EOF

---
src/btio.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/src/btio.c b/src/btio.c
index 485eec6..42a3bcd 100644
--- a/src/btio.c
+++ b/src/btio.c
@@ -1297,4 +1297,3 @@ GQuark bt_io_error_quark(void)
{
return g_quark_from_static_string("bt-io-error-quark");
}
-
--
1.7.0.4