summary refs log tree commit diff
path: root/src/modem-manager/nm-modem-gsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modem-manager/nm-modem-gsm.c')
-rw-r--r--src/modem-manager/nm-modem-gsm.c167
1 files changed, 110 insertions, 57 deletions
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);
 }