|
@@ -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);
|
|
|
|
- list_for_each_safe(p, n, &hdev->long_term_keys) {
|
|
|
|
- struct smp_ltk *ltk = list_entry(p, struct smp_ltk, list);
|
|
|
|
|
|
+ rcu_read_lock();
|
|
|
|
+ list_for_each_entry_rcu(ltk, &hdev->long_term_keys, 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);
|
|
- }
|
|
|
|
- hci_dev_unlock(hdev);
|
|
|
|
|
|
+ rcu_read_unlock();
|
|
|
|
|
|
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_del(&k->list);
|
|
|
|
- kfree(k);
|
|
|
|
|
|
+ list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
|
|
|
|
+ list_del_rcu(&k->list);
|
|
|
|
+ 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);
|
|
|
|
- kfree(k);
|
|
|
|
|
|
+ list_del_rcu(&k->list);
|
|
|
|
+ kfree_rcu(k, rcu);
|
|
removed++;
|
|
removed++;
|
|
}
|
|
}
|
|
|
|
|