Skip to content

Commit

Permalink
Bluetooth: Host: Add error to security changed callback
Browse files Browse the repository at this point in the history
Add security error to security_changed callback. Call this callback when
security has failed and provide current security level and error.
Reason for failure can be.
 - Pairing procedure failed, pairing aborted before link encryption.
 - Link encrypt procedure failed
 - Link key refresh procedure failed.

Fix missing bt_conn_unref on encryption key refresh with error status.

Signed-off-by: Joakim Andersson <[email protected]>
  • Loading branch information
joerchan authored and carlescufi committed Aug 26, 2019
1 parent f1c7371 commit 6d4b842
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 32 deletions.
4 changes: 3 additions & 1 deletion include/bluetooth/conn.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,10 @@ struct bt_conn_cb {
*
* @param conn Connection object.
* @param level New security level of the connection.
* @param err Security error. Zero for success, non-zero otherwise.
*/
void (*security_changed)(struct bt_conn *conn, bt_security_t level);
void (*security_changed)(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err);
#endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) */
struct bt_conn_cb *_next;
};
Expand Down
9 changes: 7 additions & 2 deletions samples/bluetooth/peripheral_hids/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,18 @@ static void disconnected(struct bt_conn *conn, u8_t reason)
printk("Disconnected from %s (reason 0x%02x)\n", addr, reason);
}

static void security_changed(struct bt_conn *conn, bt_security_t level)
static void security_changed(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err)
{
char addr[BT_ADDR_LE_STR_LEN];

bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

printk("Security changed: %s level %u\n", addr, level);
if (!err) {
printk("Security changed: %s level %u", addr, level);
} else {
printk("Security failed: %s level %u err %d", addr, level, err);
}
}

static struct bt_conn_cb conn_callbacks = {
Expand Down
9 changes: 7 additions & 2 deletions samples/bluetooth/peripheral_sc_only/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,18 @@ static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
printk("Identity resolved %s -> %s\n", addr_rpa, addr_identity);
}

static void security_changed(struct bt_conn *conn, bt_security_t level)
static void security_changed(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err)
{
char addr[BT_ADDR_LE_STR_LEN];

bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

printk("Security changed: %s level %u\n", addr, level);
if (!err) {
printk("Security changed: %s level %u", addr, level);
} else {
printk("Security failed: %s level %u err %d", addr, level, err);
}
}

static struct bt_conn_cb conn_callbacks = {
Expand Down
4 changes: 2 additions & 2 deletions subsys/bluetooth/host/conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -984,13 +984,13 @@ u8_t bt_conn_enc_key_size(struct bt_conn *conn)
return 0;
}

void bt_conn_security_changed(struct bt_conn *conn)
void bt_conn_security_changed(struct bt_conn *conn, enum bt_security_err err)
{
struct bt_conn_cb *cb;

for (cb = callback_list; cb; cb = cb->_next) {
if (cb->security_changed) {
cb->security_changed(conn, conn->sec_level);
cb->security_changed(conn, conn->sec_level, err);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion subsys/bluetooth/host/conn_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ void bt_conn_identity_resolved(struct bt_conn *conn);

#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
/* Notify higher layers that connection security changed */
void bt_conn_security_changed(struct bt_conn *conn);
void bt_conn_security_changed(struct bt_conn *conn, enum bt_security_err err);
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */

/* Prepare a PDU to be sent over a connection */
Expand Down
38 changes: 19 additions & 19 deletions subsys/bluetooth/host/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1699,19 +1699,23 @@ static enum bt_security_err security_err_get(u8_t hci_err)
return BT_SECURITY_ERR_UNSPECIFIED;
}
}
#endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) */

#if defined(CONFIG_BT_BREDR)
static void reset_pairing(struct bt_conn *conn)
{
atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING);
atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING_INITIATOR);
atomic_clear_bit(conn->flags, BT_CONN_BR_LEGACY_SECURE);
#if defined(CONFIG_BT_BREDR)
if (conn->type == BT_CONN_TYPE_BR) {
atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING);
atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING_INITIATOR);
atomic_clear_bit(conn->flags, BT_CONN_BR_LEGACY_SECURE);
}
#endif /* CONFIG_BT_BREDR */

