diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 31 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 10 | ||||
-rw-r--r-- | net/mac80211/iface.c | 5 | ||||
-rw-r--r-- | net/mac80211/key.c | 58 | ||||
-rw-r--r-- | net/mac80211/key.h | 13 | ||||
-rw-r--r-- | net/mac80211/main.c | 145 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 4 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 4 | ||||
-rw-r--r-- | net/mac80211/rx.c | 65 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 10 | ||||
-rw-r--r-- | net/mac80211/tx.c | 14 | ||||
-rw-r--r-- | net/mac80211/util.c | 68 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 116 | ||||
-rw-r--r-- | net/mac80211/wpa.h | 2 |
14 files changed, 444 insertions, 101 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5232b0102143..f6b9265cf04e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -133,7 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
133 | struct key_params *params) | 133 | struct key_params *params) |
134 | { | 134 | { |
135 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 135 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
136 | struct ieee80211_local *local = sdata->local; | ||
136 | struct sta_info *sta = NULL; | 137 | struct sta_info *sta = NULL; |
138 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
137 | struct ieee80211_key *key; | 139 | struct ieee80211_key *key; |
138 | int err; | 140 | int err; |
139 | 141 | ||
@@ -145,22 +147,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
145 | case WLAN_CIPHER_SUITE_WEP40: | 147 | case WLAN_CIPHER_SUITE_WEP40: |
146 | case WLAN_CIPHER_SUITE_TKIP: | 148 | case WLAN_CIPHER_SUITE_TKIP: |
147 | case WLAN_CIPHER_SUITE_WEP104: | 149 | case WLAN_CIPHER_SUITE_WEP104: |
148 | if (IS_ERR(sdata->local->wep_tx_tfm)) | 150 | if (IS_ERR(local->wep_tx_tfm)) |
149 | return -EINVAL; | 151 | return -EINVAL; |
150 | break; | 152 | break; |
153 | case WLAN_CIPHER_SUITE_CCMP: | ||
154 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
155 | case WLAN_CIPHER_SUITE_GCMP: | ||
156 | break; | ||
151 | default: | 157 | default: |
158 | cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type); | ||
152 | break; | 159 | break; |
153 | } | 160 | } |
154 | 161 | ||
155 | key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, | 162 | key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, |
156 | params->key, params->seq_len, params->seq); | 163 | params->key, params->seq_len, params->seq, |
164 | cs); | ||
157 | if (IS_ERR(key)) | 165 | if (IS_ERR(key)) |
158 | return PTR_ERR(key); | 166 | return PTR_ERR(key); |
159 | 167 | ||
160 | if (pairwise) | 168 | if (pairwise) |
161 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | 169 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; |
162 | 170 | ||
163 | mutex_lock(&sdata->local->sta_mtx); | 171 | mutex_lock(&local->sta_mtx); |
164 | 172 | ||
165 | if (mac_addr) { | 173 | if (mac_addr) { |
166 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 174 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
@@ -216,10 +224,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
216 | break; | 224 | break; |
217 | } | 225 | } |
218 | 226 | ||
227 | if (sta) | ||
228 | sta->cipher_scheme = cs; | ||
229 | |||
219 | err = ieee80211_key_link(key, sdata, sta); | 230 | err = ieee80211_key_link(key, sdata, sta); |
220 | 231 | ||
221 | out_unlock: | 232 | out_unlock: |
222 | mutex_unlock(&sdata->local->sta_mtx); | 233 | mutex_unlock(&local->sta_mtx); |
223 | 234 | ||
224 | return err; | 235 | return err; |
225 | } | 236 | } |
@@ -244,7 +255,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
244 | goto out_unlock; | 255 | goto out_unlock; |
245 | 256 | ||
246 | if (pairwise) | 257 | if (pairwise) |
247 | key = key_mtx_dereference(local, sta->ptk); | 258 | key = key_mtx_dereference(local, sta->ptk[key_idx]); |
248 | else | 259 | else |
249 | key = key_mtx_dereference(local, sta->gtk[key_idx]); | 260 | key = key_mtx_dereference(local, sta->gtk[key_idx]); |
250 | } else | 261 | } else |
@@ -291,7 +302,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
291 | goto out; | 302 | goto out; |
292 | 303 | ||
293 | if (pairwise) | 304 | if (pairwise) |
294 | key = rcu_dereference(sta->ptk); | 305 | key = rcu_dereference(sta->ptk[key_idx]); |
295 | else if (key_idx < NUM_DEFAULT_KEYS) | 306 | else if (key_idx < NUM_DEFAULT_KEYS) |
296 | key = rcu_dereference(sta->gtk[key_idx]); | 307 | key = rcu_dereference(sta->gtk[key_idx]); |
297 | } else | 308 | } else |
@@ -968,11 +979,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
968 | */ | 979 | */ |
969 | sdata->control_port_protocol = params->crypto.control_port_ethertype; | 980 | sdata->control_port_protocol = params->crypto.control_port_ethertype; |
970 | sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; | 981 | sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; |
982 | sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, | ||
983 | ¶ms->crypto, | ||
984 | sdata->vif.type); | ||
985 | |||
971 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { | 986 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { |
972 | vlan->control_port_protocol = | 987 | vlan->control_port_protocol = |
973 | params->crypto.control_port_ethertype; | 988 | params->crypto.control_port_ethertype; |
974 | vlan->control_port_no_encrypt = | 989 | vlan->control_port_no_encrypt = |
975 | params->crypto.control_port_no_encrypt; | 990 | params->crypto.control_port_no_encrypt; |
991 | vlan->encrypt_headroom = | ||
992 | ieee80211_cs_headroom(sdata->local, | ||
993 | ¶ms->crypto, | ||
994 | vlan->vif.type); | ||
976 | } | 995 | } |
977 | 996 | ||
978 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; | 997 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 29dc505be125..16f5ba4a3252 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -728,6 +728,7 @@ struct ieee80211_sub_if_data { | |||
728 | u16 sequence_number; | 728 | u16 sequence_number; |
729 | __be16 control_port_protocol; | 729 | __be16 control_port_protocol; |
730 | bool control_port_no_encrypt; | 730 | bool control_port_no_encrypt; |
731 | int encrypt_headroom; | ||
731 | 732 | ||
732 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; | 733 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; |
733 | 734 | ||
@@ -1749,6 +1750,15 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work); | |||
1749 | int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | 1750 | int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, |
1750 | struct cfg80211_csa_settings *csa_settings); | 1751 | struct cfg80211_csa_settings *csa_settings); |
1751 | 1752 | ||
1753 | bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs); | ||
1754 | bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n); | ||
1755 | const struct ieee80211_cipher_scheme * | ||
1756 | ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, | ||
1757 | enum nl80211_iftype iftype); | ||
1758 | int ieee80211_cs_headroom(struct ieee80211_local *local, | ||
1759 | struct cfg80211_crypto_settings *crypto, | ||
1760 | enum nl80211_iftype iftype); | ||
1761 | |||
1752 | #ifdef CONFIG_MAC80211_NOINLINE | 1762 | #ifdef CONFIG_MAC80211_NOINLINE |
1753 | #define debug_noinline noinline | 1763 | #define debug_noinline noinline |
1754 | #else | 1764 | #else |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index c9b04425ffc7..a851bf4f05e5 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -401,6 +401,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
401 | snprintf(sdata->name, IFNAMSIZ, "%s-monitor", | 401 | snprintf(sdata->name, IFNAMSIZ, "%s-monitor", |
402 | wiphy_name(local->hw.wiphy)); | 402 | wiphy_name(local->hw.wiphy)); |
403 | 403 | ||
404 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
405 | |||
404 | ieee80211_set_default_queues(sdata); | 406 | ieee80211_set_default_queues(sdata); |
405 | 407 | ||
406 | ret = drv_add_interface(local, sdata); | 408 | ret = drv_add_interface(local, sdata); |
@@ -1273,6 +1275,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1273 | 1275 | ||
1274 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); | 1276 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); |
1275 | sdata->control_port_no_encrypt = false; | 1277 | sdata->control_port_no_encrypt = false; |
1278 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
1276 | 1279 | ||
1277 | sdata->noack_map = 0; | 1280 | sdata->noack_map = 0; |
1278 | 1281 | ||
@@ -1689,6 +1692,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1689 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | 1692 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
1690 | sdata->user_power_level = local->user_power_level; | 1693 | sdata->user_power_level = local->user_power_level; |
1691 | 1694 | ||
1695 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
1696 | |||
1692 | /* setup type-dependent data */ | 1697 | /* setup type-dependent data */ |
1693 | ieee80211_setup_sdata(sdata, type); | 1698 | ieee80211_setup_sdata(sdata, type); |
1694 | 1699 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ab8468047200..e568d98167d0 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -267,22 +267,22 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
267 | if (new) | 267 | if (new) |
268 | list_add_tail(&new->list, &sdata->key_list); | 268 | list_add_tail(&new->list, &sdata->key_list); |
269 | 269 | ||
270 | if (sta && pairwise) { | 270 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); |
271 | rcu_assign_pointer(sta->ptk, new); | ||
272 | } else if (sta) { | ||
273 | if (old) | ||
274 | idx = old->conf.keyidx; | ||
275 | else | ||
276 | idx = new->conf.keyidx; | ||
277 | rcu_assign_pointer(sta->gtk[idx], new); | ||
278 | } else { | ||
279 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | ||
280 | 271 | ||
281 | if (old) | 272 | if (old) |
282 | idx = old->conf.keyidx; | 273 | idx = old->conf.keyidx; |
283 | else | 274 | else |
284 | idx = new->conf.keyidx; | 275 | idx = new->conf.keyidx; |
285 | 276 | ||
277 | if (sta) { | ||
278 | if (pairwise) { | ||
279 | rcu_assign_pointer(sta->ptk[idx], new); | ||
280 | sta->ptk_idx = idx; | ||
281 | } else { | ||
282 | rcu_assign_pointer(sta->gtk[idx], new); | ||
283 | sta->gtk_idx = idx; | ||
284 | } | ||
285 | } else { | ||
286 | defunikey = old && | 286 | defunikey = old && |
287 | old == key_mtx_dereference(sdata->local, | 287 | old == key_mtx_dereference(sdata->local, |
288 | sdata->default_unicast_key); | 288 | sdata->default_unicast_key); |
@@ -316,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
316 | list_del(&old->list); | 316 | list_del(&old->list); |
317 | } | 317 | } |
318 | 318 | ||
319 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | 319 | struct ieee80211_key * |
320 | const u8 *key_data, | 320 | ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
321 | size_t seq_len, const u8 *seq) | 321 | const u8 *key_data, |
322 | size_t seq_len, const u8 *seq, | ||
323 | const struct ieee80211_cipher_scheme *cs) | ||
322 | { | 324 | { |
323 | struct ieee80211_key *key; | 325 | struct ieee80211_key *key; |
324 | int i, j, err; | 326 | int i, j, err; |
@@ -397,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
397 | return ERR_PTR(err); | 399 | return ERR_PTR(err); |
398 | } | 400 | } |
399 | break; | 401 | break; |
402 | default: | ||
403 | if (cs) { | ||
404 | size_t len = (seq_len > MAX_PN_LEN) ? | ||
405 | MAX_PN_LEN : seq_len; | ||
406 | |||
407 | key->conf.iv_len = cs->hdr_len; | ||
408 | key->conf.icv_len = cs->mic_len; | ||
409 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) | ||
410 | for (j = 0; j < len; j++) | ||
411 | key->u.gen.rx_pn[i][j] = | ||
412 | seq[len - j - 1]; | ||
413 | } | ||
400 | } | 414 | } |
401 | memcpy(key->conf.key, key_data, key_len); | 415 | memcpy(key->conf.key, key_data, key_len); |
402 | INIT_LIST_HEAD(&key->list); | 416 | INIT_LIST_HEAD(&key->list); |
@@ -479,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
479 | mutex_lock(&sdata->local->key_mtx); | 493 | mutex_lock(&sdata->local->key_mtx); |
480 | 494 | ||
481 | if (sta && pairwise) | 495 | if (sta && pairwise) |
482 | old_key = key_mtx_dereference(sdata->local, sta->ptk); | 496 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); |
483 | else if (sta) | 497 | else if (sta) |
484 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); | 498 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
485 | else | 499 | else |
@@ -629,8 +643,10 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, | |||
629 | list_add(&key->list, &keys); | 643 | list_add(&key->list, &keys); |
630 | } | 644 | } |
631 | 645 | ||
632 | key = key_mtx_dereference(local, sta->ptk); | 646 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { |
633 | if (key) { | 647 | key = key_mtx_dereference(local, sta->ptk[i]); |
648 | if (!key) | ||
649 | continue; | ||
634 | ieee80211_key_replace(key->sdata, key->sta, | 650 | ieee80211_key_replace(key->sdata, key->sta, |
635 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 651 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
636 | key, NULL); | 652 | key, NULL); |
@@ -881,7 +897,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, | |||
881 | 897 | ||
882 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, | 898 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, |
883 | keyconf->keylen, keyconf->key, | 899 | keyconf->keylen, keyconf->key, |
884 | 0, NULL); | 900 | 0, NULL, NULL); |
885 | if (IS_ERR(key)) | 901 | if (IS_ERR(key)) |
886 | return ERR_CAST(key); | 902 | return ERR_CAST(key); |
887 | 903 | ||
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index aaae0ed37004..0aebb889caba 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #define NUM_DEFAULT_KEYS 4 | 19 | #define NUM_DEFAULT_KEYS 4 |
20 | #define NUM_DEFAULT_MGMT_KEYS 2 | 20 | #define NUM_DEFAULT_MGMT_KEYS 2 |
21 | #define MAX_PN_LEN 16 | ||
21 | 22 | ||
22 | struct ieee80211_local; | 23 | struct ieee80211_local; |
23 | struct ieee80211_sub_if_data; | 24 | struct ieee80211_sub_if_data; |
@@ -93,6 +94,10 @@ struct ieee80211_key { | |||
93 | u32 replays; /* dot11RSNAStatsCMACReplays */ | 94 | u32 replays; /* dot11RSNAStatsCMACReplays */ |
94 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ | 95 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ |
95 | } aes_cmac; | 96 | } aes_cmac; |
97 | struct { | ||
98 | /* generic cipher scheme */ | ||
99 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN]; | ||
100 | } gen; | ||
96 | } u; | 101 | } u; |
97 | 102 | ||
98 | /* number of times this key has been used */ | 103 | /* number of times this key has been used */ |
@@ -113,9 +118,11 @@ struct ieee80211_key { | |||
113 | struct ieee80211_key_conf conf; | 118 | struct ieee80211_key_conf conf; |
114 | }; | 119 | }; |
115 | 120 | ||
116 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | 121 | struct ieee80211_key * |
117 | const u8 *key_data, | 122 | ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
118 | size_t seq_len, const u8 *seq); | 123 | const u8 *key_data, |
124 | size_t seq_len, const u8 *seq, | ||
125 | const struct ieee80211_cipher_scheme *cs); | ||
119 | /* | 126 | /* |
120 | * Insert a key into data structures (sdata, sta if necessary) | 127 | * Insert a key into data structures (sdata, sta if necessary) |
121 | * to make it used, free old key. On failure, also free the new key. | 128 | * to make it used, free old key. On failure, also free the new key. |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 21d5d44444d0..bdb0b6c104b5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
651 | } | 651 | } |
652 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 652 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
653 | 653 | ||
654 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 654 | static int ieee80211_init_cipher_suites(struct ieee80211_local *local) |
655 | { | 655 | { |
656 | struct ieee80211_local *local = hw_to_local(hw); | 656 | bool have_wep = !(IS_ERR(local->wep_tx_tfm) || |
657 | int result, i; | 657 | IS_ERR(local->wep_rx_tfm)); |
658 | enum ieee80211_band band; | 658 | bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE; |
659 | int channels, max_bitrates; | 659 | const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes; |
660 | bool supp_ht, supp_vht; | 660 | int n_suites = 0, r = 0, w = 0; |
661 | netdev_features_t feature_whitelist; | 661 | u32 *suites; |
662 | struct cfg80211_chan_def dflt_chandef = {}; | ||
663 | static const u32 cipher_suites[] = { | 662 | static const u32 cipher_suites[] = { |
664 | /* keep WEP first, it may be removed below */ | 663 | /* keep WEP first, it may be removed below */ |
665 | WLAN_CIPHER_SUITE_WEP40, | 664 | WLAN_CIPHER_SUITE_WEP40, |
@@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
671 | WLAN_CIPHER_SUITE_AES_CMAC | 670 | WLAN_CIPHER_SUITE_AES_CMAC |
672 | }; | 671 | }; |
673 | 672 | ||
673 | /* Driver specifies the ciphers, we have nothing to do... */ | ||
674 | if (local->hw.wiphy->cipher_suites && have_wep) | ||
675 | return 0; | ||
676 | |||
677 | /* Set up cipher suites if driver relies on mac80211 cipher defs */ | ||
678 | if (!local->hw.wiphy->cipher_suites && !cs) { | ||
679 | local->hw.wiphy->cipher_suites = cipher_suites; | ||
680 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
681 | |||
682 | if (!have_mfp) | ||
683 | local->hw.wiphy->n_cipher_suites--; | ||
684 | |||
685 | if (!have_wep) { | ||
686 | local->hw.wiphy->cipher_suites += 2; | ||
687 | local->hw.wiphy->n_cipher_suites -= 2; | ||
688 | } | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | if (!local->hw.wiphy->cipher_suites) { | ||
694 | /* | ||
695 | * Driver specifies cipher schemes only | ||
696 | * We start counting ciphers defined by schemes, TKIP and CCMP | ||
697 | */ | ||
698 | n_suites = local->hw.n_cipher_schemes + 2; | ||
699 | |||
700 | /* check if we have WEP40 and WEP104 */ | ||
701 | if (have_wep) | ||
702 | n_suites += 2; | ||
703 | |||
704 | /* check if we have AES_CMAC */ | ||
705 | if (have_mfp) | ||
706 | n_suites++; | ||
707 | |||
708 | suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); | ||
709 | if (!suites) | ||
710 | return -ENOMEM; | ||
711 | |||
712 | suites[w++] = WLAN_CIPHER_SUITE_CCMP; | ||
713 | suites[w++] = WLAN_CIPHER_SUITE_TKIP; | ||
714 | |||
715 | if (have_wep) { | ||
716 | suites[w++] = WLAN_CIPHER_SUITE_WEP40; | ||
717 | suites[w++] = WLAN_CIPHER_SUITE_WEP104; | ||
718 | } | ||
719 | |||
720 | if (have_mfp) | ||
721 | suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; | ||
722 | |||
723 | for (r = 0; r < local->hw.n_cipher_schemes; r++) | ||
724 | suites[w++] = cs[r].cipher; | ||
725 | } else { | ||
726 | /* Driver provides cipher suites, but we need to exclude WEP */ | ||
727 | suites = kmemdup(local->hw.wiphy->cipher_suites, | ||
728 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
729 | GFP_KERNEL); | ||
730 | if (!suites) | ||
731 | return -ENOMEM; | ||
732 | |||
733 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { | ||
734 | u32 suite = local->hw.wiphy->cipher_suites[r]; | ||
735 | |||
736 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
737 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
738 | continue; | ||
739 | suites[w++] = suite; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | local->hw.wiphy->cipher_suites = suites; | ||
744 | local->hw.wiphy->n_cipher_suites = w; | ||
745 | local->wiphy_ciphers_allocated = true; | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | int ieee80211_register_hw(struct ieee80211_hw *hw) | ||
751 | { | ||
752 | struct ieee80211_local *local = hw_to_local(hw); | ||
753 | int result, i; | ||
754 | enum ieee80211_band band; | ||
755 | int channels, max_bitrates; | ||
756 | bool supp_ht, supp_vht; | ||
757 | netdev_features_t feature_whitelist; | ||
758 | struct cfg80211_chan_def dflt_chandef = {}; | ||
759 | |||
674 | if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && | 760 | if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && |
675 | (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || | 761 | (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || |
676 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | 762 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) |
@@ -851,43 +937,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
851 | if (local->hw.wiphy->max_scan_ie_len) | 937 | if (local->hw.wiphy->max_scan_ie_len) |
852 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; | 938 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; |
853 | 939 | ||
854 | /* Set up cipher suites unless driver already did */ | 940 | WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes, |
855 | if (!local->hw.wiphy->cipher_suites) { | 941 | local->hw.n_cipher_schemes)); |
856 | local->hw.wiphy->cipher_suites = cipher_suites; | 942 | |
857 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 943 | result = ieee80211_init_cipher_suites(local); |
858 | if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) | 944 | if (result < 0) |
859 | local->hw.wiphy->n_cipher_suites--; | 945 | goto fail_wiphy_register; |
860 | } | ||
861 | if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { | ||
862 | if (local->hw.wiphy->cipher_suites == cipher_suites) { | ||
863 | local->hw.wiphy->cipher_suites += 2; | ||
864 | local->hw.wiphy->n_cipher_suites -= 2; | ||
865 | } else { | ||
866 | u32 *suites; | ||
867 | int r, w = 0; | ||
868 | |||
869 | /* Filter out WEP */ | ||
870 | |||
871 | suites = kmemdup( | ||
872 | local->hw.wiphy->cipher_suites, | ||
873 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
874 | GFP_KERNEL); | ||
875 | if (!suites) { | ||
876 | result = -ENOMEM; | ||
877 | goto fail_wiphy_register; | ||
878 | } | ||
879 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { | ||
880 | u32 suite = local->hw.wiphy->cipher_suites[r]; | ||
881 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
882 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
883 | continue; | ||
884 | suites[w++] = suite; | ||
885 | } | ||
886 | local->hw.wiphy->cipher_suites = suites; | ||
887 | local->hw.wiphy->n_cipher_suites = w; | ||
888 | local->wiphy_ciphers_allocated = true; | ||
889 | } | ||
890 | } | ||
891 | 946 | ||
892 | if (!local->ops->remain_on_channel) | 947 | if (!local->ops->remain_on_channel) |
893 | local->hw.wiphy->max_remain_on_channel_duration = 5000; | 948 | local->hw.wiphy->max_remain_on_channel_duration = 5000; |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 486819cd02cd..56e0c072007a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -254,13 +254,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, | |||
254 | return -EAGAIN; | 254 | return -EAGAIN; |
255 | 255 | ||
256 | skb = dev_alloc_skb(local->tx_headroom + | 256 | skb = dev_alloc_skb(local->tx_headroom + |
257 | IEEE80211_ENCRYPT_HEADROOM + | 257 | sdata->encrypt_headroom + |
258 | IEEE80211_ENCRYPT_TAILROOM + | 258 | IEEE80211_ENCRYPT_TAILROOM + |
259 | hdr_len + | 259 | hdr_len + |
260 | 2 + 15 /* PERR IE */); | 260 | 2 + 15 /* PERR IE */); |
261 | if (!skb) | 261 | if (!skb) |
262 | return -1; | 262 | return -1; |
263 | skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); | 263 | skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom); |
264 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | 264 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); |
265 | memset(mgmt, 0, hdr_len); | 265 | memset(mgmt, 0, hdr_len); |
266 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 266 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d39d27feb594..f8dca58b7e52 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1747,6 +1747,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1747 | 1747 | ||
1748 | ifmgd->flags = 0; | 1748 | ifmgd->flags = 0; |
1749 | ieee80211_vif_release_channel(sdata); | 1749 | ieee80211_vif_release_channel(sdata); |
1750 | |||
1751 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
1750 | } | 1752 | } |
1751 | 1753 | ||
1752 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1754 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
@@ -4191,6 +4193,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4191 | 4193 | ||
4192 | sdata->control_port_protocol = req->crypto.control_port_ethertype; | 4194 | sdata->control_port_protocol = req->crypto.control_port_ethertype; |
4193 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; | 4195 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; |
4196 | sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto, | ||
4197 | sdata->vif.type); | ||
4194 | 4198 | ||
4195 | /* kick off associate process */ | 4199 | /* kick off associate process */ |
4196 | 4200 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 401f3c26e707..79f76791f77a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -638,6 +638,27 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
638 | return le16_to_cpu(mmie->key_id); | 638 | return le16_to_cpu(mmie->key_id); |
639 | } | 639 | } |
640 | 640 | ||
641 | static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, | ||
642 | struct sk_buff *skb) | ||
643 | { | ||
644 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
645 | __le16 fc; | ||
646 | int hdrlen; | ||
647 | u8 keyid; | ||
648 | |||
649 | fc = hdr->frame_control; | ||
650 | hdrlen = ieee80211_hdrlen(fc); | ||
651 | |||
652 | if (skb->len < hdrlen + cs->hdr_len) | ||
653 | return -EINVAL; | ||
654 | |||
655 | skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1); | ||
656 | keyid &= cs->key_idx_mask; | ||
657 | keyid >>= cs->key_idx_shift; | ||
658 | |||
659 | return keyid; | ||
660 | } | ||
661 | |||
641 | static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | 662 | static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) |
642 | { | 663 | { |
643 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 664 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
@@ -1360,6 +1381,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1360 | struct ieee80211_key *sta_ptk = NULL; | 1381 | struct ieee80211_key *sta_ptk = NULL; |
1361 | int mmie_keyidx = -1; | 1382 | int mmie_keyidx = -1; |
1362 | __le16 fc; | 1383 | __le16 fc; |
1384 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
1363 | 1385 | ||
1364 | /* | 1386 | /* |
1365 | * Key selection 101 | 1387 | * Key selection 101 |
@@ -1397,11 +1419,19 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1397 | 1419 | ||
1398 | /* start without a key */ | 1420 | /* start without a key */ |
1399 | rx->key = NULL; | 1421 | rx->key = NULL; |
1422 | fc = hdr->frame_control; | ||
1400 | 1423 | ||
1401 | if (rx->sta) | 1424 | if (rx->sta) { |
1402 | sta_ptk = rcu_dereference(rx->sta->ptk); | 1425 | int keyid = rx->sta->ptk_idx; |
1403 | 1426 | ||
1404 | fc = hdr->frame_control; | 1427 | if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) { |
1428 | cs = rx->sta->cipher_scheme; | ||
1429 | keyid = iwl80211_get_cs_keyid(cs, rx->skb); | ||
1430 | if (unlikely(keyid < 0)) | ||
1431 | return RX_DROP_UNUSABLE; | ||
1432 | } | ||
1433 | sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); | ||
1434 | } | ||
1405 | 1435 | ||
1406 | if (!ieee80211_has_protected(fc)) | 1436 | if (!ieee80211_has_protected(fc)) |
1407 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); | 1437 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); |
@@ -1463,6 +1493,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1463 | return RX_CONTINUE; | 1493 | return RX_CONTINUE; |
1464 | } else { | 1494 | } else { |
1465 | u8 keyid; | 1495 | u8 keyid; |
1496 | |||
1466 | /* | 1497 | /* |
1467 | * The device doesn't give us the IV so we won't be | 1498 | * The device doesn't give us the IV so we won't be |
1468 | * able to look up the key. That's ok though, we | 1499 | * able to look up the key. That's ok though, we |
@@ -1478,15 +1509,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1478 | 1509 | ||
1479 | hdrlen = ieee80211_hdrlen(fc); | 1510 | hdrlen = ieee80211_hdrlen(fc); |
1480 | 1511 | ||
1481 | if (rx->skb->len < 8 + hdrlen) | 1512 | if (cs) { |
1482 | return RX_DROP_UNUSABLE; /* TODO: count this? */ | 1513 | keyidx = iwl80211_get_cs_keyid(cs, rx->skb); |
1483 | 1514 | ||
1484 | /* | 1515 | if (unlikely(keyidx < 0)) |
1485 | * no need to call ieee80211_wep_get_keyidx, | 1516 | return RX_DROP_UNUSABLE; |
1486 | * it verifies a bunch of things we've done already | 1517 | } else { |
1487 | */ | 1518 | if (rx->skb->len < 8 + hdrlen) |
1488 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | 1519 | return RX_DROP_UNUSABLE; /* TODO: count this? */ |
1489 | keyidx = keyid >> 6; | 1520 | /* |
1521 | * no need to call ieee80211_wep_get_keyidx, | ||
1522 | * it verifies a bunch of things we've done already | ||
1523 | */ | ||
1524 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | ||
1525 | keyidx = keyid >> 6; | ||
1526 | } | ||
1490 | 1527 | ||
1491 | /* check per-station GTK first, if multicast packet */ | 1528 | /* check per-station GTK first, if multicast packet */ |
1492 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) | 1529 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) |
@@ -1534,11 +1571,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1534 | result = ieee80211_crypto_aes_cmac_decrypt(rx); | 1571 | result = ieee80211_crypto_aes_cmac_decrypt(rx); |
1535 | break; | 1572 | break; |
1536 | default: | 1573 | default: |
1537 | /* | 1574 | result = ieee80211_crypto_hw_decrypt(rx); |
1538 | * We can reach here only with HW-only algorithms | ||
1539 | * but why didn't it decrypt the frame?! | ||
1540 | */ | ||
1541 | return RX_DROP_UNUSABLE; | ||
1542 | } | 1575 | } |
1543 | 1576 | ||
1544 | /* the hdr variable is invalid after the decrypt handlers */ | 1577 | /* the hdr variable is invalid after the decrypt handlers */ |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3ef06a26b9cb..6b0d6c2dcba7 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -231,8 +231,10 @@ struct sta_ampdu_mlme { | |||
231 | * @hnext: hash table linked list pointer | 231 | * @hnext: hash table linked list pointer |
232 | * @local: pointer to the global information | 232 | * @local: pointer to the global information |
233 | * @sdata: virtual interface this station belongs to | 233 | * @sdata: virtual interface this station belongs to |
234 | * @ptk: peer key negotiated with this station, if any | 234 | * @ptk: peer keys negotiated with this station, if any |
235 | * @ptk_idx: last installed peer key index | ||
235 | * @gtk: group keys negotiated with this station, if any | 236 | * @gtk: group keys negotiated with this station, if any |
237 | * @gtk_idx: last installed group key index | ||
236 | * @rate_ctrl: rate control algorithm reference | 238 | * @rate_ctrl: rate control algorithm reference |
237 | * @rate_ctrl_priv: rate control private per-STA pointer | 239 | * @rate_ctrl_priv: rate control private per-STA pointer |
238 | * @last_tx_rate: rate used for last transmit, to report to userspace as | 240 | * @last_tx_rate: rate used for last transmit, to report to userspace as |
@@ -303,6 +305,7 @@ struct sta_ampdu_mlme { | |||
303 | * @chain_signal_avg: signal average (per chain) | 305 | * @chain_signal_avg: signal average (per chain) |
304 | * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for | 306 | * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for |
305 | * AP only. | 307 | * AP only. |
308 | * @cipher_scheme: optional cipher scheme for this station | ||
306 | */ | 309 | */ |
307 | struct sta_info { | 310 | struct sta_info { |
308 | /* General information, mostly static */ | 311 | /* General information, mostly static */ |
@@ -312,7 +315,9 @@ struct sta_info { | |||
312 | struct ieee80211_local *local; | 315 | struct ieee80211_local *local; |
313 | struct ieee80211_sub_if_data *sdata; | 316 | struct ieee80211_sub_if_data *sdata; |
314 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 317 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
315 | struct ieee80211_key __rcu *ptk; | 318 | struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS]; |
319 | u8 gtk_idx; | ||
320 | u8 ptk_idx; | ||
316 | struct rate_control_ref *rate_ctrl; | 321 | struct rate_control_ref *rate_ctrl; |
317 | void *rate_ctrl_priv; | 322 | void *rate_ctrl_priv; |
318 | spinlock_t lock; | 323 | spinlock_t lock; |
@@ -414,6 +419,7 @@ struct sta_info { | |||
414 | unsigned int beacon_loss_count; | 419 | unsigned int beacon_loss_count; |
415 | 420 | ||
416 | enum ieee80211_smps_mode known_smps_mode; | 421 | enum ieee80211_smps_mode known_smps_mode; |
422 | const struct ieee80211_cipher_scheme *cipher_scheme; | ||
417 | 423 | ||
418 | /* keep last! */ | 424 | /* keep last! */ |
419 | struct ieee80211_sta sta; | 425 | struct ieee80211_sta sta; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5ad2e8b1f92c..e541856b4007 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -557,7 +557,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
557 | 557 | ||
558 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) | 558 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) |
559 | tx->key = NULL; | 559 | tx->key = NULL; |
560 | else if (tx->sta && (key = rcu_dereference(tx->sta->ptk))) | 560 | else if (tx->sta && |
561 | (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx]))) | ||
561 | tx->key = key; | 562 | tx->key = key; |
562 | else if (ieee80211_is_mgmt(hdr->frame_control) && | 563 | else if (ieee80211_is_mgmt(hdr->frame_control) && |
563 | is_multicast_ether_addr(hdr->addr1) && | 564 | is_multicast_ether_addr(hdr->addr1) && |
@@ -840,15 +841,16 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, | |||
840 | rem -= fraglen; | 841 | rem -= fraglen; |
841 | tmp = dev_alloc_skb(local->tx_headroom + | 842 | tmp = dev_alloc_skb(local->tx_headroom + |
842 | frag_threshold + | 843 | frag_threshold + |
843 | IEEE80211_ENCRYPT_HEADROOM + | 844 | tx->sdata->encrypt_headroom + |
844 | IEEE80211_ENCRYPT_TAILROOM); | 845 | IEEE80211_ENCRYPT_TAILROOM); |
845 | if (!tmp) | 846 | if (!tmp) |
846 | return -ENOMEM; | 847 | return -ENOMEM; |
847 | 848 | ||
848 | __skb_queue_tail(&tx->skbs, tmp); | 849 | __skb_queue_tail(&tx->skbs, tmp); |
849 | 850 | ||
850 | skb_reserve(tmp, local->tx_headroom + | 851 | skb_reserve(tmp, |
851 | IEEE80211_ENCRYPT_HEADROOM); | 852 | local->tx_headroom + tx->sdata->encrypt_headroom); |
853 | |||
852 | /* copy control information */ | 854 | /* copy control information */ |
853 | memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); | 855 | memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); |
854 | 856 | ||
@@ -1485,7 +1487,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
1485 | 1487 | ||
1486 | headroom = local->tx_headroom; | 1488 | headroom = local->tx_headroom; |
1487 | if (may_encrypt) | 1489 | if (may_encrypt) |
1488 | headroom += IEEE80211_ENCRYPT_HEADROOM; | 1490 | headroom += sdata->encrypt_headroom; |
1489 | headroom -= skb_headroom(skb); | 1491 | headroom -= skb_headroom(skb); |
1490 | headroom = max_t(int, 0, headroom); | 1492 | headroom = max_t(int, 0, headroom); |
1491 | 1493 | ||
@@ -2108,7 +2110,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2108 | */ | 2110 | */ |
2109 | 2111 | ||
2110 | if (head_need > 0 || skb_cloned(skb)) { | 2112 | if (head_need > 0 || skb_cloned(skb)) { |
2111 | head_need += IEEE80211_ENCRYPT_HEADROOM; | 2113 | head_need += sdata->encrypt_headroom; |
2112 | head_need += local->tx_headroom; | 2114 | head_need += local->tx_headroom; |
2113 | head_need = max_t(int, 0, head_need); | 2115 | head_need = max_t(int, 0, head_need); |
2114 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { | 2116 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index fd4fe5d61782..5dfa41abdf8b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -2475,3 +2475,71 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | |||
2475 | ieee80211_tx_skb(sdata, skb); | 2475 | ieee80211_tx_skb(sdata, skb); |
2476 | return 0; | 2476 | return 0; |
2477 | } | 2477 | } |
2478 | |||
2479 | bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs) | ||
2480 | { | ||
2481 | return !(cs == NULL || cs->cipher == 0 || | ||
2482 | cs->hdr_len < cs->pn_len + cs->pn_off || | ||
2483 | cs->hdr_len <= cs->key_idx_off || | ||
2484 | cs->key_idx_shift > 7 || | ||
2485 | cs->key_idx_mask == 0); | ||
2486 | } | ||
2487 | |||
2488 | bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n) | ||
2489 | { | ||
2490 | int i; | ||
2491 | |||
2492 | /* Ensure we have enough iftype bitmap space for all iftype values */ | ||
2493 | WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype)); | ||
2494 | |||
2495 | for (i = 0; i < n; i++) | ||
2496 | if (!ieee80211_cs_valid(&cs[i])) | ||
2497 | return false; | ||
2498 | |||
2499 | return true; | ||
2500 | } | ||
2501 | |||
2502 | const struct ieee80211_cipher_scheme * | ||
2503 | ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, | ||
2504 | enum nl80211_iftype iftype) | ||
2505 | { | ||
2506 | const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes; | ||
2507 | int n = local->hw.n_cipher_schemes; | ||
2508 | int i; | ||
2509 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
2510 | |||
2511 | for (i = 0; i < n; i++) { | ||
2512 | if (l[i].cipher == cipher) { | ||
2513 | cs = &l[i]; | ||
2514 | break; | ||
2515 | } | ||
2516 | } | ||
2517 | |||
2518 | if (!cs || !(cs->iftype & BIT(iftype))) | ||
2519 | return NULL; | ||
2520 | |||
2521 | return cs; | ||
2522 | } | ||
2523 | |||
2524 | int ieee80211_cs_headroom(struct ieee80211_local *local, | ||
2525 | struct cfg80211_crypto_settings *crypto, | ||
2526 | enum nl80211_iftype iftype) | ||
2527 | { | ||
2528 | const struct ieee80211_cipher_scheme *cs; | ||
2529 | int headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
2530 | int i; | ||
2531 | |||
2532 | for (i = 0; i < crypto->n_ciphers_pairwise; i++) { | ||
2533 | cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i], | ||
2534 | iftype); | ||
2535 | |||
2536 | if (cs && headroom < cs->hdr_len) | ||
2537 | headroom = cs->hdr_len; | ||
2538 | } | ||
2539 | |||
2540 | cs = ieee80211_cs_get(local, crypto->cipher_group, iftype); | ||
2541 | if (cs && headroom < cs->hdr_len) | ||
2542 | headroom = cs->hdr_len; | ||
2543 | |||
2544 | return headroom; | ||
2545 | } | ||
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d65728220763..7313d379c0d3 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -545,6 +545,106 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
545 | return RX_CONTINUE; | 545 | return RX_CONTINUE; |
546 | } | 546 | } |
547 | 547 | ||
548 | static ieee80211_tx_result | ||
549 | ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | ||
550 | struct sk_buff *skb) | ||
551 | { | ||
552 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
553 | struct ieee80211_key *key = tx->key; | ||
554 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
555 | const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme; | ||
556 | int hdrlen; | ||
557 | u8 *pos; | ||
558 | |||
559 | if (info->control.hw_key && | ||
560 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { | ||
561 | /* hwaccel has no need for preallocated head room */ | ||
562 | return TX_CONTINUE; | ||
563 | } | ||
564 | |||
565 | if (unlikely(skb_headroom(skb) < cs->hdr_len && | ||
566 | pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC))) | ||
567 | return TX_DROP; | ||
568 | |||
569 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
570 | |||
571 | pos = skb_push(skb, cs->hdr_len); | ||
572 | memmove(pos, pos + cs->hdr_len, hdrlen); | ||
573 | skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len); | ||
574 | |||
575 | return TX_CONTINUE; | ||
576 | } | ||
577 | |||
578 | static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len) | ||
579 | { | ||
580 | int i; | ||
581 | |||
582 | /* pn is little endian */ | ||
583 | for (i = len - 1; i >= 0; i--) { | ||
584 | if (pn1[i] < pn2[i]) | ||
585 | return -1; | ||
586 | else if (pn1[i] > pn2[i]) | ||
587 | return 1; | ||
588 | } | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static ieee80211_rx_result | ||
594 | ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) | ||
595 | { | ||
596 | struct ieee80211_key *key = rx->key; | ||
597 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
598 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
599 | int hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
600 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
601 | int data_len; | ||
602 | u8 *rx_pn; | ||
603 | u8 *skb_pn; | ||
604 | u8 qos_tid; | ||
605 | |||
606 | if (!rx->sta || !rx->sta->cipher_scheme || | ||
607 | !(status->flag & RX_FLAG_DECRYPTED)) | ||
608 | return RX_DROP_UNUSABLE; | ||
609 | |||
610 | if (!ieee80211_is_data(hdr->frame_control)) | ||
611 | return RX_CONTINUE; | ||
612 | |||
613 | cs = rx->sta->cipher_scheme; | ||
614 | |||
615 | data_len = rx->skb->len - hdrlen - cs->hdr_len; | ||
616 | |||
617 | if (data_len < 0) | ||
618 | return RX_DROP_UNUSABLE; | ||
619 | |||
620 | if (ieee80211_is_data_qos(hdr->frame_control)) | ||
621 | qos_tid = *ieee80211_get_qos_ctl(hdr) & | ||
622 | IEEE80211_QOS_CTL_TID_MASK; | ||
623 | else | ||
624 | qos_tid = 0; | ||
625 | |||
626 | if (skb_linearize(rx->skb)) | ||
627 | return RX_DROP_UNUSABLE; | ||
628 | |||
629 | hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
630 | |||
631 | rx_pn = key->u.gen.rx_pn[qos_tid]; | ||
632 | skb_pn = rx->skb->data + hdrlen + cs->pn_off; | ||
633 | |||
634 | if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0) | ||
635 | return RX_DROP_UNUSABLE; | ||
636 | |||
637 | memcpy(rx_pn, skb_pn, cs->pn_len); | ||
638 | |||
639 | /* remove security header and MIC */ | ||
640 | if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len)) | ||
641 | return RX_DROP_UNUSABLE; | ||
642 | |||
643 | memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen); | ||
644 | skb_pull(rx->skb, cs->hdr_len); | ||
645 | |||
646 | return RX_CONTINUE; | ||
647 | } | ||
548 | 648 | ||
549 | static void bip_aad(struct sk_buff *skb, u8 *aad) | 649 | static void bip_aad(struct sk_buff *skb, u8 *aad) |
550 | { | 650 | { |
@@ -685,6 +785,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
685 | { | 785 | { |
686 | struct sk_buff *skb; | 786 | struct sk_buff *skb; |
687 | struct ieee80211_tx_info *info = NULL; | 787 | struct ieee80211_tx_info *info = NULL; |
788 | ieee80211_tx_result res; | ||
688 | 789 | ||
689 | skb_queue_walk(&tx->skbs, skb) { | 790 | skb_queue_walk(&tx->skbs, skb) { |
690 | info = IEEE80211_SKB_CB(skb); | 791 | info = IEEE80211_SKB_CB(skb); |
@@ -692,9 +793,24 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
692 | /* handle hw-only algorithm */ | 793 | /* handle hw-only algorithm */ |
693 | if (!info->control.hw_key) | 794 | if (!info->control.hw_key) |
694 | return TX_DROP; | 795 | return TX_DROP; |
796 | |||
797 | if (tx->key->sta->cipher_scheme) { | ||
798 | res = ieee80211_crypto_cs_encrypt(tx, skb); | ||
799 | if (res != TX_CONTINUE) | ||
800 | return res; | ||
801 | } | ||
695 | } | 802 | } |
696 | 803 | ||
697 | ieee80211_tx_set_protected(tx); | 804 | ieee80211_tx_set_protected(tx); |
698 | 805 | ||
699 | return TX_CONTINUE; | 806 | return TX_CONTINUE; |
700 | } | 807 | } |
808 | |||
809 | ieee80211_rx_result | ||
810 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) | ||
811 | { | ||
812 | if (rx->sta->cipher_scheme) | ||
813 | return ieee80211_crypto_cs_decrypt(rx); | ||
814 | |||
815 | return RX_DROP_UNUSABLE; | ||
816 | } | ||
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 07e33f899c71..62e5a12dfe0a 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h | |||
@@ -34,5 +34,7 @@ ieee80211_rx_result | |||
34 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); | 34 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); |
35 | ieee80211_tx_result | 35 | ieee80211_tx_result |
36 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); | 36 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); |
37 | ieee80211_rx_result | ||
38 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); | ||
37 | 39 | ||
38 | #endif /* WPA_H */ | 40 | #endif /* WPA_H */ |