diff options
author | Mat Martineau <mathewm@codeaurora.org> | 2012-10-23 18:24:11 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-10-23 22:12:04 -0400 |
commit | 32b32735ca1439e2ead658dd63234c0c380af8ac (patch) | |
tree | ea400cb0ba20d8c105ff33911a39e115f545572a | |
parent | 02b0fbb92dbb0e3c50f1c955547444e3997c80e3 (diff) |
Bluetooth: Add new ERTM receive states for channel move
Two new states are required to implement channel moves with the ERTM
receive state machine.
The "WAIT_P" state is used by a move responder to wait for a "poll"
flag after a move is completed (success or failure). "WAIT_F" is
similarly used by a move initiator to wait for a "final" flag when the
move is completing. In either state, the reqseq value in the
poll/final frame tells the state machine exactly which frame should be
expected next.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Acked-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
-rw-r--r-- | net/bluetooth/l2cap_core.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 24729f54bfd0..b9a91bf3d95e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -4713,6 +4713,12 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, | |||
4713 | return err; | 4713 | return err; |
4714 | } | 4714 | } |
4715 | 4715 | ||
4716 | static int l2cap_resegment(struct l2cap_chan *chan) | ||
4717 | { | ||
4718 | /* Placeholder */ | ||
4719 | return 0; | ||
4720 | } | ||
4721 | |||
4716 | void l2cap_chan_busy(struct l2cap_chan *chan, int busy) | 4722 | void l2cap_chan_busy(struct l2cap_chan *chan, int busy) |
4717 | { | 4723 | { |
4718 | u8 event; | 4724 | u8 event; |
@@ -5218,6 +5224,96 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan, | |||
5218 | return err; | 5224 | return err; |
5219 | } | 5225 | } |
5220 | 5226 | ||
5227 | static int l2cap_finish_move(struct l2cap_chan *chan) | ||
5228 | { | ||
5229 | BT_DBG("chan %p", chan); | ||
5230 | |||
5231 | chan->rx_state = L2CAP_RX_STATE_RECV; | ||
5232 | |||
5233 | if (chan->hs_hcon) | ||
5234 | chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; | ||
5235 | else | ||
5236 | chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; | ||
5237 | |||
5238 | return l2cap_resegment(chan); | ||
5239 | } | ||
5240 | |||
5241 | static int l2cap_rx_state_wait_p(struct l2cap_chan *chan, | ||
5242 | struct l2cap_ctrl *control, | ||
5243 | struct sk_buff *skb, u8 event) | ||
5244 | { | ||
5245 | int err; | ||
5246 | |||
5247 | BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb, | ||
5248 | event); | ||
5249 | |||
5250 | if (!control->poll) | ||
5251 | return -EPROTO; | ||
5252 | |||
5253 | l2cap_process_reqseq(chan, control->reqseq); | ||
5254 | |||
5255 | if (!skb_queue_empty(&chan->tx_q)) | ||
5256 | chan->tx_send_head = skb_peek(&chan->tx_q); | ||
5257 | else | ||
5258 | chan->tx_send_head = NULL; | ||
5259 | |||
5260 | /* Rewind next_tx_seq to the point expected | ||
5261 | * by the receiver. | ||
5262 | */ | ||
5263 | chan->next_tx_seq = control->reqseq; | ||
5264 | chan->unacked_frames = 0; | ||
5265 | |||
5266 | err = l2cap_finish_move(chan); | ||
5267 | if (err) | ||
5268 | return err; | ||
5269 | |||
5270 | set_bit(CONN_SEND_FBIT, &chan->conn_state); | ||
5271 | l2cap_send_i_or_rr_or_rnr(chan); | ||
5272 | |||
5273 | if (event == L2CAP_EV_RECV_IFRAME) | ||
5274 | return -EPROTO; | ||
5275 | |||
5276 | return l2cap_rx_state_recv(chan, control, NULL, event); | ||
5277 | } | ||
5278 | |||
5279 | static int l2cap_rx_state_wait_f(struct l2cap_chan *chan, | ||
5280 | struct l2cap_ctrl *control, | ||
5281 | struct sk_buff *skb, u8 event) | ||
5282 | { | ||
5283 | int err; | ||
5284 | |||
5285 | if (!control->final) | ||
5286 | return -EPROTO; | ||
5287 | |||
5288 | clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); | ||
5289 | |||
5290 | chan->rx_state = L2CAP_RX_STATE_RECV; | ||
5291 | l2cap_process_reqseq(chan, control->reqseq); | ||
5292 | |||
5293 | if (!skb_queue_empty(&chan->tx_q)) | ||
5294 | chan->tx_send_head = skb_peek(&chan->tx_q); | ||
5295 | else | ||
5296 | chan->tx_send_head = NULL; | ||
5297 | |||
5298 | /* Rewind next_tx_seq to the point expected | ||
5299 | * by the receiver. | ||
5300 | */ | ||
5301 | chan->next_tx_seq = control->reqseq; | ||
5302 | chan->unacked_frames = 0; | ||
5303 | |||
5304 | if (chan->hs_hcon) | ||
5305 | chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; | ||
5306 | else | ||
5307 | chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; | ||
5308 | |||
5309 | err = l2cap_resegment(chan); | ||
5310 | |||
5311 | if (!err) | ||
5312 | err = l2cap_rx_state_recv(chan, control, skb, event); | ||
5313 | |||
5314 | return err; | ||
5315 | } | ||
5316 | |||
5221 | static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq) | 5317 | static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq) |
5222 | { | 5318 | { |
5223 | /* Make sure reqseq is for a packet that has been sent but not acked */ | 5319 | /* Make sure reqseq is for a packet that has been sent but not acked */ |
@@ -5244,6 +5340,12 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, | |||
5244 | err = l2cap_rx_state_srej_sent(chan, control, skb, | 5340 | err = l2cap_rx_state_srej_sent(chan, control, skb, |
5245 | event); | 5341 | event); |
5246 | break; | 5342 | break; |
5343 | case L2CAP_RX_STATE_WAIT_P: | ||
5344 | err = l2cap_rx_state_wait_p(chan, control, skb, event); | ||
5345 | break; | ||
5346 | case L2CAP_RX_STATE_WAIT_F: | ||
5347 | err = l2cap_rx_state_wait_f(chan, control, skb, event); | ||
5348 | break; | ||
5247 | default: | 5349 | default: |
5248 | /* shut it down */ | 5350 | /* shut it down */ |
5249 | break; | 5351 | break; |