aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-08-27 07:26:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-27 13:27:07 -0400
commit3ffc2a905b1faae4c0fe39d66f0752c3a4cbb3c7 (patch)
treed50902e1e171877e4fb034e36c837f16984ab9b4
parent7d64b7cc1fc33bab24567903a93f699d11649c0b (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.c5
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/key.c38
-rw-r--r--net/mac80211/key.h6
-rw-r--r--net/mac80211/main.c44
-rw-r--r--net/mac80211/rx.c6
-rw-r--r--net/mac80211/tx.c12
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
63static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) 63static 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
96out_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
95static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) 115static 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
332void ieee80211_key_link(struct ieee80211_key *key, 352int 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
397static void __ieee80211_key_free(struct ieee80211_key *key) 419static 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 */
133void ieee80211_key_link(struct ieee80211_key *key, 133int __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);
136void ieee80211_key_free(struct ieee80211_local *local, 136void ieee80211_key_free(struct ieee80211_local *local,
137 struct ieee80211_key *key); 137 struct ieee80211_key *key);
138void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); 138void 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}
845EXPORT_SYMBOL(ieee80211_free_hw); 877EXPORT_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)
947static ieee80211_tx_result debug_noinline 947static ieee80211_tx_result debug_noinline
948ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) 948ieee80211_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