summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bluetooth/smp.c60
1 files changed, 43 insertions, 17 deletions
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 8cfa1c1..9a4ce45 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -56,6 +56,7 @@ enum {
SMP_FLAG_REMOTE_PK,
SMP_FLAG_DEBUG_KEY,
SMP_FLAG_WAIT_USER,
+ SMP_FLAG_DHKEY_PENDING,
};
struct smp_chan {
@@ -994,6 +995,29 @@ static void smp_notify_keys(struct l2cap_conn *conn)
}
}
+static void sc_add_ltk(struct smp_chan *smp)
+{
+ struct hci_conn *hcon = smp->conn->hcon;
+ u8 key_type, auth;
+
+ if (test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags))
+ key_type = SMP_LTK_P256_DEBUG;
+ else
+ key_type = SMP_LTK_P256;
+
+ if (hcon->pending_sec_level == BT_SECURITY_FIPS)
+ auth = 1;
+ else
+ auth = 0;
+
+ memset(smp->tk + smp->enc_key_size, 0,
+ SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
+
+ smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
+ key_type, auth, smp->tk, smp->enc_key_size,
+ 0, 0);
+}
+
static void sc_generate_link_key(struct smp_chan *smp)
{
/* These constants are as specified in the core specification.
@@ -1312,12 +1336,10 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
if (!hcon->out) {
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
sizeof(smp->prnd), smp->prnd);
- if (smp->passkey_round == 20) {
- sc_dhkey_check(smp);
+ if (smp->passkey_round == 20)
SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
- } else {
+ else
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
- }
return 0;
}
@@ -1394,7 +1416,14 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
return 0;
}
- sc_dhkey_check(smp);
+ /* Initiator sends DHKey check first */
+ if (hcon->out) {
+ sc_dhkey_check(smp);
+ SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
+ } else if (test_and_clear_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags)) {
+ sc_dhkey_check(smp);
+ sc_add_ltk(smp);
+ }
return 0;
}
@@ -2262,7 +2291,6 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
struct smp_chan *smp = chan->data;
u8 a[7], b[7], *local_addr, *remote_addr;
u8 io_cap[3], r[16], e[16];
- u8 key_type, auth;
int err;
BT_DBG("conn %p", conn);
@@ -2298,19 +2326,17 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
if (memcmp(check->e, e, 16))
return SMP_DHKEY_CHECK_FAILED;
- if (test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags))
- key_type = SMP_LTK_P256_DEBUG;
- else
- key_type = SMP_LTK_P256;
+ if (!hcon->out) {
+ if (test_bit(SMP_FLAG_WAIT_USER, &smp->flags)) {
+ set_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags);
+ return 0;
+ }
- if (hcon->pending_sec_level == BT_SECURITY_FIPS)
- auth = 1;
- else
- auth = 0;
+ /* Slave sends DHKey check as response to master */
+ sc_dhkey_check(smp);
+ }
- smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
- key_type, auth, smp->tk, smp->enc_key_size,
- 0, 0);
+ sc_add_ltk(smp);
if (hcon->out) {
hci_le_start_enc(hcon, 0, 0, smp->tk);
OpenPOWER on IntegriCloud