Hi Johan and Luiz,
This series of patches are for BT DUN server support in oFono. Could
you please to review them especially the btio.[ch] changes in patch
2/6.
oFono git: git://git.kernel.org/pub/scm/network/ofono/ofono.git
Thanks.
Zhenhua
Hi Zhenhua,
* Zhenhua Zhang <[email protected]> [2010-07-29 15:18:16 +0800]:
> Add bluetooth_ref()/bluetooth_unref() to support reference count in
> bluetooth utils.
> ---
> plugins/bluetooth.c | 62 +++++++++++++++++++++++++++++++++++++--------------
> 1 files changed, 45 insertions(+), 17 deletions(-)
>
> diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
> index 5a85eaa..10cc49d 100644
> --- a/plugins/bluetooth.c
> +++ b/plugins/bluetooth.c
> @@ -39,6 +39,7 @@
> static DBusConnection *connection;
> static GHashTable *uuid_hash = NULL;
> static GHashTable *adapter_address_hash = NULL;
> +static gint ref_count;
>
> void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
> char *buf, int size)
> @@ -503,13 +504,10 @@ static guint adapter_added_watch;
> static guint adapter_removed_watch;
> static guint property_watch;
>
> -int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
> +static int bluetooth_init()
> {
> int err;
>
> - if (uuid_hash)
> - goto done;
> -
> connection = ofono_dbus_get_connection();
>
> bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
> @@ -542,13 +540,6 @@ int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
> adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
> g_free, g_free);
>
> -done:
> - g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
> -
> - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
> - manager_properties_cb, NULL, NULL, -1,
> - DBUS_TYPE_INVALID);
> -
> return 0;
>
> remove:
> @@ -556,14 +547,27 @@ remove:
> g_dbus_remove_watch(connection, adapter_added_watch);
> g_dbus_remove_watch(connection, adapter_removed_watch);
> g_dbus_remove_watch(connection, property_watch);
> +
> return err;
> }
>
> -void bluetooth_unregister_uuid(const char *uuid)
> +static int bluetooth_ref()
> {
> - g_hash_table_remove(uuid_hash, uuid);
> + g_atomic_int_inc(&ref_count);
> +
> + if (ref_count > 1)
> + return 0;
> +
> + return bluetooth_init();
> +}
> +
> +static void bluetooth_unref()
> +{
> + gboolean is_zero;
> +
> + is_zero = g_atomic_int_dec_and_test(&ref_count);
>
> - if (g_hash_table_size(uuid_hash))
> + if (is_zero == FALSE)
> return;
We can remove the is_zero variable, and test g_atomic_int_dec_and_test()
directly. What do you think?
>
> g_dbus_remove_watch(connection, bluetooth_watch);
> @@ -571,9 +575,33 @@ void bluetooth_unregister_uuid(const char *uuid)
> g_dbus_remove_watch(connection, adapter_removed_watch);
> g_dbus_remove_watch(connection, property_watch);
>
> - g_hash_table_destroy(uuid_hash);
> - g_hash_table_destroy(adapter_address_hash);
> - uuid_hash = NULL;
> + if (uuid_hash)
> + g_hash_table_destroy(uuid_hash);
> +
> + if (adapter_address_hash)
> + g_hash_table_destroy(adapter_address_hash);
> +}
> +
> +int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
> +{
> + int err = bluetooth_ref();
> +
> + if (err != 0)
> + return err;
> +
> + g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
> +
> + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
> + manager_properties_cb, NULL, NULL, -1,
> + DBUS_TYPE_INVALID);
> + return 0;
> +}
> +
> +void bluetooth_unregister_uuid(const char *uuid)
> +{
> + g_hash_table_remove(uuid_hash, uuid);
> +
> + bluetooth_unref();
> }
>
> OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Gustavo F. Padovan
http://padovan.org
DUN server plug-in watches ofono modem status. When the modem comes to
ONLINE state, it registers itself on Bluetooth adapter and want for
incoming DUN connection.
---
Makefile.am | 4 ++
plugins/dun_gw.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 147 insertions(+), 0 deletions(-)
create mode 100644 plugins/dun_gw.c
diff --git a/Makefile.am b/Makefile.am
index e256841..2e08ff2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -242,6 +242,10 @@ builtin_sources += plugins/bluetooth.c plugins/bluetooth.h
builtin_modules += hfp
builtin_sources += plugins/hfp.c plugins/bluetooth.h
+builtin_modules += dun_gw
+builtin_sources += plugins/dun_gw.c plugins/bluetooth.h plugins/btio.c \
+ plugins/btio.h
+
builtin_modules += palmpre
builtin_sources += plugins/palmpre.c
diff --git a/plugins/dun_gw.c b/plugins/dun_gw.c
new file mode 100644
index 0000000..56bd03d
--- /dev/null
+++ b/plugins/dun_gw.c
@@ -0,0 +1,143 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <ofono.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+
+#include <ofono/dbus.h>
+
+#include "gdbus.h"
+#include "bluetooth.h"
+
+#ifndef DBUS_TYPE_UNIX_FD
+#define DBUS_TYPE_UNIX_FD -1
+#endif
+
+#define DUN_GW_CHANNEL 1
+
+static struct server *server;
+static int modem_watch;
+
+static void dun_gw_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+ DBG("");
+
+ if (err) {
+ DBG("%s", err->message);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ g_io_channel_shutdown(io, TRUE, NULL);
+ bluetooth_unregister_server(server);
+ server = NULL;
+}
+
+static gboolean property_changed(DBusConnection *connection, DBusMessage *msg,
+ void *user_data)
+{
+ const char *property;
+ DBusMessageIter iter, var;
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&iter, &property);
+
+ if (g_str_equal(property, "Online") == TRUE) {
+ const char *path = dbus_message_get_path(msg);
+ struct ofono_modem *modem;
+ struct ofono_atom *gprs;
+ gboolean online;
+
+ if (!dbus_message_iter_next(&iter))
+ return FALSE;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return FALSE;
+
+ dbus_message_iter_recurse(&iter, &var);
+
+ dbus_message_iter_get_basic(&var, &online);
+
+ if (online == FALSE) {
+ bluetooth_unregister_server(server);
+ server = NULL;
+ goto done;
+ }
+
+ /* Create DUN server */
+ modem = ofono_modem_get_modem_by_path(path);
+ gprs = __ofono_modem_find_atom(modem,
+ OFONO_ATOM_TYPE_GPRS);
+ /* Make sure the modem has GPRS atom */
+ if (!gprs)
+ goto done;
+
+ server = bluetooth_register_server(DUN_GW,
+ "Dial-Up Networking", DUN_GW_CHANNEL,
+ dun_gw_connect_cb, modem);
+ }
+
+done:
+ return TRUE;
+}
+
+static int dun_gw_init()
+{
+ DBusConnection *connection = ofono_dbus_get_connection();
+
+ if (DBUS_TYPE_UNIX_FD < 0)
+ return -EBADF;
+
+ modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_MODEM_INTERFACE,
+ "PropertyChanged",
+ property_changed, NULL, NULL);
+
+ return 0;
+}
+
+static void dun_gw_exit()
+{
+ if (server)
+ bluetooth_unregister_server(server);
+
+ if (modem_watch)
+ g_source_remove(modem_watch);
+}
+
+OFONO_PLUGIN_DEFINE(dun_gw, "Dial-up Networking Profile Plugins", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, dun_gw_init, dun_gw_exit)
--
1.7.0.4
DUN server could create emulator and use GAtServer to talk AT commands
to DUN client side.
---
Makefile.am | 4 +-
include/emulator.h | 41 ++++++++++++++++++
plugins/dun_gw.c | 8 +++
src/emulator.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ofono.h | 3 +
5 files changed, 175 insertions(+), 2 deletions(-)
create mode 100644 include/emulator.h
create mode 100644 src/emulator.c
diff --git a/Makefile.am b/Makefile.am
index 2e08ff2..1ec04f3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@ include_HEADERS = include/log.h include/plugin.h include/history.h \
include/cbs.h include/call-volume.h \
include/gprs.h include/gprs-context.h \
include/radio-settings.h include/stk.h \
- include/nettime.h
+ include/nettime.h include/emulator.h
nodist_include_HEADERS = include/version.h
@@ -274,7 +274,7 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) \
src/storage.c src/cbs.c src/watch.c src/call-volume.c \
src/gprs.c src/idmap.h src/idmap.c \
src/radio-settings.c src/stkutil.h src/stkutil.c \
- src/nettime.c
+ src/nettime.c src/emulator.c
src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl
diff --git a/include/emulator.h b/include/emulator.h
new file mode 100644
index 0000000..1033e59
--- /dev/null
+++ b/include/emulator.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 __OFONO_EMULATOR_H
+#define __OFONO_EMULATOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ofono/types.h>
+
+struct ofono_emulator;
+
+struct ofono_emulator *ofono_emulator_create(struct ofono_modem *modem,
+ enum ofono_atom_type type,
+ GIOChannel *io);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OFONO_EMULATOR_H */
diff --git a/plugins/dun_gw.c b/plugins/dun_gw.c
index 56bd03d..840d22d 100644
--- a/plugins/dun_gw.c
+++ b/plugins/dun_gw.c
@@ -48,6 +48,9 @@ static int modem_watch;
static void dun_gw_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
+ struct ofono_modem *modem = user_data;
+ struct ofono_emulator *emulator;
+
DBG("");
if (err) {
@@ -55,6 +58,11 @@ static void dun_gw_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
goto failed;
}
+ emulator = ofono_emulator_create(modem, OFONO_ATOM_TYPE_EMULATOR_DUN,
+ io);
+ if (!emulator)
+ goto failed;
+
return;
failed:
diff --git a/src/emulator.c b/src/emulator.c
new file mode 100644
index 0000000..6219bb1
--- /dev/null
+++ b/src/emulator.c
@@ -0,0 +1,121 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <gdbus.h>
+
+#include "ofono.h"
+#include "common.h"
+#include "gatserver.h"
+
+struct ofono_emulator {
+ struct ofono_modem *modem;
+ struct ofono_atom *atom;
+ enum ofono_atom_type type;
+ unsigned int id;
+ GAtServer *server;
+};
+
+static unsigned int ofono_emulator_ids;
+
+static void ofono_emulator_debug(const char *str, void *data)
+{
+ g_print("%s: %s\n", (char *)data, str);
+}
+
+static unsigned int ofono_emulator_next_id()
+{
+ unsigned int i;
+
+ for (i = 1; i < sizeof(ofono_emulator_ids) * 8; i++) {
+ if (ofono_emulator_ids & (0x1 << i))
+ continue;
+
+ ofono_emulator_ids |= (0x1 << i);
+
+ return i;
+ }
+
+ return 0;
+}
+
+static void ofono_emulator_release_id(int id)
+{
+ ofono_emulator_ids &= ~(0x1 << id);
+}
+
+static void emulator_remove(struct ofono_atom *atom)
+{
+ struct ofono_emulator *e = __ofono_atom_get_data(atom);
+
+ DBG("");
+
+ g_at_server_shutdown(e->server);
+ g_at_server_unref(e->server);
+ e->server = NULL;
+
+ ofono_emulator_release_id(e->id);
+ g_free(e);
+ e = NULL;
+}
+
+static void emulator_disconnect(gpointer user_data)
+{
+ struct ofono_emulator *e = user_data;
+
+ __ofono_atom_free(e->atom);
+}
+
+struct ofono_emulator *ofono_emulator_create(struct ofono_modem *modem,
+ enum ofono_atom_type type,
+ GIOChannel *channel)
+{
+ struct ofono_emulator *e;
+
+ DBG("");
+
+ e = g_try_new0(struct ofono_emulator, 1);
+ if (!e)
+ return NULL;
+
+ e->server = g_at_server_new(channel);
+ if (!e->server) {
+ g_free(e);
+ return NULL;
+ }
+
+ g_at_server_set_debug(e->server, ofono_emulator_debug, "Server");
+ g_at_server_set_disconnect_function(e->server, emulator_disconnect, e);
+
+ e->modem = modem;
+ e->type = type;
+ e->id = ofono_emulator_next_id();
+ e->atom = __ofono_modem_add_atom(modem, type, emulator_remove, e);
+
+ return e;
+}
diff --git a/src/ofono.h b/src/ofono.h
index aaa01d9..8982a95 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -117,6 +117,7 @@ enum ofono_atom_type {
OFONO_ATOM_TYPE_RADIO_SETTINGS = 18,
OFONO_ATOM_TYPE_STK = 19,
OFONO_ATOM_TYPE_NETTIME = 20,
+ OFONO_ATOM_TYPE_EMULATOR_DUN = 21,
};
enum ofono_atom_watch_condition {
@@ -289,3 +290,5 @@ void __ofono_nettime_probe_drivers(struct ofono_modem *modem);
void __ofono_nettime_info_received(struct ofono_modem *modem,
struct ofono_network_time *info);
+
+#include <ofono/emulator.h>
--
1.7.0.4
Return modem instance by searching modem path.
---
include/modem.h | 1 +
src/modem.c | 15 +++++++++++++++
2 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/include/modem.h b/include/modem.h
index e1cd049..34c3fbf 100644
--- a/include/modem.h
+++ b/include/modem.h
@@ -36,6 +36,7 @@ void ofono_modem_remove_interface(struct ofono_modem *modem,
const char *interface);
const char *ofono_modem_get_path(struct ofono_modem *modem);
+struct ofono_modem *ofono_modem_get_modem_by_path(const char *path);
void ofono_modem_set_data(struct ofono_modem *modem, void *data);
void *ofono_modem_get_data(struct ofono_modem *modem);
diff --git a/src/modem.c b/src/modem.c
index f89d609..6907a5e 100644
--- a/src/modem.c
+++ b/src/modem.c
@@ -157,6 +157,21 @@ const char *ofono_modem_get_path(struct ofono_modem *modem)
return NULL;
}
+struct ofono_modem *ofono_modem_get_modem_by_path(const char *path)
+{
+ GSList *l;
+ struct ofono_modem *modem = NULL;
+
+ for (l = g_modem_list; l; l = l->next) {
+ modem = l->data;
+
+ if (g_str_equal(modem->path, path))
+ break;
+ }
+
+ return modem;
+}
+
struct ofono_atom *__ofono_modem_add_atom(struct ofono_modem *modem,
enum ofono_atom_type type,
void (*destruct)(struct ofono_atom *),
--
1.7.0.4
Btio library is the low level socket API for BT RFCOMM connection.
---
plugins/btio.c | 479 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/btio.h | 118 ++++++++++++++
2 files changed, 597 insertions(+), 0 deletions(-)
create mode 100644 plugins/btio.c
create mode 100644 plugins/btio.h
diff --git a/plugins/btio.c b/plugins/btio.c
new file mode 100644
index 0000000..6156027
--- /dev/null
+++ b/plugins/btio.c
@@ -0,0 +1,479 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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 <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;
+ int defer;
+ int sec_level;
+ uint8_t channel;
+ int master;
+};
+
+struct connect {
+ BtIOConnect connect;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+struct accept {
+ BtIOConnect connect;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+struct server {
+ BtIOConnect connect;
+ BtIOConfirm confirm;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
+{
+ memcpy(dst, src, sizeof(bdaddr_t));
+}
+
+static void baswap(bdaddr_t *dst, const bdaddr_t *src)
+{
+ register unsigned char *d = (unsigned char *) dst;
+ register const unsigned char *s = (const unsigned char *) src;
+ register int i;
+
+ for (i = 0; i < 6; i++)
+ d[i] = s[5-i];
+}
+
+static int ba2str(const bdaddr_t *ba, char *str)
+{
+ uint8_t b[6];
+
+ baswap((bdaddr_t *) b, ba);
+ return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ b[0], b[1], b[2], b[3], b[4], b[5]);
+}
+
+static void server_remove(struct server *server)
+{
+ if (server->destroy)
+ server->destroy(server->user_data);
+ g_free(server);
+}
+
+static void accept_remove(struct accept *accept)
+{
+ if (accept->destroy)
+ accept->destroy(accept->user_data);
+ g_free(accept);
+}
+
+static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct accept *accept = user_data;
+ GError *err = NULL;
+
+ /* If the user aborted this accept attempt */
+ if (cond & G_IO_NVAL)
+ 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 server_cb(GIOChannel *io, GIOCondition cond,
+ gpointer 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)
+ 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, gpointer 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 accept_add(GIOChannel *io, BtIOConnect connect, gpointer 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 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;
+ }
+
+ ret = rfcomm_set_lm(sock, level);
+ if (ret < 0) {
+ ERROR_FAILED(err, "setsockopt(LM)", -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int rfcomm_bind(int sock, const bdaddr_t *src, uint8_t channel)
+{
+ struct sockaddr_rc addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+ addr.rc_channel = channel;
+
+ return bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+}
+
+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;
+
+ return TRUE;
+}
+
+static gboolean parse_set_opts(struct set_opts *opts, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ BtIOOption opt = opt1;
+
+ memset(opts, 0, sizeof(*opts));
+
+ /* Set defaults */
+ opts->defer = DEFAULT_DEFER_TIMEOUT;
+ opts->master = -1;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_CHANNEL:
+ opts->channel = va_arg(args, int);
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ opts->sec_level = 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 gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
+ va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_rc src, dst;
+
+ 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_DEST:
+ ba2str(&dst.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel ?
+ src.rc_channel : dst.rc_channel;
+ 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 = g_io_channel_unix_get_fd(io);
+
+ if (type != BT_IO_RFCOMM) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return FALSE;
+ }
+
+ return rfcomm_get(sock, err, opt1, args);
+}
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer 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_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;
+
+ if (type != BT_IO_RFCOMM)
+ return NULL;
+
+ 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) < 0) {
+ ERROR_FAILED(err, "rfcomm_bind", errno);
+ return NULL;
+ }
+
+ if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
+ 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;
+}
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, gpointer user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...)
+{
+ GIOChannel *io;
+ va_list args;
+ struct set_opts opts;
+ int sock;
+ gboolean ret;
+
+ 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/plugins/btio.h b/plugins/btio.h
new file mode 100644
index 0000000..78d5961
--- /dev/null
+++ b/plugins/btio.h
@@ -0,0 +1,118 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009 Marcel Holtmann <[email protected]>
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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 <glib.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#ifndef AF_BLUETOOTH
+#define AF_BLUETOOTH 31
+#define PF_BLUETOOTH AF_BLUETOOTH
+#endif
+
+#define BTPROTO_RFCOMM 3
+#define SOL_RFCOMM 18
+#define SOL_BLUETOOTH 274
+
+struct bt_security {
+ uint8_t level;
+};
+#define BT_SECURITY_SDP 0
+#define BT_SECURITY_LOW 1
+#define BT_SECURITY_MEDIUM 2
+#define BT_SECURITY_HIGH 3
+#define BT_SECURITY 4
+
+#define BT_DEFER_SETUP 7
+
+/* BD Address */
+typedef struct {
+ uint8_t b[6];
+} __attribute__((packed)) bdaddr_t;
+
+#define RFCOMM_LM 0x03
+#define RFCOMM_LM_AUTH 0x0002
+#define RFCOMM_LM_ENCRYPT 0x0004
+#define RFCOMM_LM_TRUSTED 0x0008
+#define RFCOMM_LM_RELIABLE 0x0010
+#define RFCOMM_LM_SECURE 0x0020
+
+#include <sys/socket.h>
+
+/* RFCOMM socket address */
+struct sockaddr_rc {
+ sa_family_t rc_family;
+ bdaddr_t rc_bdaddr;
+ uint8_t rc_channel;
+};
+
+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_RFCOMM,
+} BtIOType;
+
+typedef enum {
+ BT_IO_OPT_INVALID = 0,
+ BT_IO_OPT_SOURCE,
+ BT_IO_OPT_DEST,
+ BT_IO_OPT_SEC_LEVEL,
+ BT_IO_OPT_CHANNEL,
+} 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, gpointer user_data);
+
+typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer 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_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, gpointer user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...);
--
1.7.0.4
It watches Bluetooth adapter property changes and addes DUN record to
listen DUN client connection request.
---
plugins/bluetooth.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/bluetooth.h | 14 ++
2 files changed, 393 insertions(+), 0 deletions(-)
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index 10cc49d..5890161 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -35,12 +35,71 @@
#include <ofono/dbus.h>
#include "bluetooth.h"
+#include "btio.h"
static DBusConnection *connection;
static GHashTable *uuid_hash = NULL;
static GHashTable *adapter_address_hash = NULL;
+static GSList *server_list = NULL;
static gint ref_count;
+static const gchar *dun_record = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
+<record> \
+ <attribute id=\"0x0001\"> \
+ <sequence> \
+ <uuid value=\"0x1103\"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0004\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x0100\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0003\"/> \
+ <uint8 value=\"%u\" name=\"channel\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0008\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0009\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x1103\"/> \
+ <uint16 value=\"0x0100\" name=\"version\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0100\"> \
+ <text value=\"%s\" name=\"name\"/> \
+ </attribute> \
+</record>";
+
+#define TIMEOUT (60*1000) /* Timeout for user response (miliseconds) */
+
+struct client {
+ GIOChannel *io;
+ guint watch;
+};
+
+struct server {
+ guint16 service;
+ gchar *name;
+ guint8 channel;
+ GIOChannel *io;
+ gchar *adapter;
+ guint handle;
+ ConnectFunc connect_cb;
+ gpointer user_data;
+
+ struct client client;
+};
+
void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size)
{
@@ -370,6 +429,253 @@ static gboolean property_changed(DBusConnection *connection, DBusMessage *msg,
return TRUE;
}
+static void disconnect(struct server *server)
+{
+ struct client *client = &server->client;
+
+ if (!client->io)
+ return;
+
+ g_io_channel_unref(client->io);
+ client->io = NULL;
+
+ if (client->watch > 0) {
+ g_source_remove(client->watch);
+ client->watch = 0;
+ }
+
+ return;
+}
+
+static void server_stop(gpointer data, gpointer user_data)
+{
+ struct server *server = data;
+
+ disconnect(server);
+
+ if (server->handle) {
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call(BLUEZ_SERVICE,
+ server->adapter,
+ BLUEZ_SERVICE_INTERFACE,
+ "RemoveRecord");
+ dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle,
+ DBUS_TYPE_INVALID);
+ g_dbus_send_message(connection, msg);
+
+ server->handle = 0;
+ }
+
+ if (server->io) {
+ g_io_channel_shutdown(server->io, TRUE, NULL);
+ g_io_channel_unref(server->io);
+ server->io = NULL;
+ }
+
+ g_free(server->adapter);
+ server->adapter = NULL;
+}
+
+static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct server *server = data;
+
+ disconnect(server);
+
+ return FALSE;
+}
+
+static void cancel_authorization(struct server *server)
+{
+ DBusMessage *msg;
+
+ if (!server->adapter)
+ return;
+
+ msg = dbus_message_new_method_call(BLUEZ_SERVICE, server->adapter,
+ BLUEZ_SERVICE_INTERFACE,
+ "CancelAuthorization");
+
+ g_dbus_send_message(connection, msg);
+}
+
+static void auth_cb(DBusPendingCall *call, gpointer user_data)
+{
+ struct server *server = user_data;
+ struct client *client = &server->client;
+ GIOChannel *io = client->io;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+ GError *err = NULL;
+
+ dbus_error_init(&derr);
+
+ if (dbus_set_error_from_message(&derr, reply)) {
+ ofono_error("RequestAuthorization error: %s, %s",
+ derr.name, derr.message);
+
+ if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
+ cancel_authorization(server);
+
+ dbus_error_free(&derr);
+ goto failed;
+ }
+
+ ofono_info("RequestAuthorization succeeded");
+
+ if (!bt_io_accept(io, server->connect_cb, server->user_data,
+ NULL, &err)) {
+ ofono_error("%s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ g_source_remove(client->watch);
+
+ client->watch = g_io_add_watch(client->io,
+ G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ client_event, server);
+
+ dbus_message_unref(reply);
+
+ return;
+
+failed:
+ dbus_message_unref(reply);
+ disconnect(server);
+}
+
+static gboolean auth_watch(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct server *server = user_data;
+
+ cancel_authorization(server);
+ disconnect(server);
+
+ return FALSE;
+}
+
+static void confirm_event(GIOChannel *io, gpointer user_data)
+{
+ struct server *server = user_data;
+ struct client *client = &server->client;
+ GError *err = NULL;
+ char address[18];
+ const char *addr;
+ guint8 channel;
+ int ret;
+
+ if (client->io) {
+ ofono_error("Rejecting connection since one client already \
+ connected");
+ return;
+ }
+
+ bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_DEST, address,
+ BT_IO_OPT_CHANNEL, &channel,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ ofono_error("%s", err->message);
+ g_error_free(err);
+ return;
+ }
+
+ ofono_info("New connection from: %s, channel %u", address, channel);
+
+ addr = address;
+ ret = bluetooth_send_with_reply(server->adapter,
+ BLUEZ_SERVICE_INTERFACE,
+ "RequestAuthorization",
+ auth_cb, server, NULL, TIMEOUT,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_UINT32, &server->handle,
+ DBUS_TYPE_INVALID);
+ if (ret < 0) {
+ ofono_error("Request Bluetooth authorization failed");
+ return;
+ }
+
+ ofono_info("RequestAuthorization(%s, 0x%x)", address, server->handle);
+
+ client->io = g_io_channel_ref(io);
+ client->watch = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ auth_watch, server);
+
+ return;
+}
+
+static void add_record_cb(DBusPendingCall *call, gpointer user_data)
+{
+ struct server *server = user_data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+ guint32 handle;
+
+ dbus_error_init(&derr);
+
+ if (dbus_set_error_from_message(&derr, reply)) {
+ ofono_error("Replied with an error: %s, %s",
+ derr.name, derr.message);
+ dbus_error_free(&derr);
+ server_stop(server, NULL);
+ goto done;
+ }
+
+ dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+ server->handle = handle;
+
+ ofono_info("Registered: %s, handle: 0x%x", server->name, handle);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static void server_start(gpointer data, gpointer user_data)
+{
+ struct server *server = data;
+ gchar *path = user_data;
+ GError *err = NULL;
+ gchar *xml;
+
+ if (server->handle != 0)
+ return;
+
+ if (server->service != DUN_GW)
+ goto failed;
+
+ server->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event,
+ server, NULL, &err,
+ BT_IO_OPT_CHANNEL, server->channel,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_INVALID);
+ if (!server->io) {
+ ofono_error("Bluetooth %s register failed: %s",
+ server->name, err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ server->adapter = g_strdup(path);
+
+ xml = g_markup_printf_escaped(dun_record, server->channel,
+ server->name);
+
+ bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE, "AddRecord",
+ add_record_cb, server, NULL, -1,
+ DBUS_TYPE_STRING, &xml,
+ DBUS_TYPE_INVALID);
+
+ g_free(xml);
+
+ return;
+
+failed:
+ server_stop(server, NULL);
+}
+
static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data)
{
const char *path = user_data;
@@ -394,6 +700,9 @@ static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data)
g_hash_table_insert(adapter_address_hash,
g_strdup(path), g_strdup(addr));
+ if (server_list)
+ g_slist_foreach(server_list, server_start, (gpointer)path);
+
for (l = device_list; l; l = l->next) {
const char *device = l->data;
@@ -428,11 +737,26 @@ static gboolean adapter_removed(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
const char *path;
+ GSList *l;
if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID) == TRUE)
g_hash_table_remove(adapter_address_hash, path);
+ for (l = server_list; l; l = l->next) {
+ struct server *server = l->data;
+
+ if (!server->adapter)
+ continue;
+
+ if (!g_str_equal(path, server->adapter))
+ continue;
+
+ /* Don't remove handle if the adapter has been removed */
+ server->handle = 0;
+ server_stop(server, NULL);
+ }
+
return TRUE;
}
@@ -564,6 +888,7 @@ static int bluetooth_ref()
static void bluetooth_unref()
{
gboolean is_zero;
+ GSList *l;
is_zero = g_atomic_int_dec_and_test(&ref_count);
@@ -580,6 +905,20 @@ static void bluetooth_unref()
if (adapter_address_hash)
g_hash_table_destroy(adapter_address_hash);
+
+ if (server_list == NULL)
+ return;
+
+ for (l = server_list; l; l = l->next) {
+ struct server *server = l->data;
+
+ server_stop(server, NULL);
+ g_free(server->name);
+ g_free(server);
+ }
+
+ g_slist_free(server_list);
+ server_list = NULL;
}
int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
@@ -604,5 +943,45 @@ void bluetooth_unregister_uuid(const char *uuid)
bluetooth_unref();
}
+struct server *bluetooth_register_server(guint16 service, char *name,
+ guint8 channel, ConnectFunc cb,
+ gpointer user_data)
+{
+ struct server *server;
+ int err = bluetooth_ref();
+
+ if (err != 0)
+ return NULL;
+
+ server = g_try_new0(struct server, 1);
+ if (!server)
+ return NULL;
+
+ server->service = service;
+ server->name = g_strdup(name);
+ server->channel = channel;
+ server->connect_cb = cb;
+ server->user_data = user_data;
+
+ server_list = g_slist_prepend(server_list, server);
+
+ bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
+ manager_properties_cb, NULL, NULL, -1,
+ DBUS_TYPE_INVALID);
+
+ return server;
+}
+
+void bluetooth_unregister_server(struct server *server)
+{
+ server_list = g_slist_remove(server_list, server);
+
+ server_stop(server, NULL);
+ g_free(server->name);
+ g_free(server);
+
+ bluetooth_unref();
+}
+
OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL)
diff --git a/plugins/bluetooth.h b/plugins/bluetooth.h
index fb0d841..ab42c99 100644
--- a/plugins/bluetooth.h
+++ b/plugins/bluetooth.h
@@ -2,6 +2,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2010 Gustavo F. Padovan <[email protected]>
+ * Copyright (C) 2010 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,12 +23,16 @@
#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
+#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service"
#define HFP_AG_UUID "0000111F-0000-1000-8000-00805F9B34FB"
/* Profiles bitfield */
#define HFP_AG 0x01
+/* Service bitfield */
+#define DUN_GW 0x01
+
struct bluetooth_profile {
const char *name;
int (*create)(const char *device, const char *dev_addr,
@@ -36,10 +41,19 @@ struct bluetooth_profile {
void (*set_alias)(const char *device, const char *);
};
+typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data);
+
+struct server;
+
int bluetooth_register_uuid(const char *uuid,
struct bluetooth_profile *profile);
void bluetooth_unregister_uuid(const char *uuid);
+struct server *bluetooth_register_server(guint16 service, char *name,
+ guint8 channel, ConnectFunc cb,
+ gpointer user_data);
+void bluetooth_unregister_server(struct server *server);
+
void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size);
--
1.7.0.4
Add bluetooth_ref()/bluetooth_unref() to support reference count in
bluetooth utils.
---
plugins/bluetooth.c | 62 +++++++++++++++++++++++++++++++++++++--------------
1 files changed, 45 insertions(+), 17 deletions(-)
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index 5a85eaa..10cc49d 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -39,6 +39,7 @@
static DBusConnection *connection;
static GHashTable *uuid_hash = NULL;
static GHashTable *adapter_address_hash = NULL;
+static gint ref_count;
void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size)
@@ -503,13 +504,10 @@ static guint adapter_added_watch;
static guint adapter_removed_watch;
static guint property_watch;
-int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
+static int bluetooth_init()
{
int err;
- if (uuid_hash)
- goto done;
-
connection = ofono_dbus_get_connection();
bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
@@ -542,13 +540,6 @@ int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
-done:
- g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
-
- bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
- manager_properties_cb, NULL, NULL, -1,
- DBUS_TYPE_INVALID);
-
return 0;
remove:
@@ -556,14 +547,27 @@ remove:
g_dbus_remove_watch(connection, adapter_added_watch);
g_dbus_remove_watch(connection, adapter_removed_watch);
g_dbus_remove_watch(connection, property_watch);
+
return err;
}
-void bluetooth_unregister_uuid(const char *uuid)
+static int bluetooth_ref()
{
- g_hash_table_remove(uuid_hash, uuid);
+ g_atomic_int_inc(&ref_count);
+
+ if (ref_count > 1)
+ return 0;
+
+ return bluetooth_init();
+}
+
+static void bluetooth_unref()
+{
+ gboolean is_zero;
+
+ is_zero = g_atomic_int_dec_and_test(&ref_count);
- if (g_hash_table_size(uuid_hash))
+ if (is_zero == FALSE)
return;
g_dbus_remove_watch(connection, bluetooth_watch);
@@ -571,9 +575,33 @@ void bluetooth_unregister_uuid(const char *uuid)
g_dbus_remove_watch(connection, adapter_removed_watch);
g_dbus_remove_watch(connection, property_watch);
- g_hash_table_destroy(uuid_hash);
- g_hash_table_destroy(adapter_address_hash);
- uuid_hash = NULL;
+ if (uuid_hash)
+ g_hash_table_destroy(uuid_hash);
+
+ if (adapter_address_hash)
+ g_hash_table_destroy(adapter_address_hash);
+}
+
+int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
+{
+ int err = bluetooth_ref();
+
+ if (err != 0)
+ return err;
+
+ g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
+
+ bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
+ manager_properties_cb, NULL, NULL, -1,
+ DBUS_TYPE_INVALID);
+ return 0;
+}
+
+void bluetooth_unregister_uuid(const char *uuid)
+{
+ g_hash_table_remove(uuid_hash, uuid);
+
+ bluetooth_unref();
}
OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
--
1.7.0.4
Hi Padovan,
Gustavo F. Padovan wrote:
> Hi Zhenhua,
>
> * Zhenhua Zhang <[email protected]> [2010-07-29 15:18:16 +0800]:
>
>> Add bluetooth_ref()/bluetooth_unref() to support reference count in
>> bluetooth utils.
>> ---
>> plugins/bluetooth.c | 62
>> +++++++++++++++++++++++++++++++++++++-------------- 1 files
>> changed, 45 insertions(+), 17 deletions(-)
>>
>> diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
>> index 5a85eaa..10cc49d 100644
>> --- a/plugins/bluetooth.c
>> +++ b/plugins/bluetooth.c
>> @@ -39,6 +39,7 @@
>> static DBusConnection *connection;
>> static GHashTable *uuid_hash = NULL;
>> static GHashTable *adapter_address_hash = NULL;
>> +static gint ref_count;
>>
>> void bluetooth_create_path(const char *dev_addr, const char
>> *adapter_addr, char *buf, int size) @@ -503,13 +504,10 @@
>> static guint adapter_added_watch; static guint
>> adapter_removed_watch; static guint property_watch;
>>
>> -int bluetooth_register_uuid(const char *uuid, struct
>> bluetooth_profile *profile) +static int bluetooth_init() {
>> int err;
>>
>> - if (uuid_hash)
>> - goto done;
>> -
>> connection = ofono_dbus_get_connection();
>>
>> bluetooth_watch = g_dbus_add_service_watch(connection,
>> BLUEZ_SERVICE, @@ -542,13 +540,6 @@ int
>> bluetooth_register_uuid(const char *uuid, struct bluetooth_profile
>> *profile) adapter_address_hash = g_hash_table_new_full(g_str_hash,
>> g_str_equal, g_free, g_free);
>>
>> -done:
>> - g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); -
>> - bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE,
>> "GetProperties",
>> - manager_properties_cb, NULL, NULL, -1,
>> - DBUS_TYPE_INVALID);
>> -
>> return 0;
>>
>> remove:
>> @@ -556,14 +547,27 @@ remove:
>> g_dbus_remove_watch(connection, adapter_added_watch);
>> g_dbus_remove_watch(connection, adapter_removed_watch);
>> g_dbus_remove_watch(connection, property_watch);
>> +
>> return err;
>> }
>>
>> -void bluetooth_unregister_uuid(const char *uuid)
>> +static int bluetooth_ref()
>> {
>> - g_hash_table_remove(uuid_hash, uuid);
>> + g_atomic_int_inc(&ref_count);
>> +
>> + if (ref_count > 1)
>> + return 0;
>> +
>> + return bluetooth_init();
>> +}
>> +
>> +static void bluetooth_unref()
>> +{
>> + gboolean is_zero;
>> +
>> + is_zero = g_atomic_int_dec_and_test(&ref_count);
>>
>> - if (g_hash_table_size(uuid_hash))
>> + if (is_zero == FALSE)
>> return;
>
> We can remove the is_zero variable, and test
> g_atomic_int_dec_and_test() directly. What do you think?
Actually I think it's ok to keep this variable. We also have it in gatchat and gatppp.
Thanks,
Zhenhua
>>
>> g_dbus_remove_watch(connection, bluetooth_watch);
>> @@ -571,9 +575,33 @@ void bluetooth_unregister_uuid(const char *uuid)
>> g_dbus_remove_watch(connection, adapter_removed_watch);
>> g_dbus_remove_watch(connection, property_watch);
>>
>> - g_hash_table_destroy(uuid_hash);
>> - g_hash_table_destroy(adapter_address_hash);
>> - uuid_hash = NULL;
>> + if (uuid_hash)
>> + g_hash_table_destroy(uuid_hash);
>> +
>> + if (adapter_address_hash)
>> + g_hash_table_destroy(adapter_address_hash);
>> +}
>> +
>> +int bluetooth_register_uuid(const char *uuid, struct
>> bluetooth_profile *profile) +{ + int err = bluetooth_ref();
>> +
>> + if (err != 0)
>> + return err;
>> +
>> + g_hash_table_insert(uuid_hash, g_strdup(uuid), profile); +
>> + bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE,
>> "GetProperties", + manager_properties_cb, NULL, NULL, -1,
>> + DBUS_TYPE_INVALID);
>> + return 0;
>> +}
>> +
>> +void bluetooth_unregister_uuid(const char *uuid)
>> +{
>> + g_hash_table_remove(uuid_hash, uuid);
>> +
>> + bluetooth_unref();
>> }
>>
>> OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
>> --
>> 1.7.0.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe
>> linux-bluetooth" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
Regards,
Zhenhua