about summary refs log tree commit diff
path: root/src/devices/wwan/nm-modem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/wwan/nm-modem.c')
-rw-r--r--src/devices/wwan/nm-modem.c294
1 files changed, 101 insertions, 193 deletions
diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c
index 61b7247e..010a2b60 100644
--- a/src/devices/wwan/nm-modem.c
+++ b/src/devices/wwan/nm-modem.c
@@ -44,10 +44,13 @@
 
 NM_GOBJECT_PROPERTIES_DEFINE (NMModem,
 	PROP_CONTROL_PORT,
-	PROP_IP_IFINDEX,
+	PROP_DATA_PORT,
 	PROP_PATH,
 	PROP_UID,
 	PROP_DRIVER,
+	PROP_IP4_METHOD,
+	PROP_IP6_METHOD,
+	PROP_IP_TIMEOUT,
 	PROP_STATE,
 	PROP_DEVICE_ID,
 	PROP_SIM_ID,
@@ -76,12 +79,7 @@ typedef struct _NMModemPrivate {
 	char *driver;
 	char *control_port;
 	char *data_port;
-
-	/* TODO: ip_iface is solely used for nm_modem_owns_port().
-	 * We should rework the code that it's not necessary */
-	char *ip_iface;
-
-	int ip_ifindex;
+	char *ppp_iface;
 	NMModemIPMethod ip4_method;
 	NMModemIPMethod ip6_method;
 	NMUtilsIPv6IfaceId iid;
@@ -98,7 +96,7 @@ typedef struct _NMModemPrivate {
 	guint32 secrets_tries;
 	NMActRequestGetSecretsCallId *secrets_id;
 
-	guint mm_ip_timeout;
+	guint32 mm_ip_timeout;
 
 	guint32 ip4_route_table;
 	guint32 ip4_route_metric;
@@ -155,10 +153,6 @@ _nmlog_prefix (char *prefix, NMModem *self)
     } G_STMT_END
 
 /*****************************************************************************/
-
-static void _set_ip_ifindex (NMModem *self, int ifindex, const char *ifname);
-
-/*****************************************************************************/
 /* State/enabled/connected */
 
 static const char *state_table[] = {
@@ -456,28 +450,20 @@ ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_
 }
 
 static void
-ppp_ifindex_set (NMPPPManager *ppp_manager,
-                 int ifindex,
-                 const char *iface,
-                 gpointer user_data)
+set_data_port (NMModem *self, const char *new_data_port)
 {
-	NMModem *self = NM_MODEM (user_data);
-
-	nm_assert (ifindex >= 0);
-	nm_assert (NM_MODEM_GET_PRIVATE (self)->ppp_manager == ppp_manager);
+	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
 
-	if (ifindex <= 0 && iface) {
-		/* this might happen, if the ifname was already deleted
-		 * and we failed to resolve ifindex.
-		 *
-		 * Forget about the name. */
-		iface = NULL;
+	if (g_strcmp0 (priv->data_port, new_data_port) != 0) {
+		g_free (priv->data_port);
+		priv->data_port = g_strdup (new_data_port);
+		_notify (self, PROP_DATA_PORT);
 	}
-	_set_ip_ifindex (self, ifindex, iface);
 }
 
 static void
 ppp_ip4_config (NMPPPManager *ppp_manager,
+                const char *iface,
                 NMIP4Config *config,
                 gpointer user_data)
 {
@@ -489,6 +475,9 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
 	guint32 good_dns2 = htonl (0x04020202);  /* GTE nameserver */
 	gboolean dns_workaround = FALSE;
 
+	/* Notify about the new data port to use */
+	set_data_port (self, iface);
+
 	/* Work around a PPP bug (#1732) which causes many mobile broadband
 	 * providers to return 10.11.12.13 and 10.11.12.14 for the DNS servers.
 	 * Apparently fixed in ppp-2.4.5 but we've had some reports that this is
@@ -530,12 +519,16 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
 
 static void
 ppp_ip6_config (NMPPPManager *ppp_manager,
+                const char *iface,
                 const NMUtilsIPv6IfaceId *iid,
                 NMIP6Config *config,
                 gpointer user_data)
 {
 	NMModem *self = NM_MODEM (user_data);
 
+	/* Notify about the new data port to use */
+	set_data_port (self, iface);
+
 	NM_MODEM_GET_PRIVATE (self)->iid = *iid;
 
 	nm_modem_emit_ip6_config_result (self, config, NULL);
@@ -564,18 +557,6 @@ port_speed_is_zero (const char *port)
 {
 	struct termios options;
 	nm_auto_close int fd = -1;
-	gs_free char *path = NULL;
-
-	nm_assert (port);
-
-	if (port[0] != '/') {
-		if (   !port[0]
-		    || strchr (port, '/')
-		    || NM_IN_STRSET (port, ".", ".."))
-			return FALSE;
-		path = g_build_path ("/sys/class/tty", port, NULL);
-		port = path;
-	}
 
 	fd = open (port, O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC);
 	if (fd < 0)
@@ -617,12 +598,6 @@ ppp_stage3_ip_config_start (NMModem *self,
 			return NM_ACT_STAGE_RETURN_FAILURE;
 	}
 
-	if (!priv->data_port) {
-		_LOGE ("error starting PPP (no data port)");
-		NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED);
-		return NM_ACT_STAGE_RETURN_FAILURE;
-	}
-
 	/* 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) {
@@ -654,7 +629,9 @@ ppp_stage3_ip_config_start (NMModem *self,
 	                              ip_timeout, baud_override, &error)) {
 		_LOGE ("error starting PPP: %s", error->message);
 		g_error_free (error);
+
 		g_clear_object (&priv->ppp_manager);
+
 		NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED);
 		return NM_ACT_STAGE_RETURN_FAILURE;
 	}
@@ -662,9 +639,6 @@ ppp_stage3_ip_config_start (NMModem *self,
 	g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED,
 	                  G_CALLBACK (ppp_state_changed),
 	                  self);
-	g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IFINDEX_SET,
-	                  G_CALLBACK (ppp_ifindex_set),
-	                  self);
 	g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_IP4_CONFIG,
 	                  G_CALLBACK (ppp_ip4_config),
 	                  self);
@@ -1091,20 +1065,12 @@ nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection)
 gboolean
 nm_modem_complete_connection (NMModem *self,
                               NMConnection *connection,
-                              NMConnection *const*existing_connections,
+                              const GSList *existing_connections,
                               GError **error)
 {
-	NMModemClass *klass;
-
-	klass = NM_MODEM_GET_CLASS (self);
-	if (!klass->complete_connection) {
-		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION,
-		             "Modem class %s had no complete_connection method",
-		             G_OBJECT_TYPE_NAME (self));
-		return FALSE;
-	}
-
-	return klass->complete_connection (self, connection, existing_connections, error);
+	if (NM_MODEM_GET_CLASS (self)->complete_connection)
+		return NM_MODEM_GET_CLASS (self)->complete_connection (self, connection, existing_connections, error);
+	return FALSE;
 }
 
 /*****************************************************************************/
@@ -1129,10 +1095,7 @@ deactivate_cleanup (NMModem *self, NMDevice *device)
 
 	priv->in_bytes = priv->out_bytes = 0;
 
-	if (priv->ppp_manager) {
-		g_signal_handlers_disconnect_by_data (priv->ppp_manager, self);
-		g_clear_object (&priv->ppp_manager);
-	}
+	g_clear_object (&priv->ppp_manager);
 
 	if (device) {
 		g_return_if_fail (NM_IS_DEVICE (device));
@@ -1151,12 +1114,11 @@ deactivate_cleanup (NMModem *self, NMDevice *device)
 			}
 		}
 	}
-
-	nm_clear_g_free (&priv->data_port);
-	priv->mm_ip_timeout = 0;
 	priv->ip4_method = NM_MODEM_IP_METHOD_UNKNOWN;
 	priv->ip6_method = NM_MODEM_IP_METHOD_UNKNOWN;
-	_set_ip_ifindex (self, -1, NULL);
+
+	g_free (priv->ppp_iface);
+	priv->ppp_iface = NULL;
 }
 
 /*****************************************************************************/
@@ -1407,117 +1369,17 @@ nm_modem_get_control_port (NMModem *self)
 	return NM_MODEM_GET_PRIVATE (self)->control_port;
 }
 
