aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntonio Quartulli <ordex@autistici.org>2013-02-16 08:42:39 -0500
committerAntonio Quartulli <ordex@autistici.org>2013-03-27 05:29:53 -0400
commitcb4b0d48645fa29bc0e12537d4e3556c4bf79ac7 (patch)
treeebd1e583f63c67f5a5dff26008ab7cfc16822684
parent3dbd550b8b2e204833d8305451bbde990e1cd743 (diff)
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: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Antonio Quartulli <ordex@autistici.org> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
-rw-r--r--net/batman-adv/hard-interface.c39
1 files changed, 33 insertions, 6 deletions
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index f33ced8e31f4..522243aff2f3 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -307,11 +307,35 @@ batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
307 batadv_update_min_mtu(hard_iface->soft_iface); 307 batadv_update_min_mtu(hard_iface->soft_iface);
308} 308}
309 309
310/**
311 * batadv_master_del_slave - remove hard_iface from the current master interface
312 * @slave: the interface enslaved in another master
313 * @master: the master from which slave has to be removed
314 *
315 * Invoke ndo_del_slave on master passing slave as argument. In this way slave
316 * is free'd and master can correctly change its internal state.
317 * Return 0 on success, a negative value representing the error otherwise
318 */
319static int batadv_master_del_slave(struct batadv_hard_iface *slave,
320 struct net_device *master)
321{
322 int ret;
323
324 if (!master)
325 return 0;
326
327 ret = -EBUSY;
328 if (master->netdev_ops->ndo_del_slave)
329 ret = master->netdev_ops->ndo_del_slave(master, slave->net_dev);
330
331 return ret;
332}
333
310int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, 334int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
311 const char *iface_name) 335 const char *iface_name)
312{ 336{
313 struct batadv_priv *bat_priv; 337 struct batadv_priv *bat_priv;
314 struct net_device *soft_iface; 338 struct net_device *soft_iface, *master;
315 __be16 ethertype = __constant_htons(ETH_P_BATMAN); 339 __be16 ethertype = __constant_htons(ETH_P_BATMAN);
316 int ret; 340 int ret;
317 341
@@ -321,11 +345,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
321 if (!atomic_inc_not_zero(&hard_iface->refcount)) 345 if (!atomic_inc_not_zero(&hard_iface->refcount))
322 goto out; 346 goto out;
323 347
324 /* hard-interface is part of a bridge */
325 if (hard_iface->net_dev->priv_flags & IFF_BRIDGE_PORT)
326 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",
327 hard_iface->net_dev->name);
328
329 soft_iface = dev_get_by_name(&init_net, iface_name); 348 soft_iface = dev_get_by_name(&init_net, iface_name);
330 349
331 if (!soft_iface) { 350 if (!soft_iface) {
@@ -347,6 +366,14 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
347 goto err_dev; 366 goto err_dev;
348 } 367 }
349 368
369 /* check if the interface is enslaved in another virtual one and
370 * in that case unlink it first
371 */
372 master = netdev_master_upper_dev_get(hard_iface->net_dev);
373 ret = batadv_master_del_slave(hard_iface, master);
374 if (ret)
375 goto err_dev;
376
350 hard_iface->soft_iface = soft_iface; 377 hard_iface->soft_iface = soft_iface;
351 bat_priv = netdev_priv(hard_iface->soft_iface); 378 bat_priv = netdev_priv(hard_iface->soft_iface);
352 379