aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-05-17 23:53:37 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2012-06-04 23:34:03 -0400
commit4b51dae96731c9d82f5634e75ac7ffd3b9c1b060 (patch)
treedc41898f921861dcbd734cf101debd68c4f6c6e8
parentcec8ab6e20a7fbdc056894ff7b3fbdbc2a82a563 (diff)
Bluetooth: Add streaming mode receive and incoming packet classifier
Streaming mode reception is fairly simple, with in-sequence frames being reassembled as they arrive. Out-of-sequence frames are dropped, and also clear any partially-assembled SDUs that may exist. The packet classifier determines if the txseq value of the incoming packet is expected, invalid (resulting in a disconnection), invalid (ignorable), duplicate, or having to do with an SREJ request that was previously sent. The rules for each classification are defined in the ERTM specification, and consolidating these rules in one place helps clarify the receive state machine. Signed-off-by: Mat Martineau <mathewm@codeaurora.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
-rw-r--r--net/bluetooth/l2cap_core.c136
1 files changed, 130 insertions, 6 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a84d33769192..0a195ab4a385 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2420,6 +2420,13 @@ static int l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
2420 return err; 2420 return err;
2421} 2421}
2422 2422
2423static void l2cap_pass_to_tx(struct l2cap_chan *chan,
2424 struct l2cap_ctrl *control)
2425{
2426 BT_DBG("chan %p, control %p", chan, control);
2427 l2cap_tx(chan, control, 0, L2CAP_EV_RECV_REQSEQ_AND_FBIT);
2428}
2429
2423/* Copy frame to all raw sockets on that connection */ 2430/* Copy frame to all raw sockets on that connection */
2424static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) 2431static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
2425{ 2432{
@@ -4324,11 +4331,12 @@ static void append_skb_frag(struct sk_buff *skb,
4324 skb->truesize += new_frag->truesize; 4331 skb->truesize += new_frag->truesize;
4325} 4332}
4326 4333
4327static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control) 4334static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb,
4335 struct l2cap_ctrl *control)
4328{ 4336{
4329 int err = -EINVAL; 4337 int err = -EINVAL;
4330 4338
4331 switch (__get_ctrl_sar(chan, control)) { 4339 switch (control->sar) {
4332 case L2CAP_SAR_UNSEGMENTED: 4340 case L2CAP_SAR_UNSEGMENTED:
4333 if (chan->sdu) 4341 if (chan->sdu)
4334 break; 4342 break;
@@ -4463,7 +4471,6 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
4463 4471
4464 skb = skb_dequeue(&chan->srej_q); 4472 skb = skb_dequeue(&chan->srej_q);
4465 control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar); 4473 control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
4466 err = l2cap_reassemble_sdu(chan, skb, control);
4467 4474
4468 if (err < 0) { 4475 if (err < 0) {
4469 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); 4476 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@@ -4637,7 +4644,6 @@ expected:
4637 return 0; 4644 return 0;
4638 } 4645 }
4639 4646
4640 err = l2cap_reassemble_sdu(chan, skb, rx_control);
4641 chan->buffer_seq = __next_seq(chan, chan->buffer_seq); 4647 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4642 4648
4643 if (err < 0) { 4649 if (err < 0) {
@@ -4822,6 +4828,93 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_cont
4822 return 0; 4828 return 0;
4823} 4829}
4824 4830
4831static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)
4832{
4833 BT_DBG("chan %p, txseq %d", chan, txseq);
4834
4835 BT_DBG("last_acked_seq %d, expected_tx_seq %d", chan->last_acked_seq,
4836 chan->expected_tx_seq);
4837
4838 if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
4839 if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
4840 chan->tx_win) {
4841 /* See notes below regarding "double poll" and
4842 * invalid packets.
4843 */
4844 if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
4845 BT_DBG("Invalid/Ignore - after SREJ");
4846 return L2CAP_TXSEQ_INVALID_IGNORE;
4847 } else {
4848 BT_DBG("Invalid - in window after SREJ sent");
4849 return L2CAP_TXSEQ_INVALID;
4850 }
4851 }
4852
4853 if (chan->srej_list.head == txseq) {
4854 BT_DBG("Expected SREJ");
4855 return L2CAP_TXSEQ_EXPECTED_SREJ;
4856 }
4857
4858 if (l2cap_ertm_seq_in_queue(&chan->srej_q, txseq)) {
4859 BT_DBG("Duplicate SREJ - txseq already stored");
4860 return L2CAP_TXSEQ_DUPLICATE_SREJ;
4861 }
4862
4863 if (l2cap_seq_list_contains(&chan->srej_list, txseq)) {
4864 BT_DBG("Unexpected SREJ - not requested");
4865 return L2CAP_TXSEQ_UNEXPECTED_SREJ;
4866 }
4867 }
4868
4869 if (chan->expected_tx_seq == txseq) {
4870 if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
4871 chan->tx_win) {
4872 BT_DBG("Invalid - txseq outside tx window");
4873 return L2CAP_TXSEQ_INVALID;
4874 } else {
4875 BT_DBG("Expected");
4876 return L2CAP_TXSEQ_EXPECTED;
4877 }
4878 }
4879
4880 if (__seq_offset(chan, txseq, chan->last_acked_seq) <
4881 __seq_offset(chan, chan->expected_tx_seq,
4882 chan->last_acked_seq)){
4883 BT_DBG("Duplicate - expected_tx_seq later than txseq");
4884 return L2CAP_TXSEQ_DUPLICATE;
4885 }
4886
4887 if (__seq_offset(chan, txseq, chan->last_acked_seq) >= chan->tx_win) {
4888 /* A source of invalid packets is a "double poll" condition,
4889 * where delays cause us to send multiple poll packets. If
4890 * the remote stack receives and processes both polls,
4891 * sequence numbers can wrap around in such a way that a
4892 * resent frame has a sequence number that looks like new data
4893 * with a sequence gap. This would trigger an erroneous SREJ
4894 * request.
4895 *
4896 * Fortunately, this is impossible with a tx window that's
4897 * less than half of the maximum sequence number, which allows
4898 * invalid frames to be safely ignored.
4899 *
4900 * With tx window sizes greater than half of the tx window
4901 * maximum, the frame is invalid and cannot be ignored. This
4902 * causes a disconnect.
4903 */
4904
4905 if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
4906 BT_DBG("Invalid/Ignore - txseq outside tx window");
4907 return L2CAP_TXSEQ_INVALID_IGNORE;
4908 } else {
4909 BT_DBG("Invalid - txseq outside tx window");
4910 return L2CAP_TXSEQ_INVALID;
4911 }
4912 } else {
4913 BT_DBG("Unexpected - txseq indicates missing frames");
4914 return L2CAP_TXSEQ_UNEXPECTED;
4915 }
4916}
4917
4825static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, 4918static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
4826 struct sk_buff *skb, u8 event) 4919 struct sk_buff *skb, u8 event)
4827{ 4920{
@@ -4832,8 +4925,39 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
4832static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, 4925static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
4833 struct sk_buff *skb) 4926 struct sk_buff *skb)
4834{ 4927{
4835 /* Placeholder */ 4928 int err = 0;
4836 return -ENOTSUPP; 4929
4930 BT_DBG("chan %p, control %p, skb %p, state %d", chan, control, skb,
4931 chan->rx_state);
4932
4933 if (l2cap_classify_txseq(chan, control->txseq) ==
4934 L2CAP_TXSEQ_EXPECTED) {
4935 l2cap_pass_to_tx(chan, control);
4936
4937 BT_DBG("buffer_seq %d->%d", chan->buffer_seq,
4938 __next_seq(chan, chan->buffer_seq));
4939
4940 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4941
4942 l2cap_reassemble_sdu(chan, skb, control);
4943 } else {
4944 if (chan->sdu) {
4945 kfree_skb(chan->sdu);
4946 chan->sdu = NULL;
4947 }
4948 chan->sdu_last_frag = NULL;
4949 chan->sdu_len = 0;
4950
4951 if (skb) {
4952 BT_DBG("Freeing %p", skb);
4953 kfree_skb(skb);
4954 }
4955 }
4956
4957 chan->last_acked_seq = control->txseq;
4958 chan->expected_tx_seq = __next_seq(chan, control->txseq);
4959
4960 return err;
4837} 4961}
4838 4962
4839static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) 4963static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)