diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2008-04-17 19:03:36 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-05-07 15:02:11 -0400 |
commit | 3ec47732a0be038f15a0b8d852a4e4ff9c5b0196 (patch) | |
tree | 2cb45a6582df77a571554850152256df611ce094 /drivers/net/wireless/iwlwifi/iwl-sta.c | |
parent | c6adbd2158fee972adcc6232de5e2ef375f1f782 (diff) |
iwlwifi: HW crypto acceleration fixes
This patch fixes several issues in security:
1) the uCode doesn't know about TKIP-MMIC failure, if uCode set
RX_RES_STATUS_BAD_ICV_MIC, it means ICV failure: drop the packet silently.
2) do not allocate room in the key table of the uCode is the set_key call
is a replacement of an old key
3) check the keyidx of the key in the uCode before removing it upon
disable_key call
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 53 |
1 files changed, 44 insertions, 9 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index fa463ce6399b..d39ac1cffb57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -207,10 +207,14 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, | |||
207 | memcpy(&priv->stations[sta_id].sta.key.key[3], | 207 | memcpy(&priv->stations[sta_id].sta.key.key[3], |
208 | keyconf->key, keyconf->keylen); | 208 | keyconf->key, keyconf->keylen); |
209 | 209 | ||
210 | priv->stations[sta_id].sta.key.key_offset = | 210 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) |
211 | == STA_KEY_FLG_NO_ENC) | ||
212 | priv->stations[sta_id].sta.key.key_offset = | ||
211 | iwl_get_free_ucode_key_index(priv); | 213 | iwl_get_free_ucode_key_index(priv); |
212 | priv->stations[sta_id].sta.key.key_flags = key_flags; | 214 | /* else, we are overriding an existing key => no need to allocated room |
215 | * in uCode. */ | ||
213 | 216 | ||
217 | priv->stations[sta_id].sta.key.key_flags = key_flags; | ||
214 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | 218 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; |
215 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 219 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
216 | 220 | ||
@@ -249,8 +253,13 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, | |||
249 | memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, | 253 | memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, |
250 | keyconf->keylen); | 254 | keyconf->keylen); |
251 | 255 | ||
252 | priv->stations[sta_id].sta.key.key_offset = | 256 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) |
253 | iwl_get_free_ucode_key_index(priv); | 257 | == STA_KEY_FLG_NO_ENC) |
258 | priv->stations[sta_id].sta.key.key_offset = | ||
259 | iwl_get_free_ucode_key_index(priv); | ||
260 | /* else, we are overriding an existing key => no need to allocated room | ||
261 | * in uCode. */ | ||
262 | |||
254 | priv->stations[sta_id].sta.key.key_flags = key_flags; | 263 | priv->stations[sta_id].sta.key.key_flags = key_flags; |
255 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | 264 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; |
256 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 265 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
@@ -278,8 +287,13 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, | |||
278 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; | 287 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; |
279 | priv->stations[sta_id].keyinfo.conf = keyconf; | 288 | priv->stations[sta_id].keyinfo.conf = keyconf; |
280 | priv->stations[sta_id].keyinfo.keylen = 16; | 289 | priv->stations[sta_id].keyinfo.keylen = 16; |
281 | priv->stations[sta_id].sta.key.key_offset = | 290 | |
291 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) | ||
292 | == STA_KEY_FLG_NO_ENC) | ||
293 | priv->stations[sta_id].sta.key.key_offset = | ||
282 | iwl_get_free_ucode_key_index(priv); | 294 | iwl_get_free_ucode_key_index(priv); |
295 | /* else, we are overriding an existing key => no need to allocated room | ||
296 | * in uCode. */ | ||
283 | 297 | ||
284 | /* This copy is acutally not needed: we get the key with each TX */ | 298 | /* This copy is acutally not needed: we get the key with each TX */ |
285 | memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); | 299 | memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); |
@@ -291,13 +305,31 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, | |||
291 | return ret; | 305 | return ret; |
292 | } | 306 | } |
293 | 307 | ||
294 | int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id) | 308 | int iwl_remove_dynamic_key(struct iwl_priv *priv, |
309 | struct ieee80211_key_conf *keyconf, | ||
310 | u8 sta_id) | ||
295 | { | 311 | { |
296 | unsigned long flags; | 312 | unsigned long flags; |
313 | int ret = 0; | ||
314 | u16 key_flags; | ||
315 | u8 keyidx; | ||
297 | 316 | ||
298 | priv->key_mapping_key = 0; | 317 | priv->key_mapping_key = 0; |
299 | 318 | ||
300 | spin_lock_irqsave(&priv->sta_lock, flags); | 319 | spin_lock_irqsave(&priv->sta_lock, flags); |
320 | key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); | ||
321 | keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3; | ||
322 | |||
323 | if (keyconf->keyidx != keyidx) { | ||
324 | /* We need to remove a key with index different that the one | ||
325 | * in the uCode. This means that the key we need to remove has | ||
326 | * been replaced by another one with different index. | ||
327 | * Don't do anything and return ok | ||
328 | */ | ||
329 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
301 | if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset, | 333 | if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset, |
302 | &priv->ucode_key_table)) | 334 | &priv->ucode_key_table)) |
303 | IWL_ERROR("index %d not used in uCode key table.\n", | 335 | IWL_ERROR("index %d not used in uCode key table.\n", |
@@ -306,13 +338,16 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id) | |||
306 | sizeof(struct iwl4965_hw_key)); | 338 | sizeof(struct iwl4965_hw_key)); |
307 | memset(&priv->stations[sta_id].sta.key, 0, | 339 | memset(&priv->stations[sta_id].sta.key, 0, |
308 | sizeof(struct iwl4965_keyinfo)); | 340 | sizeof(struct iwl4965_keyinfo)); |
309 | priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; | 341 | priv->stations[sta_id].sta.key.key_flags = |
342 | STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; | ||
343 | priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; | ||
310 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | 344 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; |
311 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 345 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
312 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
313 | 346 | ||
314 | IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); | 347 | IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); |
315 | return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); | 348 | ret = iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); |
349 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
350 | return ret; | ||
316 | } | 351 | } |
317 | 352 | ||
318 | int iwl_set_dynamic_key(struct iwl_priv *priv, | 353 | int iwl_set_dynamic_key(struct iwl_priv *priv, |