diff options
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r-- | drivers/net/macvlan.c | 44 |
1 files changed, 34 insertions, 10 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 18373b6ae37d..9bf46bd19b87 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -118,8 +118,6 @@ static int macvlan_broadcast_one(struct sk_buff *skb, const struct ethhdr *eth, bool local) { struct net_device *dev = vlan->dev; - if (!skb) - return NET_RX_DROP; if (local) return vlan->forward(dev, skb); @@ -171,9 +169,13 @@ static void macvlan_broadcast(struct sk_buff *skb, hash = mc_hash(vlan, eth->h_dest); if (!test_bit(hash, vlan->mc_filter)) continue; + + err = NET_RX_DROP; nskb = skb_clone(skb, GFP_ATOMIC); - err = macvlan_broadcast_one(nskb, vlan, eth, - mode == MACVLAN_MODE_BRIDGE); + if (likely(nskb)) + err = macvlan_broadcast_one( + nskb, vlan, eth, + mode == MACVLAN_MODE_BRIDGE); macvlan_count_rx(vlan, skb->len + ETH_HLEN, err == NET_RX_SUCCESS, 1); } @@ -337,8 +339,11 @@ static int macvlan_open(struct net_device *dev) int err; if (vlan->port->passthru) { - if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) - dev_set_promiscuity(lowerdev, 1); + if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) { + err = dev_set_promiscuity(lowerdev, 1); + if (err < 0) + goto out; + } goto hash_add; } @@ -597,6 +602,9 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], if (!vlan->port->passthru) return -EOPNOTSUPP; + if (flags & NLM_F_REPLACE) + return -EOPNOTSUPP; + if (is_unicast_ether_addr(addr)) err = dev_uc_add_excl(dev, addr); else if (is_multicast_ether_addr(addr)) @@ -680,7 +688,7 @@ void macvlan_common_setup(struct net_device *dev) dev->priv_flags |= IFF_UNICAST_FLT; dev->netdev_ops = &macvlan_netdev_ops; dev->destructor = free_netdev; - dev->header_ops = &macvlan_hard_header_ops, + dev->header_ops = &macvlan_hard_header_ops; dev->ethtool_ops = &macvlan_ethtool_ops; } EXPORT_SYMBOL_GPL(macvlan_common_setup); @@ -736,6 +744,10 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) return -EADDRNOTAVAIL; } + if (data && data[IFLA_MACVLAN_FLAGS] && + nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~MACVLAN_FLAG_NOPROMISC) + return -EINVAL; + if (data && data[IFLA_MACVLAN_MODE]) { switch (nla_get_u32(data[IFLA_MACVLAN_MODE])) { case MACVLAN_MODE_PRIVATE: @@ -813,7 +825,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, if (port->count) return -EINVAL; port->passthru = true; - memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN); + eth_hw_addr_inherit(dev, lowerdev); } err = netdev_upper_dev_link(lowerdev, dev); @@ -863,6 +875,18 @@ static int macvlan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct macvlan_dev *vlan = netdev_priv(dev); + enum macvlan_mode mode; + bool set_mode = false; + + /* Validate mode, but don't set yet: setting flags may fail. */ + if (data && data[IFLA_MACVLAN_MODE]) { + set_mode = true; + mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + /* Passthrough mode can't be set or cleared dynamically */ + if ((mode == MACVLAN_MODE_PASSTHRU) != + (vlan->mode == MACVLAN_MODE_PASSTHRU)) + return -EINVAL; + } if (data && data[IFLA_MACVLAN_FLAGS]) { __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); @@ -879,8 +903,8 @@ static int macvlan_changelink(struct net_device *dev, } vlan->flags = flags; } - if (data && data[IFLA_MACVLAN_MODE]) - vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + if (set_mode) + vlan->mode = mode; return 0; } |