Skip to content

Commit 9aa9d94

Browse files
committed
Bluetooth: L2CAP: Fix responding with wrong PDU type
L2CAP_ECRED_CONN_REQ shall be responded with L2CAP_ECRED_CONN_RSP not L2CAP_LE_CONN_RSP: L2CAP LE EATT Server - Reject - run Listening for connections New client connection with handle 0x002a Sending L2CAP Request from client Client received response code 0x15 Unexpected L2CAP response code (expected 0x18) L2CAP LE EATT Server - Reject - test failed > ACL Data RX: Handle 42 flags 0x02 dlen 26 LE L2CAP: Enhanced Credit Connection Request (0x17) ident 1 len 18 PSM: 39 (0x0027) MTU: 64 MPS: 64 Credits: 5 Source CID: 65 Source CID: 66 Source CID: 67 Source CID: 68 Source CID: 69 < ACL Data TX: Handle 42 flags 0x00 dlen 16 LE L2CAP: LE Connection Response (0x15) ident 1 len 8 invalid size 00 00 00 00 00 00 06 00 L2CAP LE EATT Server - Reject - run Listening for connections New client connection with handle 0x002a Sending L2CAP Request from client Client received response code 0x18 L2CAP LE EATT Server - Reject - test passed Fixes: 15f02b9 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 5d44ab9 commit 9aa9d94

File tree

1 file changed

+79
-38
lines changed

1 file changed

+79
-38
lines changed

net/bluetooth/l2cap_core.c

Lines changed: 79 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,17 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
708708
}
709709
EXPORT_SYMBOL_GPL(l2cap_chan_del);
710710

711+
static void __l2cap_chan_list_id(struct l2cap_conn *conn, u16 id,
712+
l2cap_chan_func_t func, void *data)
713+
{
714+
struct l2cap_chan *chan, *l;
715+
716+
list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
717+
if (chan->ident == id)
718+
func(chan, data);
719+
}
720+
}
721+
711722
static void __l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
712723
void *data)
713724
{
@@ -775,23 +786,9 @@ static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
775786

776787
static void l2cap_chan_ecred_connect_reject(struct l2cap_chan *chan)
777788
{
778-
struct l2cap_conn *conn = chan->conn;
779-
struct l2cap_ecred_conn_rsp rsp;
780-
u16 result;
781-
782-
if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
783-
result = L2CAP_CR_LE_AUTHORIZATION;
784-
else
785-
result = L2CAP_CR_LE_BAD_PSM;
786-
787789
l2cap_state_change(chan, BT_DISCONN);
788790

789-
memset(&rsp, 0, sizeof(rsp));
790-
791-
rsp.result = cpu_to_le16(result);
792-
793-
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
794-
&rsp);
791+
__l2cap_ecred_conn_rsp_defer(chan);
795792
}
796793

797794
static void l2cap_chan_connect_reject(struct l2cap_chan *chan)
@@ -846,7 +843,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
846843
break;
847844
case L2CAP_MODE_EXT_FLOWCTL:
848845
l2cap_chan_ecred_connect_reject(chan);
849-
break;
846+
return;
850847
}
851848
}
852849
}
@@ -3938,43 +3935,86 @@ void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan)
39383935
&rsp);
39393936
}
39403937

