diff options
-rw-r--r-- | net/atm/br2684.c | 43 |
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 | ||
273 | static 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 | |||
272 | static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb, | 284 | static 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) |