Bluetooth: Host: Add error to security changed callback

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 <joakim.andersson@nordicsemi.no>
This commit is contained in:
Joakim Andersson 2019-08-19 16:20:59 +02:00 committed by Carles Cufí
commit 6d4b842a10
8 changed files with 59 additions and 32 deletions

View file

@ -442,8 +442,10 @@ struct bt_conn_cb {
* *
* @param conn Connection object. * @param conn Connection object.
* @param level New security level of the connection. * @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) */ #endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) */
struct bt_conn_cb *_next; struct bt_conn_cb *_next;
}; };

View file

@ -58,13 +58,18 @@ static void disconnected(struct bt_conn *conn, u8_t reason)
printk("Disconnected from %s (reason 0x%02x)\n", addr, 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]; char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); 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 = { static struct bt_conn_cb conn_callbacks = {

View file

@ -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); 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]; char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); 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 = { static struct bt_conn_cb conn_callbacks = {

View file

@ -984,13 +984,13 @@ u8_t bt_conn_enc_key_size(struct bt_conn *conn)
return 0; 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; struct bt_conn_cb *cb;
for (cb = callback_list; cb; cb = cb->_next) { for (cb = callback_list; cb; cb = cb->_next) {
if (cb->security_changed) { if (cb->security_changed) {
cb->security_changed(conn, conn->sec_level); cb->security_changed(conn, conn->sec_level, err);
} }
} }
} }

View file

@ -218,7 +218,7 @@ void bt_conn_identity_resolved(struct bt_conn *conn);
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) #if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
/* Notify higher layers that connection security changed */ /* 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 */ #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
/* Prepare a PDU to be sent over a connection */ /* Prepare a PDU to be sent over a connection */

View file

@ -1699,19 +1699,23 @@ static enum bt_security_err security_err_get(u8_t hci_err)
return BT_SECURITY_ERR_UNSPECIFIED; 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) static void reset_pairing(struct bt_conn *conn)
{ {
#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);
atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING_INITIATOR); atomic_clear_bit(conn->flags, BT_CONN_BR_PAIRING_INITIATOR);
atomic_clear_bit(conn->flags, BT_CONN_BR_LEGACY_SECURE); atomic_clear_bit(conn->flags, BT_CONN_BR_LEGACY_SECURE);
}
#endif /* CONFIG_BT_BREDR */
/* Reset required security level to current operational */ /* Reset required security level to current operational */
conn->required_sec_level = conn->sec_level; 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) static int reject_conn(const bt_addr_t *bdaddr, u8_t reason)
{ {
struct bt_hci_cp_reject_conn_req *cp; struct bt_hci_cp_reject_conn_req *cp;
@ -3026,16 +3030,9 @@ static void hci_encrypt_change(struct net_buf *buf)
} }
if (evt->status) { 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); reset_pairing(conn);
#endif /* CONFIG_BT_BREDR */ bt_l2cap_encrypt_change(conn, evt->status);
} bt_conn_security_changed(conn, security_err_get(evt->status));
bt_conn_unref(conn); bt_conn_unref(conn);
return; return;
} }
@ -3072,13 +3069,12 @@ static void hci_encrypt_change(struct net_buf *buf)
bt_smp_br_send_pairing_req(conn); bt_smp_br_send_pairing_req(conn);
} }
} }
reset_pairing(conn);
} }
#endif /* CONFIG_BT_BREDR */ #endif /* CONFIG_BT_BREDR */
reset_pairing(conn);
bt_l2cap_encrypt_change(conn, evt->status); 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); bt_conn_unref(conn);
} }
@ -3100,7 +3096,10 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
} }
if (evt->status) { if (evt->status) {
reset_pairing(conn);
bt_l2cap_encrypt_change(conn, evt->status); bt_l2cap_encrypt_change(conn, evt->status);
bt_conn_security_changed(conn, security_err_get(evt->status));
bt_conn_unref(conn);
return; return;
} }
@ -3122,8 +3121,9 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
} }
#endif /* CONFIG_BT_BREDR */ #endif /* CONFIG_BT_BREDR */
reset_pairing(conn);
bt_l2cap_encrypt_change(conn, evt->status); 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); bt_conn_unref(conn);
} }
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */ #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */

View file

@ -1584,9 +1584,16 @@ static void smp_pairing_complete(struct bt_smp *smp, u8_t status)
bt_auth->pairing_complete(smp->chan.chan.conn, bt_auth->pairing_complete(smp->chan.chan.conn,
bond_flag); bond_flag);
} }
} else if (bt_auth && bt_auth->pairing_failed) { } else {
bt_auth->pairing_failed(smp->chan.chan.conn, u8_t auth_err = auth_err_get(status);
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); smp_reset(smp);

View file

@ -213,12 +213,20 @@ static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
#endif #endif
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) #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]; char addr[BT_ADDR_LE_STR_LEN];
conn_addr_str(conn, addr, sizeof(addr)); 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 #endif