Bluetooth: host: Set error in security changed when not required level

Set the error in the security changed callback when the encryption has
not reached the required security level.
Terminate the pairing procedure in SMP on failure to avoid the security
changed callback being called twice in this case.

Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c
index e7b90a3..8a44507 100644
--- a/subsys/bluetooth/host/hci_core.c
+++ b/subsys/bluetooth/host/hci_core.c
@@ -3582,13 +3582,8 @@
 	bt_adv_foreach(adv_unpause_enabled, NULL);
 }
 
-static void update_sec_level(struct bt_conn *conn)
+static bool update_sec_level(struct bt_conn *conn)
 {
-	if (!conn->encrypt) {
-		conn->sec_level = BT_SECURITY_L1;
-		return;
-	}
-
 	if (conn->le.keys && (conn->le.keys->flags & BT_KEYS_AUTHENTICATED)) {
 		if (conn->le.keys->flags & BT_KEYS_SC &&
 		    conn->le.keys->enc_size == BT_SMP_MAX_ENC_KEY_SIZE) {
@@ -3600,10 +3595,7 @@
 		conn->sec_level = BT_SECURITY_L2;
 	}
 
-	if (conn->required_sec_level > conn->sec_level) {
-		BT_ERR("Failed to set required security level");
-		bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL);
-	}
+	return !(conn->required_sec_level > conn->sec_level);
 }
 #endif /* CONFIG_BT_SMP */
 
@@ -3612,6 +3604,7 @@
 {
 	struct bt_hci_evt_encrypt_change *evt = (void *)buf->data;
 	uint16_t handle = sys_le16_to_cpu(evt->handle);
+	uint8_t status = evt->status;
 	struct bt_conn *conn;
 
 	BT_DBG("status 0x%02x handle %u encrypt 0x%02x", evt->status, handle,
@@ -3623,9 +3616,9 @@
 		return;
 	}
 
-	if (evt->status) {
-		bt_conn_security_changed(conn, evt->status,
-					 bt_security_err_get(evt->status));
+	if (status) {
+		bt_conn_security_changed(conn, status,
+					 bt_security_err_get(status));
 		bt_conn_unref(conn);
 		return;
 	}
@@ -3645,7 +3638,10 @@
 		if (conn->encrypt) {
 			bt_smp_update_keys(conn);
 		}
-		update_sec_level(conn);
+
+		if (!update_sec_level(conn)) {
+			status = BT_HCI_ERR_AUTH_FAIL;
+		}
 	}
 #endif /* CONFIG_BT_SMP */
 #if defined(CONFIG_BT_BREDR)
@@ -3668,7 +3664,12 @@
 	}
 #endif /* CONFIG_BT_BREDR */
 
-	bt_conn_security_changed(conn, evt->status, BT_SECURITY_ERR_SUCCESS);
+	bt_conn_security_changed(conn, status, bt_security_err_get(status));
+
+	if (status) {
+		BT_ERR("Failed to set required security level");
+		bt_conn_disconnect(conn, status);
+	}
 
 	bt_conn_unref(conn);
 }
@@ -3676,6 +3677,7 @@
 static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
 {
 	struct bt_hci_evt_encrypt_key_refresh_complete *evt = (void *)buf->data;
+	uint8_t status = evt->status;
 	struct bt_conn *conn;
 	uint16_t handle;
 
@@ -3689,9 +3691,9 @@
 		return;
 	}
 
-	if (evt->status) {
-		bt_conn_security_changed(conn, evt->status,
-					 bt_security_err_get(evt->status));
+	if (status) {
+		bt_conn_security_changed(conn, status,
+					 bt_security_err_get(status));
 		bt_conn_unref(conn);
 		return;
 	}
@@ -3705,7 +3707,10 @@
 #if defined(CONFIG_BT_SMP)
 	if (conn->type == BT_CONN_TYPE_LE) {
 		bt_smp_update_keys(conn);
-		update_sec_level(conn);
+
+		if (!update_sec_level(conn)) {
+			status = BT_HCI_ERR_AUTH_FAIL;
+		}
 	}
 #endif /* CONFIG_BT_SMP */
 #if defined(CONFIG_BT_BREDR)
@@ -3717,7 +3722,12 @@
 	}
 #endif /* CONFIG_BT_BREDR */
 
-	bt_conn_security_changed(conn, evt->status, BT_SECURITY_ERR_SUCCESS);
+	bt_conn_security_changed(conn, status, bt_security_err_get(status));
+	if (status) {
+		BT_ERR("Failed to set required security level");
+		bt_conn_disconnect(conn, status);
+	}
+
 	bt_conn_unref(conn);
 }
 #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c
index f92c6e0..5d6d44a 100644
--- a/subsys/bluetooth/host/smp.c
+++ b/subsys/bluetooth/host/smp.c
@@ -439,7 +439,6 @@
 	}
 }
 
-#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
 static uint8_t smp_err_get(enum bt_security_err auth_err)
 {
 	switch (auth_err) {
@@ -464,7 +463,6 @@
 		return 0;
 	}
 }
-#endif /* CONFIG_BT_SMP_APP_PAIRING_ACCEPT */
 
 static struct net_buf *smp_create_pdu(struct bt_smp *smp, uint8_t op, size_t len)
 {
@@ -4536,9 +4534,24 @@
 	BT_DBG("chan %p conn %p handle %u encrypt 0x%02x hci status 0x%02x",
 	       chan, conn, conn->handle, conn->encrypt, hci_status);
 
-	atomic_clear_bit(smp->flags, SMP_FLAG_ENC_PENDING);
+	if (!atomic_test_and_clear_bit(smp->flags, SMP_FLAG_ENC_PENDING)) {
+		/* We where not waiting for encryption procedure.
+		 * This happens when encrypt change is called to notify that
+		 * security has failed before starting encryption.
+		 */
+		return;
+	}
 
 	if (hci_status) {
+		if (atomic_test_bit(smp->flags, SMP_FLAG_PAIRING)) {
+			uint8_t smp_err = smp_err_get(
+				bt_security_err_get(hci_status));
+
+			/* Fail as if it happened during key distribution */
+			atomic_set_bit(smp->flags, SMP_FLAG_KEYS_DISTR);
+			smp_pairing_complete(smp, smp_err);
+		}
+
 		return;
 	}