summary refs log tree commit diff
path: root/src/modem-manager
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2012-03-24 01:37:02 +0100
committerMichael Biebl <biebl@debian.org>2012-03-24 01:37:02 +0100
commitde06e5715e780baade318f3490ac7a4c9ce84e32 (patch)
tree23fbc3fafc12072476eff98bee60100eb54c29db /src/modem-manager
parentb436a68a20ff3114ded32a7a3d70cdd4954039f9 (diff)
Imported Upstream version 0.9.4.0 upstream/0.9.4.0
Diffstat (limited to 'src/modem-manager')
-rw-r--r--src/modem-manager/Makefile.am9
-rw-r--r--src/modem-manager/Makefile.in19
-rw-r--r--src/modem-manager/nm-modem-cdma.c55
-rw-r--r--src/modem-manager/nm-modem-cdma.h6
-rw-r--r--src/modem-manager/nm-modem-gsm.c167
-rw-r--r--src/modem-manager/nm-modem-gsm.h6
-rw-r--r--src/modem-manager/nm-modem-manager.c106
-rw-r--r--src/modem-manager/nm-modem.c189
-rw-r--r--src/modem-manager/nm-modem.h10
9 files changed, 254 insertions, 313 deletions
diff --git a/src/modem-manager/Makefile.am b/src/modem-manager/Makefile.am
index 3c3af16c..a5c6a668 100644
--- a/src/modem-manager/Makefile.am
+++ b/src/modem-manager/Makefile.am
@@ -1,9 +1,14 @@
+include $(GLIB_MAKEFILE)
+
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_builddir}/libnm-util
 
 noinst_LTLIBRARIES = libmodem-manager.la
 
@@ -23,7 +28,7 @@ libmodem_manager_la_CPPFLAGS = \
 	$(DBUS_CFLAGS)
 
 libmodem_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS)
diff --git a/src/modem-manager/Makefile.in b/src/modem-manager/Makefile.in
index 494bb1be..87afed0c 100644
--- a/src/modem-manager/Makefile.in
+++ b/src/modem-manager/Makefile.in
@@ -57,7 +57,7 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libmodem_manager_la_DEPENDENCIES =  \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am_libmodem_manager_la_OBJECTS = libmodem_manager_la-nm-modem.lo \
@@ -144,6 +144,8 @@ GIO_LIBS = @GIO_LIBS@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
 GLIB_LIBS = @GLIB_LIBS@
+GLIB_MAKEFILE = @GLIB_MAKEFILE@
+GLIB_MKENUMS = @GLIB_MKENUMS@
 GMODULE_CFLAGS = @GMODULE_CFLAGS@
 GMODULE_LIBS = @GMODULE_LIBS@
 GMSGFMT = @GMSGFMT@
@@ -198,11 +200,15 @@ LIBNL2_LIBS = @LIBNL2_LIBS@
 LIBNL3_CFLAGS = @LIBNL3_CFLAGS@
 LIBNL3_LIBS = @LIBNL3_LIBS@
 LIBNL_CFLAGS = @LIBNL_CFLAGS@
+LIBNL_GENL3_CFLAGS = @LIBNL_GENL3_CFLAGS@
+LIBNL_GENL3_LIBS = @LIBNL_GENL3_LIBS@
 LIBNL_LIBS = @LIBNL_LIBS@
 LIBNL_ROUTE3_CFLAGS = @LIBNL_ROUTE3_CFLAGS@
 LIBNL_ROUTE3_LIBS = @LIBNL_ROUTE3_LIBS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
@@ -213,6 +219,7 @@ MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
+MOC = @MOC@
 MSGFMT = @MSGFMT@
 MSGFMT_015 = @MSGFMT_015@
 MSGMERGE = @MSGMERGE@
@@ -252,6 +259,8 @@ SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
 SYSTEM_CA_PATH = @SYSTEM_CA_PATH@
 UDEV_BASE_DIR = @UDEV_BASE_DIR@
 USE_NLS = @USE_NLS@
@@ -317,10 +326,13 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 INCLUDES = \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/generated \
+	-I${top_builddir}/src/generated \
 	-I${top_srcdir}/src/logging \
 	-I${top_srcdir}/include \
+	-I${top_builddir}/include \
 	-I${top_srcdir}/libnm-util \
-	-I${top_builddir}/marshallers
+	-I${top_builddir}/libnm-util
 
 noinst_LTLIBRARIES = libmodem-manager.la
 libmodem_manager_la_SOURCES = \
@@ -339,7 +351,7 @@ libmodem_manager_la_CPPFLAGS = \
 	$(DBUS_CFLAGS)
 
 libmodem_manager_la_LIBADD = \
-	$(top_builddir)/marshallers/libmarshallers.la \
+	$(top_builddir)/src/generated/libnm-generated.la \
 	$(top_builddir)/src/logging/libnm-logging.la \
 	$(LIBNL_LIBS) \
 	$(DBUS_LIBS)
@@ -663,6 +675,7 @@ uninstall-am:
 	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
 	pdf pdf-am ps ps-am tags uninstall uninstall-am
 
+include $(GLIB_MAKEFILE)
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c
index 5db6a84f..fa19a342 100644
--- a/src/modem-manager/nm-modem-cdma.c
+++ b/src/modem-manager/nm-modem-cdma.c
@@ -27,11 +27,13 @@
 #include "nm-dbus-glib-types.h"
 #include "nm-modem-cdma.h"
 #include "nm-modem-types.h"
+#include "nm-enum-types.h"
 #include "nm-device.h"
 #include "nm-device-private.h"
 #include "nm-dbus-manager.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-cdma.h"
