Commit c38e01b8 authored by John Fastabend's avatar John Fastabend Committed by David S. Miller

net: fix bridge notify hook to manage flags correctly

The bridge notify hook rtnl_bridge_notify() was not handling the
case where the master flags was set or with both flags set. First
flags are not being passed correctly and second the logic to parse
them is broken.

This patch passes the original flags value and fixes the
logic.
Reported-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarJohn Fastabend <john.r.fastabend@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 26cdfb49
...@@ -2364,13 +2364,19 @@ static int rtnl_bridge_notify(struct net_device *dev, u16 flags) ...@@ -2364,13 +2364,19 @@ static int rtnl_bridge_notify(struct net_device *dev, u16 flags)
goto errout; goto errout;
} }
if (!flags && master && master->netdev_ops->ndo_bridge_getlink) if ((!flags || (flags & BRIDGE_FLAGS_MASTER)) &&
master && master->netdev_ops->ndo_bridge_getlink) {
err = master->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev); err = master->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev);
else if (dev->netdev_ops->ndo_bridge_getlink) if (err < 0)
err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev); goto errout;
}
if (err < 0) if ((flags & BRIDGE_FLAGS_SELF) &&
goto errout; dev->netdev_ops->ndo_bridge_getlink) {
err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev);
if (err < 0)
goto errout;
}
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
return 0; return 0;
...@@ -2389,7 +2395,8 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2389,7 +2395,8 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
struct net_device *dev; struct net_device *dev;
struct nlattr *br_spec, *attr = NULL; struct nlattr *br_spec, *attr = NULL;
int rem, err = -EOPNOTSUPP; int rem, err = -EOPNOTSUPP;
u16 flags = 0; u16 oflags, flags = 0;
bool have_flags = false;
if (nlmsg_len(nlh) < sizeof(*ifm)) if (nlmsg_len(nlh) < sizeof(*ifm))
return -EINVAL; return -EINVAL;
...@@ -2408,12 +2415,15 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2408,12 +2415,15 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
if (br_spec) { if (br_spec) {
nla_for_each_nested(attr, br_spec, rem) { nla_for_each_nested(attr, br_spec, rem) {
if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
have_flags = true;
flags = nla_get_u16(attr); flags = nla_get_u16(attr);
break; break;
} }
} }
} }
oflags = flags;
if (!flags || (flags & BRIDGE_FLAGS_MASTER)) { if (!flags || (flags & BRIDGE_FLAGS_MASTER)) {
if (!dev->master || if (!dev->master ||
!dev->master->netdev_ops->ndo_bridge_setlink) { !dev->master->netdev_ops->ndo_bridge_setlink) {
...@@ -2438,11 +2448,11 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2438,11 +2448,11 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
flags &= ~BRIDGE_FLAGS_SELF; flags &= ~BRIDGE_FLAGS_SELF;
} }
if (attr && nla_type(attr) == IFLA_BRIDGE_FLAGS) if (have_flags)
memcpy(nla_data(attr), &flags, sizeof(flags)); memcpy(nla_data(attr), &flags, sizeof(flags));
/* Generate event to notify upper layer of bridge change */ /* Generate event to notify upper layer of bridge change */
if (!err) if (!err)
err = rtnl_bridge_notify(dev, flags); err = rtnl_bridge_notify(dev, oflags);
out: out:
return err; return err;
} }
......
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