Bluetooth: Fix LE Connection refcnts
Some rebalancing of refcnts due to issues found during testing:
Refcnt was not being released on security completion, if local side
was paired but the remote side had deleted the pairing info, and then
the re-pair failed to complete successfully.
Additionally, the refcnt was not held-released properly if pairing
was initiated due to the client socket being opened with security
level elevated from the start.
Change-Id: I120fed4dc74035d280781ca949a23d4cbcfa3f3e
CRs-fixed: 335993
Signed-off-by: Brian Gix <bgix@codeaurora.org>
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index e301edf..2484a9a 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -652,6 +652,7 @@
static int smp_encrypt_link(struct hci_conn *hcon, struct link_key *key)
{
struct key_master_id *master;
+ u8 sec_level;
u8 zerobuf[8];
if (!hcon || !key || !key->data)
@@ -666,6 +667,17 @@
hcon->enc_key_size = key->pin_len;
hcon->sec_req = TRUE;
+ sec_level = authreq_to_seclevel(key->auth);
+
+ BT_DBG("cur %d, req: %d", hcon->sec_level, sec_level);
+
+ if (sec_level > hcon->sec_level)
+ hcon->pending_sec_level = sec_level;
+
+
+ if (!(hcon->link_mode & HCI_LM_ENCRYPT))
+ hci_conn_hold(hcon);
+
hci_le_start_enc(hcon, master->ediv, master->rand, key->val);
return 0;
@@ -690,11 +702,6 @@
if (smp_encrypt_link(hcon, key) < 0)
goto invalid_key;
- hcon->sec_level = authreq_to_seclevel(key->auth);
-
- if (!(hcon->link_mode & HCI_LM_ENCRYPT))
- hci_conn_hold(hcon);
-
return 0;
}
@@ -729,33 +736,26 @@
struct hci_conn *hcon = conn->hcon;
__u8 authreq;
- BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
+ BT_DBG("conn %p hcon %p %d req: %d",
+ conn, hcon, hcon->sec_level, sec_level);
- if (IS_ERR(hcon->hdev->tfm)) {
- BT_DBG("IS_ERR");
+ if (IS_ERR(hcon->hdev->tfm))
return 1;
- }
- if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
- BT_DBG("HCI_CONN_ENCRYPT_PEND");
+ if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
return -EINPROGRESS;
- }
- if (sec_level == BT_SECURITY_LOW) {
- BT_DBG("BT_SECURITY_LOW");
+ if (sec_level == BT_SECURITY_LOW)
return 1;
- }
- if (hcon->sec_level > sec_level) {
- BT_DBG("hcon->sec_level > sec_level");
+
+ if (hcon->sec_level >= sec_level)
return 1;
- }
authreq = seclevel_to_authreq(sec_level);
- BT_ERR("conn = %p, sec: %d", conn, sec_level);
hcon->smp_conn = conn;
- hcon->sec_level = sec_level;
+ hcon->pending_sec_level = sec_level;
if ((hcon->link_mode & HCI_LM_MASTER) && !hcon->sec_req) {
struct link_key *key;
@@ -785,6 +785,7 @@
msecs_to_jiffies(SMP_TIMEOUT));
smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
+ hci_conn_hold(hcon);
} else {
struct smp_cmd_security_req cp;
cp.auth_req = authreq;
@@ -792,7 +793,6 @@
}
done:
- hcon->pending_sec_level = sec_level;
set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
return 0;
@@ -1045,15 +1045,17 @@
clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+ if (!status && encrypt && hcon->sec_level < hcon->pending_sec_level)
+ hcon->sec_level = hcon->pending_sec_level;
+
if (!status && encrypt && !hcon->sec_req)
- smp_distribute_keys(conn, 0);
+ return smp_distribute_keys(conn, 0);
/* Fall back to Pairing request if failed a Link Security request */
else if (hcon->sec_req && (status || !encrypt))
- smp_conn_security(conn, hcon->sec_level);
+ smp_conn_security(conn, hcon->pending_sec_level);
- else
- hci_conn_put(hcon);
+ hci_conn_put(hcon);
return 0;
}