aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-05-17 23:53:34 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2012-06-04 23:34:02 -0400
commit18a48e76640c590a14b0286c9da5fde6ac146cc2 (patch)
tree8ba776cf162896dab0163389d1efad6ad3b235b2 /net/bluetooth/l2cap_core.c
parent3733937d96f3fe4dfc3b8da43385d739e905ff41 (diff)
Bluetooth: Refactor l2cap_ertm_send
The new implementation is aware of the new transmit state machine, and uses struct l2cap_ctrl to compose ERTM headers. It also has improved error handling for allocation failures, and does not send the packet until after all skb and channel data structures are updated. Signed-off-by: Mat Martineau <mathewm@codeaurora.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c79
1 files changed, 39 insertions, 40 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 25edccff4c94..429a67ea47d0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1741,9 +1741,10 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
1741static int l2cap_ertm_send(struct l2cap_chan *chan) 1741static int l2cap_ertm_send(struct l2cap_chan *chan)
1742{ 1742{
1743 struct sk_buff *skb, *tx_skb; 1743 struct sk_buff *skb, *tx_skb;
1744 u16 fcs; 1744 struct l2cap_ctrl *control;
1745 u32 control; 1745 int sent = 0;
1746 int nsent = 0; 1746
1747 BT_DBG("chan %p", chan);
1747 1748
1748 if (chan->state != BT_CONNECTED) 1749 if (chan->state != BT_CONNECTED)
1749 return -ENOTCONN; 1750 return -ENOTCONN;
@@ -1751,61 +1752,57 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
1751 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) 1752 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
1752 return 0; 1753 return 0;
1753 1754
1754 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { 1755 while (chan->tx_send_head &&
1755 1756 chan->unacked_frames < chan->remote_tx_win &&
1756 if (bt_cb(skb)->control.retries == chan->remote_max_tx && 1757 chan->tx_state == L2CAP_TX_STATE_XMIT) {
1757 chan->remote_max_tx) {
1758 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
1759 break;
1760 }
1761 1758
1762 tx_skb = skb_clone(skb, GFP_ATOMIC); 1759 skb = chan->tx_send_head;
1763 1760
1764 bt_cb(skb)->control.retries++; 1761 bt_cb(skb)->control.retries = 1;
1765 1762 control = &bt_cb(skb)->control;
1766 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
1767 control &= __get_sar_mask(chan);
1768 1763
1769 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) 1764 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
1770 control |= __set_ctrl_final(chan); 1765 control->final = 1;
1771 1766
1772 control |= __set_reqseq(chan, chan->buffer_seq); 1767 control->reqseq = chan->buffer_seq;
1773 control |= __set_txseq(chan, chan->next_tx_seq); 1768 chan->last_acked_seq = chan->buffer_seq;
1774 control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); 1769 control->txseq = chan->next_tx_seq;
1775 1770
1776 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); 1771 __pack_control(chan, control, skb);
1777 1772
1778 if (chan->fcs == L2CAP_FCS_CRC16) { 1773 if (chan->fcs == L2CAP_FCS_CRC16) {
1779 fcs = crc16(0, (u8 *)skb->data, 1774 u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
1780 tx_skb->len - L2CAP_FCS_SIZE); 1775 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
1781 put_unaligned_le16(fcs, skb->data +
1782 tx_skb->len - L2CAP_FCS_SIZE);
1783 } 1776 }
1784 1777
1785 l2cap_do_send(chan, tx_skb); 1778 /* Clone after data has been modified. Data is assumed to be
1779 read-only (for locking purposes) on cloned sk_buffs.
1780 */
1781 tx_skb = skb_clone(skb, GFP_KERNEL);
1786 1782
1787 __set_retrans_timer(chan); 1783 if (!tx_skb)
1784 break;
1788 1785
1789 bt_cb(skb)->control.txseq = chan->next_tx_seq; 1786 __set_retrans_timer(chan);
1790 1787
1791 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); 1788 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
1792 1789 chan->unacked_frames++;
1793 if (bt_cb(skb)->control.retries == 1) {
1794 chan->unacked_frames++;
1795
1796 if (!nsent++)
1797 __clear_ack_timer(chan);
1798 }
1799
1800 chan->frames_sent++; 1790 chan->frames_sent++;
1791 sent++;
1801 1792
1802 if (skb_queue_is_last(&chan->tx_q, skb)) 1793 if (skb_queue_is_last(&chan->tx_q, skb))
1803 chan->tx_send_head = NULL; 1794 chan->tx_send_head = NULL;
1804 else 1795 else
1805 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); 1796 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
1797
1798 l2cap_do_send(chan, tx_skb);
1799 BT_DBG("Sent txseq %d", (int)control->txseq);
1806 } 1800 }
1807 1801
1808 return nsent; 1802 BT_DBG("Sent %d, %d unacked, %d in ERTM queue", sent,
1803 (int) chan->unacked_frames, skb_queue_len(&chan->tx_q));
1804
1805 return sent;
1809} 1806}
1810 1807
1811static int l2cap_retransmit_frames(struct l2cap_chan *chan) 1808static int l2cap_retransmit_frames(struct l2cap_chan *chan)
@@ -2009,7 +2006,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
2009 lh->cid = cpu_to_le16(chan->dcid); 2006 lh->cid = cpu_to_le16(chan->dcid);
2010 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); 2007 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
2011 2008
2012 __put_control(chan, 0, skb_put(skb, __ctrl_size(chan))); 2009 /* Control header is populated later */
2010 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2011 put_unaligned_le32(0, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
2012 else
2013 put_unaligned_le16(0, skb_put(skb, L2CAP_ENH_CTRL_SIZE));
2013 2014
2014 if (sdulen) 2015 if (sdulen)
2015 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); 2016 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
@@ -2020,9 +2021,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
2020 return ERR_PTR(err); 2021 return ERR_PTR(err);
2021 } 2022 }
2022 2023
2023 if (chan->fcs == L2CAP_FCS_CRC16) 2024 bt_cb(skb)->control.fcs = chan->fcs;
2024 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
2025
2026 bt_cb(skb)->control.retries = 0; 2025 bt_cb(skb)->control.retries = 0;
2027 return skb; 2026 return skb;
2028} 2027}