Bluetooth: L2CAP: Handle incoming BR/EDR connection request
Enables L2CAP protocol definitions for connection request/response and use it then to start handle incoming PSM connection request to valid registered local PSM server. SDP PSM got no security restrictions. The other PSM connections are validated against link encryption and availability of SSP feature and if not matched are refused with security error. Change-Id: I429cf5dbce92300bd52639d5065e0144f8db4d13 Signed-off-by: Arkadiusz Lichwa <arkadiusz.lichwa@tieto.com>
This commit is contained in:
parent
eeb2b733e4
commit
8b1c837e28
4 changed files with 138 additions and 0 deletions
|
@ -126,6 +126,9 @@ struct bt_hci_cmd_hdr {
|
||||||
#define BT_LMP_LE 0x40
|
#define BT_LMP_LE 0x40
|
||||||
#define BT_LMP_REMOTE_EXT_FEATURES 0x80
|
#define BT_LMP_REMOTE_EXT_FEATURES 0x80
|
||||||
|
|
||||||
|
/* Host features */
|
||||||
|
#define BT_LMP_HOST_SSP 0x01
|
||||||
|
|
||||||
/* LE features */
|
/* LE features */
|
||||||
#define BT_HCI_LE_ENCRYPTION 0x01
|
#define BT_HCI_LE_ENCRYPTION 0x01
|
||||||
#define BT_HCI_LE_CONN_PARAM_REQ_PROC 0x02
|
#define BT_HCI_LE_CONN_PARAM_REQ_PROC 0x02
|
||||||
|
|
|
@ -64,6 +64,10 @@ struct bt_conn_le {
|
||||||
#define lmp_ext_feat_capable(conn) \
|
#define lmp_ext_feat_capable(conn) \
|
||||||
((conn)->br.features[0][7] & BT_LMP_REMOTE_EXT_FEATURES)
|
((conn)->br.features[0][7] & BT_LMP_REMOTE_EXT_FEATURES)
|
||||||
|
|
||||||
|
/* Helper to validate SSP host support within retrieved remote LMP features */
|
||||||
|
#define lmp_ssp_host_supported(conn) \
|
||||||
|
((conn)->br.features[1][0] & BT_LMP_HOST_SSP)
|
||||||
|
|
||||||
struct bt_conn_br {
|
struct bt_conn_br {
|
||||||
bt_addr_t dst;
|
bt_addr_t dst;
|
||||||
uint8_t remote_io_capa;
|
uint8_t remote_io_capa;
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
|
|
||||||
#define L2CAP_BR_MIN_MTU 48
|
#define L2CAP_BR_MIN_MTU 48
|
||||||
|
|
||||||
|
#define L2CAP_BR_PSM_SDP 0x0001
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* L2CAP extended feature mask:
|
* L2CAP extended feature mask:
|
||||||
* BR/EDR fixed channel support enabled
|
* BR/EDR fixed channel support enabled
|
||||||
|
@ -99,6 +101,22 @@ struct bt_l2cap_chan *bt_l2cap_br_lookup_rx_cid(struct bt_conn *conn,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct bt_l2cap_chan *bt_l2cap_br_lookup_tx_cid(struct bt_conn *conn,
|
||||||
|
uint16_t cid)
|
||||||
|
{
|
||||||
|
struct bt_l2cap_chan *chan;
|
||||||
|
|
||||||
|
for (chan = conn->channels; chan; chan = chan->_next) {
|
||||||
|
struct bt_l2cap_br_chan *ch = BR_CHAN(chan);
|
||||||
|
|
||||||
|
if (ch->tx.cid == cid) {
|
||||||
|
return chan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static struct bt_l2cap_br_chan*
|
static struct bt_l2cap_br_chan*
|
||||||
l2cap_br_chan_alloc_cid(struct bt_conn *conn, struct bt_l2cap_chan *chan)
|
l2cap_br_chan_alloc_cid(struct bt_conn *conn, struct bt_l2cap_chan *chan)
|
||||||
{
|
{
|
||||||
|
@ -367,6 +385,101 @@ static struct bt_l2cap_server *l2cap_br_server_lookup_psm(uint16_t psm)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
|
||||||
|
struct net_buf *buf)
|
||||||
|
{
|
||||||
|
struct bt_conn *conn = l2cap->chan.chan.conn;
|
||||||
|
struct bt_l2cap_chan *chan;
|
||||||
|
struct bt_l2cap_server *server;
|
||||||
|
struct bt_l2cap_conn_req *req = (void *)buf->data;
|
||||||
|
struct bt_l2cap_conn_rsp *rsp;
|
||||||
|
struct bt_l2cap_sig_hdr *hdr;
|
||||||
|
uint16_t psm, scid, dcid, result;
|
||||||
|
|
||||||
|
if (buf->len < sizeof(*req)) {
|
||||||
|
BT_ERR("Too small L2CAP conn req packet size");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
psm = sys_le16_to_cpu(req->psm);
|
||||||
|
scid = sys_le16_to_cpu(req->scid);
|
||||||
|
dcid = 0;
|
||||||
|
|
||||||
|
BT_DBG("psm 0x%02x scid 0x%04x", psm, scid);
|
||||||
|
|
||||||
|
buf = bt_l2cap_create_pdu(&br_sig);
|
||||||
|
if (!buf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr = net_buf_add(buf, sizeof(*hdr));
|
||||||
|
hdr->code = BT_L2CAP_CONN_RSP;
|
||||||
|
hdr->ident = ident;
|
||||||
|
hdr->len = sys_cpu_to_le16(sizeof(*rsp));
|
||||||
|
|
||||||
|
rsp = net_buf_add(buf, sizeof(*rsp));
|
||||||
|
memset(rsp, 0, sizeof(*rsp));
|
||||||
|
|
||||||
|
/* Check if there is a server registered */
|
||||||
|
server = l2cap_br_server_lookup_psm(psm);
|
||||||
|
if (!server) {
|
||||||
|
result = BT_L2CAP_ERR_PSM_NOT_SUPP;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Report security violation for non SDP channel without encryption when
|
||||||
|
* remote supports SSP.
|
||||||
|
*/
|
||||||
|
if (psm != L2CAP_BR_PSM_SDP && lmp_ssp_host_supported(conn) &&
|
||||||
|
!conn->encrypt) {
|
||||||
|
result = BT_L2CAP_ERR_SEC_BLOCK;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scid < L2CAP_BR_DYN_CID_START || scid > L2CAP_BR_DYN_CID_END) {
|
||||||
|
result = BT_L2CAP_ERR_INVALID_SCID;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
chan = bt_l2cap_br_lookup_tx_cid(conn, scid);
|
||||||
|
if (chan) {
|
||||||
|
result = BT_L2CAP_ERR_SCID_IN_USE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request server to accept the new connection and allocate the
|
||||||
|
* channel.
|
||||||
|
*/
|
||||||
|
if (server->accept(conn, &chan) < 0) {
|
||||||
|
result = BT_L2CAP_ERR_NO_RESOURCES;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
l2cap_br_chan_add(conn, chan);
|
||||||
|
BR_CHAN(chan)->tx.cid = scid;
|
||||||
|
dcid = BR_CHAN(chan)->rx.cid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Verify security level on link if this PSM channel requires
|
||||||
|
* higher security.
|
||||||
|
*/
|
||||||
|
|
||||||
|
result = BT_L2CAP_SUCCESS;
|
||||||
|
done:
|
||||||
|
rsp->dcid = sys_cpu_to_le16(dcid);
|
||||||
|
rsp->scid = req->scid;
|
||||||
|
rsp->result = sys_cpu_to_le16(result);
|
||||||
|
/* TODO: add command timeout guard */
|
||||||
|
bt_l2cap_send(conn, BT_L2CAP_CID_BR_SIG, buf);
|
||||||
|
|
||||||
|
/* Disconnect link when security rules were violated */
|
||||||
|
if (result == BT_L2CAP_ERR_SEC_BLOCK) {
|
||||||
|
bt_conn_disconnect(conn, BT_HCI_ERR_AUTHENTICATION_FAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int bt_l2cap_br_server_register(struct bt_l2cap_server *server)
|
int bt_l2cap_br_server_register(struct bt_l2cap_server *server)
|
||||||
{
|
{
|
||||||
if (server->psm < L2CAP_BR_PSM_START || !server->accept) {
|
if (server->psm < L2CAP_BR_PSM_START || !server->accept) {
|
||||||
|
@ -575,6 +688,9 @@ static void l2cap_br_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
|
||||||
case BT_L2CAP_DISCONN_REQ:
|
case BT_L2CAP_DISCONN_REQ:
|
||||||
l2cap_br_disconn_req(l2cap, hdr->ident, buf);
|
l2cap_br_disconn_req(l2cap, hdr->ident, buf);
|
||||||
break;
|
break;
|
||||||
|
case BT_L2CAP_CONN_REQ:
|
||||||
|
l2cap_br_conn_req(l2cap, hdr->ident, buf);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
BT_WARN("Unknown/Unsupported L2CAP PDU code 0x%02x", hdr->code);
|
BT_WARN("Unknown/Unsupported L2CAP PDU code 0x%02x", hdr->code);
|
||||||
l2cap_br_send_reject(chan->conn, hdr->ident,
|
l2cap_br_send_reject(chan->conn, hdr->ident,
|
||||||
|
|
|
@ -55,6 +55,20 @@ struct bt_l2cap_cmd_reject_cid_data {
|
||||||
uint16_t dcid;
|
uint16_t dcid;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
#define BT_L2CAP_CONN_REQ 0x02
|
||||||
|
struct bt_l2cap_conn_req {
|
||||||
|
uint16_t psm;
|
||||||
|
uint16_t scid;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define BT_L2CAP_CONN_RSP 0x03
|
||||||
|
struct bt_l2cap_conn_rsp {
|
||||||
|
uint16_t dcid;
|
||||||
|
uint16_t scid;
|
||||||
|
uint16_t result;
|
||||||
|
uint16_t status;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
#define BT_L2CAP_DISCONN_REQ 0x06
|
#define BT_L2CAP_DISCONN_REQ 0x06
|
||||||
struct bt_l2cap_disconn_req {
|
struct bt_l2cap_disconn_req {
|
||||||
uint16_t dcid;
|
uint16_t dcid;
|
||||||
|
@ -113,6 +127,7 @@ struct bt_l2cap_le_conn_req {
|
||||||
|
|
||||||
#define BT_L2CAP_SUCCESS 0x0000
|
#define BT_L2CAP_SUCCESS 0x0000
|
||||||
#define BT_L2CAP_ERR_PSM_NOT_SUPP 0x0002
|
#define BT_L2CAP_ERR_PSM_NOT_SUPP 0x0002
|
||||||
|
#define BT_L2CAP_ERR_SEC_BLOCK 0x0003
|
||||||
#define BT_L2CAP_ERR_NO_RESOURCES 0x0004
|
#define BT_L2CAP_ERR_NO_RESOURCES 0x0004
|
||||||
#define BT_L2CAP_ERR_AUTHENTICATION 0x0005
|
#define BT_L2CAP_ERR_AUTHENTICATION 0x0005
|
||||||
#define BT_L2CAP_ERR_AUTHORIZATION 0x0006
|
#define BT_L2CAP_ERR_AUTHORIZATION 0x0006
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue