diff options
Diffstat (limited to 'src/devices/wwan')
-rw-r--r-- | src/devices/wwan/Makefile.in | 30 | ||||
-rw-r--r-- | src/devices/wwan/nm-device-modem.c | 71 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem-broadband.c | 385 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem.c | 310 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem.h | 24 | ||||
-rw-r--r-- | src/devices/wwan/wwan-exports.ver | 2 |
6 files changed, 602 insertions, 220 deletions
diff --git a/src/devices/wwan/Makefile.in b/src/devices/wwan/Makefile.in index 18cbfdd37..1a8aef3b6 100644 --- a/src/devices/wwan/Makefile.in +++ b/src/devices/wwan/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2013 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -15,7 +15,17 @@ @SET_MAKE@ VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ @@ -79,8 +89,6 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/devices/wwan -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/compiler_warnings.m4 \ @@ -97,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ $(top_srcdir)/m4/vapigen.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -216,6 +225,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -242,7 +253,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_GLIB_100_CFLAGS = @DBUS_GLIB_100_CFLAGS@ DBUS_GLIB_100_LIBS = @DBUS_GLIB_100_LIBS@ @@ -277,6 +287,7 @@ GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ GNUTLS_LIBS = @GNUTLS_LIBS@ GREP = @GREP@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ GTKDOC_MKPDF = @GTKDOC_MKPDF@ @@ -553,7 +564,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wwan/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/devices/wwan/Makefile -.PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ @@ -631,14 +641,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -866,6 +876,8 @@ uninstall-am: uninstall-pkglibLTLIBRARIES mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkglibLTLIBRARIES +.PRECIOUS: Makefile + include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index f681e59ca..f819d1d77 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -295,16 +295,19 @@ modem_state_cb (NMModem *modem, * device's enabled/disabled state. */ nm_modem_set_mm_enabled (priv->modem, priv->rf_enabled); + + /* Now allow connections without a PIN to be available */ + nm_device_recheck_available_connections (device); } - if ((dev_state >= NM_DEVICE_STATE_DISCONNECTED) && !nm_device_is_available (device)) { + if ((dev_state >= NM_DEVICE_STATE_DISCONNECTED) && !nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_MODEM_FAILED); return; } - if ((dev_state == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device)) { + if ((dev_state == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { nm_device_state_changed (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_MODEM_AVAILABLE); @@ -391,6 +394,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) static gboolean check_connection_available (NMDevice *device, NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, const char *specific_object) { NMDeviceModem *self = NM_DEVICE_MODEM (device); @@ -433,6 +437,50 @@ deactivate (NMDevice *device) nm_modem_deactivate (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device); } +/***********************************************************/ + +static gboolean +deactivate_async_finish (NMDevice *self, + GAsyncResult *res, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); +} + +static void +modem_deactivate_async_ready (NMModem *modem, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + + if (!nm_modem_deactivate_async_finish (modem, res, &error)) + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +deactivate_async (NMDevice *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + simple = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + deactivate_async); + nm_modem_deactivate_async (NM_DEVICE_MODEM_GET_PRIVATE (self)->modem, + self, + cancellable, + (GAsyncReadyCallback) modem_deactivate_async_ready, + simple); +} + +/***********************************************************/ + static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { @@ -536,24 +584,19 @@ set_enabled (NMDevice *device, gboolean enabled) } static gboolean -is_available (NMDevice *device) +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { NMDeviceModem *self = NM_DEVICE_MODEM (device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); NMModemState modem_state; - if (!priv->rf_enabled) { - _LOGD (LOGD_MB, "not available because WWAN airplane mode is on"); + if (!priv->rf_enabled) return FALSE; - } g_assert (priv->modem); modem_state = nm_modem_get_state (priv->modem); - if (modem_state <= NM_MODEM_STATE_INITIALIZING) { - _LOGD (LOGD_MB, "not available because modem is not ready (%s)", - nm_modem_state_to_string (modem_state)); + if (modem_state <= NM_MODEM_STATE_INITIALIZING) return FALSE; - } return TRUE; } @@ -638,7 +681,7 @@ set_modem (NMDeviceModem *self, NMModem *modem) static void set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) + const GValue *value, GParamSpec *pspec) { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); @@ -661,7 +704,7 @@ set_property (GObject *object, guint prop_id, static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object); @@ -711,6 +754,8 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; + device_class->deactivate_async = deactivate_async; + device_class->deactivate_async_finish = deactivate_async_finish; device_class->deactivate = deactivate; device_class->act_stage1_prepare = act_stage1_prepare; device_class->act_stage2_config = act_stage2_config; diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index f8239b799..4bb72fd19 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -42,7 +42,7 @@ struct _NMModemBroadbandPrivate { MMModemSimple *simple_iface; /* Connection setup */ - MMSimpleConnectProperties *connect_properties; + MMBearer *bearer; MMBearerIpConfig *ipv4_config; MMBearerIpConfig *ipv6_config; @@ -176,78 +176,6 @@ get_bearer_ip_method (MMBearerIpConfig *config) return NM_MODEM_IP_METHOD_UNKNOWN; } -static void -connect_ready (MMModemSimple *simple_iface, - GAsyncResult *res, - NMModemBroadband *self) -{ - GError *error = NULL; - NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; - NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - - g_clear_object (&self->priv->connect_properties); - - self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error); - if (!self->priv->bearer) { - if (g_error_matches (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) || - (g_error_matches (error, - MM_CORE_ERROR, - MM_CORE_ERROR_UNAUTHORIZED) && - mm_modem_get_unlock_required (self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { - /* Request PIN */ - ask_for_pin (self); - } else { - /* Strip remote error info before logging it */ - if (g_dbus_error_is_remote_error (error)) - g_dbus_error_strip_remote_error (error); - - nm_log_warn (LOGD_MB, "(%s) failed to connect modem: %s", - nm_modem_get_uid (NM_MODEM (self)), - error && error->message ? error->message : "(unknown)"); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); - } - - g_clear_error (&error); - g_object_unref (self); - return; - } - - /* Grab IP configurations */ - self->priv->ipv4_config = mm_bearer_get_ipv4_config (self->priv->bearer); - if (self->priv->ipv4_config) - ip4_method = get_bearer_ip_method (self->priv->ipv4_config); - - self->priv->ipv6_config = mm_bearer_get_ipv6_config (self->priv->bearer); - if (self->priv->ipv6_config) - ip6_method = get_bearer_ip_method (self->priv->ipv6_config); - - if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN && - ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) { - nm_log_warn (LOGD_MB, "(%s) failed to connect modem: invalid bearer IP configuration", - nm_modem_get_uid (NM_MODEM (self))); - - error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "invalid bearer IP configuration"); - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, error); - g_error_free (error); - g_object_unref (self); - return; - } - - g_object_set (self, - NM_MODEM_DATA_PORT, mm_bearer_get_interface (self->priv->bearer), - NM_MODEM_IP4_METHOD, ip4_method, - NM_MODEM_IP6_METHOD, ip6_method, - NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (self->priv->bearer), - NULL); - - g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); - g_object_unref (self); -} - static MMSimpleConnectProperties * create_cdma_connect_properties (NMConnection *connection) { @@ -266,15 +194,12 @@ create_cdma_connect_properties (NMConnection *connection) } static MMSimpleConnectProperties * -create_gsm_connect_properties (NMModem *modem, - NMConnection *connection, - GError **error) +create_gsm_connect_properties (NMConnection *connection) { NMSettingGsm *setting; NMSettingPpp *s_ppp; MMSimpleConnectProperties *properties; const gchar *str; - NMModemIPType ip_type; setting = nm_connection_get_setting_gsm (connection); properties = mm_simple_connect_properties_new (); @@ -329,23 +254,137 @@ create_gsm_connect_properties (NMModem *modem, mm_simple_connect_properties_set_allowed_auth (properties, allowed_auth); } - /* Determine IP types to use when connecting */ - ip_type = nm_modem_get_connection_ip_type (modem, connection, error); - if (ip_type == NM_MODEM_IP_TYPE_UNKNOWN) { - g_object_unref (properties); - return NULL; + return properties; +} + +typedef struct { + NMModemBroadband *self; + MMModemCapability caps; + MMSimpleConnectProperties *connect_properties; + GArray *ip_types; + guint ip_types_i; + GError *first_error; +} ActStageContext; + +static void +act_stage_context_free (ActStageContext *ctx) +{ + g_clear_error (&ctx->first_error); + g_clear_pointer (&ctx->ip_types, (GDestroyNotify) g_array_unref); + g_clear_object (&ctx->connect_properties); + g_object_unref (ctx->self); + g_slice_free (ActStageContext, ctx); +} + +static void act_stage_context_step (ActStageContext *ctx); + +static void +connect_ready (MMModemSimple *simple_iface, + GAsyncResult *res, + ActStageContext *ctx) +{ + GError *error = NULL; + NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; + NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; + + ctx->self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error); + if (!ctx->self->priv->bearer) { + if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) || + (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) && + mm_modem_get_unlock_required (ctx->self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { + /* Request PIN */ + ask_for_pin (ctx->self); + g_error_free (error); + act_stage_context_free (ctx); + return; + } + + /* Save the error, if it's the first one */ + if (!ctx->first_error) { + /* Strip remote error info before saving it */ + if (g_dbus_error_is_remote_error (error)) + g_dbus_error_strip_remote_error (error); + ctx->first_error = error; + } else + g_error_free (error); + + /* If the modem/provider lies and the IP type we tried isn't supported, + * retry with the next one, if any. + */ + ctx->ip_types_i++; + act_stage_context_step (ctx); + return; } - if (ip_type == NM_MODEM_IP_TYPE_IPV4) - mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV4); - else if (ip_type == NM_MODEM_IP_TYPE_IPV6) - mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV6); - else if (ip_type == NM_MODEM_IP_TYPE_IPV4V6) - mm_simple_connect_properties_set_ip_type (properties, MM_BEARER_IP_FAMILY_IPV4V6); - else - g_assert_not_reached (); + /* Grab IP configurations */ + ctx->self->priv->ipv4_config = mm_bearer_get_ipv4_config (ctx->self->priv->bearer); + if (ctx->self->priv->ipv4_config) + ip4_method = get_bearer_ip_method (ctx->self->priv->ipv4_config); - return properties; + ctx->self->priv->ipv6_config = mm_bearer_get_ipv6_config (ctx->self->priv->bearer); + if (ctx->self->priv->ipv6_config) + ip6_method = get_bearer_ip_method (ctx->self->priv->ipv6_config); + + if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN && + ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) { + nm_log_warn (LOGD_MB, "(%s): failed to connect modem: invalid bearer IP configuration", + nm_modem_get_uid (NM_MODEM (ctx->self))); + g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + act_stage_context_free (ctx); + return; + } + + g_object_set (ctx->self, + NM_MODEM_DATA_PORT, mm_bearer_get_interface (ctx->self->priv->bearer), + NM_MODEM_IP4_METHOD, ip4_method, + NM_MODEM_IP6_METHOD, ip6_method, + NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (ctx->self->priv->bearer), + NULL); + + g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); + act_stage_context_free (ctx); +} + +static void +act_stage_context_step (ActStageContext *ctx) +{ + if (ctx->ip_types_i < ctx->ip_types->len) { + NMModemIPType current; + + current = 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, MM_BEARER_IP_FAMILY_IPV4); + else if (current == NM_MODEM_IP_TYPE_IPV6) + mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV6); + else if (current == NM_MODEM_IP_TYPE_IPV4V6) + mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4V6); + else + g_assert_not_reached (); + + nm_log_dbg (LOGD_MB, "(%s): launching connection with ip type '%s'", + nm_modem_get_uid (NM_MODEM (ctx->self)), + nm_modem_ip_type_to_string (current)); + + mm_modem_simple_connect (ctx->self->priv->simple_iface, + ctx->connect_properties, + NULL, + (GAsyncReadyCallback)connect_ready, + ctx); + return; + } + + /* If we have a saved error from a previous attempt, use it */ + if (!ctx->first_error) + ctx->first_error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "invalid bearer IP configuration"); + + nm_log_warn (LOGD_MB, "(%s): failed to connect modem: %s", + nm_modem_get_uid (NM_MODEM (ctx->self)), + ctx->first_error->message); + g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (ctx->first_error)); + act_stage_context_free (ctx); } static NMActStageReturn @@ -354,42 +393,55 @@ act_stage1_prepare (NMModem *_self, NMDeviceStateReason *reason) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - MMModemCapability caps; + ActStageContext *ctx; GError *error = NULL; - g_clear_object (&self->priv->connect_properties); + /* Make sure we can get the Simple interface from the modem */ + if (!self->priv->simple_iface) { + self->priv->simple_iface = mm_object_get_modem_simple (self->priv->modem_object); + if (!self->priv->simple_iface) { + nm_log_warn (LOGD_MB, "(%s) cannot access the Simple mobile broadband modem interface", + nm_modem_get_uid (NM_MODEM (self))); + *reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; + return NM_ACT_STAGE_RETURN_FAILURE; + } + } + + /* Allocate new context for this activation stage attempt */ + ctx = g_slice_new0 (ActStageContext); + ctx->self = NM_MODEM_BROADBAND (g_object_ref (self)); + ctx->caps = mm_modem_get_current_capabilities (self->priv->modem_iface); - caps = mm_modem_get_current_capabilities (self->priv->modem_iface); - if (MODEM_CAPS_3GPP (caps)) - self->priv->connect_properties = create_gsm_connect_properties (_self, connection, &error); - else if (MODEM_CAPS_3GPP2 (caps)) - self->priv->connect_properties = create_cdma_connect_properties (connection); + /* Create core connect properties based on the modem capabilities */ + if (MODEM_CAPS_3GPP (ctx->caps)) + ctx->connect_properties = create_gsm_connect_properties (connection); + else if (MODEM_CAPS_3GPP2 (ctx->caps)) + ctx->connect_properties = create_cdma_connect_properties (connection); else { - nm_log_warn (LOGD_MB, "(%s) not a mobile broadband modem", - nm_modem_get_uid (NM_MODEM (self))); + nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': not a mobile broadband modem", + nm_modem_get_uid (NM_MODEM (self)), + nm_connection_get_id (connection)); + act_stage_context_free (ctx); *reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; return NM_ACT_STAGE_RETURN_FAILURE; } + g_assert (ctx->connect_properties); - if (error) { + /* Checkout list of IP types that we need to use in the retries */ + ctx->ip_types = nm_modem_get_connection_ip_type (NM_MODEM (self), connection, &error); + if (!ctx->ip_types) { nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': %s", nm_modem_get_uid (NM_MODEM (self)), nm_connection_get_id (connection), - error->message); + error ? error->message : "unknown error"); g_clear_error (&error); + act_stage_context_free (ctx); *reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; return NM_ACT_STAGE_RETURN_FAILURE; } - if (!self->priv->simple_iface) - self->priv->simple_iface = mm_object_get_modem_simple (self->priv->modem_object); - g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (self->priv->simple_iface), MODEM_CONNECT_TIMEOUT_SECS * 1000); - mm_modem_simple_connect (self->priv->simple_iface, - self->priv->connect_properties, - NULL, - (GAsyncReadyCallback)connect_ready, - g_object_ref (self)); + act_stage_context_step (ctx); return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -566,9 +618,9 @@ set_power_state_low_ready (MMModem *modem, if (!mm_modem_set_power_state_finish (modem, result, &error)) { /* Log but ignore errors; not all modems support low power state */ - nm_log_dbg (LOGD_MB, "(%s) failed to set modem low power state: %s", - nm_modem_get_uid (NM_MODEM (self)), - error && error->message ? error->message : "(unknown)"); + nm_log_dbg (LOGD_MB, "(%s): failed to set modem low power state: %s", + nm_modem_get_uid (NM_MODEM (self)), + error && error->message ? error->message : "(unknown)"); g_clear_error (&error); } @@ -591,7 +643,7 @@ modem_disable_ready (MMModem *modem_iface, (GAsyncReadyCallback) set_power_state_low_ready, g_object_ref (self)); } else { - nm_log_warn (LOGD_MB, "(%s) failed to disable modem: %s", + nm_log_warn (LOGD_MB, "(%s): failed to disable modem: %s", nm_modem_get_uid (NM_MODEM (self)), error && error->message ? error->message : "(unknown)"); nm_modem_set_prev_state (NM_MODEM (self), "disable failed"); @@ -708,7 +760,7 @@ static_stage3_ip4_done (NMModemBroadband *self) /* DNS servers */ dns = mm_bearer_ip_config_get_dns (self->priv->ipv4_config); - for (i = 0; dns[i]; i++) { + for (i = 0; dns && dns[i]; i++) { if ( ip4_string_to_num (dns[i], &address_network) && address_network > 0) { nm_ip4_config_add_nameserver (config, address_network); @@ -761,9 +813,9 @@ stage3_ip6_done (NMModemBroadband *self) /* DHCP/SLAAC is allowed to skip addresses; other methods require it */ if (ip_method != NM_MODEM_IP_METHOD_AUTO) { error = g_error_new (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: no address given", - nm_modem_get_uid (NM_MODEM (self))); + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IPv6 configuration failed: no address given", + nm_modem_get_uid (NM_MODEM (self))); } goto out; } @@ -792,10 +844,10 @@ stage3_ip6_done (NMModemBroadband *self) if (address_string) { if (!inet_pton (AF_INET6, address_string, (void *) &(address.address))) { error = g_error_new (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", - nm_modem_get_uid (NM_MODEM (self)), - address_string); + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", + nm_modem_get_uid (NM_MODEM (self)), + address_string); goto out; } nm_log_info (LOGD_MB, " gateway %s", address_string); @@ -844,20 +896,47 @@ stage3_ip6_config_request (NMModem *_self, NMDeviceStateReason *reason) typedef struct { NMModemBroadband *self; + GSimpleAsyncResult *result; + GCancellable *cancellable; gboolean warn; -} SimpleDisconnectContext; +} DisconnectContext; static void -simple_disconnect_context_free (SimpleDisconnectContext *ctx) +disconnect_context_complete (DisconnectContext *ctx) { + g_simple_async_result_complete_in_idle (ctx->result); + if (ctx->cancellable) + g_object_unref (ctx->cancellable); + g_object_unref (ctx->result); g_object_unref (ctx->self); - g_slice_free (SimpleDisconnectContext, ctx); + g_slice_free (DisconnectContext, ctx); +} + +static gboolean +disconnect_context_complete_if_cancelled (DisconnectContext *ctx) +{ + GError *error = NULL; + + if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) { + g_simple_async_result_take_error (ctx->result, error); + disconnect_context_complete (ctx); + return TRUE; + } + return FALSE; +} + +static gboolean +disconnect_finish (NMModem *self, + GAsyncResult *res, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); } static void simple_disconnect_ready (MMModemSimple *modem_iface, GAsyncResult *res, - SimpleDisconnectContext *ctx) + DisconnectContext *ctx) { GError *error = NULL; @@ -865,33 +944,48 @@ simple_disconnect_ready (MMModemSimple *modem_iface, if (ctx->warn) nm_log_warn (LOGD_MB, "(%s) failed to disconnect modem: %s", nm_modem_get_uid (NM_MODEM (ctx->self)), - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); + error->message); + g_simple_async_result_take_error (ctx->result, error); } - simple_disconnect_context_free (ctx); + disconnect_context_complete (ctx); } static void -disconnect (NMModem *modem, - gboolean warn) +disconnect (NMModem *self, + gboolean warn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - NMModemBroadband *self = NM_MODEM_BROADBAND (modem); - SimpleDisconnectContext *ctx; - - if (!self->priv->simple_iface) - return; + DisconnectContext *ctx; - ctx = g_slice_new (SimpleDisconnectContext); + ctx = g_slice_new (DisconnectContext); ctx->self = g_object_ref (self); - + ctx->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + disconnect); /* Don't bother warning on FAILED since the modem is already gone */ ctx->warn = warn; + /* Setup cancellable */ + ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + if (disconnect_context_complete_if_cancelled (ctx)) + return; + + /* If no simple iface, we're done */ + if (!ctx->self->priv->simple_iface) { + disconnect_context_complete (ctx); + return; + } + + nm_log_dbg (LOGD_MB, "(%s): notifying ModemManager about the modem disconnection", + nm_modem_get_uid (NM_MODEM (ctx->self))); mm_modem_simple_disconnect ( ctx->self->priv->simple_iface, NULL, /* bearer path; if NULL given ALL get disconnected */ - NULL, /* cancellable */ + cancellable, (GAsyncReadyCallback)simple_disconnect_ready, ctx); } @@ -899,7 +993,7 @@ disconnect (NMModem *modem, /*****************************************************************************/ static void -deactivate (NMModem *_self, NMDevice *device) +deactivate_cleanup (NMModem *_self, NMDevice *device) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); @@ -913,7 +1007,7 @@ deactivate (NMModem *_self, NMDevice *device) self->priv->pin_tries = 0; /* Chain up parent's */ - NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate (_self, device); + NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate_cleanup (_self, device); } /*****************************************************************************/ @@ -1027,7 +1121,7 @@ get_sim_ready (MMModem *modem, NULL); g_object_unref (new_sim); } else { - nm_log_warn (LOGD_MB, "(%s) failed to retrieve SIM object: %s", + nm_log_warn (LOGD_MB, "(%s): failed to retrieve SIM object: %s", nm_modem_get_uid (NM_MODEM (self)), error && error->message ? error->message : "(unknown)"); } @@ -1062,7 +1156,7 @@ nm_modem_broadband_init (NMModemBroadband *self) static void set_property (GObject *object, guint prop_id, - const GValue *value, + const GValue *value, GParamSpec *pspec) { NMModemBroadband *self = NM_MODEM_BROADBAND (object); @@ -1095,7 +1189,7 @@ set_property (GObject *object, static void get_property (GObject *object, guint prop_id, - GValue *value, + GValue *value, GParamSpec *pspec) { NMModemBroadband *self = NM_MODEM_BROADBAND (object); @@ -1142,7 +1236,8 @@ nm_modem_broadband_class_init (NMModemBroadbandClass *klass) modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; modem_class->stage3_ip6_config_request = stage3_ip6_config_request; modem_class->disconnect = disconnect; - modem_class->deactivate = deactivate; + modem_class->disconnect_finish = disconnect_finish; + modem_class->deactivate_cleanup = deactivate_cleanup; modem_class->set_mm_enabled = set_mm_enabled; modem_class->get_user_pass = get_user_pass; modem_class->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index ba1db8a4e..69eaddf3c 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -175,23 +175,23 @@ nm_modem_set_mm_enabled (NMModem *self, NMModemState prev_state = priv->state; if (enabled && priv->state >= NM_MODEM_STATE_ENABLING) { - nm_log_dbg (LOGD_MB, "(%s) cannot enable modem: already enabled", + nm_log_dbg (LOGD_MB, "(%s): cannot enable modem: already enabled", nm_modem_get_uid (self)); return; } if (!enabled && priv->state <= NM_MODEM_STATE_DISABLING) { - nm_log_dbg (LOGD_MB, "(%s) cannot disable modem: already disabled", + nm_log_dbg (LOGD_MB, "(%s): cannot disable modem: already disabled", nm_modem_get_uid (self)); return; } if (priv->state <= NM_MODEM_STATE_INITIALIZING) { - nm_log_dbg (LOGD_MB, "(%s) cannot enable/disable modem: initializing or failed", + nm_log_dbg (LOGD_MB, "(%s): cannot enable/disable modem: initializing or failed", nm_modem_get_uid (self)); return; } else if (priv->state == NM_MODEM_STATE_LOCKED) { /* Don't try to enable if the modem is locked since that will fail */ - nm_log_warn (LOGD_MB, "(%s) cannot enable/disable modem: locked", + nm_log_warn (LOGD_MB, "(%s): cannot enable/disable modem: locked", nm_modem_get_uid (self)); /* Try to unlock the modem if it's being enabled */ @@ -221,17 +221,39 @@ nm_modem_get_supported_ip_types (NMModem *self) return NM_MODEM_GET_PRIVATE (self)->ip_types; } +const gchar * +nm_modem_ip_type_to_string (NMModemIPType ip_type) +{ + switch (ip_type) { + case NM_MODEM_IP_TYPE_IPV4: + return "ipv4"; + case NM_MODEM_IP_TYPE_IPV6: + return "ipv6"; + case NM_MODEM_IP_TYPE_IPV4V6: + return "ipv4v6"; + default: + g_return_val_if_reached ("unknown"); + } +} + +static GArray * +build_single_ip_type_array (NMModemIPType type) +{ + return g_array_append_val (g_array_sized_new (FALSE, FALSE, sizeof (NMModemIPType), 1), type); +} + /** * nm_modem_get_connection_ip_type: * @self: the #NMModem * @connection: the #NMConnection to determine IP type to use * - * Given a modem and a connection, determine which NMModemIpType to use + * Given a modem and a connection, determine which #NMModemIPTypes to use * when connecting. * - * Returns: a single %NMModemIpType value + * Returns: an array of #NMModemIpType values, in the order in which they + * should be tried. */ -NMModemIPType +GArray * nm_modem_get_connection_ip_type (NMModem *self, NMConnection *connection, GError **error) @@ -265,9 +287,9 @@ nm_modem_get_connection_ip_type (NMModem *self, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection requested IPv4 but IPv4 is " "unsuported by the modem."); - return NM_MODEM_IP_TYPE_UNKNOWN; + return NULL; } - return NM_MODEM_IP_TYPE_IPV4; + return build_single_ip_type_array (NM_MODEM_IP_TYPE_IPV4); } if (ip6 && !ip4) { @@ -277,38 +299,54 @@ nm_modem_get_connection_ip_type (NMModem *self, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection requested IPv6 but IPv6 is " "unsuported by the modem."); - return NM_MODEM_IP_TYPE_UNKNOWN; + return NULL; } - return NM_MODEM_IP_TYPE_IPV6; + return build_single_ip_type_array (NM_MODEM_IP_TYPE_IPV6); } if (ip4 && ip6) { - /* Modem supports dual-stack */ - if (priv->ip_types & NM_MODEM_IP_TYPE_IPV4V6) - return NM_MODEM_IP_TYPE_IPV4V6; + NMModemIPType type; + GArray *out; - /* Both IPv4 and IPv6 requested, but modem doesn't support dual-stack; - * if one method is marked "may-fail" then use the other. - */ - if (ip6_may_fail) - return NM_MODEM_IP_TYPE_IPV4; - else if (ip4_may_fail) - return NM_MODEM_IP_TYPE_IPV6; + out = g_array_sized_new (FALSE, FALSE, sizeof (NMModemIPType), 3); + /* Modem supports dual-stack? */ + if (priv->ip_types & NM_MODEM_IP_TYPE_IPV4V6) { + type = NM_MODEM_IP_TYPE_IPV4V6; + g_array_append_val (out, type); + } + + /* If IPv6 may-fail=false, we should NOT try IPv4 as fallback */ + if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV4) && ip6_may_fail) { + type = NM_MODEM_IP_TYPE_IPV4; + g_array_append_val (out, type); + } + + /* If IPv4 may-fail=false, we should NOT try IPv6 as fallback */ + if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV6) && ip4_may_fail) { + type = NM_MODEM_IP_TYPE_IPV6; + g_array_append_val (out, type); + } + + if (out->len > 0) + return out; + + /* Error... */ + g_array_unref (out); g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection requested both IPv4 and IPv6 " "but dual-stack addressing is unsupported " "by the modem."); - return NM_MODEM_IP_TYPE_UNKNOWN; + return NULL; } g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection specified no IP configuration!"); - return NM_MODEM_IP_TYPE_UNKNOWN; + return NULL; } /*****************************************************************************/ @@ -343,9 +381,9 @@ set_data_port (NMModem *self, const char *new_data_port) static void ppp_ip4_config (NMPPPManager *ppp_manager, - const char *iface, - NMIP4Config *config, - gpointer user_data) + const char *iface, + NMIP4Config *config, + gpointer user_data) { NMModem *self = NM_MODEM (user_data); guint32 i, num; @@ -416,9 +454,9 @@ ppp_ip6_config (NMPPPManager *ppp_manager, static void ppp_stats (NMPPPManager *ppp_manager, - guint32 in_bytes, - guint32 out_bytes, - gpointer user_data) + guint32 in_bytes, + guint32 out_bytes, + gpointer user_data) { NMModem *self = NM_MODEM (user_data); NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); @@ -464,7 +502,8 @@ ppp_stage3_ip_config_start (NMModem *self, /* Check if ModemManager requested a specific IP timeout to be used. If 0 reported, * use the default one (30s) */ if (priv->mm_ip_timeout > 0) { - nm_log_info (LOGD_PPP, "using modem-specified IP timeout: %u seconds", + nm_log_info (LOGD_PPP, "(%s): using modem-specified IP timeout: %u seconds", + nm_modem_get_uid (self), priv->mm_ip_timeout); ip_timeout = priv->mm_ip_timeout; } @@ -486,7 +525,8 @@ ppp_stage3_ip_config_start (NMModem *self, ret = NM_ACT_STAGE_RETURN_POSTPONE; } else { - nm_log_err (LOGD_PPP, "error starting PPP: (%d) %s", + nm_log_err (LOGD_PPP, "(%s): error starting PPP: (%d) %s", + nm_modem_get_uid (self), error ? error->code : -1, error && error->message ? error->message : "(unknown)"); g_error_free (error); @@ -705,7 +745,7 @@ modem_secrets_cb (NMActRequest *req, priv->secrets_id = 0; if (error) - nm_log_warn (LOGD_MB, "%s", error->message); + nm_log_warn (LOGD_MB, "(%s): %s", nm_modem_get_uid (self), error->message); g_signal_emit (self, signals[AUTH_RESULT], 0, error); } @@ -839,13 +879,12 @@ nm_modem_complete_connection (NMModem *self, /*****************************************************************************/ static void -deactivate (NMModem *self, NMDevice *device) +deactivate_cleanup (NMModem *self, NMDevice *device) { NMModemPrivate *priv; int ifindex; g_return_if_fail (NM_IS_MODEM (self)); - g_return_if_fail (NM_IS_DEVICE (device)); priv = NM_MODEM_GET_PRIVATE (self); @@ -864,15 +903,19 @@ deactivate (NMModem *self, NMDevice *device) priv->ppp_manager = NULL; } - if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC || - priv->ip4_method == NM_MODEM_IP_METHOD_AUTO || - priv->ip6_method == NM_MODEM_IP_METHOD_STATIC || - priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) { - ifindex = nm_device_get_ip_ifindex (device); - if (ifindex > 0) { - nm_platform_route_flush (ifindex); - nm_platform_address_flush (ifindex); - nm_platform_link_set_down (ifindex); + if (device) { + g_return_if_fail (NM_IS_DEVICE (device)); + + if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC || + priv->ip4_method == NM_MODEM_IP_METHOD_AUTO || + priv->ip6_method == NM_MODEM_IP_METHOD_STATIC || + priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) { + ifindex = nm_device_get_ip_ifindex (device); + if (ifindex > 0) { + nm_platform_route_flush (ifindex); + nm_platform_address_flush (ifindex); + nm_platform_link_set_down (ifindex); + } } } priv->ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; @@ -884,10 +927,176 @@ deactivate (NMModem *self, NMDevice *device) /*****************************************************************************/ +typedef enum { + DEACTIVATE_CONTEXT_STEP_FIRST, + DEACTIVATE_CONTEXT_STEP_CLEANUP, + DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP, + DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT, + DEACTIVATE_CONTEXT_STEP_LAST +} DeactivateContextStep; + +typedef struct { + NMModem *self; + NMDevice *device; + GCancellable *cancellable; + GSimpleAsyncResult *result; + DeactivateContextStep step; + NMPPPManager *ppp_manager; +} DeactivateContext; + +static void +deactivate_context_complete (DeactivateContext *ctx) +{ + if (ctx->ppp_manager) + g_object_unref (ctx->ppp_manager); + if (ctx->cancellable) + g_object_unref (ctx->cancellable); + g_simple_async_result_complete_in_idle (ctx->result); + g_object_unref (ctx->result); + g_object_unref (ctx->device); + g_object_unref (ctx->self); + g_slice_free (DeactivateContext, ctx); +} + +gboolean +nm_modem_deactivate_async_finish (NMModem *self, + GAsyncResult *res, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); +} + +static void deactivate_step (DeactivateContext *ctx); + +static void +disconnect_ready (NMModem *self, + GAsyncResult *res, + DeactivateContext *ctx) +{ + GError *error = NULL; + + if (!NM_MODEM_GET_CLASS (self)->disconnect_finish (self, res, &error)) { + g_simple_async_result_take_error (ctx->result, error); + deactivate_context_complete (ctx); + return; + } + + /* Go on */ + ctx->step++; + deactivate_step (ctx); +} + +static void +ppp_manager_stop_ready (NMPPPManager *ppp_manager, + GAsyncResult *res, + DeactivateContext *ctx) +{ + GError *error = NULL; + + if (!nm_ppp_manager_stop_finish (ppp_manager, res, &error)) { + nm_log_warn (LOGD_MB, "(%s): cannot stop PPP manager: %s", + nm_modem_get_uid (ctx->self), + error->message); + g_simple_async_result_take_error (ctx->result, error); + deactivate_context_complete (ctx); + return; + } + + /* Go on */ + ctx->step++; + deactivate_step (ctx); +} + +static void +deactivate_step (DeactivateContext *ctx) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (ctx->self); + GError *error = NULL; + + /* Check cancellable in each step */ + if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) { + g_simple_async_result_take_error (ctx->result, error); + deactivate_context_complete (ctx); + return; + } + + switch (ctx->step) { + case DEACTIVATE_CONTEXT_STEP_FIRST: + ctx->step++; + /* Fall down */ + + case DEACTIVATE_CONTEXT_STEP_CLEANUP: + /* Make sure we keep a ref to the PPP manager if there is one */ + if (priv->ppp_manager) + ctx->ppp_manager = g_object_ref (priv->ppp_manager); + /* Run cleanup */ + NM_MODEM_GET_CLASS (ctx->self)->deactivate_cleanup (ctx->self, ctx->device); + ctx->step++; + /* Fall down */ + + case DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP: + /* If we have a PPP manager, stop it */ + if (ctx->ppp_manager) { + nm_ppp_manager_stop (ctx->ppp_manager, + ctx->cancellable, + (GAsyncReadyCallback) ppp_manager_stop_ready, + ctx); + return; + } + ctx->step++; + /* Fall down */ + + case DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT: + /* Disconnect asynchronously */ + NM_MODEM_GET_CLASS (ctx->self)->disconnect (ctx->self, + FALSE, + ctx->cancellable, + (GAsyncReadyCallback) disconnect_ready, + ctx); + return; + + case DEACTIVATE_CONTEXT_STEP_LAST: + nm_log_dbg (LOGD_MB, "(%s): modem deactivation finished", + nm_modem_get_uid (ctx->self)); + deactivate_context_complete (ctx); + return; + } + + g_assert_not_reached (); +} + +void +nm_modem_deactivate_async (NMModem *self, + NMDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + DeactivateContext *ctx; + + ctx = g_slice_new0 (DeactivateContext); + ctx->self = g_object_ref (self); + ctx->device = g_object_ref (device); + ctx->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + nm_modem_deactivate_async); + ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + /* Start */ + ctx->step = DEACTIVATE_CONTEXT_STEP_FIRST; + deactivate_step (ctx); +} + +/*****************************************************************************/ + void nm_modem_deactivate (NMModem *self, NMDevice *device) { - NM_MODEM_GET_CLASS (self)->deactivate (self, device); + /* First cleanup */ + NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, device); + /* Then disconnect without waiting */ + NM_MODEM_GET_CLASS (self)->disconnect (self, FALSE, NULL, NULL, NULL); } /*****************************************************************************/ @@ -912,7 +1121,6 @@ nm_modem_device_state_changed (NMModem *self, switch (new_state) { case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: - case NM_DEVICE_STATE_DISCONNECTED: case NM_DEVICE_STATE_FAILED: if (priv->act_request) { cancel_get_secrets (self); @@ -924,7 +1132,9 @@ nm_modem_device_state_changed (NMModem *self, /* Don't bother warning on FAILED since the modem is already gone */ if (new_state == NM_DEVICE_STATE_FAILED) warn = FALSE; - NM_MODEM_GET_CLASS (self)->disconnect (self, warn); + /* First cleanup */ + NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, NULL); + NM_MODEM_GET_CLASS (self)->disconnect (self, warn, NULL, NULL, NULL); } break; default: @@ -1030,8 +1240,8 @@ nm_modem_init (NMModem *self) static GObject* constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) + guint n_construct_params, + GObjectConstructParam *construct_params) { GObject *object; NMModemPrivate *priv; @@ -1056,7 +1266,7 @@ constructor (GType type, return object; - err: +err: g_object_unref (object); return NULL; } @@ -1209,7 +1419,7 @@ nm_modem_class_init (NMModemClass *klass) klass->act_stage1_prepare = act_stage1_prepare; klass->stage3_ip6_config_request = stage3_ip6_config_request; - klass->deactivate = deactivate; + klass->deactivate_cleanup = deactivate_cleanup; /* Properties */ diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index 2a4d91733..2cace8902 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -143,9 +143,16 @@ typedef struct { void (*set_mm_enabled) (NMModem *self, gboolean enabled); - void (*disconnect) (NMModem *self, gboolean warn); + void (*disconnect) (NMModem *self, + gboolean warn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (*disconnect_finish) (NMModem *self, + GAsyncResult *res, + GError **error); - void (*deactivate) (NMModem *self, NMDevice *device); + void (*deactivate_cleanup) (NMModem *self, NMDevice *device); gboolean (*owns_port) (NMModem *self, const char *iface); @@ -218,6 +225,15 @@ gboolean nm_modem_get_secrets (NMModem *modem, void nm_modem_deactivate (NMModem *modem, NMDevice *device); +void nm_modem_deactivate_async (NMModem *self, + NMDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean nm_modem_deactivate_async_finish (NMModem *self, + GAsyncResult *res, + GError **error); + void nm_modem_device_state_changed (NMModem *modem, NMDeviceState new_state, NMDeviceState old_state, @@ -237,7 +253,7 @@ NMModemIPType nm_modem_get_supported_ip_types (NMModem *self); /* For the modem-manager only */ void nm_modem_emit_removed (NMModem *self); -NMModemIPType nm_modem_get_connection_ip_type (NMModem *self, +GArray *nm_modem_get_connection_ip_type (NMModem *self, NMConnection *connection, GError **error); @@ -246,6 +262,8 @@ void nm_modem_emit_ip6_config_result (NMModem *self, NMIP6Config *config, GError *error); +const gchar *nm_modem_ip_type_to_string (NMModemIPType ip_type); + G_END_DECLS #endif /* __NETWORKMANAGER_MODEM_H__ */ diff --git a/src/devices/wwan/wwan-exports.ver b/src/devices/wwan/wwan-exports.ver index c23ab24b7..23412de62 100644 --- a/src/devices/wwan/wwan-exports.ver +++ b/src/devices/wwan/wwan-exports.ver @@ -5,6 +5,8 @@ global: nm_modem_check_connection_compatible; nm_modem_complete_connection; nm_modem_deactivate; + nm_modem_deactivate_async; + nm_modem_deactivate_async_finish; nm_modem_device_state_changed; nm_modem_get_capabilities; nm_modem_get_control_port; |