aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2008-07-14 14:13:52 -0400
committerMarcel Holtmann <marcel@holtmann.org>2008-07-14 14:13:52 -0400
commita0c22f226502be6eab37a1d9bf6fb0fadf551376 (patch)
treefe0237624038290fc0d84ce5ee97a65c49b56818 /net
parent8b6b3da765af9600b5edd8e3e84a20523e975884 (diff)
[Bluetooth] Move pending packets from RFCOMM socket to TTY
When an incoming RFCOMM socket connection gets converted into a TTY, it can happen that packets are lost. This mainly happens with the Handsfree profile where the remote side starts sending data right away. The problem is that these packets are in the socket receive queue. So when creating the TTY make sure to copy all pending packets from the socket receive queue to a private queue inside the TTY. To make this actually work, the flow control on the newly created TTY will be disabled and only enabled again when the TTY is opened by an application. And right before that, the pending packets will be put into the TTY flip buffer. Signed-off-by: Denis Kenzior <denis.kenzior@trolltech.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/rfcomm/core.c2
-rw-r--r--net/bluetooth/rfcomm/tty.c55
2 files changed, 55 insertions, 2 deletions
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index fcd2cafe70c8..b6b3d9b4066f 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -53,7 +53,7 @@
53#define BT_DBG(D...) 53#define BT_DBG(D...)
54#endif 54#endif
55 55
56#define VERSION "1.9" 56#define VERSION "1.10"
57 57
58static int disable_cfc = 0; 58static int disable_cfc = 0;
59static int channel_mtu = -1; 59static int channel_mtu = -1;
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 8fcca08cef8e..ec22ebe0c2c8 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -77,6 +77,8 @@ struct rfcomm_dev {
77 struct device *tty_dev; 77 struct device *tty_dev;
78 78
79 atomic_t wmem_alloc; 79 atomic_t wmem_alloc;
80
81 struct sk_buff_head pending;
80}; 82};
81 83
82static LIST_HEAD(rfcomm_dev_list); 84static LIST_HEAD(rfcomm_dev_list);
@@ -264,7 +266,25 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
264 init_waitqueue_head(&dev->wait); 266 init_waitqueue_head(&dev->wait);
265 tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); 267 tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
266 268
269 skb_queue_head_init(&dev->pending);
270
267 rfcomm_dlc_lock(dlc); 271 rfcomm_dlc_lock(dlc);
272
273 if (req->flags & (1 << RFCOMM_REUSE_DLC)) {
274 struct sock *sk = dlc->owner;
275 struct sk_buff *skb;
276
277 BUG_ON(!sk);
278
279 rfcomm_dlc_throttle(dlc);
280
281 while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
282 skb_orphan(skb);
283 skb_queue_tail(&dev->pending, skb);
284 atomic_sub(skb->len, &sk->sk_rmem_alloc);
285 }
286 }
287
268 dlc->data_ready = rfcomm_dev_data_ready; 288 dlc->data_ready = rfcomm_dev_data_ready;
269 dlc->state_change = rfcomm_dev_state_change; 289 dlc->state_change = rfcomm_dev_state_change;
270 dlc->modem_status = rfcomm_dev_modem_status; 290 dlc->modem_status = rfcomm_dev_modem_status;
@@ -542,11 +562,16 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
542 struct rfcomm_dev *dev = dlc->owner; 562 struct rfcomm_dev *dev = dlc->owner;
543 struct tty_struct *tty; 563 struct tty_struct *tty;
544 564
545 if (!dev || !(tty = dev->tty)) { 565 if (!dev) {
546 kfree_skb(skb); 566 kfree_skb(skb);
547 return; 567 return;
548 } 568 }
549 569
570 if (!(tty = dev->tty) || !skb_queue_empty(&dev->pending)) {
571 skb_queue_tail(&dev->pending, skb);
572 return;
573 }
574
550 BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len); 575 BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
551 576
552 tty_insert_flip_string(tty, skb->data, skb->len); 577 tty_insert_flip_string(tty, skb->data, skb->len);
@@ -630,6 +655,30 @@ static void rfcomm_tty_wakeup(unsigned long arg)
630#endif 655#endif
631} 656}
632 657
658static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
659{
660 struct tty_struct *tty = dev->tty;
661 struct sk_buff *skb;
662 int inserted = 0;
663
664 if (!tty)
665 return;
666
667 BT_DBG("dev %p tty %p", dev, tty);
668
669 rfcomm_dlc_lock(dev->dlc);
670
671 while ((skb = skb_dequeue(&dev->pending))) {
672 inserted += tty_insert_flip_string(tty, skb->data, skb->len);
673 kfree_skb(skb);
674 }
675
676 rfcomm_dlc_unlock(dev->dlc);
677
678 if (inserted > 0)
679 tty_flip_buffer_push(tty);
680}
681
633static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) 682static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
634{ 683{
635 DECLARE_WAITQUEUE(wait, current); 684 DECLARE_WAITQUEUE(wait, current);
@@ -694,6 +743,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
694 if (err == 0) 743 if (err == 0)
695 device_move(dev->tty_dev, rfcomm_get_device(dev)); 744 device_move(dev->tty_dev, rfcomm_get_device(dev));
696 745
746 rfcomm_tty_copy_pending(dev);
747
748 rfcomm_dlc_unthrottle(dev->dlc);
749
697 return err; 750 return err;
698} 751}
699 752