aboutsummaryrefslogtreecommitdiffstats
path: root/net/atm
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2012-11-27 18:28:36 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-12-01 19:05:14 -0500
commitb89588531f1db93a218c108eee713ff6002a67bf (patch)
tree074d0b433a381f95325082c8d9f0ba10a835b517 /net/atm
parentc971f08cba56ed17fe22040ca5ff97fe5c3f0bd7 (diff)
br2684: don't send frames on not-ready vcc
Avoid submitting packets to a vcc which is being closed. Things go badly wrong when the ->pop method gets later called after everything's been torn down. Use the ATM socket lock for synchronisation with vcc_destroy_socket(), which clears the ATM_VF_READY bit under the same lock. Otherwise, we could end up submitting a packet to the device driver even after its ->ops->close method has been called. And it could call the vcc's ->pop method after the protocol has been shut down. Which leads to a panic. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Acked-by: Krzysztof Mazur <krzysiek@podlesie.net>
Diffstat (limited to 'net/atm')
-rw-r--r--net/atm/br2684.c43
1 files changed, 40 insertions, 3 deletions
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 8eb6fbe8d8dd..4de3ae7bc3e2 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -68,6 +68,7 @@ struct br2684_vcc {
68 /* keep old push, pop functions for chaining */ 68 /* keep old push, pop functions for chaining */
69 void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb); 69 void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb);
70 void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); 70 void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
71 void (*old_release_cb)(struct atm_vcc *vcc);
71 enum br2684_encaps encaps; 72 enum br2684_encaps encaps;
72 struct list_head brvccs; 73 struct list_head brvccs;
73#ifdef CONFIG_ATM_BR2684_IPFILTER 74#ifdef CONFIG_ATM_BR2684_IPFILTER
@@ -269,6 +270,17 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
269 return !atmvcc->send(atmvcc, skb); 270 return !atmvcc->send(atmvcc, skb);
270} 271}
271 272
273static void br2684_release_cb(struct atm_vcc *atmvcc)
274{
275 struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
276
277 if (atomic_read(&brvcc->qspace) > 0)
278 netif_wake_queue(brvcc->device);
279
280 if (brvcc->old_release_cb)
281 brvcc->old_release_cb(atmvcc);
282}
283
272static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb, 284static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb,
273 const struct br2684_dev *brdev) 285 const struct br2684_dev *brdev)
274{ 286{
@@ -280,6 +292,8 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,
280{ 292{
281 struct br2684_dev *brdev = BRPRIV(dev); 293 struct br2684_dev *brdev = BRPRIV(dev);
282 struct br2684_vcc *brvcc; 294 struct br2684_vcc *brvcc;
295 struct atm_vcc *atmvcc;
296 netdev_tx_t ret = NETDEV_TX_OK;
283 297
284 pr_debug("skb_dst(skb)=%p\n", skb_dst(skb)); 298 pr_debug("skb_dst(skb)=%p\n", skb_dst(skb));
285 read_lock(&devs_lock); 299 read_lock(&devs_lock);
@@ -290,9 +304,26 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,
290 dev->stats.tx_carrier_errors++; 304 dev->stats.tx_carrier_errors++;
291 /* netif_stop_queue(dev); */ 305 /* netif_stop_queue(dev); */
292 dev_kfree_skb(skb); 306 dev_kfree_skb(skb);
293 read_unlock(&devs_lock); 307 goto out_devs;
294 return NETDEV_TX_OK;
295 } 308 }
309 atmvcc = brvcc->atmvcc;
310
311 bh_lock_sock(sk_atm(atmvcc));
312
313 if (test_bit(ATM_VF_RELEASED, &atmvcc->flags) ||
314 test_bit(ATM_VF_CLOSE, &atmvcc->flags) ||
315 !test_bit(ATM_VF_READY, &atmvcc->flags)) {
316 dev->stats.tx_dropped++;
317 dev_kfree_skb(skb);
318 goto out;
319 }
320
321 if (sock_owned_by_user(sk_atm(atmvcc))) {
322 netif_stop_queue(brvcc->device);
323 ret = NETDEV_TX_BUSY;
324 goto out;
325 }
326
296 if (!br2684_xmit_vcc(skb, dev, brvcc)) { 327 if (!br2684_xmit_vcc(skb, dev, brvcc)) {
297 /* 328 /*
298 * We should probably use netif_*_queue() here, but that 329 * We should probably use netif_*_queue() here, but that
@@ -304,8 +335,11 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,
304 dev->stats.tx_errors++; 335 dev->stats.tx_errors++;
305 dev->stats.tx_fifo_errors++; 336 dev->stats.tx_fifo_errors++;
306 } 337 }
338 out:
339 bh_unlock_sock(sk_atm(atmvcc));
340 out_devs:
307 read_unlock(&devs_lock); 341 read_unlock(&devs_lock);
308 return NETDEV_TX_OK; 342 return ret;
309} 343}
310 344
311/* 345/*
@@ -378,6 +412,7 @@ static void br2684_close_vcc(struct br2684_vcc *brvcc)
378 list_del(&brvcc->brvccs); 412 list_del(&brvcc->brvccs);
379 write_unlock_irq(&devs_lock); 413 write_unlock_irq(&devs_lock);
380 brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */ 414 brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */
415 brvcc->atmvcc->release_cb = brvcc->old_release_cb;
381 brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */ 416 brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */
382 kfree(brvcc); 417 kfree(brvcc);
383 module_put(THIS_MODULE); 418 module_put(THIS_MODULE);
@@ -554,9 +589,11 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
554 brvcc->encaps = (enum br2684_encaps)be.encaps; 589 brvcc->encaps = (enum br2684_encaps)be.encaps;
555 brvcc->old_push = atmvcc->push; 590 brvcc->old_push = atmvcc->push;
556 brvcc->old_pop = atmvcc->pop; 591 brvcc->old_pop = atmvcc->pop;
592 brvcc->old_release_cb = atmvcc->release_cb;
557 barrier(); 593 barrier();
558 atmvcc->push = br2684_push; 594 atmvcc->push = br2684_push;
559 atmvcc->pop = br2684_pop; 595 atmvcc->pop = br2684_pop;
596 atmvcc->release_cb = br2684_release_cb;
560 597
561 /* initialize netdev carrier state */ 598 /* initialize netdev carrier state */
562 if (atmvcc->dev->signal == ATM_PHY_SIG_LOST) 599 if (atmvcc->dev->signal == ATM_PHY_SIG_LOST)