From: Andrew Lunn andrew@lunn.ch
batman-adv tries to prevent the user from placing a batX soft interface into another batman mesh as a hard interface. It does this by walking up the devices list of parents and ensures they are all none batX interfaces. iflink can point to an interface in a different namespace, so also retrieve the parents name space when finding the parent and use it when doing the comparison.
Signed-off-by: Andrew Lunn andrew@lunn.ch Acked-by: Antonio Quartulli a@untable.cc Signed-off-by: Sven Eckelmann sven@narfation.org --- compat-patches/0001-get_link_net.patch | 26 ++++++++++++++++++ net/batman-adv/hard-interface.c | 49 +++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 compat-patches/0001-get_link_net.patch
diff --git a/compat-patches/0001-get_link_net.patch b/compat-patches/0001-get_link_net.patch new file mode 100644 index 0000000..25ee879 --- /dev/null +++ b/compat-patches/0001-get_link_net.patch @@ -0,0 +1,26 @@ +From: Sven Eckelmann sven@narfation.org +Date: Sat, 12 Mar 2016 00:01:45 +0100 +Subject: [PATCH] get_link_net +--- + net/batman-adv/hard-interface.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c +index bd98195..f568053 100644 +--- a/net/batman-adv/hard-interface.c ++++ b/net/batman-adv/hard-interface.c +@@ -97,10 +97,14 @@ static struct net *batadv_getlink_net(const struct net_device *netdev, + if (!netdev->rtnl_link_ops) + return fallback_net; + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) ++ return fallback_net; ++#else + if (!netdev->rtnl_link_ops->get_link_net) + return fallback_net; + + return netdev->rtnl_link_ops->get_link_net(netdev); ++#endif + } + + /** diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index ca8e0d4..bd98195 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -36,6 +36,8 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/workqueue.h> +#include <net/net_namespace.h> +#include <net/rtnetlink.h>
#include "bridge_loop_avoidance.h" #include "debugfs.h" @@ -83,25 +85,55 @@ out: }
/** + * batadv_getlink_net - return link net namespace (of use fallback) + * @netdev: net_device to check + * @fallback_net: return in case get_link_net is not available for @netdev + * + * Return: result of rtnl_link_ops->get_link_net or @fallback_net + */ +static struct net *batadv_getlink_net(const struct net_device *netdev, + struct net *fallback_net) +{ + if (!netdev->rtnl_link_ops) + return fallback_net; + + if (!netdev->rtnl_link_ops->get_link_net) + return fallback_net; + + return netdev->rtnl_link_ops->get_link_net(netdev); +} + +/** * batadv_mutual_parents - check if two devices are each others parent - * @dev1: 1st net_device - * @dev2: 2nd net_device + * @dev1: 1st net dev + * @net1: 1st devices netns + * @dev2: 2nd net dev + * @net2: 2nd devices netns * * veth devices come in pairs and each is the parent of the other! * * Return: true if the devices are each others parent, otherwise false */ static bool batadv_mutual_parents(const struct net_device *dev1, - const struct net_device *dev2) + struct net *net1, + const struct net_device *dev2, + struct net *net2) { int dev1_parent_iflink = dev_get_iflink(dev1); int dev2_parent_iflink = dev_get_iflink(dev2); + const struct net *dev1_parent_net; + const struct net *dev2_parent_net; + + dev1_parent_net = batadv_getlink_net(dev1, net1); + dev2_parent_net = batadv_getlink_net(dev2, net2);
if (!dev1_parent_iflink || !dev2_parent_iflink) return false;
return (dev1_parent_iflink == dev2->ifindex) && - (dev2_parent_iflink == dev1->ifindex); + (dev2_parent_iflink == dev1->ifindex) && + net_eq(dev1_parent_net, net2) && + net_eq(dev2_parent_net, net1); }
/** @@ -119,8 +151,9 @@ static bool batadv_mutual_parents(const struct net_device *dev1, */ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) { - struct net_device *parent_dev; struct net *net = dev_net(net_dev); + struct net_device *parent_dev; + struct net *parent_net; bool ret;
/* check if this is a batman-adv mesh interface */ @@ -132,13 +165,15 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) dev_get_iflink(net_dev) == net_dev->ifindex) return false;
+ parent_net = batadv_getlink_net(net_dev, net); + /* recurse over the parent device */ - parent_dev = __dev_get_by_index(net, dev_get_iflink(net_dev)); + parent_dev = __dev_get_by_index(parent_net, dev_get_iflink(net_dev)); /* if we got a NULL parent_dev there is something broken.. */ if (WARN(!parent_dev, "Cannot find parent device")) return false;
- if (batadv_mutual_parents(net_dev, parent_dev)) + if (batadv_mutual_parents(net_dev, net, parent_dev, parent_net)) return false;
ret = batadv_is_on_batman_iface(parent_dev);