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 nameplace, so also retrieve the parents name space when finding the parent.
Additionally, veth devices come in pairs and they are each others parents. Don't infinitely recurse in this situation.
Signed-off-by: Andrew Lunn andrew@lunn.ch --- net/batman-adv/hard-interface.c | 44 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index a5ce58a..8d51a4a 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -75,6 +75,39 @@ out: }
/** + * batadv_mutual_parents - check if two devices are each others parent + * @net_dev - 1st parent + * @parent_dev - 2nd parent + * + * 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 *dev1_net, + const struct net_device *dev2, + const struct net *dev2_net) +{ + int dev1_parent_iflink = dev_get_iflink(dev1); + int dev2_parent_iflink = dev_get_iflink(dev2); + const struct net *dev1_parent_net = dev1_net; + const struct net *dev2_parent_net = dev2_net; + + if (dev1->rtnl_link_ops && dev1->rtnl_link_ops->get_link_net) + dev1_parent_net = dev1->rtnl_link_ops->get_link_net(dev1); + if (dev2->rtnl_link_ops && dev2->rtnl_link_ops->get_link_net) + dev2_parent_net = dev2->rtnl_link_ops->get_link_net(dev2); + + if (!dev1_parent_iflink || !dev2_parent_iflink) + return false; + + return (dev1_parent_iflink == dev2->ifindex) && + (dev2_parent_iflink == dev1->ifindex) && + net_eq(dev1_parent_net, dev2_net) && + net_eq(dev2_parent_net, dev1_net); +} + +/** * batadv_is_on_batman_iface - check if a device is a batman iface descendant * @net_dev: the device to check * @@ -89,8 +122,9 @@ out: */ 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 = net; bool ret;
/* check if this is a batman-adv mesh interface */ @@ -102,12 +136,18 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) dev_get_iflink(net_dev) == net_dev->ifindex) return false;
+ if (net_dev->rtnl_link_ops && net_dev->rtnl_link_ops->get_link_net) + parent_net = net_dev->rtnl_link_ops->get_link_net(net_dev); + /* 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, net, parent_dev, parent_net)) + return false; + ret = batadv_is_on_batman_iface(parent_dev);
return ret;