From 5c0a502e9fdd316c79d26c5d6f40ccd7e9532b85 Mon Sep 17 00:00:00 2001 From: Arkadiusz Lichwa Date: Thu, 8 Dec 2016 20:24:13 +0100 Subject: [PATCH] Bluetooth: L2CAP: Fix uninitialized pointer When PSM server doesn't have BR/EDR L2CAP resources to assign and handle incoming request properly, local channel pointer may stay uninitialized. This fixes such scenario. The fix refactors main connection request reply handler to additional helper which can be used to send response unconditionally for situation when local channel is not allocated to setup L2CAP link between. Jira: ZEP-1405 Change-Id: I5caedd63a59ad0d1704ac87fa51616a0770320bf Signed-off-by: Arkadiusz Lichwa --- subsys/bluetooth/host/l2cap_br.c | 42 +++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/subsys/bluetooth/host/l2cap_br.c b/subsys/bluetooth/host/l2cap_br.c index 788822066b8..7cecfb58f95 100644 --- a/subsys/bluetooth/host/l2cap_br.c +++ b/subsys/bluetooth/host/l2cap_br.c @@ -690,17 +690,13 @@ l2cap_br_conn_security(struct bt_l2cap_chan *chan, const uint16_t psm) return L2CAP_CONN_SECURITY_REJECT; } -static int l2cap_br_conn_req_reply(struct bt_l2cap_chan *chan, uint16_t result) +static int l2cap_br_send_conn_rsp(struct bt_conn *conn, uint16_t scid, + uint16_t dcid, uint8_t ident, uint16_t result) { struct net_buf *buf; struct bt_l2cap_conn_rsp *rsp; struct bt_l2cap_sig_hdr *hdr; - if (!atomic_test_bit(BR_CHAN(chan)->flags, L2CAP_FLAG_CONN_ACCEPTOR)) { - return -ESRCH; - } - - /* Send response to connection request only when in acceptor role */ buf = bt_l2cap_create_pdu(&br_sig, 0); if (!buf) { BT_ERR("No buffers for PDU"); @@ -709,12 +705,12 @@ static int l2cap_br_conn_req_reply(struct bt_l2cap_chan *chan, uint16_t result) hdr = net_buf_add(buf, sizeof(*hdr)); hdr->code = BT_L2CAP_CONN_RSP; - hdr->ident = chan->ident; + hdr->ident = ident; hdr->len = sys_cpu_to_le16(sizeof(*rsp)); rsp = net_buf_add(buf, sizeof(*rsp)); - rsp->dcid = sys_cpu_to_le16(BR_CHAN(chan)->rx.cid); - rsp->scid = sys_cpu_to_le16(BR_CHAN(chan)->tx.cid); + rsp->dcid = sys_cpu_to_le16(dcid); + rsp->scid = sys_cpu_to_le16(scid); rsp->result = sys_cpu_to_le16(result); if (result == BT_L2CAP_BR_PENDING) { @@ -723,12 +719,28 @@ static int l2cap_br_conn_req_reply(struct bt_l2cap_chan *chan, uint16_t result) rsp->status = sys_cpu_to_le16(BT_L2CAP_CS_NO_INFO); } - bt_l2cap_send(chan->conn, BT_L2CAP_CID_BR_SIG, buf); - chan->ident = 0; + bt_l2cap_send(conn, BT_L2CAP_CID_BR_SIG, buf); return 0; } +static int l2cap_br_conn_req_reply(struct bt_l2cap_chan *chan, uint16_t result) +{ + int err; + + /* Send response to connection request only when in acceptor role */ + if (!atomic_test_bit(BR_CHAN(chan)->flags, L2CAP_FLAG_CONN_ACCEPTOR)) { + return -ESRCH; + } + + err = l2cap_br_send_conn_rsp(chan->conn, BR_CHAN(chan)->tx.cid, + BR_CHAN(chan)->rx.cid, chan->ident, + result); + chan->ident = 0; + + return err; +} + static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident, struct net_buf *buf) { @@ -779,11 +791,13 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident, /* * Request server to accept the new connection and allocate the - * channel. + * channel. If no free channels available for PSM server reply with + * proper result and quit since chan pointer is uninitialized then. */ if (server->accept(conn, &chan) < 0) { - result = BT_L2CAP_BR_ERR_NO_RESOURCES; - goto done; + l2cap_br_send_conn_rsp(conn, scid, dcid, ident, + BT_L2CAP_BR_ERR_NO_RESOURCES); + return; } chan->required_sec_level = server->sec_level;