-int
-nm_modem_get_ip_ifindex (NMModem *self)
-{
-	NMModemPrivate *priv;
-
-	g_return_val_if_fail (NM_IS_MODEM (self), 0);
-
-	priv = NM_MODEM_GET_PRIVATE (self);
-
-	/* internally we track an unset ip_ifindex as -1.
-	 * For the caller of nm_modem_get_ip_ifindex(), this
-	 * shall be zero too. */
-	return priv->ip_ifindex != -1 ? priv->ip_ifindex : 0;
-}
-
-static void
-_set_ip_ifindex (NMModem *self, int ifindex, const char *ifname)
-{
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
-
-	nm_assert (ifindex >= -1);
-	nm_assert ((ifindex > 0) == !!ifname);
-
-	if (!nm_streq0 (priv->ip_iface, ifname)) {
-		g_free (priv->ip_iface);
-		priv->ip_iface = g_strdup (ifname);
-	}
-
-	if (priv->ip_ifindex != ifindex) {
-		priv->ip_ifindex = ifindex;
-		_notify (self, PROP_IP_IFINDEX);
-	}
-}
-
-gboolean
-nm_modem_set_data_port (NMModem *self,
-                        NMPlatform *platform,
-                        const char *data_port,
-                        NMModemIPMethod ip4_method,
-                        NMModemIPMethod ip6_method,
-                        guint timeout,
-                        GError **error)
+const char *
+nm_modem_get_data_port (NMModem *self)
 {
-	NMModemPrivate *priv;
-	gboolean is_ppp;
-	int ifindex = -1;
-
-	g_return_val_if_fail (NM_IS_MODEM (self), FALSE);
-	g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE);
-	g_return_val_if_fail (!error || !*error, FALSE);
-
-	priv = NM_MODEM_GET_PRIVATE (self);
-
-	if (   priv->ppp_manager
-	    || priv->data_port
-	    || priv->ip_ifindex != -1) {
-		g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		                     "cannot set data port in activated state");
-		/* this really shouldn't happen. Assert. */
-		g_return_val_if_reached (FALSE);
-	}
-
-	if (!data_port) {
-		g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		                     "missing data port");
-		return FALSE;
-	}
-
-	is_ppp =    (ip4_method == NM_MODEM_IP_METHOD_PPP)
-	         || (ip6_method == NM_MODEM_IP_METHOD_PPP);
-	if (is_ppp) {
-		if (   !NM_IN_SET (ip4_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_PPP)
-		    || !NM_IN_SET (ip6_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_PPP)) {
-			g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-			                     "conflicting ip methods");
-			return FALSE;
-		}
-	} else if (   !NM_IN_SET (ip4_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_STATIC, NM_MODEM_IP_METHOD_AUTO)
-	           || !NM_IN_SET (ip6_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_STATIC, NM_MODEM_IP_METHOD_AUTO)
-	           || (   ip4_method == NM_MODEM_IP_METHOD_UNKNOWN
-	               && ip6_method == NM_MODEM_IP_METHOD_UNKNOWN)) {
-		g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-		                     "invalid ip methods");
-		return FALSE;
-	}
-
-	if (!is_ppp) {
-		ifindex = nm_platform_if_nametoindex (platform, data_port);
-		if (ifindex <= 0) {
-			g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-			             "cannot find network interface %s", data_port);
-			return FALSE;
-		}
-		if (!nm_platform_process_events_ensure_link (platform, ifindex, data_port)) {
-			g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
-			             "cannot find network interface %s in platform cache", data_port);
-			return FALSE;
-		}
-	}
+	g_return_val_if_fail (NM_IS_MODEM (self), NULL);
 
