diff options
| -rw-r--r-- | include/net/mac80211.h | 12 | ||||
| -rw-r--r-- | net/mac80211/key.c | 10 | ||||
| -rw-r--r-- | net/mac80211/main.c | 65 |
3 files changed, 58 insertions, 29 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 275ee56152ad..33b87c50a4cf 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
| @@ -1634,6 +1634,12 @@ struct ieee80211_tx_control { | |||
| 1634 | * be created. It is expected user-space will create vifs as | 1634 | * be created. It is expected user-space will create vifs as |
| 1635 | * desired (and thus have them named as desired). | 1635 | * desired (and thus have them named as desired). |
| 1636 | * | 1636 | * |
| 1637 | * @IEEE80211_HW_SW_CRYPTO_CONTROL: The driver wants to control which of the | ||
| 1638 | * crypto algorithms can be done in software - so don't automatically | ||
| 1639 | * try to fall back to it if hardware crypto fails, but do so only if | ||
| 1640 | * the driver returns 1. This also forces the driver to advertise its | ||
| 1641 | * supported cipher suites. | ||
| 1642 | * | ||
| 1637 | * @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface | 1643 | * @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface |
| 1638 | * queue mapping in order to use different queues (not just one per AC) | 1644 | * queue mapping in order to use different queues (not just one per AC) |
| 1639 | * for different virtual interfaces. See the doc section on HW queue | 1645 | * for different virtual interfaces. See the doc section on HW queue |
| @@ -1681,6 +1687,7 @@ enum ieee80211_hw_flags { | |||
| 1681 | IEEE80211_HW_MFP_CAPABLE = 1<<13, | 1687 | IEEE80211_HW_MFP_CAPABLE = 1<<13, |
| 1682 | IEEE80211_HW_WANT_MONITOR_VIF = 1<<14, | 1688 | IEEE80211_HW_WANT_MONITOR_VIF = 1<<14, |
| 1683 | IEEE80211_HW_NO_AUTO_VIF = 1<<15, | 1689 | IEEE80211_HW_NO_AUTO_VIF = 1<<15, |
| 1690 | IEEE80211_HW_SW_CRYPTO_CONTROL = 1<<16, | ||
| 1684 | /* free slots */ | 1691 | /* free slots */ |
| 1685 | IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, | 1692 | IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, |
| 1686 | IEEE80211_HW_CONNECTION_MONITOR = 1<<19, | 1693 | IEEE80211_HW_CONNECTION_MONITOR = 1<<19, |
| @@ -1955,6 +1962,11 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); | |||
| 1955 | * added; if you return 0 then hw_key_idx must be assigned to the | 1962 | * added; if you return 0 then hw_key_idx must be assigned to the |
| 1956 | * hardware key index, you are free to use the full u8 range. | 1963 | * hardware key index, you are free to use the full u8 range. |
| 1957 | * | 1964 | * |
| 1965 | * Note that in the case that the @IEEE80211_HW_SW_CRYPTO_CONTROL flag is | ||
| 1966 | * set, mac80211 will not automatically fall back to software crypto if | ||
| 1967 | * enabling hardware crypto failed. The set_key() call may also return the | ||
| 1968 | * value 1 to permit this specific key/algorithm to be done in software. | ||
| 1969 | * | ||
| 1958 | * When the cmd is %DISABLE_KEY then it must succeed. | 1970 | * When the cmd is %DISABLE_KEY then it must succeed. |
| 1959 | * | 1971 | * |
| 1960 | * Note that it is permissible to not decrypt a frame even if a key | 1972 | * Note that it is permissible to not decrypt a frame even if a key |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f8d9f0ee59bf..5167c53aa15f 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
| @@ -90,7 +90,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
| 90 | { | 90 | { |
| 91 | struct ieee80211_sub_if_data *sdata; | 91 | struct ieee80211_sub_if_data *sdata; |
| 92 | struct sta_info *sta; | 92 | struct sta_info *sta; |
| 93 | int ret; | 93 | int ret = -EOPNOTSUPP; |
| 94 | 94 | ||
| 95 | might_sleep(); | 95 | might_sleep(); |
| 96 | 96 | ||
| @@ -150,7 +150,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
| 150 | return 0; | 150 | return 0; |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | if (ret != -ENOSPC && ret != -EOPNOTSUPP) | 153 | if (ret != -ENOSPC && ret != -EOPNOTSUPP && ret != 1) |
| 154 | sdata_err(sdata, | 154 | sdata_err(sdata, |
| 155 | "failed to set key (%d, %pM) to hardware (%d)\n", | 155 | "failed to set key (%d, %pM) to hardware (%d)\n", |
| 156 | key->conf.keyidx, | 156 | key->conf.keyidx, |
| @@ -163,7 +163,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
| 163 | case WLAN_CIPHER_SUITE_TKIP: | 163 | case WLAN_CIPHER_SUITE_TKIP: |
| 164 | case WLAN_CIPHER_SUITE_CCMP: | 164 | case WLAN_CIPHER_SUITE_CCMP: |
| 165 | case WLAN_CIPHER_SUITE_AES_CMAC: | 165 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 166 | /* all of these we can do in software */ | 166 | /* all of these we can do in software - if driver can */ |
| 167 | if (ret == 1) | ||
| 168 | return 0; | ||
| 169 | if (key->local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL) | ||
| 170 | return -EINVAL; | ||
| 167 | return 0; | 171 | return 0; |
| 168 | default: | 172 | default: |
| 169 | return -EINVAL; | 173 | return -EINVAL; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 46264cb6604b..ea6b82ac4f0b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -658,7 +658,6 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
| 658 | bool have_wep = !(IS_ERR(local->wep_tx_tfm) || | 658 | bool have_wep = !(IS_ERR(local->wep_tx_tfm) || |
| 659 | IS_ERR(local->wep_rx_tfm)); | 659 | IS_ERR(local->wep_rx_tfm)); |
| 660 | bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE; | 660 | bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE; |
| 661 | const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes; | ||
| 662 | int n_suites = 0, r = 0, w = 0; | 661 | int n_suites = 0, r = 0, w = 0; |
| 663 | u32 *suites; | 662 | u32 *suites; |
| 664 | static const u32 cipher_suites[] = { | 663 | static const u32 cipher_suites[] = { |
| @@ -672,12 +671,38 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
| 672 | WLAN_CIPHER_SUITE_AES_CMAC | 671 | WLAN_CIPHER_SUITE_AES_CMAC |
| 673 | }; | 672 | }; |
| 674 | 673 | ||
| 675 | /* Driver specifies the ciphers, we have nothing to do... */ | 674 | if (local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL || |
| 676 | if (local->hw.wiphy->cipher_suites && have_wep) | 675 | local->hw.wiphy->cipher_suites) { |
| 677 | return 0; | 676 | /* If the driver advertises, or doesn't support SW crypto, |
| 677 | * we only need to remove WEP if necessary. | ||
| 678 | */ | ||
| 679 | if (have_wep) | ||
| 680 | return 0; | ||
| 681 | |||
| 682 | /* well if it has _no_ ciphers ... fine */ | ||
| 683 | if (!local->hw.wiphy->n_cipher_suites) | ||
| 684 | return 0; | ||
| 685 | |||
| 686 | /* Driver provides cipher suites, but we need to exclude WEP */ | ||
| 687 | suites = kmemdup(local->hw.wiphy->cipher_suites, | ||
| 688 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
| 689 | GFP_KERNEL); | ||
| 690 | if (!suites) | ||
| 691 | return -ENOMEM; | ||
| 678 | 692 | ||
| 679 | /* Set up cipher suites if driver relies on mac80211 cipher defs */ | 693 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { |
| 680 | if (!local->hw.wiphy->cipher_suites && !cs) { | 694 | u32 suite = local->hw.wiphy->cipher_suites[r]; |
| 695 | |||
| 696 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
| 697 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
| 698 | continue; | ||
| 699 | suites[w++] = suite; | ||
| 700 | } | ||
| 701 | } else if (!local->hw.cipher_schemes) { | ||
| 702 | /* If the driver doesn't have cipher schemes, there's nothing | ||
| 703 | * else to do other than assign the (software supported and | ||
| 704 | * perhaps offloaded) cipher suites. | ||
| 705 | */ | ||
| 681 | local->hw.wiphy->cipher_suites = cipher_suites; | 706 | local->hw.wiphy->cipher_suites = cipher_suites; |
| 682 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 707 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
| 683 | 708 | ||
| @@ -689,12 +714,16 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
| 689 | local->hw.wiphy->n_cipher_suites -= 2; | 714 | local->hw.wiphy->n_cipher_suites -= 2; |
| 690 | } | 715 | } |
| 691 | 716 | ||
| 717 | /* not dynamically allocated, so just return */ | ||
| 692 | return 0; | 718 | return 0; |
| 693 | } | 719 | } else { |
| 720 | const struct ieee80211_cipher_scheme *cs; | ||
| 694 | 721 | ||
| 695 | if (!local->hw.wiphy->cipher_suites) { | 722 | cs = local->hw.cipher_schemes; |
| 696 | /* | 723 | |
| 697 | * Driver specifies cipher schemes only | 724 | /* Driver specifies cipher schemes only (but not cipher suites |
| 725 | * including the schemes) | ||
| 726 | * | ||
| 698 | * We start counting ciphers defined by schemes, TKIP and CCMP | 727 | * We start counting ciphers defined by schemes, TKIP and CCMP |
| 699 | */ | 728 | */ |
| 700 | n_suites = local->hw.n_cipher_schemes + 2; | 729 | n_suites = local->hw.n_cipher_schemes + 2; |
| @@ -724,22 +753,6 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
| 724 | 753 | ||
| 725 | for (r = 0; r < local->hw.n_cipher_schemes; r++) | 754 | for (r = 0; r < local->hw.n_cipher_schemes; r++) |
| 726 | suites[w++] = cs[r].cipher; | 755 | suites[w++] = cs[r].cipher; |
| 727 | } else { | ||
| 728 | /* Driver provides cipher suites, but we need to exclude WEP */ | ||
| 729 | suites = kmemdup(local->hw.wiphy->cipher_suites, | ||
| 730 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
| 731 | GFP_KERNEL); | ||
| 732 | if (!suites) | ||
| 733 | return -ENOMEM; | ||
| 734 | |||
| 735 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { | ||
| 736 | u32 suite = local->hw.wiphy->cipher_suites[r]; | ||
| 737 | |||
| 738 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
| 739 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
| 740 | continue; | ||
| 741 | suites[w++] = suite; | ||
| 742 | } | ||
| 743 | } | 756 | } |
| 744 | 757 | ||
| 745 | local->hw.wiphy->cipher_suites = suites; | 758 | local->hw.wiphy->cipher_suites = suites; |
