summaryrefslogtreecommitdiff
path: root/src/devices/wwan
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-01-11 09:47:30 +0100
committerThomas Haller <thaller@redhat.com>2018-02-21 20:28:46 +0100
commitc7b3586b9db49fed8926d746ec24e3d21b542f42 (patch)
tree9f25cf61525bbb144688802a003111eae0a8d171 /src/devices/wwan
parent2ea8e1029fc3a4f51e240ea4b90a74f5031a608b (diff)
wwan: rework setting modem's data-port
Depending on the bearer's configuration method, the data-port is either a networking interface, or an tty for ppp. Let's treat them strictily separate. Also, rework how NM_MODEM_DATA_PORT was used in both contexts. Instead, use the that we actually care about. Also, when nm_device_set_ip_ifindex() fails, fail activation right away. Also, we early try to resolve the network interface's name to an ifindex. If that fails, the device is already gone and we fail early.
Diffstat (limited to 'src/devices/wwan')
-rw-r--r--src/devices/wwan/libnm-wwan.ver1
-rw-r--r--src/devices/wwan/nm-device-modem.c23
-rw-r--r--src/devices/wwan/nm-modem-broadband.c19
-rw-r--r--src/devices/wwan/nm-modem-ofono.c26
-rw-r--r--src/devices/wwan/nm-modem.c199
-rw-r--r--src/devices/wwan/nm-modem.h12
-rw-r--r--src/devices/wwan/nm-wwan-factory.c9
7 files changed, 165 insertions, 124 deletions
diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver
index 6efcb03fa..d30a175ce 100644
--- a/src/devices/wwan/libnm-wwan.ver
+++ b/src/devices/wwan/libnm-wwan.ver
@@ -15,6 +15,7 @@ global:
nm_modem_get_driver;
nm_modem_get_iid;
nm_modem_get_path;
+ nm_modem_get_ip_ifindex;
nm_modem_get_secrets;
nm_modem_get_state;
nm_modem_get_type;
diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c
index 86f186494..7aa2fd931 100644
--- a/src/devices/wwan/nm-device-modem.c
+++ b/src/devices/wwan/nm-device-modem.c
@@ -260,21 +260,26 @@ modem_ip6_config_result (NMModem *modem,
}
static void
-data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data)
+ip_ifindex_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data)
{
- NMDevice *self = NM_DEVICE (user_data);
- gboolean has_ifindex;
+ NMDevice *device = NM_DEVICE (user_data);
+
+ if (!nm_device_is_activating (device))
+ return;
- /* We set the IP iface in the device as soon as we know it, so that we
- * properly ifup it if needed */
- has_ifindex = nm_device_set_ip_iface (self, nm_modem_get_data_port (modem));
+ if (!nm_device_set_ip_ifindex (device,
+ nm_modem_get_ip_ifindex (modem))) {
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+ return;
+ }
/* Disable IPv6 immediately on the interface since NM handles IPv6
* internally, and leaving it enabled could allow the kernel's IPv6
* RA handling code to run before NM is ready.
*/
- if (has_ifindex)
- nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1");
+ nm_device_ipv6_sysctl_set (device, "disable_ipv6", "1");
}
static void
@@ -629,7 +634,7 @@ set_modem (NMDeviceModem *self, NMModem *modem)
g_signal_connect (modem, NM_MODEM_STATE_CHANGED, G_CALLBACK (modem_state_cb), self);
g_signal_connect (modem, NM_MODEM_REMOVED, G_CALLBACK (modem_removed_cb), self);
- g_signal_connect (modem, "notify::" NM_MODEM_DATA_PORT, G_CALLBACK (data_port_changed_cb), self);
+ g_signal_connect (modem, "notify::" NM_MODEM_IP_IFINDEX, G_CALLBACK (ip_ifindex_changed_cb), self);
g_signal_connect (modem, "notify::" NM_MODEM_DEVICE_ID, G_CALLBACK (ids_changed_cb), self);
g_signal_connect (modem, "notify::" NM_MODEM_SIM_ID, G_CALLBACK (ids_changed_cb), self);
g_signal_connect (modem, "notify::" NM_MODEM_SIM_OPERATOR_ID, G_CALLBACK (ids_changed_cb), self);
diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c
index dd3328f86..683d6ed84 100644
--- a/src/devices/wwan/nm-modem-broadband.c
+++ b/src/devices/wwan/nm-modem-broadband.c
@@ -411,21 +411,20 @@ connect_ready (MMModemSimple *simple_iface,
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) {
- _LOGW ("failed to connect modem: invalid bearer IP configuration");
+ if (!nm_modem_set_data_port (NM_MODEM (self),
+ NM_PLATFORM_GET,
+ mm_bearer_get_interface (self->_priv.bearer),
+ ip4_method,
+ ip6_method,
+ mm_bearer_get_ip_timeout (self->_priv.bearer),
+ &error)) {
+ _LOGW ("failed to connect modem: %s", error->message);
+ g_error_free (error);
nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
connect_context_clear (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);
-
ctx->step++;
connect_context_step (self);
}
diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c
index 811c3afb2..a1c6aef25 100644
--- a/src/devices/wwan/nm-modem-ofono.c
+++ b/src/devices/wwan/nm-modem-ofono.c
@@ -836,6 +836,7 @@ context_property_changed (GDBusProxy *proxy,
guint32 address_network, gateway_network;
guint32 ip4_route_table, ip4_route_metric;
int ifindex;
+ GError *error = NULL;
_LOGD ("PropertyChanged: %s", property);
@@ -860,27 +861,26 @@ context_property_changed (GDBusProxy *proxy,
_LOGW ("Settings 'Interface' missing");
goto out;
}
- if (!interface || !interface[0]) {
- _LOGW ("Settings 'Interface'; empty");
- goto out;
- }
- ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, interface);
- if (ifindex <= 0) {
- _LOGW ("Interface \"%s\" not found", interface);
+ _LOGD ("Interface: %s", interface);
+ if (!nm_modem_set_data_port (NM_MODEM (self),
+ NM_PLATFORM_GET,
+ interface,
+ NM_MODEM_IP_METHOD_STATIC,
+ NM_MODEM_IP_METHOD_UNKNOWN,
+ 0,
+ &error)) {
+ _LOGW ("failed to connect to modem: %s", error->message);
+ g_clear_error (&error);
goto out;
}
- _LOGD ("Interface: %s", interface);
- g_object_set (self,
- NM_MODEM_DATA_PORT, interface,
- NM_MODEM_IP4_METHOD, NM_MODEM_IP_METHOD_STATIC,
- NULL);
+ ifindex = nm_modem_get_ip_ifindex (NM_MODEM (self));
+ nm_assert (ifindex > 0);
/* TODO: verify handling of ip4_config; check other places it's used... */
g_clear_object (&priv->ip4_config);
-
priv->ip4_config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
ifindex);
diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c
index 491334d20..873d87187 100644
--- a/src/devices/wwan/nm-modem.c
+++ b/src/devices/wwan/nm-modem.c
@@ -44,14 +44,10 @@
NM_GOBJECT_PROPERTIES_DEFINE (NMModem,
PROP_CONTROL_PORT,
- PROP_DATA_PORT,
PROP_IP_IFINDEX,
PROP_PATH,
PROP_UID,
PROP_DRIVER,
- PROP_IP4_METHOD,
- PROP_IP6_METHOD,
- PROP_IP_TIMEOUT,
PROP_STATE,
PROP_DEVICE_ID,
PROP_SIM_ID,
@@ -80,7 +76,11 @@ 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;
NMModemIPMethod ip4_method;
NMModemIPMethod ip6_method;
@@ -98,7 +98,7 @@ typedef struct _NMModemPrivate {
guint32 secrets_tries;
NMActRequestGetSecretsCallId *secrets_id;
- guint32 mm_ip_timeout;
+ guint mm_ip_timeout;
guint32 ip4_route_table;
guint32 ip4_route_metric;
@@ -156,7 +156,7 @@ _nmlog_prefix (char *prefix, NMModem *self)
/*****************************************************************************/
-static void _set_ip_ifindex (NMModem *self, int ifindex);
+static void _set_ip_ifindex (NMModem *self, int ifindex, const char *ifname);
/*****************************************************************************/
/* State/enabled/connected */
@@ -462,19 +462,18 @@ ppp_ifindex_set (NMPPPManager *ppp_manager,
gpointer user_data)
{
NMModem *self = NM_MODEM (user_data);
- NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
nm_assert (ifindex >= 0);
-
- /* Notify about the new data port to use.
- *
- * @iface might be %NULL. */
- if (g_strcmp0 (priv->data_port, iface) != 0) {
- g_free (priv->data_port);
- priv->data_port = g_strdup (iface);
- _notify (self, PROP_DATA_PORT);
+ nm_assert (NM_MODEM_GET_PRIVATE (self)->ppp_manager == ppp_manager);
+
+ 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;
}
- _set_ip_ifindex (self, ifindex);
+ _set_ip_ifindex (self, ifindex, iface);
}
static void
@@ -565,9 +564,19 @@ 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)
return FALSE;
@@ -1134,12 +1143,12 @@ 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);
- if (nm_clear_g_free (&priv->ip_iface))
- _notify (self, PROP_DATA_PORT);
+ _set_ip_ifindex (self, -1, NULL);
}
/*****************************************************************************/
@@ -1393,17 +1402,9 @@ nm_modem_get_control_port (NMModem *self)
const char *
nm_modem_get_data_port (NMModem *self)
{
- NMModemPrivate *priv;
-
g_return_val_if_fail (NM_IS_MODEM (self), NULL);
- priv = NM_MODEM_GET_PRIVATE (self);
-
- /* The ip_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 priv->ip_iface ?: priv->data_port;
+ return NM_MODEM_GET_PRIVATE (self)->data_port;
}
int
@@ -1422,11 +1423,17 @@ nm_modem_get_ip_ifindex (NMModem *self)
}
static void
-_set_ip_ifindex (NMModem *self, int ifindex)
+_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;
@@ -1435,6 +1442,85 @@ _set_ip_ifindex (NMModem *self, int 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)
+{
+ 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;
+ }
+ }
+
+ 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;
+}
+
+gboolean
nm_modem_owns_port (NMModem *self, const char *iface)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
@@ -1560,24 +1646,12 @@ get_property (GObject *object, guint prop_id,
case PROP_CONTROL_PORT:
g_value_set_string (value, priv->control_port);
break;
- case PROP_DATA_PORT:
- g_value_set_string (value, nm_modem_get_data_port (self));
- break;
case PROP_IP_IFINDEX:
g_value_set_int (value, nm_modem_get_ip_ifindex (self));
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;
@@ -1620,23 +1694,10 @@ 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);
@@ -1764,40 +1825,12 @@ nm_modem_class_init (NMModemClass *klass)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_DATA_PORT] =
- g_param_spec_string (NM_MODEM_DATA_PORT, "", "",
- NULL,
- G_PARAM_READWRITE |
- 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_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, "", "",
NM_MODEM_STATE_UNKNOWN, _NM_MODEM_STATE_LAST, NM_MODEM_STATE_UNKNOWN,
diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h
index 39b85d0a4..047cb37af 100644
--- a/src/devices/wwan/nm-modem.h
+++ b/src/devices/wwan/nm-modem.h
@@ -37,11 +37,7 @@
#define NM_MODEM_PATH "path"
#define NM_MODEM_DRIVER "driver"
#define NM_MODEM_CONTROL_PORT "control-port"
-#define NM_MODEM_DATA_PORT "data-port"
#define NM_MODEM_IP_IFINDEX "ip-ifindex"
-#define NM_MODEM_IP4_METHOD "ip4-method"
-#define NM_MODEM_IP6_METHOD "ip6-method"
-#define NM_MODEM_IP_TIMEOUT "ip-timeout"
#define NM_MODEM_STATE "state"
#define NM_MODEM_DEVICE_ID "device-id"
#define NM_MODEM_SIM_ID "sim-id"
@@ -176,6 +172,14 @@ const char *nm_modem_get_sim_id (NMModem *modem);
const char *nm_modem_get_sim_operator_id (NMModem *modem);
gboolean nm_modem_get_iid (NMModem *modem, NMUtilsIPv6IfaceId *out_iid);
+gboolean nm_modem_set_data_port (NMModem *self,
+ NMPlatform *platform,
+ const char *data_port,
+ NMModemIPMethod ip4_method,
+ NMModemIPMethod ip6_method,
+ guint timeout,
+ GError **error);
+
gboolean nm_modem_owns_port (NMModem *modem, const char *iface);
void nm_modem_get_capabilities (NMModem *self,
diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c
index 663102de4..8767fe09c 100644
--- a/src/devices/wwan/nm-wwan-factory.c
+++ b/src/devices/wwan/nm-wwan-factory.c
@@ -80,7 +80,7 @@ modem_added_cb (NMModemManager *manager,
{
NMWwanFactory *self = NM_WWAN_FACTORY (user_data);
NMDevice *device;
- const char *driver, *port;
+ const char *driver;
/* Do nothing if the modem was consumed by some other plugin */
if (nm_device_factory_emit_component_added (NM_DEVICE_FACTORY (self), G_OBJECT (modem)))
@@ -93,10 +93,9 @@ modem_added_cb (NMModemManager *manager,
* by the Bluetooth code during the connection process.
*/
if (driver && strstr (driver, "bluetooth")) {
- port = nm_modem_get_data_port (modem);
- if (!port)
- port = nm_modem_get_control_port (modem);
- nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", port);
+ nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)",
+ nm_modem_get_data_port (modem)
+ ?: nm_modem_get_control_port (modem));
return;
}