summaryrefslogtreecommitdiff
path: root/src/devices/wwan
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/wwan')
-rw-r--r--src/devices/wwan/Makefile.in30
-rw-r--r--src/devices/wwan/nm-device-modem.c71
-rw-r--r--src/devices/wwan/nm-modem-broadband.c385
-rw-r--r--src/devices/wwan/nm-modem.c310
-rw-r--r--src/devices/wwan/nm-modem.h24
-rw-r--r--src/devices/wwan/wwan-exports.ver2
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;