Bluetooth: Convert LTK list to RCU
This patch set converts the hdev->long_term_keys list to use RCU to eliminate the need to use hci_dev_lock/unlock. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
committed by
Marcel Holtmann
parent
3e64b7bd82
commit
970d0f1b28
@@ -108,6 +108,7 @@ struct smp_csrk {
|
|||||||
|
|
||||||
struct smp_ltk {
|
struct smp_ltk {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
struct rcu_head rcu;
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
u8 bdaddr_type;
|
u8 bdaddr_type;
|
||||||
u8 authenticated;
|
u8 authenticated;
|
||||||
|
|||||||
@@ -778,17 +778,15 @@ static const struct file_operations identity_resolving_keys_fops = {
|
|||||||
static int long_term_keys_show(struct seq_file *f, void *ptr)
|
static int long_term_keys_show(struct seq_file *f, void *ptr)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev = f->private;
|
struct hci_dev *hdev = f->private;
|
||||||
struct list_head *p, *n;
|
struct smp_ltk *ltk;
|
||||||
|
|
||||||
hci_dev_lock(hdev);
|
rcu_read_lock();
|
||||||
list_for_each_safe(p, n, &hdev->long_term_keys) {
|
list_for_each_entry_rcu(ltk, &hdev->long_term_keys, list)
|
||||||
struct smp_ltk *ltk = list_entry(p, struct smp_ltk, list);
|
|
||||||
seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN\n",
|
seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN\n",
|
||||||
<k->bdaddr, ltk->bdaddr_type, ltk->authenticated,
|
<k->bdaddr, ltk->bdaddr_type, ltk->authenticated,
|
||||||
ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv),
|
ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv),
|
||||||
__le64_to_cpu(ltk->rand), 16, ltk->val);
|
__le64_to_cpu(ltk->rand), 16, ltk->val);
|
||||||
}
|
rcu_read_unlock();
|
||||||
hci_dev_unlock(hdev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3106,11 +3104,11 @@ void hci_link_keys_clear(struct hci_dev *hdev)
|
|||||||
|
|
||||||
void hci_smp_ltks_clear(struct hci_dev *hdev)
|
void hci_smp_ltks_clear(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct smp_ltk *k, *tmp;
|
struct smp_ltk *k;
|
||||||
|
|
||||||
list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
|
list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
|
||||||
list_del(&k->list);
|
list_del_rcu(&k->list);
|
||||||
kfree(k);
|
kfree_rcu(k, rcu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3184,15 +3182,18 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
|
|||||||
{
|
{
|
||||||
struct smp_ltk *k;
|
struct smp_ltk *k;
|
||||||
|
|
||||||
list_for_each_entry(k, &hdev->long_term_keys, list) {
|
rcu_read_lock();
|
||||||
|
list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
|
||||||
if (k->ediv != ediv || k->rand != rand)
|
if (k->ediv != ediv || k->rand != rand)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ltk_role(k->type) != role)
|
if (ltk_role(k->type) != role)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -3202,11 +3203,16 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|||||||
{
|
{
|
||||||
struct smp_ltk *k;
|
struct smp_ltk *k;
|
||||||
|
|
||||||
list_for_each_entry(k, &hdev->long_term_keys, list)
|
rcu_read_lock();
|
||||||
|
list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
|
||||||
if (addr_type == k->bdaddr_type &&
|
if (addr_type == k->bdaddr_type &&
|
||||||
bacmp(bdaddr, &k->bdaddr) == 0 &&
|
bacmp(bdaddr, &k->bdaddr) == 0 &&
|
||||||
ltk_role(k->type) == role)
|
ltk_role(k->type) == role) {
|
||||||
|
rcu_read_unlock();
|
||||||
return k;
|
return k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -3309,7 +3315,7 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|||||||
key = kzalloc(sizeof(*key), GFP_KERNEL);
|
key = kzalloc(sizeof(*key), GFP_KERNEL);
|
||||||
if (!key)
|
if (!key)
|
||||||
return NULL;
|
return NULL;
|
||||||
list_add(&key->list, &hdev->long_term_keys);
|
list_add_rcu(&key->list, &hdev->long_term_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
bacpy(&key->bdaddr, bdaddr);
|
bacpy(&key->bdaddr, bdaddr);
|
||||||
@@ -3365,17 +3371,17 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
|||||||
|
|
||||||
int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)
|
int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)
|
||||||
{
|
{
|
||||||
struct smp_ltk *k, *tmp;
|
struct smp_ltk *k;
|
||||||
int removed = 0;
|
int removed = 0;
|
||||||
|
|
||||||
list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
|
list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
|
||||||
if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type)
|
if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
BT_DBG("%s removing %pMR", hdev->name, bdaddr);
|
BT_DBG("%s removing %pMR", hdev->name, bdaddr);
|
||||||
|
|
||||||
list_del(&k->list);
|
list_del_rcu(&k->list);
|
||||||
kfree(k);
|
kfree_rcu(k, rcu);
|
||||||
removed++;
|
removed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4578,8 +4578,8 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||||||
*/
|
*/
|
||||||
if (ltk->type == SMP_STK) {
|
if (ltk->type == SMP_STK) {
|
||||||
set_bit(HCI_CONN_STK_ENCRYPT, &conn->flags);
|
set_bit(HCI_CONN_STK_ENCRYPT, &conn->flags);
|
||||||
list_del(<k->list);
|
list_del_rcu(<k->list);
|
||||||
kfree(ltk);
|
kfree_rcu(ltk, rcu);
|
||||||
} else {
|
} else {
|
||||||
clear_bit(HCI_CONN_STK_ENCRYPT, &conn->flags);
|
clear_bit(HCI_CONN_STK_ENCRYPT, &conn->flags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -383,13 +383,13 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
|
|||||||
/* If pairing failed clean up any keys we might have */
|
/* If pairing failed clean up any keys we might have */
|
||||||
if (!complete) {
|
if (!complete) {
|
||||||
if (smp->ltk) {
|
if (smp->ltk) {
|
||||||
list_del(&smp->ltk->list);
|
list_del_rcu(&smp->ltk->list);
|
||||||
kfree(smp->ltk);
|
kfree_rcu(smp->ltk, rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (smp->slave_ltk) {
|
if (smp->slave_ltk) {
|
||||||
list_del(&smp->slave_ltk->list);
|
list_del_rcu(&smp->slave_ltk->list);
|
||||||
kfree(smp->slave_ltk);
|
kfree_rcu(smp->slave_ltk, rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (smp->remote_irk) {
|
if (smp->remote_irk) {
|
||||||
@@ -1321,7 +1321,6 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||||||
|
|
||||||
skb_pull(skb, sizeof(*rp));
|
skb_pull(skb, sizeof(*rp));
|
||||||
|
|
||||||
hci_dev_lock(hdev);
|
|
||||||
authenticated = (hcon->sec_level == BT_SECURITY_HIGH);
|
authenticated = (hcon->sec_level == BT_SECURITY_HIGH);
|
||||||
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, SMP_LTK,
|
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, SMP_LTK,
|
||||||
authenticated, smp->tk, smp->enc_key_size,
|
authenticated, smp->tk, smp->enc_key_size,
|
||||||
@@ -1329,7 +1328,6 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||||||
smp->ltk = ltk;
|
smp->ltk = ltk;
|
||||||
if (!(smp->remote_key_dist & KEY_DIST_MASK))
|
if (!(smp->remote_key_dist & KEY_DIST_MASK))
|
||||||
smp_distribute_keys(smp);
|
smp_distribute_keys(smp);
|
||||||
hci_dev_unlock(hdev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user