X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=plugins%2Fofono.c;h=36873d5a0c82551d97c29ae2f341e07f197d42e3;hb=c647a4b6f1132684c9d8b8ad71ec38d81147b278;hp=5cd83029908c7ee0d3d96dfdd31c79f7e5d4ed52;hpb=6aa4055ef0544ae85457c25c510fe3db04949c43;p=platform%2Fupstream%2Fconnman.git diff --git a/plugins/ofono.c b/plugins/ofono.c index 5cd8302..36873d5 100755 --- a/plugins/ofono.c +++ b/plugins/ofono.c @@ -133,6 +133,7 @@ static GHashTable *context_hash; struct network_context { char *path; int index; + struct connman_network *network; enum connman_ipconfig_method ipv4_method; struct connman_ipaddress *ipv4_address; @@ -141,15 +142,19 @@ struct network_context { enum connman_ipconfig_method ipv6_method; struct connman_ipaddress *ipv6_address; char *ipv6_nameservers; + + int refcount; + + bool active; + bool valid_apn; /* APN is 'valid' if length > 0 */ }; struct modem_data { char *path; struct connman_device *device; - struct connman_network *network; - struct network_context *context; + GSList *context_list; /* Modem Interface */ char *serial; @@ -167,10 +172,6 @@ struct modem_data { bool attached; bool cm_powered; - /* ConnectionContext Interface */ - bool active; - bool valid_apn; /* APN is 'valid' if length > 0 */ - /* SimManager Interface */ char *imsi; @@ -219,6 +220,40 @@ static char *get_ident(const char *path) return pos + 1; } +static struct network_context *get_context_with_path(GSList *context_list, + const gchar *path) +{ + GSList *list; + + DBG("path %s", path); + + for (list = context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (g_strcmp0(context->path, path) == 0) + return context; + } + + return NULL; +} + +static struct network_context *get_context_with_network(GSList *context_list, + const struct connman_network *network) +{ + GSList *list; + + DBG("network %p", network); + + for (list = context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network == network) + return context; + } + + return NULL; +} + static struct network_context *network_context_alloc(const char *path) { struct network_context *context; @@ -238,11 +273,25 @@ static struct network_context *network_context_alloc(const char *path) context->ipv6_address = NULL; context->ipv6_nameservers = NULL; + context->refcount = 1; + return context; } -static void network_context_free(struct network_context *context) +static void network_context_ref(struct network_context *context) +{ + DBG("%p ref %d", context, context->refcount + 1); + + __sync_fetch_and_add(&context->refcount, 1); +} + +static void network_context_unref(struct network_context *context) { + DBG("%p ref %d", context, context->refcount - 1); + + if (__sync_fetch_and_sub(&context->refcount, 1) != 1) + return; + g_free(context->path); connman_ipaddress_free(context->ipv4_address); @@ -251,10 +300,11 @@ static void network_context_free(struct network_context *context) connman_ipaddress_free(context->ipv6_address); g_free(context->ipv6_nameservers); - free(context); + g_free(context); } -static void set_connected(struct modem_data *modem) +static void set_connected(struct modem_data *modem, + struct network_context *context) { struct connman_service *service; bool setip = false; @@ -264,21 +314,21 @@ static void set_connected(struct modem_data *modem) DBG("%s", modem->path); - index = modem->context->index; + index = context->index; - method = modem->context->ipv4_method; - if (index < 0 || (!modem->context->ipv4_address && + method = context->ipv4_method; + if (index < 0 || (!context->ipv4_address && method == CONNMAN_IPCONFIG_METHOD_FIXED)) { connman_error("Invalid index and/or address"); return; } - service = connman_service_lookup_from_network(modem->network); + service = connman_service_lookup_from_network(context->network); if (!service) return; connman_service_create_ip4config(service, index); - connman_network_set_ipv4_method(modem->network, method); + connman_network_set_ipv4_method(context->network, method); if (method == CONNMAN_IPCONFIG_METHOD_FIXED || method == CONNMAN_IPCONFIG_METHOD_DHCP) { @@ -286,69 +336,68 @@ static void set_connected(struct modem_data *modem) } if (method == CONNMAN_IPCONFIG_METHOD_FIXED) { - connman_network_set_ipaddress(modem->network, - modem->context->ipv4_address); + connman_network_set_ipaddress(context->network, + context->ipv4_address); } - method = modem->context->ipv6_method; + method = context->ipv6_method; connman_service_create_ip6config(service, index); - connman_network_set_ipv6_method(modem->network, method); + connman_network_set_ipv6_method(context->network, method); if (method == CONNMAN_IPCONFIG_METHOD_AUTO) { setip = true; } /* Set the nameservers */ - if (modem->context->ipv4_nameservers && - modem->context->ipv6_nameservers) { + if (context->ipv4_nameservers && + context->ipv6_nameservers) { nameservers = g_strdup_printf("%s %s", - modem->context->ipv4_nameservers, - modem->context->ipv6_nameservers); - connman_network_set_nameservers(modem->network, nameservers); + context->ipv4_nameservers, + context->ipv6_nameservers); + connman_network_set_nameservers(context->network, nameservers); g_free(nameservers); - } else if (modem->context->ipv4_nameservers) { - connman_network_set_nameservers(modem->network, - modem->context->ipv4_nameservers); - } else if (modem->context->ipv6_nameservers) { - connman_network_set_nameservers(modem->network, - modem->context->ipv6_nameservers); + } else if (context->ipv4_nameservers) { + connman_network_set_nameservers(context->network, + context->ipv4_nameservers); + } else if (context->ipv6_nameservers) { + connman_network_set_nameservers(context->network, + context->ipv6_nameservers); } if (setip) { - connman_network_set_index(modem->network, index); - connman_network_set_connected(modem->network, true); + connman_network_set_index(context->network, index); + connman_network_set_connected(context->network, true); } } -static void set_disconnected(struct modem_data *modem) +static void set_disconnected(struct network_context *context) { - DBG("%s", modem->path); + DBG("%s", context->path); - if (modem->network) - connman_network_set_connected(modem->network, false); + if (context->network) + connman_network_set_connected(context->network, false); - if (modem->context) { - g_free(modem->context->ipv4_nameservers); - modem->context->ipv4_nameservers = NULL; - if (modem->context->ipv4_method != CONNMAN_IPCONFIG_METHOD_OFF) - modem->context->ipv4_method = - CONNMAN_IPCONFIG_METHOD_UNKNOWN; + g_free(context->ipv4_nameservers); + context->ipv4_nameservers = NULL; + if (context->ipv4_method != CONNMAN_IPCONFIG_METHOD_OFF) + context->ipv4_method = + CONNMAN_IPCONFIG_METHOD_UNKNOWN; - g_free(modem->context->ipv6_nameservers); - modem->context->ipv6_nameservers = NULL; - if (modem->context->ipv6_method != CONNMAN_IPCONFIG_METHOD_OFF) - modem->context->ipv6_method = - CONNMAN_IPCONFIG_METHOD_UNKNOWN; - } + g_free(context->ipv6_nameservers); + context->ipv6_nameservers = NULL; + if (context->ipv6_method != CONNMAN_IPCONFIG_METHOD_OFF) + context->ipv6_method = + CONNMAN_IPCONFIG_METHOD_UNKNOWN; } typedef void (*set_property_cb)(struct modem_data *data, - bool success); + struct network_context *context, bool success); typedef void (*get_properties_cb)(struct modem_data *data, DBusMessageIter *dict); struct property_info { struct modem_data *modem; + struct network_context *context; const char *path; const char *interface; const char *property; @@ -356,6 +405,16 @@ struct property_info { get_properties_cb get_properties_cb; }; +static void free_property_info(void * memory) +{ + struct property_info * info = memory; + + if (info->context) + network_context_unref(info->context); + + g_free(info); +} + static void set_property_reply(DBusPendingCall *call, void *user_data) { struct property_info *info = user_data; @@ -381,7 +440,8 @@ static void set_property_reply(DBusPendingCall *call, void *user_data) } if (info->set_property_cb) - (*info->set_property_cb)(info->modem, success); + (*info->set_property_cb)(info->modem, info->context, + success); dbus_message_unref(reply); @@ -389,6 +449,7 @@ static void set_property_reply(DBusPendingCall *call, void *user_data) } static int set_property(struct modem_data *modem, + struct network_context *context, const char *path, const char *interface, const char *property, int type, void *value, set_property_cb notify) @@ -401,8 +462,8 @@ static int set_property(struct modem_data *modem, if (modem->call_set_property) { DBG("Cancel pending SetProperty"); - dbus_pending_call_cancel(modem->call_set_property); + dbus_pending_call_unref(modem->call_set_property); modem->call_set_property = NULL; } @@ -435,13 +496,17 @@ static int set_property(struct modem_data *modem, } info->modem = modem; + info->context = context; info->path = path; info->interface = interface; info->property = property; info->set_property_cb = notify; + if (info->context) + network_context_ref(info->context); + dbus_pending_call_set_notify(modem->call_set_property, - set_property_reply, info, g_free); + set_property_reply, info, free_property_info); dbus_message_unref(message); @@ -542,14 +607,14 @@ static int get_properties(const char *path, const char *interface, } static void context_set_active_reply(struct modem_data *modem, - bool success) + struct network_context *context, bool success) { - DBG("%s", modem->path); + DBG("%s", context->path); if (success) { /* * Don't handle do anything on success here. oFono will send - * the change via PropertyChanged singal. + * the change via PropertyChanged signal. */ return; } @@ -561,7 +626,7 @@ static void context_set_active_reply(struct modem_data *modem, * cycle the modem in such cases? */ - if (!modem->network) { + if (!context->network) { /* * In the case where we power down the device * we don't wait for the reply, therefore the network @@ -570,18 +635,19 @@ static void context_set_active_reply(struct modem_data *modem, return; } - connman_network_set_error(modem->network, + connman_network_set_error(context->network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); } static int context_set_active(struct modem_data *modem, - dbus_bool_t active) + struct network_context *context, + dbus_bool_t active) { int err; DBG("%s active %d", modem->path, active); - err = set_property(modem, modem->context->path, + err = set_property(modem, context, context->path, OFONO_CONTEXT_INTERFACE, "Active", DBUS_TYPE_BOOLEAN, &active, @@ -594,14 +660,14 @@ static int context_set_active(struct modem_data *modem, } static void cdma_cm_set_powered_reply(struct modem_data *modem, - bool success) + struct network_context *context, bool success) { - DBG("%s", modem->path); + DBG("%s", context->path); if (success) { /* * Don't handle do anything on success here. oFono will send - * the change via PropertyChanged singal. + * the change via PropertyChanged signal. */ return; } @@ -613,7 +679,7 @@ static void cdma_cm_set_powered_reply(struct modem_data *modem, * cycle the modem in such cases? */ - if (!modem->network) { + if (!context->network) { /* * In the case where we power down the device * we don't wait for the reply, therefore the network @@ -622,17 +688,24 @@ static void cdma_cm_set_powered_reply(struct modem_data *modem, return; } - connman_network_set_error(modem->network, + connman_network_set_error(context->network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); } static int cdma_cm_set_powered(struct modem_data *modem, dbus_bool_t powered) { int err; + struct network_context *context = NULL; + + if (!modem->context_list) + return -1; DBG("%s powered %d", modem->path, powered); - err = set_property(modem, modem->path, OFONO_CDMA_CM_INTERFACE, + /* In case of CDMA, there is only one context */ + context = modem->context_list->data; + err = set_property(modem, context, modem->path, + OFONO_CDMA_CM_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &powered, cdma_cm_set_powered_reply); @@ -647,7 +720,7 @@ static int modem_set_online(struct modem_data *modem, dbus_bool_t online) { DBG("%s online %d", modem->path, online); - return set_property(modem, modem->path, + return set_property(modem, NULL, modem->path, OFONO_MODEM_INTERFACE, "Online", DBUS_TYPE_BOOLEAN, &online, @@ -660,7 +733,7 @@ static int cm_set_powered(struct modem_data *modem, dbus_bool_t powered) DBG("%s powered %d", modem->path, powered); - err = set_property(modem, modem->path, + err = set_property(modem, NULL, modem->path, OFONO_CM_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &powered, @@ -680,7 +753,7 @@ static int modem_set_powered(struct modem_data *modem, dbus_bool_t powered) modem->set_powered = powered; - err = set_property(modem, modem->path, + err = set_property(modem, NULL, modem->path, OFONO_MODEM_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &powered, @@ -768,7 +841,6 @@ static void extract_ipv4_settings(DBusMessageIter *array, connman_ipaddress_free(context->ipv4_address); context->ipv4_address = NULL; - context->index = -1; if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) return; @@ -871,7 +943,6 @@ static void extract_ipv6_settings(DBusMessageIter *array, connman_ipaddress_free(context->ipv6_address); context->ipv6_address = NULL; - context->index = -1; if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) return; @@ -1017,71 +1088,68 @@ static void destroy_device(struct modem_data *modem) connman_device_set_powered(modem->device, false); - if (modem->network) { - connman_device_remove_network(modem->device, modem->network); - connman_network_unref(modem->network); - modem->network = NULL; - } - connman_device_unregister(modem->device); connman_device_unref(modem->device); modem->device = NULL; } -static void add_network(struct modem_data *modem) +static void add_network(struct modem_data *modem, + struct network_context *context) { const char *group; DBG("%s", modem->path); - if (modem->network) + if (context->network) return; - modem->network = connman_network_create(modem->context->path, - CONNMAN_NETWORK_TYPE_CELLULAR); - if (!modem->network) + context->network = connman_network_create(context->path, + CONNMAN_NETWORK_TYPE_CELLULAR); + if (!context->network) return; - DBG("network %p", modem->network); + DBG("network %p", context->network); - connman_network_set_data(modem->network, modem); + connman_network_set_data(context->network, modem); - connman_network_set_string(modem->network, "Path", - modem->context->path); + connman_network_set_string(context->network, "Path", + context->path); if (modem->name) - connman_network_set_name(modem->network, modem->name); + connman_network_set_name(context->network, modem->name); else - connman_network_set_name(modem->network, ""); + connman_network_set_name(context->network, ""); - connman_network_set_strength(modem->network, modem->strength); + connman_network_set_strength(context->network, modem->strength); - group = get_ident(modem->context->path); - connman_network_set_group(modem->network, group); + group = get_ident(context->path); + connman_network_set_group(context->network, group); - connman_network_set_bool(modem->network, "Roaming", - modem->roaming); + connman_network_set_bool(context->network, "Roaming", + modem->roaming); - if (connman_device_add_network(modem->device, modem->network) < 0) { - connman_network_unref(modem->network); - modem->network = NULL; + if (connman_device_add_network(modem->device, context->network) < 0) { + connman_network_unref(context->network); + context->network = NULL; return; } } -static void remove_network(struct modem_data *modem) +static void remove_network(struct modem_data *modem, + struct network_context *context) { DBG("%s", modem->path); - if (!modem->network) + if (!context || !context->network) return; - DBG("network %p", modem->network); + DBG("network %p", context->network); - connman_device_remove_network(modem->device, modem->network); - connman_network_unref(modem->network); - modem->network = NULL; + if (modem->device) + connman_device_remove_network(modem->device, context->network); + connman_network_unref(context->network); + context->network = NULL; } static int set_context_ipconfig(struct network_context *context, @@ -1134,14 +1202,6 @@ static int add_cm_context(struct modem_data *modem, const char *context_path, DBG("%s context path %s", modem->path, context_path); - if (modem->context) { - /* - * We have already assigned a context to this modem - * and we do only support one Internet context. - */ - return -EALREADY; - } - context = network_context_alloc(context_path); if (!context) return -ENOMEM; @@ -1178,9 +1238,9 @@ static int add_cm_context(struct modem_data *modem, const char *context_path, dbus_message_iter_get_basic(&value, &apn); if (apn && strlen(apn) > 0) - modem->valid_apn = true; + context->valid_apn = true; else - modem->valid_apn = false; + context->valid_apn = false; DBG("%s AccessPointName '%s'", modem->path, apn); } else if (g_str_equal(key, "Protocol") && @@ -1195,51 +1255,80 @@ static int add_cm_context(struct modem_data *modem, const char *context_path, } if (g_strcmp0(context_type, "internet") != 0) { - network_context_free(context); + network_context_unref(context); return -EINVAL; } if (ip_protocol) set_context_ipconfig(context, ip_protocol); - modem->context = context; - modem->active = active; + context->active = active; + modem->context_list = g_slist_prepend(modem->context_list, context); g_hash_table_replace(context_hash, g_strdup(context_path), modem); - if (modem->valid_apn && modem->attached && - has_interface(modem->interfaces, - OFONO_API_NETREG)) { - add_network(modem); - } + if (context->valid_apn && modem->attached && + has_interface(modem->interfaces, OFONO_API_NETREG)) + add_network(modem, context); return 0; } static void remove_cm_context(struct modem_data *modem, - const char *context_path) + struct network_context *context) { - if (!modem->context) + if (!modem->context_list) return; + if (!context) + return; + + g_hash_table_remove(context_hash, context->path); + + if (context->network) + remove_network(modem, context); + modem->context_list = g_slist_remove(modem->context_list, context); + + network_context_unref(context); + context = NULL; +} + +static void remove_all_contexts(struct modem_data *modem) +{ + GSList *list = NULL; - if (modem->network) - remove_network(modem); + DBG(""); + + if (modem->context_list == NULL) + return; + + list = modem->context_list; + while (list) { + struct network_context *context = list->data; - g_hash_table_remove(context_hash, context_path); + remove_cm_context(modem, context); - network_context_free(modem->context); - modem->context = NULL; + list = modem->context_list; + } + g_slist_free(modem->context_list); + modem->context_list = NULL; +} + +static void remove_all_networks(struct modem_data *modem) +{ + GSList *list; - modem->valid_apn = false; + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; - if (modem->network) - remove_network(modem); + remove_network(modem, context); + } } static gboolean context_changed(DBusConnection *conn, DBusMessage *message, void *user_data) { + struct network_context *context = NULL; const char *context_path = dbus_message_get_path(message); struct modem_data *modem = NULL; DBusMessageIter iter, value; @@ -1251,6 +1340,10 @@ static gboolean context_changed(DBusConnection *conn, if (!modem) return TRUE; + context = get_context_with_path(modem->context_list, context_path); + if (!context) + return TRUE; + if (!dbus_message_iter_init(message, &iter)) return TRUE; @@ -1267,23 +1360,23 @@ static gboolean context_changed(DBusConnection *conn, if (g_str_equal(key, "Settings")) { DBG("%s Settings", modem->path); - extract_ipv4_settings(&value, modem->context); + extract_ipv4_settings(&value, context); } else if (g_str_equal(key, "IPv6.Settings")) { DBG("%s IPv6.Settings", modem->path); - extract_ipv6_settings(&value, modem->context); + extract_ipv6_settings(&value, context); } else if (g_str_equal(key, "Active")) { dbus_bool_t active; dbus_message_iter_get_basic(&value, &active); - modem->active = active; + context->active = active; - DBG("%s Active %d", modem->path, modem->active); + DBG("%s Active %d", modem->path, context->active); - if (modem->active) - set_connected(modem); + if (context->active) + set_connected(modem, context); else - set_disconnected(modem); + set_disconnected(context); } else if (g_str_equal(key, "AccessPointName")) { const char *apn; @@ -1292,9 +1385,9 @@ static gboolean context_changed(DBusConnection *conn, DBG("%s AccessPointName %s", modem->path, apn); if (apn && strlen(apn) > 0) { - modem->valid_apn = true; + context->valid_apn = true; - if (modem->network) + if (context->network) return TRUE; if (!modem->attached) @@ -1304,17 +1397,17 @@ static gboolean context_changed(DBusConnection *conn, OFONO_API_NETREG)) return TRUE; - add_network(modem); + add_network(modem, context); - if (modem->active) - set_connected(modem); + if (context->active) + set_connected(modem, context); } else { - modem->valid_apn = false; + context->valid_apn = false; - if (!modem->network) + if (!context->network) return TRUE; - remove_network(modem); + remove_network(modem, context); } } else if (g_str_equal(key, "Protocol") && @@ -1323,7 +1416,7 @@ static gboolean context_changed(DBusConnection *conn, dbus_message_iter_get_basic(&value, &ip_protocol); - set_context_ipconfig(modem->context, ip_protocol); + set_context_ipconfig(context, ip_protocol); } return TRUE; @@ -1367,7 +1460,7 @@ static void cm_get_contexts_reply(DBusPendingCall *call, void *user_data) dbus_message_iter_next(&entry); dbus_message_iter_recurse(&entry, &value); - if (add_cm_context(modem, context_path, &value) == 0) + if (add_cm_context(modem, context_path, &value)) break; dbus_message_iter_next(&dict); @@ -1422,7 +1515,7 @@ static gboolean cm_context_added(DBusConnection *conn, const char *path = dbus_message_get_path(message); char *context_path; struct modem_data *modem; - DBusMessageIter iter, properties; + DBusMessageIter iter, properties, dict; DBG("%s", path); @@ -1438,6 +1531,13 @@ static gboolean cm_context_added(DBusConnection *conn, dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &properties); + /* Sometimes, we get an array instead of dict */ + if (dbus_message_iter_get_arg_type(&properties) == DBUS_TYPE_ARRAY) { + /* Must recurse again */ + dbus_message_iter_recurse(&properties, &dict); + if (add_cm_context(modem, context_path, &dict) != 0) + return TRUE; + } if (add_cm_context(modem, context_path, &properties) != 0) return TRUE; @@ -1451,6 +1551,7 @@ static gboolean cm_context_removed(DBusConnection *conn, const char *path = dbus_message_get_path(message); const char *context_path; struct modem_data *modem; + struct network_context *context; DBusMessageIter iter; DBG("context path %s", path); @@ -1464,7 +1565,8 @@ static gboolean cm_context_removed(DBusConnection *conn, if (!modem) return TRUE; - remove_cm_context(modem, context_path); + context = get_context_with_path(modem->context_list, context_path); + remove_cm_context(modem, context); return TRUE; } @@ -1473,6 +1575,7 @@ static void netreg_update_name(struct modem_data *modem, DBusMessageIter* value) { char *name; + GSList *list; dbus_message_iter_get_basic(value, &name); @@ -1481,21 +1584,30 @@ static void netreg_update_name(struct modem_data *modem, g_free(modem->name); modem->name = g_strdup(name); - if (!modem->network) + if (!modem->context_list) return; - connman_network_set_name(modem->network, modem->name); - connman_network_update(modem->network); + /* For all the context */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network) { + connman_network_set_name(context->network, modem->name); + connman_network_update(context->network); + } + } } static void netreg_update_strength(struct modem_data *modem, DBusMessageIter *value) { + GSList *list; + dbus_message_iter_get_basic(value, &modem->strength); DBG("%s Strength %d", modem->path, modem->strength); - if (!modem->network) + if (!modem->context_list) return; /* @@ -1514,19 +1626,29 @@ static void netreg_update_strength(struct modem_data *modem, if (modem->data_strength != 0) return; - connman_network_set_strength(modem->network, modem->strength); - connman_network_update(modem->network); + /* For all the context */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network) { + connman_network_set_strength(context->network, + modem->strength); + connman_network_update(context->network); + } + } } /* Retrieve 1xEVDO Data Strength signal */ static void netreg_update_datastrength(struct modem_data *modem, DBusMessageIter *value) { + GSList *list; + dbus_message_iter_get_basic(value, &modem->data_strength); DBG("%s Data Strength %d", modem->path, modem->data_strength); - if (!modem->network) + if (!modem->context_list) return; /* @@ -1537,8 +1659,16 @@ static void netreg_update_datastrength(struct modem_data *modem, if (modem->data_strength == 0) return; - connman_network_set_strength(modem->network, modem->data_strength); - connman_network_update(modem->network); + /* For all the context */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network) { + connman_network_set_strength(context->network, + modem->data_strength); + connman_network_update(context->network); + } + } } static void netreg_update_status(struct modem_data *modem, @@ -1546,6 +1676,7 @@ static void netreg_update_status(struct modem_data *modem, { char *status; bool roaming; + GSList *list; dbus_message_iter_get_basic(value, &status); @@ -1557,12 +1688,19 @@ static void netreg_update_status(struct modem_data *modem, modem->roaming = roaming; - if (!modem->network) + if (!modem->context_list) return; - connman_network_set_bool(modem->network, + /* For all the context */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; + + if (context->network) { + connman_network_set_bool(context->network, "Roaming", modem->roaming); - connman_network_update(modem->network); + connman_network_update(context->network); + } + } } static void netreg_update_regdom(struct modem_data *modem, @@ -1624,6 +1762,8 @@ static gboolean netreg_changed(DBusConnection *conn, DBusMessage *message, static void netreg_properties_reply(struct modem_data *modem, DBusMessageIter *dict) { + GSList *list = NULL; + DBG("%s", modem->path); while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) { @@ -1648,7 +1788,7 @@ static void netreg_properties_reply(struct modem_data *modem, dbus_message_iter_next(dict); } - if (!modem->context) { + if (!modem->context_list) { /* * netgreg_get_properties() was issued after we got * cm_get_contexts_reply() where we create the @@ -1659,12 +1799,15 @@ static void netreg_properties_reply(struct modem_data *modem, */ return; } + /* Check for all contexts if they are valids and/or actives */ + for (list = modem->context_list; list; list = list->next) { + struct network_context *context = list->data; - if (modem->valid_apn) - add_network(modem); - - if (modem->active) - set_connected(modem); + if (context->valid_apn) + add_network(modem, context); + if (context->active) + set_connected(modem, context); + } } static int netreg_get_properties(struct modem_data *modem) @@ -1675,6 +1818,7 @@ static int netreg_get_properties(struct modem_data *modem) static void add_cdma_network(struct modem_data *modem) { + struct network_context *context = NULL; /* Be sure that device is created before adding CDMA network */ if (!modem->device) return; @@ -1683,16 +1827,20 @@ static void add_cdma_network(struct modem_data *modem) * CDMA modems don't need contexts for data call, however the current * add_network() logic needs one, so we create one to proceed. */ - if (!modem->context) - modem->context = network_context_alloc(modem->path); + if (!modem->context_list) { + context = network_context_alloc(modem->path); + modem->context_list = g_slist_prepend(modem->context_list, + context); + } else + context = modem->context_list->data; if (!modem->name) modem->name = g_strdup("CDMA Network"); - add_network(modem); + add_network(modem, context); if (modem->cdma_cm_powered) - set_connected(modem); + set_connected(modem, context); } static gboolean cdma_netreg_changed(DBusConnection *conn, @@ -1733,7 +1881,7 @@ static gboolean cdma_netreg_changed(DBusConnection *conn, if (modem->registered) add_cdma_network(modem); else - remove_network(modem); + remove_all_networks(modem); return TRUE; } @@ -1768,7 +1916,7 @@ static void cdma_netreg_properties_reply(struct modem_data *modem, if (modem->registered) add_cdma_network(modem); else - remove_network(modem); + remove_all_networks(modem); } static int cdma_netreg_get_properties(struct modem_data *modem) @@ -1788,7 +1936,7 @@ static void cm_update_attached(struct modem_data *modem, DBG("%s Attached %d", modem->path, modem->attached); if (!modem->attached) { - remove_network(modem); + remove_all_networks(modem); return; } @@ -1849,6 +1997,7 @@ static gboolean cm_changed(DBusConnection *conn, DBusMessage *message, static void cdma_cm_update_powered(struct modem_data *modem, DBusMessageIter *value) { + struct network_context *context = NULL; dbus_bool_t cdma_cm_powered; dbus_message_iter_get_basic(value, &cdma_cm_powered); @@ -1856,13 +2005,15 @@ static void cdma_cm_update_powered(struct modem_data *modem, DBG("%s CDMA cm Powered %d", modem->path, modem->cdma_cm_powered); - if (!modem->network) + if (!modem->context_list) return; + /* In case of CDMA, there is only one context */ + context = modem->context_list->data; if (modem->cdma_cm_powered) - set_connected(modem); + set_connected(modem, context); else - set_disconnected(modem); + set_disconnected(context); } static void cdma_cm_update_settings(struct modem_data *modem, @@ -1870,7 +2021,7 @@ static void cdma_cm_update_settings(struct modem_data *modem, { DBG("%s Settings", modem->path); - extract_ipv4_settings(value, modem->context); + extract_ipv4_settings(value, modem->context_list->data); } static gboolean cdma_cm_changed(DBusConnection *conn, @@ -1885,7 +2036,7 @@ static gboolean cdma_cm_changed(DBusConnection *conn, if (!modem) return TRUE; - if (modem->online && !modem->network) + if (modem->online && !modem->context_list) cdma_netreg_get_properties(modem); if (!dbus_message_iter_init(message, &iter)) @@ -2142,17 +2293,24 @@ static void modem_update_interfaces(struct modem_data *modem, if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG)) cdma_netreg_get_properties(modem); - if (api_removed(old_ifaces, new_ifaces, OFONO_API_CM)) - remove_cm_context(modem, modem->context->path); + if (api_removed(old_ifaces, new_ifaces, OFONO_API_CM)) { + if (modem->call_get_contexts) { + DBG("cancelling pending GetContexts call"); + dbus_pending_call_cancel(modem->call_get_contexts); + dbus_pending_call_unref(modem->call_get_contexts); + modem->call_get_contexts = NULL; + } + remove_all_contexts(modem); + } if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_CM)) - remove_cm_context(modem, modem->context->path); + remove_all_contexts(modem); if (api_removed(old_ifaces, new_ifaces, OFONO_API_NETREG)) - remove_network(modem); + remove_all_networks(modem); if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG)) - remove_network(modem); + remove_all_networks(modem); } static gboolean modem_changed(DBusConnection *conn, DBusMessage *message, @@ -2186,8 +2344,8 @@ static gboolean modem_changed(DBusConnection *conn, DBusMessage *message, DBG("%s Powered %d", modem->path, modem->powered); - if (!modem->powered) - modem_set_powered(modem, TRUE); + /* Set the powered according to the value */ + modem_set_powered(modem, powered); } else if (g_str_equal(key, "Online")) { dbus_bool_t online; @@ -2340,21 +2498,31 @@ static void remove_modem(gpointer data) DBG("%s", modem->path); - if (modem->call_set_property) + if (modem->call_set_property) { dbus_pending_call_cancel(modem->call_set_property); + dbus_pending_call_unref(modem->call_set_property); + modem->call_set_property = NULL; + } - if (modem->call_get_properties) + if (modem->call_get_properties) { dbus_pending_call_cancel(modem->call_get_properties); + dbus_pending_call_unref(modem->call_get_properties); + modem->call_get_properties = NULL; + } - if (modem->call_get_contexts) + if (modem->call_get_contexts) { dbus_pending_call_cancel(modem->call_get_contexts); + dbus_pending_call_unref(modem->call_get_contexts); + modem->call_get_contexts = NULL; + } + + /* Must remove the contexts before the device */ + if (modem->context_list) + remove_all_contexts(modem); if (modem->device) destroy_device(modem); - if (modem->context) - remove_cm_context(modem, modem->context->path); - g_free(modem->serial); g_free(modem->name); g_free(modem->imsi); @@ -2530,12 +2698,20 @@ static void network_remove(struct connman_network *network) static int network_connect(struct connman_network *network) { + struct network_context *context; struct modem_data *modem = connman_network_get_data(network); DBG("%s network %p", modem->path, network); + if (!g_hash_table_lookup(modem_hash, modem->path)) + return -ENODEV; + + context = get_context_with_network(modem->context_list, network); + if (!context) + return -ENODEV; + if (has_interface(modem->interfaces, OFONO_API_CM)) - return context_set_active(modem, TRUE); + return context_set_active(modem, context, TRUE); else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM)) return cdma_cm_set_powered(modem, TRUE); @@ -2546,12 +2722,20 @@ static int network_connect(struct connman_network *network) static int network_disconnect(struct connman_network *network) { + struct network_context *context; struct modem_data *modem = connman_network_get_data(network); DBG("%s network %p", modem->path, network); + if (!g_hash_table_lookup(modem_hash, modem->path)) + return -ENODEV; + + context = get_context_with_network(modem->context_list, network); + if (!context) + return -ENODEV; + if (has_interface(modem->interfaces, OFONO_API_CM)) - return context_set_active(modem, FALSE); + return context_set_active(modem, context, FALSE); else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM)) return cdma_cm_set_powered(modem, FALSE); @@ -2784,7 +2968,7 @@ static void ofono_exit(void) if (modem_hash) { /* - * We should propably wait for the SetProperty() reply + * We should probably wait for the SetProperty() reply * message, because ... */ g_hash_table_foreach(modem_hash, modem_power_down, NULL);