-	priv->mm_ip_timeout = timeout;
-	priv->ip4_method = ip4_method;
-	priv->ip6_method = ip6_method;
-	if (is_ppp) {
-		priv->data_port = g_strdup (data_port);
-		_set_ip_ifindex (self, -1, NULL);
-	} else {
-		priv->data_port = NULL;
-		_set_ip_ifindex (self, ifindex, data_port);
-	}
-	return TRUE;
+	/* The ppp_iface takes precedence over the data interface when PPP is used,
+	 * since data_iface is the TTY over which PPP is run, and that TTY can't
+	 * do IP.  The caller really wants the thing that's doing IP.
+	 */
+	return NM_MODEM_GET_PRIVATE (self)->ppp_iface ?
+		NM_MODEM_GET_PRIVATE (self)->ppp_iface : NM_MODEM_GET_PRIVATE (self)->data_port;
 }
 
 gboolean
@@ -1530,10 +1392,15 @@ nm_modem_owns_port (NMModem *self, const char *iface)
 	if (NM_MODEM_GET_CLASS (self)->owns_port)
 		return NM_MODEM_GET_CLASS (self)->owns_port (self, iface);
 
-	return NM_IN_STRSET (iface,
-	                     priv->ip_iface,
-	                     priv->data_port,
-	                     priv->control_port);
+	/* Fall back to data/control ports */
+	if (priv->ppp_iface && (strcmp (priv->ppp_iface, iface) == 0))
+		return TRUE;
+	if (priv->data_port && (strcmp (priv->data_port, iface) == 0))
+		return TRUE;
+	if (priv->control_port && (strcmp (priv->control_port, iface) == 0))
+		return TRUE;
+
+	return FALSE;
 }
 
 gboolean
