aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorYogesh Ashok Powar <yogeshp@marvell.com>2011-06-28 09:11:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-07-05 15:26:50 -0400
commit3bff1865186c6bb97855f0c13e3850543dce9cef (patch)
tree4a9150f82cbb83a01f8fb82b3bf2d69028230928 /net/mac80211
parent252e735d64880b011f6cdeb41ebcac2eaeb58fd3 (diff)
mac80211: Skip tailroom reservation for full HW-crypto devices with race fix
Based on inputs from Johannes Berg <johannes@sipsolutions.net> from http://article.gmane.org/gmane.linux.kernel.wireless.general/68193 and http://article.gmane.org/gmane.linux.kernel.wireless.general/71702 In xmit path, devices that do full hardware crypto (including MMIC and ICV) need no tailroom. For such devices, tailroom reservation can be skipped if all the keys are programmed into the hardware (i.e software crypto is not used for any of the keys) and none of the keys wants software to generate Michael MIC and IV. v2: Added check for IV along with MMIC. Reported-by: Fabio Rossi <rossi.f@inwind.it> Tested-by: Fabio Rossi <rossi.f@inwind.it> Signed-off-by: Mohammed Shafi Shajakhan <mshajakhan@atheros.com> Cc: Mohammed Shafi Shajakhan <mshajakhan@atheros.com> v3: Fixing races to avoid WARNING: at net/mac80211/wpa.c:397 ccmp_encrypt_skb+0xc4/0x1f0 Reported-by: Andreas Hartmann <andihartmann@01019freenet.de> Tested-by: Andreas Hartmann <andihartmann@01019freenet.de> v4: Added links with message ID Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/key.c51
-rw-r--r--net/mac80211/tx.c14
3 files changed, 57 insertions, 11 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 25c15cc6331..4f2e424e8b1 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -544,6 +544,9 @@ struct ieee80211_sub_if_data {
544 /* keys */ 544 /* keys */
545 struct list_head key_list; 545 struct list_head key_list;
546 546
547 /* count for keys needing tailroom space allocation */
548 int crypto_tx_tailroom_needed_cnt;
549
547 struct net_device *dev; 550 struct net_device *dev;
548 struct ieee80211_local *local; 551 struct ieee80211_local *local;
549 552
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index f825e2f0a57..0af958c7434 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -61,6 +61,36 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
61 return NULL; 61 return NULL;
62} 62}
63 63
64static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
65{
66 /*
67 * When this count is zero, SKB resizing for allocating tailroom
68 * for IV or MMIC is skipped. But, this check has created two race
69 * cases in xmit path while transiting from zero count to one:
70 *
71 * 1. SKB resize was skipped because no key was added but just before
72 * the xmit key is added and SW encryption kicks off.
73 *
74 * 2. SKB resize was skipped because all the keys were hw planted but
75 * just before xmit one of the key is deleted and SW encryption kicks
76 * off.
77 *
78 * In both the above case SW encryption will find not enough space for
79 * tailroom and exits with WARN_ON. (See WARN_ONs at wpa.c)
80 *
81 * Solution has been explained at
82 * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
83 */
84
85 if (!sdata->crypto_tx_tailroom_needed_cnt++) {
86 /*
87 * Flush all XMIT packets currently using HW encryption or no
88 * encryption at all if the count transition is from 0 -> 1.
89 */
90 synchronize_net();
91 }
92}
93
64static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) 94static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
65{ 95{
66 struct ieee80211_sub_if_data *sdata; 96 struct ieee80211_sub_if_data *sdata;
@@ -101,6 +131,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
101 131
102 if (!ret) { 132 if (!ret) {
103 key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; 133 key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
134
135 if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
136 (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
137 sdata->crypto_tx_tailroom_needed_cnt--;
138
104 return 0; 139 return 0;
105 } 140 }
106 141
@@ -142,6 +177,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
142 sta = get_sta_for_key(key); 177 sta = get_sta_for_key(key);
143 sdata = key->sdata; 178 sdata = key->sdata;
144 179
180 if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
181 (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
182 increment_tailroom_need_count(sdata);
183
145 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 184 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
146 sdata = container_of(sdata->bss, 185 sdata = container_of(sdata->bss,
147 struct ieee80211_sub_if_data, 186 struct ieee80211_sub_if_data,
@@ -394,8 +433,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
394 ieee80211_aes_key_free(key->u.ccmp.tfm); 433 ieee80211_aes_key_free(key->u.ccmp.tfm);
395 if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) 434 if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
396 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); 435 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
397 if (key->local) 436 if (key->local) {
398 ieee80211_debugfs_key_remove(key); 437 ieee80211_debugfs_key_remove(key);
438 key->sdata->crypto_tx_tailroom_needed_cnt--;
439 }
399 440
400 kfree(key); 441 kfree(key);
401} 442}
@@ -452,6 +493,8 @@ int ieee80211_key_link(struct ieee80211_key *key,
452 else 493 else
453 old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); 494 old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
454 495
496 increment_tailroom_need_count(sdata);
497
455 __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); 498 __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
456 __ieee80211_key_destroy(old_key); 499 __ieee80211_key_destroy(old_key);
457 500
@@ -498,8 +541,12 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
498 541
499 mutex_lock(&sdata->local->key_mtx); 542 mutex_lock(&sdata->local->key_mtx);
500 543
501 list_for_each_entry(key, &sdata->key_list, list) 544 sdata->crypto_tx_tailroom_needed_cnt = 0;
545
546 list_for_each_entry(key, &sdata->key_list, list) {
547 increment_tailroom_need_count(sdata);
502 ieee80211_key_enable_hw_accel(key); 548 ieee80211_key_enable_hw_accel(key);
549 }
503 550
504 mutex_unlock(&sdata->local->key_mtx); 551 mutex_unlock(&sdata->local->key_mtx);
505} 552}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3104c844b54..e8d0d2d2266 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1474,18 +1474,14 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
1474 1474
1475/* device xmit handlers */ 1475/* device xmit handlers */
1476 1476
1477static int ieee80211_skb_resize(struct ieee80211_local *local, 1477static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
1478 struct sk_buff *skb, 1478 struct sk_buff *skb,
1479 int head_need, bool may_encrypt) 1479 int head_need, bool may_encrypt)
1480{ 1480{
1481 struct ieee80211_local *local = sdata->local;
1481 int tail_need = 0; 1482 int tail_need = 0;
1482 1483
1483 /* 1484 if (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt) {
1484 * This could be optimised, devices that do full hardware
1485 * crypto (including TKIP MMIC) need no tailroom... But we
1486 * have no drivers for such devices currently.
1487 */
1488 if (may_encrypt) {
1489 tail_need = IEEE80211_ENCRYPT_TAILROOM; 1485 tail_need = IEEE80211_ENCRYPT_TAILROOM;
1490 tail_need -= skb_tailroom(skb); 1486 tail_need -= skb_tailroom(skb);
1491 tail_need = max_t(int, tail_need, 0); 1487 tail_need = max_t(int, tail_need, 0);
@@ -1578,7 +1574,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
1578 headroom -= skb_headroom(skb); 1574 headroom -= skb_headroom(skb);
1579 headroom = max_t(int, 0, headroom); 1575 headroom = max_t(int, 0, headroom);
1580 1576
1581 if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) { 1577 if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
1582 dev_kfree_skb(skb); 1578 dev_kfree_skb(skb);
1583 rcu_read_unlock(); 1579 rcu_read_unlock();
1584 return; 1580 return;
@@ -1945,7 +1941,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
1945 head_need += IEEE80211_ENCRYPT_HEADROOM; 1941 head_need += IEEE80211_ENCRYPT_HEADROOM;
1946 head_need += local->tx_headroom; 1942 head_need += local->tx_headroom;
1947 head_need = max_t(int, 0, head_need); 1943 head_need = max_t(int, 0, head_need);
1948 if (ieee80211_skb_resize(local, skb, head_need, true)) 1944 if (ieee80211_skb_resize(sdata, skb, head_need, true))
1949 goto fail; 1945 goto fail;
1950 } 1946 }
1951 1947