Bluetooth: Fix DHKey Check sending order for slave role

According to the LE SC specification the initiating device sends its
DHKey check first and the non-initiating devices sends its DHKey check
as a response to this. It's also important that the non-initiating
device doesn't send the response if it's still waiting for user input.
In order to synchronize all this a new flag is added.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Johan Hedberg 2014-06-04 11:07:40 +03:00 committed by Marcel Holtmann
parent 38606f1418
commit d3e54a876e
1 changed files with 43 additions and 17 deletions

View File

@ -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);