Skip to content

Commit 27e2d4c

Browse files
Johan Hedbergholtmann
authored andcommitted
Bluetooth: Add basic LE L2CAP connect request receiving support
This patch adds the necessary boiler plate code to handle receiving L2CAP connect requests over LE and respond to them with a proper connect response. Signed-off-by: Johan Hedberg <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent 791d60f commit 27e2d4c

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

include/net/bluetooth/l2cap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,7 @@ int l2cap_init_sockets(void);
846846
void l2cap_cleanup_sockets(void);
847847
bool l2cap_is_socket(struct socket *sock);
848848

849+
void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan);
849850
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
850851

851852
int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);

net/bluetooth/l2cap_core.c

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,29 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
617617
return;
618618
}
619619

620+
static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
621+
{
622+
struct l2cap_conn *conn = chan->conn;
623+
struct l2cap_le_conn_rsp rsp;
624+
u16 result;
625+
626+
if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
627+
result = L2CAP_CR_AUTHORIZATION;
628+
else
629+
result = L2CAP_CR_BAD_PSM;
630+
631+
l2cap_state_change(chan, BT_DISCONN);
632+
633+
rsp.dcid = cpu_to_le16(chan->scid);
634+
rsp.mtu = cpu_to_le16(chan->imtu);
635+
rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
636+
rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS);
637+
rsp.result = cpu_to_le16(result);
638+
639+
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
640+
&rsp);
641+
}
642+
620643
static void l2cap_chan_connect_reject(struct l2cap_chan *chan)
621644
{
622645
struct l2cap_conn *conn = chan->conn;
@@ -663,6 +686,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
663686
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
664687
if (conn->hcon->type == ACL_LINK)
665688
l2cap_chan_connect_reject(chan);
689+
else if (conn->hcon->type == LE_LINK)
690+
l2cap_chan_le_connect_reject(chan);
666691
}
667692

668693
l2cap_chan_del(chan, reason);
@@ -3641,6 +3666,23 @@ static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data,
36413666
return ptr - data;
36423667
}
36433668

3669+
void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan)
3670+
{
3671+
struct l2cap_le_conn_rsp rsp;
3672+
struct l2cap_conn *conn = chan->conn;
3673+
3674+
BT_DBG("chan %p", chan);
3675+
3676+
rsp.dcid = cpu_to_le16(chan->scid);
3677+
rsp.mtu = cpu_to_le16(chan->imtu);
3678+
rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
3679+
rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS);
3680+
rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
3681+
3682+
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
3683+
&rsp);
3684+
}
3685+
36443686
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
36453687
{
36463688
struct l2cap_conn_rsp rsp;
@@ -5382,6 +5424,113 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
53825424
return err;
53835425
}
53845426

5427+
static int l2cap_le_connect_req(struct l2cap_conn *conn,
5428+
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
5429+
u8 *data)
5430+
{
5431+
struct l2cap_le_conn_req *req = (struct l2cap_le_conn_req *) data;
5432+
struct l2cap_le_conn_rsp rsp;
5433+
struct l2cap_chan *chan, *pchan;
5434+
u16 dcid, scid, mtu, mps;
5435+
__le16 psm;
5436+
u8 result;
5437+
5438+
if (cmd_len != sizeof(*req))
5439+
return -EPROTO;
5440+
5441+
scid = __le16_to_cpu(req->scid);
5442+
mtu = __le16_to_cpu(req->mtu);
5443+
mps = __le16_to_cpu(req->mps);
5444+
psm = req->psm;
5445+
dcid = 0;
5446+
5447+
if (mtu < 23 || mps < 23)
5448+
return -EPROTO;
5449+
5450+
BT_DBG("psm 0x%2.2x scid 0x%4.4x mtu %u mps %u", __le16_to_cpu(psm),
5451+
scid, mtu, mps);
5452+
5453+
/* Check if we have socket listening on psm */
5454+
pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
5455+
&conn->hcon->dst, LE_LINK);
5456+
if (!pchan) {
5457+
result = L2CAP_CR_BAD_PSM;
5458+
chan = NULL;
5459+
goto response;
5460+
}
5461+
5462+
mutex_lock(&conn->chan_lock);
5463+
l2cap_chan_lock(pchan);
5464+
5465+
if (!smp_sufficient_security(conn->hcon, pchan->sec_level)) {
5466+
result = L2CAP_CR_AUTHENTICATION;
5467+
chan = NULL;
5468+
goto response_unlock;
5469+
}
5470+
5471+
/* Check if we already have channel with that dcid */
5472+
if (__l2cap_get_chan_by_dcid(conn, scid)) {
5473+
result = L2CAP_CR_NO_MEM;
5474+
chan = NULL;
5475+
goto response_unlock;
5476+
}
5477+
5478+
chan = pchan->ops->new_connection(pchan);
5479+
if (!chan) {
5480+
result = L2CAP_CR_NO_MEM;
5481+
goto response_unlock;
5482+
}
5483+
5484+
bacpy(&chan->src, &conn->hcon->src);
5485+
bacpy(&chan->dst, &conn->hcon->dst);
5486+
chan->src_type = bdaddr_type(conn->hcon, conn->hcon->src_type);
5487+
chan->dst_type = bdaddr_type(conn->hcon, conn->hcon->dst_type);
5488+
chan->psm = psm;
5489+
chan->dcid = scid;
5490+
chan->omtu = mtu;
5491+
chan->remote_mps = mps;
5492+
5493+
__l2cap_chan_add(conn, chan);
5494+
dcid = chan->scid;
5495+
5496+
__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
5497+
5498+
chan->ident = cmd->ident;
5499+
5500+
if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
5501+
l2cap_state_change(chan, BT_CONNECT2);
5502+
result = L2CAP_CR_PEND;
5503+
chan->ops->defer(chan);
5504+
} else {
5505+
l2cap_chan_ready(chan);
5506+
result = L2CAP_CR_SUCCESS;
5507+
}
5508+
5509+
response_unlock:
5510+
l2cap_chan_unlock(pchan);
5511+
mutex_unlock(&conn->chan_lock);
5512+
5513+
if (result == L2CAP_CR_PEND)
5514+
return 0;
5515+
5516+
response:
5517+
if (chan) {
5518+
rsp.mtu = cpu_to_le16(chan->imtu);
5519+
rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
5520+
} else {
5521+
rsp.mtu = 0;
5522+
rsp.mps = 0;
5523+
}
5524+
5525+
rsp.dcid = cpu_to_le16(dcid);
5526+
rsp.credits = __constant_cpu_to_le16(L2CAP_LE_MAX_CREDITS);
5527+
rsp.result = cpu_to_le16(result);
5528+
5529+
l2cap_send_cmd(conn, cmd->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), &rsp);
5530+
5531+
return 0;
5532+
}
5533+
53855534
static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
53865535
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
53875536
u8 *data)
@@ -5400,6 +5549,9 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
54005549
l2cap_le_connect_rsp(conn, cmd, cmd_len, data);
54015550
return 0;
54025551

5552+
case L2CAP_LE_CONN_REQ:
5553+
return l2cap_le_connect_req(conn, cmd, cmd_len, data);
5554+
54035555
default:
54045556
BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
54055557
return -EINVAL;

0 commit comments

Comments
 (0)