Commit f4a407be authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann

Bluetooth: Wait for SMP key distribution completion when pairing

When we initiate pairing through mgmt_pair_device the code has so far
been waiting for a successful HCI Encrypt Change event in order to
respond to the mgmt command. However, putting privacy into the play we
actually want the key distribution to be complete before replying so
that we can include the Identity Address in the mgmt response.

This patch updates the various hci_conn callbacks for LE in mgmt.c to
only respond in the case of failure, and adds a new mgmt_smp_complete
function that the SMP code will call once key distribution has been
completed.

Since the smp_chan_destroy function that's used to indicate completion
and clean up the SMP context can be called from various places,
including outside of smp.c, the easiest way to track failure vs success
is a new flag that we set once key distribution has been successfully
completed.
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 387a33e3
...@@ -1212,6 +1212,7 @@ int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); ...@@ -1212,6 +1212,7 @@ int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_reenable_advertising(struct hci_dev *hdev);
void mgmt_smp_complete(struct hci_conn *conn, bool complete);
/* HCI info for socket */ /* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk) #define hci_pi(sk) ((struct hci_pinfo *) sk)
......
...@@ -2655,6 +2655,16 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) ...@@ -2655,6 +2655,16 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
} }
void mgmt_smp_complete(struct hci_conn *conn, bool complete)
{
u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
struct pending_cmd *cmd;
cmd = find_pairing(conn);
if (cmd)
pairing_complete(cmd, status);
}
static void pairing_complete_cb(struct hci_conn *conn, u8 status) static void pairing_complete_cb(struct hci_conn *conn, u8 status)
{ {
struct pending_cmd *cmd; struct pending_cmd *cmd;
...@@ -2668,7 +2678,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) ...@@ -2668,7 +2678,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status)
pairing_complete(cmd, mgmt_status(status)); pairing_complete(cmd, mgmt_status(status));
} }
static void le_connect_complete_cb(struct hci_conn *conn, u8 status) static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
{ {
struct pending_cmd *cmd; struct pending_cmd *cmd;
...@@ -2755,13 +2765,16 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2755,13 +2765,16 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
} }
/* For LE, just connecting isn't a proof that the pairing finished */ /* For LE, just connecting isn't a proof that the pairing finished */
if (cp->addr.type == BDADDR_BREDR) if (cp->addr.type == BDADDR_BREDR) {
conn->connect_cfm_cb = pairing_complete_cb; conn->connect_cfm_cb = pairing_complete_cb;
else
conn->connect_cfm_cb = le_connect_complete_cb;
conn->security_cfm_cb = pairing_complete_cb; conn->security_cfm_cb = pairing_complete_cb;
conn->disconn_cfm_cb = pairing_complete_cb; conn->disconn_cfm_cb = pairing_complete_cb;
} else {
conn->connect_cfm_cb = le_pairing_complete_cb;
conn->security_cfm_cb = le_pairing_complete_cb;
conn->disconn_cfm_cb = le_pairing_complete_cb;
}
conn->io_capability = cp->io_cap; conn->io_capability = cp->io_cap;
cmd->user_data = conn; cmd->user_data = conn;
......
...@@ -565,9 +565,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) ...@@ -565,9 +565,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
void smp_chan_destroy(struct l2cap_conn *conn) void smp_chan_destroy(struct l2cap_conn *conn)
{ {
struct smp_chan *smp = conn->smp_chan; struct smp_chan *smp = conn->smp_chan;
bool complete;
BUG_ON(!smp); BUG_ON(!smp);
complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
mgmt_smp_complete(conn->hcon, complete);
kfree(smp); kfree(smp);
conn->smp_chan = NULL; conn->smp_chan = NULL;
conn->hcon->smp_conn = NULL; conn->hcon->smp_conn = NULL;
...@@ -1187,6 +1191,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) ...@@ -1187,6 +1191,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) { if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) {
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
cancel_delayed_work_sync(&conn->security_timer); cancel_delayed_work_sync(&conn->security_timer);
set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags);
smp_chan_destroy(conn); smp_chan_destroy(conn);
} }
......
...@@ -118,6 +118,7 @@ struct smp_cmd_security_req { ...@@ -118,6 +118,7 @@ struct smp_cmd_security_req {
#define SMP_FLAG_TK_VALID 1 #define SMP_FLAG_TK_VALID 1
#define SMP_FLAG_CFM_PENDING 2 #define SMP_FLAG_CFM_PENDING 2
#define SMP_FLAG_MITM_AUTH 3 #define SMP_FLAG_MITM_AUTH 3
#define SMP_FLAG_COMPLETE 4
struct smp_chan { struct smp_chan {
struct l2cap_conn *conn; struct l2cap_conn *conn;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment