diff options
-rw-r--r-- | net/batman-adv/hard-interface.c | 39 |
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 | */ | ||
319 | static 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 | |||
310 | int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, | 334 | int 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 | ||