aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2014-11-13 07:37:48 -0500
committerMarcel Holtmann <marcel@holtmann.org>2014-11-14 19:53:27 -0500
commitadae20cb2d20e5151b866945f802b0c2312f0f82 (patch)
tree82db161600f3689fc508aa4442d7a1a4ef22d2b6
parent970d0f1b280372cfd46b6de5529d96f8448de943 (diff)
Bluetooth: Convert IRK list to RCU
This patch set converts the hdev->identity_resolving_keys list to use RCU to eliminate the need to use hci_dev_lock/unlock. An additional change that must be done is to remove use of CRYPTO_ALG_ASYNC for the hdev-specific AES crypto context. The reason is that this context is used for matching RPAs and the loop that does the matching is under the RCU read lock, i.e. is an atomic section which cannot sleep. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/hci_core.h1
-rw-r--r--net/bluetooth/hci_core.c46
-rw-r--r--net/bluetooth/smp.c10
3 files changed, 33 insertions, 24 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a4adef22ad7c..fe2d5f299e12 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -121,6 +121,7 @@ struct smp_ltk {
121 121
122struct smp_irk { 122struct smp_irk {
123 struct list_head list; 123 struct list_head list;
124 struct rcu_head rcu;
124 bdaddr_t rpa; 125 bdaddr_t rpa;
125 bdaddr_t bdaddr; 126 bdaddr_t bdaddr;
126 u8 addr_type; 127 u8 addr_type;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c9495fb9f595..90ea0b7670d2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -748,16 +748,15 @@ static const struct file_operations white_list_fops = {
748static int identity_resolving_keys_show(struct seq_file *f, void *ptr) 748static int identity_resolving_keys_show(struct seq_file *f, void *ptr)
749{ 749{
750 struct hci_dev *hdev = f->private; 750 struct hci_dev *hdev = f->private;
751 struct list_head *p, *n; 751 struct smp_irk *irk;
752 752
753 hci_dev_lock(hdev); 753 rcu_read_lock();
754 list_for_each_safe(p, n, &hdev->identity_resolving_keys) { 754 list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
755 struct smp_irk *irk = list_entry(p, struct smp_irk, list);
756 seq_printf(f, "%pMR (type %u) %*phN %pMR\n", 755 seq_printf(f, "%pMR (type %u) %*phN %pMR\n",
757 &irk->bdaddr, irk->addr_type, 756 &irk->bdaddr, irk->addr_type,
758 16, irk->val, &irk->rpa); 757 16, irk->val, &irk->rpa);
759 } 758 }
760 hci_dev_unlock(hdev); 759 rcu_read_unlock();
761 760
762 return 0; 761 return 0;
763} 762}
@@ -3114,11 +3113,11 @@ void hci_smp_ltks_clear(struct hci_dev *hdev)
3114 3113
3115void hci_smp_irks_clear(struct hci_dev *hdev) 3114void hci_smp_irks_clear(struct hci_dev *hdev)
3116{ 3115{
3117 struct smp_irk *k, *tmp; 3116 struct smp_irk *k;
3118 3117
3119 list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) { 3118 list_for_each_entry_rcu(k, &hdev->identity_resolving_keys, list) {
3120 list_del(&k->list); 3119 list_del_rcu(&k->list);
3121 kfree(k); 3120 kfree_rcu(k, rcu);
3122 } 3121 }
3123} 3122}
3124 3123
@@ -3221,17 +3220,22 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
3221{ 3220{
3222 struct smp_irk *irk; 3221 struct smp_irk *irk;
3223 3222
3224 list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { 3223 rcu_read_lock();
3225 if (!bacmp(&irk->rpa, rpa)) 3224 list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
3225 if (!bacmp(&irk->rpa, rpa)) {
3226 rcu_read_unlock();
3226 return irk; 3227 return irk;
3228 }
3227 } 3229 }
3228 3230
3229 list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { 3231 list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
3230 if (smp_irk_matches(hdev, irk->val, rpa)) { 3232 if (smp_irk_matches(hdev, irk->val, rpa)) {
3231 bacpy(&irk->rpa, rpa); 3233 bacpy(&irk->rpa, rpa);
3234 rcu_read_unlock();
3232 return irk; 3235 return irk;
3233 } 3236 }
3234 } 3237 }
3238 rcu_read_unlock();
3235 3239
3236 return NULL; 3240 return NULL;
3237} 3241}
@@ -3245,11 +3249,15 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
3245 if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0) 3249 if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0)
3246 return NULL; 3250 return NULL;
3247 3251
3248 list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { 3252 rcu_read_lock();
3253 list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
3249 if (addr_type == irk->addr_type && 3254 if (addr_type == irk->addr_type &&
3250 bacmp(bdaddr, &irk->bdaddr) == 0) 3255 bacmp(bdaddr, &irk->bdaddr) == 0) {
3256 rcu_read_unlock();
3251 return irk; 3257 return irk;
3258 }
3252 } 3259 }
3260 rcu_read_unlock();
3253 3261
3254 return NULL; 3262 return NULL;
3255} 3263}
@@ -3344,7 +3352,7 @@ struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr,
3344 bacpy(&irk->bdaddr, bdaddr); 3352 bacpy(&irk->bdaddr, bdaddr);
3345 irk->addr_type = addr_type; 3353 irk->addr_type = addr_type;
3346 3354
3347 list_add(&irk->list, &hdev->identity_resolving_keys); 3355 list_add_rcu(&irk->list, &hdev->identity_resolving_keys);
3348 } 3356 }
3349 3357
3350 memcpy(irk->val, val, 16); 3358 memcpy(irk->val, val, 16);
@@ -3390,16 +3398,16 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)
3390 3398
3391void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) 3399void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type)
3392{ 3400{
3393 struct smp_irk *k, *tmp; 3401 struct smp_irk *k;
3394 3402
3395 list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) { 3403 list_for_each_entry_rcu(k, &hdev->identity_resolving_keys, list) {
3396 if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type) 3404 if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type)
3397 continue; 3405 continue;
3398 3406
3399 BT_DBG("%s removing %pMR", hdev->name, bdaddr); 3407 BT_DBG("%s removing %pMR", hdev->name, bdaddr);
3400 3408
3401 list_del(&k->list); 3409 list_del_rcu(&k->list);
3402 kfree(k); 3410 kfree_rcu(k, rcu);
3403 } 3411 }
3404} 3412}
3405 3413
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index fd2dfe5222bc..7b610f615257 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -393,8 +393,8 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
393 } 393 }
394 394
395 if (smp->remote_irk) { 395 if (smp->remote_irk) {
396 list_del(&smp->remote_irk->list); 396 list_del_rcu(&smp->remote_irk->list);
397 kfree(smp->remote_irk); 397 kfree_rcu(smp->remote_irk, rcu);
398 } 398 }
399 } 399 }
400 400
@@ -655,8 +655,8 @@ static void smp_notify_keys(struct l2cap_conn *conn)
655 * just remove it. 655 * just remove it.
656 */ 656 */
657 if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { 657 if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) {
658 list_del(&smp->remote_irk->list); 658 list_del_rcu(&smp->remote_irk->list);
659 kfree(smp->remote_irk); 659 kfree_rcu(smp->remote_irk, rcu);
660 smp->remote_irk = NULL; 660 smp->remote_irk = NULL;
661 } 661 }
662 } 662 }
@@ -1696,7 +1696,7 @@ int smp_register(struct hci_dev *hdev)
1696 1696
1697 BT_DBG("%s", hdev->name); 1697 BT_DBG("%s", hdev->name);
1698 1698
1699 tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); 1699 tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, 0);
1700 if (IS_ERR(tfm_aes)) { 1700 if (IS_ERR(tfm_aes)) {
1701 int err = PTR_ERR(tfm_aes); 1701 int err = PTR_ERR(tfm_aes);
1702 BT_ERR("Unable to create crypto context"); 1702 BT_ERR("Unable to create crypto context");