diff options
author | Mat Martineau <mathewm@codeaurora.org> | 2012-05-17 23:53:42 -0400 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2012-06-04 23:34:03 -0400 |
commit | d2a7ac5d5d3a0b166ac128883bd088064c029fe5 (patch) | |
tree | b6a03c938d1ac579a5fd8f7a6095441e9c4505eb | |
parent | e31f76337257616aca0ea15abee271513b17426c (diff) |
Bluetooth: Add the ERTM receive state machine
This adds a top-level state machine with handlers for two receive
states defined in the ERTM spec, RECV and SREJ_SENT. The reqseq value
of the incoming frame is also validated at the top level and a
disconnection is forced if it is invalid. The actions for the RECV
and SREJ_SENT states are implemented according to the state tables in
the ERTM specification.
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.c | 355 |
1 files changed, 353 insertions, 2 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a7d96c937392..287d64cf2dd4 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -1760,6 +1760,12 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) | |||
1760 | return sent; | 1760 | return sent; |
1761 | } | 1761 | } |
1762 | 1762 | ||
1763 | static void l2cap_retransmit_all(struct l2cap_chan *chan, | ||
1764 | struct l2cap_ctrl *control) | ||
1765 | { | ||
1766 | /* Placeholder */ | ||
1767 | } | ||
1768 | |||
1763 | static void l2cap_send_ack(struct l2cap_chan *chan) | 1769 | static void l2cap_send_ack(struct l2cap_chan *chan) |
1764 | { | 1770 | { |
1765 | struct l2cap_ctrl control; | 1771 | struct l2cap_ctrl control; |
@@ -2127,6 +2133,21 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, | |||
2127 | return err; | 2133 | return err; |
2128 | } | 2134 | } |
2129 | 2135 | ||
2136 | static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq) | ||
2137 | { | ||
2138 | /* Placeholder */ | ||
2139 | } | ||
2140 | |||
2141 | static void l2cap_send_srej_tail(struct l2cap_chan *chan) | ||
2142 | { | ||
2143 | /* Placeholder */ | ||
2144 | } | ||
2145 | |||
2146 | static void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq) | ||
2147 | { | ||
2148 | /* Placeholder */ | ||
2149 | } | ||
2150 | |||
2130 | static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq) | 2151 | static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq) |
2131 | { | 2152 | { |
2132 | struct sk_buff *acked_skb; | 2153 | struct sk_buff *acked_skb; |
@@ -4327,6 +4348,24 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy) | |||
4327 | l2cap_tx(chan, 0, 0, event); | 4348 | l2cap_tx(chan, 0, 0, event); |
4328 | } | 4349 | } |
4329 | 4350 | ||
4351 | static int l2cap_rx_queued_iframes(struct l2cap_chan *chan) | ||
4352 | { | ||
4353 | /* Placeholder */ | ||
4354 | return 0; | ||
4355 | } | ||
4356 | |||
4357 | static void l2cap_handle_srej(struct l2cap_chan *chan, | ||
4358 | struct l2cap_ctrl *control) | ||
4359 | { | ||
4360 | /* Placeholder */ | ||
4361 | } | ||
4362 | |||
4363 | static void l2cap_handle_rej(struct l2cap_chan *chan, | ||
4364 | struct l2cap_ctrl *control) | ||
4365 | { | ||
4366 | /* Placeholder */ | ||
4367 | } | ||
4368 | |||
4330 | static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq) | 4369 | static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq) |
4331 | { | 4370 | { |
4332 | BT_DBG("chan %p, txseq %d", chan, txseq); | 4371 | BT_DBG("chan %p, txseq %d", chan, txseq); |
@@ -4414,11 +4453,323 @@ static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq) | |||
4414 | } | 4453 | } |
4415 | } | 4454 | } |
4416 | 4455 | ||
4456 | static int l2cap_rx_state_recv(struct l2cap_chan *chan, | ||
4457 | struct l2cap_ctrl *control, | ||
4458 | struct sk_buff *skb, u8 event) | ||
4459 | { | ||
4460 | int err = 0; | ||
4461 | bool skb_in_use = 0; | ||
4462 | |||
4463 | BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb, | ||
4464 | event); | ||
4465 | |||
4466 | switch (event) { | ||
4467 | case L2CAP_EV_RECV_IFRAME: | ||
4468 | switch (l2cap_classify_txseq(chan, control->txseq)) { | ||
4469 | case L2CAP_TXSEQ_EXPECTED: | ||
4470 | l2cap_pass_to_tx(chan, control); | ||
4471 | |||
4472 | if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { | ||
4473 | BT_DBG("Busy, discarding expected seq %d", | ||
4474 | control->txseq); | ||
4475 | break; | ||
4476 | } | ||
4477 | |||
4478 | chan->expected_tx_seq = __next_seq(chan, | ||
4479 | control->txseq); | ||
4480 | |||
4481 | chan->buffer_seq = chan->expected_tx_seq; | ||
4482 | skb_in_use = 1; | ||
4483 | |||
4484 | err = l2cap_reassemble_sdu(chan, skb, control); | ||
4485 | if (err) | ||
4486 | break; | ||
4487 | |||
4488 | if (control->final) { | ||
4489 | if (!test_and_clear_bit(CONN_REJ_ACT, | ||
4490 | &chan->conn_state)) { | ||
4491 | control->final = 0; | ||
4492 | l2cap_retransmit_all(chan, control); | ||
4493 | l2cap_ertm_send(chan); | ||
4494 | } | ||
4495 | } | ||
4496 | |||
4497 | if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) | ||
4498 | l2cap_send_ack(chan); | ||
4499 | break; | ||
4500 | case L2CAP_TXSEQ_UNEXPECTED: | ||
4501 | l2cap_pass_to_tx(chan, control); | ||
4502 | |||
4503 | /* Can't issue SREJ frames in the local busy state. | ||
4504 | * Drop this frame, it will be seen as missing | ||
4505 | * when local busy is exited. | ||
4506 | */ | ||
4507 | if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { | ||
4508 | BT_DBG("Busy, discarding unexpected seq %d", | ||
4509 | control->txseq); | ||
4510 | break; | ||
4511 | } | ||
4512 | |||
4513 | /* There was a gap in the sequence, so an SREJ | ||
4514 | * must be sent for each missing frame. The | ||
4515 | * current frame is stored for later use. | ||
4516 | */ | ||
4517 | skb_queue_tail(&chan->srej_q, skb); | ||
4518 | skb_in_use = 1; | ||
4519 | BT_DBG("Queued %p (queue len %d)", skb, | ||
4520 | skb_queue_len(&chan->srej_q)); | ||
4521 | |||
4522 | clear_bit(CONN_SREJ_ACT, &chan->conn_state); | ||
4523 | l2cap_seq_list_clear(&chan->srej_list); | ||
4524 | l2cap_send_srej(chan, control->txseq); | ||
4525 | |||
4526 | chan->rx_state = L2CAP_RX_STATE_SREJ_SENT; | ||
4527 | break; | ||
4528 | case L2CAP_TXSEQ_DUPLICATE: | ||
4529 | l2cap_pass_to_tx(chan, control); | ||
4530 | break; | ||
4531 | case L2CAP_TXSEQ_INVALID_IGNORE: | ||
4532 | break; | ||
4533 | case L2CAP_TXSEQ_INVALID: | ||
4534 | default: | ||
4535 | l2cap_send_disconn_req(chan->conn, chan, | ||
4536 | ECONNRESET); | ||
4537 | break; | ||
4538 | } | ||
4539 | break; | ||
4540 | case L2CAP_EV_RECV_RR: | ||
4541 | l2cap_pass_to_tx(chan, control); | ||
4542 | if (control->final) { | ||
4543 | clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); | ||
4544 | |||
4545 | if (!test_and_clear_bit(CONN_REJ_ACT, | ||
4546 | &chan->conn_state)) { | ||
4547 | control->final = 0; | ||
4548 | l2cap_retransmit_all(chan, control); | ||
4549 | } | ||
4550 | |||
4551 | l2cap_ertm_send(chan); | ||
4552 | } else if (control->poll) { | ||
4553 | l2cap_send_i_or_rr_or_rnr(chan); | ||
4554 | } else { | ||
4555 | if (test_and_clear_bit(CONN_REMOTE_BUSY, | ||
4556 | &chan->conn_state) && | ||
4557 | chan->unacked_frames) | ||
4558 | __set_retrans_timer(chan); | ||
4559 | |||
4560 | l2cap_ertm_send(chan); | ||
4561 | } | ||
4562 | break; | ||
4563 | case L2CAP_EV_RECV_RNR: | ||
4564 | set_bit(CONN_REMOTE_BUSY, &chan->conn_state); | ||
4565 | l2cap_pass_to_tx(chan, control); | ||
4566 | if (control && control->poll) { | ||
4567 | set_bit(CONN_SEND_FBIT, &chan->conn_state); | ||
4568 | l2cap_send_rr_or_rnr(chan, 0); | ||
4569 | } | ||
4570 | __clear_retrans_timer(chan); | ||
4571 | l2cap_seq_list_clear(&chan->retrans_list); | ||
4572 | break; | ||
4573 | case L2CAP_EV_RECV_REJ: | ||
4574 | l2cap_handle_rej(chan, control); | ||
4575 | break; | ||
4576 | case L2CAP_EV_RECV_SREJ: | ||
4577 | l2cap_handle_srej(chan, control); | ||
4578 | break; | ||
4579 | default: | ||
4580 | break; | ||
4581 | } | ||
4582 | |||
4583 | if (skb && !skb_in_use) { | ||
4584 | BT_DBG("Freeing %p", skb); | ||
4585 | kfree_skb(skb); | ||
4586 | } | ||
4587 | |||
4588 | return err; | ||
4589 | } | ||
4590 | |||
4591 | static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan, | ||
4592 | struct l2cap_ctrl *control, | ||
4593 | struct sk_buff *skb, u8 event) | ||
4594 | { | ||
4595 | int err = 0; | ||
4596 | u16 txseq = control->txseq; | ||
4597 | bool skb_in_use = 0; | ||
4598 | |||
4599 | BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb, | ||
4600 | event); | ||
4601 | |||
4602 | switch (event) { | ||
4603 | case L2CAP_EV_RECV_IFRAME: | ||
4604 | switch (l2cap_classify_txseq(chan, txseq)) { | ||
4605 | case L2CAP_TXSEQ_EXPECTED: | ||
4606 | /* Keep frame for reassembly later */ | ||
4607 | l2cap_pass_to_tx(chan, control); | ||
4608 | skb_queue_tail(&chan->srej_q, skb); | ||
4609 | skb_in_use = 1; | ||
4610 | BT_DBG("Queued %p (queue len %d)", skb, | ||
4611 | skb_queue_len(&chan->srej_q)); | ||
4612 | |||
4613 | chan->expected_tx_seq = __next_seq(chan, txseq); | ||
4614 | break; | ||
4615 | case L2CAP_TXSEQ_EXPECTED_SREJ: | ||
4616 | l2cap_seq_list_pop(&chan->srej_list); | ||
4617 | |||
4618 | l2cap_pass_to_tx(chan, control); | ||
4619 | skb_queue_tail(&chan->srej_q, skb); | ||
4620 | skb_in_use = 1; | ||
4621 | BT_DBG("Queued %p (queue len %d)", skb, | ||
4622 | skb_queue_len(&chan->srej_q)); | ||
4623 | |||
4624 | err = l2cap_rx_queued_iframes(chan); | ||
4625 | if (err) | ||
4626 | break; | ||
4627 | |||
4628 | break; | ||
4629 | case L2CAP_TXSEQ_UNEXPECTED: | ||
4630 | /* Got a frame that can't be reassembled yet. | ||
4631 | * Save it for later, and send SREJs to cover | ||
4632 | * the missing frames. | ||
4633 | */ | ||
4634 | skb_queue_tail(&chan->srej_q, skb); | ||
4635 | skb_in_use = 1; | ||
4636 | BT_DBG("Queued %p (queue len %d)", skb, | ||
4637 | skb_queue_len(&chan->srej_q)); | ||
4638 | |||
4639 | l2cap_pass_to_tx(chan, control); | ||
4640 | l2cap_send_srej(chan, control->txseq); | ||
4641 | break; | ||
4642 | case L2CAP_TXSEQ_UNEXPECTED_SREJ: | ||
4643 | /* This frame was requested with an SREJ, but | ||
4644 | * some expected retransmitted frames are | ||
4645 | * missing. Request retransmission of missing | ||
4646 | * SREJ'd frames. | ||
4647 | */ | ||
4648 | skb_queue_tail(&chan->srej_q, skb); | ||
4649 | skb_in_use = 1; | ||
4650 | BT_DBG("Queued %p (queue len %d)", skb, | ||
4651 | skb_queue_len(&chan->srej_q)); | ||
4652 | |||
4653 | l2cap_pass_to_tx(chan, control); | ||
4654 | l2cap_send_srej_list(chan, control->txseq); | ||
4655 | break; | ||
4656 | case L2CAP_TXSEQ_DUPLICATE_SREJ: | ||
4657 | /* We've already queued this frame. Drop this copy. */ | ||
4658 | l2cap_pass_to_tx(chan, control); | ||
4659 | break; | ||
4660 | case L2CAP_TXSEQ_DUPLICATE: | ||
4661 | /* Expecting a later sequence number, so this frame | ||
4662 | * was already received. Ignore it completely. | ||
4663 | */ | ||
4664 | break; | ||
4665 | case L2CAP_TXSEQ_INVALID_IGNORE: | ||
4666 | break; | ||
4667 | case L2CAP_TXSEQ_INVALID: | ||
4668 | default: | ||
4669 | l2cap_send_disconn_req(chan->conn, chan, | ||
4670 | ECONNRESET); | ||
4671 | break; | ||
4672 | } | ||
4673 | break; | ||
4674 | case L2CAP_EV_RECV_RR: | ||
4675 | l2cap_pass_to_tx(chan, control); | ||
4676 | if (control->final) { | ||
4677 | clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); | ||
4678 | |||
4679 | if (!test_and_clear_bit(CONN_REJ_ACT, | ||
4680 | &chan->conn_state)) { | ||
4681 | control->final = 0; | ||
4682 | l2cap_retransmit_all(chan, control); | ||
4683 | } | ||
4684 | |||
4685 | l2cap_ertm_send(chan); | ||
4686 | } else if (control->poll) { | ||
4687 | if (test_and_clear_bit(CONN_REMOTE_BUSY, | ||
4688 | &chan->conn_state) && | ||
4689 | chan->unacked_frames) { | ||
4690 | __set_retrans_timer(chan); | ||
4691 | } | ||
4692 | |||
4693 | set_bit(CONN_SEND_FBIT, &chan->conn_state); | ||
4694 | l2cap_send_srej_tail(chan); | ||
4695 | } else { | ||
4696 | if (test_and_clear_bit(CONN_REMOTE_BUSY, | ||
4697 | &chan->conn_state) && | ||
4698 | chan->unacked_frames) | ||
4699 | __set_retrans_timer(chan); | ||
4700 | |||
4701 | l2cap_send_ack(chan); | ||
4702 | } | ||
4703 | break; | ||
4704 | case L2CAP_EV_RECV_RNR: | ||
4705 | set_bit(CONN_REMOTE_BUSY, &chan->conn_state); | ||
4706 | l2cap_pass_to_tx(chan, control); | ||
4707 | if (control->poll) { | ||
4708 | l2cap_send_srej_tail(chan); | ||
4709 | } else { | ||
4710 | struct l2cap_ctrl rr_control; | ||
4711 | memset(&rr_control, 0, sizeof(rr_control)); | ||
4712 | rr_control.sframe = 1; | ||
4713 | rr_control.super = L2CAP_SUPER_RR; | ||
4714 | rr_control.reqseq = chan->buffer_seq; | ||
4715 | l2cap_send_sframe(chan, &rr_control); | ||
4716 | } | ||
4717 | |||
4718 | break; | ||
4719 | case L2CAP_EV_RECV_REJ: | ||
4720 | l2cap_handle_rej(chan, control); | ||
4721 | break; | ||
4722 | case L2CAP_EV_RECV_SREJ: | ||
4723 | l2cap_handle_srej(chan, control); | ||
4724 | break; | ||
4725 | } | ||
4726 | |||
4727 | if (skb && !skb_in_use) { | ||
4728 | BT_DBG("Freeing %p", skb); | ||
4729 | kfree_skb(skb); | ||
4730 | } | ||
4731 | |||
4732 | return err; | ||
4733 | } | ||
4734 | |||
4735 | static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq) | ||
4736 | { | ||
4737 | /* Make sure reqseq is for a packet that has been sent but not acked */ | ||
4738 | u16 unacked; | ||
4739 | |||
4740 | unacked = __seq_offset(chan, chan->next_tx_seq, chan->expected_ack_seq); | ||
4741 | return __seq_offset(chan, chan->next_tx_seq, reqseq) <= unacked; | ||
4742 | } | ||
4743 | |||
4417 | static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, | 4744 | static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, |
4418 | struct sk_buff *skb, u8 event) | 4745 | struct sk_buff *skb, u8 event) |
4419 | { | 4746 | { |
4420 | /* Placeholder */ | 4747 | int err = 0; |
4421 | return -ENOTSUPP; | 4748 | |
4749 | BT_DBG("chan %p, control %p, skb %p, event %d, state %d", chan, | ||
4750 | control, skb, event, chan->rx_state); | ||
4751 | |||
4752 | if (__valid_reqseq(chan, control->reqseq)) { | ||
4753 | switch (chan->rx_state) { | ||
4754 | case L2CAP_RX_STATE_RECV: | ||
4755 | err = l2cap_rx_state_recv(chan, control, skb, event); | ||
4756 | break; | ||
4757 | case L2CAP_RX_STATE_SREJ_SENT: | ||
4758 | err = l2cap_rx_state_srej_sent(chan, control, skb, | ||
4759 | event); | ||
4760 | break; | ||
4761 | default: | ||
4762 | /* shut it down */ | ||
4763 | break; | ||
4764 | } | ||
4765 | } else { | ||
4766 | BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d", | ||
4767 | control->reqseq, chan->next_tx_seq, | ||
4768 | chan->expected_ack_seq); | ||
4769 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); | ||
4770 | } | ||
4771 | |||
4772 | return err; | ||
4422 | } | 4773 | } |
4423 | 4774 | ||
4424 | static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, | 4775 | static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, |