diff options
author | Eliad Peller <eliad@wizery.com> | 2012-09-03 11:27:58 -0400 |
---|---|---|
committer | Luciano Coelho <luca@coelho.fi> | 2012-09-27 05:13:54 -0400 |
commit | af390f4dd35373b3ca32bafc12d7f2ad12840529 (patch) | |
tree | 692652e15a9aed463e43f40aa351b4d640789faa /drivers | |
parent | ab2c4f37dcef5bd517a95a32da50d5ed0cc24cb5 (diff) |
wlcore: protect wlcore_op_set_key with mutex
wlcore_op_set_key() calls wl18xx_set_key(),
which in turn executes some of his function
calls without acquiring wl->mutex and making
sure the fw is awake.
Adding mutex_lock()/ps_elp_wakeup() calls is
not enough, as wl18xx_set_key() calls
wl1271_tx_flush() which can't be called while
the mutex is taken.
Add the required calls to wlcore_op_set_key,
but limit the queues_stop and flushing
to the only encryption types in which
a spare block might be needed (GEM and TKIP).
[Arik - move state != ON check]
Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <luca@coelho.fi>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ti/wl18xx/main.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/main.c | 68 |
2 files changed, 43 insertions, 33 deletions
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 9e3e10a13498..a39682a7c25f 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c | |||
@@ -1252,13 +1252,6 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
1252 | if (!change_spare) | 1252 | if (!change_spare) |
1253 | return wlcore_set_key(wl, cmd, vif, sta, key_conf); | 1253 | return wlcore_set_key(wl, cmd, vif, sta, key_conf); |
1254 | 1254 | ||
1255 | /* | ||
1256 | * stop the queues and flush to ensure the next packets are | ||
1257 | * in sync with FW spare block accounting | ||
1258 | */ | ||
1259 | wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); | ||
1260 | wl1271_tx_flush(wl); | ||
1261 | |||
1262 | ret = wlcore_set_key(wl, cmd, vif, sta, key_conf); | 1255 | ret = wlcore_set_key(wl, cmd, vif, sta, key_conf); |
1263 | if (ret < 0) | 1256 | if (ret < 0) |
1264 | goto out; | 1257 | goto out; |
@@ -1281,7 +1274,6 @@ static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
1281 | } | 1274 | } |
1282 | 1275 | ||
1283 | out: | 1276 | out: |
1284 | wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); | ||
1285 | return ret; | 1277 | return ret; |
1286 | } | 1278 | } |
1287 | 1279 | ||
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 6ada018fe4a4..25530c8760cb 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -3063,8 +3063,45 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3063 | struct ieee80211_key_conf *key_conf) | 3063 | struct ieee80211_key_conf *key_conf) |
3064 | { | 3064 | { |
3065 | struct wl1271 *wl = hw->priv; | 3065 | struct wl1271 *wl = hw->priv; |
3066 | int ret; | ||
3067 | bool might_change_spare = | ||
3068 | key_conf->cipher == WL1271_CIPHER_SUITE_GEM || | ||
3069 | key_conf->cipher == WLAN_CIPHER_SUITE_TKIP; | ||
3070 | |||
3071 | if (might_change_spare) { | ||
3072 | /* | ||
3073 | * stop the queues and flush to ensure the next packets are | ||
3074 | * in sync with FW spare block accounting | ||
3075 | */ | ||
3076 | mutex_lock(&wl->mutex); | ||
3077 | wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); | ||
3078 | mutex_unlock(&wl->mutex); | ||
3079 | |||
3080 | wl1271_tx_flush(wl); | ||
3081 | } | ||
3082 | |||
3083 | mutex_lock(&wl->mutex); | ||
3084 | |||
3085 | if (unlikely(wl->state != WLCORE_STATE_ON)) { | ||
3086 | ret = -EAGAIN; | ||
3087 | goto out_wake_queues; | ||
3088 | } | ||
3066 | 3089 | ||
3067 | return wlcore_hw_set_key(wl, cmd, vif, sta, key_conf); | 3090 | ret = wl1271_ps_elp_wakeup(wl); |
3091 | if (ret < 0) | ||
3092 | goto out_wake_queues; | ||
3093 | |||
3094 | ret = wlcore_hw_set_key(wl, cmd, vif, sta, key_conf); | ||
3095 | |||
3096 | wl1271_ps_elp_sleep(wl); | ||
3097 | |||
3098 | out_wake_queues: | ||
3099 | if (might_change_spare) | ||
3100 | wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); | ||
3101 | |||
3102 | mutex_unlock(&wl->mutex); | ||
3103 | |||
3104 | return ret; | ||
3068 | } | 3105 | } |
3069 | 3106 | ||
3070 | int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | 3107 | int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, |
@@ -3086,17 +3123,6 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
3086 | key_conf->keylen, key_conf->flags); | 3123 | key_conf->keylen, key_conf->flags); |
3087 | wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); | 3124 | wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); |
3088 | 3125 | ||
3089 | mutex_lock(&wl->mutex); | ||
3090 | |||
3091 | if (unlikely(wl->state != WLCORE_STATE_ON)) { | ||
3092 | ret = -EAGAIN; | ||
3093 | goto out_unlock; | ||
3094 | } | ||
3095 | |||
3096 | ret = wl1271_ps_elp_wakeup(wl); | ||
3097 | if (ret < 0) | ||
3098 | goto out_unlock; | ||
3099 | |||
3100 | switch (key_conf->cipher) { | 3126 | switch (key_conf->cipher) { |
3101 | case WLAN_CIPHER_SUITE_WEP40: | 3127 | case WLAN_CIPHER_SUITE_WEP40: |
3102 | case WLAN_CIPHER_SUITE_WEP104: | 3128 | case WLAN_CIPHER_SUITE_WEP104: |
@@ -3126,8 +3152,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
3126 | default: | 3152 | default: |
3127 | wl1271_error("Unknown key algo 0x%x", key_conf->cipher); | 3153 | wl1271_error("Unknown key algo 0x%x", key_conf->cipher); |
3128 | 3154 | ||
3129 | ret = -EOPNOTSUPP; | 3155 | return -EOPNOTSUPP; |
3130 | goto out_sleep; | ||
3131 | } | 3156 | } |
3132 | 3157 | ||
3133 | switch (cmd) { | 3158 | switch (cmd) { |
@@ -3138,7 +3163,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
3138 | tx_seq_32, tx_seq_16, sta); | 3163 | tx_seq_32, tx_seq_16, sta); |
3139 | if (ret < 0) { | 3164 | if (ret < 0) { |
3140 | wl1271_error("Could not add or replace key"); | 3165 | wl1271_error("Could not add or replace key"); |
3141 | goto out_sleep; | 3166 | return ret; |
3142 | } | 3167 | } |
3143 | 3168 | ||
3144 | /* | 3169 | /* |
@@ -3152,7 +3177,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
3152 | ret = wl1271_cmd_build_arp_rsp(wl, wlvif); | 3177 | ret = wl1271_cmd_build_arp_rsp(wl, wlvif); |
3153 | if (ret < 0) { | 3178 | if (ret < 0) { |
3154 | wl1271_warning("build arp rsp failed: %d", ret); | 3179 | wl1271_warning("build arp rsp failed: %d", ret); |
3155 | goto out_sleep; | 3180 | return ret; |
3156 | } | 3181 | } |
3157 | } | 3182 | } |
3158 | break; | 3183 | break; |
@@ -3164,22 +3189,15 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | |||
3164 | 0, 0, sta); | 3189 | 0, 0, sta); |
3165 | if (ret < 0) { | 3190 | if (ret < 0) { |
3166 | wl1271_error("Could not remove key"); | 3191 | wl1271_error("Could not remove key"); |
3167 | goto out_sleep; | 3192 | return ret; |
3168 | } | 3193 | } |
3169 | break; | 3194 | break; |
3170 | 3195 | ||
3171 | default: | 3196 | default: |
3172 | wl1271_error("Unsupported key cmd 0x%x", cmd); | 3197 | wl1271_error("Unsupported key cmd 0x%x", cmd); |
3173 | ret = -EOPNOTSUPP; | 3198 | return -EOPNOTSUPP; |
3174 | break; | ||
3175 | } | 3199 | } |
3176 | 3200 | ||
3177 | out_sleep: | ||
3178 | wl1271_ps_elp_sleep(wl); | ||
3179 | |||
3180 | out_unlock: | ||
3181 | mutex_unlock(&wl->mutex); | ||
3182 | |||
3183 | return ret; | 3201 | return ret; |
3184 | } | 3202 | } |
3185 | EXPORT_SYMBOL_GPL(wlcore_set_key); | 3203 | EXPORT_SYMBOL_GPL(wlcore_set_key); |