3941-
void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan)
3938+
static void l2cap_ecred_list_defer(struct l2cap_chan *chan, void *data)
39423939
{
3940+
int *result = data;
3941+
3942+
if (*result || test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
3943+
return;
3944+
3945+
switch (chan->state) {
3946+
case BT_CONNECT2:
3947+
/* If channel still pending accept add to result */
3948+
(*result)++;
3949+
return;
3950+
case BT_CONNECTED:
3951+
return;
3952+
default:
3953+
/* If not connected or pending accept it has been refused */
3954+
*result = -ECONNREFUSED;
3955+
return;
3956+
}
3957+
}
3958+
3959+
struct l2cap_ecred_rsp_data {
39433960
struct {
39443961
struct l2cap_ecred_conn_rsp rsp;
3945-
__le16 dcid[5];
3962+
__le16 scid[L2CAP_ECRED_MAX_CID];
39463963
} __packed pdu;
3964+
int count;
3965+
};
3966+
3967+
static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
3968+
{
3969+
struct l2cap_ecred_rsp_data *rsp = data;
3970+
3971+
if (test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
3972+
return;
3973+
3974+
/* Reset ident so only one response is sent */
3975+
chan->ident = 0;
3976+
3977+
/* Include all channels pending with the same ident */
3978+
if (!rsp->pdu.rsp.result)
3979+
rsp->pdu.rsp.dcid[rsp->count++] = cpu_to_le16(chan->scid);
3980+
else
3981+
l2cap_chan_del(chan, ECONNRESET);
3982+
}
3983+
3984+
void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan)
3985+
{
39473986
struct l2cap_conn *conn = chan->conn;
3948-
u16 ident = chan->ident;
3949-
int i = 0;
3987+
struct l2cap_ecred_rsp_data data;
3988+
u16 id = chan->ident;
3989+
int result = 0;
39503990

3951-
if (!ident)
3991+
if (!id)
39523992
return;
39533993

3954-
BT_DBG("chan %p ident %d", chan, ident);
3994+
BT_DBG("chan %p id %d", chan, id);
39553995

3956-
pdu.rsp.mtu = cpu_to_le16(chan->imtu);
3957-
pdu.rsp.mps = cpu_to_le16(chan->mps);
3958-
pdu.rsp.credits = cpu_to_le16(chan->rx_credits);
3959-
pdu.rsp.result = cpu_to_le16(L2CAP_CR_LE_SUCCESS);
3996+
memset(&data, 0, sizeof(data));
39603997

3961-
mutex_lock(&conn->chan_lock);
3998+
data.pdu.rsp.mtu = cpu_to_le16(chan->imtu);
3999+
data.pdu.rsp.mps = cpu_to_le16(chan->mps);
4000+
data.pdu.rsp.credits = cpu_to_le16(chan->rx_credits);
4001+
data.pdu.rsp.result = cpu_to_le16(L2CAP_CR_LE_SUCCESS);
39624002

3963-
list_for_each_entry(chan, &conn->chan_l, list) {
3964-
if (chan->ident != ident)
3965-
continue;
4003+
/* Verify that all channels are ready */
4004+
__l2cap_chan_list_id(conn, id, l2cap_ecred_list_defer, &result);
39664005

3967-
/* Reset ident so only one response is sent */
3968-
chan->ident = 0;
4006+
if (result > 0)
4007+
return;
39694008

3970-
/* Include all channels pending with the same ident */
3971-
pdu.dcid[i++] = cpu_to_le16(chan->scid);
3972-
}
4009+
if (result < 0)
4010+
data.pdu.rsp.result = cpu_to_le16(L2CAP_CR_LE_AUTHORIZATION);
39734011

3974-
mutex_unlock(&conn->chan_lock);
4012+
/* Build response */
4013+
__l2cap_chan_list_id(conn, id, l2cap_ecred_rsp_defer, &data);
39754014

3976-
l2cap_send_cmd(conn, ident, L2CAP_ECRED_CONN_RSP,
3977-
sizeof(pdu.rsp) + i * sizeof(__le16), &pdu);
4015+
l2cap_send_cmd(conn, id, L2CAP_ECRED_CONN_RSP,
4016+
sizeof(data.pdu.rsp) + (data.count * sizeof(__le16)),
4017+
&data.pdu);
39784018
}
39794019

39804020
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
@@ -6078,6 +6118,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
60786118
__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
60796119

60806120
chan->ident = cmd->ident;
6121+
chan->mode = L2CAP_MODE_EXT_FLOWCTL;
60816122

60826123
if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
60836124
l2cap_state_change(chan, BT_CONNECT2);

0 commit comments

Comments
 (0)