From: Daniel Wagner <[email protected]>

This patch will be splittet into smaller patches later. This is work
in progress.
---

Hi,

just an update on this one. I am pretty happy with this version.
Though I have started to trigger some of the unusal execution
paths, such as killing ofonod and seeing what is going wrong.
I tend to say if ofonod dies or shutsdown gracefully we are facing 
lot's of race condition when trying to do something. Maybe the
best idea is just to ignore those cases and make the pending
callback functions rock solid.

cheers,
daniel

 plugins/ofono.c | 1638 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 1631 insertions(+), 7 deletions(-)

diff --git a/plugins/ofono.c b/plugins/ofono.c
index 7d979c4..245e26c 100644
--- a/plugins/ofono.c
+++ b/plugins/ofono.c
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
  *  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *  Copyright (C) 2011  BWM 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
@@ -34,11 +35,1508 @@
 #include <connman/plugin.h>
 #include <connman/device.h>
 #include <connman/network.h>
+#include <connman/technology.h>
+#include <connman/inet.h>
 #include <connman/dbus.h>
 #include <connman/log.h>
 
+#define OFONO_SERVICE                  "org.ofono"
+
+#define OFONO_MANAGER_INTERFACE                OFONO_SERVICE ".Manager"
+#define OFONO_MODEM_INTERFACE          OFONO_SERVICE ".Modem"
+#define OFONO_SIM_INTERFACE            OFONO_SERVICE ".SimManager"
+#define OFONO_NETREG_INTERFACE         OFONO_SERVICE ".NetworkRegistration"
+#define OFONO_CM_INTERFACE             OFONO_SERVICE ".ConnectionManager"
+#define OFONO_CONTEXT_INTERFACE                OFONO_SERVICE 
".ConnectionContext"
+
+#define MODEM_ADDED                    "ModemAdded"
+#define MODEM_REMOVED                  "ModemRemoved"
+#define PROPERTY_CHANGED               "PropertyChanged"
+#define CONTEXT_ADDED                  "ContextAdded"
+#define CONTEXT_REMOVED                        "ContextRemoved"
+
+#define GET_PROPERTIES                 "GetProperties"
+#define SET_PROPERTY                   "SetProperty"
+#define GET_MODEMS                     "GetModems"
+
+#define TIMEOUT 40000
+
+enum ofono_api {
+       OFONO_API_SIM =         0x1,
+       OFONO_API_NETREG =      0x2,
+       OFONO_API_CM =          0x4,
+};
+
 static DBusConnection *connection;
 
