|
@@ -53,8 +53,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
|
|
|
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
|
|
|
void *data);
|
|
|
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
|
|
|
-static void l2cap_send_disconn_req(struct l2cap_conn *conn,
|
|
|
- struct l2cap_chan *chan, int err);
|
|
|
+static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
|
|
|
|
|
|
static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
|
|
|
struct sk_buff_head *skbs, u8 event);
|
|
@@ -632,7 +631,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
|
|
|
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
|
|
|
conn->hcon->type == ACL_LINK) {
|
|
|
__set_chan_timer(chan, sk->sk_sndtimeo);
|
|
|
- l2cap_send_disconn_req(conn, chan, reason);
|
|
|
+ l2cap_send_disconn_req(chan, reason);
|
|
|
} else
|
|
|
l2cap_chan_del(chan, reason);
|
|
|
break;
|
|
@@ -1014,6 +1013,7 @@ static bool __amp_capable(struct l2cap_chan *chan)
|
|
|
struct l2cap_conn *conn = chan->conn;
|
|
|
|
|
|
if (enable_hs &&
|
|
|
+ hci_amp_capable() &&
|
|
|
chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED &&
|
|
|
conn->fixed_chan_mask & L2CAP_FC_A2MP)
|
|
|
return true;
|
|
@@ -1180,10 +1180,10 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void l2cap_send_disconn_req(struct l2cap_conn *conn,
|
|
|
- struct l2cap_chan *chan, int err)
|
|
|
+static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err)
|
|
|
{
|
|
|
struct sock *sk = chan->sk;
|
|
|
+ struct l2cap_conn *conn = chan->conn;
|
|
|
struct l2cap_disconn_req req;
|
|
|
|
|
|
if (!conn)
|
|
@@ -1960,7 +1960,7 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
|
|
|
if (chan->max_tx != 0 &&
|
|
|
bt_cb(skb)->control.retries > chan->max_tx) {
|
|
|
BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
l2cap_seq_list_clear(&chan->retrans_list);
|
|
|
break;
|
|
|
}
|
|
@@ -2666,7 +2666,7 @@ static void l2cap_tx_state_wait_f(struct l2cap_chan *chan,
|
|
|
__set_monitor_timer(chan);
|
|
|
chan->retry_count++;
|
|
|
} else {
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNABORTED);
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
@@ -3106,18 +3106,17 @@ done:
|
|
|
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
|
|
|
l2cap_add_opt_efs(&ptr, chan);
|
|
|
|
|
|
- if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
|
|
|
- break;
|
|
|
-
|
|
|
- if (chan->fcs == L2CAP_FCS_NONE ||
|
|
|
- test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
|
|
|
- chan->fcs = L2CAP_FCS_NONE;
|
|
|
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
|
|
|
- }
|
|
|
-
|
|
|
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
|
|
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
|
|
|
chan->tx_win);
|
|
|
+
|
|
|
+ if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
|
|
|
+ if (chan->fcs == L2CAP_FCS_NONE ||
|
|
|
+ test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
|
|
|
+ chan->fcs = L2CAP_FCS_NONE;
|
|
|
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
|
|
|
+ chan->fcs);
|
|
|
+ }
|
|
|
break;
|
|
|
|
|
|
case L2CAP_MODE_STREAMING:
|
|
@@ -3139,14 +3138,13 @@ done:
|
|
|
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
|
|
|
l2cap_add_opt_efs(&ptr, chan);
|
|
|
|
|
|
- if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
|
|
|
- break;
|
|
|
-
|
|
|
- if (chan->fcs == L2CAP_FCS_NONE ||
|
|
|
- test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
|
|
|
- chan->fcs = L2CAP_FCS_NONE;
|
|
|
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
|
|
|
- }
|
|
|
+ if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
|
|
|
+ if (chan->fcs == L2CAP_FCS_NONE ||
|
|
|
+ test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
|
|
|
+ chan->fcs = L2CAP_FCS_NONE;
|
|
|
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
|
|
|
+ chan->fcs);
|
|
|
+ }
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -3198,7 +3196,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
|
|
|
|
|
case L2CAP_CONF_FCS:
|
|
|
if (val == L2CAP_FCS_NONE)
|
|
|
- set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
|
|
|
+ set_bit(CONF_RECV_NO_FCS, &chan->conf_state);
|
|
|
break;
|
|
|
|
|
|
case L2CAP_CONF_EFS:
|
|
@@ -3433,6 +3431,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
|
|
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
|
|
|
(unsigned long) &efs);
|
|
|
break;
|
|
|
+
|
|
|
+ case L2CAP_CONF_FCS:
|
|
|
+ if (*result == L2CAP_CONF_PENDING)
|
|
|
+ if (val == L2CAP_FCS_NONE)
|
|
|
+ set_bit(CONF_RECV_NO_FCS,
|
|
|
+ &chan->conf_state);
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -3802,7 +3807,7 @@ static inline void set_default_fcs(struct l2cap_chan *chan)
|
|
|
*/
|
|
|
if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
|
|
|
chan->fcs = L2CAP_FCS_NONE;
|
|
|
- else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
|
|
|
+ else if (!test_bit(CONF_RECV_NO_FCS, &chan->conf_state))
|
|
|
chan->fcs = L2CAP_FCS_CRC16;
|
|
|
}
|
|
|
|
|
@@ -3877,7 +3882,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
|
|
/* Complete config. */
|
|
|
len = l2cap_parse_conf_req(chan, rsp);
|
|
|
if (len < 0) {
|
|
|
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
goto unlock;
|
|
|
}
|
|
|
|
|
@@ -3899,7 +3904,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
|
|
err = l2cap_ertm_init(chan);
|
|
|
|
|
|
if (err < 0)
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, -err);
|
|
|
+ l2cap_send_disconn_req(chan, -err);
|
|
|
else
|
|
|
l2cap_chan_ready(chan);
|
|
|
|
|
@@ -3967,7 +3972,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|
|
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
|
|
|
buf, &result);
|
|
|
if (len < 0) {
|
|
|
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
@@ -3988,7 +3993,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|
|
char req[64];
|
|
|
|
|
|
if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
|
|
|
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
@@ -3997,7 +4002,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|
|
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
|
|
|
req, &result);
|
|
|
if (len < 0) {
|
|
|
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
@@ -4013,7 +4018,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|
|
l2cap_chan_set_err(chan, ECONNRESET);
|
|
|
|
|
|
__set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
|
|
|
- l2cap_send_disconn_req(conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
@@ -4030,7 +4035,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|
|
err = l2cap_ertm_init(chan);
|
|
|
|
|
|
if (err < 0)
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, -err);
|
|
|
+ l2cap_send_disconn_req(chan, -err);
|
|
|
else
|
|
|
l2cap_chan_ready(chan);
|
|
|
}
|
|
@@ -4392,7 +4397,7 @@ static void l2cap_logical_fail(struct l2cap_chan *chan)
|
|
|
/* Logical link setup failed */
|
|
|
if (chan->state != BT_CONNECTED) {
|
|
|
/* Create channel failure, disconnect */
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -4435,7 +4440,7 @@ static void l2cap_logical_finish_create(struct l2cap_chan *chan,
|
|
|
|
|
|
err = l2cap_ertm_init(chan);
|
|
|
if (err < 0)
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, -err);
|
|
|
+ l2cap_send_disconn_req(chan, -err);
|
|
|
else
|
|
|
l2cap_chan_ready(chan);
|
|
|
}
|
|
@@ -5400,7 +5405,7 @@ static void l2cap_handle_srej(struct l2cap_chan *chan,
|
|
|
|
|
|
if (control->reqseq == chan->next_tx_seq) {
|
|
|
BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -5414,7 +5419,7 @@ static void l2cap_handle_srej(struct l2cap_chan *chan,
|
|
|
|
|
|
if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) {
|
|
|
BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -5458,7 +5463,7 @@ static void l2cap_handle_rej(struct l2cap_chan *chan,
|
|
|
|
|
|
if (control->reqseq == chan->next_tx_seq) {
|
|
|
BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -5467,7 +5472,7 @@ static void l2cap_handle_rej(struct l2cap_chan *chan,
|
|
|
if (chan->max_tx && skb &&
|
|
|
bt_cb(skb)->control.retries >= chan->max_tx) {
|
|
|
BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -5651,8 +5656,7 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,
|
|
|
break;
|
|
|
case L2CAP_TXSEQ_INVALID:
|
|
|
default:
|
|
|
- l2cap_send_disconn_req(chan->conn, chan,
|
|
|
- ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
break;
|
|
|
}
|
|
|
break;
|
|
@@ -5785,8 +5789,7 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
|
|
|
break;
|
|
|
case L2CAP_TXSEQ_INVALID:
|
|
|
default:
|
|
|
- l2cap_send_disconn_req(chan->conn, chan,
|
|
|
- ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
break;
|
|
|
}
|
|
|
break;
|
|
@@ -5981,7 +5984,7 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
|
|
|
BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d",
|
|
|
control->reqseq, chan->next_tx_seq,
|
|
|
chan->expected_ack_seq);
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
}
|
|
|
|
|
|
return err;
|
|
@@ -6050,7 +6053,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|
|
len -= L2CAP_FCS_SIZE;
|
|
|
|
|
|
if (len > chan->mps) {
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
goto drop;
|
|
|
}
|
|
|
|
|
@@ -6075,8 +6078,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|
|
}
|
|
|
|
|
|
if (err)
|
|
|
- l2cap_send_disconn_req(chan->conn, chan,
|
|
|
- ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
} else {
|
|
|
const u8 rx_func_to_event[4] = {
|
|
|
L2CAP_EV_RECV_RR, L2CAP_EV_RECV_REJ,
|
|
@@ -6093,7 +6095,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|
|
|
|
|
if (len != 0) {
|
|
|
BT_ERR("Trailing bytes: %d in sframe", len);
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
goto drop;
|
|
|
}
|
|
|
|
|
@@ -6104,7 +6106,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|
|
|
|
|
event = rx_func_to_event[control->super];
|
|
|
if (l2cap_rx(chan, control, skb, event))
|
|
|
- l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
|
|
|
+ l2cap_send_disconn_req(chan, ECONNRESET);
|
|
|
}
|
|
|
|
|
|
return 0;
|