+#include "nm-setting-ppp.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
@@ -46,14 +48,7 @@ typedef struct {
 } NMModemCdmaPrivate;
 
 
-typedef enum {
-	NM_CDMA_ERROR_CONNECTION_NOT_CDMA = 0,
-	NM_CDMA_ERROR_CONNECTION_INVALID,
-	NM_CDMA_ERROR_CONNECTION_INCOMPATIBLE,
-} NMCdmaError;
-
 #define NM_CDMA_ERROR (nm_cdma_error_quark ())
-#define NM_TYPE_CDMA_ERROR (nm_cdma_error_get_type ())
 
 static GQuark
 nm_cdma_error_quark (void)
@@ -64,29 +59,6 @@ nm_cdma_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_cdma_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not a CDMA connection. */
-			ENUM_ENTRY (NM_CDMA_ERROR_CONNECTION_NOT_CDMA, "ConnectionNotCdma"),
-			/* Connection was not a valid CDMA connection. */
-			ENUM_ENTRY (NM_CDMA_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Connection does not apply to this device. */
-			ENUM_ENTRY (NM_CDMA_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMCdmaError", values);
-	}
-	return etype;
-}
-
 
 NMModem *
 nm_modem_cdma_new (const char *path,
@@ -169,7 +141,7 @@ create_connect_properties (NMConnection *connection)
 	GHashTable *properties;
 	const char *str;
 
-	setting = NM_SETTING_CDMA (nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA));
+	setting = nm_connection_get_setting_cdma (connection);
 	properties = value_hash_create ();
 
 	str = nm_setting_cdma_get_number (setting);
@@ -230,7 +202,7 @@ real_get_best_auto_connection (NMModem *modem,
 		NMConnection *connection = NM_CONNECTION (iter->data);
 		NMSettingConnection *s_con;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 		g_assert (s_con);
 
 		if (!nm_setting_connection_get_autoconnect (s_con))
@@ -252,7 +224,7 @@ real_check_connection_compatible (NMModem *modem,
 	NMSettingConnection *s_con;
 	NMSettingCdma *s_cdma;
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
 	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_CDMA_SETTING_NAME)) {
@@ -262,7 +234,7 @@ real_check_connection_compatible (NMModem *modem,
 		return FALSE;
 	}
 
-	s_cdma = NM_SETTING_CDMA (nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA));
+	s_cdma = nm_connection_get_setting_cdma (connection);
 	if (!s_cdma) {
 		g_set_error (error,
 		             NM_CDMA_ERROR, NM_CDMA_ERROR_CONNECTION_INVALID,
@@ -280,8 +252,9 @@ real_complete_connection (NMModem *modem,
                           GError **error)
 {
 	NMSettingCdma *s_cdma;
+	NMSettingPPP *s_ppp;
 
-	s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
+	s_cdma = nm_connection_get_setting_cdma (connection);
 	if (!s_cdma) {
 		s_cdma = (NMSettingCdma *) nm_setting_cdma_new ();
 		nm_connection_add_setting (connection, NM_SETTING (s_cdma));
@@ -290,6 +263,16 @@ real_complete_connection (NMModem *modem,
 	if (!nm_setting_cdma_get_number (s_cdma))
 		g_object_set (G_OBJECT (s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL);
 
+	s_ppp = nm_connection_get_setting_ppp (connection);
+	if (!s_ppp) {
+		s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
+		g_object_set (G_OBJECT (s_ppp),
+		              NM_SETTING_PPP_LCP_ECHO_FAILURE, 5,
+		              NM_SETTING_PPP_LCP_ECHO_INTERVAL, 30,
+		              NULL);
+		nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+	}
+
 	nm_utils_complete_generic (connection,
 	                           NM_SETTING_CDMA_SETTING_NAME,
 	                           existing_connections,
@@ -308,7 +291,7 @@ real_get_user_pass (NMModem *modem,
 {
 	NMSettingCdma *s_cdma;
 
-	s_cdma = (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA);
+	s_cdma = nm_connection_get_setting_cdma (connection);
 	if (!s_cdma)
 		return FALSE;
 
diff --git a/src/modem-manager/nm-modem-cdma.h b/src/modem-manager/nm-modem-cdma.h
index 0abe4e0c..2229c183 100644
--- a/src/modem-manager/nm-modem-cdma.h
+++ b/src/modem-manager/nm-modem-cdma.h
@@ -33,6 +33,12 @@ G_BEGIN_DECLS
 #define NM_IS_MODEM_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_MODEM_CDMA))
 #define NM_MODEM_CDMA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_MODEM_CDMA, NMModemCdmaClass))
 
+typedef enum {
+	NM_CDMA_ERROR_CONNECTION_NOT_CDMA = 0, /*< nick=ConnectionNotCdma >*/
+	NM_CDMA_ERROR_CONNECTION_INVALID,      /*< nick=ConnectionInvalid >*/
+	NM_CDMA_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
+} NMCdmaError;
+
 typedef struct {
 	NMModem parent;
 } NMModemCdma;
diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c
index 9a96ae99..183b4780 100644
--- a/src/modem-manager/nm-modem-gsm.c
+++ b/src/modem-manager/nm-modem-gsm.c
@@ -30,7 +30,9 @@
 #include "nm-device-private.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-gsm.h"
+#include "nm-setting-ppp.h"
 #include "nm-modem-types.h"
+#include "nm-enum-types.h"
 #include "nm-logging.h"
 #include "NetworkManagerUtils.h"
 
@@ -60,6 +62,18 @@ typedef enum {
     MM_MODEM_GSM_ALLOWED_MODE_LAST = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY
 } MMModemGsmAllowedMode;
 
+typedef enum {
+	MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN  = 0x0000,
+    /* bits 0..4 order match Ericsson device bitmap */
+    MM_MODEM_GSM_ALLOWED_AUTH_NONE     = 0x0001,
+    MM_MODEM_GSM_ALLOWED_AUTH_PAP      = 0x0002,
+    MM_MODEM_GSM_ALLOWED_AUTH_CHAP     = 0x0004,
+    MM_MODEM_GSM_ALLOWED_AUTH_MSCHAP   = 0x0008,
+    MM_MODEM_GSM_ALLOWED_AUTH_MSCHAPV2 = 0x0010,
+    MM_MODEM_GSM_ALLOWED_AUTH_EAP      = 0x0020,
+
+    MM_MODEM_GSM_ALLOWED_AUTH_LAST = MM_MODEM_GSM_ALLOWED_AUTH_EAP
+} MMModemGsmAllowedAuth;
 
 G_DEFINE_TYPE (NMModemGsm, nm_modem_gsm, NM_TYPE_MODEM)
 
@@ -70,17 +84,12 @@ typedef struct {
 
 	GHashTable *connect_properties;
 	guint32 pin_tries;
+
+	guint enable_delay_id;
 } NMModemGsmPrivate;
 
 
-typedef enum {
-	NM_GSM_ERROR_CONNECTION_NOT_GSM = 0,
-	NM_GSM_ERROR_CONNECTION_INVALID,
-	NM_GSM_ERROR_CONNECTION_INCOMPATIBLE,
-} NMGsmError;
-
 #define NM_GSM_ERROR (nm_gsm_error_quark ())
-#define NM_TYPE_GSM_ERROR (nm_gsm_error_get_type ())
 
 static GQuark
 nm_gsm_error_quark (void)
@@ -91,30 +100,6 @@ nm_gsm_error_quark (void)
 	return quark;
 }
 
-/* This should really be standard. */
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType
-nm_gsm_error_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0) {
-		static const GEnumValue values[] = {
-			/* Connection was not a GSM connection. */
-			ENUM_ENTRY (NM_GSM_ERROR_CONNECTION_NOT_GSM, "ConnectionNotGsm"),
-			/* Connection was not a valid GSM connection. */
-			ENUM_ENTRY (NM_GSM_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
-			/* Connection does not apply to this device. */
-			ENUM_ENTRY (NM_GSM_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
-			{ 0, 0, 0 }
-		};
-		etype = g_enum_register_static ("NMGsmError", values);
-	}
-	return etype;
-}
-
-
 NMModem *
 nm_modem_gsm_new (const char *path,
                   const char *device,
@@ -140,20 +125,33 @@ translate_mm_error (GError *error)
 
 	if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_CARRIER))
 		reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER;
-	if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_DIALTONE))
-		reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT;
-	if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_BUSY))
+	else if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_DIALTONE))
+		reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE;
+	else if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_BUSY))
 		reason = NM_DEVICE_STATE_REASON_MODEM_BUSY;
-	if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_ANSWER))
+	else if (dbus_g_error_has_name (error, MM_MODEM_CONNECT_ERROR_NO_ANSWER))
 		reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT;
-	if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NETWORK_NOT_ALLOWED))
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NETWORK_NOT_ALLOWED))
 		reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED;
-	if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NETWORK_TIMEOUT))
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NETWORK_TIMEOUT))
 		reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT;
-	if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NO_NETWORK))
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_NO_NETWORK))
 		reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING;
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_NOT_INSERTED))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED;
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PIN))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED;
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PUK))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED;
+	else if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_WRONG))
+		reason = NM_DEVICE_STATE_REASON_GSM_SIM_WRONG;
+	else {
+		/* unable to map the ModemManager error to a NM_DEVICE_STATE_REASON */
+		nm_log_dbg (LOGD_MB, "unmapped dbus error detected: '%s'", dbus_g_error_get_name (error));
+		reason = NM_DEVICE_STATE_REASON_UNKNOWN;
+	}
 
-	/* FIXME: We have only GSM error messages here, and we have no idea which 
+	/* FIXME: We have only GSM error messages here, and we have no idea which
 	   activation state failed. Reasons like:
 	   NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED,
 	   NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED,
@@ -162,9 +160,6 @@ translate_mm_error (GError *error)
 	   NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED
 	   are not used.
 	*/
-	else
-		reason = NM_DEVICE_STATE_REASON_UNKNOWN;
-
 	return reason;
 }
 
@@ -237,38 +232,51 @@ do_connect (NMModemGsm *self)
 
 static void stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data);
 
-static void
+/* do_enable() is used as a GSourceFunc, hence the gboolean return */
+static gboolean
 do_enable (NMModemGsm *self)
 {
 	DBusGProxy *proxy;
 
-	g_return_if_fail (self != NULL);
-	g_return_if_fail (NM_IS_MODEM_GSM (self));
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_MODEM_GSM (self), FALSE);
 
+	NM_MODEM_GSM_GET_PRIVATE (self)->enable_delay_id = 0;
 	proxy = nm_modem_get_proxy (NM_MODEM (self), MM_DBUS_INTERFACE_MODEM);
 	dbus_g_proxy_begin_call_with_timeout (proxy,
 	                                      "Enable", stage1_enable_done,
 	                                      self, NULL, 20000,
 	                                      G_TYPE_BOOLEAN, TRUE,
 	                                      G_TYPE_INVALID);