+static GHashTable *modem_hash;
+static GHashTable *context_hash;
+
+struct network_context {
+       char *path;
+       int index;
+       enum connman_ipconfig_method method;
+       struct connman_ipaddress *address;
+       char *nameservers;
+};
+
+struct modem_data {
+       char *path;
+
+       struct connman_device *device;
+       struct connman_network *network;
+
+       struct network_context *ipv4_context;
+
+       /* Modem Interface */
+       connman_bool_t powered;
+       connman_bool_t online;
+       uint8_t interfaces;
+
+       connman_bool_t set_powered;
+       connman_bool_t set_online;
+
+       /* ConnectionManager Interface */
+       connman_bool_t attached;
+
+       /* ConnectionContext Interface */
+       connman_bool_t active;
+
+       /* SimManager Interface */
+       char *imsi;
+
+       /* Netreg Interface */
+       char *name;
+       uint8_t strength;
+};
+
+static char *get_ident(const char *path)
+{
+       char *pos;
+
+       if (*path != '/')
+               return NULL;
+
+       pos = strrchr(path, '/');
+       if (pos == NULL)
+               return NULL;
+
+       return pos + 1;
+}
+
+static struct network_context *network_context_alloc(const char *path)
+{
+       struct network_context *context;
+
+       context = g_try_new0(struct network_context, 1);
+       if (context == NULL)
+               return NULL;
+
+       context->path = g_strdup(path);
+       context->index = -1;
+       context->method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
+       context->address = NULL;
+       context->nameservers = NULL;
+
+       return context;
+}
+
+static void network_context_free(struct network_context *context)
+{
+       g_free(context->path);
+       g_free(context->nameservers);
+       connman_ipaddress_free(context->address);
+
+       free(context);
+}
+
+static void set_connected(struct modem_data *modem)
+{
+       DBG("path %s", modem->path);
+
+       switch (modem->ipv4_context->method) {
+       case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+       case CONNMAN_IPCONFIG_METHOD_OFF:
+       case CONNMAN_IPCONFIG_METHOD_MANUAL:
+       case CONNMAN_IPCONFIG_METHOD_AUTO:
+               return;
+
+       case CONNMAN_IPCONFIG_METHOD_FIXED:
+               connman_network_set_ipv4_method(modem->network,
+                                               modem->ipv4_context->method);
+               connman_network_set_ipaddress(modem->network,
+                                               modem->ipv4_context->address);
+               connman_network_set_nameservers(modem->network,
+                                       modem->ipv4_context->nameservers);
+               break;
+
+       case CONNMAN_IPCONFIG_METHOD_DHCP:
+               connman_network_set_ipv4_method(modem->network,
+                                               modem->ipv4_context->method);
+               break;
+       }
+
+       connman_network_set_connected(modem->network, TRUE);
+}
+
+static void set_disconnected(struct modem_data *modem)
+{
+       DBG("path %s", modem->path);
+
+       connman_network_set_connected(modem->network, FALSE);
+}
+
+static int call_ofono(const char *path,
+                       const char *interface, const char *method,
+                       DBusPendingCallNotifyFunction notify, void *user_data,
+                       DBusFreeFunction free_function,
+                       int type, ...)
+{
+       DBusMessage *message;
+       DBusPendingCall *call;
+       dbus_bool_t ok;
+       va_list va;
+
+       DBG("path %s %s.%s()", path, interface, method);
+
+       message = dbus_message_new_method_call(OFONO_SERVICE, path,
+                                       interface, method);
+       if (message == NULL)
+               return -ENOMEM;
+
+       va_start(va, type);
+       ok = dbus_message_append_args_valist(message, type, va);
+       va_end(va);
+
+       if (ok == FALSE) {
+               dbus_message_unref(message);
+
+               return -ENOMEM;
+       }
+
+       if (dbus_connection_send_with_reply(connection, message,
+                                               &call, TIMEOUT) == FALSE) {
+               connman_error("Failed to call %s.%s()", interface, method);
+               dbus_message_unref(message);
+
+               return -EINVAL;
+       }
+
+       if (call == NULL) {
+               connman_error("D-Bus connection not available");
+               dbus_message_unref(message);
+
+               return -EINVAL;
+       }
+
+       dbus_pending_call_set_notify(call, notify, user_data, free_function);
+
+       dbus_message_unref(message);
+
+       return -EINPROGRESS;
+}
+
+static void set_property_reply(DBusPendingCall *call, void *user_data)
+{
+       char const *name = user_data;
+       DBusMessage *reply;
+       DBusError error;
+
+       DBG("SetProperty(%s)", name);
+
+       dbus_error_init(&error);
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       if (dbus_set_error_from_message(&error, reply)) {
+               connman_error("SetProperty(%s) %s %s", name,
+                               error.name, error.message);
+               dbus_error_free(&error);
+       }
+
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(call);
+}
+
+static int set_property(const char *path, const char *interface,
+                       const char *property, int type, void *value,
+                       DBusPendingCallNotifyFunction notify, void *user_data,
+                       DBusFreeFunction free_function)
+{
+       DBusMessage *message;
+       DBusMessageIter iter;
+       DBusPendingCall *call;
+
+       DBG("path %s %s.%s", path, interface, property);
+
+       message = dbus_message_new_method_call(OFONO_SERVICE, path,
+                                       interface, SET_PROPERTY);
+       if (message == NULL)
+               return -ENOMEM;
+
+       dbus_message_iter_init_append(message, &iter);
+       connman_dbus_property_append_basic(&iter, property, type, value);
+
+       if (dbus_connection_send_with_reply(connection, message,
+                                               &call, TIMEOUT) == FALSE) {
+               connman_error("Failed to change \"%s\" property on %s",
+                               property, interface);
+               dbus_message_unref(message);
+
+               return -EINVAL;
+       }
+
+       if (call == NULL) {
+               connman_error("D-Bus connection not available");
+               dbus_message_unref(message);
+
+               return -EINVAL;
+       }
+
+       if (notify == NULL) {
+               notify = set_property_reply;
+               user_data = (void *)property;
+               free_function = NULL;
+       }
+
+       dbus_pending_call_set_notify(call, notify, user_data, free_function);
+
+       dbus_message_unref(message);
+
+       return -EINPROGRESS;
+}
+
+static int get_properties(const char *path, const char *interface,
+                       DBusPendingCallNotifyFunction notify, void *user_data,
+                       DBusFreeFunction free_function)
+{
+       DBG("path %s %s.GetProperties()", path, interface);
+
+       return call_ofono(path, interface, GET_PROPERTIES,
+                       notify, user_data, NULL, DBUS_TYPE_INVALID);
+}
+
+static void context_set_active_reply(DBusPendingCall *call, void *user_data)
+{
+       struct modem_data *modem = user_data;
+       DBusMessage *reply;
+       DBusError error;
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       DBG("ipv4 context path %s", modem->ipv4_context->path);
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == TRUE) {
+               connman_error("SetProperty(Active) %s %s",
+                               error.name, error.message);
+
+               connman_network_set_error(modem->network,
+                                       CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
+
+               dbus_error_free(&error);
+       }
+
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(call);
+}
+
+static int context_set_active(struct modem_data *modem)
+{
+       dbus_bool_t active = TRUE;
+
+       DBG("path %s", modem->path);
+
+       return set_property(modem->ipv4_context->path, OFONO_CONTEXT_INTERFACE,
+                               "Active", DBUS_TYPE_BOOLEAN, &active,
+                               context_set_active_reply, modem, NULL);
+}
+
+static int context_set_inactive(struct modem_data *modem)
+{
+       dbus_bool_t active = FALSE;
+       int err;
+
+       DBG("path %s", modem->path);
+
+       err = set_property(modem->ipv4_context->path, OFONO_CONTEXT_INTERFACE,
+                               "Active", DBUS_TYPE_BOOLEAN, &active,
+                               NULL, NULL, NULL);
+       if (err == -EINPROGRESS)
+               return 0;
+
+       return err;
+}
+
+static int modem_set_online(struct modem_data *modem)
+{
+       dbus_bool_t online = TRUE;
+
+       DBG("path %s", modem->path);
+
+       modem->set_online = TRUE;
+
+       return set_property(modem->path, OFONO_MODEM_INTERFACE, "Online",
+                               DBUS_TYPE_BOOLEAN, &online,
+                               NULL, NULL, NULL);
+}
+
+static int modem_set_powered(struct modem_data *modem)
+{
+       dbus_bool_t powered = TRUE;
+
+       DBG("path %s", modem->path);
+
+       modem->set_powered = TRUE;
+
+       return set_property(modem->path, OFONO_MODEM_INTERFACE, "Powered",
+                               DBUS_TYPE_BOOLEAN, &powered,
+                               NULL, NULL, NULL);
+}
+
+static int modem_set_unpowered(struct modem_data *modem)
+{
+       dbus_bool_t powered = FALSE;
+
+       DBG("path %s", modem->path);
+
+       modem->set_powered = FALSE;
+
+       return set_property(modem->path, OFONO_MODEM_INTERFACE, "Powered",
+                               DBUS_TYPE_BOOLEAN, &powered,
+                               NULL, NULL, NULL);
+}
+
+static connman_bool_t has_interface(uint8_t interfaces,
+                                       enum ofono_api api)
+{
+       if ((interfaces & api) == api)
+               return TRUE;
+
+       return FALSE;
+}
+
+static uint8_t extract_interfaces(DBusMessageIter *array)
+{
+       DBusMessageIter entry;
+       uint8_t interfaces = 0;
+
+       dbus_message_iter_recurse(array, &entry);
+
+       while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+               const char *name;
+
+               dbus_message_iter_get_basic(&entry, &name);
+
+               if (g_str_equal(name, OFONO_SIM_INTERFACE) == TRUE)
+                       interfaces |= OFONO_API_SIM;
+               else if (g_str_equal(name, OFONO_NETREG_INTERFACE) == TRUE)
+                       interfaces |= OFONO_API_NETREG;
+               else if (g_str_equal(name, OFONO_CM_INTERFACE) == TRUE)
+                       interfaces |= OFONO_API_CM;
+
+               dbus_message_iter_next(&entry);
+       }
+
+       return interfaces;
+}
+
+static char *extract_nameservers(DBusMessageIter *array)
+{
+       DBusMessageIter entry;
+       char *nameservers = NULL;
+       char *tmp;
+
+       dbus_message_iter_recurse(array, &entry);
+
+       while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+               const char *nameserver;
+
+               dbus_message_iter_get_basic(&entry, &nameserver);
+
+               if (nameservers == NULL) {
+                       nameservers = g_strdup(nameserver);
+               } else {
+                       tmp = nameservers;
+                       nameservers = g_strdup_printf("%s %s", tmp, nameserver);
+                       g_free(tmp);
+               }
+
+               dbus_message_iter_next(&entry);
+       }
+
+       return nameservers;
+}
+
+static struct network_context *extract_settings(DBusMessageIter *array,
+                                               const char *context_path,
+                                               enum connman_ipconfig_type type)
+{
+       DBusMessageIter dict;
+       char *address = NULL, *netmask = NULL, *gateway = NULL;
+       char *nameservers = NULL;
+       const char *interface = NULL;
+       struct network_context *context = NULL;
+       int index;
+       enum connman_ipconfig_method method;
+       struct connman_ipaddress *ipaddr = NULL;
+
+       if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(array, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry, value;
+               const char *key, *val;
+
+               dbus_message_iter_recurse(&dict, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (g_str_equal(key, "Interface") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &interface);
+
+                       DBG("Interface %s", interface);
+
+                       index = connman_inet_ifindex(interface);
+
+                       DBG("index %d", index);
+               } else if (g_str_equal(key, "Method") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &val);
+
+                       DBG("Method %s", val);
+
+                       if (g_strcmp0(val, "static") == 0) {
+                               method = CONNMAN_IPCONFIG_METHOD_FIXED;
+                       } else if (g_strcmp0(val, "dhcp") == 0) {
+                               method = CONNMAN_IPCONFIG_METHOD_DHCP;
+                               break;
+                       }
+               } else if (g_str_equal(key, "Address") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &val);
+
+                       address = g_strdup(val);
+
+                       DBG("Address %s", address);
+               } else if (g_str_equal(key, "Netmask") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &val);
+
+                       netmask = g_strdup(val);
+
+                       DBG("Netmask %s", netmask);
+               } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
+                       nameservers = extract_nameservers(&value);
+
+                       DBG("Nameservers %s", nameservers);
+               } else if (g_str_equal(key, "Gateway") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &val);
+
+                       gateway = g_strdup(val);
+
+                       DBG("Gateway %s", gateway);
+               }
+
+               /* Add IPv6 parsing part */
+
+               dbus_message_iter_next(&dict);
+       }
+
+       context = network_context_alloc(context_path);
+       if (context == NULL)
+               goto out;
+
+       if (method == CONNMAN_IPCONFIG_METHOD_FIXED) {
+               ipaddr = connman_ipaddress_alloc(type);
+               if (ipaddr == NULL) {
+                       network_context_free(context);
+                       context = NULL;
+                       goto out;
+               }
+
+               if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+                       connman_ipaddress_set_ipv4(ipaddr, address,
+                                                       netmask, gateway);
+               }
+
+               context->nameservers = nameservers;
+       }
+
+       context->address = ipaddr;
+       context->method = method;
+       context->index = index;
+
+out:
+       if (context == NULL || context->nameservers != nameservers)
+               g_free(nameservers);
+
+       g_free(address);
+       g_free(netmask);
+       g_free(gateway);
+
+       return context;
+}
+
+static void create_device(struct modem_data *modem)
+{
+       struct connman_device *device;
+       char *ident;
+
+       DBG("path %s", modem->path);
+
+       if (modem->device != NULL) {
+               DBG("Modem is already registered at core, bug?");
+               return;
+       }
+
+       if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE)
+               ident = modem->imsi;
+       else
+               ident = "unknown"; /* CDMA ? */
+
+       device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_CELLULAR);
+       if (device == NULL)
+               return;
+
+       DBG("device %p", device);
+
+       connman_device_set_ident(device, ident);
+
+       connman_device_set_string(device, "Path", modem->path);
+
+       connman_device_set_data(device, modem);
+
+       if (connman_device_register(device) < 0) {
+               connman_error("Failed to register cellular device");
+               connman_device_unref(device);
+
+               return;
+       }
+
+       modem->device = device;
+}
+
+static void add_network(struct modem_data *modem)
+{
+       const char *group;
+
+       DBG("path %s", modem->path);
+
+       if (modem->network != NULL)
+               return;
+
+       modem->network = connman_network_create(modem->ipv4_context->path,
+                                               CONNMAN_NETWORK_TYPE_CELLULAR);
+       if (modem->network == NULL)
+               return;
+
+       connman_network_set_data(modem->network, modem);
+
+       connman_network_set_string(modem->network, "Path",
+                                       modem->ipv4_context->path);
+
+       connman_network_set_index(modem->network, modem->ipv4_context->index);
+
+       if (modem->name != NULL)
+               connman_network_set_name(modem->network, modem->name);
+       else
+               connman_network_set_name(modem->network, "");
+
+       connman_network_set_strength(modem->network, modem->strength);
+
+       group = get_ident(modem->ipv4_context->path);
+       connman_network_set_group(modem->network, group);
+
+       connman_network_set_available(modem->network, TRUE);
+
+       if (connman_device_add_network(modem->device, modem->network) < 0) {
+               connman_network_unref(modem->network);
+               modem->network = NULL;
+
+               return;
+       }
+}
+
+static int add_cm_context(struct modem_data *modem, const char *context_path,
+                               DBusMessageIter *dict)
+{
+       const char *context_type;
+       struct network_context *ipv4_context = NULL;
+       connman_bool_t active = FALSE;
+
+       DBG("path %s context path %s", modem->path, context_path);
+
+       while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry, value;
+               const char *key;
+
+               dbus_message_iter_recurse(dict, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               DBG("key %s", key);
+
+               if (g_str_equal(key, "Type") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &context_type);
+
+                       DBG("path %s context %s type %s", modem->path,
+                               context_path, context_type);
+               } else if (g_str_equal(key, "Settings") == TRUE) {
+                       ipv4_context = extract_settings(&value, context_path,
+                                               CONNMAN_IPCONFIG_TYPE_IPV4);
+               } else if (g_str_equal(key, "Active") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &active);
+
+                       DBG("path %s Active %d", modem->path, active);
+               }
+
+               dbus_message_iter_next(dict);
+       }
+
+       if (ipv4_context == NULL)
+               return -EINVAL;
+
+       if (g_strcmp0(context_type, "internet") != 0) {
+               network_context_free(ipv4_context);
+               return -EINVAL;
+       }
+
+       if (modem->ipv4_context != NULL) {
+               /*
+                * We have already assigned a context to this modem
+                * and we do only support one Internet context.
+                */
+               network_context_free(ipv4_context);
+               return -EALREADY;
+       }
+
+       modem->ipv4_context = ipv4_context;
+       modem->active = active;
+
+       g_hash_table_replace(context_hash, g_strdup(context_path), modem);
+
+       return 0;
+}
+
+static void remove_cm_context(struct modem_data *modem, const char 
*context_path)
+{
+       if (modem->ipv4_context == NULL)
+               return;
+
+       network_context_free(modem->ipv4_context);
+       modem->ipv4_context = NULL;
+
+       g_hash_table_remove(context_hash, context_path);
+}
+
+static gboolean context_changed(DBusConnection *connection,
+                               DBusMessage *message,
+                               void *user_data)
+{
+       const char *context_path = dbus_message_get_path(message);
+       struct modem_data *modem = NULL;
+       DBusMessageIter iter, value;
+       const char *key;
+
+       DBG("context_path %s", context_path);
+
+       modem = g_hash_table_lookup(context_hash, context_path);
+       if (modem == NULL)
+               return TRUE;
+
+       if (dbus_message_iter_init(message, &iter) == FALSE)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &key);
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_recurse(&iter, &value);
+
+       /*
+        * oFono guarantees the ordering of Settings and
+        * Active. Settings will always be send before Active = True.
+        * That means we don't have to order here anything.
+        */
+       if (g_str_equal(key, "Settings") == TRUE) {
+               struct network_context *ipv4_context;
+
+               DBG("path %s Settings", modem->path);
+
+               ipv4_context = extract_settings(&value, context_path,
+                                               CONNMAN_IPCONFIG_TYPE_IPV4);
+
+               if (ipv4_context == NULL)
+                       return TRUE;
+
+               if (modem->ipv4_context != NULL)
+                       network_context_free(modem->ipv4_context);
+
+               modem->ipv4_context = ipv4_context;
+       } else if (g_str_equal(key, "Active") == TRUE) {
+               dbus_message_iter_get_basic(&value, &modem->active);
+
+               DBG("path %s Active %d", modem->path, modem->active);
+
+               if (modem->active == TRUE)
+                       set_connected(modem);
+               else
+                       set_disconnected(modem);
+       }
+
+       return TRUE;
+}
+
+static void cm_get_contexts_reply(DBusPendingCall *call, void *user_data)
+{
+       struct modem_data *modem = user_data;
+       DBusMessageIter array, dict, entry, value;
+       DBusMessage *reply;
+       DBusError error;
+
+       DBG("path %s", modem->path);
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
+               goto done;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == TRUE) {
+               connman_error("%s", error.message);
+               dbus_error_free(&error);
+               goto done;
+       }
+
+       if (dbus_message_iter_init(reply, &array) == FALSE)
+               goto done;
+
+       if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+               goto done;
+
+       dbus_message_iter_recurse(&array, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
+               const char *context_path;
+
+               dbus_message_iter_recurse(&dict, &entry);
+               dbus_message_iter_get_basic(&entry, &context_path);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (add_cm_context(modem, context_path, &value) == 0)
+                       break;
+
+               dbus_message_iter_next(&dict);
+       }
+
+done:
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(call);
+}
+
+static void cm_get_contexts(struct modem_data *modem)
+{
+       call_ofono(modem->path, OFONO_CM_INTERFACE, "GetContexts",
+                       cm_get_contexts_reply, modem,
+                       NULL, DBUS_TYPE_INVALID);
+}
+
+static gboolean cm_context_added(DBusConnection *connection,
+                                       DBusMessage *message,
+                                       void *user_data)
+{
+       const char *path = dbus_message_get_path(message);
+       char *context_path;
+       struct modem_data *modem;
+       DBusMessageIter iter, properties;
+
+       DBG("path %s", path);
+
+       modem = g_hash_table_lookup(modem_hash, context_path);
+       if (modem == NULL)
+               return TRUE;
+
+       if (dbus_message_iter_init(message, &iter) == FALSE)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &context_path);
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_recurse(&iter, &properties);
+
+       if (add_cm_context(modem, context_path, &properties) != 0)
+               return TRUE;
+
+       return TRUE;
+}
+
+static gboolean cm_context_removed(DBusConnection *connection,
+                                       DBusMessage *message,
+                                       void *user_data)
+{
+       const char *path = dbus_message_get_path(message);
+       const char *context_path;
+       struct modem_data *modem;
+       DBusMessageIter iter;
+
+       DBG("context path %s", path);
+
+       if (dbus_message_iter_init(message, &iter) == FALSE)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &context_path);
+
+       modem = g_hash_table_lookup(context_hash, context_path);
+       if (modem == NULL)
+               return TRUE;
+
+       remove_cm_context(modem, context_path);
+
+       return TRUE;
+}
+
+static gboolean netreg_changed(DBusConnection *connection, DBusMessage 
*message,
+                               void *user_data)
+{
+       const char *path = dbus_message_get_path(message);
+       struct modem_data *modem;
+       DBusMessageIter iter, value;
+       const char *key;
+
+       modem = g_hash_table_lookup(modem_hash, path);
+       if (modem == NULL)
+               return TRUE;
+
+       if (dbus_message_iter_init(message, &iter) == FALSE)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &key);
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_recurse(&iter, &value);
+
+       if (g_str_equal(key, "Name") == TRUE) {
+               char *name;
+
+               dbus_message_iter_get_basic(&value, &name);
+
+               DBG("path %s Name %s", modem->path, name);
+
+               g_free(modem->name);
+               modem->name = g_strdup(name);
+
+               if (modem->network == NULL)
+                       return TRUE;
+
+               connman_network_set_name(modem->network, modem->name);
+               connman_network_update(modem->network);
+       } else if (g_str_equal(key, "Strength") == TRUE) {
+               dbus_message_iter_get_basic(&value, &modem->strength);
+
+               DBG("path %s Strength %d", modem->path, modem->strength);
+
+               if (modem->network == NULL)
+                       return TRUE;
+
+               connman_network_set_strength(modem->network, modem->strength);
+               connman_network_update(modem->network);
+       }
+
+       return TRUE;
+}
+
+static void netreg_properties_reply(DBusPendingCall *call, void *user_data)
+{
+       struct modem_data *modem = user_data;
+       DBusMessageIter array, dict;
+       DBusMessage *reply;
+       DBusError error;
+
+       DBG("");
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == TRUE) {
+               connman_error("%s", error.message);
+               dbus_error_free(&error);
+               goto done;
+       }
+
+       if (dbus_message_iter_init(reply, &array) == FALSE)
+               goto done;
+
+       if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+               goto done;
+
+       dbus_message_iter_recurse(&array, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry, value;
+               const char *key;
+
+               dbus_message_iter_recurse(&dict, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (g_str_equal(key, "Name") == TRUE) {
+                       char *name;
+
+                       dbus_message_iter_get_basic(&value, &name);
+
+                       DBG("path %s Name %s", modem->path, name);
+
+                       g_free(modem->name);
+                       modem->name = g_strdup(name);
+
+                       if (modem->network != NULL) {
+                               connman_network_set_name(modem->network,
+                                                               modem->name);
+                               connman_network_update(modem->network);
+                       }
+               } else if (g_str_equal(key, "Strength") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &modem->strength);
+
+                       DBG("path %s Strength %d", modem->path,
+                               modem->strength);
+
+                       if (modem->network != NULL) {
+                               connman_network_set_strength(modem->network,
+                                                       modem->strength);
+                               connman_network_update(modem->network);
+                       }
+               }
+
+               dbus_message_iter_next(&dict);
+       }
+
+       add_network(modem);
+
+       if (modem->active == TRUE)
+               set_connected(modem);
+
+done:
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(call);
+}
+
+static void netreg_get_properties(struct modem_data *modem)
+{
+       get_properties(modem->path, OFONO_NETREG_INTERFACE,
+                       netreg_properties_reply,
+                       modem, NULL);
+}
+
+static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
+                               void *user_data)
+{
+       const char *path = dbus_message_get_path(message);
+       struct modem_data *modem;
+       DBusMessageIter iter, value;
+       const char *key;
+
+       modem = g_hash_table_lookup(modem_hash, path);
+       if (modem == NULL)
+               return TRUE;
+
+       if (dbus_message_iter_init(message, &iter) == FALSE)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &key);
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_recurse(&iter, &value);
+
+       if (g_str_equal(key, "Attached") == TRUE) {
+               dbus_message_iter_get_basic(&value, &modem->attached);
+
+               DBG("path %s Attached %d", modem->path, modem->attached);
+
+               if (modem->attached == TRUE && modem->set_online == TRUE)
+                       netreg_get_properties(modem);
+       }
+
+       return TRUE;
+}
+
+static void cm_properties_reply(DBusPendingCall *call, void *user_data)
+{
+       struct modem_data *modem = user_data;
+       DBusMessageIter array, dict;
+       DBusMessage *reply;
+       DBusError error;
+
+       DBG("path %s", modem->path);
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == TRUE) {
+               connman_error("%s", error.message);
+               dbus_error_free(&error);
+               goto done;
+       }
+
+       if (dbus_message_iter_init(reply, &array) == FALSE)
+               goto done;
+
+       if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+               goto done;
+
+       dbus_message_iter_recurse(&array, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry, value;
+               const char *key;
+
+               dbus_message_iter_recurse(&dict, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (g_str_equal(key, "Attached") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &modem->attached);
+
+                       DBG("path %s Attached %d", modem->path,
+                               modem->attached);
+
+                       if (modem->attached == TRUE &&
+                                       modem->set_online == FALSE) {
+                               netreg_get_properties(modem);
+                       }
+
+                       break;
+               }
+
+               dbus_message_iter_next(&dict);
+       }
+
+done:
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(call);
+}
+
+static void cm_get_properties(struct modem_data *modem)
+{
+       get_properties(modem->path, OFONO_CM_INTERFACE,
+                       cm_properties_reply,
+                       modem, NULL);
+}
+
+static void update_sim_imsi(struct modem_data *modem,
+                               const char *imsi)
+{
+       DBG("path %s imsi %s", modem->path, imsi);
+
+       if (g_strcmp0(modem->imsi, imsi) == 0)
+               return;
+
+       g_free(modem->imsi);
+       modem->imsi = g_strdup(imsi);
+}
+
+static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
+                               void *user_data)
+{
+       const char *path = dbus_message_get_path(message);
+       struct modem_data *modem;
+       DBusMessageIter iter, value;
+       const char *key;
+
+       modem = g_hash_table_lookup(modem_hash, path);
+       if (modem == NULL)
+               return TRUE;
+
+       if (dbus_message_iter_init(message, &iter) == FALSE)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &key);
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_recurse(&iter, &value);
+
+       if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
+               char *imsi;
+
+               dbus_message_iter_get_basic(&value, &imsi);
+
+               update_sim_imsi(modem, imsi);
+
+               if (modem->online == FALSE) {
+                       modem_set_online(modem);
+               } else if (modem->device == NULL)
+                       create_device(modem);
+       }
+
+       return TRUE;
+}
+
+static void sim_properties_reply(DBusPendingCall *call, void *user_data)
+{
+       struct modem_data *modem = user_data;
+       DBusMessageIter array, dict;
+       DBusMessage *reply;
+       DBusError error;
+
+       DBG("");
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == TRUE) {
+               connman_error("%s", error.message);
+               dbus_error_free(&error);
+               goto done;
+       }
+
+       if (dbus_message_iter_init(reply, &array) == FALSE)
+               goto done;
+
+       if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+               goto done;
+
+       dbus_message_iter_recurse(&array, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry, value;
+               const char *key;
+
+               dbus_message_iter_recurse(&dict, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
+                       char *imsi;
+
+                       dbus_message_iter_get_basic(&value, &imsi);
+
+                       update_sim_imsi(modem, imsi);
+
+                       if (modem->online == FALSE) {
+                               modem_set_online(modem);
+                               break;
+                       }
+
+                       if (modem->device == NULL)
+                               create_device(modem);
+
+                       if (has_interface(modem->interfaces,
+                                               OFONO_API_CM) == TRUE) {
+                               cm_get_properties(modem);
+                               cm_get_contexts(modem);
+                       }
+
+                       break;
+               }
+
+               dbus_message_iter_next(&dict);
+       }
+
+done:
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(call);
+}
+
+static void sim_get_properties(struct modem_data *modem)
+{
+       get_properties(modem->path, OFONO_SIM_INTERFACE,
+                       sim_properties_reply,
+                       modem, NULL);
+}
+
+static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
+                               void *user_data)
+{
+       const char *path = dbus_message_get_path(message);
+       struct modem_data *modem;
+       DBusMessageIter iter, value;
+       const char *key;
+
+       modem = g_hash_table_lookup(modem_hash, path);
+       if (modem == NULL)
+               return TRUE;
+
+       if (dbus_message_iter_init(message, &iter) == FALSE)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &key);
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_recurse(&iter, &value);
+
+       if (g_str_equal(key, "Powered") == TRUE) {
+               dbus_message_iter_get_basic(&value, &modem->powered);
+
+               DBG("path %s Powered %d", modem->path, modem->powered);
+
+               if (modem->powered == FALSE)
+                       modem_set_powered(modem);
+       } else if (g_str_equal(key, "Online") == TRUE) {
+               dbus_message_iter_get_basic(&value, &modem->online);
+
+               DBG("path %s Online %d", modem->path, modem->online);
+
+               if (modem->online == TRUE &&
+                               has_interface(modem->interfaces,
+                                               OFONO_API_CM) == TRUE) {
+                       cm_get_properties(modem);
+                       cm_get_contexts(modem);
+               }
+       } else if (g_str_equal(key, "Interfaces") == TRUE) {
+               modem->interfaces = extract_interfaces(&value);
+
+               DBG("path %s Interfaces 0x%02x", modem->path,
+                       modem->interfaces);
+
+               if (modem->imsi == NULL &&
+                               has_interface(modem->interfaces,
+                                               OFONO_API_SIM) == TRUE &&
+                               modem->set_powered == FALSE) {
+                       sim_get_properties(modem);
+                       return TRUE;
+               }
+
+               if (modem->device == NULL &&
+                               has_interface(modem->interfaces,
+                                               OFONO_API_CM) == TRUE) {
+                       create_device(modem);
+                       cm_get_properties(modem);
+                       cm_get_contexts(modem);
+               }
+       }
+
+       return TRUE;
+}
+
+static void add_modem(const char *path, DBusMessageIter *prop)
+{
+       struct modem_data *modem;
+
+       DBG("%s", path);
+
+       modem = g_hash_table_lookup(modem_hash, path);
+       if (modem != NULL)
+               return;
+
+       modem = g_try_new0(struct modem_data, 1);
+       if (modem == NULL)
+               return;
+
+       modem->path = g_strdup(path);
+
+       g_hash_table_insert(modem_hash, g_strdup(path), modem);
+
+       while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry, value;
+               const char *key;
+
+               dbus_message_iter_recurse(prop, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (g_str_equal(key, "Powered") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &modem->powered);
+
+                       DBG("path %s Powered %d", modem->path, modem->powered);
+               } else if (g_str_equal(key, "Online") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &modem->online);
+
+                       DBG("path %s Online %d", modem->path, modem->online);
+               } else if (g_str_equal(key, "Interfaces") == TRUE) {
+                       modem->interfaces = extract_interfaces(&value);
+
+                       DBG("path %s Interfaces 0x%02x", modem->path,
+                               modem->interfaces);
+
+               }
+
+               dbus_message_iter_next(prop);
+       }
+
+       if (modem->powered == FALSE)
+               modem_set_powered(modem);
+       else if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE)
+               sim_get_properties(modem);
+}
+
+static void remove_modem(gpointer data)
+{
+       struct modem_data *modem = data;
+
+       if (modem->powered == TRUE)
+               modem_set_unpowered(modem);
+
+       if (modem->network != NULL) {
+               connman_network_set_connected(modem->network, FALSE);
+               connman_network_set_available(modem->network, FALSE);
+       }
+
+       if (modem->device != NULL) {
+               if (modem->network != NULL)
+                       connman_device_remove_network(modem->device, 
modem->network);
+
+               connman_device_unregister(modem->device);
+               connman_device_unref(modem->device);
+       }
+
+       network_context_free(modem->ipv4_context);
+
+       g_free(modem->name);
+       g_free(modem->imsi);
+       g_free(modem->path);
+
+       g_free(modem);
+}
+
+static gboolean modem_added(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       DBusMessageIter iter, properties;
+       const char *path;
+
+       DBG("");
+
+       if (dbus_message_iter_init(message, &iter) == FALSE)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &path);
+
+       dbus_message_iter_next(&iter);
+       dbus_message_iter_recurse(&iter, &properties);
+
+       add_modem(path, &properties);
+
+       return TRUE;
+}
+
+static gboolean modem_removed(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       DBusMessageIter iter;
+       const char *path;
+
+       DBG("");
+
+       if (dbus_message_iter_init(message, &iter) == FALSE)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &path);
+
+       g_hash_table_remove(modem_hash, path);
+
+       return TRUE;
+}
+
+static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
+{
+       DBusMessage *reply;
+       DBusError error;
+       DBusMessageIter array, dict;
+
+       DBG("");
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == TRUE) {
+               connman_error("%s", error.message);
+               dbus_error_free(&error);
+               goto done;
+       }
+
+       if (dbus_message_iter_init(reply, &array) == FALSE)
+               goto done;
+
+       dbus_message_iter_recurse(&array, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
+               DBusMessageIter value, properties;
+               const char *path;
+
+               dbus_message_iter_recurse(&dict, &value);
+               dbus_message_iter_get_basic(&value, &path);
+
+               dbus_message_iter_next(&value);
+               dbus_message_iter_recurse(&value, &properties);
+
+               add_modem(path, &properties);
+
+               dbus_message_iter_next(&dict);
+       }
+
+done:
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(call);
+}
+
+static void manager_get_modems(void)
+{
+       DBG("");
+
+       call_ofono("/", OFONO_MANAGER_INTERFACE, GET_MODEMS,
+                       manager_get_modems_reply, NULL, NULL,
+                       DBUS_TYPE_INVALID);
+}
+
+static void ofono_connect(DBusConnection *conn, void *user_data)
+{
+       DBG("");
+
+       modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                               g_free, remove_modem);
+       if (modem_hash == NULL)
+               return;
+
+       context_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                               g_free, NULL);
+       if (context_hash == NULL) {
+               g_hash_table_destroy(modem_hash);
+               return;
+       }
+
+       manager_get_modems();
+}
+
+static void ofono_disconnect(DBusConnection *conn, void *user_data)
+{
+       DBG("");
+
+       if (modem_hash == NULL || context_hash == NULL)
+               return;
+
+       g_hash_table_destroy(modem_hash);
+       modem_hash = NULL;
+
+       g_hash_table_destroy(context_hash);
+       context_hash = NULL;
+}
+
+
 static int network_probe(struct connman_network *network)
 {
        DBG("network %p", network);
@@ -53,16 +1551,20 @@ static void network_remove(struct connman_network 
*network)
 
 static int network_connect(struct connman_network *network)
 {
-       DBG("network %p", network);
+       struct modem_data *modem = connman_network_get_data(network);
 
-       return 0;
+       DBG("path %s network %p", modem->path, network);
+
+       return context_set_active(modem);
 }
 
 static int network_disconnect(struct connman_network *network)
 {
+       struct modem_data *modem = connman_network_get_data(network);
+
        DBG("network %p", network);
 
-       return 0;
+       return context_set_inactive(modem);
 }
 
 static struct connman_network_driver network_driver = {
@@ -76,26 +1578,43 @@ static struct connman_network_driver network_driver = {
 
 static int modem_probe(struct connman_device *device)
 {
-       DBG("device %p", device);
+       struct modem_data *modem = connman_device_get_data(device);
+
+       DBG("path %s device %p", modem->path, device);
 
        return 0;
 }
 
 static void modem_remove(struct connman_device *device)
 {
-       DBG("device %p", device);
+       struct modem_data *modem = connman_device_get_data(device);
+
+       DBG("path %s device %p", modem->path, device);
 }
 
+/*
+ * Enabling and disabling modems are steered through the rfkill
+ * interface. That means when ConnMan toggles the rfkill bit oFono
+ * will add or remove the modems.
+ *
+ * ConnMan will always power up (set Powered and Online) the
+ * modems. No need to power them down because this will be done
+ * through the rfkill inteface.
+ */
 static int modem_enable(struct connman_device *device)
 {
-       DBG("device %p", device);
+       struct modem_data *modem = connman_device_get_data(device);
+
+       DBG("path %s device %p", modem->path, device);
 
        return 0;
 }
 
 static int modem_disable(struct connman_device *device)
 {
-       DBG("device %p", device);
+       struct modem_data *modem = connman_device_get_data(device);
+
+       DBG("path %s device %p", modem->path, device);
 
        return 0;
 }
@@ -109,6 +1628,17 @@ static struct connman_device_driver modem_driver = {
        .disable        = modem_disable,
 };
 
+static guint watch;
+static guint modem_added_watch;
+static guint modem_removed_watch;
+static guint modem_watch;
+static guint cm_watch;
+static guint sim_watch;
+static guint context_added_watch;
+static guint context_removed_watch;
+static guint netreg_watch;
+static guint context_watch;
+
 static int ofono_init(void)
 {
        int err;
@@ -119,6 +1649,74 @@ static int ofono_init(void)
        if (connection == NULL)
                return -EIO;
 
+       watch = g_dbus_add_service_watch(connection,
+                                       OFONO_SERVICE, ofono_connect,
+                                       ofono_disconnect, NULL, NULL);
+
+       modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+                                               OFONO_MANAGER_INTERFACE,
+                                               MODEM_ADDED,
+                                               modem_added,
+                                               NULL, NULL);
+
+       modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+                                               OFONO_MANAGER_INTERFACE,
+                                               MODEM_REMOVED,
+                                               modem_removed,
+                                               NULL, NULL);
+
+       modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+                                               OFONO_MODEM_INTERFACE,
+                                               PROPERTY_CHANGED,
+                                               modem_changed,
+                                               NULL, NULL);
+
+       cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+                                               OFONO_CM_INTERFACE,
+                                               PROPERTY_CHANGED,
+                                               cm_changed,
+                                               NULL, NULL);
+
+       sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+                                               OFONO_SIM_INTERFACE,
+                                               PROPERTY_CHANGED,
+                                               sim_changed,
+                                               NULL, NULL);
+
+       context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+                                               OFONO_CM_INTERFACE,
+                                               CONTEXT_ADDED,
+                                               cm_context_added,
+                                               NULL, NULL);
+
+       context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+                                               OFONO_CM_INTERFACE,
+                                               CONTEXT_REMOVED,
+                                               cm_context_removed,
+                                               NULL, NULL);
+
+       context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+                                               OFONO_CONTEXT_INTERFACE,
+                                               PROPERTY_CHANGED,
+                                               context_changed,
+                                               NULL, NULL);
+
+       netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+                                               OFONO_NETREG_INTERFACE,
+                                               PROPERTY_CHANGED,
+                                               netreg_changed,
+                                               NULL, NULL);
+
+
+       if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
+                       modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
+                       context_added_watch == 0 ||
+                       context_removed_watch == 0 ||
+                       context_watch == 0 || netreg_watch == 0) {
+               err = -EIO;
+               goto remove;
+       }
+
        err = connman_network_driver_register(&network_driver);
        if (err < 0)
                goto remove;