/* Reset required security level to current operational */
conn->required_sec_level = conn->sec_level;
}
#endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) */

#if defined(CONFIG_BT_BREDR)
static int reject_conn(const bt_addr_t *bdaddr, u8_t reason)
{
struct bt_hci_cp_reject_conn_req *cp;
Expand Down Expand Up @@ -3026,16 +3030,9 @@ static void hci_encrypt_change(struct net_buf *buf)
}

if (evt->status) {
/* TODO report error */
if (conn->type == BT_CONN_TYPE_LE) {
/* reset required security level in case of error */
conn->required_sec_level = conn->sec_level;
#if defined(CONFIG_BT_BREDR)
} else {
bt_l2cap_encrypt_change(conn, evt->status);
reset_pairing(conn);
#endif /* CONFIG_BT_BREDR */
}
reset_pairing(conn);
bt_l2cap_encrypt_change(conn, evt->status);
bt_conn_security_changed(conn, security_err_get(evt->status));
bt_conn_unref(conn);
return;
}
Expand Down Expand Up @@ -3072,13 +3069,12 @@ static void hci_encrypt_change(struct net_buf *buf)
bt_smp_br_send_pairing_req(conn);
}
}

reset_pairing(conn);
}
#endif /* CONFIG_BT_BREDR */
reset_pairing(conn);

bt_l2cap_encrypt_change(conn, evt->status);
bt_conn_security_changed(conn);
bt_conn_security_changed(conn, BT_SECURITY_ERR_SUCCESS);

bt_conn_unref(conn);
}
Expand All @@ -3100,7 +3096,10 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
}

if (evt->status) {
reset_pairing(conn);
bt_l2cap_encrypt_change(conn, evt->status);
bt_conn_security_changed(conn, security_err_get(evt->status));
bt_conn_unref(conn);
return;
}

Expand All @@ -3122,8 +3121,9 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
}
#endif /* CONFIG_BT_BREDR */

reset_pairing(conn);
bt_l2cap_encrypt_change(conn, evt->status);
bt_conn_security_changed(conn);
bt_conn_security_changed(conn, BT_SECURITY_ERR_SUCCESS);
bt_conn_unref(conn);
}
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
Expand Down
13 changes: 10 additions & 3 deletions subsys/bluetooth/host/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1584,9 +1584,16 @@ static void smp_pairing_complete(struct bt_smp *smp, u8_t status)
bt_auth->pairing_complete(smp->chan.chan.conn,
bond_flag);
}
} else if (bt_auth && bt_auth->pairing_failed) {
bt_auth->pairing_failed(smp->chan.chan.conn,
auth_err_get(status));
} else {
u8_t auth_err = auth_err_get(status);

if (!atomic_test_bit(smp->flags, SMP_FLAG_KEYS_DISTR)) {
bt_conn_security_changed(smp->chan.chan.conn, auth_err);
}

if (bt_auth && bt_auth->pairing_failed) {
bt_auth->pairing_failed(smp->chan.chan.conn, auth_err);
}
}

smp_reset(smp);
Expand Down
12 changes: 10 additions & 2 deletions subsys/bluetooth/shell/bt.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,20 @@ static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
#endif

#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
static void security_changed(struct bt_conn *conn, bt_security_t level)
static void security_changed(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err)
{
char addr[BT_ADDR_LE_STR_LEN];

conn_addr_str(conn, addr, sizeof(addr));
shell_print(ctx_shell, "Security changed: %s level %u", addr, level);

if (!err) {
shell_print(ctx_shell, "Security changed: %s level %u", addr,
level);
} else {
shell_print(ctx_shell, "Security failed: %s level %u reason %d",
addr, level, err);
}
}
#endif

Expand Down

0 comments on commit 6d4b842

Please sign in to comment.