diff options
Diffstat (limited to 'src/core/devices/wwan')
| -rw-r--r-- | src/core/devices/wwan/nm-device-modem.c | 24 | ||||
| -rw-r--r-- | src/core/devices/wwan/nm-device-modem.h | 2 | ||||
| -rw-r--r-- | src/core/devices/wwan/nm-modem-broadband.c | 13 | ||||
| -rw-r--r-- | src/core/devices/wwan/nm-modem-broadband.h | 2 | ||||
| -rw-r--r-- | src/core/devices/wwan/nm-modem-manager.h | 2 | ||||
| -rw-r--r-- | src/core/devices/wwan/nm-modem-ofono.c | 740 | ||||
| -rw-r--r-- | src/core/devices/wwan/nm-modem-ofono.h | 5 | ||||
| -rw-r--r-- | src/core/devices/wwan/nm-modem.c | 10 | ||||
| -rw-r--r-- | src/core/devices/wwan/nm-modem.h | 2 | ||||
| -rw-r--r-- | src/core/devices/wwan/nm-wwan-factory.c | 2 |
10 files changed, 625 insertions, 177 deletions
diff --git a/src/core/devices/wwan/nm-device-modem.c b/src/core/devices/wwan/nm-device-modem.c index e0209aff..b83120f9 100644 --- a/src/core/devices/wwan/nm-device-modem.c +++ b/src/core/devices/wwan/nm-device-modem.c @@ -273,6 +273,15 @@ modem_state_cb(NMModem *modem, int new_state_i, int old_state_i, gpointer user_d /* Called when the ModemManager modem enabled state is changed externally * to NetworkManager (eg something using MM's D-Bus API directly). */ + + if (!NM_MODEM_GET_CLASS(priv->modem)->set_mm_enabled) { + /* We cannot re-enable this modem, thus device becomes unavailable. */ + nm_device_state_changed(device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + return; + } + if (nm_device_is_activating(device) || dev_state == NM_DEVICE_STATE_ACTIVATED) { /* user-initiated action, hence DISCONNECTED not FAILED */ nm_device_state_changed(device, @@ -435,6 +444,13 @@ check_connection_available(NMDevice *device, return FALSE; } + if (!NM_MODEM_GET_CLASS(priv->modem)->set_mm_enabled && state <= NM_MODEM_STATE_DISABLING) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem is disabled and NM cannot enable it"); + return FALSE; + } + if (state == NM_MODEM_STATE_LOCKED) { if (!nm_connection_get_setting_gsm(connection)) { nm_utils_error_set_literal(error, @@ -599,6 +615,11 @@ set_enabled(NMDevice *device, gboolean enabled) if (enabled == FALSE) { nm_device_state_changed(device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NONE); + } else { + /* It's possible that the modem is enabled outside of NM. Need to recheck. */ + nm_device_queue_recheck_available(device, + NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, + NM_DEVICE_STATE_REASON_MODEM_FAILED); } } @@ -617,6 +638,9 @@ is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) if (modem_state <= NM_MODEM_STATE_INITIALIZING) return FALSE; + if (!NM_MODEM_GET_CLASS(priv->modem)->set_mm_enabled && modem_state <= NM_MODEM_STATE_DISABLING) + return FALSE; + return TRUE; } diff --git a/src/core/devices/wwan/nm-device-modem.h b/src/core/devices/wwan/nm-device-modem.h index f171d76f..317a5bde 100644 --- a/src/core/devices/wwan/nm-device-modem.h +++ b/src/core/devices/wwan/nm-device-modem.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_MODEM (nm_device_modem_get_type()) #define NM_DEVICE_MODEM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) #define NM_DEVICE_MODEM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) #define NM_IS_DEVICE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MODEM)) diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c index db4fb29f..f0907c46 100644 --- a/src/core/devices/wwan/nm-modem-broadband.c +++ b/src/core/devices/wwan/nm-modem-broadband.c @@ -636,7 +636,7 @@ connect_context_step(NMModemBroadband *self) if (ctx->ip_types_i < ctx->ip_types->len) { NMModemIPType current; - current = g_array_index(ctx->ip_types, NMModemIPType, ctx->ip_types_i); + current = nm_g_array_index(ctx->ip_types, NMModemIPType, ctx->ip_types_i); if (current == NM_MODEM_IP_TYPE_IPV4) mm_simple_connect_properties_set_ip_type(ctx->connect_properties, @@ -993,7 +993,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho /* Fully fail if invalid IP address retrieved */ address_string = mm_bearer_ip_config_get_address(self->_priv.ipv4_config); if (!address_string - || !nm_utils_parse_inaddr_bin(AF_INET, address_string, NULL, &address_network)) { + || !nm_inet_parse_bin(AF_INET, address_string, NULL, &address_network)) { g_set_error(&error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, @@ -1005,7 +1005,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho /* Missing gateway not a hard failure */ gw_string = mm_bearer_ip_config_get_gateway(self->_priv.ipv4_config); - if (gw_string && !nm_utils_parse_inaddr_bin(AF_INET, gw_string, NULL, &gw)) { + if (gw_string && !nm_inet_parse_bin(AF_INET, gw_string, NULL, &gw)) { g_set_error(&error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, @@ -1057,9 +1057,8 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho dns = mm_bearer_ip_config_get_dns(self->_priv.ipv4_config); for (i = 0; dns && dns[i]; i++) { - if (nm_utils_parse_inaddr_bin(AF_INET, dns[i], NULL, &address_network) - && address_network > 0) { - nm_l3_config_data_add_nameserver(l3cd, AF_INET, &address_network); + if (nm_inet_parse_bin(AF_INET, dns[i], NULL, &address_network) && address_network > 0) { + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &address_network, NULL); _LOGI(" DNS %s", dns[i]); } } @@ -1174,7 +1173,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho struct in6_addr addr; if (inet_pton(AF_INET6, dns[i], &addr)) { - nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &addr); + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET6, &addr, NULL); _LOGI(" DNS %s", dns[i]); } } diff --git a/src/core/devices/wwan/nm-modem-broadband.h b/src/core/devices/wwan/nm-modem-broadband.h index 627fe25a..e4467310 100644 --- a/src/core/devices/wwan/nm-modem-broadband.h +++ b/src/core/devices/wwan/nm-modem-broadband.h @@ -10,7 +10,7 @@ #define NM_TYPE_MODEM_BROADBAND (nm_modem_broadband_get_type()) #define NM_MODEM_BROADBAND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) #define NM_MODEM_BROADBAND_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) #define NM_IS_MODEM_BROADBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_BROADBAND)) diff --git a/src/core/devices/wwan/nm-modem-manager.h b/src/core/devices/wwan/nm-modem-manager.h index e89a032b..a9339ffc 100644 --- a/src/core/devices/wwan/nm-modem-manager.h +++ b/src/core/devices/wwan/nm-modem-manager.h @@ -12,7 +12,7 @@ #define NM_TYPE_MODEM_MANAGER (nm_modem_manager_get_type()) #define NM_MODEM_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_MANAGER, NMModemManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_MANAGER, NMModemManager)) #define NM_MODEM_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_MANAGER, NMModemManagerClass)) #define NM_IS_MODEM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_MANAGER)) diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c index fc27c3fd..b3745621 100644 --- a/src/core/devices/wwan/nm-modem-ofono.c +++ b/src/core/devices/wwan/nm-modem-ofono.c @@ -7,8 +7,12 @@ #include "nm-modem-ofono.h" +#include "libnm-glib-aux/nm-dbus-aux.h" #include "libnm-core-intern/nm-core-internal.h" +#include "libnm-glib-aux/nm-uuid.h" #include "devices/nm-device-private.h" +#include "nm-setting-gsm.h" +#include "settings/nm-settings.h" #include "nm-modem.h" #include "libnm-platform/nm-platform.h" #include "nm-l3-config-data.h" @@ -27,27 +31,44 @@ /*****************************************************************************/ typedef struct { + NMModemOfono *self; + char *name; + char *type; + gboolean preferred; + GDBusProxy *proxy; +} OfonoContextData; + +typedef struct { GHashTable *connect_properties; + GHashTable *connections; + GHashTable *contexts; GDBusProxy *modem_proxy; GDBusProxy *connman_proxy; - GDBusProxy *context_proxy; GDBusProxy *sim_proxy; GCancellable *modem_proxy_cancellable; GCancellable *connman_proxy_cancellable; - GCancellable *context_proxy_cancellable; + GCancellable *connect_cancellable; GCancellable *sim_proxy_cancellable; GError *property_error; - char *context_path; char *imsi; gboolean modem_online; + gboolean connman_powered; gboolean gprs_attached; NML3ConfigData *l3cd_4; + NMSettings *settings; + + guint n_context_proxy_pending; + + /* unowned; reference held by 'contexts' above. */ + OfonoContextData *current_octx; + + GSource *deferred_connection_timeout_source; } NMModemOfonoPrivate; struct _NMModemOfono { @@ -96,6 +117,21 @@ G_DEFINE_TYPE(NMModemOfono, nm_modem_ofono, NM_TYPE_MODEM) /*****************************************************************************/ +/* + * Deterministic UUID is used to pair imsi+context with exported connection + * (via a pair of hash tables). + */ + +static char * +_generate_uuid(const char *imsi, const char *object_path) +{ + return nm_uuid_generate_from_strings( + NM_UUID_TYPE_VERSION5, + &NM_UUID_INIT(b5, 6b, ad, f5, ef, 9d, 4a, 21, a8, e7, 7d, db, 69, bb, 6b, ee), + imsi, + object_path); +} + static void get_capabilities(NMModem *_self, NMDeviceModemCapabilities *modem_caps, @@ -106,6 +142,8 @@ get_capabilities(NMModem *_self, *current_caps = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS; } +static void do_context_activate(NMModemOfono *self); + static void update_modem_state(NMModemOfono *self) { @@ -114,13 +152,16 @@ update_modem_state(NMModemOfono *self) NMModemState new_state = NM_MODEM_STATE_DISABLED; const char *reason = NULL; - _LOGI("'Attached': %s 'Online': %s 'IMSI': %s", + _LOGI("'Attached': %s 'Online': %s 'Powered': %s 'IMSI': %s", priv->gprs_attached ? "true" : "false", priv->modem_online ? "true" : "false", + priv->connman_powered ? "true" : "false", priv->imsi); if (priv->modem_online == FALSE) { reason = "modem 'Online=false'"; + } else if (priv->connman_powered == FALSE) { + reason = "ConnectionManager 'Powered=false'"; } else if (priv->imsi == NULL && state != NM_MODEM_STATE_ENABLING) { reason = "modem not ready"; } else if (priv->gprs_attached == FALSE) { @@ -131,8 +172,27 @@ update_modem_state(NMModemOfono *self) reason = "modem ready"; } - if (state != new_state) + if (state != new_state) { + if (new_state == NM_MODEM_STATE_DISABLED && priv->deferred_connection_timeout_source) { + /* + * Do this before set_state(), because we want the final device state + * to be "unavailable", not "failed" or "disconnected". + */ + _LOGI("canceling deferred context activation"); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); + } + nm_modem_set_state(NM_MODEM(self), new_state, reason); + + if (new_state == NM_MODEM_STATE_REGISTERED && priv->deferred_connection_timeout_source) { + _LOGI("resuming deferred context activation"); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + do_context_activate(self); + } + } } /* Disconnect */ @@ -213,7 +273,8 @@ disconnect(NMModem *modem, ctx->callback = callback; ctx->callback_user_data = user_data; - if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable)) { + if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable) + || priv->current_octx == NULL) { nm_utils_invoke_on_idle(cancellable, disconnect_context_complete_on_idle, ctx); return; } @@ -222,7 +283,7 @@ disconnect(NMModem *modem, NM_MODEM_STATE_DISCONNECTING, nm_modem_state_to_string(NM_MODEM_STATE_DISCONNECTING)); - g_dbus_proxy_call(priv->context_proxy, + g_dbus_proxy_call(priv->current_octx->proxy, "SetProperty", g_variant_new("(sv)", "Active", g_variant_new("b", warn)), G_DBUS_CALL_FLAGS_NONE, @@ -230,6 +291,8 @@ disconnect(NMModem *modem, ctx->cancellable, disconnect_done, ctx); + + priv->current_octx = NULL; } static void @@ -251,7 +314,7 @@ check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection, { NMModemOfono *self = NM_MODEM_OFONO(modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char *id; + const char *uuid; if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, NULL)) { nm_utils_error_set(error, @@ -268,19 +331,12 @@ check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection, return FALSE; } - id = nm_connection_get_id(connection); - - if (!strstr(id, "/context")) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID has no context"); - return FALSE; - } + uuid = nm_connection_get_uuid(connection); - if (!strstr(id, priv->imsi)) { + if (!g_hash_table_contains(priv->contexts, uuid)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID does not contain the IMSI"); + "connection ID does not match known contexts"); return FALSE; } @@ -398,11 +454,11 @@ _sim_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->sim_proxy = proxy; /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect(priv->sim_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(sim_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->sim_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(sim_property_changed), + self); g_dbus_proxy_call(priv->sim_proxy, "GetProperties", @@ -469,6 +525,19 @@ handle_connman_property(GDBusProxy *proxy, const char *property, GVariant *v, gp update_modem_state(self); } + } else if (nm_streq(property, "Powered") && VARIANT_IS_OF_TYPE_BOOLEAN(v)) { + gboolean powered = g_variant_get_boolean(v); + gboolean old_powered = priv->connman_powered; + + _LOGD("Powered: %s", powered ? "True" : "False"); + + if (old_powered != powered) { + priv->connman_powered = powered; + + _LOGI("Powered %s -> %s", old_powered ? "true" : "false", powered ? "true" : "false"); + + update_modem_state(self); + } } } @@ -484,7 +553,6 @@ static void connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data) { NMModemOfono *self; - NMModemOfonoPrivate *priv; gs_free_error GError *error = NULL; gs_unref_variant GVariant *v_properties = NULL; gs_unref_variant GVariant *v_dict = NULL; @@ -498,9 +566,6 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user return; self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->connman_proxy_cancellable); if (!v_properties) { g_dbus_error_strip_remote_error(error); @@ -526,6 +591,366 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user } static void +ofono_context_data_free(OfonoContextData *octx) +{ + g_free(octx->name); + g_free(octx->type); + + if (octx->proxy) { + g_signal_handlers_disconnect_by_data(octx->proxy, octx); + g_object_unref(octx->proxy); + } + + g_slice_free(OfonoContextData, octx); +} + +static void +add_or_update_connection(NMModemOfono *self, const char *context_name, const char *uuid) +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + gs_unref_object NMConnection *connection = NULL; + NMSetting *setting; + NMSettingsConnection *sett_conn; + gs_free_error GError *error = NULL; + + /* + * See first if we have an existing connection (from previous or current + * run of NM) that we can update in-place. + */ + + sett_conn = nm_settings_get_connection_by_uuid(priv->settings, uuid); + if (sett_conn + && !NM_FLAGS_HAS(nm_settings_connection_get_flags(sett_conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) { + /* + * Either we have a coliding connection, or our connection has been + * modified by user. For the latter case it's safe to leave it alone; + * the UUID will still let it connect. However, for the first case, + * we can't really do anything about it unless we re-write the way we + * track connection <-> context, which I (Ratchanan) don't want to do + * right now... + */ + return; + } + + connection = nm_simple_connection_new(); + setting = nm_setting_connection_new(); + g_object_set(setting, + NM_SETTING_CONNECTION_ID, + context_name, + NM_SETTING_CONNECTION_UUID, + uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, + TRUE, + NM_SETTING_CONNECTION_TYPE, + NM_SETTING_GSM_SETTING_NAME, + NULL); + nm_connection_add_setting(connection, setting); + + setting = nm_setting_gsm_new(); + + /* + * oFono should already know how to handle placing the call, but NM + * insists on having a number. Pass the usual *99#. + */ + g_object_set(setting, NM_SETTING_GSM_NUMBER, "*99#", NULL); + nm_connection_add_setting(connection, setting); + + if (!nm_connection_normalize(connection, NULL, NULL, &error)) { + nm_log_err(LOGD_MB, + "ofono: could not not generate a connection for %s: %s", + context_name, + error->message); + return; + } + + if (!sett_conn) { + nm_settings_add_connection(priv->settings, + NULL, /* plugin */ + connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_ADD_REASON_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, + &sett_conn, + &error); + } else { + nm_settings_update_connection(priv->settings, + sett_conn, + NULL, /* plugin_name */ + connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, + /* log_context_name */ "ofono", + &error); + } + + if (!sett_conn) { + nm_log_warn(LOGD_MB, + "ofono: could not add or update new connection for '%s' (%s): %s", + context_name, + uuid, + error->message); + return; + } + + g_hash_table_insert(priv->connections, g_strdup(uuid), g_object_ref(sett_conn)); +} + +/* + * Used when we decide a connection is not needed. Rationale being that the + * connection could have been modified by user since it's created by us, + * after which we don't want to delete, but we don't want to track it either. + */ + +static void +untrack_connection_and_delete_if_generated(NMModemOfono *self, char const *uuid) +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + NMSettingsConnection *sett_conn; + + sett_conn = g_hash_table_lookup(priv->connections, uuid); + if (!sett_conn) + return; + + if (NM_FLAGS_HAS(nm_settings_connection_get_flags(sett_conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + nm_settings_connection_delete(sett_conn, FALSE); + + g_hash_table_remove(priv->connections, uuid); +} + +static void +update_connection_list(NMModemOfono *self) +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + GHashTableIter iter; + char *uuid; + OfonoContextData *octx; + OfonoContextData *octx_preferred = NULL; + + _LOGI("(re-)checking which context needs a connection"); + + g_hash_table_iter_init(&iter, priv->contexts); + while (g_hash_table_iter_next(&iter, (gpointer *) &uuid, (gpointer *) &octx)) { + if (octx->preferred) { + octx_preferred = octx; + break; + } + } + + g_hash_table_iter_init(&iter, priv->contexts); + while (g_hash_table_iter_next(&iter, (gpointer *) &uuid, (gpointer *) &octx)) { + gboolean connection_should_exist = + (!octx_preferred || octx_preferred == octx) + && (nm_streq(octx->type, "internet") || nm_streq(octx->type, "internet+mms")); + gboolean connection_exists = g_hash_table_contains(priv->connections, uuid); + + if (connection_should_exist && !connection_exists) { + _LOGI("creating connection for %s%s", + octx_preferred ? "preferred context " : "", + g_dbus_proxy_get_object_path(octx->proxy)); + add_or_update_connection(self, octx->name, uuid); + } else if (!connection_should_exist && connection_exists) { + _LOGI("removing connection for %s", g_dbus_proxy_get_object_path(octx->proxy)); + untrack_connection_and_delete_if_generated(self, uuid); + + /* priv->current_octx is deliberately not cleared here because the + * disconnection chain happens in another main loop iteration. + */ + } + } +} + +static void handle_settings(NMModemOfono *self, GVariant *v_dict); + +static void +context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) +{ + OfonoContextData *octx = user_data; + NMModemOfono *self = octx->self; + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + gs_unref_variant GVariant *v_inner = g_variant_get_child_value(v, 0); + + if (!v_inner) { + _LOGW("ofono: (%s): error handling PropertyChanged signal", + nm_modem_get_uid(NM_MODEM(self))); + return; + } + + if (nm_streq(property, "Name")) { + gs_free char *uuid = NULL; + + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_STRING)); + g_free(octx->name); + octx->name = g_variant_dup_string(v_inner, /* &length */ NULL); + + uuid = _generate_uuid(priv->imsi, g_dbus_proxy_get_object_path(proxy)); + if (g_hash_table_contains(priv->connections, uuid)) + add_or_update_connection(self, octx->name, uuid); + } else if (nm_streq(property, "Type")) { + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_STRING)); + g_free(octx->type); + octx->type = g_variant_dup_string(v_inner, /* &length */ NULL); + + update_connection_list(self); + } else if (nm_streq(property, "Preferred")) { + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_BOOLEAN)); + octx->preferred = g_variant_get_boolean(v_inner); + + update_connection_list(self); + } else if (nm_streq(property, "Settings") && priv->current_octx == octx) { + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_VARDICT)); + handle_settings(self, v_inner); + } +} + +static void +_context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + OfonoContextData *octx = user_data; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; + char *uuid; + + proxy = g_dbus_proxy_new_for_bus_finish(result, &error); + if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + ofono_context_data_free(octx); + return; + } + + self = octx->self; + priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + if (!proxy) { + _LOGW("failed to create ConnectionContext proxy: %s", error->message); + ofono_context_data_free(octx); + return; + } + + _LOGD("recieved proxy for %s", g_dbus_proxy_get_object_path(proxy)); + octx->proxy = proxy; + + _nm_dbus_proxy_signal_connect(proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(context_property_changed), + octx); + + uuid = _generate_uuid(priv->imsi, g_dbus_proxy_get_object_path(proxy)); + g_hash_table_insert(priv->contexts, uuid, octx); + priv->n_context_proxy_pending--; + + if (priv->n_context_proxy_pending == 0) + update_connection_list(self); +} + +static void +connman_context_removed(GDBusProxy *proxy, const char *object_path, gpointer user_data) +{ + NMModemOfono *self = NM_MODEM_OFONO(user_data); + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + gs_free char *uuid = NULL; + OfonoContextData *octx; + + /* look up the connction, and if we have connection disconnect and remove it */ + uuid = _generate_uuid(priv->imsi, object_path); + untrack_connection_and_delete_if_generated(self, uuid); + + octx = g_hash_table_lookup(priv->contexts, uuid); + if (octx) { + gboolean preferred = octx->preferred; + + if (octx == priv->current_octx) + priv->current_octx = NULL; + + g_hash_table_remove(priv->contexts, uuid); + + if (preferred) + update_connection_list(self); + } +} + +static void +connman_context_added(GDBusProxy *proxy, const char *object_path, GVariant *v, gpointer user_data) +{ + NMModemOfono *self = user_data; + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + OfonoContextData *octx; + gs_unref_variant GVariant *v_context_type = NULL; + gs_unref_variant GVariant *v_context_name = NULL; + gs_unref_variant GVariant *v_context_preferred = NULL; + + nm_log_info(LOGD_MB, "ofono: processing context %s", object_path); + + v_context_name = g_variant_lookup_value(v, "Name", G_VARIANT_TYPE_STRING); + v_context_type = g_variant_lookup_value(v, "Type", G_VARIANT_TYPE_STRING); + if (!v_context_name || !v_context_type) { + nm_log_err(LOGD_MB, "ofono: context dictionary is missing required key(s)."); + return; + } + + /* Preferred property exists in some oFono fork only (mostly Ubuntu Touch's). */ + v_context_preferred = g_variant_lookup_value(v, "Preferred", G_VARIANT_TYPE_BOOLEAN); + + octx = g_slice_new0(OfonoContextData); + octx->self = self; + octx->name = g_variant_dup_string(v_context_name, NULL); + octx->type = g_variant_dup_string(v_context_type, NULL); + octx->preferred = v_context_preferred && g_variant_get_boolean(v_context_preferred); + + priv->n_context_proxy_pending++; + g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, /* GDBusInterfaceInfo */ + OFONO_DBUS_SERVICE, + object_path, + OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, + priv->connman_proxy_cancellable, + _context_proxy_new_cb, + octx); +} + +static void +connman_get_contexts_done(GObject *source, GAsyncResult *result, gpointer user_data) +{ + NMModemOfono *self; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v_contexts = NULL; + gs_unref_variant GVariant *v_objects = NULL; + gs_unref_variant GVariant *v = NULL; + GVariantIter i; + const char *object_path; + + v_contexts = _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), + result, + G_VARIANT_TYPE("(a(oa{sv}))"), + &error); + if (!v_contexts && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + + if (!v_contexts) { + g_dbus_error_strip_remote_error(error); + _LOGW("Error getting list of contexts: %s", error->message); + return; + } + + nm_log_info(LOGD_MB, "ofono: printing %s", g_variant_get_type_string(v_contexts)); + + v_objects = g_variant_get_child_value(v_contexts, 0); + + g_variant_iter_init(&i, v_objects); + while (g_variant_iter_loop(&i, "(&o@a{sv})", &object_path, &v)) + connman_context_added(NULL, object_path, v, self); +} + +static void _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) { NMModemOfono *self; @@ -548,11 +973,23 @@ _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->connman_proxy = proxy; - _nm_dbus_signal_connect(priv->connman_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(connman_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(connman_property_changed), + self); + + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "ContextAdded", + G_VARIANT_TYPE("(oa{sv})"), + G_CALLBACK(connman_context_added), + self); + + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "ContextRemoved", + G_VARIANT_TYPE("(o)"), + G_CALLBACK(connman_context_removed), + self); g_dbus_proxy_call(priv->connman_proxy, "GetProperties", @@ -562,6 +999,15 @@ _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->connman_proxy_cancellable, connman_get_properties_done, self); + + g_dbus_proxy_call(priv->connman_proxy, + "GetContexts", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 20000, + priv->connman_proxy_cancellable, + connman_get_contexts_done, + self); } static void @@ -572,6 +1018,9 @@ handle_connman_iface(NMModemOfono *self, gboolean found) _LOGD("ConnectionManager interface %sfound", found ? "" : "not "); if (!found && (priv->connman_proxy || priv->connman_proxy_cancellable)) { + GHashTableIter iter; + NMSettingsConnection *conn; + _LOGI("ConnectionManager interface disappeared"); nm_clear_g_cancellable(&priv->connman_proxy_cancellable); if (priv->connman_proxy) { @@ -584,6 +1033,18 @@ handle_connman_iface(NMModemOfono *self, gboolean found) */ priv->gprs_attached = FALSE; + g_hash_table_iter_init(&iter, priv->connections); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &conn)) { + if (NM_FLAGS_HAS(nm_settings_connection_get_flags(conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) { + nm_settings_connection_delete(conn, FALSE); + } + } + + priv->current_octx = NULL; + g_hash_table_remove_all(priv->connections); + g_hash_table_remove_all(priv->contexts); + update_modem_state(self); } else if (found && (!priv->connman_proxy && !priv->connman_proxy_cancellable)) { _LOGI("found new ConnectionManager interface"); @@ -716,7 +1177,7 @@ stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data) self = NM_MODEM_OFONO(user_data); priv = NM_MODEM_OFONO_GET_PRIVATE(self); - g_clear_object(&priv->context_proxy_cancellable); + g_clear_object(&priv->connect_cancellable); nm_clear_pointer(&priv->connect_properties, g_hash_table_destroy); @@ -730,9 +1191,8 @@ stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data) } static void -handle_settings(GVariant *v_dict, gpointer user_data) +handle_settings(NMModemOfono *self, GVariant *v_dict) { - NMModemOfono *self = NM_MODEM_OFONO(user_data); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; NMPlatformIP4Address address; @@ -744,14 +1204,20 @@ handle_settings(GVariant *v_dict, gpointer user_data) int ifindex; GError *error = NULL; - //_LOGD("PropertyChanged: %s", property); - /* * TODO: might be a good idea and re-factor this to mimic bluez-device, * ie. have this function just check the key, and call a sub-func to * handle the action. */ + if (nm_modem_get_state(NM_MODEM(self)) < NM_MODEM_STATE_REGISTERED) { + /* + * Connection definitely isn't happening. Avoid trigering bogus + * failure which would put device in a wrong state. + */ + return; + } + _LOGI("IPv4 static Settings:"); if (!g_variant_lookup(v_dict, "Interface", "&s", &interface)) { @@ -786,7 +1252,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("Settings 'Address' missing"); goto out; } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { + if (!s || !nm_inet_parse_bin(AF_INET, s, NULL, &address_network)) { _LOGW("can't convert 'Address' %s to addr", s ?: ""); goto out; } @@ -801,11 +1267,11 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("Settings 'Netmask' missing"); goto out; } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { + if (!s || !nm_inet_parse_bin(AF_INET, s, NULL, &address_network)) { _LOGW("invalid 'Netmask': %s", s ?: ""); goto out; } - address.plen = _nm_utils_ip4_netmask_to_prefix(address_network); + address.plen = nm_ip4_addr_netmask_to_prefix(address_network); _LOGI("Address: %s", nm_platform_ip4_address_to_string(&address, sbuf, sizeof(sbuf))); nm_l3_config_data_add_address_4(priv->l3cd_4, &address); @@ -814,7 +1280,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("Settings 'Gateway' missing"); goto out; } - if (!nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &gateway_network)) { + if (!nm_inet_parse_bin(AF_INET, s, NULL, &gateway_network)) { _LOGW("invalid 'Gateway': %s", s); goto out; } @@ -841,14 +1307,13 @@ handle_settings(GVariant *v_dict, gpointer user_data) gsize i; for (i = 0; array[i]; i++) { - if (!nm_utils_parse_inaddr_bin(AF_INET, array[i], NULL, &address_network) - || !address_network) { + if (!nm_inet_parse_bin(AF_INET, array[i], NULL, &address_network) || !address_network) { _LOGW("invalid NameServer: %s", array[i]); continue; } any_good = TRUE; _LOGI("DNS: %s", array[i]); - nm_l3_config_data_add_nameserver(priv->l3cd_4, AF_INET, &address_network); + nm_l3_config_data_add_nameserver_detail(priv->l3cd_4, AF_INET, &address_network, NULL); } if (!any_good) { _LOGW("Settings: 'DomainNameServers': none specified"); @@ -858,7 +1323,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) if (g_variant_lookup(v_dict, "MessageProxy", "&s", &s)) { _LOGI("MessageProxy: %s", s); - if (s && nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { + if (s && nm_inet_parse_bin(AF_INET, s, NULL, &address_network)) { const NMPlatformIP4Route mms_route = { .network = address_network, .plen = 32, @@ -893,28 +1358,6 @@ out: } static void -context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono *self = NM_MODEM_OFONO(user_data); - gs_unref_variant GVariant *v_dict = NULL; - - _LOGD("PropertyChanged: %s", property); - - if (g_strcmp0(property, "Settings") != 0) - return; - - v_dict = g_variant_get_child_value(v, 0); - if (!v_dict) { - _LOGW("ofono: (%s): error getting IPv4 Settings", nm_modem_get_uid(NM_MODEM(self))); - return; - } - - g_assert(g_variant_is_of_type(v_dict, G_VARIANT_TYPE_VARDICT)); - - handle_settings(v_dict, user_data); -} - -static void stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_method) { NMModemOfono *self = NM_MODEM_OFONO(modem); @@ -948,17 +1391,13 @@ out: static void context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - NMModemOfono *self; - NMModemOfonoPrivate *priv; + NMModemOfono *self = user_data; gs_free_error GError *error = NULL; gs_unref_variant GVariant *properties = NULL; gs_unref_variant GVariant *settings = NULL; gs_unref_variant GVariant *v_dict = NULL; gboolean active; - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - properties = g_dbus_proxy_call_finish(proxy, result, &error); if (!properties) { @@ -978,13 +1417,6 @@ context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat goto error; } - /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect(priv->context_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(context_property_changed), - self); - if (active) { _LOGD("ofono: connection is already Active"); @@ -994,9 +1426,9 @@ context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat goto error; } - handle_settings(settings, user_data); + handle_settings(self, settings); } else { - g_dbus_proxy_call(priv->context_proxy, + g_dbus_proxy_call(proxy, "SetProperty", g_variant_new("(sv)", "Active", g_variant_new("b", TRUE)), G_DBUS_CALL_FLAGS_NONE, @@ -1012,36 +1444,15 @@ error: } static void -context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) +do_context_activate(NMModemOfono *self) { - NMModemOfono *self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy *proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy || g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); + g_return_if_fail(NM_IS_MODEM_OFONO(self)); - if (!proxy) { - _LOGE("failed to create ofono ConnectionContext DBus proxy: %s", error->message); - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); - return; - } + nm_clear_g_cancellable(&priv->connect_cancellable); - priv->context_proxy = proxy; - - if (!priv->gprs_attached) { - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), - FALSE, - NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return; - } + priv->connect_cancellable = g_cancellable_new(); /* We have an old copy of the settings from a previous activation, * clear it so that we can gate getting the IP config from oFono @@ -1051,39 +1462,16 @@ context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) /* We need to directly query ConnectionContextinteface to get the current * property values */ - g_dbus_proxy_call(priv->context_proxy, + g_dbus_proxy_call(priv->current_octx->proxy, "GetProperties", NULL, G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, + priv->connect_cancellable, (GAsyncReadyCallback) context_properties_cb, self); } -static void -do_context_activate(NMModemOfono *self) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_return_if_fail(NM_IS_MODEM_OFONO(self)); - - nm_clear_g_cancellable(&priv->context_proxy_cancellable); - g_clear_object(&priv->context_proxy); - - priv->context_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - OFONO_DBUS_SERVICE, - priv->context_path, - OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, - priv->context_proxy_cancellable, - context_proxy_new_cb, - self); -} - static GHashTable * create_connect_properties(NMConnection *connection) { @@ -1109,6 +1497,20 @@ create_connect_properties(NMConnection *connection) return properties; } +static gboolean +wait_for_signal_timeout(gpointer user_data) +{ + NMModemOfono *self = NM_MODEM_OFONO(user_data); + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + nm_modem_emit_prepare_result(NM_MODEM(self), + FALSE, + NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + return G_SOURCE_REMOVE; +} + static NMActStageReturn modem_act_stage1_prepare(NMModem *modem, NMConnection *connection, @@ -1116,20 +1518,10 @@ modem_act_stage1_prepare(NMModem *modem, { NMModemOfono *self = NM_MODEM_OFONO(modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char *context_id; - char **id = NULL; + const char *uuid = nm_connection_get_uuid(connection); + OfonoContextData *octx = g_hash_table_lookup(priv->contexts, uuid); - context_id = nm_connection_get_id(connection); - id = g_strsplit(context_id, "/", 0); - g_return_val_if_fail(id[2], NM_ACT_STAGE_RETURN_FAILURE); - - _LOGD("trying %s %s", id[1], id[2]); - - g_free(priv->context_path); - priv->context_path = g_strdup_printf("%s/%s", nm_modem_get_path(modem), id[2]); - g_strfreev(id); - - if (!priv->context_path) { + if (!octx) { NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_GSM_APN_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -1139,11 +1531,19 @@ modem_act_stage1_prepare(NMModem *modem, priv->connect_properties = create_connect_properties(connection); - _LOGI("activating context %s", priv->context_path); + _LOGI("activating context %s", g_dbus_proxy_get_object_path(octx->proxy)); + priv->current_octx = octx; update_modem_state(self); if (nm_modem_get_state(modem) == NM_MODEM_STATE_REGISTERED) { do_context_activate(self); + } else if (nm_modem_get_state(modem) == NM_MODEM_STATE_SEARCHING) { + _LOGI("activation deferred while modem is searching for signal."); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + priv->deferred_connection_timeout_source = + nm_g_timeout_add_seconds_source(60 /* seconds */, wait_for_signal_timeout, self); + /* update_modem_state() will advance the next step. */ } else { _LOGW("could not activate context: modem is not registered."); NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); @@ -1176,11 +1576,11 @@ modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->modem_proxy = proxy; - _nm_dbus_signal_connect(priv->modem_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(modem_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->modem_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(modem_property_changed), + self); g_dbus_proxy_call(priv->modem_proxy, "GetProperties", @@ -1196,7 +1596,17 @@ modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) static void nm_modem_ofono_init(NMModemOfono *self) -{} +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + priv->modem_proxy_cancellable = g_cancellable_new(); + priv->connections = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref); + priv->contexts = g_hash_table_new_full(nm_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) ofono_context_data_free); + priv->settings = g_object_ref(NM_SETTINGS_GET); +} static void constructed(GObject *object) @@ -1204,8 +1614,6 @@ constructed(GObject *object) NMModemOfono *self = NM_MODEM_OFONO(object); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - priv->modem_proxy_cancellable = g_cancellable_new(); - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, @@ -1257,7 +1665,7 @@ dispose(GObject *object) nm_clear_g_cancellable(&priv->modem_proxy_cancellable); nm_clear_g_cancellable(&priv->connman_proxy_cancellable); - nm_clear_g_cancellable(&priv->context_proxy_cancellable); + nm_clear_g_cancellable(&priv->connect_cancellable); nm_clear_g_cancellable(&priv->sim_proxy_cancellable); if (priv->connect_properties) { @@ -1265,6 +1673,16 @@ dispose(GObject *object) priv->connect_properties = NULL; } + if (priv->connections) { + g_hash_table_destroy(priv->connections); + priv->connections = NULL; + } + + if (priv->contexts) { + g_hash_table_destroy(priv->contexts); + priv->contexts = NULL; + } + nm_clear_l3cd(&priv->l3cd_4); if (priv->modem_proxy) { @@ -1277,19 +1695,21 @@ dispose(GObject *object) g_clear_object(&priv->connman_proxy); } - if (priv->context_proxy) { - g_signal_handlers_disconnect_by_data(priv->context_proxy, self); - g_clear_object(&priv->context_proxy); - } - if (priv->sim_proxy) { g_signal_handlers_disconnect_by_data(priv->sim_proxy, self); g_clear_object(&priv->sim_proxy); } + if (priv->settings) { + g_signal_handlers_disconnect_by_data(priv->settings, self); + g_clear_object(&priv->settings); + } + g_free(priv->imsi); priv->imsi = NULL; + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + G_OBJECT_CLASS(nm_modem_ofono_parent_class)->dispose(object); } diff --git a/src/core/devices/wwan/nm-modem-ofono.h b/src/core/devices/wwan/nm-modem-ofono.h index ebe21023..02ba49ad 100644 --- a/src/core/devices/wwan/nm-modem-ofono.h +++ b/src/core/devices/wwan/nm-modem-ofono.h @@ -8,8 +8,9 @@ #include "nm-modem.h" -#define NM_TYPE_MODEM_OFONO (nm_modem_ofono_get_type()) -#define NM_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_OFONO, NMModemOfono)) +#define NM_TYPE_MODEM_OFONO (nm_modem_ofono_get_type()) +#define NM_MODEM_OFONO(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_OFONO, NMModemOfono)) #define NM_IS_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_OFONO)) #define NM_MODEM_OFONO_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_OFONO, NMModemOfonoClass)) diff --git a/src/core/devices/wwan/nm-modem.c b/src/core/devices/wwan/nm-modem.c index a5ee8ce8..0159d351 100644 --- a/src/core/devices/wwan/nm-modem.c +++ b/src/core/devices/wwan/nm-modem.c @@ -353,6 +353,12 @@ nm_modem_set_mm_enabled(NMModem *self, gboolean enabled) NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); NMModemState prev_state = priv->state; + /* Not all modem classes support set_mm_enabled */ + if (!NM_MODEM_GET_CLASS(self)->set_mm_enabled) { + _LOGD("cannot enable modem: not implemented"); + return; + } + if (enabled && priv->state >= NM_MODEM_STATE_ENABLING) { _LOGD("cannot enable modem: already enabled"); return; @@ -375,9 +381,7 @@ nm_modem_set_mm_enabled(NMModem *self, gboolean enabled) return; } - /* Not all modem classes support set_mm_enabled */ - if (NM_MODEM_GET_CLASS(self)->set_mm_enabled) - NM_MODEM_GET_CLASS(self)->set_mm_enabled(self, enabled); + NM_MODEM_GET_CLASS(self)->set_mm_enabled(self, enabled); /* Pre-empt the state change signal */ nm_modem_set_state(self, diff --git a/src/core/devices/wwan/nm-modem.h b/src/core/devices/wwan/nm-modem.h index ca541073..ec001102 100644 --- a/src/core/devices/wwan/nm-modem.h +++ b/src/core/devices/wwan/nm-modem.h @@ -11,7 +11,7 @@ #include "devices/nm-device.h" #define NM_TYPE_MODEM (nm_modem_get_type()) -#define NM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM, NMModem)) +#define NM_MODEM(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM, NMModem)) #define NM_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM, NMModemClass)) #define NM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM)) #define NM_IS_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM)) diff --git a/src/core/devices/wwan/nm-wwan-factory.c b/src/core/devices/wwan/nm-wwan-factory.c index 169407c7..1c6d351f 100644 --- a/src/core/devices/wwan/nm-wwan-factory.c +++ b/src/core/devices/wwan/nm-wwan-factory.c @@ -18,7 +18,7 @@ #define NM_TYPE_WWAN_FACTORY (nm_wwan_factory_get_type()) #define NM_WWAN_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) #define NM_WWAN_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WWAN_FACTORY, NMWwanFactoryClass)) #define NM_IS_WWAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WWAN_FACTORY)) |