diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-08-27 07:26:52 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-08-27 13:27:07 -0400 |
commit | 3ffc2a905b1faae4c0fe39d66f0752c3a4cbb3c7 (patch) | |
tree | d50902e1e171877e4fb034e36c837f16984ab9b4 | |
parent | 7d64b7cc1fc33bab24567903a93f699d11649c0b (diff) |
mac80211: allow vendor specific cipher suites
Allow drivers to specify their own set of cipher
suites to advertise vendor-specific ciphers. The
driver is then required to implement hardware
crypto offload for it.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | net/mac80211/cfg.c | 5 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/key.c | 38 | ||||
-rw-r--r-- | net/mac80211/key.h | 6 | ||||
-rw-r--r-- | net/mac80211/main.c | 44 | ||||
-rw-r--r-- | net/mac80211/rx.c | 6 | ||||
-rw-r--r-- | net/mac80211/tx.c | 12 |
7 files changed, 92 insertions, 21 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 581438255d7e..f149b4eb28d9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -119,9 +119,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
119 | } | 119 | } |
120 | } | 120 | } |
121 | 121 | ||
122 | ieee80211_key_link(key, sdata, sta); | 122 | err = ieee80211_key_link(key, sdata, sta); |
123 | if (err) | ||
124 | ieee80211_key_free(sdata->local, key); | ||
123 | 125 | ||
124 | err = 0; | ||
125 | out_unlock: | 126 | out_unlock: |
126 | mutex_unlock(&sdata->local->sta_mtx); | 127 | mutex_unlock(&sdata->local->sta_mtx); |
127 | 128 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 31713320258c..7d2bb6fbc2e6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -662,6 +662,8 @@ struct ieee80211_local { | |||
662 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll; | 662 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll; |
663 | unsigned int filter_flags; /* FIF_* */ | 663 | unsigned int filter_flags; /* FIF_* */ |
664 | 664 | ||
665 | bool wiphy_ciphers_allocated; | ||
666 | |||
665 | /* protects the aggregated multicast list and filter calls */ | 667 | /* protects the aggregated multicast list and filter calls */ |
666 | spinlock_t filter_lock; | 668 | spinlock_t filter_lock; |
667 | 669 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 2ce2dbbf6309..3570f8c2bb40 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -60,7 +60,7 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) | |||
60 | return NULL; | 60 | return NULL; |
61 | } | 61 | } |
62 | 62 | ||
63 | static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | 63 | static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) |
64 | { | 64 | { |
65 | struct ieee80211_sub_if_data *sdata; | 65 | struct ieee80211_sub_if_data *sdata; |
66 | struct ieee80211_sta *sta; | 66 | struct ieee80211_sta *sta; |
@@ -68,8 +68,10 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
68 | 68 | ||
69 | might_sleep(); | 69 | might_sleep(); |
70 | 70 | ||
71 | if (!key->local->ops->set_key) | 71 | if (!key->local->ops->set_key) { |
72 | return; | 72 | ret = -EOPNOTSUPP; |
73 | goto out_unsupported; | ||
74 | } | ||
73 | 75 | ||
74 | assert_key_lock(key->local); | 76 | assert_key_lock(key->local); |
75 | 77 | ||
@@ -90,6 +92,24 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
90 | wiphy_err(key->local->hw.wiphy, | 92 | wiphy_err(key->local->hw.wiphy, |
91 | "failed to set key (%d, %pM) to hardware (%d)\n", | 93 | "failed to set key (%d, %pM) to hardware (%d)\n", |
92 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | 94 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
95 | |||
96 | out_unsupported: | ||
97 | if (ret) { | ||
98 | switch (key->conf.cipher) { | ||
99 | case WLAN_CIPHER_SUITE_WEP40: | ||
100 | case WLAN_CIPHER_SUITE_WEP104: | ||
101 | case WLAN_CIPHER_SUITE_TKIP: | ||
102 | case WLAN_CIPHER_SUITE_CCMP: | ||
103 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
104 | /* all of these we can do in software */ | ||
105 | ret = 0; | ||
106 | break; | ||
107 | default: | ||
108 | ret = -EINVAL; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | return ret; | ||
93 | } | 113 | } |
94 | 114 | ||
95 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | 115 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) |
@@ -329,12 +349,12 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
329 | kfree(key); | 349 | kfree(key); |
330 | } | 350 | } |
331 | 351 | ||
332 | void ieee80211_key_link(struct ieee80211_key *key, | 352 | int ieee80211_key_link(struct ieee80211_key *key, |
333 | struct ieee80211_sub_if_data *sdata, | 353 | struct ieee80211_sub_if_data *sdata, |
334 | struct sta_info *sta) | 354 | struct sta_info *sta) |
335 | { | 355 | { |
336 | struct ieee80211_key *old_key; | 356 | struct ieee80211_key *old_key; |
337 | int idx; | 357 | int idx, ret; |
338 | 358 | ||
339 | BUG_ON(!sdata); | 359 | BUG_ON(!sdata); |
340 | BUG_ON(!key); | 360 | BUG_ON(!key); |
@@ -389,9 +409,11 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
389 | 409 | ||
390 | ieee80211_debugfs_key_add(key); | 410 | ieee80211_debugfs_key_add(key); |
391 | 411 | ||
392 | ieee80211_key_enable_hw_accel(key); | 412 | ret = ieee80211_key_enable_hw_accel(key); |
393 | 413 | ||
394 | mutex_unlock(&sdata->local->key_mtx); | 414 | mutex_unlock(&sdata->local->key_mtx); |
415 | |||
416 | return ret; | ||
395 | } | 417 | } |
396 | 418 | ||
397 | static void __ieee80211_key_free(struct ieee80211_key *key) | 419 | static void __ieee80211_key_free(struct ieee80211_key *key) |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 53b5ce12536f..cb9a4a65cc68 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -130,9 +130,9 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
130 | * Insert a key into data structures (sdata, sta if necessary) | 130 | * Insert a key into data structures (sdata, sta if necessary) |
131 | * to make it used, free old key. | 131 | * to make it used, free old key. |
132 | */ | 132 | */ |
133 | void ieee80211_key_link(struct ieee80211_key *key, | 133 | int __must_check ieee80211_key_link(struct ieee80211_key *key, |
134 | struct ieee80211_sub_if_data *sdata, | 134 | struct ieee80211_sub_if_data *sdata, |
135 | struct sta_info *sta); | 135 | struct sta_info *sta); |
136 | void ieee80211_key_free(struct ieee80211_local *local, | 136 | void ieee80211_key_free(struct ieee80211_local *local, |
137 | struct ieee80211_key *key); | 137 | struct ieee80211_key *key); |
138 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); | 138 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 80db5ea02052..15f0e960fde8 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -662,13 +662,40 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
662 | if (local->hw.wiphy->max_scan_ie_len) | 662 | if (local->hw.wiphy->max_scan_ie_len) |
663 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; | 663 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; |
664 | 664 | ||
665 | local->hw.wiphy->cipher_suites = cipher_suites; | 665 | /* Set up cipher suites unless driver already did */ |
666 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 666 | if (!local->hw.wiphy->cipher_suites) { |
667 | if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) | 667 | local->hw.wiphy->cipher_suites = cipher_suites; |
668 | local->hw.wiphy->n_cipher_suites--; | 668 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
669 | if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) | ||
670 | local->hw.wiphy->n_cipher_suites--; | ||
671 | } | ||
669 | if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { | 672 | if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { |
670 | local->hw.wiphy->cipher_suites += 2; | 673 | if (local->hw.wiphy->cipher_suites == cipher_suites) { |
671 | local->hw.wiphy->n_cipher_suites -= 2; | 674 | local->hw.wiphy->cipher_suites += 2; |
675 | local->hw.wiphy->n_cipher_suites -= 2; | ||
676 | } else { | ||
677 | u32 *suites; | ||
678 | int r, w = 0; | ||
679 | |||
680 | /* Filter out WEP */ | ||
681 | |||
682 | suites = kmemdup( | ||
683 | local->hw.wiphy->cipher_suites, | ||
684 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
685 | GFP_KERNEL); | ||
686 | if (!suites) | ||
687 | return -ENOMEM; | ||
688 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { | ||
689 | u32 suite = local->hw.wiphy->cipher_suites[r]; | ||
690 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
691 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
692 | continue; | ||
693 | suites[w++] = suite; | ||
694 | } | ||
695 | local->hw.wiphy->cipher_suites = suites; | ||
696 | local->hw.wiphy->n_cipher_suites = w; | ||
697 | local->wiphy_ciphers_allocated = true; | ||
698 | } | ||
672 | } | 699 | } |
673 | 700 | ||
674 | result = wiphy_register(local->hw.wiphy); | 701 | result = wiphy_register(local->hw.wiphy); |
@@ -783,6 +810,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
783 | fail_workqueue: | 810 | fail_workqueue: |
784 | wiphy_unregister(local->hw.wiphy); | 811 | wiphy_unregister(local->hw.wiphy); |
785 | fail_wiphy_register: | 812 | fail_wiphy_register: |
813 | if (local->wiphy_ciphers_allocated) | ||
814 | kfree(local->hw.wiphy->cipher_suites); | ||
786 | kfree(local->int_scan_req); | 815 | kfree(local->int_scan_req); |
787 | return result; | 816 | return result; |
788 | } | 817 | } |
@@ -840,6 +869,9 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
840 | mutex_destroy(&local->iflist_mtx); | 869 | mutex_destroy(&local->iflist_mtx); |
841 | mutex_destroy(&local->mtx); | 870 | mutex_destroy(&local->mtx); |
842 | 871 | ||
872 | if (local->wiphy_ciphers_allocated) | ||
873 | kfree(local->hw.wiphy->cipher_suites); | ||
874 | |||
843 | wiphy_free(local->hw.wiphy); | 875 | wiphy_free(local->hw.wiphy); |
844 | } | 876 | } |
845 | EXPORT_SYMBOL(ieee80211_free_hw); | 877 | EXPORT_SYMBOL(ieee80211_free_hw); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e67deb48af5c..6e5fb16af55c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1000,6 +1000,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1000 | case WLAN_CIPHER_SUITE_AES_CMAC: | 1000 | case WLAN_CIPHER_SUITE_AES_CMAC: |
1001 | result = ieee80211_crypto_aes_cmac_decrypt(rx); | 1001 | result = ieee80211_crypto_aes_cmac_decrypt(rx); |
1002 | break; | 1002 | break; |
1003 | default: | ||
1004 | /* | ||
1005 | * We can reach here only with HW-only algorithms | ||
1006 | * but why didn't it decrypt the frame?! | ||
1007 | */ | ||
1008 | return RX_DROP_UNUSABLE; | ||
1003 | } | 1009 | } |
1004 | 1010 | ||
1005 | /* either the frame has been decrypted or will be dropped */ | 1011 | /* either the frame has been decrypted or will be dropped */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a6ac9fd248f2..31a8903a45af 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -947,6 +947,8 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | |||
947 | static ieee80211_tx_result debug_noinline | 947 | static ieee80211_tx_result debug_noinline |
948 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | 948 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) |
949 | { | 949 | { |
950 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | ||
951 | |||
950 | if (!tx->key) | 952 | if (!tx->key) |
951 | return TX_CONTINUE; | 953 | return TX_CONTINUE; |
952 | 954 | ||
@@ -960,10 +962,16 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
960 | return ieee80211_crypto_ccmp_encrypt(tx); | 962 | return ieee80211_crypto_ccmp_encrypt(tx); |
961 | case WLAN_CIPHER_SUITE_AES_CMAC: | 963 | case WLAN_CIPHER_SUITE_AES_CMAC: |
962 | return ieee80211_crypto_aes_cmac_encrypt(tx); | 964 | return ieee80211_crypto_aes_cmac_encrypt(tx); |
965 | default: | ||
966 | /* handle hw-only algorithm */ | ||
967 | if (info->control.hw_key) { | ||
968 | ieee80211_tx_set_protected(tx); | ||
969 | return TX_CONTINUE; | ||
970 | } | ||
971 | break; | ||
972 | |||
963 | } | 973 | } |
964 | 974 | ||
965 | /* not reached */ | ||
966 | WARN_ON(1); | ||
967 | return TX_DROP; | 975 | return TX_DROP; |
968 | } | 976 | } |
969 | 977 | ||