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.
This commit is contained in:
Dan Williams 2014-02-09 03:49:55 -06:00
parent 5c1dee10cd
commit 9d50e9dbd9
4 changed files with 58 additions and 11 deletions

View file

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

View file

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

View file

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

View file

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