+	return FALSE;
 }
 
 static void
 stage1_pin_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
 	NMModemGsm *self = NM_MODEM_GSM (user_data);
+	NMModemGsmPrivate *priv = NM_MODEM_GSM_GET_PRIVATE (self);
+	NMDeviceStateReason reason;
 	GError *error = NULL;
 
 	if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) {
-		/* Success; go back and try the enable again */
-		do_enable (self);
+		/* Success; try to enable the modem again.  Wait a few seconds to ensure
+		 * that ModemManager is ready for the enable right after the unlock.
+		 */
+		if (priv->enable_delay_id == 0)
+			priv->enable_delay_id = g_timeout_add_seconds (4, (GSourceFunc) do_enable, self);
 	} else {
 		nm_log_warn (LOGD_MB, "GSM PIN unlock failed: (%d) %s",
 		             error ? error->code : -1,
 		             error && error->message ? error->message : "(unknown)");
-		g_error_free (error);
 
-		g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
+		/* try to translate the error reason */
+		reason = translate_mm_error (error);
+		if (reason == NM_DEVICE_STATE_REASON_UNKNOWN)
+			reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
+
+		g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, reason);
+		g_error_free (error);
 	}
 }
 
@@ -301,6 +309,7 @@ static void
 stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
 {
 	NMModemGsm *self = NM_MODEM_GSM (user_data);
+	NMDeviceStateReason reason;
 	GError *error = NULL;
 
 	if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID))
@@ -312,8 +321,13 @@ stage1_enable_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_da
 
 		if (dbus_g_error_has_name (error, MM_MODEM_ERROR_SIM_PIN))
 			handle_enable_pin_required (self);
-		else
-			g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED);
+		else {
+			/* try to translate the error reason */
+			reason = translate_mm_error (error);
+			if (reason == NM_DEVICE_STATE_REASON_UNKNOWN)
+				reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED;
+			g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, reason);
+		}
 
 		g_error_free (error);
 	}
@@ -324,10 +338,11 @@ static GHashTable *
 create_connect_properties (NMConnection *connection)
 {
 	NMSettingGsm *setting;
+	NMSettingPPP *s_ppp;
 	GHashTable *properties;
 	const char *str;
 
-	setting = NM_SETTING_GSM (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM));
+	setting = nm_connection_get_setting_gsm (connection);
 	properties = value_hash_create ();
 
 	str = nm_setting_gsm_get_number (setting);
@@ -382,6 +397,28 @@ create_connect_properties (NMConnection *connection)
 	if (nm_setting_gsm_get_home_only (setting))
 		value_hash_add_bool (properties, "home_only", TRUE);
 
