diff options
author | Eric Dumazet <edumazet@google.com> | 2016-12-21 21:00:24 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-12-23 17:53:47 -0500 |
commit | b1227d019fa98c43381ad8827baf7efbe2923ed1 (patch) | |
tree | 576fad624349c35feded5a554103bf1c4cf5a68e /drivers/net/ipvlan/ipvlan_main.c | |
parent | 50b17cfb1917b207612327d354e9043dbcbde431 (diff) |
ipvlan: fix various issues in ipvlan_process_multicast()
1) netif_rx() / dev_forward_skb() should not be called from process
context.
2) ipvlan_count_rx() should be called with preemption disabled.
3) We should check if ipvlan->dev is up before feeding packets
to netif_rx()
4) We need to prevent device from disappearing if some packets
are in the multicast backlog.
5) One kfree_skb() should be a consume_skb() eventually
Fixes: ba35f8588f47 ("ipvlan: Defer multicast / broadcast processing to
a work-queue")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Mahesh Bandewar <maheshb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ipvlan/ipvlan_main.c')
-rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 693ec5b66222..8b0f99300cbc 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c | |||
@@ -135,6 +135,7 @@ err: | |||
135 | static void ipvlan_port_destroy(struct net_device *dev) | 135 | static void ipvlan_port_destroy(struct net_device *dev) |
136 | { | 136 | { |
137 | struct ipvl_port *port = ipvlan_port_get_rtnl(dev); | 137 | struct ipvl_port *port = ipvlan_port_get_rtnl(dev); |
138 | struct sk_buff *skb; | ||
138 | 139 | ||
139 | dev->priv_flags &= ~IFF_IPVLAN_MASTER; | 140 | dev->priv_flags &= ~IFF_IPVLAN_MASTER; |
140 | if (port->mode == IPVLAN_MODE_L3S) { | 141 | if (port->mode == IPVLAN_MODE_L3S) { |
@@ -144,7 +145,11 @@ static void ipvlan_port_destroy(struct net_device *dev) | |||
144 | } | 145 | } |
145 | netdev_rx_handler_unregister(dev); | 146 | netdev_rx_handler_unregister(dev); |
146 | cancel_work_sync(&port->wq); | 147 | cancel_work_sync(&port->wq); |
147 | __skb_queue_purge(&port->backlog); | 148 | while ((skb = __skb_dequeue(&port->backlog)) != NULL) { |
149 | if (skb->dev) | ||
150 | dev_put(skb->dev); | ||
151 | kfree_skb(skb); | ||
152 | } | ||
148 | kfree(port); | 153 | kfree(port); |
149 | } | 154 | } |
150 | 155 | ||