diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 0c2c937..e4142ea 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -457,7 +457,6 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) if (len > d->mtu) return -EINVAL; - rfcomm_make_uih(skb, d->addr); skb_queue_tail(&d->tx_queue, skb); if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags)) @@ -1674,6 +1673,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) return skb_queue_len(&d->tx_queue); while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) { + rfcomm_make_uih(skb, d->addr); err = rfcomm_send_frame(d->session, skb->data, skb->len); if (err < 0) { skb_queue_head(&d->tx_queue, skb); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index c919187..f2a2e1c 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -77,6 +77,9 @@ struct rfcomm_dev { struct device *tty_dev; atomic_t wmem_alloc; + + struct sk_buff_head rx_queue; + atomic_t rxq_mem_alloc; }; static LIST_HEAD(rfcomm_dev_list); @@ -88,6 +91,8 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig); static void rfcomm_tty_wakeup(unsigned long arg); +static void rfcomm_tty_copy_buffered(struct rfcomm_dev *dev); + /* ---- Device functions ---- */ static void rfcomm_dev_destruct(struct rfcomm_dev *dev) { @@ -207,6 +212,8 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) struct rfcomm_dev *dev; struct list_head *head = &rfcomm_dev_list, *p; int err = 0; + struct sock *sk; + struct sk_buff *skb; BT_DBG("id %d channel %d", req->dev_id, req->channel); @@ -263,8 +270,20 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) init_waitqueue_head(&dev->wait); tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); + skb_queue_head_init(&dev->rx_queue); + atomic_set(&dev->rxq_mem_alloc, 0); rfcomm_dlc_lock(dlc); + + if ((req->flags & (1 << RFCOMM_REUSE_DLC)) && (sk = dlc->owner)) { + while ((skb = skb_dequeue(&sk->sk_receive_queue))) { + skb_orphan(skb); + atomic_sub(skb->len, &sk->sk_rmem_alloc); + atomic_add(skb->len, &dev->rxq_mem_alloc); + skb_queue_tail(&dev->rx_queue, skb); + } + } + dlc->data_ready = rfcomm_dev_data_ready; dlc->state_change = rfcomm_dev_state_change; dlc->modem_status = rfcomm_dev_modem_status; @@ -539,11 +558,21 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) struct rfcomm_dev *dev = dlc->owner; struct tty_struct *tty; - if (!dev || !(tty = dev->tty)) { + if (!dev) { kfree_skb(skb); return; } + if (!(tty = dev->tty) || !skb_queue_empty(&dev->rx_queue)) { + atomic_add(skb->len, &dev->rxq_mem_alloc); + skb_queue_tail(&dev->rx_queue, skb); + + if (atomic_read(&dev->rxq_mem_alloc) >= RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10) + rfcomm_dlc_throttle(dlc); + + return; + } + BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len); tty_insert_flip_string(tty, skb->data, skb->len); @@ -627,6 +656,33 @@ static void rfcomm_tty_wakeup(unsigned long arg) #endif } +static void rfcomm_tty_copy_buffered(struct rfcomm_dev *dev) +{ + struct tty_struct *tty = dev->tty; + struct sk_buff *skb; + int inserted; + + if (!tty) + return; + + BT_DBG("dev %p tty %p", dev, tty); + + rfcomm_dlc_lock(dev->dlc); + + inserted = 0; + while ((skb = skb_dequeue(&dev->rx_queue))) { + inserted += tty_insert_flip_string(tty, skb->data, skb->len); + kfree_skb(skb); + } + + rfcomm_dlc_unlock(dev->dlc); + + if (inserted) { + tty_flip_buffer_push(tty); + rfcomm_dlc_unthrottle(dev->dlc); + } +} + static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) { DECLARE_WAITQUEUE(wait, current); @@ -691,6 +747,8 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) if (err == 0) device_move(dev->tty_dev, rfcomm_get_device(dev)); + rfcomm_tty_copy_buffered(dev); + return err; }