+	/* For IpMethod == STATIC or DHCP */
+	s_ppp = nm_connection_get_setting_ppp (connection);
+	if (s_ppp) {
+		guint32 auth = MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN;
+
+		if (nm_setting_ppp_get_noauth (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_NONE;
+		if (!nm_setting_ppp_get_refuse_pap (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_PAP;
+		if (!nm_setting_ppp_get_refuse_chap (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_CHAP;
+		if (!nm_setting_ppp_get_refuse_mschap (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_MSCHAP;
+		if (!nm_setting_ppp_get_refuse_mschapv2 (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_MSCHAPV2;
+		if (!nm_setting_ppp_get_refuse_eap (s_ppp))
+			auth |= MM_MODEM_GSM_ALLOWED_AUTH_EAP;
+
+		if (auth != MM_MODEM_GSM_ALLOWED_AUTH_UNKNOWN)
+			value_hash_add_uint (properties, "allowed_auth", auth);
+	}
+
 	return properties;
 }
 
@@ -429,7 +466,7 @@ real_get_best_auto_connection (NMModem *modem,
 		NMConnection *connection = NM_CONNECTION (iter->data);
 		NMSettingConnection *s_con;
 
-		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		s_con = nm_connection_get_setting_connection (connection);
 		g_assert (s_con);
 
 		if (!nm_setting_connection_get_autoconnect (s_con))
@@ -451,7 +488,7 @@ real_check_connection_compatible (NMModem *modem,
 	NMSettingConnection *s_con;
 	NMSettingGsm *s_gsm;
 
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	s_con = nm_connection_get_setting_connection (connection);
 	g_assert (s_con);
 
 	if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME)) {
@@ -461,7 +498,7 @@ real_check_connection_compatible (NMModem *modem,
 		return FALSE;
 	}
 
-	s_gsm = NM_SETTING_GSM (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM));
+	s_gsm = nm_connection_get_setting_gsm (connection);
 	if (!s_gsm) {
 		g_set_error (error,
 		             NM_GSM_ERROR, NM_GSM_ERROR_CONNECTION_INVALID,
@@ -479,8 +516,9 @@ real_complete_connection (NMModem *modem,
                           GError **error)
 {
 	NMSettingGsm *s_gsm;
+	NMSettingPPP *s_ppp;
 
-	s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
+	s_gsm = nm_connection_get_setting_gsm (connection);
 	if (!s_gsm || !nm_setting_gsm_get_apn (s_gsm)) {
 		/* Need an APN at least */
 		g_set_error_literal (error,
@@ -493,6 +531,16 @@ real_complete_connection (NMModem *modem,
 	if (!nm_setting_gsm_get_number (s_gsm))
 		g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL);
 
+	s_ppp = nm_connection_get_setting_ppp (connection);
+	if (!s_ppp) {
+		s_ppp = (NMSettingPPP *) nm_setting_ppp_new ();
+		g_object_set (G_OBJECT (s_ppp),
+		              NM_SETTING_PPP_LCP_ECHO_FAILURE, 5,
+		              NM_SETTING_PPP_LCP_ECHO_INTERVAL, 30,
+		              NULL);
+		nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+	}
+
 	nm_utils_complete_generic (connection,
 	                           NM_SETTING_GSM_SETTING_NAME,
 	                           existing_connections,
@@ -511,7 +559,7 @@ real_get_user_pass (NMModem *modem,
 {
 	NMSettingGsm *s_gsm;
 
-	s_gsm = (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM);
+	s_gsm = nm_connection_get_setting_gsm (connection);
 	if (!s_gsm)
 		return FALSE;
 
@@ -544,6 +592,9 @@ real_deactivate (NMModem *modem, NMDevice *device)
 
 	priv->pin_tries = 0;
 
+	if (priv->enable_delay_id)
+		g_source_remove (priv->enable_delay_id);
+
 	NM_MODEM_CLASS (nm_modem_gsm_parent_class)->deactivate (modem, device);	
 }
 
@@ -563,6 +614,8 @@ dispose (GObject *object)
 
 	if (priv->connect_properties)
 		g_hash_table_destroy (priv->connect_properties);
+	if (priv->enable_delay_id)
+		g_source_remove (priv->enable_delay_id);
 
 	G_OBJECT_CLASS (nm_modem_gsm_parent_class)->dispose (object);
 }
diff --git a/src/modem-manager/nm-modem-gsm.h b/src/modem-manager/nm-modem-gsm.h
index f481bdb8..e1c94f04 100644
--- a/src/modem-manager/nm-modem-gsm.h
+++ b/src/modem-manager/nm-modem-gsm.h
@@ -33,6 +33,12 @@ G_BEGIN_DECLS
 #define NM_IS_MODEM_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),	 NM_TYPE_MODEM_GSM))
 #define NM_MODEM_GSM_GET_CLASS(obj)	 (G_TYPE_INSTANCE_GET_CLASS ((obj),	 NM_TYPE_MODEM_GSM, NMModemGsmClass))
 
+typedef enum {
+	NM_GSM_ERROR_CONNECTION_NOT_GSM = 0,  /*< nick=ConnectionNotGsm >*/
+	NM_GSM_ERROR_CONNECTION_INVALID,      /*< nick=ConnectionInvalid >*/
+	NM_GSM_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
+} NMGsmError;
+
 typedef struct {
 	NMModem parent;
 } NMModemGsm;
diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c
index 3509d667..051940f5 100644
--- a/src/modem-manager/nm-modem-manager.c
+++ b/src/modem-manager/nm-modem-manager.c
@@ -76,86 +76,56 @@ get_modem_properties (DBusGConnection *connection,
 					  char **data_device,
 					  char **driver,
 					  guint32 *type,
-					  guint32 *ip_method)
+					  guint32 *ip_method,
+					  guint32 *ip_timeout)
 {
 	DBusGProxy *proxy;
-	GValue value = { 0 };
 	GError *err = NULL;
+	GHashTable *props = NULL;
+	GHashTableIter iter;
+	const char *prop;
+	GValue *value;
 
 	proxy = dbus_g_proxy_new_for_name (connection,
-									   MM_DBUS_SERVICE,
-									   path,
-									   "org.freedesktop.DBus.Properties");
-
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-	                                    G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-	                                    G_TYPE_STRING, "Type",
-	                                    G_TYPE_INVALID,
-	                                    G_TYPE_VALUE, &value,
-	                                    G_TYPE_INVALID)) {
-		*type = g_value_get_uint (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get device type: %s", err->message);
-		goto out;
-	}
-
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-	                                    G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-	                                    G_TYPE_STRING, "MasterDevice",
-	                                    G_TYPE_INVALID,
-	                                    G_TYPE_VALUE, &value,
-	                                    G_TYPE_INVALID)) {
-		*device = g_value_dup_string (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get device: %s", err->message);
-		goto out;
-	}
-
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-										G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-										G_TYPE_STRING, "IpMethod",
-										G_TYPE_INVALID,
-										G_TYPE_VALUE, &value,
-										G_TYPE_INVALID)) {
-		*ip_method = g_value_get_uint (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get IP method: %s", err->message);
+	                                   MM_DBUS_SERVICE,
+	                                   path,
+	                                   "org.freedesktop.DBus.Properties");
+
+	if (!dbus_g_proxy_call_with_timeout (proxy, "GetAll", 15000, &err,
+	                                     G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
+	                                     G_TYPE_INVALID,
+	                                     DBUS_TYPE_G_MAP_OF_VARIANT, &props,
+	                                     G_TYPE_INVALID)) {
+		nm_log_warn (LOGD_MB, "could not get modem properties: %s %s",
+		             err ? dbus_g_error_get_name (err) : "(none)",
+		             err ? err->message : "(unknown)");
+		g_clear_error (&err);
 		goto out;
 	}
 
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-										G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-										G_TYPE_STRING, "Device",
-										G_TYPE_INVALID,
-										G_TYPE_VALUE, &value,
-										G_TYPE_INVALID)) {
-		*data_device = g_value_dup_string (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get modem data device: %s", err->message);
+	if (!props) {
+		nm_log_warn (LOGD_MB, "no modem properties found");
 		goto out;
 	}
 
-	if (dbus_g_proxy_call_with_timeout (proxy, "Get", 15000, &err,
-										G_TYPE_STRING, MM_DBUS_INTERFACE_MODEM,
-										G_TYPE_STRING, "Driver",
-										G_TYPE_INVALID,
-										G_TYPE_VALUE, &value,
-										G_TYPE_INVALID)) {
-		*driver = g_value_dup_string (&value);
-		g_value_unset (&value);
-	} else {
-		nm_log_warn (LOGD_MB, "could not get modem driver: %s", err->message);
-		goto out;
+	g_hash_table_iter_init (&iter, props);
+	while (g_hash_table_iter_next (&iter, (gpointer) &prop, (gpointer) &value)) {
+		if (g_strcmp0 (prop, "Type") == 0)
+			*type = g_value_get_uint (value);
+		else if (g_strcmp0 (prop, "MasterDevice") == 0)
+			*device = g_value_dup_string (value);
+		else if (g_strcmp0 (prop, "IpMethod") == 0)
+			*ip_method = g_value_get_uint (value);
+		else if (g_strcmp0 (prop, "Device") == 0)
+			*data_device = g_value_dup_string (value);
+		else if (g_strcmp0 (prop, "Driver") == 0)
+			*driver = g_value_dup_string (value);
+		else if (g_strcmp0 (prop, "IpTimeout") == 0)
+			*ip_timeout = g_value_get_uint (value);
 	}
+	g_hash_table_unref (props);
 
  out:
-	if (err)
-		g_error_free (err);
-
 	g_object_unref (proxy);
 
 	return *data_device && *driver;
@@ -169,6 +139,7 @@ create_modem (NMModemManager *manager, const char *path)
 	char *data_device = NULL, *driver = NULL, *master_device = NULL;
 	uint modem_type = MM_MODEM_TYPE_UNKNOWN;
 	uint ip_method = MM_MODEM_IP_METHOD_PPP;
+	uint ip_timeout = 0;
 
 	if (g_hash_table_lookup (priv->modems, path)) {
 		nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path);
@@ -177,7 +148,7 @@ create_modem (NMModemManager *manager, const char *path)
 
 	if (!get_modem_properties (nm_dbus_manager_get_connection (priv->dbus_mgr),
 	                           path, &master_device, &data_device, &driver,
-	                           &modem_type, &ip_method))
+	                           &modem_type, &ip_method, &ip_timeout))
 		return;
 
 	if (modem_type == MM_MODEM_TYPE_UNKNOWN) {
@@ -210,6 +181,7 @@ create_modem (NMModemManager *manager, const char *path)
 	g_free (data_device);
 
 	if (modem) {
+		g_object_set (G_OBJECT (modem), NM_MODEM_IP_TIMEOUT, ip_timeout, NULL);
 		g_hash_table_insert (priv->modems, g_strdup (path), modem);
 		g_signal_emit (manager, signals[MODEM_ADDED], 0, modem, driver);
 	}
diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c
index debfbdf7..91c0b06d 100644
--- a/src/modem-manager/nm-modem.c
+++ b/src/modem-manager/nm-modem.c
@@ -30,7 +30,6 @@
 #include "nm-logging.h"
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
-#include "nm-device-interface.h"
 #include "nm-dbus-glib-types.h"
 
 G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT)
@@ -43,6 +42,7 @@ enum {
 	PROP_IFACE,
 	PROP_PATH,
 	PROP_IP_METHOD,
+	PROP_IP_TIMEOUT,
 	PROP_ENABLED,
 
 	LAST_PROP
@@ -55,7 +55,6 @@ typedef struct {
 
 	char *path;
 	NMPPPManager *ppp_manager;
-	NMIP4Config	 *pending_ip4_config;
 	guint32 ip_method;
 	char *device;
 	char *iface;
@@ -67,6 +66,7 @@ typedef struct {
 	DBusGProxyCall *call;
 
 	gboolean mm_enabled;
+	guint32 mm_ip_timeout;
 
 	/* PPP stats */
 	guint32 in_bytes;
@@ -129,21 +129,6 @@ nm_modem_get_proxy (NMModem *self,
 	return priv->proxy;
 }
 
-static void
-merge_ip4_config (NMActRequest *req, NMIP4Config *config)
-{
-	NMConnection *connection;
-	NMSettingIP4Config *s_ip4;
-
-	/* Merge user-defined overrides into the IP4Config to be applied */
-	connection = nm_act_request_get_connection (req);
-	g_assert (connection);
-
-	s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-	if (s_ip4)
-		nm_utils_merge_ip4_config (config, s_ip4);
-}
-
 /*****************************************************************************/
 /* IP method PPP */
 
@@ -169,7 +154,6 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
 				gpointer user_data)
 {
 	NMModem *self = NM_MODEM (user_data);
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
 	guint32 i, num;
 	guint32 bad_dns1 = htonl (0x0A0B0C0D);
 	guint32 good_dns1 = htonl (0x04020201);  /* GTE nameserver */
@@ -213,7 +197,6 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
 		nm_ip4_config_add_nameserver (config, good_dns2);
 	}
 
-	priv->pending_ip4_config = g_object_ref (config);
 	g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, iface, config, NULL);
 }
 
@@ -243,6 +226,7 @@ ppp_stage3_ip4_config_start (NMModem *self,
 	const char *ppp_name = NULL;
 	GError *error = NULL;
 	NMActStageReturn ret;
+	guint ip_timeout = 20;
 
 	g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 	g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
@@ -258,8 +242,16 @@ ppp_stage3_ip4_config_start (NMModem *self,
 			return NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
+	/* Check if ModemManager requested a specific IP timeout to be used. If 0 reported,
+	 * use the default one (20s) */
+	if (priv->mm_ip_timeout > 0) {
+		nm_log_info (LOGD_PPP, "using modem-specified IP timeout: %u seconds",
+		             priv->mm_ip_timeout);
+		ip_timeout = priv->mm_ip_timeout;
+	}
+
 	priv->ppp_manager = nm_ppp_manager_new (priv->iface);
-	if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, 20, &error)) {
+	if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, &error)) {
 		g_signal_connect (priv->ppp_manager, "state-changed",
 						  G_CALLBACK (ppp_state_changed),
 						  self);
@@ -287,22 +279,6 @@ ppp_stage3_ip4_config_start (NMModem *self,
 	return ret;
 }
 
-static NMActStageReturn
-ppp_stage4 (NMModem *self,
-            NMActRequest *req,
-            NMIP4Config **config,
-            NMDeviceStateReason *reason)
-{
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-
-	*config = priv->pending_ip4_config;
-	priv->pending_ip4_config = NULL;
-
-	merge_ip4_config (req, *config);
-
-	return NM_ACT_STAGE_RETURN_SUCCESS;
-}
-
 /*****************************************************************************/
 /* IP method static */
 
@@ -336,9 +312,6 @@ static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
 			nm_ip4_config_add_nameserver (config, g_value_get_uint (value));
 		}
 		g_value_array_free (ret_array);
-
-		priv->pending_ip4_config = g_object_ref (config);
-		g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, NULL, config, NULL);
 	}
 
 	g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, NULL, config, error);
@@ -368,32 +341,6 @@ static_stage3_ip4_config_start (NMModem *self,
 	return NM_ACT_STAGE_RETURN_POSTPONE;
 }
 
-static NMActStageReturn
-static_stage4 (NMModem *self,
-               NMActRequest *req,
-               NMDevice *device,
-               NMIP4Config **config,
-               NMDeviceStateReason *reason)
-{
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-	gboolean no_firmware = FALSE;
-
-	if (!nm_device_hw_bring_up (device, TRUE, &no_firmware)) {
-		if (no_firmware)
-			*reason = NM_DEVICE_STATE_REASON_FIRMWARE_MISSING;
-		else
-			*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
-		return NM_ACT_STAGE_RETURN_FAILURE;
-	}
-
-	*config = priv->pending_ip4_config;
-	priv->pending_ip4_config = NULL;
-
-	merge_ip4_config (req, *config);
-
-	return NM_ACT_STAGE_RETURN_SUCCESS;
-}
-
 /*****************************************************************************/
 
 NMActStageReturn
@@ -426,7 +373,7 @@ nm_modem_stage3_ip4_config_start (NMModem *self,
 		ret = static_stage3_ip4_config_start (self, req, reason);
 		break;
 	case MM_MODEM_IP_METHOD_DHCP:
-		ret = device_class->act_stage3_ip4_config_start (device, reason);
+		ret = device_class->act_stage3_ip4_config_start (device, NULL, reason);
 		break;
 	default:
 		nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
@@ -438,45 +385,14 @@ nm_modem_stage3_ip4_config_start (NMModem *self,
 }
 
 NMActStageReturn
-nm_modem_stage4_get_ip4_config (NMModem *self,
-                                NMDevice *device,
-                                NMDeviceClass *device_class,
-								NMIP4Config **config,
-								NMDeviceStateReason *reason)
+nm_modem_stage3_ip6_config_start (NMModem *self,
+                                  NMDevice *device,
+                                  NMDeviceClass *device_class,
+                                  NMDeviceStateReason *reason)
 {
-	NMModemPrivate *priv;
-	NMActRequest *req;
-	NMActStageReturn ret;
-
-	g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (device != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (NM_IS_DEVICE (device), NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (device_class != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (NM_IS_DEVICE_CLASS (device_class), NM_ACT_STAGE_RETURN_FAILURE);
-	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	req = nm_device_get_act_request (device);
-	g_assert (req);
-
-	priv = NM_MODEM_GET_PRIVATE (self);
-	switch (priv->ip_method) {
-	case MM_MODEM_IP_METHOD_PPP:
-		ret = ppp_stage4 (self, req, config, reason);
-		break;
-	case MM_MODEM_IP_METHOD_STATIC:
-		ret = static_stage4 (self, req, device, config, reason);
-		break;
-	case MM_MODEM_IP_METHOD_DHCP:
-		ret = device_class->act_stage4_get_ip4_config (device, config, reason);
-		break;
-	default:
-		nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
-		ret = NM_ACT_STAGE_RETURN_FAILURE;
-		break;
-	}
-
-	return ret;
+	/* FIXME: We don't support IPv6 on modems quite yet... */
+	nm_device_activate_schedule_ip6_config_timeout (device);
+	return NM_ACT_STAGE_RETURN_POSTPONE;
 }
 
 static void
@@ -586,7 +502,7 @@ nm_modem_act_stage1_prepare (NMModem *self,
 		if (hints)
 			g_ptr_array_free (hints, TRUE);
 	}
-	
+
 	return ret;
 }
 
@@ -662,11 +578,6 @@ real_deactivate (NMModem *self, NMDevice *device)
 		priv->call = NULL;
 	}
 
-	if (priv->pending_ip4_config) {
-		g_object_unref (priv->pending_ip4_config);
-		priv->pending_ip4_config = NULL;
-	}
-
 	priv->in_bytes = priv->out_bytes = 0;
 
 	if (priv->ppp_manager) {
@@ -680,10 +591,12 @@ real_deactivate (NMModem *self, NMDevice *device)
 	case MM_MODEM_IP_METHOD_STATIC:
 	case MM_MODEM_IP_METHOD_DHCP:
 		ifindex = nm_device_get_ip_ifindex (device);
-		/* FIXME: use AF_UNSPEC here when we have IPv6 support */
-		nm_system_iface_flush_routes (ifindex, AF_INET);
-		nm_system_iface_flush_addresses (ifindex, AF_UNSPEC);
-		nm_system_iface_set_up (ifindex, FALSE, NULL);
+		if (ifindex >= 0) {
+			/* FIXME: use AF_UNSPEC here when we have IPv6 support */
+			nm_system_iface_flush_routes (ifindex, AF_INET);
+			nm_system_iface_flush_addresses (ifindex, AF_UNSPEC);
+			nm_system_iface_set_up (ifindex, FALSE, NULL);
+		}
 		break;
 	default:
 		nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
@@ -721,7 +634,7 @@ nm_modem_device_state_changed (NMModem *self,
 	g_return_if_fail (self != NULL);
 	g_return_if_fail (NM_IS_MODEM (self));
 
-	if (IS_ACTIVATING_STATE (old_state) || (old_state == NM_DEVICE_STATE_ACTIVATED))
+	if (old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_ACTIVATED)
 		was_connected = TRUE;
 
 	priv = NM_MODEM_GET_PRIVATE (self);
@@ -758,44 +671,20 @@ nm_modem_device_state_changed (NMModem *self,
 	}
 }
 
-static gboolean
-_state_is_active (NMDeviceState state)
-{
-	return (state >= NM_DEVICE_STATE_IP_CONFIG && state <= NM_DEVICE_STATE_DEACTIVATING);
-}
-
 gboolean
 nm_modem_hw_is_up (NMModem *self, NMDevice *device)
 {
-	guint32 ip_method = NM_MODEM_GET_PRIVATE (self)->ip_method;
+	int ifindex = nm_device_get_ip_ifindex (device);
 
-	if (ip_method == MM_MODEM_IP_METHOD_STATIC || ip_method == MM_MODEM_IP_METHOD_DHCP) {
-		NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-		NMDeviceState state;
-
-		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
-		if (priv->pending_ip4_config || _state_is_active (state))
-			return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
-	}
-
-	return TRUE;
+	return ifindex > 0 ? nm_system_iface_is_up (ifindex) : TRUE;
 }
 
 gboolean
 nm_modem_hw_bring_up (NMModem *self, NMDevice *device, gboolean *no_firmware)
 {
-	guint32 ip_method = NM_MODEM_GET_PRIVATE (self)->ip_method;
-
-	if (ip_method == MM_MODEM_IP_METHOD_STATIC || ip_method == MM_MODEM_IP_METHOD_DHCP) {
-		NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-		NMDeviceState state;
-
-		state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
-		if (priv->pending_ip4_config || _state_is_active (state))
-			return nm_system_iface_set_up (nm_device_get_ip_ifindex (device), TRUE, no_firmware);
-	}
+	int ifindex = nm_device_get_ip_ifindex (device);
 
-	return TRUE;
+	return ifindex > 0 ? nm_system_iface_set_up (ifindex, TRUE, no_firmware) : TRUE;
 }
 
 const char *
@@ -1013,6 +902,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_IP_METHOD:
 		g_value_set_uint (value, priv->ip_method);
 		break;
+	case PROP_IP_TIMEOUT:
+		g_value_set_uint (value, priv->mm_ip_timeout);
+		break;
 	case PROP_ENABLED:
 		g_value_set_boolean (value, priv->mm_enabled);
 		break;
@@ -1046,6 +938,9 @@ set_property (GObject *object, guint prop_id,
 		/* Construct only */
 		priv->ip_method = g_value_get_uint (value);
 		break;
+	case PROP_IP_TIMEOUT:
+		priv->mm_ip_timeout = g_value_get_uint (value);
+		break;
 	case PROP_ENABLED:
 		break;
 	default:
@@ -1129,6 +1024,14 @@ nm_modem_class_init (NMModemClass *klass)
 							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property
+		(object_class, PROP_IP_TIMEOUT,
+		 g_param_spec_uint (NM_MODEM_IP_TIMEOUT,
+		                    "IP timeout",
+		                    "IP timeout",
+		                    0, 360, 20,
+		                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property
 		(object_class, PROP_ENABLED,
 		 g_param_spec_boolean (NM_MODEM_ENABLED,
 		                       "Enabled",
diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h
index bad19b04..8fe52bc0 100644
--- a/src/modem-manager/nm-modem.h
+++ b/src/modem-manager/nm-modem.h
@@ -40,6 +40,7 @@ G_BEGIN_DECLS
 #define NM_MODEM_DEVICE    "device"
 #define NM_MODEM_IFACE     "iface"
 #define NM_MODEM_IP_METHOD "ip-method"
+#define NM_MODEM_IP_TIMEOUT "ip-timeout"
 #define NM_MODEM_ENABLED   "enabled"
 
 #define NM_MODEM_PPP_STATS         "ppp-stats"
@@ -129,11 +130,10 @@ NMActStageReturn nm_modem_stage3_ip4_config_start (NMModem *modem,
                                                    NMDeviceClass *device_class,
                                                    NMDeviceStateReason *reason);
 
-NMActStageReturn nm_modem_stage4_get_ip4_config (NMModem *modem,
-                                                 NMDevice *device,
-                                                 NMDeviceClass *device_class,
-                                                 NMIP4Config **config,
-                                                 NMDeviceStateReason *reason);
+NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *modem,
+                                                   NMDevice *device,
+                                                   NMDeviceClass *device_class,
+                                                   NMDeviceStateReason *reason);
 
 gboolean nm_modem_get_secrets (NMModem *modem,
                                const char *setting_name,