Skip to content

Commit f1496de

Browse files
Johan Hedbergholtmann
authored andcommitted
Bluetooth: Add initial code for LE L2CAP Connect Request
This patch adds the necessary code to send an LE L2CAP Connect Request and handle its response when user space has provided us with an LE socket with a PSM instead of a fixed CID. Signed-off-by: Johan Hedberg <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent ee5ec5c commit f1496de

File tree

1 file changed

+98
-8
lines changed

1 file changed

+98
-8
lines changed

net/bluetooth/l2cap_core.c

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,21 +1160,51 @@ static void l2cap_chan_ready(struct l2cap_chan *chan)
11601160
chan->ops->ready(chan);
11611161
}
11621162

1163+
static void l2cap_le_connect(struct l2cap_chan *chan)
1164+
{
1165+
struct l2cap_conn *conn = chan->conn;
1166+
struct l2cap_le_conn_req req;
1167+
1168+
req.psm = chan->psm;
1169+
req.scid = cpu_to_le16(chan->scid);
1170+
req.mtu = cpu_to_le16(chan->imtu);
1171+
req.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
1172+
req.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS);
1173+
1174+
chan->ident = l2cap_get_ident(conn);
1175+
1176+
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_REQ,
1177+
sizeof(req), &req);
1178+
}
1179+
1180+
static void l2cap_le_start(struct l2cap_chan *chan)
1181+
{
1182+
struct l2cap_conn *conn = chan->conn;
1183+
1184+
if (!smp_conn_security(conn->hcon, chan->sec_level))
1185+
return;
1186+
1187+
if (!chan->psm) {
1188+
l2cap_chan_ready(chan);
1189+
return;
1190+
}
1191+
1192+
if (chan->state == BT_CONNECT)
1193+
l2cap_le_connect(chan);
1194+
}
1195+
11631196
static void l2cap_start_connection(struct l2cap_chan *chan)
11641197
{
11651198
if (__amp_capable(chan)) {
11661199
BT_DBG("chan %p AMP capable: discover AMPs", chan);
11671200
a2mp_discover_amp(chan);
1201+
} else if (chan->conn->hcon->type == LE_LINK) {
1202+
l2cap_le_start(chan);
11681203
} else {
11691204
l2cap_send_conn_req(chan);
11701205
}
11711206
}
11721207

1173-
static void l2cap_le_start(struct l2cap_chan *chan)
1174-
{
1175-
l2cap_chan_ready(chan);
1176-
}
1177-
11781208
static void l2cap_do_start(struct l2cap_chan *chan)
11791209
{
11801210
struct l2cap_conn *conn = chan->conn;
@@ -1438,9 +1468,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
14381468
}
14391469

14401470
if (hcon->type == LE_LINK) {
1441-
if (smp_conn_security(hcon, chan->sec_level))
1442-
l2cap_chan_ready(chan);
1443-
1471+
l2cap_le_start(chan);
14441472
} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
14451473
l2cap_chan_ready(chan);
14461474

@@ -5210,6 +5238,64 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
52105238
return 0;
52115239
}
52125240

5241+
static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
5242+
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
5243+
u8 *data)
5244+
{
5245+
struct l2cap_le_conn_rsp *rsp = (struct l2cap_le_conn_rsp *) data;
5246+
u16 dcid, mtu, mps, credits, result;
5247+
struct l2cap_chan *chan;
5248+
int err;
5249+
5250+
if (cmd_len < sizeof(*rsp))
5251+
return -EPROTO;
5252+
5253+
dcid = __le16_to_cpu(rsp->dcid);
5254+
mtu = __le16_to_cpu(rsp->mtu);
5255+
mps = __le16_to_cpu(rsp->mps);
5256+
credits = __le16_to_cpu(rsp->credits);
5257+
result = __le16_to_cpu(rsp->result);
5258+
5259+
if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23))
5260+
return -EPROTO;
5261+
5262+
BT_DBG("dcid 0x%4.4x mtu %u mps %u credits %u result 0x%2.2x",
5263+
dcid, mtu, mps, credits, result);
5264+
5265+
mutex_lock(&conn->chan_lock);
5266+
5267+
chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
5268+
if (!chan) {
5269+
err = -EBADSLT;
5270+
goto unlock;
5271+
}
5272+
5273+
err = 0;
5274+
5275+
l2cap_chan_lock(chan);
5276+
5277+
switch (result) {
5278+
case L2CAP_CR_SUCCESS:
5279+
chan->ident = 0;
5280+
chan->dcid = dcid;
5281+
chan->omtu = mtu;
5282+
chan->remote_mps = mps;
5283+
l2cap_chan_ready(chan);
5284+
break;
5285+
5286+
default:
5287+
l2cap_chan_del(chan, ECONNREFUSED);
5288+
break;
5289+
}
5290+
5291+
l2cap_chan_unlock(chan);
5292+
5293+
unlock:
5294+
mutex_unlock(&conn->chan_lock);
5295+
5296+
return err;
5297+
}
5298+
52135299
static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
52145300
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
52155301
u8 *data)
@@ -5304,6 +5390,10 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
53045390
case L2CAP_CONN_PARAM_UPDATE_RSP:
53055391
return 0;
53065392

5393+
case L2CAP_LE_CONN_RSP:
5394+
l2cap_le_connect_rsp(conn, cmd, cmd_len, data);
5395+
return 0;
5396+
53075397
default:
53085398
BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
53095399
return -EINVAL;

0 commit comments

Comments
 (0)