@@ -132,6 +1730,16 @@ static int ofono_init(void)
        return 0;
 
 remove:
+       g_dbus_remove_watch(connection, netreg_watch);
+       g_dbus_remove_watch(connection, context_watch);
+       g_dbus_remove_watch(connection, context_removed_watch);
+       g_dbus_remove_watch(connection, context_added_watch);
+       g_dbus_remove_watch(connection, sim_watch);
+       g_dbus_remove_watch(connection, cm_watch);
+       g_dbus_remove_watch(connection, modem_watch);
+       g_dbus_remove_watch(connection, modem_removed_watch);
+       g_dbus_remove_watch(connection, modem_added_watch);
+       g_dbus_remove_watch(connection, watch);
        dbus_connection_unref(connection);
 
        return err;
@@ -141,9 +1749,25 @@ static void ofono_exit(void)
 {
        DBG("");
 
+       if (modem_hash != NULL) {
+               g_hash_table_destroy(modem_hash);
+               modem_hash = NULL;
+       }
+
        connman_device_driver_unregister(&modem_driver);
        connman_network_driver_unregister(&network_driver);
 
+       g_dbus_remove_watch(connection, netreg_watch);
+       g_dbus_remove_watch(connection, context_watch);
+       g_dbus_remove_watch(connection, context_removed_watch);
+       g_dbus_remove_watch(connection, context_added_watch);
+       g_dbus_remove_watch(connection, sim_watch);
+       g_dbus_remove_watch(connection, cm_watch);
+       g_dbus_remove_watch(connection, modem_watch);
+       g_dbus_remove_watch(connection, modem_added_watch);
+       g_dbus_remove_watch(connection, modem_removed_watch);
+       g_dbus_remove_watch(connection, watch);
+
        dbus_connection_unref(connection);
 }
 
-- 
1.7.8.rc1.14.g248db

_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman

Reply via email to