[RFC v0] elect: Add DUN support
by Daniel Wagner
From: Daniel Wagner <daniel.wagner(a)bmw-carit.de>
---
Hi,
so this is the first very rough version of the new DUN daemon.
There are several things I am sure need to be fixed such as the
names (dun.c used to be gsmdial.c. Though both names do not reall
match IMO).
I will split up this huge patch in smaller ones after the general
approach is accepted.
cheers,
daniel
/me hopes his fire proof underpents will be worth its money...
Makefile.am | 24 ++
bootstrap-configure | 1 +
configure.ac | 4 +
doc/elect-api.txt | 92 +++++++
elect/device.c | 685 +++++++++++++++++++++++++++++++++++++++++++++++++
elect/dun.c | 270 +++++++++++++++++++
elect/elect.conf | 23 ++
elect/elect.h | 102 ++++++++
elect/elect.service | 11 +
elect/main.c | 253 ++++++++++++++++++
elect/manager.c | 115 +++++++++
plugins/bluetooth.h | 1 +
test/elect-connect | 20 ++
test/elect-disconnect | 20 ++
14 files changed, 1621 insertions(+), 0 deletions(-)
create mode 100644 doc/elect-api.txt
create mode 100644 elect/device.c
create mode 100644 elect/dun.c
create mode 100644 elect/elect.conf
create mode 100644 elect/elect.h
create mode 100644 elect/elect.service
create mode 100644 elect/main.c
create mode 100644 elect/manager.c
create mode 100755 test/elect-connect
create mode 100755 test/elect-disconnect
diff --git a/Makefile.am b/Makefile.am
index 337aeb7..657203e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -647,6 +647,30 @@ tools_lookup_provider_name_SOURCES = plugins/mbpi.c plugins/mbpi.h \
tools_lookup_provider_name_LDADD = @GLIB_LIBS@
endif
+if ELECT
+
+sbin_PROGRAMS += elect/electd
+
+elect_electd_SOURCES = $(gdbus_sources) $(gatchat_sources) $(btio_sources) \
+ elect/main.c elect/manager.c elect/device.c elect/dun.c \
+ src/log.c src/dbus.c plugins/bluetooth.c
+
+elect_electd_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl
+
+if DATAFILES
+
+dist_dbusconf_DATA += elect/elect.conf
+
+if SYSTEMD
+systemdunitdir += @SYSTEMD_UNITDIR@
+
+systemdunit_DATA += elect/elect.service
+endif
+
+endif
+
+endif
+
noinst_PROGRAMS += gatchat/gsmdial gatchat/test-server gatchat/test-qcdm
gatchat_gsmdial_SOURCES = gatchat/gsmdial.c $(gatchat_sources)
diff --git a/bootstrap-configure b/bootstrap-configure
index db70c66..d80ed8b 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -14,4 +14,5 @@ fi
--localstatedir=/var \
--enable-capng \
--enable-tools \
+ --enable-elect \
--disable-datafiles $*
diff --git a/configure.ac b/configure.ac
index 5e4d34f..f8f3387 100644
--- a/configure.ac
+++ b/configure.ac
@@ -165,6 +165,10 @@ if (test "${enable_tools}" = "yes"); then
fi
AM_CONDITIONAL(TOOLS, test "${enable_tools}" = "yes")
+AC_ARG_ENABLE(elect, AC_HELP_STRING([--enable-elect],
+ [enable DUN deamon support]), [enable_elect=${enableval}])
+AM_CONDITIONAL(ELECT, test "${enable_elect}" = "yes")
+
AC_ARG_ENABLE(atmodem, AC_HELP_STRING([--disable-atmodem],
[disable ETSI AT modem support]),
[enable_atmodem=${enableval}])
diff --git a/doc/elect-api.txt b/doc/elect-api.txt
new file mode 100644
index 0000000..49a4e25
--- /dev/null
+++ b/doc/elect-api.txt
@@ -0,0 +1,92 @@
+
+Manager hierarchy
+=================
+
+Service org.ofono.elect
+Interface org.ofono.elect.Manager
+Object path /
+
+Methods array{object,dict} GetDevices()
+
+ Get an array of device objects and properties
+ that represent the currently attached devices.
+
+ This method call should only be used once when an
+ application starts up. Further device additions
+ and removal shall be monitored via DeviceAdded and
+ DeviceRemoved signals.
+
+Signals DeviceAdded(object path, dict properties)
+
+ Signal that is sent when a new device is added. It
+ contains the object path of new device and its
+ properties.
+
+ DeviceRemoved(object path)
+
+ Signal that is sent when a device has been removed.
+ The object path is no longer accessible after this
+ signal and only emitted for reference.
+
+
+Device hierarchy
+================
+
+Service org.ofono.elect
+Interface org.ofono.elect.Device
+Object path [variable prefix]/{device0,device1,...}
+
+Methods dict GetProperties()
+
+ Returns properties for the device object. See
+ the properties section for available properties.
+
+ Connect()
+
+ Establish a connection.
+
+ Disconnect()
+
+ Tear down a connection.
+
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+Properties string Name [readonly]
+
+ Friendly name of the device.
+
+ boolean Active [readwrite]
+
+ Holds whether the device is connected.
+
+ dict Settings [readonly]
+
+ Holds all the IP network settings.
+
+ string Interface [readonly, optional]
+
+ Holds the interface of the network interface
+ used by this connection (e.g. "ppp0" "usb0").
+
+ string Method [readonly, optional]
+
+ Holds the IP network config method.
+ "static"- Set IP network statically
+ "dhcp" - Set IP network through DHCP
+
+ string Address [readonly, optional]
+
+ Holds the IP address for this connection.
+
+ string Netmask [readonly, optional]
+
+ Holds the Netmask for this connection.
+
+ array{string} DomainNameServers [readonly, optional]
+
+ Holds the list of domain name servers for this
+ connection.
diff --git a/elect/device.c b/elect/device.c
new file mode 100644
index 0000000..1592cab
--- /dev/null
+++ b/elect/device.c
@@ -0,0 +1,685 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2011 BMW Car IT GmbH. 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 <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <netinet/ether.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "plugins/bluetooth.h"
+
+#include "elect.h"
+
+#define STATIC_IP_NETMASK "255.255.255.255"
+
+static DBusConnection *connection;
+
+static GHashTable *device_hash;
+
+struct ipv4_settings {
+ char *interface;
+
+ char *ip;
+ char **nameservers;
+};
+
+struct elect_device {
+ DBusPendingCall *call;
+ DBusMessage *pending;
+
+ char *path;
+ char *address;
+ char *tty;
+
+ char *elect_path;
+ gboolean active;
+ struct ipv4_settings settings;
+ char *name;
+
+ struct elect_dun *dun;
+};
+
+static char *get_ident(const char *path)
+{
+ char *pos;
+
+ if (*path != '/')
+ return NULL;
+
+ pos = strrchr(path, '/');
+ if (pos == NULL)
+ return NULL;
+
+ return pos + 1;
+}
+
+const char *__elect_device_get_path(struct elect_device *device)
+{
+ return device->elect_path;
+}
+
+static void settings_append(struct elect_device *device,
+ DBusMessageIter *iter)
+{
+ DBusMessageIter variant;
+ DBusMessageIter array;
+ char typesig[5];
+ char arraysig[6];
+ const char *method;
+ const char *netmask;
+
+ arraysig[0] = DBUS_TYPE_ARRAY;
+ arraysig[1] = typesig[0] = DBUS_DICT_ENTRY_BEGIN_CHAR;
+ arraysig[2] = typesig[1] = DBUS_TYPE_STRING;
+ arraysig[3] = typesig[2] = DBUS_TYPE_VARIANT;
+ arraysig[4] = typesig[3] = DBUS_DICT_ENTRY_END_CHAR;
+ arraysig[5] = typesig[4] = '\0';
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ arraysig, &variant);
+
+ dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+ typesig, &array);
+
+ if (device->active == FALSE)
+ goto out;
+
+ if (device->settings.interface)
+ ofono_dbus_dict_append(&array, "Interface",
+ DBUS_TYPE_STRING, &device->settings.interface);
+
+ method = "static";
+ ofono_dbus_dict_append(&array, "Method", DBUS_TYPE_STRING, &method);
+
+ if (device->settings.ip)
+ ofono_dbus_dict_append(&array, "Address", DBUS_TYPE_STRING,
+ &device->settings.ip);
+
+ netmask = STATIC_IP_NETMASK;
+ ofono_dbus_dict_append(&array, "Netmask", DBUS_TYPE_STRING,
+ &netmask);
+
+ if (device->settings.nameservers)
+ ofono_dbus_dict_append_array(&array, "DomainNameServers",
+ DBUS_TYPE_STRING,
+ &device->settings.nameservers);
+
+out:
+ dbus_message_iter_close_container(&variant, &array);
+
+ dbus_message_iter_close_container(iter, &variant);
+}
+
+static void settings_append_dict(struct elect_device *device,
+ DBusMessageIter *dict)
+{
+ DBusMessageIter entry;
+ const char *key = "Settings";
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ settings_append(device, &entry);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+void __elect_device_append_properties(struct elect_device *device,
+ DBusMessageIter *dict)
+{
+ settings_append_dict(device, dict);
+
+ ofono_dbus_dict_append(dict, "Active", DBUS_TYPE_BOOLEAN,
+ &device->active);
+
+ ofono_dbus_dict_append(dict, "Name", DBUS_TYPE_STRING,
+ &device->name);
+}
+
+void __elect_device_foreach(elect_device_foreach_func func, void *userdata)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ DBG("");
+
+ g_hash_table_iter_init(&iter, device_hash);
+
+ while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+ struct elect_device *device = value;
+
+ func(device, userdata);
+ }
+}
+
+static void settings_changed(struct elect_device *device)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter;
+ const char *key = "Settings";
+
+ signal = dbus_message_new_signal(device->elect_path,
+ ELECT_DEVICE_INTERFACE,
+ "PropertyChanged");
+
+ if (signal == NULL)
+ return;
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
+
+ settings_append(device, &iter);
+
+ g_dbus_send_message(connection, signal);
+}
+
+static void connect_cb(const char *interface, const char *ip,
+ const char *peer, const char *dns1, const char *dns2,
+ void *data)
+{
+ struct elect_device *device = data;
+ const char *dns[3] = { dns1, dns2, 0 };
+
+ DBG("%p", device);
+
+ g_free(device->settings.interface);
+ device->settings.interface = g_strdup(interface);
+ if (device->settings.interface == NULL)
+ goto err;
+
+ g_free(device->settings.ip);
+ device->settings.ip = g_strdup(ip);
+ if (device->settings.ip == NULL)
+ goto err;
+
+ g_strfreev(device->settings.nameservers);
+ device->settings.nameservers = g_strdupv((gchar **)dns);
+ if (device->settings.nameservers == NULL)
+ goto err;
+
+ device->active = TRUE;
+
+ settings_changed(device);
+ ofono_dbus_signal_property_changed(connection, device->elect_path,
+ ELECT_DEVICE_INTERFACE, "Active",
+ DBUS_TYPE_BOOLEAN, &device->active);
+
+ return;
+
+err:
+ g_free(device->settings.interface);
+ g_free(device->settings.ip);
+ g_strfreev(device->settings.nameservers);
+ device->settings.interface = NULL;
+ device->settings.ip = NULL;
+ device->settings.nameservers = NULL;
+}
+
+static int bt_disconnect(struct elect_device *device);
+
+static void disconnect_cb(void *data)
+{
+ struct elect_device *device = data;
+
+ DBG("%p", device);
+
+ g_free(device->settings.interface);
+ g_free(device->settings.ip);
+ g_strfreev(device->settings.nameservers);
+ device->settings.interface = NULL;
+ device->settings.ip = NULL;
+ device->settings.nameservers = NULL;
+
+ device->active = FALSE;
+
+ settings_changed(device);
+ ofono_dbus_signal_property_changed(connection, device->elect_path,
+ ELECT_DEVICE_INTERFACE, "Active",
+ DBUS_TYPE_BOOLEAN, &device->active);
+
+ bt_disconnect(device);
+}
+
+static void bt_connect_reply(DBusPendingCall *call, gpointer user_data)
+{
+ struct elect_device *device = user_data;
+ DBusMessage *reply;
+ DBusError derr;
+ char *tty;
+
+ DBG("%p", device);
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ device->call = NULL;
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ DBG("Connection to bt serial returned with error: %s, %s",
+ derr.name, derr.message);
+
+ dbus_error_free(&derr);
+ goto done;
+ }
+
+ dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &tty,
+ DBUS_TYPE_INVALID);
+
+ DBG("%p tty %s", device, tty);
+
+ device->tty = g_strdup(tty);
+
+ device->dun = __elect_dun_create(device->tty, connect_cb,
+ disconnect_cb, device);
+ __elect_dun_connect(device->dun);
+
+done:
+ dbus_message_unref(reply);
+
+ if (device->pending != NULL) {
+ DBusMessage *reply;
+
+ if (device->tty != NULL)
+ reply = dbus_message_new_method_return(device->pending);
+ else
+ reply = __ofono_error_failed(device->pending);
+
+ __ofono_dbus_pending_reply(&device->pending, reply);
+
+ device->pending = NULL;
+ }
+}
+
+static int bt_connect(struct elect_device *device)
+{
+ DBusPendingCall *call;
+ int status;
+ char *profile = "dun";
+
+ DBG("%p", device);
+
+ status = bluetooth_send_with_reply(device->path,
+ BLUEZ_SERIAL_INTERFACE, "Connect",
+ &call, bt_connect_reply,
+ device, NULL, DBUS_TIMEOUT,
+ DBUS_TYPE_STRING, &profile,
+ DBUS_TYPE_INVALID);
+ if (status < 0)
+ return -EINVAL;
+
+ device->call = call;
+
+ return -EINPROGRESS;
+}
+
+static void bt_disconnect_reply(DBusPendingCall *call, gpointer user_data)
+{
+ struct elect_device *device = user_data;
+ DBusMessage *reply;
+
+ DBG("%p", device);
+
+ reply = dbus_pending_call_steal_reply(call);
+ dbus_message_unref(reply);
+
+ device->call = NULL;
+
+ g_free(device->tty);
+ device->tty = NULL;
+
+ __elect_dun_unref(device->dun);
+ device->dun = NULL;
+}
+
+static int bt_disconnect(struct elect_device *device)
+{
+ DBusPendingCall *call;
+ int status;
+
+ DBG("%p", device);
+
+ if (device->tty == NULL)
+ return 0;
+
+ status = bluetooth_send_with_reply(device->path,
+ BLUEZ_SERIAL_INTERFACE, "Disconnect",
+ &call, bt_disconnect_reply,
+ device, NULL, DBUS_TIMEOUT,
+ DBUS_TYPE_STRING, &device->tty,
+ DBUS_TYPE_INVALID);
+ if (status < 0)
+ return -EINVAL;
+
+ device->call = call;
+
+ return -EINPROGRESS;
+}
+
+static int register_device(struct elect_device *device);
+
+static int bt_probe(const char *path, const char *dev_addr,
+ const char *adapter_addr, const char *alias)
+{
+ struct elect_device *device;
+ char buf[256];
+
+ DBG("");
+
+ /* We already have this device in our hash, ignore */
+ if (g_hash_table_lookup(device_hash, path) != NULL)
+ return -EALREADY;
+
+ ofono_info("Using device: %s, devaddr: %s, adapter: %s",
+ path, dev_addr, adapter_addr);
+
+ strcpy(buf, "dun/");
+ bluetooth_create_path(dev_addr, adapter_addr, buf + 4, sizeof(buf) - 4);
+
+ device = g_try_new0(struct elect_device, 1);
+ if (device == 0) {
+ DBG("Failed to create device data structure");
+ return -ENOMEM;
+ }
+
+ DBG("%p", device);
+
+ device->path = g_strdup(path);
+ if (device->path == NULL)
+ goto free;
+
+ device->address = g_strdup(dev_addr);
+ if (device->address == NULL)
+ goto free;
+
+ device->name = g_strdup(alias);
+ if (device->name == NULL)
+ goto free;
+
+ device->elect_path = g_strdup_printf("/device/%s", get_ident(path));
+ if (device->elect_path == NULL)
+ goto free;
+
+ g_hash_table_insert(device_hash, g_strdup(path), device);
+
+ register_device(device);
+
+ return 0;
+
+free:
+ g_free(device->path);
+ g_free(device->address);
+ g_free(device->name);
+ g_free(device->elect_path);
+ g_free(device);
+
+ return -ENOMEM;
+}
+
+static int unregister_device(struct elect_device *device);
+
+static gboolean bt_remove_device(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct elect_device *device = value;
+ const char *path = key;
+ const char *prefix = user_data;
+
+ DBG("%p", device);
+
+ if (device->call != NULL)
+ dbus_pending_call_cancel(device->call);
+
+ if (prefix && g_str_has_prefix(path, prefix) == FALSE)
+ return FALSE;
+
+ unregister_device(device);
+
+ return TRUE;
+}
+
+static void bt_remove(const char *prefix)
+{
+ DBG("%s", prefix);
+
+ if (device_hash == NULL)
+ return;
+
+ g_hash_table_foreach_remove(device_hash, bt_remove_device,
+ (gpointer) prefix);
+}
+
+static void bt_set_alias(const char *path, const char *alias)
+{
+ struct elect_device *device;
+
+ DBG("");
+
+ if (path == NULL || alias == NULL)
+ return;
+
+ device = g_hash_table_lookup(device_hash, path);
+ if (device == NULL)
+ return;
+
+ g_free(device->name);
+ device->name = g_strdup(alias);
+}
+
+static struct bluetooth_profile dun_profile = {
+ .name = "dun_dt",
+ .probe = bt_probe,
+ .remove = bt_remove,
+ .set_alias = bt_set_alias,
+};
+
+static DBusMessage *device_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct elect_device *device = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+
+ __elect_device_append_properties(device, &dict);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static DBusMessage *device_connect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct elect_device *device = data;
+ int err;
+
+ DBG("");
+
+ err = bt_connect(device);
+ if (err != -EINPROGRESS && err < 0)
+ return __ofono_error_failed(msg);
+
+ device->pending = dbus_message_ref(msg);
+
+ return NULL;
+}
+
+static DBusMessage *device_disconnect(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct elect_device *device = data;
+
+ DBG("");
+
+ if (device->dun)
+ __elect_dun_disconnect(device->dun);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable device_methods[] = {
+ { "GetProperties", "", "a{sv}", device_get_properties },
+ { "Connect", "", "", device_connect,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "Disconnect", "", "", device_disconnect },
+ { }
+};
+
+static GDBusSignalTable device_signals[] = {
+ { "PropertyChanged", "sv" },
+ { }
+};
+
+static int register_device(struct elect_device *device)
+{
+ DBusMessage *signal;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+
+ DBG("%p elect_path %s", device, device->elect_path);
+
+ if (!g_dbus_register_interface(connection, device->elect_path,
+ ELECT_DEVICE_INTERFACE,
+ device_methods, device_signals,
+ NULL, device, NULL)) {
+ ofono_error("Could not register Device %s", device->path);
+ return -EIO;
+ }
+
+ signal = dbus_message_new_signal(ELECT_MANAGER_PATH,
+ ELECT_MANAGER_INTERFACE,
+ "DeviceAdded");
+
+ if (signal == NULL)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(signal, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &device->elect_path);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+ __elect_device_append_properties(device, &dict);
+ dbus_message_iter_close_container(&iter, &dict);
+
+ g_dbus_send_message(connection, signal);
+
+ return 0;
+}
+
+static int unregister_device(struct elect_device *device)
+{
+ DBG("%p elect_path %s", device, device->elect_path);
+
+ g_dbus_unregister_interface(connection, device->elect_path,
+ ELECT_DEVICE_INTERFACE);
+
+ g_dbus_emit_signal(connection, ELECT_MANAGER_PATH,
+ ELECT_MANAGER_INTERFACE, "DeviceRemoved",
+ DBUS_TYPE_OBJECT_PATH, &device->elect_path,
+ DBUS_TYPE_INVALID);
+
+ return 0;
+}
+
+static void destroy_device(gpointer user)
+{
+ struct elect_device *device = user;
+
+ if (device->pending)
+ dbus_message_unref(device->pending);
+
+ if (device->call)
+ dbus_pending_call_cancel(device->call);
+
+ g_free(device->settings.interface);
+ g_free(device->settings.ip);
+ g_strfreev(device->settings.nameservers);
+
+ g_free(device->path);
+ g_free(device->address);
+ g_free(device->tty);
+ g_free(device->elect_path);
+ g_free(device->name);
+
+ g_free(device);
+}
+
+static void device_shutdown(gpointer key, gpointer value, gpointer user_data)
+{
+ struct elect_device *device = value;
+
+ unregister_device(device);
+}
+
+void __elect_device_shutdown(void)
+{
+ g_hash_table_foreach(device_hash, device_shutdown, NULL);
+
+ __elect_exit();
+}
+
+int __elect_device_init(DBusConnection *conn)
+{
+ int err;
+
+ DBG("");
+
+ connection = conn;
+
+ err = bluetooth_register_uuid(DUN_GW_UUID, &dun_profile);
+ if (err < 0)
+ return err;
+
+
+ device_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, destroy_device);
+
+ return 0;
+}
+
+void __elect_device_cleanup(void)
+{
+ DBG("");
+
+ bluetooth_unregister_uuid(DUN_GW_UUID);
+
+ g_hash_table_destroy(device_hash);
+}
diff --git a/elect/dun.c b/elect/dun.c
new file mode 100644
index 0000000..012591e
--- /dev/null
+++ b/elect/dun.c
@@ -0,0 +1,270 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2011 BMW Car IT GmbH. 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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/signalfd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+#include <gatchat.h>
+#include <gattty.h>
+#include <gatppp.h>
+
+#include "elect.h"
+
+static const char *none_prefix[] = { NULL };
+
+struct elect_dun {
+ char *path;
+
+ GAtPPP *ppp;
+ GAtChat *control;
+ GAtChat *modem;
+
+ elect_dun_connect_cb_t connect_cb;
+ elect_dun_disconnect_cb_t disconnect_cb;
+ void *data;
+};
+
+static void dun_debug(const char *str, void *data)
+{
+ DBG("%s: %s\n", (const char *) data, str);
+}
+
+static void kill_ppp(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct elect_dun *dun = user_data;
+
+ DBG("%s %s\n", dun->path, ok ? "ok" : "failed");
+
+ if (ok == FALSE)
+ return;
+
+ g_at_ppp_unref(dun->ppp);
+ dun->ppp = NULL;
+
+ dun->disconnect_cb(dun->data);
+}
+
+static void ppp_suspend_ath0(gpointer user_data)
+{
+ struct elect_dun *dun = user_data;
+
+ DBG("%s", dun->path);
+
+ g_at_chat_resume(dun->modem);
+ g_at_chat_send(dun->modem, "ATH0", none_prefix, kill_ppp, dun, NULL);
+}
+
+static void resume_ppp(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct elect_dun *dun = user_data;
+
+ DBG("%s %s\n", dun->path, ok ? "ok" : "failed");
+
+ if (ok == FALSE)
+ return;
+
+ g_at_chat_suspend(dun->modem);
+ g_at_ppp_resume(dun->ppp);
+
+ dun->disconnect_cb(dun->data);
+}
+
+static void ppp_suspend_ato0(gpointer user_data)
+{
+ struct elect_dun *dun = user_data;
+
+ DBG("%s", dun->path);
+
+ g_at_chat_resume(dun->modem);
+ g_at_chat_send(dun->modem, "ATO0", none_prefix, resume_ppp, dun, NULL);
+}
+
+static void ppp_connect(const char *iface, const char *local, const char *peer,
+ const char *dns1, const char *dns2,
+ gpointer user_data)
+{
+ struct elect_dun *dun = user_data;
+
+ DBG("Network Device: %s\n", iface);
+ DBG("IP Address: %s\n", local);
+ DBG("Peer IP Address: %s\n", peer);
+ DBG("Primary DNS Server: %s\n", dns1);
+ DBG("Secondary DNS Server: %s\n", dns2);
+
+ if (dun->connect_cb)
+ dun->connect_cb(iface, local, peer, dns1, dns2, dun->data);
+}
+
+static void ppp_disconnect(GAtPPPDisconnectReason reason, gpointer user_data)
+{
+ struct elect_dun *dun = user_data;
+
+ DBG("PPP Link down: %d\n", reason);
+
+ g_at_ppp_unref(dun->ppp);
+ dun->ppp = NULL;
+
+ g_at_chat_resume(dun->modem);
+
+ if (dun->disconnect_cb)
+ dun->disconnect_cb(dun->data);
+}
+
+static void connect_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct elect_dun *dun = user_data;
+ GAtIO *io;
+
+ if (!ok) {
+ DBG("Unable to define context\n");
+ return;
+ }
+
+ /* get the data IO channel */
+ io = g_at_chat_get_io(dun->modem);
+
+ /*
+ * shutdown gatchat or else it tries to take all the input
+ * from the modem and does not let PPP get it.
+ */
+ g_at_chat_suspend(dun->modem);
+
+ /* open ppp */
+ dun->ppp = g_at_ppp_new();
+ if (dun->ppp == NULL) {
+ DBG("Unable to create PPP object\n");
+ return;
+ }
+ g_at_ppp_set_debug(dun->ppp, dun_debug, "PPP");
+
+ /* set connect and disconnect callbacks */
+ g_at_ppp_set_connect_function(dun->ppp, ppp_connect, dun);
+ g_at_ppp_set_disconnect_function(dun->ppp, ppp_disconnect, dun);
+
+ /* open the ppp connection */
+ g_at_ppp_open(dun->ppp, io);
+}
+
+static int open_serial(struct elect_dun *dun)
+{
+ GAtSyntax *syntax;
+ GIOChannel *channel;
+
+ channel = g_at_tty_open(dun->path, NULL);
+ if (channel == NULL)
+ return -EIO;
+
+ syntax = g_at_syntax_new_gsm_permissive();
+ dun->control = g_at_chat_new(channel, syntax);
+ g_io_channel_unref(channel);
+ g_at_syntax_unref(syntax);
+
+ if (dun->control == NULL)
+ return -EIO;
+
+ g_at_chat_ref(dun->control);
+ dun->modem = dun->control;
+ g_at_chat_set_debug(dun->control, dun_debug, "Control");
+
+ return 0;
+}
+
+struct elect_dun *__elect_dun_create(const char *path,
+ elect_dun_connect_cb_t connect_cb,
+ elect_dun_disconnect_cb_t disconnect_cb,
+ void *data)
+{
+ struct elect_dun *dun;
+
+ DBG("%s", path);
+
+ dun = g_try_new0(struct elect_dun, 1);
+ if (dun == NULL)
+ return NULL;
+
+ dun->path = g_strdup(path);
+ dun->connect_cb = connect_cb;
+ dun->disconnect_cb = disconnect_cb;
+ dun->data = data;
+
+ return dun;
+}
+
+int __elect_dun_connect(struct elect_dun *dun)
+{
+ int err;
+
+ DBG("%s", dun->path);
+
+ err = open_serial(dun);
+ if (err < 0)
+ return err;
+
+ g_at_chat_send(dun->control, "ATD*99#", none_prefix, connect_cb,
+ dun, NULL);
+
+ return 0;
+}
+
+int __elect_dun_disconnect(struct elect_dun *dun)
+{
+ DBG("%s", dun->path);
+
+ if (dun->ppp == NULL)
+ return -EINVAL;
+
+ /* XXX Which one is the right one? */
+ if (FALSE)
+ g_at_ppp_set_suspend_function(dun->ppp, ppp_suspend_ath0, dun);
+ else
+ g_at_ppp_set_suspend_function(dun->ppp, ppp_suspend_ato0, dun);
+
+ g_at_ppp_suspend(dun->ppp);
+
+ return 0;
+}
+
+void __elect_dun_unref(struct elect_dun *dun)
+{
+ DBG("%s", dun->path);
+
+ if (dun->ppp)
+ g_at_ppp_unref(dun->ppp);
+ if (dun->control)
+ g_at_chat_unref(dun->control);
+
+ g_free(dun->path);
+
+ g_free(dun);
+}
diff --git a/elect/elect.conf b/elect/elect.conf
new file mode 100644
index 0000000..548ffe8
--- /dev/null
+++ b/elect/elect.conf
@@ -0,0 +1,23 @@
+<!-- This configuration file specifies the required security policies
+ for oFono elect (DUN) daemon to work. -->
+
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- ../system.conf have denied everything, so we just punch some holes -->
+
+ <policy user="root">
+ <allow own="org.ofono.elect"/>
+ <allow send_destination="org.ofono.elect"/>
+ </policy>
+
+ <policy at_console="true">
+ <allow send_destination="org.ofono.elect"/>
+ </policy>
+
+ <policy context="default">
+ <deny send_destination="org.ofono.elect"/>
+ </policy>
+
+</busconfig>
diff --git a/elect/elect.h b/elect/elect.h
new file mode 100644
index 0000000..75d161b
--- /dev/null
+++ b/elect/elect.h
@@ -0,0 +1,102 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2011 BMW Car IT GmbH. 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
+ *
+ */
+
+#include <glib.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+
+#include <ofono/types.h>
+
+void __elect_exit(void);
+
+#include <ofono/log.h>
+
+int __ofono_log_init(const char *program, const char *debug,
+ ofono_bool_t detach);
+void __ofono_log_cleanup(void);
+void __ofono_log_enable(struct ofono_debug_desc *start,
+ struct ofono_debug_desc *stop);
+
+#include <ofono/dbus.h>
+
+#define ELECT_SERVICE "org.ofono.elect"
+#define ELECT_MANAGER_INTERFACE "org.ofono.elect.Manager"
+#define ELECT_DEVICE_INTERFACE "org.ofono.elect.Device"
+#define ELECT_MANAGER_PATH "/"
+
+int __ofono_dbus_init(DBusConnection *conn);
+void __ofono_dbus_cleanup(void);
+
+void __ofono_dbus_pending_reply(DBusMessage **msg, DBusMessage *reply);
+
+DBusMessage *__ofono_error_invalid_args(DBusMessage *msg);
+DBusMessage *__ofono_error_invalid_format(DBusMessage *msg);
+DBusMessage *__ofono_error_not_implemented(DBusMessage *msg);
+DBusMessage *__ofono_error_failed(DBusMessage *msg);
+DBusMessage *__ofono_error_busy(DBusMessage *msg);
+DBusMessage *__ofono_error_not_found(DBusMessage *msg);
+DBusMessage *__ofono_error_not_active(DBusMessage *msg);
+DBusMessage *__ofono_error_not_supported(DBusMessage *msg);
+DBusMessage *__ofono_error_not_available(DBusMessage *msg);
+DBusMessage *__ofono_error_timed_out(DBusMessage *msg);
+DBusMessage *__ofono_error_sim_not_ready(DBusMessage *msg);
+DBusMessage *__ofono_error_in_use(DBusMessage *msg);
+DBusMessage *__ofono_error_not_attached(DBusMessage *msg);
+DBusMessage *__ofono_error_attach_in_progress(DBusMessage *msg);
+DBusMessage *__ofono_error_not_registered(DBusMessage *msg);
+DBusMessage *__ofono_error_canceled(DBusMessage *msg);
+DBusMessage *__ofono_error_access_denied(DBusMessage *msg);
+DBusMessage *__ofono_error_emergency_active(DBusMessage *msg);
+
+
+int __elect_manager_init(DBusConnection *conn);
+void __elect_manager_cleanup(void);
+
+
+struct elect_device;
+
+int __elect_device_init(DBusConnection *conn);
+void __elect_device_cleanup(void);
+
+typedef void (*elect_device_foreach_func)(struct elect_device *device,
+ void *data);
+void __elect_device_foreach(elect_device_foreach_func cb, void *userdata);
+
+const char *__elect_device_get_path(struct elect_device *device);
+void __elect_device_append_properties(struct elect_device *device,
+ DBusMessageIter *dict);
+void __elect_device_shutdown(void);
+
+
+typedef void (*elect_dun_connect_cb_t)(const char *interface, const char *ip,
+ const char *peer,
+ const char *dns1, const char *dns2,
+ void *data);
+typedef void (*elect_dun_disconnect_cb_t)(void *data);
+
+struct elect_dun *__elect_dun_create(const char *path,
+ elect_dun_connect_cb_t connect_cb,
+ elect_dun_disconnect_cb_t disconnect_cb,
+ void *data);
+int __elect_dun_connect(struct elect_dun *dun);
+int __elect_dun_disconnect(struct elect_dun *dun);
+void __elect_dun_unref(struct elect_dun *dun);
diff --git a/elect/elect.service b/elect/elect.service
new file mode 100644
index 0000000..39d9349
--- /dev/null
+++ b/elect/elect.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=DUN service
+After=syslog.target
+
+[Service]
+Type=dbus
+BusName=org.ofono.elect
+ExecStart=/usr/sbin/electd -n
+
+[Install]
+WantedBy=multi-user.target
diff --git a/elect/main.c b/elect/main.c
new file mode 100644
index 0000000..97be904
--- /dev/null
+++ b/elect/main.c
@@ -0,0 +1,253 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+
+#include <gdbus.h>
+
+#ifdef HAVE_CAPNG
+#include <cap-ng.h>
+#endif
+
+#include "elect.h"
+
+#define SHUTDOWN_GRACE_SECONDS 10
+
+static GMainLoop *event_loop;
+
+void __elect_exit(void)
+{
+ g_main_loop_quit(event_loop);
+}
+
+static gboolean quit_eventloop(gpointer user_data)
+{
+ __elect_exit();
+ return FALSE;
+}
+
+static unsigned int __terminated = 0;
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct signalfd_siginfo si;
+ ssize_t result;
+ int fd;
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+ return FALSE;
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ result = read(fd, &si, sizeof(si));
+ if (result != sizeof(si))
+ return FALSE;
+
+ switch (si.ssi_signo) {
+ case SIGINT:
+ case SIGTERM:
+ if (__terminated == 0) {
+ ofono_info("Terminating");
+ g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
+ quit_eventloop, NULL);
+
+ __elect_device_shutdown();
+ }
+
+ __terminated = 1;
+ break;
+ }
+
+ return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+ GIOChannel *channel;
+ guint source;
+ sigset_t mask;
+ int fd;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+ perror("Failed to set signal mask");
+ return 0;
+ }
+
+ fd = signalfd(-1, &mask, 0);
+ if (fd < 0) {
+ perror("Failed to create signal descriptor");
+ return 0;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ signal_handler, NULL);
+
+ g_io_channel_unref(channel);
+
+ return source;
+}
+
+static void system_bus_disconnected(DBusConnection *conn, void *user_data)
+{
+ ofono_error("System bus has disconnected!");
+
+ g_main_loop_quit(event_loop);
+}
+
+static gchar *option_debug = NULL;
+static gboolean option_detach = TRUE;
+static gboolean option_version = FALSE;
+
+static gboolean parse_debug(const char *key, const char *value,
+ gpointer user_data, GError **error)
+{
+ if (value)
+ option_debug = g_strdup(value);
+ else
+ option_debug = g_strdup("*");
+
+ return TRUE;
+}
+
+static GOptionEntry options[] = {
+ { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
+ G_OPTION_ARG_CALLBACK, parse_debug,
+ "Specify debug options to enable", "DEBUG" },
+ { "nodetach", 'n', G_OPTION_FLAG_REVERSE,
+ G_OPTION_ARG_NONE, &option_detach,
+ "Don't run as daemon in background" },
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+ "Show version information and exit" },
+ { NULL },
+};
+
+int main(int argc, char **argv)
+{
+ GOptionContext *context;
+ GError *err = NULL;
+ DBusConnection *conn;
+ DBusError error;
+ guint signal;
+
+#ifdef HAVE_CAPNG
+ /* Drop capabilities */
+ capng_clear(CAPNG_SELECT_BOTH);
+ capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+ CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
+ CAP_NET_RAW, CAP_SYS_ADMIN, -1);
+ capng_apply(CAPNG_SELECT_BOTH);
+#endif
+
+ context = g_option_context_new(NULL);
+ g_option_context_add_main_entries(context, options, NULL);
+
+ if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
+ if (err != NULL) {
+ g_printerr("%s\n", err->message);
+ g_error_free(err);
+ return 1;
+ }
+
+ g_printerr("An unknown error occurred\n");
+ return 1;
+ }
+
+ g_option_context_free(context);
+
+ if (option_version == TRUE) {
+ printf("%s\n", VERSION);
+ exit(0);
+ }
+
+ if (option_detach == TRUE) {
+ if (daemon(0, 0)) {
+ perror("Can't start daemon");
+ return 1;
+ }
+ }
+
+ event_loop = g_main_loop_new(NULL, FALSE);
+
+ signal = setup_signalfd();
+
+ __ofono_log_init(argv[0], option_debug, option_detach);
+
+ dbus_error_init(&error);
+
+ conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, ELECT_SERVICE, &error);
+ if (conn == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ ofono_error("Unable to hop onto D-Bus: %s",
+ error.message);
+ dbus_error_free(&error);
+ } else {
+ ofono_error("Unable to hop onto D-Bus");
+ }
+
+ goto cleanup;
+ }
+
+ g_dbus_set_disconnect_function(conn, system_bus_disconnected,
+ NULL, NULL);
+
+ __ofono_dbus_init(conn);
+
+ __elect_device_init(conn);
+ __elect_manager_init(conn);
+
+ g_main_loop_run(event_loop);
+
+ __elect_manager_cleanup();
+ __elect_device_cleanup();
+
+ __ofono_dbus_cleanup();
+ dbus_connection_unref(conn);
+
+cleanup:
+ g_source_remove(signal);
+
+ g_main_loop_unref(event_loop);
+
+ __ofono_log_cleanup();
+
+ return 0;
+}
diff --git a/elect/manager.c b/elect/manager.c
new file mode 100644
index 0000000..c983aea
--- /dev/null
+++ b/elect/manager.c
@@ -0,0 +1,115 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
+ * Copyright (C) 2011 BMW Car IT GmbH. 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 <string.h>
+#include <glib.h>
+#include <gdbus.h>
+
+#include "elect.h"
+
+static DBusConnection *connection;
+
+static void append_device(struct elect_device *device, void *userdata)
+{
+ DBusMessageIter *array = userdata;
+ const char *path = __elect_device_get_path(device);
+ DBusMessageIter entry, dict;
+
+ dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
+ NULL, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+ &path);
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+
+ __elect_device_append_properties(device, &dict);
+ dbus_message_iter_close_container(&entry, &dict);
+ dbus_message_iter_close_container(array, &entry);
+}
+
+static DBusMessage *manager_get_devices(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_OBJECT_PATH_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING,
+ &array);
+ __elect_device_foreach(append_device, &array);
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static GDBusMethodTable manager_methods[] = {
+ { "GetDevices", "", "a(oa{sv})", manager_get_devices },
+ { }
+};
+
+static GDBusSignalTable manager_signals[] = {
+ { "DeviceAdded", "oa{sv}" },
+ { "DeviceRemoved", "o" },
+ { }
+};
+
+int __elect_manager_init(DBusConnection *conn)
+{
+ gboolean ret;
+
+ connection = conn;
+
+ ret = g_dbus_register_interface(connection, ELECT_MANAGER_PATH,
+ ELECT_MANAGER_INTERFACE,
+ manager_methods, manager_signals,
+ NULL, NULL, NULL);
+
+ if (ret == FALSE)
+ return -1;
+
+ return 0;
+}
+
+void __elect_manager_cleanup(void)
+{
+ g_dbus_unregister_interface(connection, ELECT_MANAGER_PATH,
+ ELECT_MANAGER_INTERFACE);
+}
diff --git a/plugins/bluetooth.h b/plugins/bluetooth.h
index daa1873..4fc16ad 100644
--- a/plugins/bluetooth.h
+++ b/plugins/bluetooth.h
@@ -27,6 +27,7 @@
#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service"
+#define BLUEZ_SERIAL_INTERFACE BLUEZ_SERVICE ".Serial"
#define DBUS_TIMEOUT 15
diff --git a/test/elect-connect b/test/elect-connect
new file mode 100755
index 0000000..09e592e
--- /dev/null
+++ b/test/elect-connect
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+
+import dbus
+import sys
+
+bus = dbus.SystemBus()
+
+if len(sys.argv) == 2:
+ path = sys.argv[1]
+else:
+ manager = dbus.Interface(bus.get_object('org.ofono.elect', '/'),
+ 'org.ofono.elect.Manager')
+ devices = manager.GetDevices()
+ path = devices[0][0]
+
+print "Connect device %s..." % path
+device = dbus.Interface(bus.get_object('org.ofono.elect', path),
+ 'org.ofono.elect.Device')
+
+device.Connect()
diff --git a/test/elect-disconnect b/test/elect-disconnect
new file mode 100755
index 0000000..76ff74c
--- /dev/null
+++ b/test/elect-disconnect
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+
+import dbus
+import sys
+
+bus = dbus.SystemBus()
+
+if len(sys.argv) == 2:
+ path = sys.argv[1]
+else:
+ manager = dbus.Interface(bus.get_object('org.ofono.elect', '/'),
+ 'org.ofono.elect.Manager')
+ devices = manager.GetDevices()
+ path = devices[0][0]
+
+print "Disonnect device %s..." % path
+device = dbus.Interface(bus.get_object('org.ofono.elect', path),
+ 'org.ofono.elect.Device')
+
+device.Disconnect()
--
1.7.8.110.g4cb5d1
9 years, 1 month
[PATCH 0/9] CPHS SPN, short-SPN support
by Oleg Zhurakivskyy
Hello,
Please find the initial version of the CPHS SPN and short-SPN TODO items.
What's missing:
- changes to SPN callback in src/grps.c in order not to duplicate the logic for SPN, CPHS SPN and short SPN in both files.
Regards,
Oleg
Oleg Zhurakivskyy (9):
network: M9 coding style corrections
network: Refactor sim_spn_read_cb()
network: Rename spname to spn
gprs-provision: Fix crash if no SPN present
simutil: Add CPHS SPN and short-SPN IDs
network: Add CPHS SPN, short-SPN flags
network: Add CPHS SPN fallback
network: Add CPHS short-SPN fallback
TODO: Remove completed CPHS SPN and short-SPN tasks
TODO | 14 -----
examples/provision.c | 2 +-
src/network.c | 155 ++++++++++++++++++++++++++++++++++----------------
src/simutil.h | 2 +
4 files changed, 109 insertions(+), 64 deletions(-)
--
1.7.5.4
9 years, 1 month
[RFC_v1 0/2] Add SIM polling mechanism for Sierra
by Guillaume Zajac
Hi,
Change log from v0:
- Separate memory leak fix in another patch
- Fix issue into polling mechanism
Kind regards,
Guillaume
Guillaume Zajac (2):
sierra: Fix memory leak
sierra: Add SIM state polling
plugins/sierra.c | 29 ++++++++++++++++++++++++++++-
1 files changed, 28 insertions(+), 1 deletions(-)
9 years, 1 month
[PATCH_v2 0/2] cdma-connman add RoamingAllowed option
by Guillaume Zajac
Hi,
Change log from v1, update documentation accordingly to the implementation.
Kind regards,
Guillaume
Guillaume Zajac (2):
doc: Add RoamingAllowed property
cdma-connman: Add RoamingAllowed support
doc/cdma-connman-api.txt | 8 ++++++++
src/cdma-connman.c | 19 ++++++++++++++++++-
2 files changed, 26 insertions(+), 1 deletions(-)
9 years, 1 month
[PATCH_v1 0/2] cdma-connman add roaming support
by Guillaume Zajac
Hi,
Change log from v0:
- Remove cdma-netreg status watches
- Only change the property RomaingAllowed.
- Don't change the data call state when the property is changed.
Kind regards,
Guilllaume
Guillaume Zajac (2):
doc: Add RoamingAllowed property
cdma-connman: Add RoamingAllowed support
doc/cdma-connman-api.txt | 8 ++++++++
src/cdma-connman.c | 19 ++++++++++++++++++-
2 files changed, 26 insertions(+), 1 deletions(-)
9 years, 1 month
[PATCH_v0 0/5] Add bearer recovery implementation for CDMA modems
by Guillaume Zajac
Hi,
Those patches implement bearer recovery based on huaweicdma specifications.
It will be followed by the Radio Access Technology setting for CDMA modem.
Kind regards,
Guillaume
Guillaume Zajac (5):
doc: Add bearer property
cdma-connman: Add bearer notification public function declaration
cdma-connman: Add bearer property implementation
cdmamodem: Add bearer recovery into connman driver
huaweicdma: Specify vendor ID while creating cdma-connman atom
doc/cdma-connman-api.txt | 8 +++++++
drivers/cdmamodem/connman.c | 45 +++++++++++++++++++++++++++++++++++++++
include/cdma-connman.h | 3 ++
plugins/huaweicdma.c | 5 +++-
src/cdma-connman.c | 49 +++++++++++++++++++++++++++++++++++++++++++
src/common.h | 1 +
6 files changed, 110 insertions(+), 1 deletions(-)
9 years, 1 month
ofono with serial modem
by Andrea Galbusera
Hi! I'm new to the list and ofono project. In these days I'm trying to
figure out if ofono can help me with some embedded projects involving
M2M GPRS connections on serial modems.
I have a few questions I was not able to give an answer to, neither
from wiki nor from doc files in source code. Hope not to bother with
too newbish questions here!
1. Are non-hot-pluggable serial modem supported by ofono? I believe
they should run with the atmodem driver: is this correct?
2. Is udev detection the only way to let ofono know about a modem? If
I'm not wrong, I read about support for some kind of static
configuration in the past (modem.conf file), but it seems gone in
these days. I'm definitely fine with udev: just need some hints on how
to setup a rule to let ofono know I have a pretty standard AT modem
on, say, ttyS0. I looked at ofono.rules, but I think it deals mainly
with usb modem.
3. ofono looks very promising for its integration with d-bus. I'm
looking forward to be able to have different applications to manage
GPRS context activation/deactivation while, i.e., monitoring signal
strength and maybe asynchronous notifications by the modem itself. Are
these tasks in the ofono's scope or not?
Thanks in advance for any clarifications!
Regards,
Andrea
9 years, 1 month
[PATCH_v0 0/3] cdma-connman add roaming support
by Guillaume Zajac
Hi,
Those 3 patches are implementing roaming property support.
It contains the cdma-netreg status watches implementation, to notify
cdma connection manager that network status has changed to disable or not
data call in case roaming is allowed or not.
Kind regards,
Guillaume
Guillaume Zajac (3):
doc: Add RoamingAllowed property
cdma-netreg: Add cdma-netreg status watch
cdma-connman: Add RoamingAllowed support
doc/cdma-connman-api.txt | 8 +++++
src/cdma-connman.c | 70 +++++++++++++++++++++++++++++++++++++++++++++-
src/cdma-netreg.c | 52 ++++++++++++++++++++++++++++++++++
src/ofono.h | 13 ++++++++
4 files changed, 142 insertions(+), 1 deletions(-)
9 years, 1 month
[RFC_v0] sierra: Add SIM state polling
by Guillaume Zajac
It has been reported than for some Sierra modem, the SIM
initialization process leads to +CME ERROR: 10 sim not
present. The issue might come from SIM is not ready.
---
plugins/sierra.c | 26 +++++++++++++++++++++++++-
1 files changed, 25 insertions(+), 1 deletions(-)
diff --git a/plugins/sierra.c b/plugins/sierra.c
index c41e2d1..db54817 100644
--- a/plugins/sierra.c
+++ b/plugins/sierra.c
@@ -47,6 +47,8 @@ static const char *none_prefix[] = { NULL };
struct sierra_data {
GAtChat *chat;
+ gboolean have_sim;
+ struct at_util_sim_state_query *sim_state_query;
};
static void sierra_debug(const char *str, void *user_data)
@@ -79,6 +81,12 @@ static void sierra_remove(struct ofono_modem *modem)
ofono_modem_set_data(modem, NULL);
+ /* Cleanup potential SIM state polling */
+ at_util_sim_state_query_free(data->sim_state_query);
+
+ /* Cleanup after hot-unplug */
+ g_at_chat_unref(data->chat);
+
g_free(data);
}
@@ -115,6 +123,21 @@ static GAtChat *open_device(struct ofono_modem *modem,
return chat;
}
+static void sim_state_cb(gboolean present, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct sierra_data *data = ofono_modem_get_data(modem);
+
+ at_util_sim_state_query_free(data->sim_state_query);
+ data->sim_state_query = NULL;
+
+ data->have_sim = present;
+
+ ofono_modem_set_powered(modem, TRUE);
+
+ g_at_chat_send(data->chat, "AT&C0", NULL, NULL, NULL, NULL);
+}
+
static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
@@ -127,7 +150,8 @@ static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
data->chat = NULL;
}
- ofono_modem_set_powered(modem, ok);
+ data->sim_state_query = at_util_sim_state_query_new(data->chat,
+ 2, 20, sim_state_cb, modem);
}
static int sierra_enable(struct ofono_modem *modem)
--
1.7.1
9 years, 1 month
[PATCH 0/5] Provider name and SID
by Philippe Nunes
With this set of patches:
- cdma-providers.c is introducing an abstracted API to retrieve the provider
name from the SID.
This abstraction layer provides the ability to support multiple database for
the provider name lookup.
- As an example, the new plugin "providers" is based on the Mobile Broadband
Provider Info database.
- The lookup for the provider name is performed only if the system identifier
has changed.
Philippe Nunes (5):
cdma-providers: add driver APIs header
ofono.h: add cdma-providers
cdma-providers: add driver APIs implementation
providers: add cdma provider name plugin
cdma-netreg: Add provider name and SID support
Makefile.am | 4 +-
include/cdma-providers.h | 44 +++++++++++++++++++++++++
plugins/providers.c | 79 +++++++++++++++++++++++++++++++++++++++++++++
src/cdma-netreg.c | 40 +++++++++++++++++++++++
src/cdma-providers.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
src/ofono.h | 4 ++
6 files changed, 249 insertions(+), 2 deletions(-)
create mode 100644 include/cdma-providers.h
create mode 100644 plugins/providers.c
create mode 100644 src/cdma-providers.c
9 years, 1 month