Commit 836be934 authored by Andrei Emeltchenko's avatar Andrei Emeltchenko Committed by Gustavo F. Padovan

Bluetooth: EWS: support extended seq numbers

Adds support for extended sequence numbers found in
extended control fields.
Signed-off-by: default avatarAndrei Emeltchenko <andrei.emeltchenko@intel.com>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent 88843ab0
...@@ -158,7 +158,7 @@ struct bt_skb_cb { ...@@ -158,7 +158,7 @@ struct bt_skb_cb {
__u8 pkt_type; __u8 pkt_type;
__u8 incoming; __u8 incoming;
__u16 expect; __u16 expect;
__u8 tx_seq; __u16 tx_seq;
__u8 retries; __u8 retries;
__u8 sar; __u8 sar;
unsigned short channel; unsigned short channel;
......
...@@ -381,6 +381,7 @@ struct l2cap_chan { ...@@ -381,6 +381,7 @@ struct l2cap_chan {
__u8 fcs; __u8 fcs;
__u16 tx_win; __u16 tx_win;
__u16 tx_win_max;
__u8 max_tx; __u8 max_tx;
__u16 retrans_timeout; __u16 retrans_timeout;
__u16 monitor_timeout; __u16 monitor_timeout;
...@@ -543,6 +544,22 @@ enum { ...@@ -543,6 +544,22 @@ enum {
L2CAP_DEFAULT_ACK_TO); L2CAP_DEFAULT_ACK_TO);
#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
{
int offset;
offset = (seq1 - seq2) % (chan->tx_win_max + 1);
if (offset < 0)
offset += (chan->tx_win_max + 1);
return offset;
}
static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
{
return (seq + 1) % (chan->tx_win_max + 1);
}
static inline int l2cap_tx_window_full(struct l2cap_chan *ch) static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
{ {
int sub; int sub;
......
...@@ -1295,7 +1295,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan) ...@@ -1295,7 +1295,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan)
l2cap_do_send(chan, skb); l2cap_do_send(chan, skb);
chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
} }
} }
...@@ -1389,7 +1389,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) ...@@ -1389,7 +1389,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
__set_retrans_timer(chan); __set_retrans_timer(chan);
bt_cb(skb)->tx_seq = chan->next_tx_seq; bt_cb(skb)->tx_seq = chan->next_tx_seq;
chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
if (bt_cb(skb)->retries == 1) if (bt_cb(skb)->retries == 1)
chan->unacked_frames++; chan->unacked_frames++;
...@@ -1967,12 +1968,15 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan) ...@@ -1967,12 +1968,15 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
static inline void l2cap_txwin_setup(struct l2cap_chan *chan) static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
{ {
if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW && if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
__l2cap_ews_supported(chan)) __l2cap_ews_supported(chan)) {
/* use extended control field */ /* use extended control field */
set_bit(FLAG_EXT_CTRL, &chan->flags); set_bit(FLAG_EXT_CTRL, &chan->flags);
else chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
} else {
chan->tx_win = min_t(u16, chan->tx_win, chan->tx_win = min_t(u16, chan->tx_win,
L2CAP_DEFAULT_TX_WINDOW); L2CAP_DEFAULT_TX_WINDOW);
chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
}
} }
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
...@@ -2138,6 +2142,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) ...@@ -2138,6 +2142,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
set_bit(FLAG_EXT_CTRL, &chan->flags); set_bit(FLAG_EXT_CTRL, &chan->flags);
set_bit(CONF_EWS_RECV, &chan->conf_state); set_bit(CONF_EWS_RECV, &chan->conf_state);
chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
chan->remote_tx_win = val; chan->remote_tx_win = val;
break; break;
...@@ -3225,18 +3230,14 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, ...@@ -3225,18 +3230,14 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
return 0; return 0;
} }
tx_seq_offset = (tx_seq - chan->buffer_seq) % 64; tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
if (tx_seq_offset < 0)
tx_seq_offset += 64;
do { do {
if (bt_cb(next_skb)->tx_seq == tx_seq) if (bt_cb(next_skb)->tx_seq == tx_seq)
return -EINVAL; return -EINVAL;
next_tx_seq_offset = (bt_cb(next_skb)->tx_seq - next_tx_seq_offset = __seq_offset(chan,
chan->buffer_seq) % 64; bt_cb(next_skb)->tx_seq, chan->buffer_seq);
if (next_tx_seq_offset < 0)
next_tx_seq_offset += 64;
if (next_tx_seq_offset > tx_seq_offset) { if (next_tx_seq_offset > tx_seq_offset) {
__skb_queue_before(&chan->srej_q, next_skb, skb); __skb_queue_before(&chan->srej_q, next_skb, skb);
...@@ -3426,9 +3427,8 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq) ...@@ -3426,9 +3427,8 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
break; break;
} }
chan->buffer_seq_srej = chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
(chan->buffer_seq_srej + 1) % 64; tx_seq = __next_seq(chan, tx_seq);
tx_seq = (tx_seq + 1) % 64;
} }
} }
...@@ -3463,10 +3463,13 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq) ...@@ -3463,10 +3463,13 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
new->tx_seq = chan->expected_tx_seq; new->tx_seq = chan->expected_tx_seq;
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
list_add_tail(&new->list, &chan->srej_l); list_add_tail(&new->list, &chan->srej_l);
} }
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
} }
static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb) static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
...@@ -3492,9 +3495,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont ...@@ -3492,9 +3495,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
chan->expected_ack_seq = req_seq; chan->expected_ack_seq = req_seq;
l2cap_drop_acked_frames(chan); l2cap_drop_acked_frames(chan);
tx_seq_offset = (tx_seq - chan->buffer_seq) % 64; tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
if (tx_seq_offset < 0)
tx_seq_offset += 64;
/* invalid tx_seq */ /* invalid tx_seq */
if (tx_seq_offset >= chan->tx_win) { if (tx_seq_offset >= chan->tx_win) {
...@@ -3542,10 +3543,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont ...@@ -3542,10 +3543,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
l2cap_send_srejframe(chan, tx_seq); l2cap_send_srejframe(chan, tx_seq);
} }
} else { } else {
expected_tx_seq_offset = expected_tx_seq_offset = __seq_offset(chan,
(chan->expected_tx_seq - chan->buffer_seq) % 64; chan->expected_tx_seq, chan->buffer_seq);
if (expected_tx_seq_offset < 0)
expected_tx_seq_offset += 64;
/* duplicated tx_seq */ /* duplicated tx_seq */
if (tx_seq_offset < expected_tx_seq_offset) if (tx_seq_offset < expected_tx_seq_offset)
...@@ -3570,7 +3569,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont ...@@ -3570,7 +3569,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
return 0; return 0;
expected: expected:
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
bt_cb(skb)->tx_seq = tx_seq; bt_cb(skb)->tx_seq = tx_seq;
...@@ -3580,7 +3579,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont ...@@ -3580,7 +3579,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_cont
} }
err = l2cap_reassemble_sdu(chan, skb, rx_control); err = l2cap_reassemble_sdu(chan, skb, rx_control);
chan->buffer_seq = (chan->buffer_seq + 1) % 64; chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
if (err < 0) { if (err < 0) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
return err; return err;
...@@ -3794,14 +3794,11 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -3794,14 +3794,11 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
} }
req_seq = __get_reqseq(chan, control); req_seq = __get_reqseq(chan, control);
req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
if (req_seq_offset < 0)
req_seq_offset += 64;
next_tx_seq_offset = req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
(chan->next_tx_seq - chan->expected_ack_seq) % 64;
if (next_tx_seq_offset < 0) next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
next_tx_seq_offset += 64; chan->expected_ack_seq);
/* check for invalid req-seq */ /* check for invalid req-seq */
if (req_seq_offset > next_tx_seq_offset) { if (req_seq_offset > next_tx_seq_offset) {
...@@ -3907,7 +3904,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk ...@@ -3907,7 +3904,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
/* TODO: Notify userland of missing data */ /* TODO: Notify userland of missing data */
} }
chan->expected_tx_seq = (tx_seq + 1) % 64; chan->expected_tx_seq = __next_seq(chan, tx_seq);
if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE) if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment