diff options
author | Jiri Benc <jbenc@redhat.com> | 2012-07-27 02:58:22 +0000 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2012-08-19 18:15:25 +0100 |
commit | 99517853a21edf2327cbe34441de9142720563c8 (patch) | |
tree | ba0efbcaa5a486fd6e26c25883cdc8f6538d9883 | |
parent | f4d0e6b0307f37720d4be8609955f78074880f1b (diff) |
net: fix rtnetlink IFF_PROMISC and IFF_ALLMULTI handling
[ Upstream commit b1beb681cba5358f62e6187340660ade226a5fcc ]
When device flags are set using rtnetlink, IFF_PROMISC and IFF_ALLMULTI
flags are handled specially. Function dev_change_flags sets IFF_PROMISC and
IFF_ALLMULTI bits in dev->gflags according to the passed value but
do_setlink passes a result of rtnl_dev_combine_flags which takes those bits
from dev->flags.
This can be easily trigerred by doing:
tcpdump -i eth0 &
ip l s up eth0
ip sets IFF_UP flag in ifi_flags and ifi_change, which is combined with
IFF_PROMISC by rtnl_dev_combine_flags, causing __dev_change_flags to set
IFF_PROMISC in gflags.
Reported-by: Max Matveev <makc@redhat.com>
Signed-off-by: Jiri Benc <jbenc@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r-- | net/core/rtnetlink.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 05842ab21bc..0cf604b92f3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -670,6 +670,12 @@ static void set_operstate(struct net_device *dev, unsigned char transition) } } +static unsigned int rtnl_dev_get_flags(const struct net_device *dev) +{ + return (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI)) | + (dev->gflags & (IFF_PROMISC | IFF_ALLMULTI)); +} + static unsigned int rtnl_dev_combine_flags(const struct net_device *dev, const struct ifinfomsg *ifm) { @@ -678,7 +684,7 @@ static unsigned int rtnl_dev_combine_flags(const struct net_device *dev, /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ if (ifm->ifi_change) flags = (flags & ifm->ifi_change) | - (dev->flags & ~ifm->ifi_change); + (rtnl_dev_get_flags(dev) & ~ifm->ifi_change); return flags; } |