Commit cb4b0d48 authored by Antonio Quartulli's avatar Antonio Quartulli

batman-adv: free an hard-interface before adding it

When adding a new hard interface (e.g. wlan0) to a soft interface (e.g. bat0)
and the former is already enslaved in another virtual interface (e.g. a software
bridge) batman-adv has to free it first and then continue with the adding
mechanism.

In this way the behaviour becomes consistent with what "ip link set master"
does. At the moment batman-adv enslaves the hard interface without checking for
the master device, possibly causing strange behaviours which are never wanted by
the users.
Reported-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
Signed-off-by: default avatarAntonio Quartulli <ordex@autistici.org>
Signed-off-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
parent 3dbd550b
...@@ -307,11 +307,35 @@ batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface) ...@@ -307,11 +307,35 @@ batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
batadv_update_min_mtu(hard_iface->soft_iface); batadv_update_min_mtu(hard_iface->soft_iface);
} }
/**
* batadv_master_del_slave - remove hard_iface from the current master interface
* @slave: the interface enslaved in another master
* @master: the master from which slave has to be removed
*
* Invoke ndo_del_slave on master passing slave as argument. In this way slave
* is free'd and master can correctly change its internal state.
* Return 0 on success, a negative value representing the error otherwise
*/
static int batadv_master_del_slave(struct batadv_hard_iface *slave,
struct net_device *master)
{
int ret;
if (!master)
return 0;
ret = -EBUSY;
if (master->netdev_ops->ndo_del_slave)
ret = master->netdev_ops->ndo_del_slave(master, slave->net_dev);
return ret;
}
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
const char *iface_name) const char *iface_name)
{ {
struct batadv_priv *bat_priv; struct batadv_priv *bat_priv;
struct net_device *soft_iface; struct net_device *soft_iface, *master;
__be16 ethertype = __constant_htons(ETH_P_BATMAN); __be16 ethertype = __constant_htons(ETH_P_BATMAN);
int ret; int ret;
...@@ -321,11 +345,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, ...@@ -321,11 +345,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (!atomic_inc_not_zero(&hard_iface->refcount)) if (!atomic_inc_not_zero(&hard_iface->refcount))
goto out; goto out;
/* hard-interface is part of a bridge */
if (hard_iface->net_dev->priv_flags & IFF_BRIDGE_PORT)
pr_err("You are about to enable batman-adv on '%s' which already is part of a bridge. Unless you know exactly what you are doing this is probably wrong and won't work the way you think it would.\n",
hard_iface->net_dev->name);
soft_iface = dev_get_by_name(&init_net, iface_name); soft_iface = dev_get_by_name(&init_net, iface_name);
if (!soft_iface) { if (!soft_iface) {
...@@ -347,6 +366,14 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, ...@@ -347,6 +366,14 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
goto err_dev; goto err_dev;
} }
/* check if the interface is enslaved in another virtual one and
* in that case unlink it first
*/
master = netdev_master_upper_dev_get(hard_iface->net_dev);
ret = batadv_master_del_slave(hard_iface, master);
if (ret)
goto err_dev;
hard_iface->soft_iface = soft_iface; hard_iface->soft_iface = soft_iface;
bat_priv = netdev_priv(hard_iface->soft_iface); bat_priv = netdev_priv(hard_iface->soft_iface);
......
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