Bluetooth: L2CAP: Introduce security requirements on CoC

Applies on L2CAP channel object security requirement member and
implements on BR/EDR transport basic security cases during incoming
CoC connection request. Since channel security requirements can involve
sending 2 separate connection responses with proper results depending on
context path, there's a need to store L2CAP signaling identifier set in
original connection request to be restored later to help match proper
response context.

Change-Id: Ibac9a5d2443f2975637e1bd15f61afcad53f843b
Signed-off-by: Arkadiusz Lichwa <arkadiusz.lichwa@tieto.com>
This commit is contained in:
Arkadiusz Lichwa 2016-07-08 16:30:31 +02:00 committed by Johan Hedberg
commit 96e68fe654
3 changed files with 49 additions and 8 deletions

View file

@ -86,6 +86,7 @@ struct bt_l2cap_chan {
bt_l2cap_chan_state_t state;
/** Helps match request context during CoC */
uint8_t ident;
bt_security_t required_sec_level;
#endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */
};

View file

@ -502,6 +502,37 @@ static void l2cap_br_conf(struct bt_l2cap_chan *chan)
bt_l2cap_send(conn, BT_L2CAP_CID_BR_SIG, buf);
}
static bool l2cap_br_security_check(struct bt_l2cap_chan *chan,
const uint16_t psm)
{
int check;
if (psm == L2CAP_BR_PSM_SDP) {
return false;
};
/* No link key needed and legacy devices */
if (chan->required_sec_level == BT_SECURITY_LOW &&
!lmp_ssp_host_supported(chan->conn)) {
return false;
}
check = bt_conn_security(chan->conn, chan->required_sec_level);
/*
* Get case when connection security level already covers channel
* demands and bt_conn_security returns 0 and differentiate it to
* the case when HCI authentication request in internal subcall was send
* and bt_conn_security returns as well 0.
*/
if (check == 0 &&
chan->conn->sec_level >= chan->required_sec_level) {
return false;
}
return (check == 0) ? true : false;
}
static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
struct net_buf *buf)
{
@ -511,7 +542,7 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
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;
uint16_t psm, scid, dcid, result, status = BT_L2CAP_CS_NO_INFO;
if (buf->len < sizeof(*req)) {
BT_ERR("Too small L2CAP conn req packet size");
@ -579,17 +610,21 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
dcid = BR_CHAN(chan)->rx.cid;
l2cap_br_state_set(chan, BT_L2CAP_CONNECT);
/*
* TODO: Verify security level on link if this PSM channel requires
* higher security.
*/
result = BT_L2CAP_SUCCESS;
if (l2cap_br_security_check(chan, psm)) {
result = BT_L2CAP_PENDING;
status = BT_L2CAP_CS_AUTHEN_PEND;
/* store ident for connection response after GAP done */
chan->ident = ident;
/* TODO: auth timeout */
} else {
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 */
rsp->status = sys_cpu_to_le16(status);
bt_l2cap_send(conn, BT_L2CAP_CID_BR_SIG, buf);
/* Disconnect link when security rules were violated */

View file

@ -61,6 +61,10 @@ struct bt_l2cap_conn_req {
uint16_t scid;
} __packed;
/* command statuses in reposnse */
#define BT_L2CAP_CS_NO_INFO 0x0000
#define BT_L2CAP_CS_AUTHEN_PEND 0x0001
#define BT_L2CAP_CONN_RSP 0x03
struct bt_l2cap_conn_rsp {
uint16_t dcid;
@ -157,6 +161,7 @@ struct bt_l2cap_le_conn_req {
} __packed;
#define BT_L2CAP_SUCCESS 0x0000
#define BT_L2CAP_PENDING 0x0001
#define BT_L2CAP_ERR_PSM_NOT_SUPP 0x0002
#define BT_L2CAP_ERR_SEC_BLOCK 0x0003
#define BT_L2CAP_ERR_NO_RESOURCES 0x0004