Commit c7b3586b authored by Thomas Haller's avatar Thomas Haller
Browse files

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.
parent 2ea8e102
......@@ -540,11 +540,16 @@ modem_ip4_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);
NMDevice *device = NM_DEVICE (user_data);
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);
}
}
static gboolean
......@@ -640,29 +645,26 @@ component_added (NMDevice *device, GObject *component)
NMDeviceBt *self = NM_DEVICE_BT (device);
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
NMModem *modem;
const gchar *modem_data_port;
const gchar *modem_control_port;
char *base;
NMDeviceState state;
NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE;
if (!component || !NM_IS_MODEM (component))
if ( !component
|| !NM_IS_MODEM (component))
return FALSE;
modem = NM_MODEM (component);
modem_data_port = nm_modem_get_data_port (modem);
modem_control_port = nm_modem_get_control_port (modem);
g_return_val_if_fail (modem_data_port != NULL || modem_control_port != NULL, FALSE);
modem = NM_MODEM (component);
if (!priv->rfcomm_iface)
return FALSE;
base = g_path_get_basename (priv->rfcomm_iface);
if (g_strcmp0 (base, modem_data_port) && g_strcmp0 (base, modem_control_port)) {
g_free (base);
return FALSE;
{
gs_free char *base = NULL;
base = g_path_get_basename (priv->rfcomm_iface);
if (!NM_IN_STRSET (base,
nm_modem_get_control_port (modem),
nm_modem_get_data_port (modem)))
return FALSE;
}
g_free (base);
/* Got the modem */
nm_clear_g_source (&priv->timeout_id);
......@@ -696,7 +698,7 @@ component_added (NMDevice *device, GObject *component)
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);
/* Kick off the modem connection */
if (!modem_stage1 (self, modem, &failure_reason))
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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;
......@@ -1434,6 +1441,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)
{
......@@ -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,
......
......@@ -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,
......
......@@ -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;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment