From 9d50e9dbd9d84f5e8df32895bc245dadf133aa39 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 9 Feb 2014 03:49:55 -0600 Subject: [PATCH] mobile: fix removal of ethernet interfaces owned by modems If the kernel doesn't tag a modem's ethernet interface with DEVTYPE=wwan then NetworkManager has no idea that's a modem (and cannot be used until connected via the control port). Since DEVTYPE=wwan devices get ignored by NM, so should these interfaces when NM knows they are modems. That got broken at some point for ModemManager1, because the data port isn't read until the modem is connected. NM only looked for and removed the data-port-as-ethernet-device when the modem was added, long before the MM1 data port was found. ModemManager does provide a list of ports owned by the modem though, which we can use at modem addition time to remove an ethernet device that is controled by the modem. --- src/modem-manager/nm-modem-broadband.c | 15 +++++++++++++ src/modem-manager/nm-modem.c | 21 +++++++++++++++++++ src/modem-manager/nm-modem.h | 4 ++++ src/nm-manager.c | 29 ++++++++++++++++---------- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/modem-manager/nm-modem-broadband.c b/src/modem-manager/nm-modem-broadband.c index 611931f6b9..5acce68f79 100644 --- a/src/modem-manager/nm-modem-broadband.c +++ b/src/modem-manager/nm-modem-broadband.c @@ -124,6 +124,20 @@ get_capabilities (NMModem *_self, *current_caps = (NMDeviceModemCapabilities) mm_modem_get_current_capabilities (self->priv->modem_iface); } +static gboolean +owns_port (NMModem *_self, const char *iface) +{ + NMModemBroadband *self = NM_MODEM_BROADBAND (_self); + const MMModemPortInfo *ports = NULL; + guint n_ports = 0, i; + gboolean owns = FALSE; + + mm_modem_peek_ports (self->priv->modem_iface, &ports, &n_ports); + for (i = 0; i < n_ports && !owns; i++) + owns = (g_strcmp0 (iface, ports[i].name) == 0); + return owns; +} + /*****************************************************************************/ static void @@ -916,6 +930,7 @@ nm_modem_broadband_class_init (NMModemBroadbandClass *klass) modem_class->check_connection_compatible = check_connection_compatible; modem_class->complete_connection = complete_connection; modem_class->act_stage1_prepare = act_stage1_prepare; + modem_class->owns_port = owns_port; /* Properties */ g_object_class_install_property diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c index f427142e2b..e88ebe1bd7 100644 --- a/src/modem-manager/nm-modem.c +++ b/src/modem-manager/nm-modem.c @@ -661,6 +661,27 @@ nm_modem_get_data_port (NMModem *self) NM_MODEM_GET_PRIVATE (self)->ppp_iface : NM_MODEM_GET_PRIVATE (self)->data_port; } +gboolean +nm_modem_owns_port (NMModem *self, const char *iface) +{ + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + + g_return_val_if_fail (iface != NULL, FALSE); + + 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; +} + /*****************************************************************************/ void diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h index 531c79388e..db20407006 100644 --- a/src/modem-manager/nm-modem.h +++ b/src/modem-manager/nm-modem.h @@ -108,6 +108,8 @@ typedef struct { void (*deactivate) (NMModem *self, NMDevice *device); + gboolean (*owns_port) (NMModem *self, const char *iface); + /* Signals */ void (*ppp_stats) (NMModem *self, guint32 in_bytes, guint32 out_bytes); void (*ppp_failed) (NMModem *self, NMDeviceStateReason reason); @@ -127,6 +129,8 @@ const char *nm_modem_get_control_port (NMModem *modem); const char *nm_modem_get_data_port (NMModem *modem); const char *nm_modem_get_driver (NMModem *modem); +gboolean nm_modem_owns_port (NMModem *modem, const char *iface); + void nm_modem_get_capabilities (NMModem *self, NMDeviceModemCapabilities *modem_caps, NMDeviceModemCapabilities *current_caps); diff --git a/src/nm-manager.c b/src/nm-manager.c index 3ae48c8538..7cb71a63c7 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -550,19 +550,22 @@ modem_added (NMModemManager *modem_manager, { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *replace_device, *device = NULL; + NMDevice *device = NULL; const char *modem_iface; - GSList *iter; + GSList *iter, *remove = NULL; - /* Don't rely only on the data port; use the control port if available */ - modem_iface = nm_modem_get_data_port (modem); - if (!modem_iface) - modem_iface = nm_modem_get_control_port (modem); - g_return_if_fail (modem_iface); - - replace_device = find_device_by_ip_iface (NM_MANAGER (user_data), modem_iface); - if (replace_device) - remove_device (NM_MANAGER (user_data), replace_device, FALSE); + /* Remove ethernet devices that are actually owned by the modem, since + * they cannot be used as normal ethernet. + */ + for (iter = priv->devices; iter; iter = iter->next) { + if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_ETHERNET) { + if (nm_modem_owns_port (modem, nm_device_get_ip_iface (iter->data))) + remove = g_slist_prepend (remove, iter->data); + } + } + for (iter = remove; iter; iter = iter->next) + remove_device (self, NM_DEVICE (iter->data), FALSE); + g_slist_free (remove); /* Give Bluetooth DUN devices first chance to claim the modem */ for (iter = priv->devices; iter; iter = g_slist_next (iter)) { @@ -577,6 +580,10 @@ modem_added (NMModemManager *modem_manager, * by the Bluetooth code during the connection process. */ if (driver && !strcmp (driver, "bluetooth")) { + modem_iface = nm_modem_get_data_port (modem); + if (!modem_iface) + modem_iface = nm_modem_get_control_port (modem); + nm_log_info (LOGD_MB, "ignoring modem '%s' (no associated Bluetooth device)", modem_iface); return; }