diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 977c1e1ae6..77d258ecdd 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -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,24 @@ 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); - 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_streq (base, nm_modem_get_control_port (modem))) + return FALSE; } - g_free (base); /* Got the modem */ nm_clear_g_source (&priv->timeout_id); @@ -696,7 +696,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)) @@ -753,7 +753,7 @@ bluez_connect_cb (GObject *object, GAsyncResult *res, void *user_data) { - NMDeviceBt *self = NM_DEVICE_BT (user_data); + gs_unref_object NMDeviceBt *self = NM_DEVICE_BT (user_data); NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); GError *error = NULL; const char *device; @@ -761,6 +761,9 @@ bluez_connect_cb (GObject *object, device = nm_bluez_device_connect_finish (NM_BLUEZ_DEVICE (object), res, &error); + if (!nm_device_is_activating (NM_DEVICE (self))) + return; + if (!device) { _LOGW (LOGD_BT, "Error connecting with bluez: %s", error->message); g_clear_error (&error); @@ -768,7 +771,6 @@ bluez_connect_cb (GObject *object, nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BT_FAILED); - g_object_unref (self); return; } @@ -776,7 +778,13 @@ bluez_connect_cb (GObject *object, g_free (priv->rfcomm_iface); priv->rfcomm_iface = g_strdup (device); } else if (priv->bt_type == NM_BT_CAPABILITY_NAP) { - nm_device_set_ip_iface (NM_DEVICE (self), device); + if (!nm_device_set_ip_iface (NM_DEVICE (self), device)) { + _LOGW (LOGD_BT, "Error connecting with bluez: cannot find device %s", device); + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_BT_FAILED); + return; + } } _LOGD (LOGD_BT, "connect request successful"); @@ -784,7 +792,6 @@ bluez_connect_cb (GObject *object, /* Stage 3 gets scheduled when Bluez says we're connected */ priv->have_iface = TRUE; check_connect_continue (self); - g_object_unref (self); } static void diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index ecdf7c2008..54b0097326 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1282,126 +1282,102 @@ nm_device_get_ip_ifindex (const NMDevice *self) return priv->ip_iface ? priv->ip_ifindex : priv->ifindex; } -gboolean -nm_device_set_ip_ifindex (NMDevice *self, int ifindex) +static void +_set_ip_ifindex (NMDevice *self, + int ifindex, + const char *ifname) { - NMDevicePrivate *priv; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMPlatform *platform; - const char *name = NULL; + gboolean eq_name; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + /* normalize arguments */ + if (ifindex <= 0) { + ifindex = 0; + ifname = NULL; + } - priv = NM_DEVICE_GET_PRIVATE (self); - platform = nm_device_get_platform (self); + eq_name = nm_streq0 (priv->ip_iface, ifname); - if (ifindex > 0) { - const NMPlatformLink *plink; + if ( eq_name + && priv->ip_ifindex == ifindex) + return; - plink = nm_platform_link_get (platform, ifindex); - if (!plink) { - nm_platform_process_events (platform); - plink = nm_platform_link_get (NM_PLATFORM_GET, ifindex); - } - if (!plink) { - _LOGW (LOGD_DEVICE, "ip-ifindex: ifindex %d not found", ifindex); - return FALSE; - } - name = plink->name; - } else - g_return_val_if_fail (ifindex == 0, FALSE); + _LOGD (LOGD_DEVICE, "ip-ifindex: update ip-interface to %s%s%s, ifindex %d", + NM_PRINT_FMT_QUOTE_STRING (ifname), + ifindex); - if (priv->ip_ifindex == ifindex) - return TRUE; - - _LOGD (LOGD_DEVICE, "ip-ifindex: update ifindex to %d", ifindex); priv->ip_ifindex = ifindex; - if (!nm_streq0 (priv->ip_iface, name)) { - _LOGD (LOGD_DEVICE, "ip-ifindex: update ip-iface to %s%s%s", - NM_PRINT_FMT_QUOTED (name, "\"", name, "\"", "NULL")); - priv->ip_iface = g_strdup (name); + if (!eq_name) { + g_free (priv->ip_iface); + priv->ip_iface = g_strdup (ifname); _notify (self, PROP_IP_IFACE); } if (priv->ip_ifindex > 0) { - if (nm_platform_check_kernel_support (nm_device_get_platform (self), - NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL)) - nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ip_ifindex, TRUE); + platform = nm_device_get_platform (self); - if (!nm_platform_link_is_up (nm_device_get_platform (self), priv->ip_ifindex)) - nm_platform_link_set_up (nm_device_get_platform (self), priv->ip_ifindex, NULL); + nm_platform_process_events_ensure_link (platform, + priv->ip_ifindex, + priv->ip_iface); + + if (nm_platform_check_kernel_support (platform, + NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL)) + nm_platform_link_set_user_ipv6ll_enabled (platform, priv->ip_ifindex, TRUE); + + if (!nm_platform_link_is_up (platform, priv->ip_ifindex)) + nm_platform_link_set_up (platform, priv->ip_ifindex, NULL); } /* We don't care about any saved values from the old iface */ g_hash_table_remove_all (priv->ip6_saved_properties); +} - return TRUE; +gboolean +nm_device_set_ip_ifindex (NMDevice *self, int ifindex) +{ + char ifname_buf[IFNAMSIZ]; + const char *ifname = NULL; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (nm_device_is_activating (self), FALSE); + + if (ifindex > 0) { + ifname = nm_platform_if_indextoname (nm_device_get_platform (self), ifindex, ifname_buf); + if (!ifname) + _LOGW (LOGD_DEVICE, "ip-ifindex: ifindex %d not found", ifindex); + } + + _set_ip_ifindex (self, ifindex, ifname); + return ifindex > 0; } /** * nm_device_set_ip_iface: * @self: the #NMDevice - * @iface: the new IP interface name + * @ifname: the new IP interface name * * Updates the IP interface name and possibly the ifindex. * - * Returns: %TRUE if the anything (name or ifindex) changed, %FALSE if nothing - * changed. + * Returns: %TRUE if an interface with name @ifname exists, + * and %FALSE, if @ifname is %NULL or no such interface exists. */ gboolean -nm_device_set_ip_iface (NMDevice *self, const char *iface) +nm_device_set_ip_iface (NMDevice *self, const char *ifname) { - NMDevicePrivate *priv; - int ifindex; + int ifindex = 0; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (nm_device_is_activating (self), FALSE); - priv = NM_DEVICE_GET_PRIVATE (self); - if (nm_streq0 (iface, priv->ip_iface)) { - if (!iface) - return FALSE; - ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), iface); - if ( ifindex <= 0 - || priv->ip_ifindex == ifindex) - return FALSE; - - priv->ip_ifindex = ifindex; - _LOGD (LOGD_DEVICE, "ip-ifname: update ifindex for ifname '%s': %d", iface, priv->ip_ifindex); - } else { - g_free (priv->ip_iface); - priv->ip_iface = g_strdup (iface); - - if (iface) { - /* The @iface name is not in sync with the platform cache. - * So, there is no point asking the platform cache to resolve - * the ifindex. Instead, we can only hope that the interface - * with this name still exists and we resolve the ifindex - * anew. - */ - priv->ip_ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), iface); - if (priv->ip_ifindex > 0) - _LOGD (LOGD_DEVICE, "ip-ifname: set ifname '%s', ifindex %d", iface, priv->ip_ifindex); - else - _LOGW (LOGD_DEVICE, "ip-ifname: set ifname '%s', unknown ifindex", iface); - } else { - priv->ip_ifindex = 0; - _LOGD (LOGD_DEVICE, "ip-ifname: clear ifname"); - } + if (ifname) { + ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), ifname); + if (ifindex <= 0) + _LOGW (LOGD_DEVICE, "ip-ifindex: ifname %s not found", ifname); } - if (priv->ip_ifindex > 0) { - if (nm_platform_check_kernel_support (nm_device_get_platform (self), - NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL)) - nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ip_ifindex, TRUE); - - if (!nm_platform_link_is_up (nm_device_get_platform (self), priv->ip_ifindex)) - nm_platform_link_set_up (nm_device_get_platform (self), priv->ip_ifindex, NULL); - } - - /* We don't care about any saved values from the old iface */ - g_hash_table_remove_all (priv->ip6_saved_properties); - - _notify (self, PROP_IP_IFACE); - return TRUE; + _set_ip_ifindex (self, ifindex, ifname); + return ifindex > 0; } static gboolean @@ -12941,7 +12917,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) * those are identified by ip_iface, not by iface (which might be a tty * or ATM device). */ - nm_device_set_ip_iface (self, NULL); + _set_ip_ifindex (self, 0, NULL); } /* diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver index 6efcb03fa7..70b954c5d8 100644 --- a/src/devices/wwan/libnm-wwan.ver +++ b/src/devices/wwan/libnm-wwan.ver @@ -11,10 +11,10 @@ global: nm_modem_get_capabilities; nm_modem_get_configured_mtu; nm_modem_get_control_port; - nm_modem_get_data_port; 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 b79d145d1f..7aa2fd9315 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 changed; + NMDevice *device = NM_DEVICE (user_data); - /* We set the IP iface in the device as soon as we know it, so that we - * properly ifup it if needed */ - changed = nm_device_set_ip_iface (self, nm_modem_get_data_port (modem)); + if (!nm_device_is_activating (device)) + return; + + 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 (changed) - nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); + nm_device_ipv6_sysctl_set (device, "disable_ipv6", "1"); } static void @@ -629,11 +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); - /* In the old ModemManager the data port is known from the very beginning; - * while in the new ModemManager the data port is set afterwards when the bearer gets - * created */ - 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); @@ -708,34 +709,23 @@ nm_device_modem_new (NMModem *modem) { NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE; NMDeviceModemCapabilities current_caps = NM_DEVICE_MODEM_CAPABILITY_NONE; - NMDevice *device; - const char *data_port; g_return_val_if_fail (NM_IS_MODEM (modem), NULL); /* Load capabilities */ nm_modem_get_capabilities (modem, &caps, ¤t_caps); - device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_MODEM, - NM_DEVICE_UDI, nm_modem_get_path (modem), - NM_DEVICE_IFACE, nm_modem_get_uid (modem), - NM_DEVICE_DRIVER, nm_modem_get_driver (modem), - NM_DEVICE_TYPE_DESC, "Broadband", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_MODEM, - NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WWAN, - NM_DEVICE_MODEM_MODEM, modem, - NM_DEVICE_MODEM_CAPABILITIES, caps, - NM_DEVICE_MODEM_CURRENT_CAPABILITIES, current_caps, - NULL); - - /* If the data port is known, set it as the IP interface immediately */ - data_port = nm_modem_get_data_port (modem); - if (data_port) { - nm_device_set_ip_iface (device, data_port); - nm_device_ipv6_sysctl_set (device, "disable_ipv6", "1"); - } - - return device; + return g_object_new (NM_TYPE_DEVICE_MODEM, + NM_DEVICE_UDI, nm_modem_get_path (modem), + NM_DEVICE_IFACE, nm_modem_get_uid (modem), + NM_DEVICE_DRIVER, nm_modem_get_driver (modem), + NM_DEVICE_TYPE_DESC, "Broadband", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_MODEM, + NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WWAN, + NM_DEVICE_MODEM_MODEM, modem, + NM_DEVICE_MODEM_CAPABILITIES, caps, + NM_DEVICE_MODEM_CURRENT_CAPABILITIES, current_caps, + NULL); } static void @@ -743,9 +733,10 @@ dispose (GObject *object) { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) object); - if (priv->modem) + if (priv->modem) { g_signal_handlers_disconnect_by_data (priv->modem, NM_DEVICE_MODEM (object)); - g_clear_object (&priv->modem); + g_clear_object (&priv->modem); + } G_OBJECT_CLASS (nm_device_modem_parent_class)->dispose (object); } diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index dc0ce303ca..683d6ed84f 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -385,9 +385,10 @@ connect_ready (MMModemSimple *simple_iface, g_dbus_error_strip_remote_error (error); ctx->first_error = error; } else - g_error_free (error); + g_clear_error (&error); - if (ctx->ip_type_tries == 0 && g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)) { + if ( ctx->ip_type_tries == 0 + && g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)) { /* Try one more time */ ctx->ip_type_tries++; } else { @@ -410,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); } @@ -1409,35 +1409,34 @@ nm_modem_broadband_init (NMModemBroadband *self) NMModem * nm_modem_broadband_new (GObject *object, GError **error) { - NMModem *modem; MMObject *modem_object; MMModem *modem_iface; - gchar *drivers; + const char *const*drivers; + gs_free char *driver = NULL; g_return_val_if_fail (MM_IS_OBJECT (object), NULL); modem_object = MM_OBJECT (object); /* Ensure we have the 'Modem' interface and the primary port at least */ modem_iface = mm_object_peek_modem (modem_object); - g_return_val_if_fail (!!modem_iface, NULL); - g_return_val_if_fail (!!mm_modem_get_primary_port (modem_iface), NULL); + g_return_val_if_fail (modem_iface, NULL); + g_return_val_if_fail (mm_modem_get_primary_port (modem_iface), NULL); /* Build a single string with all drivers listed */ - drivers = g_strjoinv (", ", (gchar **)mm_modem_get_drivers (modem_iface)); + drivers = mm_modem_get_drivers (modem_iface); + if (drivers) + driver = g_strjoinv (", ", (char **) drivers); - modem = g_object_new (NM_TYPE_MODEM_BROADBAND, - NM_MODEM_PATH, mm_object_get_path (modem_object), - NM_MODEM_UID, mm_modem_get_primary_port (modem_iface), - NM_MODEM_CONTROL_PORT, mm_modem_get_primary_port (modem_iface), - NM_MODEM_DATA_PORT, NULL, /* We don't know it until bearer created */ - NM_MODEM_IP_TYPES, mm_ip_family_to_nm (mm_modem_get_supported_ip_families (modem_iface)), - NM_MODEM_STATE, (int) mm_state_to_nm (mm_modem_get_state (modem_iface)), - NM_MODEM_DEVICE_ID, mm_modem_get_device_identifier (modem_iface), - NM_MODEM_BROADBAND_MODEM, modem_object, - NM_MODEM_DRIVER, drivers, - NULL); - g_free (drivers); - return modem; + return g_object_new (NM_TYPE_MODEM_BROADBAND, + NM_MODEM_PATH, mm_object_get_path (modem_object), + NM_MODEM_UID, mm_modem_get_primary_port (modem_iface), + NM_MODEM_CONTROL_PORT, mm_modem_get_primary_port (modem_iface), + NM_MODEM_IP_TYPES, mm_ip_family_to_nm (mm_modem_get_supported_ip_families (modem_iface)), + NM_MODEM_STATE, (int) mm_state_to_nm (mm_modem_get_state (modem_iface)), + NM_MODEM_DEVICE_ID, mm_modem_get_device_identifier (modem_iface), + NM_MODEM_BROADBAND_MODEM, modem_object, + NM_MODEM_DRIVER, driver, + NULL); } static void diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 811c3afb27..a1c6aef256 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); - 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); + 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; + } + + 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 10baa424af..85f6eb039e 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -44,13 +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, @@ -79,7 +76,12 @@ typedef struct _NMModemPrivate { char *driver; char *control_port; char *data_port; - char *ppp_iface; + + /* 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; NMUtilsIPv6IfaceId iid; @@ -96,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; @@ -152,6 +154,10 @@ _nmlog_prefix (char *prefix, NMModem *self) _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } G_STMT_END +/*****************************************************************************/ + +static void _set_ip_ifindex (NMModem *self, int ifindex, const char *ifname); + /*****************************************************************************/ /* State/enabled/connected */ @@ -456,16 +462,18 @@ ppp_ifindex_set (NMPPPManager *ppp_manager, gpointer user_data) { NMModem *self = NM_MODEM (user_data); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - /* 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 (ifindex >= 0); + 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, iface); } static void @@ -556,6 +564,18 @@ 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) @@ -597,6 +617,12 @@ 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) { @@ -628,9 +654,7 @@ 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; } @@ -1097,7 +1121,10 @@ deactivate_cleanup (NMModem *self, NMDevice *device) priv->in_bytes = priv->out_bytes = 0; - g_clear_object (&priv->ppp_manager); + if (priv->ppp_manager) { + g_signal_handlers_disconnect_by_data (priv->ppp_manager, self); + g_clear_object (&priv->ppp_manager); + } if (device) { g_return_if_fail (NM_IS_DEVICE (device)); @@ -1116,11 +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; - - g_free (priv->ppp_iface); - priv->ppp_iface = NULL; + _set_ip_ifindex (self, -1, NULL); } /*****************************************************************************/ @@ -1371,17 +1399,117 @@ nm_modem_get_control_port (NMModem *self) return NM_MODEM_GET_PRIVATE (self)->control_port; } -const char * -nm_modem_get_data_port (NMModem *self) +int +nm_modem_get_ip_ifindex (NMModem *self) { - g_return_val_if_fail (NM_IS_MODEM (self), NULL); + NMModemPrivate *priv; - /* 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; + 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) +{ + 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 @@ -1394,15 +1522,10 @@ 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); - /* 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; + return NM_IN_STRSET (iface, + priv->ip_iface, + priv->data_port, + priv->control_port); } gboolean @@ -1502,7 +1625,8 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE ((NMModem *) object); + NMModem *self = NM_MODEM (object); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); switch (prop_id) { case PROP_PATH: @@ -1514,21 +1638,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 (NM_MODEM (object))); + 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; @@ -1571,23 +1686,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); @@ -1625,6 +1727,7 @@ 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; @@ -1640,7 +1743,7 @@ constructed (GObject *object) priv = NM_MODEM_GET_PRIVATE (NM_MODEM (object)); - g_return_if_fail (priv->data_port || priv->control_port); + g_return_if_fail (priv->control_port); } /*****************************************************************************/ @@ -1665,6 +1768,7 @@ 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); @@ -1713,33 +1817,11 @@ 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_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_IP_IFINDEX] = + g_param_spec_int (NM_MODEM_IP_IFINDEX, "", "", + 0, G_MAXINT, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_STATE] = g_param_spec_int (NM_MODEM_STATE, "", "", diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index 9546e4a12e..a95da25534 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -37,10 +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_IP4_METHOD "ip4-method" -#define NM_MODEM_IP6_METHOD "ip6-method" -#define NM_MODEM_IP_TIMEOUT "ip-timeout" +#define NM_MODEM_IP_IFINDEX "ip-ifindex" #define NM_MODEM_STATE "state" #define NM_MODEM_DEVICE_ID "device-id" #define NM_MODEM_SIM_ID "sim-id" @@ -167,13 +164,21 @@ GType nm_modem_get_type (void); const char *nm_modem_get_path (NMModem *modem); const char *nm_modem_get_uid (NMModem *modem); const char *nm_modem_get_control_port (NMModem *modem); -const char *nm_modem_get_data_port (NMModem *modem); +int nm_modem_get_ip_ifindex (NMModem *modem); const char *nm_modem_get_driver (NMModem *modem); const char *nm_modem_get_device_id (NMModem *modem); 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 663102de4d..f0aae04008 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,8 @@ 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_control_port (modem)); return; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 2c12359cfc..6f483fa654 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -353,6 +353,45 @@ nm_platform_process_events (NMPlatform *self) klass->process_events (self); } +const NMPlatformLink * +nm_platform_process_events_ensure_link (NMPlatform *self, + int ifindex, + const char *ifname) +{ + const NMPObject *obj; + gboolean refreshed = FALSE; + + g_return_val_if_fail (NM_IS_PLATFORM (self), NULL); + + if (ifindex <= 0 && !ifname) + return NULL; + + /* we look into the cache, whether a link for given ifindex/ifname + * exits. If not, we poll the netlink socket, maybe the event + * with the link is waiting. + * + * Then we try again to find the object. + * + * If the link is already cached the first time, we avoid polling + * the netlink socket. */ +again: + obj = nmp_cache_lookup_link_full (nm_platform_get_cache (self), + ifindex, + ifname, + FALSE, /* also invisible. We don't care here whether udev is ready */ + NM_LINK_TYPE_NONE, + NULL, NULL); + if (obj) + return NMP_OBJECT_CAST_LINK (obj); + if (!refreshed) { + refreshed = TRUE; + nm_platform_process_events (self); + goto again; + } + + return NULL; +} + /*****************************************************************************/ /** diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index a545485183..53b2975bf5 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -1106,6 +1106,10 @@ const char *nm_platform_link_get_type_name (NMPlatform *self, int ifindex); gboolean nm_platform_link_refresh (NMPlatform *self, int ifindex); void nm_platform_process_events (NMPlatform *self); +const NMPlatformLink *nm_platform_process_events_ensure_link (NMPlatform *self, + int ifindex, + const char *ifname); + gboolean nm_platform_link_set_up (NMPlatform *self, int ifindex, gboolean *out_no_firmware); gboolean nm_platform_link_set_down (NMPlatform *self, int ifindex); gboolean nm_platform_link_set_arp (NMPlatform *self, int ifindex);