wwan: merge branch 'th/modem-ip-iface'

https://github.com/NetworkManager/NetworkManager/pull/55
This commit is contained in:
Thomas Haller 2018-02-22 11:45:28 +01:00
commit 0b25e30238
11 changed files with 394 additions and 293 deletions

View file

@ -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

View file

@ -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);
}
/*

View file

@ -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;

View file

@ -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, &current_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);
}

View file

@ -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

View file

@ -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);

View file

@ -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, "", "",

View file

@ -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,

View file

@ -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;
}

View file

@ -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;
}
/*****************************************************************************/
/**

View file

@ -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);