Bluetooth: Refactor distribution of security procedure status

Layers (modules) above HCI like L2CAP need to know status of applied
security procedure when it's triggered on existing connection. It gives
them possibility to make action in layer specific context on
post-security-procedure conditions.

Change-Id: Ia10078469847b29bb7eb3b1fb376ac305dd0b0fc
Signed-off-by: Arkadiusz Lichwa <arkadiusz.lichwa@tieto.com>
This commit is contained in:
Arkadiusz Lichwa 2016-09-13 09:38:10 +02:00 committed by Johan Hedberg
parent a8de2de1f2
commit f30b3debc6
8 changed files with 68 additions and 27 deletions

View file

@ -176,11 +176,19 @@ struct bt_l2cap_chan_ops {
/** Channel encrypt_change callback
*
* If this callback is provided it will be called whenever the
* security level changed.
* security level changed (indirectly link encryption done) or
* authentication procedure fails. In both cases security initiator
* and responder got the final status (HCI status) passed by
* related to encryption and authentication events from local host's
* controller.
*
* @param chan The channel which has encryption status changed.
* @param chan The channel which has made encryption status changed.
* @param status HCI status of performed security procedure caused
* by channel security requirements. The value is populated
* by HCI layer and set to 0 when success and to non-zero (reference to
* HCI Error Codes) when security/authentication failed.
*/
void (*encrypt_change)(struct bt_l2cap_chan *chan);
void (*encrypt_change)(struct bt_l2cap_chan *chan, uint8_t hci_status);
/** Channel alloc_buf callback
*

View file

@ -1872,14 +1872,24 @@ static void bt_att_disconnected(struct bt_l2cap_chan *chan)
}
#if defined(CONFIG_BLUETOOTH_SMP)
static void bt_att_encrypt_change(struct bt_l2cap_chan *chan)
static void bt_att_encrypt_change(struct bt_l2cap_chan *chan,
uint8_t hci_status)
{
struct bt_att *att = ATT_CHAN(chan);
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
struct bt_conn *conn = ch->chan.conn;
BT_DBG("chan %p conn %p handle %u sec_level 0x%02x", ch, conn,
conn->handle, conn->sec_level);
BT_DBG("chan %p conn %p handle %u sec_level 0x%02x status 0x%02x", ch,
conn, conn->handle, conn->sec_level, hci_status);
/*
* If status (HCI status of security procedure) is non-zero, notify
* outstanding request about security failure.
*/
if (hci_status) {
att_handle_rsp(att, NULL, 0, BT_ATT_ERR_AUTHENTICATION);
return;
}
if (conn->sec_level == BT_SECURITY_LOW) {
return;

View file

@ -74,7 +74,7 @@ void bt_avdtp_l2cap_disconnected(struct bt_l2cap_chan *chan)
BT_DBG("chan %p session %p", chan, AVDTP_CHAN(chan));
}
void bt_avdtp_l2cap_encrypt_changed(struct bt_l2cap_chan *chan)
void bt_avdtp_l2cap_encrypt_changed(struct bt_l2cap_chan *chan, uint8_t status)
{
BT_DBG("");
}

View file

@ -1839,6 +1839,13 @@ static void auth_complete(struct net_buf *buf)
}
if (evt->status) {
if (conn->state == BT_CONN_CONNECTED) {
/*
* Inform layers above HCI about non-zero authentication
* status to make them able cleanup pending jobs.
*/
bt_l2cap_encrypt_change(conn, evt->status);
}
reset_pairing(conn);
} else {
link_encr(handle);
@ -1962,6 +1969,7 @@ static void hci_encrypt_change(struct net_buf *buf)
conn->required_sec_level = conn->sec_level;
#if defined(CONFIG_BLUETOOTH_BREDR)
} else {
bt_l2cap_encrypt_change(conn, evt->status);
reset_pairing(conn);
#endif /* CONFIG_BLUETOOTH_BREDR */
}
@ -1994,7 +2002,7 @@ static void hci_encrypt_change(struct net_buf *buf)
}
#endif /* CONFIG_BLUETOOTH_BREDR */
bt_l2cap_encrypt_change(conn);
bt_l2cap_encrypt_change(conn, evt->status);
bt_conn_security_changed(conn);
bt_conn_unref(conn);
@ -2010,16 +2018,17 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
BT_DBG("status %u handle %u", evt->status, handle);
if (evt->status) {
return;
}
conn = bt_conn_lookup_handle(handle);
if (!conn) {
BT_ERR("Unable to look up conn with handle %u", handle);
return;
}
if (evt->status) {
bt_l2cap_encrypt_change(conn, evt->status);
return;
}
/*
* Update keys with last pairing info for proper sec level update.
* This is done only for LE transport. For BR/EDR transport keys are
@ -2038,7 +2047,7 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
}
#endif /* CONFIG_BLUETOOTH_BREDR */
bt_l2cap_encrypt_change(conn);
bt_l2cap_encrypt_change(conn, evt->status);
bt_conn_security_changed(conn);
bt_conn_unref(conn);
}

