aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ifb.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2007-03-29 14:46:52 -0400
committerDavid S. Miller <davem@davemloft.net>2007-03-29 14:46:52 -0400
commitc01003c20563d1e75ec9828d21743919d2b43977 (patch)
tree21cae8933e8a4908d8e8c24244a627bf0c997e77 /drivers/net/ifb.c
parentdb8b22550d4b83f0910d27a34d05aa16f7f7159f (diff)
[IFB]: Fix crash on input device removal
The input_device pointer is not refcounted, which means the device may disappear while packets are queued, causing a crash when ifb passes packets with a stale skb->dev pointer to netif_rx(). Fix by storing the interface index instead and do a lookup where neccessary. Signed-off-by: Patrick McHardy <kaber@trash.net> Acked-by: Jamal Hadi Salim <hadi@cyberus.ca> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ifb.c')
-rw-r--r--drivers/net/ifb.c35
1 files changed, 13 insertions, 22 deletions
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index ca2b21f9d444..07b4c0d7a75c 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -96,17 +96,24 @@ static void ri_tasklet(unsigned long dev)
96 skb->tc_verd = SET_TC_NCLS(skb->tc_verd); 96 skb->tc_verd = SET_TC_NCLS(skb->tc_verd);
97 stats->tx_packets++; 97 stats->tx_packets++;
98 stats->tx_bytes +=skb->len; 98 stats->tx_bytes +=skb->len;
99
100 skb->dev = __dev_get_by_index(skb->iif);
101 if (!skb->dev) {
102 dev_kfree_skb(skb);
103 stats->tx_dropped++;
104 break;
105 }
106 skb->iif = _dev->ifindex;
107
99 if (from & AT_EGRESS) { 108 if (from & AT_EGRESS) {
100 dp->st_rx_frm_egr++; 109 dp->st_rx_frm_egr++;
101 dev_queue_xmit(skb); 110 dev_queue_xmit(skb);
102 } else if (from & AT_INGRESS) { 111 } else if (from & AT_INGRESS) {
103
104 dp->st_rx_frm_ing++; 112 dp->st_rx_frm_ing++;
113 skb_pull(skb, skb->dev->hard_header_len);
105 netif_rx(skb); 114 netif_rx(skb);
106 } else { 115 } else
107 dev_kfree_skb(skb); 116 BUG();
108 stats->tx_dropped++;
109 }
110 } 117 }
111 118
112 if (netif_tx_trylock(_dev)) { 119 if (netif_tx_trylock(_dev)) {
@@ -157,26 +164,10 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
157 stats->rx_packets++; 164 stats->rx_packets++;
158 stats->rx_bytes+=skb->len; 165 stats->rx_bytes+=skb->len;
159 166
160 if (!from || !skb->input_dev) { 167 if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->iif) {
161dropped:
162 dev_kfree_skb(skb); 168 dev_kfree_skb(skb);
163 stats->rx_dropped++; 169 stats->rx_dropped++;
164 return ret; 170 return ret;
165 } else {
166 /*
167 * note we could be going
168 * ingress -> egress or
169 * egress -> ingress
170 */
171 skb->dev = skb->input_dev;
172 skb->input_dev = dev;
173 if (from & AT_INGRESS) {
174 skb_pull(skb, skb->dev->hard_header_len);
175 } else {
176 if (!(from & AT_EGRESS)) {
177 goto dropped;
178 }
179 }
180 } 171 }
181 172
182 if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) { 173 if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) {