@@ -1633,8 +1500,7 @@ static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
 {
-	NMModem *self = NM_MODEM (object);
-	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
+	NMModemPrivate *priv = NM_MODEM_GET_PRIVATE ((NMModem *) object);
 
 	switch (prop_id) {
 	case PROP_PATH:
@@ -1646,12 +1512,21 @@ get_property (GObject *object, guint prop_id,
 	case PROP_CONTROL_PORT:
 		g_value_set_string (value, priv->control_port);
 		break;
-	case PROP_IP_IFINDEX:
-		g_value_set_int (value, nm_modem_get_ip_ifindex (self));
+	case PROP_DATA_PORT:
+		g_value_set_string (value, nm_modem_get_data_port (NM_MODEM (object)));
 		break;
 	case PROP_UID:
 		g_value_set_string (value, priv->uid);
 		break;
+	case PROP_IP4_METHOD:
+		g_value_set_uint (value, priv->ip4_method);
+		break;
+	case PROP_IP6_METHOD:
+		g_value_set_uint (value, priv->ip6_method);
+		break;
+	case PROP_IP_TIMEOUT:
+		g_value_set_uint (value, priv->mm_ip_timeout);
+		break;
 	case PROP_STATE:
 		g_value_set_int (value, priv->state);
 		break;
@@ -1694,10 +1569,23 @@ set_property (GObject *object, guint prop_id,
 		/* construct-only */
 		priv->control_port = g_value_dup_string (value);
 		break;
+	case PROP_DATA_PORT:
+		g_free (priv->data_port);
+		priv->data_port = g_value_dup_string (value);
+		break;
 	case PROP_UID:
 		/* construct-only */
 		priv->uid = g_value_dup_string (value);
 		break;
+	case PROP_IP4_METHOD:
+		priv->ip4_method = g_value_get_uint (value);
+		break;
+	case PROP_IP6_METHOD:
+		priv->ip6_method = g_value_get_uint (value);
+		break;
+	case PROP_IP_TIMEOUT:
+		priv->mm_ip_timeout = g_value_get_uint (value);
+		break;
 	case PROP_STATE:
 		/* construct-only */
 		priv->state = g_value_get_int (value);
@@ -1735,7 +1623,6 @@ nm_modem_init (NMModem *self)
 	self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM, NMModemPrivate);
 	priv = self->_priv;
 
-	priv->ip_ifindex = -1;
 	priv->ip4_route_table = RT_TABLE_MAIN;
 	priv->ip4_route_metric = 700;
 	priv->ip6_route_table = RT_TABLE_MAIN;
@@ -1751,7 +1638,7 @@ constructed (GObject *object)
 
 	priv = NM_MODEM_GET_PRIVATE (NM_MODEM (object));
 
-	g_return_if_fail (priv->control_port);
+	g_return_if_fail (priv->data_port || priv->control_port);
 }
 
 /*****************************************************************************/
@@ -1776,7 +1663,6 @@ finalize (GObject *object)
 	g_free (priv->driver);
 	g_free (priv->control_port);
 	g_free (priv->data_port);
-	g_free (priv->ip_iface);
 	g_free (priv->device_id);
 	g_free (priv->sim_id);
 	g_free (priv->sim_operator_id);
@@ -1825,11 +1711,33 @@ nm_modem_class_init (NMModemClass *klass)
 	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 	                          G_PARAM_STATIC_STRINGS);
 
-	obj_properties[PROP_IP_IFINDEX] =
-	     g_param_spec_int (NM_MODEM_IP_IFINDEX, "", "",
-	                       0, G_MAXINT, 0,
-	                       G_PARAM_READABLE |
-	                       G_PARAM_STATIC_STRINGS);
+	obj_properties[PROP_DATA_PORT] =
+	     g_param_spec_string (NM_MODEM_DATA_PORT, "", "",
+	                          NULL,
+	                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+	                          G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_IP4_METHOD] =
+	     g_param_spec_uint (NM_MODEM_IP4_METHOD, "", "",
+	                        NM_MODEM_IP_METHOD_UNKNOWN,
+	                        NM_MODEM_IP_METHOD_AUTO,
+	                        NM_MODEM_IP_METHOD_UNKNOWN,
+	                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+	                        G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_IP6_METHOD] =
+	     g_param_spec_uint (NM_MODEM_IP6_METHOD, "", "",
+	                        NM_MODEM_IP_METHOD_UNKNOWN,
+	                        NM_MODEM_IP_METHOD_AUTO,
+	                        NM_MODEM_IP_METHOD_UNKNOWN,
+	                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+	                        G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_IP_TIMEOUT] =
+	     g_param_spec_uint (NM_MODEM_IP_TIMEOUT, "", "",
+	                        0, 360, 20,
+	                        G_PARAM_READWRITE |
+	                        G_PARAM_STATIC_STRINGS);
 
 	obj_properties[PROP_STATE] =
 	     g_param_spec_int (NM_MODEM_STATE, "", "",