View file

@ -321,20 +321,20 @@ void bt_l2cap_disconnected(struct bt_conn *conn)
conn->channels = NULL;
}
void bt_l2cap_encrypt_change(struct bt_conn *conn)
void bt_l2cap_encrypt_change(struct bt_conn *conn, uint8_t hci_status)
{
struct bt_l2cap_chan *chan;
#if defined(CONFIG_BLUETOOTH_BREDR)
if (conn->type == BT_CONN_TYPE_BR) {
l2cap_br_encrypt_change(conn);
l2cap_br_encrypt_change(conn, hci_status);
return;
}
#endif /* CONFIG_BLUETOOTH_BREDR */
for (chan = conn->channels; chan; chan = chan->_next) {
if (chan->ops->encrypt_change) {
chan->ops->encrypt_change(chan);
chan->ops->encrypt_change(chan, hci_status);
}
}
}

View file

@ -1489,7 +1489,7 @@ static void l2cap_br_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
}
}
static void l2cap_br_conn_pend(struct bt_l2cap_chan *chan)
static void l2cap_br_conn_pend(struct bt_l2cap_chan *chan, uint8_t status)
{
struct net_buf *buf;
struct bt_l2cap_conn_rsp *rsp;
@ -1500,6 +1500,9 @@ static void l2cap_br_conn_pend(struct bt_l2cap_chan *chan)
return;
}
BT_DBG("chan %p status 0x%02x encr 0x%02x", chan, status,
chan->conn->encrypt);
if (!chan->conn->encrypt) {
return;
}
@ -1558,15 +1561,15 @@ static void l2cap_br_conn_pend(struct bt_l2cap_chan *chan)
}
}
void l2cap_br_encrypt_change(struct bt_conn *conn)
void l2cap_br_encrypt_change(struct bt_conn *conn, uint8_t hci_status)
{
struct bt_l2cap_chan *chan;
for (chan = conn->channels; chan; chan = chan->_next) {
l2cap_br_conn_pend(chan);
l2cap_br_conn_pend(chan, hci_status);
if (chan->ops && chan->ops->encrypt_change) {
chan->ops->encrypt_change(chan);
chan->ops->encrypt_change(chan, hci_status);
}
}
}

View file

@ -221,8 +221,11 @@ void bt_l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
/* Delete channel */
void bt_l2cap_chan_del(struct bt_l2cap_chan *chan);
/* Notify L2CAP channels of a change in encryption state */
void bt_l2cap_encrypt_change(struct bt_conn *conn);
/*
* Notify L2CAP channels of a change in encryption state passing additionally
* HCI status of performed security procedure.
*/
void bt_l2cap_encrypt_change(struct bt_conn *conn, uint8_t hci_status);
/* Prepare an L2CAP PDU to be sent over a connection */
struct net_buf *bt_l2cap_create_pdu(struct nano_fifo *fifo, size_t reserve);
@ -272,6 +275,9 @@ int bt_l2cap_br_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,
/* Send packet data to connected peer */
int bt_l2cap_br_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf);
/* Handle security level changed on link */
void l2cap_br_encrypt_change(struct bt_conn *conn);
/*
* Handle security level changed on link passing HCI status of performed
* security procedure.
*/
void l2cap_br_encrypt_change(struct bt_conn *conn, uint8_t hci_status);
#endif /* CONFIG_BLUETOOTH_BREDR */

View file

@ -3434,13 +3434,18 @@ static void bt_smp_disconnected(struct bt_l2cap_chan *chan)
memset(smp, 0, sizeof(*smp));
}
static void bt_smp_encrypt_change(struct bt_l2cap_chan *chan)
static void bt_smp_encrypt_change(struct bt_l2cap_chan *chan,
uint8_t hci_status)
{
struct bt_smp *smp = CONTAINER_OF(chan, struct bt_smp, chan);
struct bt_conn *conn = chan->conn;
BT_DBG("chan %p conn %p handle %u encrypt 0x%02x", chan, conn,
conn->handle, conn->encrypt);
BT_DBG("chan %p conn %p handle %u encrypt 0x%02x hci status 0x%02x",
chan, conn, conn->handle, conn->encrypt, hci_status);
if (hci_status) {
return;
}
if (!smp || !conn->encrypt) {
return;