summaryrefslogtreecommitdiff
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c100
1 files changed, 51 insertions, 49 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b52f66d22437..2c78208d793e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -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;