Commit f1496dee authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann

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: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent ee5ec5cf
...@@ -1160,21 +1160,51 @@ static void l2cap_chan_ready(struct l2cap_chan *chan) ...@@ -1160,21 +1160,51 @@ static void l2cap_chan_ready(struct l2cap_chan *chan)
chan->ops->ready(chan); chan->ops->ready(chan);
} }
static void l2cap_le_connect(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
struct l2cap_le_conn_req req;
req.psm = chan->psm;
req.scid = cpu_to_le16(chan->scid);
req.mtu = cpu_to_le16(chan->imtu);
req.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
req.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS);
chan->ident = l2cap_get_ident(conn);
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_REQ,
sizeof(req), &req);
}
static void l2cap_le_start(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
if (!smp_conn_security(conn->hcon, chan->sec_level))
return;
if (!chan->psm) {
l2cap_chan_ready(chan);
return;
}
if (chan->state == BT_CONNECT)
l2cap_le_connect(chan);
}
static void l2cap_start_connection(struct l2cap_chan *chan) static void l2cap_start_connection(struct l2cap_chan *chan)
{ {
if (__amp_capable(chan)) { if (__amp_capable(chan)) {
BT_DBG("chan %p AMP capable: discover AMPs", chan); BT_DBG("chan %p AMP capable: discover AMPs", chan);
a2mp_discover_amp(chan); a2mp_discover_amp(chan);
} else if (chan->conn->hcon->type == LE_LINK) {
l2cap_le_start(chan);
} else { } else {
l2cap_send_conn_req(chan); l2cap_send_conn_req(chan);
} }
} }
static void l2cap_le_start(struct l2cap_chan *chan)
{
l2cap_chan_ready(chan);
}
static void l2cap_do_start(struct l2cap_chan *chan) static void l2cap_do_start(struct l2cap_chan *chan)
{ {
struct l2cap_conn *conn = chan->conn; struct l2cap_conn *conn = chan->conn;
...@@ -1438,9 +1468,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) ...@@ -1438,9 +1468,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
} }
if (hcon->type == LE_LINK) { if (hcon->type == LE_LINK) {
if (smp_conn_security(hcon, chan->sec_level)) l2cap_le_start(chan);
l2cap_chan_ready(chan);
} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
l2cap_chan_ready(chan); l2cap_chan_ready(chan);
...@@ -5210,6 +5238,64 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, ...@@ -5210,6 +5238,64 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
return 0; return 0;
} }
static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
{
struct l2cap_le_conn_rsp *rsp = (struct l2cap_le_conn_rsp *) data;
u16 dcid, mtu, mps, credits, result;
struct l2cap_chan *chan;
int err;
if (cmd_len < sizeof(*rsp))
return -EPROTO;
dcid = __le16_to_cpu(rsp->dcid);
mtu = __le16_to_cpu(rsp->mtu);
mps = __le16_to_cpu(rsp->mps);
credits = __le16_to_cpu(rsp->credits);
result = __le16_to_cpu(rsp->result);
if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23))
return -EPROTO;
BT_DBG("dcid 0x%4.4x mtu %u mps %u credits %u result 0x%2.2x",
dcid, mtu, mps, credits, result);
mutex_lock(&conn->chan_lock);
chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
if (!chan) {
err = -EBADSLT;
goto unlock;
}
err = 0;
l2cap_chan_lock(chan);
switch (result) {
case L2CAP_CR_SUCCESS:
chan->ident = 0;
chan->dcid = dcid;
chan->omtu = mtu;
chan->remote_mps = mps;
l2cap_chan_ready(chan);
break;
default:
l2cap_chan_del(chan, ECONNREFUSED);
break;
}
l2cap_chan_unlock(chan);
unlock:
mutex_unlock(&conn->chan_lock);
return err;
}
static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len, struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data) u8 *data)
...@@ -5304,6 +5390,10 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, ...@@ -5304,6 +5390,10 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
case L2CAP_CONN_PARAM_UPDATE_RSP: case L2CAP_CONN_PARAM_UPDATE_RSP:
return 0; return 0;
case L2CAP_LE_CONN_RSP:
l2cap_le_connect_rsp(conn, cmd, cmd_len, data);
return 0;
default: default:
BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code); BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
return -EINVAL; return -EINVAL;
......
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