aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/key.c
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/key.c
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/key.c')
-rw-r--r--net/mac80211/key.c51
1 files changed, 49 insertions, 2 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index f825e2f0a57e..0af958c74342 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}