diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2008-05-15 01:54:09 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-05-21 21:48:01 -0400 |
commit | ccc038abe4cb00cf56aeae5b1df47fcc4ed4136c (patch) | |
tree | 0c35fec8a1c9e7179f9b756d30c3f8af02d9bfa5 | |
parent | a98410139a2ef6553ae5d73bf12bb9a68d0b38b9 (diff) |
iwlwifi: clean up and bug fix for security
This patch cleans up code in security.
1) uses the new pointer to ieee80211_key_conf passed with the tx_control.
2) resolves bug reported by Mirco Tischler (sends ADD_STA in ASYNC mode)
3) resolves bug reported by Volker Braun regarding dynamic WEP
4) drops a WEP packet which has been garbaged by firmware. This can
happen upon rekeying.
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>
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-tx.c | 41 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl4965-base.c | 3 |
6 files changed, 29 insertions, 46 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8f0852d058e5..52c7eae08d44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -2389,6 +2389,7 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, | |||
2389 | RX_RES_STATUS_BAD_KEY_TTAK) | 2389 | RX_RES_STATUS_BAD_KEY_TTAK) |
2390 | break; | 2390 | break; |
2391 | 2391 | ||
2392 | case RX_RES_STATUS_SEC_TYPE_WEP: | ||
2392 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | 2393 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == |
2393 | RX_RES_STATUS_BAD_ICV_MIC) { | 2394 | RX_RES_STATUS_BAD_ICV_MIC) { |
2394 | /* bad ICV, the packet is destroyed since the | 2395 | /* bad ICV, the packet is destroyed since the |
@@ -2396,7 +2397,6 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv, | |||
2396 | IWL_DEBUG_RX("Packet destroyed\n"); | 2397 | IWL_DEBUG_RX("Packet destroyed\n"); |
2397 | return -1; | 2398 | return -1; |
2398 | } | 2399 | } |
2399 | case RX_RES_STATUS_SEC_TYPE_WEP: | ||
2400 | case RX_RES_STATUS_SEC_TYPE_CCMP: | 2400 | case RX_RES_STATUS_SEC_TYPE_CCMP: |
2401 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | 2401 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == |
2402 | RX_RES_STATUS_DECRYPT_OK) { | 2402 | RX_RES_STATUS_DECRYPT_OK) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7a54682a3d86..305491ff9beb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -442,7 +442,6 @@ struct iwl_hw_key { | |||
442 | enum ieee80211_key_alg alg; | 442 | enum ieee80211_key_alg alg; |
443 | int keylen; | 443 | int keylen; |
444 | u8 keyidx; | 444 | u8 keyidx; |
445 | struct ieee80211_key_conf *conf; | ||
446 | u8 key[32]; | 445 | u8 key[32]; |
447 | }; | 446 | }; |
448 | 447 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index c8e468fb3caa..99ee1e14e29e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -324,7 +324,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, | |||
324 | unsigned long flags; | 324 | unsigned long flags; |
325 | 325 | ||
326 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; | 326 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; |
327 | keyconf->hw_key_idx = keyconf->keyidx; | 327 | keyconf->hw_key_idx = HW_KEY_DEFAULT; |
328 | priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; | 328 | priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; |
329 | 329 | ||
330 | spin_lock_irqsave(&priv->sta_lock, flags); | 330 | spin_lock_irqsave(&priv->sta_lock, flags); |
@@ -354,7 +354,6 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, | |||
354 | int ret; | 354 | int ret; |
355 | 355 | ||
356 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; | 356 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; |
357 | keyconf->hw_key_idx = keyconf->keyidx; | ||
358 | 357 | ||
359 | key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); | 358 | key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); |
360 | key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); | 359 | key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); |
@@ -411,7 +410,6 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, | |||
411 | key_flags |= STA_KEY_MULTICAST_MSK; | 410 | key_flags |= STA_KEY_MULTICAST_MSK; |
412 | 411 | ||
413 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 412 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
414 | keyconf->hw_key_idx = keyconf->keyidx; | ||
415 | 413 | ||
416 | spin_lock_irqsave(&priv->sta_lock, flags); | 414 | spin_lock_irqsave(&priv->sta_lock, flags); |
417 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; | 415 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; |
@@ -449,12 +447,10 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, | |||
449 | 447 | ||
450 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 448 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
451 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 449 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
452 | keyconf->hw_key_idx = keyconf->keyidx; | ||
453 | 450 | ||
454 | spin_lock_irqsave(&priv->sta_lock, flags); | 451 | spin_lock_irqsave(&priv->sta_lock, flags); |
455 | 452 | ||
456 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; | 453 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; |
457 | priv->stations[sta_id].keyinfo.conf = keyconf; | ||
458 | priv->stations[sta_id].keyinfo.keylen = 16; | 454 | priv->stations[sta_id].keyinfo.keylen = 16; |
459 | 455 | ||
460 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) | 456 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) |
@@ -483,7 +479,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, | |||
483 | u16 key_flags; | 479 | u16 key_flags; |
484 | u8 keyidx; | 480 | u8 keyidx; |
485 | 481 | ||
486 | priv->key_mapping_key = 0; | 482 | priv->key_mapping_key--; |
487 | 483 | ||
488 | spin_lock_irqsave(&priv->sta_lock, flags); | 484 | spin_lock_irqsave(&priv->sta_lock, flags); |
489 | key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); | 485 | key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); |
@@ -514,31 +510,32 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, | |||
514 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 510 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
515 | 511 | ||
516 | IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); | 512 | IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); |
517 | ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); | 513 | ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); |
518 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 514 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
519 | return ret; | 515 | return ret; |
520 | } | 516 | } |
521 | EXPORT_SYMBOL(iwl_remove_dynamic_key); | 517 | EXPORT_SYMBOL(iwl_remove_dynamic_key); |
522 | 518 | ||
523 | int iwl_set_dynamic_key(struct iwl_priv *priv, | 519 | int iwl_set_dynamic_key(struct iwl_priv *priv, |
524 | struct ieee80211_key_conf *key, u8 sta_id) | 520 | struct ieee80211_key_conf *keyconf, u8 sta_id) |
525 | { | 521 | { |
526 | int ret; | 522 | int ret; |
527 | 523 | ||
528 | priv->key_mapping_key = 1; | 524 | priv->key_mapping_key++; |
525 | keyconf->hw_key_idx = HW_KEY_DYNAMIC; | ||
529 | 526 | ||
530 | switch (key->alg) { | 527 | switch (keyconf->alg) { |
531 | case ALG_CCMP: | 528 | case ALG_CCMP: |
532 | ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id); | 529 | ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id); |
533 | break; | 530 | break; |
534 | case ALG_TKIP: | 531 | case ALG_TKIP: |
535 | ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id); | 532 | ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id); |
536 | break; | 533 | break; |
537 | case ALG_WEP: | 534 | case ALG_WEP: |
538 | ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id); | 535 | ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id); |
539 | break; | 536 | break; |
540 | default: | 537 | default: |
541 | IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg); | 538 | IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg); |
542 | ret = -EINVAL; | 539 | ret = -EINVAL; |
543 | } | 540 | } |
544 | 541 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index ee2564307084..b643546961f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h | |||
@@ -29,6 +29,9 @@ | |||
29 | #ifndef __iwl_sta_h__ | 29 | #ifndef __iwl_sta_h__ |
30 | #define __iwl_sta_h__ | 30 | #define __iwl_sta_h__ |
31 | 31 | ||
32 | #define HW_KEY_DYNAMIC 0 | ||
33 | #define HW_KEY_DEFAULT 1 | ||
34 | |||
32 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv); | 35 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv); |
33 | int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty); | 36 | int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty); |
34 | int iwl_remove_default_wep_key(struct iwl_priv *priv, | 37 | int iwl_remove_default_wep_key(struct iwl_priv *priv, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a37ced58c661..f32cddabdf64 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -639,16 +639,12 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, | |||
639 | struct sk_buff *skb_frag, | 639 | struct sk_buff *skb_frag, |
640 | int sta_id) | 640 | int sta_id) |
641 | { | 641 | { |
642 | struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; | 642 | struct ieee80211_key_conf *keyconf = ctl->hw_key; |
643 | struct iwl_wep_key *wepkey; | ||
644 | int keyidx = 0; | ||
645 | 643 | ||
646 | BUG_ON(ctl->hw_key->hw_key_idx > 3); | 644 | switch (keyconf->alg) { |
647 | |||
648 | switch (keyinfo->alg) { | ||
649 | case ALG_CCMP: | 645 | case ALG_CCMP: |
650 | tx_cmd->sec_ctl = TX_CMD_SEC_CCM; | 646 | tx_cmd->sec_ctl = TX_CMD_SEC_CCM; |
651 | memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen); | 647 | memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); |
652 | if (ctl->flags & IEEE80211_TXCTL_AMPDU) | 648 | if (ctl->flags & IEEE80211_TXCTL_AMPDU) |
653 | tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; | 649 | tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; |
654 | IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); | 650 | IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); |
@@ -656,39 +652,26 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, | |||
656 | 652 | ||
657 | case ALG_TKIP: | 653 | case ALG_TKIP: |
658 | tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; | 654 | tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; |
659 | ieee80211_get_tkip_key(keyinfo->conf, skb_frag, | 655 | ieee80211_get_tkip_key(keyconf, skb_frag, |
660 | IEEE80211_TKIP_P2_KEY, tx_cmd->key); | 656 | IEEE80211_TKIP_P2_KEY, tx_cmd->key); |
661 | IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); | 657 | IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n"); |
662 | break; | 658 | break; |
663 | 659 | ||
664 | case ALG_WEP: | 660 | case ALG_WEP: |
665 | wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx]; | ||
666 | tx_cmd->sec_ctl = 0; | ||
667 | if (priv->default_wep_key) { | ||
668 | /* the WEP key was sent as static */ | ||
669 | keyidx = ctl->hw_key->hw_key_idx; | ||
670 | memcpy(&tx_cmd->key[3], wepkey->key, | ||
671 | wepkey->key_size); | ||
672 | if (wepkey->key_size == WEP_KEY_LEN_128) | ||
673 | tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; | ||
674 | } else { | ||
675 | /* the WEP key was sent as dynamic */ | ||
676 | keyidx = keyinfo->keyidx; | ||
677 | memcpy(&tx_cmd->key[3], keyinfo->key, | ||
678 | keyinfo->keylen); | ||
679 | if (keyinfo->keylen == WEP_KEY_LEN_128) | ||
680 | tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; | ||
681 | } | ||
682 | |||
683 | tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP | | 661 | tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP | |
684 | (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); | 662 | (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); |
663 | |||
664 | if (keyconf->keylen == WEP_KEY_LEN_128) | ||
665 | tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; | ||
666 | |||
667 | memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); | ||
685 | 668 | ||
686 | IWL_DEBUG_TX("Configuring packet for WEP encryption " | 669 | IWL_DEBUG_TX("Configuring packet for WEP encryption " |
687 | "with key %d\n", keyidx); | 670 | "with key %d\n", keyconf->keyidx); |
688 | break; | 671 | break; |
689 | 672 | ||
690 | default: | 673 | default: |
691 | printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg); | 674 | printk(KERN_ERR "Unknown encode alg %d\n", keyconf->alg); |
692 | break; | 675 | break; |
693 | } | 676 | } |
694 | } | 677 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index a532a9e576dc..40616dbd26f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c | |||
@@ -4951,7 +4951,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
4951 | if (cmd == SET_KEY) | 4951 | if (cmd == SET_KEY) |
4952 | is_default_wep_key = !priv->key_mapping_key; | 4952 | is_default_wep_key = !priv->key_mapping_key; |
4953 | else | 4953 | else |
4954 | is_default_wep_key = priv->default_wep_key; | 4954 | is_default_wep_key = |
4955 | (key->hw_key_idx == HW_KEY_DEFAULT); | ||
4955 | } | 4956 | } |
4956 | 4957 | ||
4957 | switch (cmd) { | 4958 | switch (cmd) { |