diff options
author | David S. Miller <davem@davemloft.net> | 2015-03-31 16:39:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-31 16:39:04 -0400 |
commit | 7b6249bba940f57c20cdde793b306ca3831778c7 (patch) | |
tree | 24caf2ec9ea6fca08fe225228614807d0919b4b2 /net | |
parent | fbcb21705930f2930f506149d0b8d36dfbe45107 (diff) | |
parent | 2c44be81f0fc147eed9dc63e2601318b2c007aeb (diff) |
Merge tag 'mac80211-next-for-davem-2015-03-30' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says:
====================
Lots of updates for net-next; along with the usual flurry
of small fixes, cleanups and internal features we have:
* VHT support for TDLS and IBSS (conditional on drivers though)
* first TX performance improvements (the biggest will come later)
* many suspend/resume (race) fixes
* name_assign_type support from Tom Gundersen
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
46 files changed, 1515 insertions, 1111 deletions
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 7869bb40acaa..208df7c0b6ea 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c | |||
@@ -85,11 +85,15 @@ struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[], | |||
85 | return tfm; | 85 | return tfm; |
86 | 86 | ||
87 | err = crypto_aead_setkey(tfm, key, key_len); | 87 | err = crypto_aead_setkey(tfm, key, key_len); |
88 | if (!err) | 88 | if (err) |
89 | err = crypto_aead_setauthsize(tfm, mic_len); | 89 | goto free_aead; |
90 | if (!err) | 90 | err = crypto_aead_setauthsize(tfm, mic_len); |
91 | return tfm; | 91 | if (err) |
92 | goto free_aead; | ||
93 | |||
94 | return tfm; | ||
92 | 95 | ||
96 | free_aead: | ||
93 | crypto_free_aead(tfm); | 97 | crypto_free_aead(tfm); |
94 | return ERR_PTR(err); | 98 | return ERR_PTR(err); |
95 | } | 99 | } |
diff --git a/net/mac80211/aes_gcm.c b/net/mac80211/aes_gcm.c index c2bf6698d738..fd278bbe1b0d 100644 --- a/net/mac80211/aes_gcm.c +++ b/net/mac80211/aes_gcm.c | |||
@@ -80,11 +80,15 @@ struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], | |||
80 | return tfm; | 80 | return tfm; |
81 | 81 | ||
82 | err = crypto_aead_setkey(tfm, key, key_len); | 82 | err = crypto_aead_setkey(tfm, key, key_len); |
83 | if (!err) | 83 | if (err) |
84 | err = crypto_aead_setauthsize(tfm, IEEE80211_GCMP_MIC_LEN); | 84 | goto free_aead; |
85 | if (!err) | 85 | err = crypto_aead_setauthsize(tfm, IEEE80211_GCMP_MIC_LEN); |
86 | return tfm; | 86 | if (err) |
87 | goto free_aead; | ||
88 | |||
89 | return tfm; | ||
87 | 90 | ||
91 | free_aead: | ||
88 | crypto_free_aead(tfm); | 92 | crypto_free_aead(tfm); |
89 | return ERR_PTR(err); | 93 | return ERR_PTR(err); |
90 | } | 94 | } |
diff --git a/net/mac80211/aes_gmac.c b/net/mac80211/aes_gmac.c index 1c72edcb0083..f1321b7d6506 100644 --- a/net/mac80211/aes_gmac.c +++ b/net/mac80211/aes_gmac.c | |||
@@ -70,9 +70,9 @@ struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[], | |||
70 | 70 | ||
71 | err = crypto_aead_setkey(tfm, key, key_len); | 71 | err = crypto_aead_setkey(tfm, key, key_len); |
72 | if (!err) | 72 | if (!err) |
73 | return tfm; | ||
74 | if (!err) | ||
75 | err = crypto_aead_setauthsize(tfm, GMAC_MIC_LEN); | 73 | err = crypto_aead_setauthsize(tfm, GMAC_MIC_LEN); |
74 | if (!err) | ||
75 | return tfm; | ||
76 | 76 | ||
77 | crypto_free_aead(tfm); | 77 | crypto_free_aead(tfm); |
78 | return ERR_PTR(err); | 78 | return ERR_PTR(err); |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index a48bad468880..2c090c507391 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -234,6 +234,14 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, | |||
234 | int i, ret = -EOPNOTSUPP; | 234 | int i, ret = -EOPNOTSUPP; |
235 | u16 status = WLAN_STATUS_REQUEST_DECLINED; | 235 | u16 status = WLAN_STATUS_REQUEST_DECLINED; |
236 | 236 | ||
237 | if (!sta->sta.ht_cap.ht_supported) { | ||
238 | ht_dbg(sta->sdata, | ||
239 | "STA %pM erroneously requests BA session on tid %d w/o QoS\n", | ||
240 | sta->sta.addr, tid); | ||
241 | /* send a response anyway, it's an error case if we get here */ | ||
242 | goto end_no_lock; | ||
243 | } | ||
244 | |||
237 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { | 245 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { |
238 | ht_dbg(sta->sdata, | 246 | ht_dbg(sta->sdata, |
239 | "Suspend in progress - Denying ADDBA request (%pM tid %d)\n", | 247 | "Suspend in progress - Denying ADDBA request (%pM tid %d)\n", |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index a360c15cc978..20522492d8cc 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -509,11 +509,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
509 | struct tid_ampdu_tx *tid_tx; | 509 | struct tid_ampdu_tx *tid_tx; |
510 | int ret = 0; | 510 | int ret = 0; |
511 | 511 | ||
512 | trace_api_start_tx_ba_session(pubsta, tid); | ||
513 | |||
512 | if (WARN(sta->reserved_tid == tid, | 514 | if (WARN(sta->reserved_tid == tid, |
513 | "Requested to start BA session on reserved tid=%d", tid)) | 515 | "Requested to start BA session on reserved tid=%d", tid)) |
514 | return -EINVAL; | 516 | return -EINVAL; |
515 | 517 | ||
516 | trace_api_start_tx_ba_session(pubsta, tid); | 518 | if (!pubsta->ht_cap.ht_supported) |
519 | return -EINVAL; | ||
517 | 520 | ||
518 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) | 521 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) |
519 | return -EINVAL; | 522 | return -EINVAL; |
@@ -793,6 +796,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
793 | struct ieee80211_local *local = sdata->local; | 796 | struct ieee80211_local *local = sdata->local; |
794 | struct sta_info *sta; | 797 | struct sta_info *sta; |
795 | struct tid_ampdu_tx *tid_tx; | 798 | struct tid_ampdu_tx *tid_tx; |
799 | bool send_delba = false; | ||
796 | 800 | ||
797 | trace_api_stop_tx_ba_cb(sdata, ra, tid); | 801 | trace_api_stop_tx_ba_cb(sdata, ra, tid); |
798 | 802 | ||
@@ -824,13 +828,17 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
824 | } | 828 | } |
825 | 829 | ||
826 | if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop) | 830 | if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop) |
827 | ieee80211_send_delba(sta->sdata, ra, tid, | 831 | send_delba = true; |
828 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | ||
829 | 832 | ||
830 | ieee80211_remove_tid_tx(sta, tid); | 833 | ieee80211_remove_tid_tx(sta, tid); |
831 | 834 | ||
832 | unlock_sta: | 835 | unlock_sta: |
833 | spin_unlock_bh(&sta->lock); | 836 | spin_unlock_bh(&sta->lock); |
837 | |||
838 | if (send_delba) | ||
839 | ieee80211_send_delba(sdata, ra, tid, | ||
840 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | ||
841 | |||
834 | mutex_unlock(&sta->ampdu_mlme.mtx); | 842 | mutex_unlock(&sta->ampdu_mlme.mtx); |
835 | unlock: | 843 | unlock: |
836 | mutex_unlock(&local->sta_mtx); | 844 | mutex_unlock(&local->sta_mtx); |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 74f509c500f2..265e42721a66 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, | 25 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, |
26 | const char *name, | 26 | const char *name, |
27 | unsigned char name_assign_type, | ||
27 | enum nl80211_iftype type, | 28 | enum nl80211_iftype type, |
28 | u32 *flags, | 29 | u32 *flags, |
29 | struct vif_params *params) | 30 | struct vif_params *params) |
@@ -33,7 +34,7 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, | |||
33 | struct ieee80211_sub_if_data *sdata; | 34 | struct ieee80211_sub_if_data *sdata; |
34 | int err; | 35 | int err; |
35 | 36 | ||
36 | err = ieee80211_if_add(local, name, &wdev, type, params); | 37 | err = ieee80211_if_add(local, name, name_assign_type, &wdev, type, params); |
37 | if (err) | 38 | if (err) |
38 | return ERR_PTR(err); | 39 | return ERR_PTR(err); |
39 | 40 | ||
@@ -977,6 +978,14 @@ static int sta_apply_auth_flags(struct ieee80211_local *local, | |||
977 | if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) && | 978 | if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) && |
978 | set & BIT(NL80211_STA_FLAG_ASSOCIATED) && | 979 | set & BIT(NL80211_STA_FLAG_ASSOCIATED) && |
979 | !test_sta_flag(sta, WLAN_STA_ASSOC)) { | 980 | !test_sta_flag(sta, WLAN_STA_ASSOC)) { |
981 | /* | ||
982 | * When peer becomes associated, init rate control as | ||
983 | * well. Some drivers require rate control initialized | ||
984 | * before drv_sta_state() is called. | ||
985 | */ | ||
986 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
987 | rate_control_rate_init(sta); | ||
988 | |||
980 | ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | 989 | ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); |
981 | if (ret) | 990 | if (ret) |
982 | return ret; | 991 | return ret; |
@@ -1050,6 +1059,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1050 | } | 1059 | } |
1051 | } | 1060 | } |
1052 | 1061 | ||
1062 | if (mask & BIT(NL80211_STA_FLAG_WME) && | ||
1063 | local->hw.queues >= IEEE80211_NUM_ACS) | ||
1064 | sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME); | ||
1065 | |||
1053 | /* auth flags will be set later for TDLS stations */ | 1066 | /* auth flags will be set later for TDLS stations */ |
1054 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | 1067 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { |
1055 | ret = sta_apply_auth_flags(local, sta, mask, set); | 1068 | ret = sta_apply_auth_flags(local, sta, mask, set); |
@@ -1064,10 +1077,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1064 | clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE); | 1077 | clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE); |
1065 | } | 1078 | } |
1066 | 1079 | ||
1067 | if (mask & BIT(NL80211_STA_FLAG_WME)) | ||
1068 | sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME); | ||
1069 | |||
1070 | if (mask & BIT(NL80211_STA_FLAG_MFP)) { | 1080 | if (mask & BIT(NL80211_STA_FLAG_MFP)) { |
1081 | sta->sta.mfp = !!(set & BIT(NL80211_STA_FLAG_MFP)); | ||
1071 | if (set & BIT(NL80211_STA_FLAG_MFP)) | 1082 | if (set & BIT(NL80211_STA_FLAG_MFP)) |
1072 | set_sta_flag(sta, WLAN_STA_MFP); | 1083 | set_sta_flag(sta, WLAN_STA_MFP); |
1073 | else | 1084 | else |
@@ -1377,11 +1388,6 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
1377 | if (err) | 1388 | if (err) |
1378 | goto out_err; | 1389 | goto out_err; |
1379 | 1390 | ||
1380 | /* When peer becomes authorized, init rate control as well */ | ||
1381 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && | ||
1382 | test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
1383 | rate_control_rate_init(sta); | ||
1384 | |||
1385 | mutex_unlock(&local->sta_mtx); | 1391 | mutex_unlock(&local->sta_mtx); |
1386 | 1392 | ||
1387 | if ((sdata->vif.type == NL80211_IFTYPE_AP || | 1393 | if ((sdata->vif.type == NL80211_IFTYPE_AP || |
@@ -2273,7 +2279,6 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, | |||
2273 | { | 2279 | { |
2274 | struct sta_info *sta; | 2280 | struct sta_info *sta; |
2275 | enum ieee80211_smps_mode old_req; | 2281 | enum ieee80211_smps_mode old_req; |
2276 | int i; | ||
2277 | 2282 | ||
2278 | if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP)) | 2283 | if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP)) |
2279 | return -EINVAL; | 2284 | return -EINVAL; |
@@ -2297,52 +2302,44 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, | |||
2297 | } | 2302 | } |
2298 | 2303 | ||
2299 | ht_dbg(sdata, | 2304 | ht_dbg(sdata, |
2300 | "SMSP %d requested in AP mode, sending Action frame to %d stations\n", | 2305 | "SMPS %d requested in AP mode, sending Action frame to %d stations\n", |
2301 | smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta)); | 2306 | smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta)); |
2302 | 2307 | ||
2303 | mutex_lock(&sdata->local->sta_mtx); | 2308 | mutex_lock(&sdata->local->sta_mtx); |
2304 | for (i = 0; i < STA_HASH_SIZE; i++) { | 2309 | list_for_each_entry(sta, &sdata->local->sta_list, list) { |
2305 | for (sta = rcu_dereference_protected(sdata->local->sta_hash[i], | 2310 | /* |
2306 | lockdep_is_held(&sdata->local->sta_mtx)); | 2311 | * Only stations associated to our AP and |
2307 | sta; | 2312 | * associated VLANs |
2308 | sta = rcu_dereference_protected(sta->hnext, | 2313 | */ |
2309 | lockdep_is_held(&sdata->local->sta_mtx))) { | 2314 | if (sta->sdata->bss != &sdata->u.ap) |
2310 | /* | 2315 | continue; |
2311 | * Only stations associated to our AP and | ||
2312 | * associated VLANs | ||
2313 | */ | ||
2314 | if (sta->sdata->bss != &sdata->u.ap) | ||
2315 | continue; | ||
2316 | 2316 | ||
2317 | /* This station doesn't support MIMO - skip it */ | 2317 | /* This station doesn't support MIMO - skip it */ |
2318 | if (sta_info_tx_streams(sta) == 1) | 2318 | if (sta_info_tx_streams(sta) == 1) |
2319 | continue; | 2319 | continue; |
2320 | 2320 | ||
2321 | /* | 2321 | /* |
2322 | * Don't wake up a STA just to send the action frame | 2322 | * Don't wake up a STA just to send the action frame |
2323 | * unless we are getting more restrictive. | 2323 | * unless we are getting more restrictive. |
2324 | */ | 2324 | */ |
2325 | if (test_sta_flag(sta, WLAN_STA_PS_STA) && | 2325 | if (test_sta_flag(sta, WLAN_STA_PS_STA) && |
2326 | !ieee80211_smps_is_restrictive(sta->known_smps_mode, | 2326 | !ieee80211_smps_is_restrictive(sta->known_smps_mode, |
2327 | smps_mode)) { | 2327 | smps_mode)) { |
2328 | ht_dbg(sdata, | 2328 | ht_dbg(sdata, "Won't send SMPS to sleeping STA %pM\n", |
2329 | "Won't send SMPS to sleeping STA %pM\n", | 2329 | sta->sta.addr); |
2330 | sta->sta.addr); | 2330 | continue; |
2331 | continue; | 2331 | } |
2332 | } | ||
2333 | 2332 | ||
2334 | /* | 2333 | /* |
2335 | * If the STA is not authorized, wait until it gets | 2334 | * If the STA is not authorized, wait until it gets |
2336 | * authorized and the action frame will be sent then. | 2335 | * authorized and the action frame will be sent then. |
2337 | */ | 2336 | */ |
2338 | if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | 2337 | if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED)) |
2339 | continue; | 2338 | continue; |
2340 | 2339 | ||
2341 | ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr); | 2340 | ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr); |
2342 | ieee80211_send_smps_action(sdata, smps_mode, | 2341 | ieee80211_send_smps_action(sdata, smps_mode, sta->sta.addr, |
2343 | sta->sta.addr, | 2342 | sdata->vif.bss_conf.bssid); |
2344 | sdata->vif.bss_conf.bssid); | ||
2345 | } | ||
2346 | } | 2343 | } |
2347 | mutex_unlock(&sdata->local->sta_mtx); | 2344 | mutex_unlock(&sdata->local->sta_mtx); |
2348 | 2345 | ||
@@ -3581,7 +3578,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
3581 | nullfunc->qos_ctrl = cpu_to_le16(7); | 3578 | nullfunc->qos_ctrl = cpu_to_le16(7); |
3582 | 3579 | ||
3583 | local_bh_disable(); | 3580 | local_bh_disable(); |
3584 | ieee80211_xmit(sdata, skb); | 3581 | ieee80211_xmit(sdata, sta, skb); |
3585 | local_bh_enable(); | 3582 | local_bh_enable(); |
3586 | rcu_read_unlock(); | 3583 | rcu_read_unlock(); |
3587 | 3584 | ||
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index eeb0bbd69d98..23813ebb349c 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -18,172 +18,6 @@ | |||
18 | 18 | ||
19 | #define DEBUGFS_FORMAT_BUFFER_SIZE 100 | 19 | #define DEBUGFS_FORMAT_BUFFER_SIZE 100 |
20 | 20 | ||
21 | #define TX_LATENCY_BIN_DELIMTER_C ',' | ||
22 | #define TX_LATENCY_BIN_DELIMTER_S "," | ||
23 | #define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n" | ||
24 | #define TX_LATENCY_DISABLED "disable\n" | ||
25 | |||
26 | |||
27 | /* | ||
28 | * Display if Tx latency statistics & bins are enabled/disabled | ||
29 | */ | ||
30 | static ssize_t sta_tx_latency_stat_read(struct file *file, | ||
31 | char __user *userbuf, | ||
32 | size_t count, loff_t *ppos) | ||
33 | { | ||
34 | struct ieee80211_local *local = file->private_data; | ||
35 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
36 | char *buf; | ||
37 | int bufsz, i, ret; | ||
38 | int pos = 0; | ||
39 | |||
40 | rcu_read_lock(); | ||
41 | |||
42 | tx_latency = rcu_dereference(local->tx_latency); | ||
43 | |||
44 | if (tx_latency && tx_latency->n_ranges) { | ||
45 | bufsz = tx_latency->n_ranges * 15; | ||
46 | buf = kzalloc(bufsz, GFP_ATOMIC); | ||
47 | if (!buf) | ||
48 | goto err; | ||
49 | |||
50 | for (i = 0; i < tx_latency->n_ranges; i++) | ||
51 | pos += scnprintf(buf + pos, bufsz - pos, "%d,", | ||
52 | tx_latency->ranges[i]); | ||
53 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
54 | } else if (tx_latency) { | ||
55 | bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1; | ||
56 | buf = kzalloc(bufsz, GFP_ATOMIC); | ||
57 | if (!buf) | ||
58 | goto err; | ||
59 | |||
60 | pos += scnprintf(buf + pos, bufsz - pos, "%s\n", | ||
61 | TX_LATENCY_BINS_DISABLED); | ||
62 | } else { | ||
63 | bufsz = sizeof(TX_LATENCY_DISABLED) + 1; | ||
64 | buf = kzalloc(bufsz, GFP_ATOMIC); | ||
65 | if (!buf) | ||
66 | goto err; | ||
67 | |||
68 | pos += scnprintf(buf + pos, bufsz - pos, "%s\n", | ||
69 | TX_LATENCY_DISABLED); | ||
70 | } | ||
71 | |||
72 | rcu_read_unlock(); | ||
73 | |||
74 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
75 | kfree(buf); | ||
76 | |||
77 | return ret; | ||
78 | err: | ||
79 | rcu_read_unlock(); | ||
80 | return -ENOMEM; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Receive input from user regarding Tx latency statistics | ||
85 | * The input should indicate if Tx latency statistics and bins are | ||
86 | * enabled/disabled. | ||
87 | * If bins are enabled input should indicate the amount of different bins and | ||
88 | * their ranges. Each bin will count how many Tx frames transmitted within the | ||
89 | * appropriate latency. | ||
90 | * Legal input is: | ||
91 | * a) "enable(bins disabled)" - to enable only general statistics | ||
92 | * b) "a,b,c,d,...z" - to enable general statistics and bins, where all are | ||
93 | * numbers and a < b < c < d.. < z | ||
94 | * c) "disable" - disable all statistics | ||
95 | * NOTE: must configure Tx latency statistics bins before stations connected. | ||
96 | */ | ||
97 | |||
98 | static ssize_t sta_tx_latency_stat_write(struct file *file, | ||
99 | const char __user *userbuf, | ||
100 | size_t count, loff_t *ppos) | ||
101 | { | ||
102 | struct ieee80211_local *local = file->private_data; | ||
103 | char buf[128] = {}; | ||
104 | char *bins = buf; | ||
105 | char *token; | ||
106 | int buf_size, i, alloc_size; | ||
107 | int prev_bin = 0; | ||
108 | int n_ranges = 0; | ||
109 | int ret = count; | ||
110 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
111 | |||
112 | if (sizeof(buf) <= count) | ||
113 | return -EINVAL; | ||
114 | buf_size = count; | ||
115 | if (copy_from_user(buf, userbuf, buf_size)) | ||
116 | return -EFAULT; | ||
117 | |||
118 | mutex_lock(&local->sta_mtx); | ||
119 | |||
120 | /* cannot change config once we have stations */ | ||
121 | if (local->num_sta) | ||
122 | goto unlock; | ||
123 | |||
124 | tx_latency = | ||
125 | rcu_dereference_protected(local->tx_latency, | ||
126 | lockdep_is_held(&local->sta_mtx)); | ||
127 | |||
128 | /* disable Tx statistics */ | ||
129 | if (!strcmp(buf, TX_LATENCY_DISABLED)) { | ||
130 | if (!tx_latency) | ||
131 | goto unlock; | ||
132 | RCU_INIT_POINTER(local->tx_latency, NULL); | ||
133 | synchronize_rcu(); | ||
134 | kfree(tx_latency); | ||
135 | goto unlock; | ||
136 | } | ||
137 | |||
138 | /* Tx latency already enabled */ | ||
139 | if (tx_latency) | ||
140 | goto unlock; | ||
141 | |||
142 | if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) { | ||
143 | /* check how many bins and between what ranges user requested */ | ||
144 | token = buf; | ||
145 | while (*token != '\0') { | ||
146 | if (*token == TX_LATENCY_BIN_DELIMTER_C) | ||
147 | n_ranges++; | ||
148 | token++; | ||
149 | } | ||
150 | n_ranges++; | ||
151 | } | ||
152 | |||
153 | alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) + | ||
154 | n_ranges * sizeof(u32); | ||
155 | tx_latency = kzalloc(alloc_size, GFP_ATOMIC); | ||
156 | if (!tx_latency) { | ||
157 | ret = -ENOMEM; | ||
158 | goto unlock; | ||
159 | } | ||
160 | tx_latency->n_ranges = n_ranges; | ||
161 | for (i = 0; i < n_ranges; i++) { /* setting bin ranges */ | ||
162 | token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S); | ||
163 | sscanf(token, "%d", &tx_latency->ranges[i]); | ||
164 | /* bins values should be in ascending order */ | ||
165 | if (prev_bin >= tx_latency->ranges[i]) { | ||
166 | ret = -EINVAL; | ||
167 | kfree(tx_latency); | ||
168 | goto unlock; | ||
169 | } | ||
170 | prev_bin = tx_latency->ranges[i]; | ||
171 | } | ||
172 | rcu_assign_pointer(local->tx_latency, tx_latency); | ||
173 | |||
174 | unlock: | ||
175 | mutex_unlock(&local->sta_mtx); | ||
176 | |||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static const struct file_operations stats_tx_latency_ops = { | ||
181 | .write = sta_tx_latency_stat_write, | ||
182 | .read = sta_tx_latency_stat_read, | ||
183 | .open = simple_open, | ||
184 | .llseek = generic_file_llseek, | ||
185 | }; | ||
186 | |||
187 | int mac80211_format_buffer(char __user *userbuf, size_t count, | 21 | int mac80211_format_buffer(char __user *userbuf, size_t count, |
188 | loff_t *ppos, char *fmt, ...) | 22 | loff_t *ppos, char *fmt, ...) |
189 | { | 23 | { |
@@ -440,8 +274,6 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
440 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 274 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
441 | DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop); | 275 | DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop); |
442 | DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued); | 276 | DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued); |
443 | DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted, | ||
444 | local->tx_handlers_drop_unencrypted); | ||
445 | DEBUGFS_STATS_ADD(tx_handlers_drop_fragment, | 277 | DEBUGFS_STATS_ADD(tx_handlers_drop_fragment, |
446 | local->tx_handlers_drop_fragment); | 278 | local->tx_handlers_drop_fragment); |
447 | DEBUGFS_STATS_ADD(tx_handlers_drop_wep, | 279 | DEBUGFS_STATS_ADD(tx_handlers_drop_wep, |
@@ -475,6 +307,4 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
475 | DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); | 307 | DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); |
476 | DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); | 308 | DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); |
477 | DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); | 309 | DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); |
478 | |||
479 | DEBUGFS_DEVSTATS_ADD(tx_latency); | ||
480 | } | 310 | } |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index c68896adfa96..29236e832e44 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -177,7 +177,6 @@ static ssize_t ieee80211_if_write_##name(struct file *file, \ | |||
177 | IEEE80211_IF_FILE_R(name) | 177 | IEEE80211_IF_FILE_R(name) |
178 | 178 | ||
179 | /* common attributes */ | 179 | /* common attributes */ |
180 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | ||
181 | IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ], | 180 | IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ], |
182 | HEX); | 181 | HEX); |
183 | IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], | 182 | IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], |
@@ -562,7 +561,6 @@ IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration, | |||
562 | 561 | ||
563 | static void add_common_files(struct ieee80211_sub_if_data *sdata) | 562 | static void add_common_files(struct ieee80211_sub_if_data *sdata) |
564 | { | 563 | { |
565 | DEBUGFS_ADD(drop_unencrypted); | ||
566 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | 564 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
567 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 565 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
568 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | 566 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 94c70091bbd7..252859e90e8a 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -39,13 +39,6 @@ static const struct file_operations sta_ ##name## _ops = { \ | |||
39 | .llseek = generic_file_llseek, \ | 39 | .llseek = generic_file_llseek, \ |
40 | } | 40 | } |
41 | 41 | ||
42 | #define STA_OPS_W(name) \ | ||
43 | static const struct file_operations sta_ ##name## _ops = { \ | ||
44 | .write = sta_##name##_write, \ | ||
45 | .open = simple_open, \ | ||
46 | .llseek = generic_file_llseek, \ | ||
47 | } | ||
48 | |||
49 | #define STA_OPS_RW(name) \ | 42 | #define STA_OPS_RW(name) \ |
50 | static const struct file_operations sta_ ##name## _ops = { \ | 43 | static const struct file_operations sta_ ##name## _ops = { \ |
51 | .read = sta_##name##_read, \ | 44 | .read = sta_##name##_read, \ |
@@ -398,131 +391,6 @@ static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf, | |||
398 | } | 391 | } |
399 | STA_OPS(last_rx_rate); | 392 | STA_OPS(last_rx_rate); |
400 | 393 | ||
401 | static int | ||
402 | sta_tx_latency_stat_header(struct ieee80211_tx_latency_bin_ranges *tx_latency, | ||
403 | char *buf, int pos, int bufsz) | ||
404 | { | ||
405 | int i; | ||
406 | int range_count = tx_latency->n_ranges; | ||
407 | u32 *bin_ranges = tx_latency->ranges; | ||
408 | |||
409 | pos += scnprintf(buf + pos, bufsz - pos, | ||
410 | "Station\t\t\tTID\tMax\tAvg"); | ||
411 | if (range_count) { | ||
412 | pos += scnprintf(buf + pos, bufsz - pos, | ||
413 | "\t<=%d", bin_ranges[0]); | ||
414 | for (i = 0; i < range_count - 1; i++) | ||
415 | pos += scnprintf(buf + pos, bufsz - pos, "\t%d-%d", | ||
416 | bin_ranges[i], bin_ranges[i+1]); | ||
417 | pos += scnprintf(buf + pos, bufsz - pos, | ||
418 | "\t%d<", bin_ranges[range_count - 1]); | ||
419 | } | ||
420 | |||
421 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
422 | |||
423 | return pos; | ||
424 | } | ||
425 | |||
426 | static int | ||
427 | sta_tx_latency_stat_table(struct ieee80211_tx_latency_bin_ranges *tx_lat_range, | ||
428 | struct ieee80211_tx_latency_stat *tx_lat, | ||
429 | char *buf, int pos, int bufsz, int tid) | ||
430 | { | ||
431 | u32 avg = 0; | ||
432 | int j; | ||
433 | int bin_count = tx_lat->bin_count; | ||
434 | |||
435 | pos += scnprintf(buf + pos, bufsz - pos, "\t\t\t%d", tid); | ||
436 | /* make sure you don't divide in 0 */ | ||
437 | if (tx_lat->counter) | ||
438 | avg = tx_lat->sum / tx_lat->counter; | ||
439 | |||
440 | pos += scnprintf(buf + pos, bufsz - pos, "\t%d\t%d", | ||
441 | tx_lat->max, avg); | ||
442 | |||
443 | if (tx_lat_range->n_ranges && tx_lat->bins) | ||
444 | for (j = 0; j < bin_count; j++) | ||
445 | pos += scnprintf(buf + pos, bufsz - pos, | ||
446 | "\t%d", tx_lat->bins[j]); | ||
447 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
448 | |||
449 | return pos; | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * Output Tx latency statistics station && restart all statistics information | ||
454 | */ | ||
455 | static ssize_t sta_tx_latency_stat_read(struct file *file, | ||
456 | char __user *userbuf, | ||
457 | size_t count, loff_t *ppos) | ||
458 | { | ||
459 | struct sta_info *sta = file->private_data; | ||
460 | struct ieee80211_local *local = sta->local; | ||
461 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
462 | char *buf; | ||
463 | int bufsz, ret, i; | ||
464 | int pos = 0; | ||
465 | |||
466 | bufsz = 20 * IEEE80211_NUM_TIDS * | ||
467 | sizeof(struct ieee80211_tx_latency_stat); | ||
468 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
469 | if (!buf) | ||
470 | return -ENOMEM; | ||
471 | |||
472 | rcu_read_lock(); | ||
473 | |||
474 | tx_latency = rcu_dereference(local->tx_latency); | ||
475 | |||
476 | if (!sta->tx_lat) { | ||
477 | pos += scnprintf(buf + pos, bufsz - pos, | ||
478 | "Tx latency statistics are not enabled\n"); | ||
479 | goto unlock; | ||
480 | } | ||
481 | |||
482 | pos = sta_tx_latency_stat_header(tx_latency, buf, pos, bufsz); | ||
483 | |||
484 | pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", sta->sta.addr); | ||
485 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | ||
486 | pos = sta_tx_latency_stat_table(tx_latency, &sta->tx_lat[i], | ||
487 | buf, pos, bufsz, i); | ||
488 | unlock: | ||
489 | rcu_read_unlock(); | ||
490 | |||
491 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
492 | kfree(buf); | ||
493 | |||
494 | return ret; | ||
495 | } | ||
496 | STA_OPS(tx_latency_stat); | ||
497 | |||
498 | static ssize_t sta_tx_latency_stat_reset_write(struct file *file, | ||
499 | const char __user *userbuf, | ||
500 | size_t count, loff_t *ppos) | ||
501 | { | ||
502 | u32 *bins; | ||
503 | int bin_count; | ||
504 | struct sta_info *sta = file->private_data; | ||
505 | int i; | ||
506 | |||
507 | if (!sta->tx_lat) | ||
508 | return -EINVAL; | ||
509 | |||
510 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | ||
511 | bins = sta->tx_lat[i].bins; | ||
512 | bin_count = sta->tx_lat[i].bin_count; | ||
513 | |||
514 | sta->tx_lat[i].max = 0; | ||
515 | sta->tx_lat[i].sum = 0; | ||
516 | sta->tx_lat[i].counter = 0; | ||
517 | |||
518 | if (bin_count) | ||
519 | memset(bins, 0, bin_count * sizeof(u32)); | ||
520 | } | ||
521 | |||
522 | return count; | ||
523 | } | ||
524 | STA_OPS_W(tx_latency_stat_reset); | ||
525 | |||
526 | #define DEBUGFS_ADD(name) \ | 394 | #define DEBUGFS_ADD(name) \ |
527 | debugfs_create_file(#name, 0400, \ | 395 | debugfs_create_file(#name, 0400, \ |
528 | sta->debugfs.dir, sta, &sta_ ##name## _ops); | 396 | sta->debugfs.dir, sta, &sta_ ##name## _ops); |
@@ -576,8 +444,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
576 | DEBUGFS_ADD(last_ack_signal); | 444 | DEBUGFS_ADD(last_ack_signal); |
577 | DEBUGFS_ADD(current_tx_rate); | 445 | DEBUGFS_ADD(current_tx_rate); |
578 | DEBUGFS_ADD(last_rx_rate); | 446 | DEBUGFS_ADD(last_rx_rate); |
579 | DEBUGFS_ADD(tx_latency_stat); | ||
580 | DEBUGFS_ADD(tx_latency_stat_reset); | ||
581 | 447 | ||
582 | DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); | 448 | DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); |
583 | DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); | 449 | DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index fdeda17b8dd2..0a39d3db951a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -941,13 +941,13 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local, | |||
941 | trace_drv_return_void(local); | 941 | trace_drv_return_void(local); |
942 | } | 942 | } |
943 | 943 | ||
944 | static inline void drv_rssi_callback(struct ieee80211_local *local, | 944 | static inline void drv_event_callback(struct ieee80211_local *local, |
945 | struct ieee80211_sub_if_data *sdata, | 945 | struct ieee80211_sub_if_data *sdata, |
946 | const enum ieee80211_rssi_event event) | 946 | const struct ieee80211_event *event) |
947 | { | 947 | { |
948 | trace_drv_rssi_callback(local, sdata, event); | 948 | trace_drv_event_callback(local, sdata, event); |
949 | if (local->ops->rssi_callback) | 949 | if (local->ops->event_callback) |
950 | local->ops->rssi_callback(&local->hw, &sdata->vif, event); | 950 | local->ops->event_callback(&local->hw, &sdata->vif, event); |
951 | trace_drv_return_void(local); | 951 | trace_drv_return_void(local); |
952 | } | 952 | } |
953 | 953 | ||
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index ff630be2ca75..7a76ce639d58 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -252,8 +252,6 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
252 | break; | 252 | break; |
253 | } | 253 | } |
254 | 254 | ||
255 | if (bw != sta->sta.bandwidth) | ||
256 | changed = true; | ||
257 | sta->sta.bandwidth = bw; | 255 | sta->sta.bandwidth = bw; |
258 | 256 | ||
259 | sta->cur_max_bandwidth = | 257 | sta->cur_max_bandwidth = |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index f9b07588baf5..bfef1b215050 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -188,6 +188,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, | |||
188 | */ | 188 | */ |
189 | pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, | 189 | pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, |
190 | chandef, 0); | 190 | chandef, 0); |
191 | |||
192 | /* add VHT capability and information IEs */ | ||
193 | if (chandef->width != NL80211_CHAN_WIDTH_20 && | ||
194 | chandef->width != NL80211_CHAN_WIDTH_40 && | ||
195 | sband->vht_cap.vht_supported) { | ||
196 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, | ||
197 | sband->vht_cap.cap); | ||
198 | pos = ieee80211_ie_build_vht_oper(pos, &sband->vht_cap, | ||
199 | chandef); | ||
200 | } | ||
191 | } | 201 | } |
192 | 202 | ||
193 | if (local->hw.queues >= IEEE80211_NUM_ACS) | 203 | if (local->hw.queues >= IEEE80211_NUM_ACS) |
@@ -249,8 +259,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
249 | if (presp) | 259 | if (presp) |
250 | kfree_rcu(presp, rcu_head); | 260 | kfree_rcu(presp, rcu_head); |
251 | 261 | ||
252 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
253 | |||
254 | /* make a copy of the chandef, it could be modified below. */ | 262 | /* make a copy of the chandef, it could be modified below. */ |
255 | chandef = *req_chandef; | 263 | chandef = *req_chandef; |
256 | chan = chandef.chan; | 264 | chan = chandef.chan; |
@@ -417,6 +425,11 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
417 | NL80211_CHAN_WIDTH_20_NOHT); | 425 | NL80211_CHAN_WIDTH_20_NOHT); |
418 | chandef.width = sdata->u.ibss.chandef.width; | 426 | chandef.width = sdata->u.ibss.chandef.width; |
419 | break; | 427 | break; |
428 | case NL80211_CHAN_WIDTH_80: | ||
429 | case NL80211_CHAN_WIDTH_160: | ||
430 | chandef = sdata->u.ibss.chandef; | ||
431 | chandef.chan = cbss->channel; | ||
432 | break; | ||
420 | default: | 433 | default: |
421 | /* fall back to 20 MHz for unsupported modes */ | 434 | /* fall back to 20 MHz for unsupported modes */ |
422 | cfg80211_chandef_create(&chandef, cbss->channel, | 435 | cfg80211_chandef_create(&chandef, cbss->channel, |
@@ -470,22 +483,19 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
470 | struct beacon_data *presp, *old_presp; | 483 | struct beacon_data *presp, *old_presp; |
471 | struct cfg80211_bss *cbss; | 484 | struct cfg80211_bss *cbss; |
472 | const struct cfg80211_bss_ies *ies; | 485 | const struct cfg80211_bss_ies *ies; |
473 | u16 capability; | 486 | u16 capability = 0; |
474 | u64 tsf; | 487 | u64 tsf; |
475 | int ret = 0; | 488 | int ret = 0; |
476 | 489 | ||
477 | sdata_assert_lock(sdata); | 490 | sdata_assert_lock(sdata); |
478 | 491 | ||
479 | capability = WLAN_CAPABILITY_IBSS; | ||
480 | |||
481 | if (ifibss->privacy) | 492 | if (ifibss->privacy) |
482 | capability |= WLAN_CAPABILITY_PRIVACY; | 493 | capability = WLAN_CAPABILITY_PRIVACY; |
483 | 494 | ||
484 | cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan, | 495 | cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan, |
485 | ifibss->bssid, ifibss->ssid, | 496 | ifibss->bssid, ifibss->ssid, |
486 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | 497 | ifibss->ssid_len, IEEE80211_BSS_TYPE_IBSS, |
487 | WLAN_CAPABILITY_PRIVACY, | 498 | IEEE80211_PRIVACY(ifibss->privacy)); |
488 | capability); | ||
489 | 499 | ||
490 | if (WARN_ON(!cbss)) { | 500 | if (WARN_ON(!cbss)) { |
491 | ret = -EINVAL; | 501 | ret = -EINVAL; |
@@ -525,23 +535,17 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
525 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 535 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
526 | struct cfg80211_bss *cbss; | 536 | struct cfg80211_bss *cbss; |
527 | int err, changed = 0; | 537 | int err, changed = 0; |
528 | u16 capability; | ||
529 | 538 | ||
530 | sdata_assert_lock(sdata); | 539 | sdata_assert_lock(sdata); |
531 | 540 | ||
532 | /* update cfg80211 bss information with the new channel */ | 541 | /* update cfg80211 bss information with the new channel */ |
533 | if (!is_zero_ether_addr(ifibss->bssid)) { | 542 | if (!is_zero_ether_addr(ifibss->bssid)) { |
534 | capability = WLAN_CAPABILITY_IBSS; | ||
535 | |||
536 | if (ifibss->privacy) | ||
537 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
538 | |||
539 | cbss = cfg80211_get_bss(sdata->local->hw.wiphy, | 543 | cbss = cfg80211_get_bss(sdata->local->hw.wiphy, |
540 | ifibss->chandef.chan, | 544 | ifibss->chandef.chan, |
541 | ifibss->bssid, ifibss->ssid, | 545 | ifibss->bssid, ifibss->ssid, |
542 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | 546 | ifibss->ssid_len, |
543 | WLAN_CAPABILITY_PRIVACY, | 547 | IEEE80211_BSS_TYPE_IBSS, |
544 | capability); | 548 | IEEE80211_PRIVACY(ifibss->privacy)); |
545 | /* XXX: should not really modify cfg80211 data */ | 549 | /* XXX: should not really modify cfg80211 data */ |
546 | if (cbss) { | 550 | if (cbss) { |
547 | cbss->channel = sdata->csa_chandef.chan; | 551 | cbss->channel = sdata->csa_chandef.chan; |
@@ -682,19 +686,13 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) | |||
682 | struct cfg80211_bss *cbss; | 686 | struct cfg80211_bss *cbss; |
683 | struct beacon_data *presp; | 687 | struct beacon_data *presp; |
684 | struct sta_info *sta; | 688 | struct sta_info *sta; |
685 | u16 capability; | ||
686 | 689 | ||
687 | if (!is_zero_ether_addr(ifibss->bssid)) { | 690 | if (!is_zero_ether_addr(ifibss->bssid)) { |
688 | capability = WLAN_CAPABILITY_IBSS; | ||
689 | |||
690 | if (ifibss->privacy) | ||
691 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
692 | |||
693 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, | 691 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, |
694 | ifibss->bssid, ifibss->ssid, | 692 | ifibss->bssid, ifibss->ssid, |
695 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | 693 | ifibss->ssid_len, |
696 | WLAN_CAPABILITY_PRIVACY, | 694 | IEEE80211_BSS_TYPE_IBSS, |
697 | capability); | 695 | IEEE80211_PRIVACY(ifibss->privacy)); |
698 | 696 | ||
699 | if (cbss) { | 697 | if (cbss) { |
700 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | 698 | cfg80211_unlink_bss(local->hw.wiphy, cbss); |
@@ -980,110 +978,140 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
980 | mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0); | 978 | mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0); |
981 | } | 979 | } |
982 | 980 | ||
983 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 981 | static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, |
984 | struct ieee80211_mgmt *mgmt, size_t len, | 982 | struct ieee80211_mgmt *mgmt, size_t len, |
985 | struct ieee80211_rx_status *rx_status, | 983 | struct ieee80211_rx_status *rx_status, |
986 | struct ieee802_11_elems *elems) | 984 | struct ieee802_11_elems *elems, |
985 | struct ieee80211_channel *channel) | ||
987 | { | 986 | { |
988 | struct ieee80211_local *local = sdata->local; | ||
989 | struct cfg80211_bss *cbss; | ||
990 | struct ieee80211_bss *bss; | ||
991 | struct sta_info *sta; | 987 | struct sta_info *sta; |
992 | struct ieee80211_channel *channel; | ||
993 | u64 beacon_timestamp, rx_timestamp; | ||
994 | u32 supp_rates = 0; | ||
995 | enum ieee80211_band band = rx_status->band; | 988 | enum ieee80211_band band = rx_status->band; |
996 | enum nl80211_bss_scan_width scan_width; | 989 | enum nl80211_bss_scan_width scan_width; |
990 | struct ieee80211_local *local = sdata->local; | ||
997 | struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; | 991 | struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; |
998 | bool rates_updated = false; | 992 | bool rates_updated = false; |
993 | u32 supp_rates = 0; | ||
999 | 994 | ||
1000 | channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); | 995 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) |
1001 | if (!channel) | ||
1002 | return; | 996 | return; |
1003 | 997 | ||
1004 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 998 | if (!ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid)) |
1005 | ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid)) { | 999 | return; |
1006 | 1000 | ||
1007 | rcu_read_lock(); | 1001 | rcu_read_lock(); |
1008 | sta = sta_info_get(sdata, mgmt->sa); | 1002 | sta = sta_info_get(sdata, mgmt->sa); |
1009 | 1003 | ||
1010 | if (elems->supp_rates) { | 1004 | if (elems->supp_rates) { |
1011 | supp_rates = ieee80211_sta_get_rates(sdata, elems, | 1005 | supp_rates = ieee80211_sta_get_rates(sdata, elems, |
1012 | band, NULL); | 1006 | band, NULL); |
1013 | if (sta) { | 1007 | if (sta) { |
1014 | u32 prev_rates; | 1008 | u32 prev_rates; |
1015 | 1009 | ||
1016 | prev_rates = sta->sta.supp_rates[band]; | 1010 | prev_rates = sta->sta.supp_rates[band]; |
1017 | /* make sure mandatory rates are always added */ | 1011 | /* make sure mandatory rates are always added */ |
1018 | scan_width = NL80211_BSS_CHAN_WIDTH_20; | 1012 | scan_width = NL80211_BSS_CHAN_WIDTH_20; |
1019 | if (rx_status->flag & RX_FLAG_5MHZ) | 1013 | if (rx_status->flag & RX_FLAG_5MHZ) |
1020 | scan_width = NL80211_BSS_CHAN_WIDTH_5; | 1014 | scan_width = NL80211_BSS_CHAN_WIDTH_5; |
1021 | if (rx_status->flag & RX_FLAG_10MHZ) | 1015 | if (rx_status->flag & RX_FLAG_10MHZ) |
1022 | scan_width = NL80211_BSS_CHAN_WIDTH_10; | 1016 | scan_width = NL80211_BSS_CHAN_WIDTH_10; |
1023 | 1017 | ||
1024 | sta->sta.supp_rates[band] = supp_rates | | 1018 | sta->sta.supp_rates[band] = supp_rates | |
1025 | ieee80211_mandatory_rates(sband, | 1019 | ieee80211_mandatory_rates(sband, scan_width); |
1026 | scan_width); | 1020 | if (sta->sta.supp_rates[band] != prev_rates) { |
1027 | if (sta->sta.supp_rates[band] != prev_rates) { | 1021 | ibss_dbg(sdata, |
1028 | ibss_dbg(sdata, | 1022 | "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", |
1029 | "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", | 1023 | sta->sta.addr, prev_rates, |
1030 | sta->sta.addr, prev_rates, | 1024 | sta->sta.supp_rates[band]); |
1031 | sta->sta.supp_rates[band]); | 1025 | rates_updated = true; |
1032 | rates_updated = true; | ||
1033 | } | ||
1034 | } else { | ||
1035 | rcu_read_unlock(); | ||
1036 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, | ||
1037 | mgmt->sa, supp_rates); | ||
1038 | } | 1026 | } |
1027 | } else { | ||
1028 | rcu_read_unlock(); | ||
1029 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, | ||
1030 | mgmt->sa, supp_rates); | ||
1039 | } | 1031 | } |
1032 | } | ||
1040 | 1033 | ||
1041 | if (sta && elems->wmm_info) | 1034 | if (sta && elems->wmm_info && local->hw.queues >= IEEE80211_NUM_ACS) |
1042 | sta->sta.wme = true; | 1035 | sta->sta.wme = true; |
1043 | 1036 | ||
1044 | if (sta && elems->ht_operation && elems->ht_cap_elem && | 1037 | if (sta && elems->ht_operation && elems->ht_cap_elem && |
1045 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | 1038 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && |
1046 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 && | 1039 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 && |
1047 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) { | 1040 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) { |
1048 | /* we both use HT */ | 1041 | /* we both use HT */ |
1049 | struct ieee80211_ht_cap htcap_ie; | 1042 | struct ieee80211_ht_cap htcap_ie; |
1050 | struct cfg80211_chan_def chandef; | 1043 | struct cfg80211_chan_def chandef; |
1051 | 1044 | enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth; | |
1052 | ieee80211_ht_oper_to_chandef(channel, | 1045 | |
1053 | elems->ht_operation, | 1046 | ieee80211_ht_oper_to_chandef(channel, |
1054 | &chandef); | 1047 | elems->ht_operation, |
1055 | 1048 | &chandef); | |
1056 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); | 1049 | |
1057 | 1050 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); | |
1058 | /* | 1051 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1059 | * fall back to HT20 if we don't use or use | 1052 | &htcap_ie, |
1060 | * the other extension channel | 1053 | sta); |
1061 | */ | 1054 | |
1062 | if (chandef.center_freq1 != | 1055 | if (elems->vht_operation && elems->vht_cap_elem && |
1063 | sdata->u.ibss.chandef.center_freq1) | 1056 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20 && |
1064 | htcap_ie.cap_info &= | 1057 | sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_40) { |
1065 | cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40); | 1058 | /* we both use VHT */ |
1066 | 1059 | struct ieee80211_vht_cap cap_ie; | |
1067 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap( | 1060 | struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap; |
1068 | sdata, sband, &htcap_ie, sta); | 1061 | |
1062 | ieee80211_vht_oper_to_chandef(channel, | ||
1063 | elems->vht_operation, | ||
1064 | &chandef); | ||
1065 | memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); | ||
1066 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | ||
1067 | &cap_ie, sta); | ||
1068 | if (memcmp(&cap, &sta->sta.vht_cap, sizeof(cap))) | ||
1069 | rates_updated |= true; | ||
1069 | } | 1070 | } |
1070 | 1071 | ||
1071 | if (sta && rates_updated) { | 1072 | if (bw != sta->sta.bandwidth) |
1072 | u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; | 1073 | rates_updated |= true; |
1073 | u8 rx_nss = sta->sta.rx_nss; | ||
1074 | 1074 | ||
1075 | /* Force rx_nss recalculation */ | 1075 | if (!cfg80211_chandef_compatible(&sdata->u.ibss.chandef, |
1076 | sta->sta.rx_nss = 0; | 1076 | &chandef)) |
1077 | rate_control_rate_init(sta); | 1077 | WARN_ON_ONCE(1); |
1078 | if (sta->sta.rx_nss != rx_nss) | 1078 | } |
1079 | changed |= IEEE80211_RC_NSS_CHANGED; | ||
1080 | 1079 | ||
1081 | drv_sta_rc_update(local, sdata, &sta->sta, changed); | 1080 | if (sta && rates_updated) { |
1082 | } | 1081 | u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; |
1082 | u8 rx_nss = sta->sta.rx_nss; | ||
1083 | 1083 | ||
1084 | rcu_read_unlock(); | 1084 | /* Force rx_nss recalculation */ |
1085 | sta->sta.rx_nss = 0; | ||
1086 | rate_control_rate_init(sta); | ||
1087 | if (sta->sta.rx_nss != rx_nss) | ||
1088 | changed |= IEEE80211_RC_NSS_CHANGED; | ||
1089 | |||
1090 | drv_sta_rc_update(local, sdata, &sta->sta, changed); | ||
1085 | } | 1091 | } |
1086 | 1092 | ||
1093 | rcu_read_unlock(); | ||
1094 | } | ||
1095 | |||
1096 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||
1097 | struct ieee80211_mgmt *mgmt, size_t len, | ||
1098 | struct ieee80211_rx_status *rx_status, | ||
1099 | struct ieee802_11_elems *elems) | ||
1100 | { | ||
1101 | struct ieee80211_local *local = sdata->local; | ||
1102 | struct cfg80211_bss *cbss; | ||
1103 | struct ieee80211_bss *bss; | ||
1104 | struct ieee80211_channel *channel; | ||
1105 | u64 beacon_timestamp, rx_timestamp; | ||
1106 | u32 supp_rates = 0; | ||
1107 | enum ieee80211_band band = rx_status->band; | ||
1108 | |||
1109 | channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); | ||
1110 | if (!channel) | ||
1111 | return; | ||
1112 | |||
1113 | ieee80211_update_sta_info(sdata, mgmt, len, rx_status, elems, channel); | ||
1114 | |||
1087 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 1115 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
1088 | channel); | 1116 | channel); |
1089 | if (!bss) | 1117 | if (!bss) |
@@ -1273,7 +1301,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
1273 | 1301 | ||
1274 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); | 1302 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); |
1275 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, | 1303 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, |
1276 | NULL, scan_width); | 1304 | NULL, 0, scan_width); |
1277 | } | 1305 | } |
1278 | 1306 | ||
1279 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | 1307 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) |
@@ -1304,14 +1332,82 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
1304 | 1332 | ||
1305 | if (ifibss->privacy) | 1333 | if (ifibss->privacy) |
1306 | capability |= WLAN_CAPABILITY_PRIVACY; | 1334 | capability |= WLAN_CAPABILITY_PRIVACY; |
1307 | else | ||
1308 | sdata->drop_unencrypted = 0; | ||
1309 | 1335 | ||
1310 | __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, | 1336 | __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, |
1311 | &ifibss->chandef, ifibss->basic_rates, | 1337 | &ifibss->chandef, ifibss->basic_rates, |
1312 | capability, 0, true); | 1338 | capability, 0, true); |
1313 | } | 1339 | } |
1314 | 1340 | ||
1341 | static unsigned ibss_setup_channels(struct wiphy *wiphy, | ||
1342 | struct ieee80211_channel **channels, | ||
1343 | unsigned int channels_max, | ||
1344 | u32 center_freq, u32 width) | ||
1345 | { | ||
1346 | struct ieee80211_channel *chan = NULL; | ||
1347 | unsigned int n_chan = 0; | ||
1348 | u32 start_freq, end_freq, freq; | ||
1349 | |||
1350 | if (width <= 20) { | ||
1351 | start_freq = center_freq; | ||
1352 | end_freq = center_freq; | ||
1353 | } else { | ||
1354 | start_freq = center_freq - width / 2 + 10; | ||
1355 | end_freq = center_freq + width / 2 - 10; | ||
1356 | } | ||
1357 | |||
1358 | for (freq = start_freq; freq <= end_freq; freq += 20) { | ||
1359 | chan = ieee80211_get_channel(wiphy, freq); | ||
1360 | if (!chan) | ||
1361 | continue; | ||
1362 | if (n_chan >= channels_max) | ||
1363 | return n_chan; | ||
1364 | |||
1365 | channels[n_chan] = chan; | ||
1366 | n_chan++; | ||
1367 | } | ||
1368 | |||
1369 | return n_chan; | ||
1370 | } | ||
1371 | |||
1372 | static unsigned int | ||
1373 | ieee80211_ibss_setup_scan_channels(struct wiphy *wiphy, | ||
1374 | const struct cfg80211_chan_def *chandef, | ||
1375 | struct ieee80211_channel **channels, | ||
1376 | unsigned int channels_max) | ||
1377 | { | ||
1378 | unsigned int n_chan = 0; | ||
1379 | u32 width, cf1, cf2 = 0; | ||
1380 | |||
1381 | switch (chandef->width) { | ||
1382 | case NL80211_CHAN_WIDTH_40: | ||
1383 | width = 40; | ||
1384 | break; | ||
1385 | case NL80211_CHAN_WIDTH_80P80: | ||
1386 | cf2 = chandef->center_freq2; | ||
1387 | /* fall through */ | ||
1388 | case NL80211_CHAN_WIDTH_80: | ||
1389 | width = 80; | ||
1390 | break; | ||
1391 | case NL80211_CHAN_WIDTH_160: | ||
1392 | width = 160; | ||
1393 | break; | ||
1394 | default: | ||
1395 | width = 20; | ||
1396 | break; | ||
1397 | } | ||
1398 | |||
1399 | cf1 = chandef->center_freq1; | ||
1400 | |||
1401 | n_chan = ibss_setup_channels(wiphy, channels, channels_max, cf1, width); | ||
1402 | |||
1403 | if (cf2) | ||
1404 | n_chan += ibss_setup_channels(wiphy, &channels[n_chan], | ||
1405 | channels_max - n_chan, cf2, | ||
1406 | width); | ||
1407 | |||
1408 | return n_chan; | ||
1409 | } | ||
1410 | |||
1315 | /* | 1411 | /* |
1316 | * This function is called with state == IEEE80211_IBSS_MLME_SEARCH | 1412 | * This function is called with state == IEEE80211_IBSS_MLME_SEARCH |
1317 | */ | 1413 | */ |
@@ -1325,7 +1421,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
1325 | const u8 *bssid = NULL; | 1421 | const u8 *bssid = NULL; |
1326 | enum nl80211_bss_scan_width scan_width; | 1422 | enum nl80211_bss_scan_width scan_width; |
1327 | int active_ibss; | 1423 | int active_ibss; |
1328 | u16 capability; | ||
1329 | 1424 | ||
1330 | sdata_assert_lock(sdata); | 1425 | sdata_assert_lock(sdata); |
1331 | 1426 | ||
@@ -1335,9 +1430,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
1335 | if (active_ibss) | 1430 | if (active_ibss) |
1336 | return; | 1431 | return; |
1337 | 1432 | ||
1338 | capability = WLAN_CAPABILITY_IBSS; | ||
1339 | if (ifibss->privacy) | ||
1340 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
1341 | if (ifibss->fixed_bssid) | 1433 | if (ifibss->fixed_bssid) |
1342 | bssid = ifibss->bssid; | 1434 | bssid = ifibss->bssid; |
1343 | if (ifibss->fixed_channel) | 1435 | if (ifibss->fixed_channel) |
@@ -1346,8 +1438,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
1346 | bssid = ifibss->bssid; | 1438 | bssid = ifibss->bssid; |
1347 | cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, | 1439 | cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, |
1348 | ifibss->ssid, ifibss->ssid_len, | 1440 | ifibss->ssid, ifibss->ssid_len, |
1349 | WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY, | 1441 | IEEE80211_BSS_TYPE_IBSS, |
1350 | capability); | 1442 | IEEE80211_PRIVACY(ifibss->privacy)); |
1351 | 1443 | ||
1352 | if (cbss) { | 1444 | if (cbss) { |
1353 | struct ieee80211_bss *bss; | 1445 | struct ieee80211_bss *bss; |
@@ -1381,11 +1473,18 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
1381 | /* Selected IBSS not found in current scan results - try to scan */ | 1473 | /* Selected IBSS not found in current scan results - try to scan */ |
1382 | if (time_after(jiffies, ifibss->last_scan_completed + | 1474 | if (time_after(jiffies, ifibss->last_scan_completed + |
1383 | IEEE80211_SCAN_INTERVAL)) { | 1475 | IEEE80211_SCAN_INTERVAL)) { |
1476 | struct ieee80211_channel *channels[8]; | ||
1477 | unsigned int num; | ||
1478 | |||
1384 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); | 1479 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); |
1385 | 1480 | ||
1481 | num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy, | ||
1482 | &ifibss->chandef, | ||
1483 | channels, | ||
1484 | ARRAY_SIZE(channels)); | ||
1386 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); | 1485 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); |
1387 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, | 1486 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, |
1388 | ifibss->ssid_len, chan, | 1487 | ifibss->ssid_len, channels, num, |
1389 | scan_width); | 1488 | scan_width); |
1390 | } else { | 1489 | } else { |
1391 | int interval = IEEE80211_SCAN_INTERVAL; | 1490 | int interval = IEEE80211_SCAN_INTERVAL; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8d53d65bd2ab..487f5e2a9283 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -830,8 +830,6 @@ struct ieee80211_sub_if_data { | |||
830 | 830 | ||
831 | unsigned long state; | 831 | unsigned long state; |
832 | 832 | ||
833 | int drop_unencrypted; | ||
834 | |||
835 | char name[IFNAMSIZ]; | 833 | char name[IFNAMSIZ]; |
836 | 834 | ||
837 | /* Fragment table for host-based reassembly */ | 835 | /* Fragment table for host-based reassembly */ |
@@ -1042,24 +1040,6 @@ struct tpt_led_trigger { | |||
1042 | }; | 1040 | }; |
1043 | #endif | 1041 | #endif |
1044 | 1042 | ||
1045 | /* | ||
1046 | * struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges | ||
1047 | * | ||
1048 | * Measuring Tx latency statistics. Counts how many Tx frames transmitted in a | ||
1049 | * certain latency range (in Milliseconds). Each station that uses these | ||
1050 | * ranges will have bins to count the amount of frames received in that range. | ||
1051 | * The user can configure the ranges via debugfs. | ||
1052 | * If ranges is NULL then Tx latency statistics bins are disabled for all | ||
1053 | * stations. | ||
1054 | * | ||
1055 | * @n_ranges: number of ranges that are taken in account | ||
1056 | * @ranges: the ranges that the user requested or NULL if disabled. | ||
1057 | */ | ||
1058 | struct ieee80211_tx_latency_bin_ranges { | ||
1059 | int n_ranges; | ||
1060 | u32 ranges[]; | ||
1061 | }; | ||
1062 | |||
1063 | /** | 1043 | /** |
1064 | * mac80211 scan flags - currently active scan mode | 1044 | * mac80211 scan flags - currently active scan mode |
1065 | * | 1045 | * |
@@ -1211,12 +1191,6 @@ struct ieee80211_local { | |||
1211 | struct timer_list sta_cleanup; | 1191 | struct timer_list sta_cleanup; |
1212 | int sta_generation; | 1192 | int sta_generation; |
1213 | 1193 | ||
1214 | /* | ||
1215 | * Tx latency statistics parameters for all stations. | ||
1216 | * Can enable via debugfs (NULL when disabled). | ||
1217 | */ | ||
1218 | struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency; | ||
1219 | |||
1220 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 1194 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
1221 | struct tasklet_struct tx_pending_tasklet; | 1195 | struct tasklet_struct tx_pending_tasklet; |
1222 | 1196 | ||
@@ -1298,7 +1272,6 @@ struct ieee80211_local { | |||
1298 | /* TX/RX handler statistics */ | 1272 | /* TX/RX handler statistics */ |
1299 | unsigned int tx_handlers_drop; | 1273 | unsigned int tx_handlers_drop; |
1300 | unsigned int tx_handlers_queued; | 1274 | unsigned int tx_handlers_queued; |
1301 | unsigned int tx_handlers_drop_unencrypted; | ||
1302 | unsigned int tx_handlers_drop_fragment; | 1275 | unsigned int tx_handlers_drop_fragment; |
1303 | unsigned int tx_handlers_drop_wep; | 1276 | unsigned int tx_handlers_drop_wep; |
1304 | unsigned int tx_handlers_drop_not_assoc; | 1277 | unsigned int tx_handlers_drop_not_assoc; |
@@ -1568,7 +1541,8 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata); | |||
1568 | void ieee80211_scan_work(struct work_struct *work); | 1541 | void ieee80211_scan_work(struct work_struct *work); |
1569 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | 1542 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, |
1570 | const u8 *ssid, u8 ssid_len, | 1543 | const u8 *ssid, u8 ssid_len, |
1571 | struct ieee80211_channel *chan, | 1544 | struct ieee80211_channel **channels, |
1545 | unsigned int n_channels, | ||
1572 | enum nl80211_bss_scan_width scan_width); | 1546 | enum nl80211_bss_scan_width scan_width); |
1573 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 1547 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
1574 | struct cfg80211_scan_request *req); | 1548 | struct cfg80211_scan_request *req); |
@@ -1617,6 +1591,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
1617 | int ieee80211_iface_init(void); | 1591 | int ieee80211_iface_init(void); |
1618 | void ieee80211_iface_exit(void); | 1592 | void ieee80211_iface_exit(void); |
1619 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 1593 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
1594 | unsigned char name_assign_type, | ||
1620 | struct wireless_dev **new_wdev, enum nl80211_iftype type, | 1595 | struct wireless_dev **new_wdev, enum nl80211_iftype type, |
1621 | struct vif_params *params); | 1596 | struct vif_params *params); |
1622 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | 1597 | int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, |
@@ -1784,7 +1759,8 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke | |||
1784 | gfp_t gfp); | 1759 | gfp_t gfp); |
1785 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | 1760 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, |
1786 | bool bss_notify); | 1761 | bool bss_notify); |
1787 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 1762 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, |
1763 | struct sta_info *sta, struct sk_buff *skb); | ||
1788 | 1764 | ||
1789 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | 1765 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
1790 | struct sk_buff *skb, int tid, | 1766 | struct sk_buff *skb, int tid, |
@@ -1979,6 +1955,8 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1979 | u16 prot_mode); | 1955 | u16 prot_mode); |
1980 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | 1956 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, |
1981 | u32 cap); | 1957 | u32 cap); |
1958 | u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | ||
1959 | const struct cfg80211_chan_def *chandef); | ||
1982 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, | 1960 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, |
1983 | const struct ieee80211_supported_band *sband, | 1961 | const struct ieee80211_supported_band *sband, |
1984 | const u8 *srates, int srates_len, u32 *rates); | 1962 | const u8 *srates, int srates_len, u32 *rates); |
@@ -1994,6 +1972,9 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); | |||
1994 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 1972 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
1995 | const struct ieee80211_ht_operation *ht_oper, | 1973 | const struct ieee80211_ht_operation *ht_oper, |
1996 | struct cfg80211_chan_def *chandef); | 1974 | struct cfg80211_chan_def *chandef); |
1975 | void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan, | ||
1976 | const struct ieee80211_vht_operation *oper, | ||
1977 | struct cfg80211_chan_def *chandef); | ||
1997 | u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); | 1978 | u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); |
1998 | 1979 | ||
1999 | int __must_check | 1980 | int __must_check |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 81a27516813e..a0cd97fd0c49 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1508,7 +1508,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
1508 | } | 1508 | } |
1509 | 1509 | ||
1510 | /* reset some values that shouldn't be kept across type changes */ | 1510 | /* reset some values that shouldn't be kept across type changes */ |
1511 | sdata->drop_unencrypted = 0; | ||
1512 | if (type == NL80211_IFTYPE_STATION) | 1511 | if (type == NL80211_IFTYPE_STATION) |
1513 | sdata->u.mgd.use_4addr = false; | 1512 | sdata->u.mgd.use_4addr = false; |
1514 | 1513 | ||
@@ -1649,6 +1648,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
1649 | } | 1648 | } |
1650 | 1649 | ||
1651 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 1650 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
1651 | unsigned char name_assign_type, | ||
1652 | struct wireless_dev **new_wdev, enum nl80211_iftype type, | 1652 | struct wireless_dev **new_wdev, enum nl80211_iftype type, |
1653 | struct vif_params *params) | 1653 | struct vif_params *params) |
1654 | { | 1654 | { |
@@ -1677,7 +1677,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1677 | txqs = IEEE80211_NUM_ACS; | 1677 | txqs = IEEE80211_NUM_ACS; |
1678 | 1678 | ||
1679 | ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, | 1679 | ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, |
1680 | name, NET_NAME_UNKNOWN, | 1680 | name, name_assign_type, |
1681 | ieee80211_if_setup, txqs, 1); | 1681 | ieee80211_if_setup, txqs, 1); |
1682 | if (!ndev) | 1682 | if (!ndev) |
1683 | return -ENOMEM; | 1683 | return -ENOMEM; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 0825d76edcfc..2291cd730091 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -492,6 +492,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
492 | for (j = 0; j < len; j++) | 492 | for (j = 0; j < len; j++) |
493 | key->u.gen.rx_pn[i][j] = | 493 | key->u.gen.rx_pn[i][j] = |
494 | seq[len - j - 1]; | 494 | seq[len - j - 1]; |
495 | key->flags |= KEY_FLAG_CIPHER_SCHEME; | ||
495 | } | 496 | } |
496 | } | 497 | } |
497 | memcpy(key->conf.key, key_data, key_len); | 498 | memcpy(key->conf.key, key_data, key_len); |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index d57a9915494f..c5a31835be0e 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -30,10 +30,12 @@ struct sta_info; | |||
30 | * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present | 30 | * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present |
31 | * in the hardware for TX crypto hardware acceleration. | 31 | * in the hardware for TX crypto hardware acceleration. |
32 | * @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped. | 32 | * @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped. |
33 | * @KEY_FLAG_CIPHER_SCHEME: This key is for a hardware cipher scheme | ||
33 | */ | 34 | */ |
34 | enum ieee80211_internal_key_flags { | 35 | enum ieee80211_internal_key_flags { |
35 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), | 36 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), |
36 | KEY_FLAG_TAINTED = BIT(1), | 37 | KEY_FLAG_TAINTED = BIT(1), |
38 | KEY_FLAG_CIPHER_SCHEME = BIT(2), | ||
37 | }; | 39 | }; |
38 | 40 | ||
39 | enum ieee80211_internal_tkip_state { | 41 | enum ieee80211_internal_tkip_state { |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5e09d354c5a5..4977967c8b00 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -1057,7 +1057,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1057 | /* add one default STA interface if supported */ | 1057 | /* add one default STA interface if supported */ |
1058 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && | 1058 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && |
1059 | !(hw->flags & IEEE80211_HW_NO_AUTO_VIF)) { | 1059 | !(hw->flags & IEEE80211_HW_NO_AUTO_VIF)) { |
1060 | result = ieee80211_if_add(local, "wlan%d", NULL, | 1060 | result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL, |
1061 | NL80211_IFTYPE_STATION, NULL); | 1061 | NL80211_IFTYPE_STATION, NULL); |
1062 | if (result) | 1062 | if (result) |
1063 | wiphy_warn(local->hw.wiphy, | 1063 | wiphy_warn(local->hw.wiphy, |
@@ -1201,8 +1201,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
1201 | ieee80211_free_ack_frame, NULL); | 1201 | ieee80211_free_ack_frame, NULL); |
1202 | idr_destroy(&local->ack_status_frames); | 1202 | idr_destroy(&local->ack_status_frames); |
1203 | 1203 | ||
1204 | kfree(rcu_access_pointer(local->tx_latency)); | ||
1205 | |||
1206 | sta_info_stop(local); | 1204 | sta_info_stop(local); |
1207 | 1205 | ||
1208 | wiphy_free(local->hw.wiphy); | 1206 | wiphy_free(local->hw.wiphy); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 49a44bcd8aba..d4684242e78b 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -574,7 +574,8 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata) | |||
574 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 574 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
575 | u32 changed; | 575 | u32 changed; |
576 | 576 | ||
577 | ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ); | 577 | if (ifmsh->mshcfg.plink_timeout > 0) |
578 | ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ); | ||
578 | mesh_path_expire(sdata); | 579 | mesh_path_expire(sdata); |
579 | 580 | ||
580 | changed = mesh_accept_plinks_update(sdata); | 581 | changed = mesh_accept_plinks_update(sdata); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index b488e1859b18..60d737f144e3 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #define PLINK_GET_PLID(p) (p + 4) | 17 | #define PLINK_GET_PLID(p) (p + 4) |
18 | 18 | ||
19 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ | 19 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ |
20 | jiffies + HZ * t / 1000)) | 20 | jiffies + msecs_to_jiffies(t))) |
21 | 21 | ||
22 | enum plink_event { | 22 | enum plink_event { |
23 | PLINK_UNDEFINED, | 23 | PLINK_UNDEFINED, |
@@ -382,6 +382,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
382 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | 382 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); |
383 | struct ieee80211_supported_band *sband; | 383 | struct ieee80211_supported_band *sband; |
384 | u32 rates, basic_rates = 0, changed = 0; | 384 | u32 rates, basic_rates = 0, changed = 0; |
385 | enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth; | ||
385 | 386 | ||
386 | sband = local->hw.wiphy->bands[band]; | 387 | sband = local->hw.wiphy->bands[band]; |
387 | rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates); | 388 | rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates); |
@@ -401,6 +402,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
401 | elems->ht_cap_elem, sta)) | 402 | elems->ht_cap_elem, sta)) |
402 | changed |= IEEE80211_RC_BW_CHANGED; | 403 | changed |= IEEE80211_RC_BW_CHANGED; |
403 | 404 | ||
405 | if (bw != sta->sta.bandwidth) | ||
406 | changed |= IEEE80211_RC_BW_CHANGED; | ||
407 | |||
404 | /* HT peer is operating 20MHz-only */ | 408 | /* HT peer is operating 20MHz-only */ |
405 | if (elems->ht_operation && | 409 | if (elems->ht_operation && |
406 | !(elems->ht_operation->ht_param & | 410 | !(elems->ht_operation->ht_param & |
@@ -621,9 +625,9 @@ static void mesh_plink_timer(unsigned long data) | |||
621 | sta->llid, sta->plid, reason); | 625 | sta->llid, sta->plid, reason); |
622 | } | 626 | } |
623 | 627 | ||
624 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | 628 | static inline void mesh_plink_timer_set(struct sta_info *sta, u32 timeout) |
625 | { | 629 | { |
626 | sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); | 630 | sta->plink_timer.expires = jiffies + msecs_to_jiffies(timeout); |
627 | sta->plink_timer.data = (unsigned long) sta; | 631 | sta->plink_timer.data = (unsigned long) sta; |
628 | sta->plink_timer.function = mesh_plink_timer; | 632 | sta->plink_timer.function = mesh_plink_timer; |
629 | sta->plink_timeout = timeout; | 633 | sta->plink_timeout = timeout; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a4b1dd332e0f..00103f36dcbf 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1168,11 +1168,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1168 | if (!conf) { | 1168 | if (!conf) { |
1169 | sdata_info(sdata, | 1169 | sdata_info(sdata, |
1170 | "no channel context assigned to vif?, disconnecting\n"); | 1170 | "no channel context assigned to vif?, disconnecting\n"); |
1171 | ieee80211_queue_work(&local->hw, | 1171 | goto drop_connection; |
1172 | &ifmgd->csa_connection_drop_work); | ||
1173 | mutex_unlock(&local->chanctx_mtx); | ||
1174 | mutex_unlock(&local->mtx); | ||
1175 | return; | ||
1176 | } | 1172 | } |
1177 | 1173 | ||
1178 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 1174 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
@@ -1181,11 +1177,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1181 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { | 1177 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { |
1182 | sdata_info(sdata, | 1178 | sdata_info(sdata, |
1183 | "driver doesn't support chan-switch with channel contexts\n"); | 1179 | "driver doesn't support chan-switch with channel contexts\n"); |
1184 | ieee80211_queue_work(&local->hw, | 1180 | goto drop_connection; |
1185 | &ifmgd->csa_connection_drop_work); | ||
1186 | mutex_unlock(&local->chanctx_mtx); | ||
1187 | mutex_unlock(&local->mtx); | ||
1188 | return; | ||
1189 | } | 1181 | } |
1190 | 1182 | ||
1191 | ch_switch.timestamp = timestamp; | 1183 | ch_switch.timestamp = timestamp; |
@@ -1197,11 +1189,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1197 | if (drv_pre_channel_switch(sdata, &ch_switch)) { | 1189 | if (drv_pre_channel_switch(sdata, &ch_switch)) { |
1198 | sdata_info(sdata, | 1190 | sdata_info(sdata, |
1199 | "preparing for channel switch failed, disconnecting\n"); | 1191 | "preparing for channel switch failed, disconnecting\n"); |
1200 | ieee80211_queue_work(&local->hw, | 1192 | goto drop_connection; |
1201 | &ifmgd->csa_connection_drop_work); | ||
1202 | mutex_unlock(&local->chanctx_mtx); | ||
1203 | mutex_unlock(&local->mtx); | ||
1204 | return; | ||
1205 | } | 1193 | } |
1206 | 1194 | ||
1207 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, | 1195 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
@@ -1210,11 +1198,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1210 | sdata_info(sdata, | 1198 | sdata_info(sdata, |
1211 | "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", | 1199 | "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", |
1212 | res); | 1200 | res); |
1213 | ieee80211_queue_work(&local->hw, | 1201 | goto drop_connection; |
1214 | &ifmgd->csa_connection_drop_work); | ||
1215 | mutex_unlock(&local->chanctx_mtx); | ||
1216 | mutex_unlock(&local->mtx); | ||
1217 | return; | ||
1218 | } | 1202 | } |
1219 | mutex_unlock(&local->chanctx_mtx); | 1203 | mutex_unlock(&local->chanctx_mtx); |
1220 | 1204 | ||
@@ -1244,6 +1228,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1244 | mod_timer(&ifmgd->chswitch_timer, | 1228 | mod_timer(&ifmgd->chswitch_timer, |
1245 | TU_TO_EXP_TIME((csa_ie.count - 1) * | 1229 | TU_TO_EXP_TIME((csa_ie.count - 1) * |
1246 | cbss->beacon_interval)); | 1230 | cbss->beacon_interval)); |
1231 | return; | ||
1232 | drop_connection: | ||
1233 | ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); | ||
1234 | mutex_unlock(&local->chanctx_mtx); | ||
1235 | mutex_unlock(&local->mtx); | ||
1247 | } | 1236 | } |
1248 | 1237 | ||
1249 | static bool | 1238 | static bool |
@@ -1633,9 +1622,6 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
1633 | { | 1622 | { |
1634 | struct ieee80211_local *local = (void *) data; | 1623 | struct ieee80211_local *local = (void *) data; |
1635 | 1624 | ||
1636 | if (local->quiescing || local->suspended) | ||
1637 | return; | ||
1638 | |||
1639 | ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); | 1625 | ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); |
1640 | } | 1626 | } |
1641 | 1627 | ||
@@ -2260,7 +2246,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2260 | else | 2246 | else |
2261 | ssid_len = ssid[1]; | 2247 | ssid_len = ssid[1]; |
2262 | 2248 | ||
2263 | ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL, | 2249 | ieee80211_send_probe_req(sdata, sdata->vif.addr, dst, |
2264 | ssid + 2, ssid_len, NULL, | 2250 | ssid + 2, ssid_len, NULL, |
2265 | 0, (u32) -1, true, 0, | 2251 | 0, (u32) -1, true, 0, |
2266 | ifmgd->associated->channel, false); | 2252 | ifmgd->associated->channel, false); |
@@ -2372,6 +2358,24 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
2372 | } | 2358 | } |
2373 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | 2359 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); |
2374 | 2360 | ||
2361 | static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata, | ||
2362 | const u8 *buf, size_t len, bool tx, | ||
2363 | u16 reason) | ||
2364 | { | ||
2365 | struct ieee80211_event event = { | ||
2366 | .type = MLME_EVENT, | ||
2367 | .u.mlme.data = tx ? DEAUTH_TX_EVENT : DEAUTH_RX_EVENT, | ||
2368 | .u.mlme.reason = reason, | ||
2369 | }; | ||
2370 | |||
2371 | if (tx) | ||
2372 | cfg80211_tx_mlme_mgmt(sdata->dev, buf, len); | ||
2373 | else | ||
2374 | cfg80211_rx_mlme_mgmt(sdata->dev, buf, len); | ||
2375 | |||
2376 | drv_event_callback(sdata->local, sdata, &event); | ||
2377 | } | ||
2378 | |||
2375 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | 2379 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) |
2376 | { | 2380 | { |
2377 | struct ieee80211_local *local = sdata->local; | 2381 | struct ieee80211_local *local = sdata->local; |
@@ -2397,8 +2401,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2397 | } | 2401 | } |
2398 | mutex_unlock(&local->mtx); | 2402 | mutex_unlock(&local->mtx); |
2399 | 2403 | ||
2400 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 2404 | ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, |
2401 | IEEE80211_DEAUTH_FRAME_LEN); | 2405 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); |
2406 | |||
2402 | sdata_unlock(sdata); | 2407 | sdata_unlock(sdata); |
2403 | } | 2408 | } |
2404 | 2409 | ||
@@ -2522,6 +2527,10 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2522 | u8 bssid[ETH_ALEN]; | 2527 | u8 bssid[ETH_ALEN]; |
2523 | u16 auth_alg, auth_transaction, status_code; | 2528 | u16 auth_alg, auth_transaction, status_code; |
2524 | struct sta_info *sta; | 2529 | struct sta_info *sta; |
2530 | struct ieee80211_event event = { | ||
2531 | .type = MLME_EVENT, | ||
2532 | .u.mlme.data = AUTH_EVENT, | ||
2533 | }; | ||
2525 | 2534 | ||
2526 | sdata_assert_lock(sdata); | 2535 | sdata_assert_lock(sdata); |
2527 | 2536 | ||
@@ -2554,6 +2563,9 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2554 | mgmt->sa, status_code); | 2563 | mgmt->sa, status_code); |
2555 | ieee80211_destroy_auth_data(sdata, false); | 2564 | ieee80211_destroy_auth_data(sdata, false); |
2556 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); | 2565 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); |
2566 | event.u.mlme.status = MLME_DENIED; | ||
2567 | event.u.mlme.reason = status_code; | ||
2568 | drv_event_callback(sdata->local, sdata, &event); | ||
2557 | return; | 2569 | return; |
2558 | } | 2570 | } |
2559 | 2571 | ||
@@ -2576,6 +2588,8 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2576 | return; | 2588 | return; |
2577 | } | 2589 | } |
2578 | 2590 | ||
2591 | event.u.mlme.status = MLME_SUCCESS; | ||
2592 | drv_event_callback(sdata->local, sdata, &event); | ||
2579 | sdata_info(sdata, "authenticated\n"); | 2593 | sdata_info(sdata, "authenticated\n"); |
2580 | ifmgd->auth_data->done = true; | 2594 | ifmgd->auth_data->done = true; |
2581 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; | 2595 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; |
@@ -2694,7 +2708,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
2694 | 2708 | ||
2695 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2709 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2696 | 2710 | ||
2697 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); | 2711 | ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code); |
2698 | } | 2712 | } |
2699 | 2713 | ||
2700 | 2714 | ||
@@ -2720,7 +2734,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2720 | 2734 | ||
2721 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2735 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2722 | 2736 | ||
2723 | cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len); | 2737 | ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code); |
2724 | } | 2738 | } |
2725 | 2739 | ||
2726 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | 2740 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, |
@@ -2982,10 +2996,14 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2982 | 2996 | ||
2983 | rate_control_rate_init(sta); | 2997 | rate_control_rate_init(sta); |
2984 | 2998 | ||
2985 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) | 2999 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) { |
2986 | set_sta_flag(sta, WLAN_STA_MFP); | 3000 | set_sta_flag(sta, WLAN_STA_MFP); |
3001 | sta->sta.mfp = true; | ||
3002 | } else { | ||
3003 | sta->sta.mfp = false; | ||
3004 | } | ||
2987 | 3005 | ||
2988 | sta->sta.wme = elems.wmm_param; | 3006 | sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS; |
2989 | 3007 | ||
2990 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | 3008 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); |
2991 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | 3009 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
@@ -3055,6 +3073,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
3055 | u8 *pos; | 3073 | u8 *pos; |
3056 | bool reassoc; | 3074 | bool reassoc; |
3057 | struct cfg80211_bss *bss; | 3075 | struct cfg80211_bss *bss; |
3076 | struct ieee80211_event event = { | ||
3077 | .type = MLME_EVENT, | ||
3078 | .u.mlme.data = ASSOC_EVENT, | ||
3079 | }; | ||
3058 | 3080 | ||
3059 | sdata_assert_lock(sdata); | 3081 | sdata_assert_lock(sdata); |
3060 | 3082 | ||
@@ -3106,6 +3128,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
3106 | sdata_info(sdata, "%pM denied association (code=%d)\n", | 3128 | sdata_info(sdata, "%pM denied association (code=%d)\n", |
3107 | mgmt->sa, status_code); | 3129 | mgmt->sa, status_code); |
3108 | ieee80211_destroy_assoc_data(sdata, false); | 3130 | ieee80211_destroy_assoc_data(sdata, false); |
3131 | event.u.mlme.status = MLME_DENIED; | ||
3132 | event.u.mlme.reason = status_code; | ||
3133 | drv_event_callback(sdata->local, sdata, &event); | ||
3109 | } else { | 3134 | } else { |
3110 | if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { | 3135 | if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { |
3111 | /* oops -- internal error -- send timeout for now */ | 3136 | /* oops -- internal error -- send timeout for now */ |
@@ -3113,6 +3138,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
3113 | cfg80211_assoc_timeout(sdata->dev, bss); | 3138 | cfg80211_assoc_timeout(sdata->dev, bss); |
3114 | return; | 3139 | return; |
3115 | } | 3140 | } |
3141 | event.u.mlme.status = MLME_SUCCESS; | ||
3142 | drv_event_callback(sdata->local, sdata, &event); | ||
3116 | sdata_info(sdata, "associated\n"); | 3143 | sdata_info(sdata, "associated\n"); |
3117 | 3144 | ||
3118 | /* | 3145 | /* |
@@ -3315,6 +3342,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3315 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { | 3342 | ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { |
3316 | int sig = ifmgd->ave_beacon_signal; | 3343 | int sig = ifmgd->ave_beacon_signal; |
3317 | int last_sig = ifmgd->last_ave_beacon_signal; | 3344 | int last_sig = ifmgd->last_ave_beacon_signal; |
3345 | struct ieee80211_event event = { | ||
3346 | .type = RSSI_EVENT, | ||
3347 | }; | ||
3318 | 3348 | ||
3319 | /* | 3349 | /* |
3320 | * if signal crosses either of the boundaries, invoke callback | 3350 | * if signal crosses either of the boundaries, invoke callback |
@@ -3323,12 +3353,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3323 | if (sig > ifmgd->rssi_max_thold && | 3353 | if (sig > ifmgd->rssi_max_thold && |
3324 | (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { | 3354 | (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { |
3325 | ifmgd->last_ave_beacon_signal = sig; | 3355 | ifmgd->last_ave_beacon_signal = sig; |
3326 | drv_rssi_callback(local, sdata, RSSI_EVENT_HIGH); | 3356 | event.u.rssi.data = RSSI_EVENT_HIGH; |
3357 | drv_event_callback(local, sdata, &event); | ||
3327 | } else if (sig < ifmgd->rssi_min_thold && | 3358 | } else if (sig < ifmgd->rssi_min_thold && |
3328 | (last_sig >= ifmgd->rssi_max_thold || | 3359 | (last_sig >= ifmgd->rssi_max_thold || |
3329 | last_sig == 0)) { | 3360 | last_sig == 0)) { |
3330 | ifmgd->last_ave_beacon_signal = sig; | 3361 | ifmgd->last_ave_beacon_signal = sig; |
3331 | drv_rssi_callback(local, sdata, RSSI_EVENT_LOW); | 3362 | event.u.rssi.data = RSSI_EVENT_LOW; |
3363 | drv_event_callback(local, sdata, &event); | ||
3332 | } | 3364 | } |
3333 | } | 3365 | } |
3334 | 3366 | ||
@@ -3433,6 +3465,26 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3433 | if (ifmgd->csa_waiting_bcn) | 3465 | if (ifmgd->csa_waiting_bcn) |
3434 | ieee80211_chswitch_post_beacon(sdata); | 3466 | ieee80211_chswitch_post_beacon(sdata); |
3435 | 3467 | ||
3468 | /* | ||
3469 | * Update beacon timing and dtim count on every beacon appearance. This | ||
3470 | * will allow the driver to use the most updated values. Do it before | ||
3471 | * comparing this one with last received beacon. | ||
3472 | * IMPORTANT: These parameters would possibly be out of sync by the time | ||
3473 | * the driver will use them. The synchronized view is currently | ||
3474 | * guaranteed only in certain callbacks. | ||
3475 | */ | ||
3476 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { | ||
3477 | sdata->vif.bss_conf.sync_tsf = | ||
3478 | le64_to_cpu(mgmt->u.beacon.timestamp); | ||
3479 | sdata->vif.bss_conf.sync_device_ts = | ||
3480 | rx_status->device_timestamp; | ||
3481 | if (elems.tim) | ||
3482 | sdata->vif.bss_conf.sync_dtim_count = | ||
3483 | elems.tim->dtim_count; | ||
3484 | else | ||
3485 | sdata->vif.bss_conf.sync_dtim_count = 0; | ||
3486 | } | ||
3487 | |||
3436 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 3488 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
3437 | return; | 3489 | return; |
3438 | ifmgd->beacon_crc = ncrc; | 3490 | ifmgd->beacon_crc = ncrc; |
@@ -3460,18 +3512,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3460 | else | 3512 | else |
3461 | bss_conf->dtim_period = 1; | 3513 | bss_conf->dtim_period = 1; |
3462 | 3514 | ||
3463 | if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) { | ||
3464 | sdata->vif.bss_conf.sync_tsf = | ||
3465 | le64_to_cpu(mgmt->u.beacon.timestamp); | ||
3466 | sdata->vif.bss_conf.sync_device_ts = | ||
3467 | rx_status->device_timestamp; | ||
3468 | if (elems.tim) | ||
3469 | sdata->vif.bss_conf.sync_dtim_count = | ||
3470 | elems.tim->dtim_count; | ||
3471 | else | ||
3472 | sdata->vif.bss_conf.sync_dtim_count = 0; | ||
3473 | } | ||
3474 | |||
3475 | changed |= BSS_CHANGED_BEACON_INFO; | 3515 | changed |= BSS_CHANGED_BEACON_INFO; |
3476 | ifmgd->have_beacon = true; | 3516 | ifmgd->have_beacon = true; |
3477 | 3517 | ||
@@ -3502,8 +3542,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3502 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 3542 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
3503 | WLAN_REASON_DEAUTH_LEAVING, | 3543 | WLAN_REASON_DEAUTH_LEAVING, |
3504 | true, deauth_buf); | 3544 | true, deauth_buf); |
3505 | cfg80211_tx_mlme_mgmt(sdata->dev, deauth_buf, | 3545 | ieee80211_report_disconnect(sdata, deauth_buf, |
3506 | sizeof(deauth_buf)); | 3546 | sizeof(deauth_buf), true, |
3547 | WLAN_REASON_DEAUTH_LEAVING); | ||
3507 | return; | 3548 | return; |
3508 | } | 3549 | } |
3509 | 3550 | ||
@@ -3621,8 +3662,8 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
3621 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, | 3662 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, |
3622 | tx, frame_buf); | 3663 | tx, frame_buf); |
3623 | 3664 | ||
3624 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 3665 | ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, |
3625 | IEEE80211_DEAUTH_FRAME_LEN); | 3666 | reason); |
3626 | } | 3667 | } |
3627 | 3668 | ||
3628 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | 3669 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) |
@@ -3816,12 +3857,18 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3816 | ieee80211_destroy_auth_data(sdata, false); | 3857 | ieee80211_destroy_auth_data(sdata, false); |
3817 | } else if (ieee80211_probe_auth(sdata)) { | 3858 | } else if (ieee80211_probe_auth(sdata)) { |
3818 | u8 bssid[ETH_ALEN]; | 3859 | u8 bssid[ETH_ALEN]; |
3860 | struct ieee80211_event event = { | ||
3861 | .type = MLME_EVENT, | ||
3862 | .u.mlme.data = AUTH_EVENT, | ||
3863 | .u.mlme.status = MLME_TIMEOUT, | ||
3864 | }; | ||
3819 | 3865 | ||
3820 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); | 3866 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); |
3821 | 3867 | ||
3822 | ieee80211_destroy_auth_data(sdata, false); | 3868 | ieee80211_destroy_auth_data(sdata, false); |
3823 | 3869 | ||
3824 | cfg80211_auth_timeout(sdata->dev, bssid); | 3870 | cfg80211_auth_timeout(sdata->dev, bssid); |
3871 | drv_event_callback(sdata->local, sdata, &event); | ||
3825 | } | 3872 | } |
3826 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) | 3873 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) |
3827 | run_again(sdata, ifmgd->auth_data->timeout); | 3874 | run_again(sdata, ifmgd->auth_data->timeout); |
@@ -3831,9 +3878,15 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3831 | if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) || | 3878 | if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) || |
3832 | ieee80211_do_assoc(sdata)) { | 3879 | ieee80211_do_assoc(sdata)) { |
3833 | struct cfg80211_bss *bss = ifmgd->assoc_data->bss; | 3880 | struct cfg80211_bss *bss = ifmgd->assoc_data->bss; |
3881 | struct ieee80211_event event = { | ||
3882 | .type = MLME_EVENT, | ||
3883 | .u.mlme.data = ASSOC_EVENT, | ||
3884 | .u.mlme.status = MLME_TIMEOUT, | ||
3885 | }; | ||
3834 | 3886 | ||
3835 | ieee80211_destroy_assoc_data(sdata, false); | 3887 | ieee80211_destroy_assoc_data(sdata, false); |
3836 | cfg80211_assoc_timeout(sdata->dev, bss); | 3888 | cfg80211_assoc_timeout(sdata->dev, bss); |
3889 | drv_event_callback(sdata->local, sdata, &event); | ||
3837 | } | 3890 | } |
3838 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) | 3891 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) |
3839 | run_again(sdata, ifmgd->assoc_data->timeout); | 3892 | run_again(sdata, ifmgd->assoc_data->timeout); |
@@ -3905,12 +3958,8 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
3905 | { | 3958 | { |
3906 | struct ieee80211_sub_if_data *sdata = | 3959 | struct ieee80211_sub_if_data *sdata = |
3907 | (struct ieee80211_sub_if_data *) data; | 3960 | (struct ieee80211_sub_if_data *) data; |
3908 | struct ieee80211_local *local = sdata->local; | ||
3909 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3961 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3910 | 3962 | ||
3911 | if (local->quiescing) | ||
3912 | return; | ||
3913 | |||
3914 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) | 3963 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3915 | return; | 3964 | return; |
3916 | 3965 | ||
@@ -3926,9 +3975,6 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) | |||
3926 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3975 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3927 | struct ieee80211_local *local = sdata->local; | 3976 | struct ieee80211_local *local = sdata->local; |
3928 | 3977 | ||
3929 | if (local->quiescing) | ||
3930 | return; | ||
3931 | |||
3932 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) | 3978 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3933 | return; | 3979 | return; |
3934 | 3980 | ||
@@ -3991,6 +4037,34 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) | |||
3991 | IEEE80211_DEAUTH_FRAME_LEN); | 4037 | IEEE80211_DEAUTH_FRAME_LEN); |
3992 | } | 4038 | } |
3993 | 4039 | ||
4040 | /* This is a bit of a hack - we should find a better and more generic | ||
4041 | * solution to this. Normally when suspending, cfg80211 will in fact | ||
4042 | * deauthenticate. However, it doesn't (and cannot) stop an ongoing | ||
4043 | * auth (not so important) or assoc (this is the problem) process. | ||
4044 | * | ||
4045 | * As a consequence, it can happen that we are in the process of both | ||
4046 | * associating and suspending, and receive an association response | ||
4047 | * after cfg80211 has checked if it needs to disconnect, but before | ||
4048 | * we actually set the flag to drop incoming frames. This will then | ||
4049 | * cause the workqueue flush to process the association response in | ||
4050 | * the suspend, resulting in a successful association just before it | ||
4051 | * tries to remove the interface from the driver, which now though | ||
4052 | * has a channel context assigned ... this results in issues. | ||
4053 | * | ||
4054 | * To work around this (for now) simply deauth here again if we're | ||
4055 | * now connected. | ||
4056 | */ | ||
4057 | if (ifmgd->associated && !sdata->local->wowlan) { | ||
4058 | u8 bssid[ETH_ALEN]; | ||
4059 | struct cfg80211_deauth_request req = { | ||
4060 | .reason_code = WLAN_REASON_DEAUTH_LEAVING, | ||
4061 | .bssid = bssid, | ||
4062 | }; | ||
4063 | |||
4064 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | ||
4065 | ieee80211_mgd_deauth(sdata, &req); | ||
4066 | } | ||
4067 | |||
3994 | sdata_unlock(sdata); | 4068 | sdata_unlock(sdata); |
3995 | } | 4069 | } |
3996 | 4070 | ||
@@ -4379,6 +4453,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
4379 | } else | 4453 | } else |
4380 | WARN_ON_ONCE(!ether_addr_equal(ifmgd->bssid, cbss->bssid)); | 4454 | WARN_ON_ONCE(!ether_addr_equal(ifmgd->bssid, cbss->bssid)); |
4381 | 4455 | ||
4456 | /* Cancel scan to ensure that nothing interferes with connection */ | ||
4457 | if (local->scanning) | ||
4458 | ieee80211_scan_cancel(local); | ||
4459 | |||
4382 | return 0; | 4460 | return 0; |
4383 | } | 4461 | } |
4384 | 4462 | ||
@@ -4467,8 +4545,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
4467 | WLAN_REASON_UNSPECIFIED, | 4545 | WLAN_REASON_UNSPECIFIED, |
4468 | false, frame_buf); | 4546 | false, frame_buf); |
4469 | 4547 | ||
4470 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4548 | ieee80211_report_disconnect(sdata, frame_buf, |
4471 | sizeof(frame_buf)); | 4549 | sizeof(frame_buf), true, |
4550 | WLAN_REASON_UNSPECIFIED); | ||
4472 | } | 4551 | } |
4473 | 4552 | ||
4474 | sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); | 4553 | sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); |
@@ -4568,8 +4647,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4568 | WLAN_REASON_UNSPECIFIED, | 4647 | WLAN_REASON_UNSPECIFIED, |
4569 | false, frame_buf); | 4648 | false, frame_buf); |
4570 | 4649 | ||
4571 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4650 | ieee80211_report_disconnect(sdata, frame_buf, |
4572 | sizeof(frame_buf)); | 4651 | sizeof(frame_buf), true, |
4652 | WLAN_REASON_UNSPECIFIED); | ||
4573 | } | 4653 | } |
4574 | 4654 | ||
4575 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { | 4655 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { |
@@ -4859,8 +4939,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4859 | req->reason_code, tx, | 4939 | req->reason_code, tx, |
4860 | frame_buf); | 4940 | frame_buf); |
4861 | ieee80211_destroy_auth_data(sdata, false); | 4941 | ieee80211_destroy_auth_data(sdata, false); |
4862 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4942 | ieee80211_report_disconnect(sdata, frame_buf, |
4863 | IEEE80211_DEAUTH_FRAME_LEN); | 4943 | sizeof(frame_buf), true, |
4944 | req->reason_code); | ||
4864 | 4945 | ||
4865 | return 0; | 4946 | return 0; |
4866 | } | 4947 | } |
@@ -4874,8 +4955,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4874 | 4955 | ||
4875 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 4956 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
4876 | req->reason_code, tx, frame_buf); | 4957 | req->reason_code, tx, frame_buf); |
4877 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4958 | ieee80211_report_disconnect(sdata, frame_buf, |
4878 | IEEE80211_DEAUTH_FRAME_LEN); | 4959 | sizeof(frame_buf), true, |
4960 | req->reason_code); | ||
4879 | return 0; | 4961 | return 0; |
4880 | } | 4962 | } |
4881 | 4963 | ||
@@ -4907,8 +4989,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
4907 | req->reason_code, !req->local_state_change, | 4989 | req->reason_code, !req->local_state_change, |
4908 | frame_buf); | 4990 | frame_buf); |
4909 | 4991 | ||
4910 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4992 | ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, |
4911 | IEEE80211_DEAUTH_FRAME_LEN); | 4993 | req->reason_code); |
4912 | 4994 | ||
4913 | return 0; | 4995 | return 0; |
4914 | } | 4996 | } |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index ca405b6b686d..ac6ad6238e3a 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -59,9 +59,26 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
59 | cancel_work_sync(&local->dynamic_ps_enable_work); | 59 | cancel_work_sync(&local->dynamic_ps_enable_work); |
60 | del_timer_sync(&local->dynamic_ps_timer); | 60 | del_timer_sync(&local->dynamic_ps_timer); |
61 | 61 | ||
62 | local->wowlan = wowlan && local->open_count; | 62 | local->wowlan = wowlan; |
63 | if (local->wowlan) { | 63 | if (local->wowlan) { |
64 | int err = drv_suspend(local, wowlan); | 64 | int err; |
65 | |||
66 | /* Drivers don't expect to suspend while some operations like | ||
67 | * authenticating or associating are in progress. It doesn't | ||
68 | * make sense anyway to accept that, since the authentication | ||
69 | * or association would never finish since the driver can't do | ||
70 | * that on its own. | ||
71 | * Thus, clean up in-progress auth/assoc first. | ||
72 | */ | ||
73 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
74 | if (!ieee80211_sdata_running(sdata)) | ||
75 | continue; | ||
76 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
77 | continue; | ||
78 | ieee80211_mgd_quiesce(sdata); | ||
79 | } | ||
80 | |||
81 | err = drv_suspend(local, wowlan); | ||
65 | if (err < 0) { | 82 | if (err < 0) { |
66 | local->quiescing = false; | 83 | local->quiescing = false; |
67 | local->wowlan = false; | 84 | local->wowlan = false; |
@@ -80,6 +97,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
80 | return err; | 97 | return err; |
81 | } else if (err > 0) { | 98 | } else if (err > 0) { |
82 | WARN_ON(err != 1); | 99 | WARN_ON(err != 1); |
100 | /* cfg80211 will call back into mac80211 to disconnect | ||
101 | * all interfaces, allow that to proceed properly | ||
102 | */ | ||
103 | ieee80211_wake_queues_by_reason(hw, | ||
104 | IEEE80211_MAX_QUEUE_MAP, | ||
105 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, | ||
106 | false); | ||
83 | return err; | 107 | return err; |
84 | } else { | 108 | } else { |
85 | goto suspend; | 109 | goto suspend; |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 80452cfd2dc5..60698fc7042e 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -17,10 +17,11 @@ | |||
17 | #include "rc80211_minstrel.h" | 17 | #include "rc80211_minstrel.h" |
18 | #include "rc80211_minstrel_ht.h" | 18 | #include "rc80211_minstrel_ht.h" |
19 | 19 | ||
20 | #define AVG_AMPDU_SIZE 16 | ||
20 | #define AVG_PKT_SIZE 1200 | 21 | #define AVG_PKT_SIZE 1200 |
21 | 22 | ||
22 | /* Number of bits for an average sized packet */ | 23 | /* Number of bits for an average sized packet */ |
23 | #define MCS_NBITS (AVG_PKT_SIZE << 3) | 24 | #define MCS_NBITS ((AVG_PKT_SIZE * AVG_AMPDU_SIZE) << 3) |
24 | 25 | ||
25 | /* Number of symbols for a packet with (bps) bits per symbol */ | 26 | /* Number of symbols for a packet with (bps) bits per symbol */ |
26 | #define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps)) | 27 | #define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps)) |
@@ -33,7 +34,8 @@ | |||
33 | ) | 34 | ) |
34 | 35 | ||
35 | /* Transmit duration for the raw data part of an average sized packet */ | 36 | /* Transmit duration for the raw data part of an average sized packet */ |
36 | #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) | 37 | #define MCS_DURATION(streams, sgi, bps) \ |
38 | (MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) / AVG_AMPDU_SIZE) | ||
37 | 39 | ||
38 | #define BW_20 0 | 40 | #define BW_20 0 |
39 | #define BW_40 1 | 41 | #define BW_40 1 |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 944bdc04e913..4f7b922cfda4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1912,8 +1912,7 @@ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | |||
1912 | /* Drop unencrypted frames if key is set. */ | 1912 | /* Drop unencrypted frames if key is set. */ |
1913 | if (unlikely(!ieee80211_has_protected(fc) && | 1913 | if (unlikely(!ieee80211_has_protected(fc) && |
1914 | !ieee80211_is_nullfunc(fc) && | 1914 | !ieee80211_is_nullfunc(fc) && |
1915 | ieee80211_is_data(fc) && | 1915 | ieee80211_is_data(fc) && rx->key)) |
1916 | (rx->key || rx->sdata->drop_unencrypted))) | ||
1917 | return -EACCES; | 1916 | return -EACCES; |
1918 | 1917 | ||
1919 | return 0; | 1918 | return 0; |
@@ -2043,6 +2042,9 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
2043 | struct sta_info *dsta; | 2042 | struct sta_info *dsta; |
2044 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 2043 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
2045 | 2044 | ||
2045 | dev->stats.rx_packets++; | ||
2046 | dev->stats.rx_bytes += rx->skb->len; | ||
2047 | |||
2046 | skb = rx->skb; | 2048 | skb = rx->skb; |
2047 | xmit_skb = NULL; | 2049 | xmit_skb = NULL; |
2048 | 2050 | ||
@@ -2173,8 +2175,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
2173 | dev_kfree_skb(rx->skb); | 2175 | dev_kfree_skb(rx->skb); |
2174 | continue; | 2176 | continue; |
2175 | } | 2177 | } |
2176 | dev->stats.rx_packets++; | ||
2177 | dev->stats.rx_bytes += rx->skb->len; | ||
2178 | 2178 | ||
2179 | ieee80211_deliver_skb(rx); | 2179 | ieee80211_deliver_skb(rx); |
2180 | } | 2180 | } |
@@ -2400,9 +2400,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
2400 | 2400 | ||
2401 | rx->skb->dev = dev; | 2401 | rx->skb->dev = dev; |
2402 | 2402 | ||
2403 | dev->stats.rx_packets++; | ||
2404 | dev->stats.rx_bytes += rx->skb->len; | ||
2405 | |||
2406 | if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 && | 2403 | if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 && |
2407 | !is_multicast_ether_addr( | 2404 | !is_multicast_ether_addr( |
2408 | ((struct ethhdr *)rx->skb->data)->h_dest) && | 2405 | ((struct ethhdr *)rx->skb->data)->h_dest) && |
@@ -3128,6 +3125,12 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, | |||
3128 | goto rxh_next; \ | 3125 | goto rxh_next; \ |
3129 | } while (0); | 3126 | } while (0); |
3130 | 3127 | ||
3128 | /* Lock here to avoid hitting all of the data used in the RX | ||
3129 | * path (e.g. key data, station data, ...) concurrently when | ||
3130 | * a frame is released from the reorder buffer due to timeout | ||
3131 | * from the timer, potentially concurrently with RX from the | ||
3132 | * driver. | ||
3133 | */ | ||
3131 | spin_lock_bh(&rx->local->rx_path_lock); | 3134 | spin_lock_bh(&rx->local->rx_path_lock); |
3132 | 3135 | ||
3133 | while ((skb = __skb_dequeue(frames))) { | 3136 | while ((skb = __skb_dequeue(frames))) { |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 05f0d711b6d8..7bb6a9383f58 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -928,11 +928,12 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
928 | 928 | ||
929 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | 929 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, |
930 | const u8 *ssid, u8 ssid_len, | 930 | const u8 *ssid, u8 ssid_len, |
931 | struct ieee80211_channel *chan, | 931 | struct ieee80211_channel **channels, |
932 | unsigned int n_channels, | ||
932 | enum nl80211_bss_scan_width scan_width) | 933 | enum nl80211_bss_scan_width scan_width) |
933 | { | 934 | { |
934 | struct ieee80211_local *local = sdata->local; | 935 | struct ieee80211_local *local = sdata->local; |
935 | int ret = -EBUSY; | 936 | int ret = -EBUSY, i, n_ch = 0; |
936 | enum ieee80211_band band; | 937 | enum ieee80211_band band; |
937 | 938 | ||
938 | mutex_lock(&local->mtx); | 939 | mutex_lock(&local->mtx); |
@@ -942,9 +943,8 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | |||
942 | goto unlock; | 943 | goto unlock; |
943 | 944 | ||
944 | /* fill internal scan request */ | 945 | /* fill internal scan request */ |
945 | if (!chan) { | 946 | if (!channels) { |
946 | int i, max_n; | 947 | int max_n; |
947 | int n_ch = 0; | ||
948 | 948 | ||
949 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 949 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
950 | if (!local->hw.wiphy->bands[band]) | 950 | if (!local->hw.wiphy->bands[band]) |
@@ -969,12 +969,19 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | |||
969 | 969 | ||
970 | local->int_scan_req->n_channels = n_ch; | 970 | local->int_scan_req->n_channels = n_ch; |
971 | } else { | 971 | } else { |
972 | if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR | | 972 | for (i = 0; i < n_channels; i++) { |
973 | IEEE80211_CHAN_DISABLED))) | 973 | if (channels[i]->flags & (IEEE80211_CHAN_NO_IR | |
974 | IEEE80211_CHAN_DISABLED)) | ||
975 | continue; | ||
976 | |||
977 | local->int_scan_req->channels[n_ch] = channels[i]; | ||
978 | n_ch++; | ||
979 | } | ||
980 | |||
981 | if (WARN_ON_ONCE(n_ch == 0)) | ||
974 | goto unlock; | 982 | goto unlock; |
975 | 983 | ||
976 | local->int_scan_req->channels[0] = chan; | 984 | local->int_scan_req->n_channels = n_ch; |
977 | local->int_scan_req->n_channels = 1; | ||
978 | } | 985 | } |
979 | 986 | ||
980 | local->int_scan_req->ssids = &local->scan_ssid; | 987 | local->int_scan_req->ssids = &local->scan_ssid; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 00ca8dcc2bcf..aacaa1a85e63 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -229,17 +229,9 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, | |||
229 | */ | 229 | */ |
230 | void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) | 230 | void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) |
231 | { | 231 | { |
232 | int i; | ||
233 | |||
234 | if (sta->rate_ctrl) | 232 | if (sta->rate_ctrl) |
235 | rate_control_free_sta(sta); | 233 | rate_control_free_sta(sta); |
236 | 234 | ||
237 | if (sta->tx_lat) { | ||
238 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | ||
239 | kfree(sta->tx_lat[i].bins); | ||
240 | kfree(sta->tx_lat); | ||
241 | } | ||
242 | |||
243 | sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); | 235 | sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); |
244 | 236 | ||
245 | kfree(rcu_dereference_raw(sta->sta.rates)); | 237 | kfree(rcu_dereference_raw(sta->sta.rates)); |
@@ -295,42 +287,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
295 | struct ieee80211_local *local = sdata->local; | 287 | struct ieee80211_local *local = sdata->local; |
296 | struct sta_info *sta; | 288 | struct sta_info *sta; |
297 | struct timespec uptime; | 289 | struct timespec uptime; |
298 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
299 | int i; | 290 | int i; |
300 | 291 | ||
301 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); | 292 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); |
302 | if (!sta) | 293 | if (!sta) |
303 | return NULL; | 294 | return NULL; |
304 | 295 | ||
305 | rcu_read_lock(); | ||
306 | tx_latency = rcu_dereference(local->tx_latency); | ||
307 | /* init stations Tx latency statistics && TID bins */ | ||
308 | if (tx_latency) { | ||
309 | sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS * | ||
310 | sizeof(struct ieee80211_tx_latency_stat), | ||
311 | GFP_ATOMIC); | ||
312 | if (!sta->tx_lat) { | ||
313 | rcu_read_unlock(); | ||
314 | goto free; | ||
315 | } | ||
316 | |||
317 | if (tx_latency->n_ranges) { | ||
318 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | ||
319 | /* size of bins is size of the ranges +1 */ | ||
320 | sta->tx_lat[i].bin_count = | ||
321 | tx_latency->n_ranges + 1; | ||
322 | sta->tx_lat[i].bins = | ||
323 | kcalloc(sta->tx_lat[i].bin_count, | ||
324 | sizeof(u32), GFP_ATOMIC); | ||
325 | if (!sta->tx_lat[i].bins) { | ||
326 | rcu_read_unlock(); | ||
327 | goto free; | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | rcu_read_unlock(); | ||
333 | |||
334 | spin_lock_init(&sta->lock); | 296 | spin_lock_init(&sta->lock); |
335 | spin_lock_init(&sta->ps_lock); | 297 | spin_lock_init(&sta->ps_lock); |
336 | INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); | 298 | INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); |
@@ -359,8 +321,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
359 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) | 321 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) |
360 | ewma_init(&sta->chain_signal_avg[i], 1024, 8); | 322 | ewma_init(&sta->chain_signal_avg[i], 1024, 8); |
361 | 323 | ||
362 | if (sta_prepare_rate_control(local, sta, gfp)) | 324 | if (sta_prepare_rate_control(local, sta, gfp)) { |
363 | goto free; | 325 | kfree(sta); |
326 | return NULL; | ||
327 | } | ||
364 | 328 | ||
365 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | 329 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
366 | /* | 330 | /* |
@@ -405,16 +369,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
405 | } | 369 | } |
406 | 370 | ||
407 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); | 371 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); |
408 | return sta; | ||
409 | 372 | ||
410 | free: | 373 | return sta; |
411 | if (sta->tx_lat) { | ||
412 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | ||
413 | kfree(sta->tx_lat[i].bins); | ||
414 | kfree(sta->tx_lat); | ||
415 | } | ||
416 | kfree(sta); | ||
417 | return NULL; | ||
418 | } | 374 | } |
419 | 375 | ||
420 | static int sta_info_insert_check(struct sta_info *sta) | 376 | static int sta_info_insert_check(struct sta_info *sta) |
@@ -1275,7 +1231,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
1275 | } | 1231 | } |
1276 | 1232 | ||
1277 | info->band = chanctx_conf->def.chan->band; | 1233 | info->band = chanctx_conf->def.chan->band; |
1278 | ieee80211_xmit(sdata, skb); | 1234 | ieee80211_xmit(sdata, sta, skb); |
1279 | rcu_read_unlock(); | 1235 | rcu_read_unlock(); |
1280 | } | 1236 | } |
1281 | 1237 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 925e68fe64c7..248f56e59ebc 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -234,25 +234,6 @@ struct sta_ampdu_mlme { | |||
234 | u8 dialog_token_allocator; | 234 | u8 dialog_token_allocator; |
235 | }; | 235 | }; |
236 | 236 | ||
237 | /* | ||
238 | * struct ieee80211_tx_latency_stat - Tx latency statistics | ||
239 | * | ||
240 | * Measures TX latency and jitter for a station per TID. | ||
241 | * | ||
242 | * @max: worst case latency | ||
243 | * @sum: sum of all latencies | ||
244 | * @counter: amount of Tx frames sent from interface | ||
245 | * @bins: each bin counts how many frames transmitted within a certain | ||
246 | * latency range. when disabled it is NULL. | ||
247 | * @bin_count: amount of bins. | ||
248 | */ | ||
249 | struct ieee80211_tx_latency_stat { | ||
250 | u32 max; | ||
251 | u32 sum; | ||
252 | u32 counter; | ||
253 | u32 *bins; | ||
254 | u32 bin_count; | ||
255 | }; | ||
256 | 237 | ||
257 | /* Value to indicate no TID reservation */ | 238 | /* Value to indicate no TID reservation */ |
258 | #define IEEE80211_TID_UNRESERVED 0xff | 239 | #define IEEE80211_TID_UNRESERVED 0xff |
@@ -314,7 +295,6 @@ struct ieee80211_tx_latency_stat { | |||
314 | * @tid_seq: per-TID sequence numbers for sending to this STA | 295 | * @tid_seq: per-TID sequence numbers for sending to this STA |
315 | * @ampdu_mlme: A-MPDU state machine state | 296 | * @ampdu_mlme: A-MPDU state machine state |
316 | * @timer_to_tid: identity mapping to ID timers | 297 | * @timer_to_tid: identity mapping to ID timers |
317 | * @tx_lat: Tx latency statistics | ||
318 | * @llid: Local link ID | 298 | * @llid: Local link ID |
319 | * @plid: Peer link ID | 299 | * @plid: Peer link ID |
320 | * @reason: Cancel reason on PLINK_HOLDING state | 300 | * @reason: Cancel reason on PLINK_HOLDING state |
@@ -435,8 +415,6 @@ struct sta_info { | |||
435 | struct sta_ampdu_mlme ampdu_mlme; | 415 | struct sta_ampdu_mlme ampdu_mlme; |
436 | u8 timer_to_tid[IEEE80211_NUM_TIDS]; | 416 | u8 timer_to_tid[IEEE80211_NUM_TIDS]; |
437 | 417 | ||
438 | struct ieee80211_tx_latency_stat *tx_lat; | ||
439 | |||
440 | #ifdef CONFIG_MAC80211_MESH | 418 | #ifdef CONFIG_MAC80211_MESH |
441 | /* | 419 | /* |
442 | * Mesh peer link attributes | 420 | * Mesh peer link attributes |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index e679b7c9b160..2c51742428d5 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -12,7 +12,6 @@ | |||
12 | 12 | ||
13 | #include <linux/export.h> | 13 | #include <linux/export.h> |
14 | #include <linux/etherdevice.h> | 14 | #include <linux/etherdevice.h> |
15 | #include <linux/time.h> | ||
16 | #include <net/mac80211.h> | 15 | #include <net/mac80211.h> |
17 | #include <asm/unaligned.h> | 16 | #include <asm/unaligned.h> |
18 | #include "ieee80211_i.h" | 17 | #include "ieee80211_i.h" |
@@ -515,73 +514,6 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, | |||
515 | } | 514 | } |
516 | 515 | ||
517 | /* | 516 | /* |
518 | * Measure Tx frame completion and removal time for Tx latency statistics | ||
519 | * calculation. A single Tx frame latency should be measured from when it | ||
520 | * is entering the Kernel until we receive Tx complete confirmation indication | ||
521 | * and remove the skb. | ||
522 | */ | ||
523 | static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | ||
524 | struct sk_buff *skb, | ||
525 | struct sta_info *sta, | ||
526 | struct ieee80211_hdr *hdr) | ||
527 | { | ||
528 | u32 msrmnt; | ||
529 | u16 tid; | ||
530 | u8 *qc; | ||
531 | int i, bin_range_count; | ||
532 | u32 *bin_ranges; | ||
533 | __le16 fc; | ||
534 | struct ieee80211_tx_latency_stat *tx_lat; | ||
535 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
536 | ktime_t skb_arv = skb->tstamp; | ||
537 | |||
538 | tx_latency = rcu_dereference(local->tx_latency); | ||
539 | |||
540 | /* assert Tx latency stats are enabled & frame arrived when enabled */ | ||
541 | if (!tx_latency || !ktime_to_ns(skb_arv)) | ||
542 | return; | ||
543 | |||
544 | fc = hdr->frame_control; | ||
545 | |||
546 | if (!ieee80211_is_data(fc)) /* make sure it is a data frame */ | ||
547 | return; | ||
548 | |||
549 | /* get frame tid */ | ||
550 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
551 | qc = ieee80211_get_qos_ctl(hdr); | ||
552 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||
553 | } else { | ||
554 | tid = 0; | ||
555 | } | ||
556 | |||
557 | tx_lat = &sta->tx_lat[tid]; | ||
558 | |||
559 | /* Calculate the latency */ | ||
560 | msrmnt = ktime_to_ms(ktime_sub(ktime_get(), skb_arv)); | ||
561 | |||
562 | if (tx_lat->max < msrmnt) /* update stats */ | ||
563 | tx_lat->max = msrmnt; | ||
564 | tx_lat->counter++; | ||
565 | tx_lat->sum += msrmnt; | ||
566 | |||
567 | if (!tx_lat->bins) /* bins not activated */ | ||
568 | return; | ||
569 | |||
570 | /* count how many Tx frames transmitted with the appropriate latency */ | ||
571 | bin_range_count = tx_latency->n_ranges; | ||
572 | bin_ranges = tx_latency->ranges; | ||
573 | |||
574 | for (i = 0; i < bin_range_count; i++) { | ||
575 | if (msrmnt <= bin_ranges[i]) { | ||
576 | tx_lat->bins[i]++; | ||
577 | break; | ||
578 | } | ||
579 | } | ||
580 | if (i == bin_range_count) /* msrmnt is bigger than the biggest range */ | ||
581 | tx_lat->bins[i]++; | ||
582 | } | ||
583 | |||
584 | /* | ||
585 | * Use a static threshold for now, best value to be determined | 517 | * Use a static threshold for now, best value to be determined |
586 | * by testing ... | 518 | * by testing ... |
587 | * Should it depend on: | 519 | * Should it depend on: |
@@ -853,12 +785,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
853 | 785 | ||
854 | if (acked) | 786 | if (acked) |
855 | sta->last_ack_signal = info->status.ack_signal; | 787 | sta->last_ack_signal = info->status.ack_signal; |
856 | |||
857 | /* | ||
858 | * Measure frame removal for tx latency | ||
859 | * statistics calculation | ||
860 | */ | ||
861 | ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr); | ||
862 | } | 788 | } |
863 | 789 | ||
864 | rcu_read_unlock(); | 790 | rcu_read_unlock(); |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index c9f9752217ac..fff0d864adfa 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -136,6 +136,24 @@ ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata, | |||
136 | *pos = 2 * subband_cnt; | 136 | *pos = 2 * subband_cnt; |
137 | } | 137 | } |
138 | 138 | ||
139 | static void ieee80211_tdls_add_oper_classes(struct ieee80211_sub_if_data *sdata, | ||
140 | struct sk_buff *skb) | ||
141 | { | ||
142 | u8 *pos; | ||
143 | u8 op_class; | ||
144 | |||
145 | if (!ieee80211_chandef_to_operating_class(&sdata->vif.bss_conf.chandef, | ||
146 | &op_class)) | ||
147 | return; | ||
148 | |||
149 | pos = skb_put(skb, 4); | ||
150 | *pos++ = WLAN_EID_SUPPORTED_REGULATORY_CLASSES; | ||
151 | *pos++ = 2; /* len */ | ||
152 | |||
153 | *pos++ = op_class; | ||
154 | *pos++ = op_class; /* give current operating class as alternate too */ | ||
155 | } | ||
156 | |||
139 | static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) | 157 | static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) |
140 | { | 158 | { |
141 | u8 *pos = (void *)skb_put(skb, 3); | 159 | u8 *pos = (void *)skb_put(skb, 3); |
@@ -193,6 +211,17 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, | |||
193 | memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); | 211 | memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); |
194 | } | 212 | } |
195 | 213 | ||
214 | static void | ||
215 | ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | ||
216 | { | ||
217 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
218 | u8 *pos = (void *)skb_put(skb, 4); | ||
219 | |||
220 | *pos++ = WLAN_EID_AID; | ||
221 | *pos++ = 2; /* len */ | ||
222 | put_unaligned_le16(ifmgd->aid, pos); | ||
223 | } | ||
224 | |||
196 | /* translate numbering in the WMM parameter IE to the mac80211 notation */ | 225 | /* translate numbering in the WMM parameter IE to the mac80211 notation */ |
197 | static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac) | 226 | static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac) |
198 | { | 227 | { |
@@ -271,21 +300,11 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
271 | struct ieee80211_local *local = sdata->local; | 300 | struct ieee80211_local *local = sdata->local; |
272 | struct ieee80211_supported_band *sband; | 301 | struct ieee80211_supported_band *sband; |
273 | struct ieee80211_sta_ht_cap ht_cap; | 302 | struct ieee80211_sta_ht_cap ht_cap; |
303 | struct ieee80211_sta_vht_cap vht_cap; | ||
274 | struct sta_info *sta = NULL; | 304 | struct sta_info *sta = NULL; |
275 | size_t offset = 0, noffset; | 305 | size_t offset = 0, noffset; |
276 | u8 *pos; | 306 | u8 *pos; |
277 | 307 | ||
278 | rcu_read_lock(); | ||
279 | |||
280 | /* we should have the peer STA if we're already responding */ | ||
281 | if (action_code == WLAN_TDLS_SETUP_RESPONSE) { | ||
282 | sta = sta_info_get(sdata, peer); | ||
283 | if (WARN_ON_ONCE(!sta)) { | ||
284 | rcu_read_unlock(); | ||
285 | return; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | ieee80211_add_srates_ie(sdata, skb, false, band); | 308 | ieee80211_add_srates_ie(sdata, skb, false, band); |
290 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | 309 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); |
291 | ieee80211_tdls_add_supp_channels(sdata, skb); | 310 | ieee80211_tdls_add_supp_channels(sdata, skb); |
@@ -338,6 +357,19 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
338 | offset = noffset; | 357 | offset = noffset; |
339 | } | 358 | } |
340 | 359 | ||
360 | rcu_read_lock(); | ||
361 | |||
362 | /* we should have the peer STA if we're already responding */ | ||
363 | if (action_code == WLAN_TDLS_SETUP_RESPONSE) { | ||
364 | sta = sta_info_get(sdata, peer); | ||
365 | if (WARN_ON_ONCE(!sta)) { | ||
366 | rcu_read_unlock(); | ||
367 | return; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | ieee80211_tdls_add_oper_classes(sdata, skb); | ||
372 | |||
341 | /* | 373 | /* |
342 | * with TDLS we can switch channels, and HT-caps are not necessarily | 374 | * with TDLS we can switch channels, and HT-caps are not necessarily |
343 | * the same on all bands. The specification limits the setup to a | 375 | * the same on all bands. The specification limits the setup to a |
@@ -346,7 +378,9 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
346 | sband = local->hw.wiphy->bands[band]; | 378 | sband = local->hw.wiphy->bands[band]; |
347 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | 379 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); |
348 | 380 | ||
349 | if (action_code == WLAN_TDLS_SETUP_REQUEST && ht_cap.ht_supported) { | 381 | if ((action_code == WLAN_TDLS_SETUP_REQUEST || |
382 | action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) && | ||
383 | ht_cap.ht_supported) { | ||
350 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | 384 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); |
351 | 385 | ||
352 | /* disable SMPS in TDLS initiator */ | 386 | /* disable SMPS in TDLS initiator */ |
@@ -368,12 +402,63 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
368 | ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); | 402 | ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); |
369 | } | 403 | } |
370 | 404 | ||
371 | rcu_read_unlock(); | ||
372 | |||
373 | if (ht_cap.ht_supported && | 405 | if (ht_cap.ht_supported && |
374 | (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | 406 | (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) |
375 | ieee80211_tdls_add_bss_coex_ie(skb); | 407 | ieee80211_tdls_add_bss_coex_ie(skb); |
376 | 408 | ||
409 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
410 | |||
411 | /* add any custom IEs that go before VHT capabilities */ | ||
412 | if (extra_ies_len) { | ||
413 | static const u8 before_vht_cap[] = { | ||
414 | WLAN_EID_SUPP_RATES, | ||
415 | WLAN_EID_COUNTRY, | ||
416 | WLAN_EID_EXT_SUPP_RATES, | ||
417 | WLAN_EID_SUPPORTED_CHANNELS, | ||
418 | WLAN_EID_RSN, | ||
419 | WLAN_EID_EXT_CAPABILITY, | ||
420 | WLAN_EID_QOS_CAPA, | ||
421 | WLAN_EID_FAST_BSS_TRANSITION, | ||
422 | WLAN_EID_TIMEOUT_INTERVAL, | ||
423 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
424 | WLAN_EID_MULTI_BAND, | ||
425 | }; | ||
426 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
427 | before_vht_cap, | ||
428 | ARRAY_SIZE(before_vht_cap), | ||
429 | offset); | ||
430 | pos = skb_put(skb, noffset - offset); | ||
431 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
432 | offset = noffset; | ||
433 | } | ||
434 | |||
435 | /* build the VHT-cap similarly to the HT-cap */ | ||
436 | memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); | ||
437 | if ((action_code == WLAN_TDLS_SETUP_REQUEST || | ||
438 | action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) && | ||
439 | vht_cap.vht_supported) { | ||
440 | ieee80211_apply_vhtcap_overrides(sdata, &vht_cap); | ||
441 | |||
442 | /* the AID is present only when VHT is implemented */ | ||
443 | if (action_code == WLAN_TDLS_SETUP_REQUEST) | ||
444 | ieee80211_tdls_add_aid(sdata, skb); | ||
445 | |||
446 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); | ||
447 | ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap); | ||
448 | } else if (action_code == WLAN_TDLS_SETUP_RESPONSE && | ||
449 | vht_cap.vht_supported && sta->sta.vht_cap.vht_supported) { | ||
450 | /* the peer caps are already intersected with our own */ | ||
451 | memcpy(&vht_cap, &sta->sta.vht_cap, sizeof(vht_cap)); | ||
452 | |||
453 | /* the AID is present only when VHT is implemented */ | ||
454 | ieee80211_tdls_add_aid(sdata, skb); | ||
455 | |||
456 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); | ||
457 | ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap); | ||
458 | } | ||
459 | |||
460 | rcu_read_unlock(); | ||
461 | |||
377 | /* add any remaining IEs */ | 462 | /* add any remaining IEs */ |
378 | if (extra_ies_len) { | 463 | if (extra_ies_len) { |
379 | noffset = extra_ies_len; | 464 | noffset = extra_ies_len; |
@@ -381,7 +466,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
381 | memcpy(pos, extra_ies + offset, noffset - offset); | 466 | memcpy(pos, extra_ies + offset, noffset - offset); |
382 | } | 467 | } |
383 | 468 | ||
384 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
385 | } | 469 | } |
386 | 470 | ||
387 | static void | 471 | static void |
@@ -394,6 +478,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | |||
394 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 478 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
395 | size_t offset = 0, noffset; | 479 | size_t offset = 0, noffset; |
396 | struct sta_info *sta, *ap_sta; | 480 | struct sta_info *sta, *ap_sta; |
481 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
397 | u8 *pos; | 482 | u8 *pos; |
398 | 483 | ||
399 | rcu_read_lock(); | 484 | rcu_read_lock(); |
@@ -453,6 +538,21 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | |||
453 | } | 538 | } |
454 | } | 539 | } |
455 | 540 | ||
541 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
542 | |||
543 | /* only include VHT-operation if not on the 2.4GHz band */ | ||
544 | if (band != IEEE80211_BAND_2GHZ && !ap_sta->sta.vht_cap.vht_supported && | ||
545 | sta->sta.vht_cap.vht_supported) { | ||
546 | struct ieee80211_chanctx_conf *chanctx_conf = | ||
547 | rcu_dereference(sdata->vif.chanctx_conf); | ||
548 | if (!WARN_ON(!chanctx_conf)) { | ||
549 | pos = skb_put(skb, 2 + | ||
550 | sizeof(struct ieee80211_vht_operation)); | ||
551 | ieee80211_ie_build_vht_oper(pos, &sta->sta.vht_cap, | ||
552 | &chanctx_conf->def); | ||
553 | } | ||
554 | } | ||
555 | |||
456 | rcu_read_unlock(); | 556 | rcu_read_unlock(); |
457 | 557 | ||
458 | /* add any remaining IEs */ | 558 | /* add any remaining IEs */ |
@@ -461,8 +561,6 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | |||
461 | pos = skb_put(skb, noffset - offset); | 561 | pos = skb_put(skb, noffset - offset); |
462 | memcpy(pos, extra_ies + offset, noffset - offset); | 562 | memcpy(pos, extra_ies + offset, noffset - offset); |
463 | } | 563 | } |
464 | |||
465 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
466 | } | 564 | } |
467 | 565 | ||
468 | static void | 566 | static void |
@@ -708,8 +806,12 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, | |||
708 | 26 + /* max(WMM-info, WMM-param) */ | 806 | 26 + /* max(WMM-info, WMM-param) */ |
709 | 2 + max(sizeof(struct ieee80211_ht_cap), | 807 | 2 + max(sizeof(struct ieee80211_ht_cap), |
710 | sizeof(struct ieee80211_ht_operation)) + | 808 | sizeof(struct ieee80211_ht_operation)) + |
809 | 2 + max(sizeof(struct ieee80211_vht_cap), | ||
810 | sizeof(struct ieee80211_vht_operation)) + | ||
711 | 50 + /* supported channels */ | 811 | 50 + /* supported channels */ |
712 | 3 + /* 40/20 BSS coex */ | 812 | 3 + /* 40/20 BSS coex */ |
813 | 4 + /* AID */ | ||
814 | 4 + /* oper classes */ | ||
713 | extra_ies_len + | 815 | extra_ies_len + |
714 | sizeof(struct ieee80211_tdls_lnkie)); | 816 | sizeof(struct ieee80211_tdls_lnkie)); |
715 | if (!skb) | 817 | if (!skb) |
@@ -907,7 +1009,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | |||
907 | if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) && | 1009 | if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) && |
908 | !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { | 1010 | !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { |
909 | ret = -EBUSY; | 1011 | ret = -EBUSY; |
910 | goto exit; | 1012 | goto out_unlock; |
911 | } | 1013 | } |
912 | 1014 | ||
913 | /* | 1015 | /* |
@@ -922,27 +1024,34 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | |||
922 | if (!sta_info_get(sdata, peer)) { | 1024 | if (!sta_info_get(sdata, peer)) { |
923 | rcu_read_unlock(); | 1025 | rcu_read_unlock(); |
924 | ret = -ENOLINK; | 1026 | ret = -ENOLINK; |
925 | goto exit; | 1027 | goto out_unlock; |
926 | } | 1028 | } |
927 | rcu_read_unlock(); | 1029 | rcu_read_unlock(); |
928 | } | 1030 | } |
929 | 1031 | ||
930 | ieee80211_flush_queues(local, sdata, false); | 1032 | ieee80211_flush_queues(local, sdata, false); |
1033 | memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN); | ||
1034 | mutex_unlock(&local->mtx); | ||
931 | 1035 | ||
1036 | /* we cannot take the mutex while preparing the setup packet */ | ||
932 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | 1037 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, |
933 | dialog_token, status_code, | 1038 | dialog_token, status_code, |
934 | peer_capability, initiator, | 1039 | peer_capability, initiator, |
935 | extra_ies, extra_ies_len, 0, | 1040 | extra_ies, extra_ies_len, 0, |
936 | NULL); | 1041 | NULL); |
937 | if (ret < 0) | 1042 | if (ret < 0) { |
938 | goto exit; | 1043 | mutex_lock(&local->mtx); |
1044 | eth_zero_addr(sdata->u.mgd.tdls_peer); | ||
1045 | mutex_unlock(&local->mtx); | ||
1046 | return ret; | ||
1047 | } | ||
939 | 1048 | ||
940 | memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN); | ||
941 | ieee80211_queue_delayed_work(&sdata->local->hw, | 1049 | ieee80211_queue_delayed_work(&sdata->local->hw, |
942 | &sdata->u.mgd.tdls_peer_del_work, | 1050 | &sdata->u.mgd.tdls_peer_del_work, |
943 | TDLS_PEER_SETUP_TIMEOUT); | 1051 | TDLS_PEER_SETUP_TIMEOUT); |
1052 | return 0; | ||
944 | 1053 | ||
945 | exit: | 1054 | out_unlock: |
946 | mutex_unlock(&local->mtx); | 1055 | mutex_unlock(&local->mtx); |
947 | return ret; | 1056 | return ret; |
948 | } | 1057 | } |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 263a9561eb26..e9e462b349e5 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -1256,28 +1256,28 @@ TRACE_EVENT(drv_set_rekey_data, | |||
1256 | LOCAL_PR_ARG, VIF_PR_ARG) | 1256 | LOCAL_PR_ARG, VIF_PR_ARG) |
1257 | ); | 1257 | ); |
1258 | 1258 | ||
1259 | TRACE_EVENT(drv_rssi_callback, | 1259 | TRACE_EVENT(drv_event_callback, |
1260 | TP_PROTO(struct ieee80211_local *local, | 1260 | TP_PROTO(struct ieee80211_local *local, |
1261 | struct ieee80211_sub_if_data *sdata, | 1261 | struct ieee80211_sub_if_data *sdata, |
1262 | enum ieee80211_rssi_event rssi_event), | 1262 | const struct ieee80211_event *_event), |
1263 | 1263 | ||
1264 | TP_ARGS(local, sdata, rssi_event), | 1264 | TP_ARGS(local, sdata, _event), |
1265 | 1265 | ||
1266 | TP_STRUCT__entry( | 1266 | TP_STRUCT__entry( |
1267 | LOCAL_ENTRY | 1267 | LOCAL_ENTRY |
1268 | VIF_ENTRY | 1268 | VIF_ENTRY |
1269 | __field(u32, rssi_event) | 1269 | __field(u32, type) |
1270 | ), | 1270 | ), |
1271 | 1271 | ||
1272 | TP_fast_assign( | 1272 | TP_fast_assign( |
1273 | LOCAL_ASSIGN; | 1273 | LOCAL_ASSIGN; |
1274 | VIF_ASSIGN; | 1274 | VIF_ASSIGN; |
1275 | __entry->rssi_event = rssi_event; | 1275 | __entry->type = _event->type; |
1276 | ), | 1276 | ), |
1277 | 1277 | ||
1278 | TP_printk( | 1278 | TP_printk( |
1279 | LOCAL_PR_FMT VIF_PR_FMT " rssi_event:%d", | 1279 | LOCAL_PR_FMT VIF_PR_FMT " event:%d", |
1280 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->rssi_event | 1280 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->type |
1281 | ) | 1281 | ) |
1282 | ); | 1282 | ); |
1283 | 1283 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 07bd8db00af8..9f7fb4eec37b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <linux/bitmap.h> | 20 | #include <linux/bitmap.h> |
21 | #include <linux/rcupdate.h> | 21 | #include <linux/rcupdate.h> |
22 | #include <linux/export.h> | 22 | #include <linux/export.h> |
23 | #include <linux/time.h> | ||
24 | #include <net/net_namespace.h> | 23 | #include <net/net_namespace.h> |
25 | #include <net/ieee80211_radiotap.h> | 24 | #include <net/ieee80211_radiotap.h> |
26 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
@@ -595,23 +594,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
595 | else if (!is_multicast_ether_addr(hdr->addr1) && | 594 | else if (!is_multicast_ether_addr(hdr->addr1) && |
596 | (key = rcu_dereference(tx->sdata->default_unicast_key))) | 595 | (key = rcu_dereference(tx->sdata->default_unicast_key))) |
597 | tx->key = key; | 596 | tx->key = key; |
598 | else if (info->flags & IEEE80211_TX_CTL_INJECTED) | 597 | else |
599 | tx->key = NULL; | ||
600 | else if (!tx->sdata->drop_unencrypted) | ||
601 | tx->key = NULL; | ||
602 | else if (tx->skb->protocol == tx->sdata->control_port_protocol) | ||
603 | tx->key = NULL; | ||
604 | else if (ieee80211_is_robust_mgmt_frame(tx->skb) && | ||
605 | !(ieee80211_is_action(hdr->frame_control) && | ||
606 | tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) | ||
607 | tx->key = NULL; | ||
608 | else if (ieee80211_is_mgmt(hdr->frame_control) && | ||
609 | !ieee80211_is_robust_mgmt_frame(tx->skb)) | ||
610 | tx->key = NULL; | 598 | tx->key = NULL; |
611 | else { | ||
612 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); | ||
613 | return TX_DROP; | ||
614 | } | ||
615 | 599 | ||
616 | if (tx->key) { | 600 | if (tx->key) { |
617 | bool skip_hw = false; | 601 | bool skip_hw = false; |
@@ -1137,11 +1121,13 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, | |||
1137 | 1121 | ||
1138 | /* | 1122 | /* |
1139 | * initialises @tx | 1123 | * initialises @tx |
1124 | * pass %NULL for the station if unknown, a valid pointer if known | ||
1125 | * or an ERR_PTR() if the station is known not to exist | ||
1140 | */ | 1126 | */ |
1141 | static ieee80211_tx_result | 1127 | static ieee80211_tx_result |
1142 | ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | 1128 | ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, |
1143 | struct ieee80211_tx_data *tx, | 1129 | struct ieee80211_tx_data *tx, |
1144 | struct sk_buff *skb) | 1130 | struct sta_info *sta, struct sk_buff *skb) |
1145 | { | 1131 | { |
1146 | struct ieee80211_local *local = sdata->local; | 1132 | struct ieee80211_local *local = sdata->local; |
1147 | struct ieee80211_hdr *hdr; | 1133 | struct ieee80211_hdr *hdr; |
@@ -1164,17 +1150,22 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1164 | 1150 | ||
1165 | hdr = (struct ieee80211_hdr *) skb->data; | 1151 | hdr = (struct ieee80211_hdr *) skb->data; |
1166 | 1152 | ||
1167 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | 1153 | if (likely(sta)) { |
1168 | tx->sta = rcu_dereference(sdata->u.vlan.sta); | 1154 | if (!IS_ERR(sta)) |
1169 | if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) | 1155 | tx->sta = sta; |
1170 | return TX_DROP; | 1156 | } else { |
1171 | } else if (info->flags & (IEEE80211_TX_CTL_INJECTED | | 1157 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
1172 | IEEE80211_TX_INTFL_NL80211_FRAME_TX) || | 1158 | tx->sta = rcu_dereference(sdata->u.vlan.sta); |
1173 | tx->sdata->control_port_protocol == tx->skb->protocol) { | 1159 | if (!tx->sta && sdata->wdev.use_4addr) |
1174 | tx->sta = sta_info_get_bss(sdata, hdr->addr1); | 1160 | return TX_DROP; |
1161 | } else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX | | ||
1162 | IEEE80211_TX_CTL_INJECTED) || | ||
1163 | tx->sdata->control_port_protocol == tx->skb->protocol) { | ||
1164 | tx->sta = sta_info_get_bss(sdata, hdr->addr1); | ||
1165 | } | ||
1166 | if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) | ||
1167 | tx->sta = sta_info_get(sdata, hdr->addr1); | ||
1175 | } | 1168 | } |
1176 | if (!tx->sta) | ||
1177 | tx->sta = sta_info_get(sdata, hdr->addr1); | ||
1178 | 1169 | ||
1179 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && | 1170 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && |
1180 | !ieee80211_is_qos_nullfunc(hdr->frame_control) && | 1171 | !ieee80211_is_qos_nullfunc(hdr->frame_control) && |
@@ -1422,8 +1413,9 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw, | |||
1422 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1413 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
1423 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1414 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1424 | struct ieee80211_tx_data tx; | 1415 | struct ieee80211_tx_data tx; |
1416 | struct sk_buff *skb2; | ||
1425 | 1417 | ||
1426 | if (ieee80211_tx_prepare(sdata, &tx, skb) == TX_DROP) | 1418 | if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP) |
1427 | return false; | 1419 | return false; |
1428 | 1420 | ||
1429 | info->band = band; | 1421 | info->band = band; |
@@ -1440,6 +1432,14 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw, | |||
1440 | *sta = NULL; | 1432 | *sta = NULL; |
1441 | } | 1433 | } |
1442 | 1434 | ||
1435 | /* this function isn't suitable for fragmented data frames */ | ||
1436 | skb2 = __skb_dequeue(&tx.skbs); | ||
1437 | if (WARN_ON(skb2 != skb || !skb_queue_empty(&tx.skbs))) { | ||
1438 | ieee80211_free_txskb(hw, skb2); | ||
1439 | ieee80211_purge_tx_queue(hw, &tx.skbs); | ||
1440 | return false; | ||
1441 | } | ||
1442 | |||
1443 | return true; | 1443 | return true; |
1444 | } | 1444 | } |
1445 | EXPORT_SYMBOL(ieee80211_tx_prepare_skb); | 1445 | EXPORT_SYMBOL(ieee80211_tx_prepare_skb); |
@@ -1448,7 +1448,8 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb); | |||
1448 | * Returns false if the frame couldn't be transmitted but was queued instead. | 1448 | * Returns false if the frame couldn't be transmitted but was queued instead. |
1449 | */ | 1449 | */ |
1450 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | 1450 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, |
1451 | struct sk_buff *skb, bool txpending) | 1451 | struct sta_info *sta, struct sk_buff *skb, |
1452 | bool txpending) | ||
1452 | { | 1453 | { |
1453 | struct ieee80211_local *local = sdata->local; | 1454 | struct ieee80211_local *local = sdata->local; |
1454 | struct ieee80211_tx_data tx; | 1455 | struct ieee80211_tx_data tx; |
@@ -1464,7 +1465,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1464 | 1465 | ||
1465 | /* initialises tx */ | 1466 | /* initialises tx */ |
1466 | led_len = skb->len; | 1467 | led_len = skb->len; |
1467 | res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); | 1468 | res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb); |
1468 | 1469 | ||
1469 | if (unlikely(res_prepare == TX_DROP)) { | 1470 | if (unlikely(res_prepare == TX_DROP)) { |
1470 | ieee80211_free_txskb(&local->hw, skb); | 1471 | ieee80211_free_txskb(&local->hw, skb); |
@@ -1520,7 +1521,8 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, | |||
1520 | return 0; | 1521 | return 0; |
1521 | } | 1522 | } |
1522 | 1523 | ||
1523 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | 1524 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, |
1525 | struct sta_info *sta, struct sk_buff *skb) | ||
1524 | { | 1526 | { |
1525 | struct ieee80211_local *local = sdata->local; | 1527 | struct ieee80211_local *local = sdata->local; |
1526 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1528 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
@@ -1555,7 +1557,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
1555 | } | 1557 | } |
1556 | 1558 | ||
1557 | ieee80211_set_qos_hdr(sdata, skb); | 1559 | ieee80211_set_qos_hdr(sdata, skb); |
1558 | ieee80211_tx(sdata, skb, false); | 1560 | ieee80211_tx(sdata, sta, skb, false); |
1559 | } | 1561 | } |
1560 | 1562 | ||
1561 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) | 1563 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) |
@@ -1776,7 +1778,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1776 | goto fail_rcu; | 1778 | goto fail_rcu; |
1777 | 1779 | ||
1778 | info->band = chandef->chan->band; | 1780 | info->band = chandef->chan->band; |
1779 | ieee80211_xmit(sdata, skb); | 1781 | ieee80211_xmit(sdata, NULL, skb); |
1780 | rcu_read_unlock(); | 1782 | rcu_read_unlock(); |
1781 | 1783 | ||
1782 | return NETDEV_TX_OK; | 1784 | return NETDEV_TX_OK; |
@@ -1788,21 +1790,89 @@ fail: | |||
1788 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ | 1790 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ |
1789 | } | 1791 | } |
1790 | 1792 | ||
1791 | /* | 1793 | static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb) |
1792 | * Measure Tx frame arrival time for Tx latency statistics calculation | ||
1793 | * A single Tx frame latency should be measured from when it is entering the | ||
1794 | * Kernel until we receive Tx complete confirmation indication and the skb is | ||
1795 | * freed. | ||
1796 | */ | ||
1797 | static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, | ||
1798 | struct sk_buff *skb) | ||
1799 | { | 1794 | { |
1800 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | 1795 | u16 ethertype = (skb->data[12] << 8) | skb->data[13]; |
1801 | 1796 | ||
1802 | tx_latency = rcu_dereference(local->tx_latency); | 1797 | return ethertype == ETH_P_TDLS && |
1803 | if (!tx_latency) | 1798 | skb->len > 14 && |
1804 | return; | 1799 | skb->data[14] == WLAN_TDLS_SNAP_RFTYPE; |
1805 | skb->tstamp = ktime_get(); | 1800 | } |
1801 | |||
1802 | static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, | ||
1803 | struct sk_buff *skb, | ||
1804 | struct sta_info **sta_out) | ||
1805 | { | ||
1806 | struct sta_info *sta; | ||
1807 | |||
1808 | switch (sdata->vif.type) { | ||
1809 | case NL80211_IFTYPE_AP_VLAN: | ||
1810 | sta = rcu_dereference(sdata->u.vlan.sta); | ||
1811 | if (sta) { | ||
1812 | *sta_out = sta; | ||
1813 | return 0; | ||
1814 | } else if (sdata->wdev.use_4addr) { | ||
1815 | return -ENOLINK; | ||
1816 | } | ||
1817 | /* fall through */ | ||
1818 | case NL80211_IFTYPE_AP: | ||
1819 | case NL80211_IFTYPE_OCB: | ||
1820 | case NL80211_IFTYPE_ADHOC: | ||
1821 | if (is_multicast_ether_addr(skb->data)) { | ||
1822 | *sta_out = ERR_PTR(-ENOENT); | ||
1823 | return 0; | ||
1824 | } | ||
1825 | sta = sta_info_get_bss(sdata, skb->data); | ||
1826 | break; | ||
1827 | case NL80211_IFTYPE_WDS: | ||
1828 | sta = sta_info_get(sdata, sdata->u.wds.remote_addr); | ||
1829 | break; | ||
1830 | #ifdef CONFIG_MAC80211_MESH | ||
1831 | case NL80211_IFTYPE_MESH_POINT: | ||
1832 | /* determined much later */ | ||
1833 | *sta_out = NULL; | ||
1834 | return 0; | ||
1835 | #endif | ||
1836 | case NL80211_IFTYPE_STATION: | ||
1837 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { | ||
1838 | sta = sta_info_get(sdata, skb->data); | ||
1839 | if (sta) { | ||
1840 | bool tdls_peer, tdls_auth; | ||
1841 | |||
1842 | tdls_peer = test_sta_flag(sta, | ||
1843 | WLAN_STA_TDLS_PEER); | ||
1844 | tdls_auth = test_sta_flag(sta, | ||
1845 | WLAN_STA_TDLS_PEER_AUTH); | ||
1846 | |||
1847 | if (tdls_peer && tdls_auth) { | ||
1848 | *sta_out = sta; | ||
1849 | return 0; | ||
1850 | } | ||
1851 | |||
1852 | /* | ||
1853 | * TDLS link during setup - throw out frames to | ||
1854 | * peer. Allow TDLS-setup frames to unauthorized | ||
1855 | * peers for the special case of a link teardown | ||
1856 | * after a TDLS sta is removed due to being | ||
1857 | * unreachable. | ||
1858 | */ | ||
1859 | if (tdls_peer && !tdls_auth && | ||
1860 | !ieee80211_is_tdls_setup(skb)) | ||
1861 | return -EINVAL; | ||
1862 | } | ||
1863 | |||
1864 | } | ||
1865 | |||
1866 | sta = sta_info_get(sdata, sdata->u.mgd.bssid); | ||
1867 | if (!sta) | ||
1868 | return -ENOLINK; | ||
1869 | break; | ||
1870 | default: | ||
1871 | return -EINVAL; | ||
1872 | } | ||
1873 | |||
1874 | *sta_out = sta ?: ERR_PTR(-ENOENT); | ||
1875 | return 0; | ||
1806 | } | 1876 | } |
1807 | 1877 | ||
1808 | /** | 1878 | /** |
@@ -1824,7 +1894,8 @@ static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, | |||
1824 | * Returns: the (possibly reallocated) skb or an ERR_PTR() code | 1894 | * Returns: the (possibly reallocated) skb or an ERR_PTR() code |
1825 | */ | 1895 | */ |
1826 | static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | 1896 | static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, |
1827 | struct sk_buff *skb, u32 info_flags) | 1897 | struct sk_buff *skb, u32 info_flags, |
1898 | struct sta_info *sta) | ||
1828 | { | 1899 | { |
1829 | struct ieee80211_local *local = sdata->local; | 1900 | struct ieee80211_local *local = sdata->local; |
1830 | struct ieee80211_tx_info *info; | 1901 | struct ieee80211_tx_info *info; |
@@ -1837,9 +1908,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1837 | const u8 *encaps_data; | 1908 | const u8 *encaps_data; |
1838 | int encaps_len, skip_header_bytes; | 1909 | int encaps_len, skip_header_bytes; |
1839 | int nh_pos, h_pos; | 1910 | int nh_pos, h_pos; |
1840 | struct sta_info *sta = NULL; | 1911 | bool wme_sta = false, authorized = false; |
1841 | bool wme_sta = false, authorized = false, tdls_auth = false; | 1912 | bool tdls_peer; |
1842 | bool tdls_peer = false, tdls_setup_frame = false; | ||
1843 | bool multicast; | 1913 | bool multicast; |
1844 | u16 info_id = 0; | 1914 | u16 info_id = 0; |
1845 | struct ieee80211_chanctx_conf *chanctx_conf; | 1915 | struct ieee80211_chanctx_conf *chanctx_conf; |
@@ -1847,6 +1917,9 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1847 | enum ieee80211_band band; | 1917 | enum ieee80211_band band; |
1848 | int ret; | 1918 | int ret; |
1849 | 1919 | ||
1920 | if (IS_ERR(sta)) | ||
1921 | sta = NULL; | ||
1922 | |||
1850 | /* convert Ethernet header to proper 802.11 header (based on | 1923 | /* convert Ethernet header to proper 802.11 header (based on |
1851 | * operation mode) */ | 1924 | * operation mode) */ |
1852 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 1925 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
@@ -1854,8 +1927,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1854 | 1927 | ||
1855 | switch (sdata->vif.type) { | 1928 | switch (sdata->vif.type) { |
1856 | case NL80211_IFTYPE_AP_VLAN: | 1929 | case NL80211_IFTYPE_AP_VLAN: |
1857 | sta = rcu_dereference(sdata->u.vlan.sta); | 1930 | if (sdata->wdev.use_4addr) { |
1858 | if (sta) { | ||
1859 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1931 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
1860 | /* RA TA DA SA */ | 1932 | /* RA TA DA SA */ |
1861 | memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); | 1933 | memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); |
@@ -1874,7 +1946,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1874 | goto free; | 1946 | goto free; |
1875 | } | 1947 | } |
1876 | band = chanctx_conf->def.chan->band; | 1948 | band = chanctx_conf->def.chan->band; |
1877 | if (sta) | 1949 | if (sdata->wdev.use_4addr) |
1878 | break; | 1950 | break; |
1879 | /* fall through */ | 1951 | /* fall through */ |
1880 | case NL80211_IFTYPE_AP: | 1952 | case NL80211_IFTYPE_AP: |
@@ -1978,38 +2050,10 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1978 | break; | 2050 | break; |
1979 | #endif | 2051 | #endif |
1980 | case NL80211_IFTYPE_STATION: | 2052 | case NL80211_IFTYPE_STATION: |
1981 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 2053 | /* we already did checks when looking up the RA STA */ |
1982 | sta = sta_info_get(sdata, skb->data); | 2054 | tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER); |
1983 | if (sta) { | ||
1984 | authorized = test_sta_flag(sta, | ||
1985 | WLAN_STA_AUTHORIZED); | ||
1986 | wme_sta = sta->sta.wme; | ||
1987 | tdls_peer = test_sta_flag(sta, | ||
1988 | WLAN_STA_TDLS_PEER); | ||
1989 | tdls_auth = test_sta_flag(sta, | ||
1990 | WLAN_STA_TDLS_PEER_AUTH); | ||
1991 | } | ||
1992 | |||
1993 | if (tdls_peer) | ||
1994 | tdls_setup_frame = | ||
1995 | ethertype == ETH_P_TDLS && | ||
1996 | skb->len > 14 && | ||
1997 | skb->data[14] == WLAN_TDLS_SNAP_RFTYPE; | ||
1998 | } | ||
1999 | 2055 | ||
2000 | /* | 2056 | if (tdls_peer) { |
2001 | * TDLS link during setup - throw out frames to peer. We allow | ||
2002 | * TDLS-setup frames to unauthorized peers for the special case | ||
2003 | * of a link teardown after a TDLS sta is removed due to being | ||
2004 | * unreachable. | ||
2005 | */ | ||
2006 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) { | ||
2007 | ret = -EINVAL; | ||
2008 | goto free; | ||
2009 | } | ||
2010 | |||
2011 | /* send direct packets to authorized TDLS peers */ | ||
2012 | if (tdls_peer && tdls_auth) { | ||
2013 | /* DA SA BSSID */ | 2057 | /* DA SA BSSID */ |
2014 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 2058 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
2015 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 2059 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
@@ -2071,26 +2115,19 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
2071 | goto free; | 2115 | goto free; |
2072 | } | 2116 | } |
2073 | 2117 | ||
2074 | /* | ||
2075 | * There's no need to try to look up the destination | ||
2076 | * if it is a multicast address (which can only happen | ||
2077 | * in AP mode) | ||
2078 | */ | ||
2079 | multicast = is_multicast_ether_addr(hdr.addr1); | 2118 | multicast = is_multicast_ether_addr(hdr.addr1); |
2080 | if (!multicast) { | ||
2081 | sta = sta_info_get(sdata, hdr.addr1); | ||
2082 | if (sta) { | ||
2083 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); | ||
2084 | wme_sta = sta->sta.wme; | ||
2085 | } | ||
2086 | } | ||
2087 | 2119 | ||
2088 | /* For mesh, the use of the QoS header is mandatory */ | 2120 | /* sta is always NULL for mesh */ |
2089 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 2121 | if (sta) { |
2122 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); | ||
2123 | wme_sta = sta->sta.wme; | ||
2124 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
2125 | /* For mesh, the use of the QoS header is mandatory */ | ||
2090 | wme_sta = true; | 2126 | wme_sta = true; |
2127 | } | ||
2091 | 2128 | ||
2092 | /* receiver and we are QoS enabled, use a QoS type frame */ | 2129 | /* receiver does QoS (which also means we do) use it */ |
2093 | if (wme_sta && local->hw.queues >= IEEE80211_NUM_ACS) { | 2130 | if (wme_sta) { |
2094 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | 2131 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); |
2095 | hdrlen += 2; | 2132 | hdrlen += 2; |
2096 | } | 2133 | } |
@@ -2260,7 +2297,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2260 | u32 info_flags) | 2297 | u32 info_flags) |
2261 | { | 2298 | { |
2262 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2299 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
2263 | struct ieee80211_local *local = sdata->local; | 2300 | struct sta_info *sta; |
2264 | 2301 | ||
2265 | if (unlikely(skb->len < ETH_HLEN)) { | 2302 | if (unlikely(skb->len < ETH_HLEN)) { |
2266 | kfree_skb(skb); | 2303 | kfree_skb(skb); |
@@ -2269,10 +2306,12 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2269 | 2306 | ||
2270 | rcu_read_lock(); | 2307 | rcu_read_lock(); |
2271 | 2308 | ||
2272 | /* Measure frame arrival for Tx latency statistics calculation */ | 2309 | if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { |
2273 | ieee80211_tx_latency_start_msrmnt(local, skb); | 2310 | kfree_skb(skb); |
2311 | goto out; | ||
2312 | } | ||
2274 | 2313 | ||
2275 | skb = ieee80211_build_hdr(sdata, skb, info_flags); | 2314 | skb = ieee80211_build_hdr(sdata, skb, info_flags, sta); |
2276 | if (IS_ERR(skb)) | 2315 | if (IS_ERR(skb)) |
2277 | goto out; | 2316 | goto out; |
2278 | 2317 | ||
@@ -2280,7 +2319,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2280 | dev->stats.tx_bytes += skb->len; | 2319 | dev->stats.tx_bytes += skb->len; |
2281 | dev->trans_start = jiffies; | 2320 | dev->trans_start = jiffies; |
2282 | 2321 | ||
2283 | ieee80211_xmit(sdata, skb); | 2322 | ieee80211_xmit(sdata, sta, skb); |
2284 | out: | 2323 | out: |
2285 | rcu_read_unlock(); | 2324 | rcu_read_unlock(); |
2286 | } | 2325 | } |
@@ -2308,10 +2347,17 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, | |||
2308 | .local = sdata->local, | 2347 | .local = sdata->local, |
2309 | .sdata = sdata, | 2348 | .sdata = sdata, |
2310 | }; | 2349 | }; |
2350 | struct sta_info *sta; | ||
2311 | 2351 | ||
2312 | rcu_read_lock(); | 2352 | rcu_read_lock(); |
2313 | 2353 | ||
2314 | skb = ieee80211_build_hdr(sdata, skb, info_flags); | 2354 | if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { |
2355 | kfree_skb(skb); | ||
2356 | skb = ERR_PTR(-EINVAL); | ||
2357 | goto out; | ||
2358 | } | ||
2359 | |||
2360 | skb = ieee80211_build_hdr(sdata, skb, info_flags, sta); | ||
2315 | if (IS_ERR(skb)) | 2361 | if (IS_ERR(skb)) |
2316 | goto out; | 2362 | goto out; |
2317 | 2363 | ||
@@ -2369,7 +2415,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
2369 | return true; | 2415 | return true; |
2370 | } | 2416 | } |
2371 | info->band = chanctx_conf->def.chan->band; | 2417 | info->band = chanctx_conf->def.chan->band; |
2372 | result = ieee80211_tx(sdata, skb, true); | 2418 | result = ieee80211_tx(sdata, NULL, skb, true); |
2373 | } else { | 2419 | } else { |
2374 | struct sk_buff_head skbs; | 2420 | struct sk_buff_head skbs; |
2375 | 2421 | ||
@@ -3107,7 +3153,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
3107 | 3153 | ||
3108 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 3154 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
3109 | sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); | 3155 | sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); |
3110 | if (!ieee80211_tx_prepare(sdata, &tx, skb)) | 3156 | if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb)) |
3111 | break; | 3157 | break; |
3112 | dev_kfree_skb_any(skb); | 3158 | dev_kfree_skb_any(skb); |
3113 | } | 3159 | } |
@@ -3239,6 +3285,6 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | |||
3239 | */ | 3285 | */ |
3240 | local_bh_disable(); | 3286 | local_bh_disable(); |
3241 | IEEE80211_SKB_CB(skb)->band = band; | 3287 | IEEE80211_SKB_CB(skb)->band = band; |
3242 | ieee80211_xmit(sdata, skb); | 3288 | ieee80211_xmit(sdata, NULL, skb); |
3243 | local_bh_enable(); | 3289 | local_bh_enable(); |
3244 | } | 3290 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 747bdcf72e92..d1742a7d9ea4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -625,13 +625,14 @@ void ieee80211_wake_vif_queues(struct ieee80211_local *local, | |||
625 | reason, true); | 625 | reason, true); |
626 | } | 626 | } |
627 | 627 | ||
628 | static void __iterate_active_interfaces(struct ieee80211_local *local, | 628 | static void __iterate_interfaces(struct ieee80211_local *local, |
629 | u32 iter_flags, | 629 | u32 iter_flags, |
630 | void (*iterator)(void *data, u8 *mac, | 630 | void (*iterator)(void *data, u8 *mac, |
631 | struct ieee80211_vif *vif), | 631 | struct ieee80211_vif *vif), |
632 | void *data) | 632 | void *data) |
633 | { | 633 | { |
634 | struct ieee80211_sub_if_data *sdata; | 634 | struct ieee80211_sub_if_data *sdata; |
635 | bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE; | ||
635 | 636 | ||
636 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 637 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
637 | switch (sdata->vif.type) { | 638 | switch (sdata->vif.type) { |
@@ -645,9 +646,9 @@ static void __iterate_active_interfaces(struct ieee80211_local *local, | |||
645 | break; | 646 | break; |
646 | } | 647 | } |
647 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && | 648 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && |
648 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | 649 | active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) |
649 | continue; | 650 | continue; |
650 | if (ieee80211_sdata_running(sdata)) | 651 | if (ieee80211_sdata_running(sdata) || !active_only) |
651 | iterator(data, sdata->vif.addr, | 652 | iterator(data, sdata->vif.addr, |
652 | &sdata->vif); | 653 | &sdata->vif); |
653 | } | 654 | } |
@@ -656,12 +657,12 @@ static void __iterate_active_interfaces(struct ieee80211_local *local, | |||
656 | lockdep_is_held(&local->iflist_mtx) || | 657 | lockdep_is_held(&local->iflist_mtx) || |
657 | lockdep_rtnl_is_held()); | 658 | lockdep_rtnl_is_held()); |
658 | if (sdata && | 659 | if (sdata && |
659 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | 660 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only || |
660 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | 661 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) |
661 | iterator(data, sdata->vif.addr, &sdata->vif); | 662 | iterator(data, sdata->vif.addr, &sdata->vif); |
662 | } | 663 | } |
663 | 664 | ||
664 | void ieee80211_iterate_active_interfaces( | 665 | void ieee80211_iterate_interfaces( |
665 | struct ieee80211_hw *hw, u32 iter_flags, | 666 | struct ieee80211_hw *hw, u32 iter_flags, |
666 | void (*iterator)(void *data, u8 *mac, | 667 | void (*iterator)(void *data, u8 *mac, |
667 | struct ieee80211_vif *vif), | 668 | struct ieee80211_vif *vif), |
@@ -670,10 +671,10 @@ void ieee80211_iterate_active_interfaces( | |||
670 | struct ieee80211_local *local = hw_to_local(hw); | 671 | struct ieee80211_local *local = hw_to_local(hw); |
671 | 672 | ||
672 | mutex_lock(&local->iflist_mtx); | 673 | mutex_lock(&local->iflist_mtx); |
673 | __iterate_active_interfaces(local, iter_flags, iterator, data); | 674 | __iterate_interfaces(local, iter_flags, iterator, data); |
674 | mutex_unlock(&local->iflist_mtx); | 675 | mutex_unlock(&local->iflist_mtx); |
675 | } | 676 | } |
676 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 677 | EXPORT_SYMBOL_GPL(ieee80211_iterate_interfaces); |
677 | 678 | ||
678 | void ieee80211_iterate_active_interfaces_atomic( | 679 | void ieee80211_iterate_active_interfaces_atomic( |
679 | struct ieee80211_hw *hw, u32 iter_flags, | 680 | struct ieee80211_hw *hw, u32 iter_flags, |
@@ -684,7 +685,8 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
684 | struct ieee80211_local *local = hw_to_local(hw); | 685 | struct ieee80211_local *local = hw_to_local(hw); |
685 | 686 | ||
686 | rcu_read_lock(); | 687 | rcu_read_lock(); |
687 | __iterate_active_interfaces(local, iter_flags, iterator, data); | 688 | __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE, |
689 | iterator, data); | ||
688 | rcu_read_unlock(); | 690 | rcu_read_unlock(); |
689 | } | 691 | } |
690 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | 692 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); |
@@ -699,7 +701,8 @@ void ieee80211_iterate_active_interfaces_rtnl( | |||
699 | 701 | ||
700 | ASSERT_RTNL(); | 702 | ASSERT_RTNL(); |
701 | 703 | ||
702 | __iterate_active_interfaces(local, iter_flags, iterator, data); | 704 | __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE, |
705 | iterator, data); | ||
703 | } | 706 | } |
704 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); | 707 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); |
705 | 708 | ||
@@ -742,6 +745,18 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) | |||
742 | } | 745 | } |
743 | EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif); | 746 | EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif); |
744 | 747 | ||
748 | struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif) | ||
749 | { | ||
750 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
751 | |||
752 | if (!ieee80211_sdata_running(sdata) || | ||
753 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
754 | return NULL; | ||
755 | |||
756 | return &sdata->wdev; | ||
757 | } | ||
758 | EXPORT_SYMBOL_GPL(ieee80211_vif_to_wdev); | ||
759 | |||
745 | /* | 760 | /* |
746 | * Nothing should have been stuffed into the workqueue during | 761 | * Nothing should have been stuffed into the workqueue during |
747 | * the suspend->resume cycle. Since we can't check each caller | 762 | * the suspend->resume cycle. Since we can't check each caller |
@@ -1811,8 +1826,25 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1811 | list_for_each_entry(sdata, &local->interfaces, list) { | 1826 | list_for_each_entry(sdata, &local->interfaces, list) { |
1812 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 1827 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
1813 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 1828 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
1814 | ieee80211_sdata_running(sdata)) | 1829 | ieee80211_sdata_running(sdata)) { |
1815 | res = drv_add_interface(local, sdata); | 1830 | res = drv_add_interface(local, sdata); |
1831 | if (WARN_ON(res)) | ||
1832 | break; | ||
1833 | } | ||
1834 | } | ||
1835 | |||
1836 | /* If adding any of the interfaces failed above, roll back and | ||
1837 | * report failure. | ||
1838 | */ | ||
1839 | if (res) { | ||
1840 | list_for_each_entry_continue_reverse(sdata, &local->interfaces, | ||
1841 | list) | ||
1842 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
1843 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
1844 | ieee80211_sdata_running(sdata)) | ||
1845 | drv_remove_interface(local, sdata); | ||
1846 | ieee80211_handle_reconfig_failure(local); | ||
1847 | return res; | ||
1816 | } | 1848 | } |
1817 | 1849 | ||
1818 | /* add channel contexts */ | 1850 | /* add channel contexts */ |
@@ -2344,6 +2376,41 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
2344 | return pos + sizeof(struct ieee80211_ht_operation); | 2376 | return pos + sizeof(struct ieee80211_ht_operation); |
2345 | } | 2377 | } |
2346 | 2378 | ||
2379 | u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | ||
2380 | const struct cfg80211_chan_def *chandef) | ||
2381 | { | ||
2382 | struct ieee80211_vht_operation *vht_oper; | ||
2383 | |||
2384 | *pos++ = WLAN_EID_VHT_OPERATION; | ||
2385 | *pos++ = sizeof(struct ieee80211_vht_operation); | ||
2386 | vht_oper = (struct ieee80211_vht_operation *)pos; | ||
2387 | vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel( | ||
2388 | chandef->center_freq1); | ||
2389 | if (chandef->center_freq2) | ||
2390 | vht_oper->center_freq_seg2_idx = | ||
2391 | ieee80211_frequency_to_channel(chandef->center_freq2); | ||
2392 | |||
2393 | switch (chandef->width) { | ||
2394 | case NL80211_CHAN_WIDTH_160: | ||
2395 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ; | ||
2396 | break; | ||
2397 | case NL80211_CHAN_WIDTH_80P80: | ||
2398 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ; | ||
2399 | break; | ||
2400 | case NL80211_CHAN_WIDTH_80: | ||
2401 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; | ||
2402 | break; | ||
2403 | default: | ||
2404 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT; | ||
2405 | break; | ||
2406 | } | ||
2407 | |||
2408 | /* don't require special VHT peer rates */ | ||
2409 | vht_oper->basic_mcs_set = cpu_to_le16(0xffff); | ||
2410 | |||
2411 | return pos + sizeof(struct ieee80211_vht_operation); | ||
2412 | } | ||
2413 | |||
2347 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | 2414 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
2348 | const struct ieee80211_ht_operation *ht_oper, | 2415 | const struct ieee80211_ht_operation *ht_oper, |
2349 | struct cfg80211_chan_def *chandef) | 2416 | struct cfg80211_chan_def *chandef) |
@@ -2373,6 +2440,39 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | |||
2373 | cfg80211_chandef_create(chandef, control_chan, channel_type); | 2440 | cfg80211_chandef_create(chandef, control_chan, channel_type); |
2374 | } | 2441 | } |
2375 | 2442 | ||
2443 | void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan, | ||
2444 | const struct ieee80211_vht_operation *oper, | ||
2445 | struct cfg80211_chan_def *chandef) | ||
2446 | { | ||
2447 | if (!oper) | ||
2448 | return; | ||
2449 | |||
2450 | chandef->chan = control_chan; | ||
2451 | |||
2452 | switch (oper->chan_width) { | ||
2453 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
2454 | break; | ||
2455 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
2456 | chandef->width = NL80211_CHAN_WIDTH_80; | ||
2457 | break; | ||
2458 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
2459 | chandef->width = NL80211_CHAN_WIDTH_160; | ||
2460 | break; | ||
2461 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
2462 | chandef->width = NL80211_CHAN_WIDTH_80P80; | ||
2463 | break; | ||
2464 | default: | ||
2465 | break; | ||
2466 | } | ||
2467 | |||
2468 | chandef->center_freq1 = | ||
2469 | ieee80211_channel_to_frequency(oper->center_freq_seg1_idx, | ||
2470 | control_chan->band); | ||
2471 | chandef->center_freq2 = | ||
2472 | ieee80211_channel_to_frequency(oper->center_freq_seg2_idx, | ||
2473 | control_chan->band); | ||
2474 | } | ||
2475 | |||
2376 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, | 2476 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, |
2377 | const struct ieee80211_supported_band *sband, | 2477 | const struct ieee80211_supported_band *sband, |
2378 | const u8 *srates, int srates_len, u32 *rates) | 2478 | const u8 *srates, int srates_len, u32 *rates) |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 85f9596da07b..80694d55db74 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -129,10 +129,6 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
129 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) | 129 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) |
130 | return; | 130 | return; |
131 | 131 | ||
132 | /* don't support VHT for TDLS peers for now */ | ||
133 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
134 | return; | ||
135 | |||
136 | /* | 132 | /* |
137 | * A VHT STA must support 40 MHz, but if we verify that here | 133 | * A VHT STA must support 40 MHz, but if we verify that here |
138 | * then we break a few things - some APs (e.g. Netgear R6300v2 | 134 | * then we break a few things - some APs (e.g. Netgear R6300v2 |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 75de6fac40d1..9d63d93c836e 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -780,9 +780,8 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | |||
780 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 780 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
781 | struct ieee80211_key *key = tx->key; | 781 | struct ieee80211_key *key = tx->key; |
782 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 782 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
783 | const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme; | ||
784 | int hdrlen; | 783 | int hdrlen; |
785 | u8 *pos; | 784 | u8 *pos, iv_len = key->conf.iv_len; |
786 | 785 | ||
787 | if (info->control.hw_key && | 786 | if (info->control.hw_key && |
788 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { | 787 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { |
@@ -790,14 +789,14 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | |||
790 | return TX_CONTINUE; | 789 | return TX_CONTINUE; |
791 | } | 790 | } |
792 | 791 | ||
793 | if (unlikely(skb_headroom(skb) < cs->hdr_len && | 792 | if (unlikely(skb_headroom(skb) < iv_len && |
794 | pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC))) | 793 | pskb_expand_head(skb, iv_len, 0, GFP_ATOMIC))) |
795 | return TX_DROP; | 794 | return TX_DROP; |
796 | 795 | ||
797 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 796 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
798 | 797 | ||
799 | pos = skb_push(skb, cs->hdr_len); | 798 | pos = skb_push(skb, iv_len); |
800 | memmove(pos, pos + cs->hdr_len, hdrlen); | 799 | memmove(pos, pos + iv_len, hdrlen); |
801 | 800 | ||
802 | return TX_CONTINUE; | 801 | return TX_CONTINUE; |
803 | } | 802 | } |
@@ -1217,7 +1216,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
1217 | if (!info->control.hw_key) | 1216 | if (!info->control.hw_key) |
1218 | return TX_DROP; | 1217 | return TX_DROP; |
1219 | 1218 | ||
1220 | if (tx->key->sta->cipher_scheme) { | 1219 | if (tx->key->flags & KEY_FLAG_CIPHER_SCHEME) { |
1221 | res = ieee80211_crypto_cs_encrypt(tx, skb); | 1220 | res = ieee80211_crypto_cs_encrypt(tx, skb); |
1222 | if (res != TX_CONTINUE) | 1221 | if (res != TX_CONTINUE) |
1223 | return res; | 1222 | return res; |
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 29c8675f9a11..b13dfb4ff001 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -178,10 +178,18 @@ config CFG80211_WEXT | |||
178 | bool "cfg80211 wireless extensions compatibility" | 178 | bool "cfg80211 wireless extensions compatibility" |
179 | depends on CFG80211 | 179 | depends on CFG80211 |
180 | select WEXT_CORE | 180 | select WEXT_CORE |
181 | default y if CFG80211_WEXT_EXPORT | ||
181 | help | 182 | help |
182 | Enable this option if you need old userspace for wireless | 183 | Enable this option if you need old userspace for wireless |
183 | extensions with cfg80211-based drivers. | 184 | extensions with cfg80211-based drivers. |
184 | 185 | ||
186 | config CFG80211_WEXT_EXPORT | ||
187 | bool | ||
188 | depends on CFG80211 | ||
189 | help | ||
190 | Drivers should select this option if they require cfg80211's | ||
191 | wext compatibility symbols to be exported. | ||
192 | |||
185 | config LIB80211 | 193 | config LIB80211 |
186 | tristate | 194 | tristate |
187 | default n | 195 | default n |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 6309b9c0bcd5..4c55fab9b4e4 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -30,7 +30,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, | |||
30 | return; | 30 | return; |
31 | 31 | ||
32 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, | 32 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, |
33 | WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); | 33 | IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY); |
34 | 34 | ||
35 | if (WARN_ON(!bss)) | 35 | if (WARN_ON(!bss)) |
36 | return; | 36 | return; |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 2c52b59e43f3..7aae329e2b4e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -229,7 +229,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
229 | return -EALREADY; | 229 | return -EALREADY; |
230 | 230 | ||
231 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 231 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
232 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 232 | IEEE80211_BSS_TYPE_ESS, |
233 | IEEE80211_PRIVACY_ANY); | ||
233 | if (!req.bss) | 234 | if (!req.bss) |
234 | return -ENOENT; | 235 | return -ENOENT; |
235 | 236 | ||
@@ -296,7 +297,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
296 | rdev->wiphy.vht_capa_mod_mask); | 297 | rdev->wiphy.vht_capa_mod_mask); |
297 | 298 | ||
298 | req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 299 | req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
299 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 300 | IEEE80211_BSS_TYPE_ESS, |
301 | IEEE80211_PRIVACY_ANY); | ||
300 | if (!req->bss) | 302 | if (!req->bss) |
301 | return -ENOENT; | 303 | return -ENOENT; |
302 | 304 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2fb804bfa361..6dd1ab3b10ea 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -399,6 +399,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
399 | [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG }, | 399 | [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG }, |
400 | [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 }, | 400 | [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 }, |
401 | [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, | 401 | [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 }, |
402 | [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG }, | ||
402 | }; | 403 | }; |
403 | 404 | ||
404 | /* policy for the key attributes */ | 405 | /* policy for the key attributes */ |
@@ -1098,8 +1099,6 @@ static int nl80211_send_wowlan(struct sk_buff *msg, | |||
1098 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) | 1099 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) |
1099 | return -ENOBUFS; | 1100 | return -ENOBUFS; |
1100 | 1101 | ||
1101 | /* TODO: send wowlan net detect */ | ||
1102 | |||
1103 | nla_nest_end(msg, nl_wowlan); | 1102 | nla_nest_end(msg, nl_wowlan); |
1104 | 1103 | ||
1105 | return 0; | 1104 | return 0; |
@@ -2668,7 +2667,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2668 | 2667 | ||
2669 | wdev = rdev_add_virtual_intf(rdev, | 2668 | wdev = rdev_add_virtual_intf(rdev, |
2670 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 2669 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
2671 | type, err ? NULL : &flags, ¶ms); | 2670 | NET_NAME_USER, type, err ? NULL : &flags, |
2671 | ¶ms); | ||
2672 | if (WARN_ON(!wdev)) { | 2672 | if (WARN_ON(!wdev)) { |
2673 | nlmsg_free(msg); | 2673 | nlmsg_free(msg); |
2674 | return -EPROTO; | 2674 | return -EPROTO; |
@@ -4968,7 +4968,10 @@ static int parse_reg_rule(struct nlattr *tb[], | |||
4968 | static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | 4968 | static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) |
4969 | { | 4969 | { |
4970 | char *data = NULL; | 4970 | char *data = NULL; |
4971 | bool is_indoor; | ||
4971 | enum nl80211_user_reg_hint_type user_reg_hint_type; | 4972 | enum nl80211_user_reg_hint_type user_reg_hint_type; |
4973 | u32 owner_nlportid; | ||
4974 | |||
4972 | 4975 | ||
4973 | /* | 4976 | /* |
4974 | * You should only get this when cfg80211 hasn't yet initialized | 4977 | * You should only get this when cfg80211 hasn't yet initialized |
@@ -4994,7 +4997,15 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
4994 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 4997 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
4995 | return regulatory_hint_user(data, user_reg_hint_type); | 4998 | return regulatory_hint_user(data, user_reg_hint_type); |
4996 | case NL80211_USER_REG_HINT_INDOOR: | 4999 | case NL80211_USER_REG_HINT_INDOOR: |
4997 | return regulatory_hint_indoor_user(); | 5000 | if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) { |
5001 | owner_nlportid = info->snd_portid; | ||
5002 | is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR]; | ||
5003 | } else { | ||
5004 | owner_nlportid = 0; | ||
5005 | is_indoor = true; | ||
5006 | } | ||
5007 | |||
5008 | return regulatory_hint_indoor(is_indoor, owner_nlportid); | ||
4998 | default: | 5009 | default: |
4999 | return -EINVAL; | 5010 | return -EINVAL; |
5000 | } | 5011 | } |
@@ -5275,7 +5286,7 @@ do { \ | |||
5275 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, | 5286 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration, |
5276 | 0, 65535, mask, | 5287 | 0, 65535, mask, |
5277 | NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16); | 5288 | NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16); |
5278 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff, | 5289 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff, |
5279 | mask, NL80211_MESHCONF_PLINK_TIMEOUT, | 5290 | mask, NL80211_MESHCONF_PLINK_TIMEOUT, |
5280 | nla_get_u32); | 5291 | nla_get_u32); |
5281 | if (mask_out) | 5292 | if (mask_out) |
@@ -7275,8 +7286,18 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
7275 | break; | 7286 | break; |
7276 | case NL80211_CHAN_WIDTH_20: | 7287 | case NL80211_CHAN_WIDTH_20: |
7277 | case NL80211_CHAN_WIDTH_40: | 7288 | case NL80211_CHAN_WIDTH_40: |
7278 | if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS) | 7289 | if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) |
7279 | break; | 7290 | return -EINVAL; |
7291 | break; | ||
7292 | case NL80211_CHAN_WIDTH_80: | ||
7293 | case NL80211_CHAN_WIDTH_80P80: | ||
7294 | case NL80211_CHAN_WIDTH_160: | ||
7295 | if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) | ||
7296 | return -EINVAL; | ||
7297 | if (!wiphy_ext_feature_isset(&rdev->wiphy, | ||
7298 | NL80211_EXT_FEATURE_VHT_IBSS)) | ||
7299 | return -EINVAL; | ||
7300 | break; | ||
7280 | default: | 7301 | default: |
7281 | return -EINVAL; | 7302 | return -EINVAL; |
7282 | } | 7303 | } |
@@ -7389,8 +7410,8 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) | |||
7389 | 7410 | ||
7390 | static struct sk_buff * | 7411 | static struct sk_buff * |
7391 | __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, | 7412 | __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, |
7392 | int approxlen, u32 portid, u32 seq, | 7413 | struct wireless_dev *wdev, int approxlen, |
7393 | enum nl80211_commands cmd, | 7414 | u32 portid, u32 seq, enum nl80211_commands cmd, |
7394 | enum nl80211_attrs attr, | 7415 | enum nl80211_attrs attr, |
7395 | const struct nl80211_vendor_cmd_info *info, | 7416 | const struct nl80211_vendor_cmd_info *info, |
7396 | gfp_t gfp) | 7417 | gfp_t gfp) |
@@ -7421,6 +7442,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, | |||
7421 | goto nla_put_failure; | 7442 | goto nla_put_failure; |
7422 | } | 7443 | } |
7423 | 7444 | ||
7445 | if (wdev) { | ||
7446 | if (nla_put_u64(skb, NL80211_ATTR_WDEV, | ||
7447 | wdev_id(wdev))) | ||
7448 | goto nla_put_failure; | ||
7449 | if (wdev->netdev && | ||
7450 | nla_put_u32(skb, NL80211_ATTR_IFINDEX, | ||
7451 | wdev->netdev->ifindex)) | ||
7452 | goto nla_put_failure; | ||
7453 | } | ||
7454 | |||
7424 | data = nla_nest_start(skb, attr); | 7455 | data = nla_nest_start(skb, attr); |
7425 | 7456 | ||
7426 | ((void **)skb->cb)[0] = rdev; | 7457 | ((void **)skb->cb)[0] = rdev; |
@@ -7435,6 +7466,7 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, | |||
7435 | } | 7466 | } |
7436 | 7467 | ||
7437 | struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, | 7468 | struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, |
7469 | struct wireless_dev *wdev, | ||
7438 | enum nl80211_commands cmd, | 7470 | enum nl80211_commands cmd, |
7439 | enum nl80211_attrs attr, | 7471 | enum nl80211_attrs attr, |
7440 | int vendor_event_idx, | 7472 | int vendor_event_idx, |
@@ -7460,7 +7492,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, | |||
7460 | return NULL; | 7492 | return NULL; |
7461 | } | 7493 | } |
7462 | 7494 | ||
7463 | return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0, | 7495 | return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0, |
7464 | cmd, attr, info, gfp); | 7496 | cmd, attr, info, gfp); |
7465 | } | 7497 | } |
7466 | EXPORT_SYMBOL(__cfg80211_alloc_event_skb); | 7498 | EXPORT_SYMBOL(__cfg80211_alloc_event_skb); |
@@ -8808,6 +8840,9 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg, | |||
8808 | if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval)) | 8840 | if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval)) |
8809 | return -ENOBUFS; | 8841 | return -ENOBUFS; |
8810 | 8842 | ||
8843 | if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay)) | ||
8844 | return -ENOBUFS; | ||
8845 | |||
8811 | freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); | 8846 | freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); |
8812 | if (!freqs) | 8847 | if (!freqs) |
8813 | return -ENOBUFS; | 8848 | return -ENOBUFS; |
@@ -9094,6 +9129,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
9094 | const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan; | 9129 | const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan; |
9095 | int err, i; | 9130 | int err, i; |
9096 | bool prev_enabled = rdev->wiphy.wowlan_config; | 9131 | bool prev_enabled = rdev->wiphy.wowlan_config; |
9132 | bool regular = false; | ||
9097 | 9133 | ||
9098 | if (!wowlan) | 9134 | if (!wowlan) |
9099 | return -EOPNOTSUPP; | 9135 | return -EOPNOTSUPP; |
@@ -9121,12 +9157,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
9121 | if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT)) | 9157 | if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT)) |
9122 | return -EINVAL; | 9158 | return -EINVAL; |
9123 | new_triggers.disconnect = true; | 9159 | new_triggers.disconnect = true; |
9160 | regular = true; | ||
9124 | } | 9161 | } |
9125 | 9162 | ||
9126 | if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) { | 9163 | if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) { |
9127 | if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT)) | 9164 | if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT)) |
9128 | return -EINVAL; | 9165 | return -EINVAL; |
9129 | new_triggers.magic_pkt = true; | 9166 | new_triggers.magic_pkt = true; |
9167 | regular = true; | ||
9130 | } | 9168 | } |
9131 | 9169 | ||
9132 | if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) | 9170 | if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) |
@@ -9136,24 +9174,28 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
9136 | if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE)) | 9174 | if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE)) |
9137 | return -EINVAL; | 9175 | return -EINVAL; |
9138 | new_triggers.gtk_rekey_failure = true; | 9176 | new_triggers.gtk_rekey_failure = true; |
9177 | regular = true; | ||
9139 | } | 9178 | } |
9140 | 9179 | ||
9141 | if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) { | 9180 | if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) { |
9142 | if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ)) | 9181 | if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ)) |
9143 | return -EINVAL; | 9182 | return -EINVAL; |
9144 | new_triggers.eap_identity_req = true; | 9183 | new_triggers.eap_identity_req = true; |
9184 | regular = true; | ||
9145 | } | 9185 | } |
9146 | 9186 | ||
9147 | if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) { | 9187 | if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) { |
9148 | if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE)) | 9188 | if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE)) |
9149 | return -EINVAL; | 9189 | return -EINVAL; |
9150 | new_triggers.four_way_handshake = true; | 9190 | new_triggers.four_way_handshake = true; |
9191 | regular = true; | ||
9151 | } | 9192 | } |
9152 | 9193 | ||
9153 | if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) { | 9194 | if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) { |
9154 | if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE)) | 9195 | if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE)) |
9155 | return -EINVAL; | 9196 | return -EINVAL; |
9156 | new_triggers.rfkill_release = true; | 9197 | new_triggers.rfkill_release = true; |
9198 | regular = true; | ||
9157 | } | 9199 | } |
9158 | 9200 | ||
9159 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { | 9201 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { |
@@ -9162,6 +9204,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
9162 | int rem, pat_len, mask_len, pkt_offset; | 9204 | int rem, pat_len, mask_len, pkt_offset; |
9163 | struct nlattr *pat_tb[NUM_NL80211_PKTPAT]; | 9205 | struct nlattr *pat_tb[NUM_NL80211_PKTPAT]; |
9164 | 9206 | ||
9207 | regular = true; | ||
9208 | |||
9165 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | 9209 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], |
9166 | rem) | 9210 | rem) |
9167 | n_patterns++; | 9211 | n_patterns++; |
@@ -9223,6 +9267,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
9223 | } | 9267 | } |
9224 | 9268 | ||
9225 | if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) { | 9269 | if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) { |
9270 | regular = true; | ||
9226 | err = nl80211_parse_wowlan_tcp( | 9271 | err = nl80211_parse_wowlan_tcp( |
9227 | rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION], | 9272 | rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION], |
9228 | &new_triggers); | 9273 | &new_triggers); |
@@ -9231,6 +9276,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
9231 | } | 9276 | } |
9232 | 9277 | ||
9233 | if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) { | 9278 | if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) { |
9279 | regular = true; | ||
9234 | err = nl80211_parse_wowlan_nd( | 9280 | err = nl80211_parse_wowlan_nd( |
9235 | rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT], | 9281 | rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT], |
9236 | &new_triggers); | 9282 | &new_triggers); |
@@ -9238,6 +9284,17 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
9238 | goto error; | 9284 | goto error; |
9239 | } | 9285 | } |
9240 | 9286 | ||
9287 | /* The 'any' trigger means the device continues operating more or less | ||
9288 | * as in its normal operation mode and wakes up the host on most of the | ||
9289 | * normal interrupts (like packet RX, ...) | ||
9290 | * It therefore makes little sense to combine with the more constrained | ||
9291 | * wakeup trigger modes. | ||
9292 | */ | ||
9293 | if (new_triggers.any && regular) { | ||
9294 | err = -EINVAL; | ||
9295 | goto error; | ||
9296 | } | ||
9297 | |||
9241 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); | 9298 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
9242 | if (!ntrig) { | 9299 | if (!ntrig) { |
9243 | err = -ENOMEM; | 9300 | err = -ENOMEM; |
@@ -9906,7 +9963,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy, | |||
9906 | if (WARN_ON(!rdev->cur_cmd_info)) | 9963 | if (WARN_ON(!rdev->cur_cmd_info)) |
9907 | return NULL; | 9964 | return NULL; |
9908 | 9965 | ||
9909 | return __cfg80211_alloc_vendor_skb(rdev, approxlen, | 9966 | return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen, |
9910 | rdev->cur_cmd_info->snd_portid, | 9967 | rdev->cur_cmd_info->snd_portid, |
9911 | rdev->cur_cmd_info->snd_seq, | 9968 | rdev->cur_cmd_info->snd_seq, |
9912 | cmd, attr, NULL, GFP_KERNEL); | 9969 | cmd, attr, NULL, GFP_KERNEL); |
@@ -12775,6 +12832,11 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
12775 | 12832 | ||
12776 | rcu_read_unlock(); | 12833 | rcu_read_unlock(); |
12777 | 12834 | ||
12835 | /* | ||
12836 | * It is possible that the user space process that is controlling the | ||
12837 | * indoor setting disappeared, so notify the regulatory core. | ||
12838 | */ | ||
12839 | regulatory_netlink_notify(notify->portid); | ||
12778 | return NOTIFY_OK; | 12840 | return NOTIFY_OK; |
12779 | } | 12841 | } |
12780 | 12842 | ||
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 35cfb7134bdb..c6e83a7468c0 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -35,13 +35,14 @@ static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev, | |||
35 | 35 | ||
36 | static inline struct wireless_dev | 36 | static inline struct wireless_dev |
37 | *rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name, | 37 | *rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name, |
38 | unsigned char name_assign_type, | ||
38 | enum nl80211_iftype type, u32 *flags, | 39 | enum nl80211_iftype type, u32 *flags, |
39 | struct vif_params *params) | 40 | struct vif_params *params) |
40 | { | 41 | { |
41 | struct wireless_dev *ret; | 42 | struct wireless_dev *ret; |
42 | trace_rdev_add_virtual_intf(&rdev->wiphy, name, type); | 43 | trace_rdev_add_virtual_intf(&rdev->wiphy, name, type); |
43 | ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, type, flags, | 44 | ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, name_assign_type, |
44 | params); | 45 | type, flags, params); |
45 | trace_rdev_return_wdev(&rdev->wiphy, ret); | 46 | trace_rdev_return_wdev(&rdev->wiphy, ret); |
46 | return ret; | 47 | return ret; |
47 | } | 48 | } |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 48dfc7b4e981..be5f81caa488 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -82,17 +82,12 @@ | |||
82 | * be intersected with the current one. | 82 | * be intersected with the current one. |
83 | * @REG_REQ_ALREADY_SET: the regulatory request will not change the current | 83 | * @REG_REQ_ALREADY_SET: the regulatory request will not change the current |
84 | * regulatory settings, and no further processing is required. | 84 | * regulatory settings, and no further processing is required. |
85 | * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no | ||
86 | * further processing is required, i.e., not need to update last_request | ||
87 | * etc. This should be used for user hints that do not provide an alpha2 | ||
88 | * but some other type of regulatory hint, i.e., indoor operation. | ||
89 | */ | 85 | */ |
90 | enum reg_request_treatment { | 86 | enum reg_request_treatment { |
91 | REG_REQ_OK, | 87 | REG_REQ_OK, |
92 | REG_REQ_IGNORE, | 88 | REG_REQ_IGNORE, |
93 | REG_REQ_INTERSECT, | 89 | REG_REQ_INTERSECT, |
94 | REG_REQ_ALREADY_SET, | 90 | REG_REQ_ALREADY_SET, |
95 | REG_REQ_USER_HINT_HANDLED, | ||
96 | }; | 91 | }; |
97 | 92 | ||
98 | static struct regulatory_request core_request_world = { | 93 | static struct regulatory_request core_request_world = { |
@@ -133,9 +128,12 @@ static int reg_num_devs_support_basehint; | |||
133 | * State variable indicating if the platform on which the devices | 128 | * State variable indicating if the platform on which the devices |
134 | * are attached is operating in an indoor environment. The state variable | 129 | * are attached is operating in an indoor environment. The state variable |
135 | * is relevant for all registered devices. | 130 | * is relevant for all registered devices. |
136 | * (protected by RTNL) | ||
137 | */ | 131 | */ |
138 | static bool reg_is_indoor; | 132 | static bool reg_is_indoor; |
133 | static spinlock_t reg_indoor_lock; | ||
134 | |||
135 | /* Used to track the userspace process controlling the indoor setting */ | ||
136 | static u32 reg_is_indoor_portid; | ||
139 | 137 | ||
140 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) | 138 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) |
141 | { | 139 | { |
@@ -554,6 +552,9 @@ reg_call_crda(struct regulatory_request *request) | |||
554 | { | 552 | { |
555 | if (call_crda(request->alpha2)) | 553 | if (call_crda(request->alpha2)) |
556 | return REG_REQ_IGNORE; | 554 | return REG_REQ_IGNORE; |
555 | |||
556 | queue_delayed_work(system_power_efficient_wq, | ||
557 | ®_timeout, msecs_to_jiffies(3142)); | ||
557 | return REG_REQ_OK; | 558 | return REG_REQ_OK; |
558 | } | 559 | } |
559 | 560 | ||
@@ -1248,13 +1249,6 @@ static bool reg_request_cell_base(struct regulatory_request *request) | |||
1248 | return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; | 1249 | return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; |
1249 | } | 1250 | } |
1250 | 1251 | ||
1251 | static bool reg_request_indoor(struct regulatory_request *request) | ||
1252 | { | ||
1253 | if (request->initiator != NL80211_REGDOM_SET_BY_USER) | ||
1254 | return false; | ||
1255 | return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR; | ||
1256 | } | ||
1257 | |||
1258 | bool reg_last_request_cell_base(void) | 1252 | bool reg_last_request_cell_base(void) |
1259 | { | 1253 | { |
1260 | return reg_request_cell_base(get_last_request()); | 1254 | return reg_request_cell_base(get_last_request()); |
@@ -1800,8 +1794,7 @@ static void reg_set_request_processed(void) | |||
1800 | need_more_processing = true; | 1794 | need_more_processing = true; |
1801 | spin_unlock(®_requests_lock); | 1795 | spin_unlock(®_requests_lock); |
1802 | 1796 | ||
1803 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER) | 1797 | cancel_delayed_work(®_timeout); |
1804 | cancel_delayed_work(®_timeout); | ||
1805 | 1798 | ||
1806 | if (need_more_processing) | 1799 | if (need_more_processing) |
1807 | schedule_work(®_work); | 1800 | schedule_work(®_work); |
@@ -1833,11 +1826,6 @@ __reg_process_hint_user(struct regulatory_request *user_request) | |||
1833 | { | 1826 | { |
1834 | struct regulatory_request *lr = get_last_request(); | 1827 | struct regulatory_request *lr = get_last_request(); |
1835 | 1828 | ||
1836 | if (reg_request_indoor(user_request)) { | ||
1837 | reg_is_indoor = true; | ||
1838 | return REG_REQ_USER_HINT_HANDLED; | ||
1839 | } | ||
1840 | |||
1841 | if (reg_request_cell_base(user_request)) | 1829 | if (reg_request_cell_base(user_request)) |
1842 | return reg_ignore_cell_hint(user_request); | 1830 | return reg_ignore_cell_hint(user_request); |
1843 | 1831 | ||
@@ -1885,8 +1873,7 @@ reg_process_hint_user(struct regulatory_request *user_request) | |||
1885 | 1873 | ||
1886 | treatment = __reg_process_hint_user(user_request); | 1874 | treatment = __reg_process_hint_user(user_request); |
1887 | if (treatment == REG_REQ_IGNORE || | 1875 | if (treatment == REG_REQ_IGNORE || |
1888 | treatment == REG_REQ_ALREADY_SET || | 1876 | treatment == REG_REQ_ALREADY_SET) { |
1889 | treatment == REG_REQ_USER_HINT_HANDLED) { | ||
1890 | reg_free_request(user_request); | 1877 | reg_free_request(user_request); |
1891 | return treatment; | 1878 | return treatment; |
1892 | } | 1879 | } |
@@ -1947,7 +1934,6 @@ reg_process_hint_driver(struct wiphy *wiphy, | |||
1947 | case REG_REQ_OK: | 1934 | case REG_REQ_OK: |
1948 | break; | 1935 | break; |
1949 | case REG_REQ_IGNORE: | 1936 | case REG_REQ_IGNORE: |
1950 | case REG_REQ_USER_HINT_HANDLED: | ||
1951 | reg_free_request(driver_request); | 1937 | reg_free_request(driver_request); |
1952 | return treatment; | 1938 | return treatment; |
1953 | case REG_REQ_INTERSECT: | 1939 | case REG_REQ_INTERSECT: |
@@ -2047,7 +2033,6 @@ reg_process_hint_country_ie(struct wiphy *wiphy, | |||
2047 | case REG_REQ_OK: | 2033 | case REG_REQ_OK: |
2048 | break; | 2034 | break; |
2049 | case REG_REQ_IGNORE: | 2035 | case REG_REQ_IGNORE: |
2050 | case REG_REQ_USER_HINT_HANDLED: | ||
2051 | /* fall through */ | 2036 | /* fall through */ |
2052 | case REG_REQ_ALREADY_SET: | 2037 | case REG_REQ_ALREADY_SET: |
2053 | reg_free_request(country_ie_request); | 2038 | reg_free_request(country_ie_request); |
@@ -2086,11 +2071,8 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
2086 | case NL80211_REGDOM_SET_BY_USER: | 2071 | case NL80211_REGDOM_SET_BY_USER: |
2087 | treatment = reg_process_hint_user(reg_request); | 2072 | treatment = reg_process_hint_user(reg_request); |
2088 | if (treatment == REG_REQ_IGNORE || | 2073 | if (treatment == REG_REQ_IGNORE || |
2089 | treatment == REG_REQ_ALREADY_SET || | 2074 | treatment == REG_REQ_ALREADY_SET) |
2090 | treatment == REG_REQ_USER_HINT_HANDLED) | ||
2091 | return; | 2075 | return; |
2092 | queue_delayed_work(system_power_efficient_wq, | ||
2093 | ®_timeout, msecs_to_jiffies(3142)); | ||
2094 | return; | 2076 | return; |
2095 | case NL80211_REGDOM_SET_BY_DRIVER: | 2077 | case NL80211_REGDOM_SET_BY_DRIVER: |
2096 | if (!wiphy) | 2078 | if (!wiphy) |
@@ -2177,6 +2159,13 @@ static void reg_process_pending_hints(void) | |||
2177 | } | 2159 | } |
2178 | 2160 | ||
2179 | reg_process_hint(reg_request); | 2161 | reg_process_hint(reg_request); |
2162 | |||
2163 | lr = get_last_request(); | ||
2164 | |||
2165 | spin_lock(®_requests_lock); | ||
2166 | if (!list_empty(®_requests_list) && lr && lr->processed) | ||
2167 | schedule_work(®_work); | ||
2168 | spin_unlock(®_requests_lock); | ||
2180 | } | 2169 | } |
2181 | 2170 | ||
2182 | /* Processes beacon hints -- this has nothing to do with country IEs */ | 2171 | /* Processes beacon hints -- this has nothing to do with country IEs */ |
@@ -2309,22 +2298,50 @@ int regulatory_hint_user(const char *alpha2, | |||
2309 | return 0; | 2298 | return 0; |
2310 | } | 2299 | } |
2311 | 2300 | ||
2312 | int regulatory_hint_indoor_user(void) | 2301 | int regulatory_hint_indoor(bool is_indoor, u32 portid) |
2313 | { | 2302 | { |
2314 | struct regulatory_request *request; | 2303 | spin_lock(®_indoor_lock); |
2315 | 2304 | ||
2316 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | 2305 | /* It is possible that more than one user space process is trying to |
2317 | if (!request) | 2306 | * configure the indoor setting. To handle such cases, clear the indoor |
2318 | return -ENOMEM; | 2307 | * setting in case that some process does not think that the device |
2308 | * is operating in an indoor environment. In addition, if a user space | ||
2309 | * process indicates that it is controlling the indoor setting, save its | ||
2310 | * portid, i.e., make it the owner. | ||
2311 | */ | ||
2312 | reg_is_indoor = is_indoor; | ||
2313 | if (reg_is_indoor) { | ||
2314 | if (!reg_is_indoor_portid) | ||
2315 | reg_is_indoor_portid = portid; | ||
2316 | } else { | ||
2317 | reg_is_indoor_portid = 0; | ||
2318 | } | ||
2319 | 2319 | ||
2320 | request->wiphy_idx = WIPHY_IDX_INVALID; | 2320 | spin_unlock(®_indoor_lock); |
2321 | request->initiator = NL80211_REGDOM_SET_BY_USER; | 2321 | |
2322 | request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR; | 2322 | if (!is_indoor) |
2323 | queue_regulatory_request(request); | 2323 | reg_check_channels(); |
2324 | 2324 | ||
2325 | return 0; | 2325 | return 0; |
2326 | } | 2326 | } |
2327 | 2327 | ||
2328 | void regulatory_netlink_notify(u32 portid) | ||
2329 | { | ||
2330 | spin_lock(®_indoor_lock); | ||
2331 | |||
2332 | if (reg_is_indoor_portid != portid) { | ||
2333 | spin_unlock(®_indoor_lock); | ||
2334 | return; | ||
2335 | } | ||
2336 | |||
2337 | reg_is_indoor = false; | ||
2338 | reg_is_indoor_portid = 0; | ||
2339 | |||
2340 | spin_unlock(®_indoor_lock); | ||
2341 | |||
2342 | reg_check_channels(); | ||
2343 | } | ||
2344 | |||
2328 | /* Driver hints */ | 2345 | /* Driver hints */ |
2329 | int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | 2346 | int regulatory_hint(struct wiphy *wiphy, const char *alpha2) |
2330 | { | 2347 | { |
@@ -2486,13 +2503,22 @@ static void restore_regulatory_settings(bool reset_user) | |||
2486 | char alpha2[2]; | 2503 | char alpha2[2]; |
2487 | char world_alpha2[2]; | 2504 | char world_alpha2[2]; |
2488 | struct reg_beacon *reg_beacon, *btmp; | 2505 | struct reg_beacon *reg_beacon, *btmp; |
2489 | struct regulatory_request *reg_request, *tmp; | ||
2490 | LIST_HEAD(tmp_reg_req_list); | 2506 | LIST_HEAD(tmp_reg_req_list); |
2491 | struct cfg80211_registered_device *rdev; | 2507 | struct cfg80211_registered_device *rdev; |
2492 | 2508 | ||
2493 | ASSERT_RTNL(); | 2509 | ASSERT_RTNL(); |
2494 | 2510 | ||
2495 | reg_is_indoor = false; | 2511 | /* |
2512 | * Clear the indoor setting in case that it is not controlled by user | ||
2513 | * space, as otherwise there is no guarantee that the device is still | ||
2514 | * operating in an indoor environment. | ||
2515 | */ | ||
2516 | spin_lock(®_indoor_lock); | ||
2517 | if (reg_is_indoor && !reg_is_indoor_portid) { | ||
2518 | reg_is_indoor = false; | ||
2519 | reg_check_channels(); | ||
2520 | } | ||
2521 | spin_unlock(®_indoor_lock); | ||
2496 | 2522 | ||
2497 | reset_regdomains(true, &world_regdom); | 2523 | reset_regdomains(true, &world_regdom); |
2498 | restore_alpha2(alpha2, reset_user); | 2524 | restore_alpha2(alpha2, reset_user); |
@@ -2504,11 +2530,7 @@ static void restore_regulatory_settings(bool reset_user) | |||
2504 | * settings. | 2530 | * settings. |
2505 | */ | 2531 | */ |
2506 | spin_lock(®_requests_lock); | 2532 | spin_lock(®_requests_lock); |
2507 | list_for_each_entry_safe(reg_request, tmp, ®_requests_list, list) { | 2533 | list_splice_tail_init(®_requests_list, &tmp_reg_req_list); |
2508 | if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER) | ||
2509 | continue; | ||
2510 | list_move_tail(®_request->list, &tmp_reg_req_list); | ||
2511 | } | ||
2512 | spin_unlock(®_requests_lock); | 2534 | spin_unlock(®_requests_lock); |
2513 | 2535 | ||
2514 | /* Clear beacon hints */ | 2536 | /* Clear beacon hints */ |
@@ -3089,6 +3111,7 @@ int __init regulatory_init(void) | |||
3089 | 3111 | ||
3090 | spin_lock_init(®_requests_lock); | 3112 | spin_lock_init(®_requests_lock); |
3091 | spin_lock_init(®_pending_beacons_lock); | 3113 | spin_lock_init(®_pending_beacons_lock); |
3114 | spin_lock_init(®_indoor_lock); | ||
3092 | 3115 | ||
3093 | reg_regdb_size_check(); | 3116 | reg_regdb_size_check(); |
3094 | 3117 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 4b45d6e61d24..a2c4e16459da 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -25,7 +25,20 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy); | |||
25 | 25 | ||
26 | int regulatory_hint_user(const char *alpha2, | 26 | int regulatory_hint_user(const char *alpha2, |
27 | enum nl80211_user_reg_hint_type user_reg_hint_type); | 27 | enum nl80211_user_reg_hint_type user_reg_hint_type); |
28 | int regulatory_hint_indoor_user(void); | 28 | |
29 | /** | ||
30 | * regulatory_hint_indoor - hint operation in indoor env. or not | ||
31 | * @is_indoor: if true indicates that user space thinks that the | ||
32 | * device is operating in an indoor environment. | ||
33 | * @portid: the netlink port ID on which the hint was given. | ||
34 | */ | ||
35 | int regulatory_hint_indoor(bool is_indoor, u32 portid); | ||
36 | |||
37 | /** | ||
38 | * regulatory_netlink_notify - notify on released netlink socket | ||
39 | * @portid: the netlink socket port ID | ||
40 | */ | ||
41 | void regulatory_netlink_notify(u32 portid); | ||
29 | 42 | ||
30 | void wiphy_regulatory_register(struct wiphy *wiphy); | 43 | void wiphy_regulatory_register(struct wiphy *wiphy); |
31 | void wiphy_regulatory_deregister(struct wiphy *wiphy); | 44 | void wiphy_regulatory_deregister(struct wiphy *wiphy); |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index c705c3e2b751..3a50aa2553bf 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -531,24 +531,78 @@ static int cmp_bss(struct cfg80211_bss *a, | |||
531 | } | 531 | } |
532 | } | 532 | } |
533 | 533 | ||
534 | static bool cfg80211_bss_type_match(u16 capability, | ||
535 | enum ieee80211_band band, | ||
536 | enum ieee80211_bss_type bss_type) | ||
537 | { | ||
538 | bool ret = true; | ||
539 | u16 mask, val; | ||
540 | |||
541 | if (bss_type == IEEE80211_BSS_TYPE_ANY) | ||
542 | return ret; | ||
543 | |||
544 | if (band == IEEE80211_BAND_60GHZ) { | ||
545 | mask = WLAN_CAPABILITY_DMG_TYPE_MASK; | ||
546 | switch (bss_type) { | ||
547 | case IEEE80211_BSS_TYPE_ESS: | ||
548 | val = WLAN_CAPABILITY_DMG_TYPE_AP; | ||
549 | break; | ||
550 | case IEEE80211_BSS_TYPE_PBSS: | ||
551 | val = WLAN_CAPABILITY_DMG_TYPE_PBSS; | ||
552 | break; | ||
553 | case IEEE80211_BSS_TYPE_IBSS: | ||
554 | val = WLAN_CAPABILITY_DMG_TYPE_IBSS; | ||
555 | break; | ||
556 | default: | ||
557 | return false; | ||
558 | } | ||
559 | } else { | ||
560 | mask = WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS; | ||
561 | switch (bss_type) { | ||
562 | case IEEE80211_BSS_TYPE_ESS: | ||
563 | val = WLAN_CAPABILITY_ESS; | ||
564 | break; | ||
565 | case IEEE80211_BSS_TYPE_IBSS: | ||
566 | val = WLAN_CAPABILITY_IBSS; | ||
567 | break; | ||
568 | case IEEE80211_BSS_TYPE_MBSS: | ||
569 | val = 0; | ||
570 | break; | ||
571 | default: | ||
572 | return false; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | ret = ((capability & mask) == val); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
534 | /* Returned bss is reference counted and must be cleaned up appropriately. */ | 580 | /* Returned bss is reference counted and must be cleaned up appropriately. */ |
535 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | 581 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, |
536 | struct ieee80211_channel *channel, | 582 | struct ieee80211_channel *channel, |
537 | const u8 *bssid, | 583 | const u8 *bssid, |
538 | const u8 *ssid, size_t ssid_len, | 584 | const u8 *ssid, size_t ssid_len, |
539 | u16 capa_mask, u16 capa_val) | 585 | enum ieee80211_bss_type bss_type, |
586 | enum ieee80211_privacy privacy) | ||
540 | { | 587 | { |
541 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 588 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
542 | struct cfg80211_internal_bss *bss, *res = NULL; | 589 | struct cfg80211_internal_bss *bss, *res = NULL; |
543 | unsigned long now = jiffies; | 590 | unsigned long now = jiffies; |
591 | int bss_privacy; | ||
544 | 592 | ||
545 | trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask, | 593 | trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, bss_type, |
546 | capa_val); | 594 | privacy); |
547 | 595 | ||
548 | spin_lock_bh(&rdev->bss_lock); | 596 | spin_lock_bh(&rdev->bss_lock); |
549 | 597 | ||
550 | list_for_each_entry(bss, &rdev->bss_list, list) { | 598 | list_for_each_entry(bss, &rdev->bss_list, list) { |
551 | if ((bss->pub.capability & capa_mask) != capa_val) | 599 | if (!cfg80211_bss_type_match(bss->pub.capability, |
600 | bss->pub.channel->band, bss_type)) | ||
601 | continue; | ||
602 | |||
603 | bss_privacy = (bss->pub.capability & WLAN_CAPABILITY_PRIVACY); | ||
604 | if ((privacy == IEEE80211_PRIVACY_ON && !bss_privacy) || | ||
605 | (privacy == IEEE80211_PRIVACY_OFF && bss_privacy)) | ||
552 | continue; | 606 | continue; |
553 | if (channel && bss->pub.channel != channel) | 607 | if (channel && bss->pub.channel != channel) |
554 | continue; | 608 | continue; |
@@ -896,6 +950,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, | |||
896 | struct cfg80211_bss_ies *ies; | 950 | struct cfg80211_bss_ies *ies; |
897 | struct ieee80211_channel *channel; | 951 | struct ieee80211_channel *channel; |
898 | struct cfg80211_internal_bss tmp = {}, *res; | 952 | struct cfg80211_internal_bss tmp = {}, *res; |
953 | int bss_type; | ||
899 | bool signal_valid; | 954 | bool signal_valid; |
900 | 955 | ||
901 | if (WARN_ON(!wiphy)) | 956 | if (WARN_ON(!wiphy)) |
@@ -950,8 +1005,15 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, | |||
950 | if (!res) | 1005 | if (!res) |
951 | return NULL; | 1006 | return NULL; |
952 | 1007 | ||
953 | if (res->pub.capability & WLAN_CAPABILITY_ESS) | 1008 | if (channel->band == IEEE80211_BAND_60GHZ) { |
954 | regulatory_hint_found_beacon(wiphy, channel, gfp); | 1009 | bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK; |
1010 | if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || | ||
1011 | bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) | ||
1012 | regulatory_hint_found_beacon(wiphy, channel, gfp); | ||
1013 | } else { | ||
1014 | if (res->pub.capability & WLAN_CAPABILITY_ESS) | ||
1015 | regulatory_hint_found_beacon(wiphy, channel, gfp); | ||
1016 | } | ||
955 | 1017 | ||
956 | trace_cfg80211_return_bss(&res->pub); | 1018 | trace_cfg80211_return_bss(&res->pub); |
957 | /* cfg80211_bss_update gives us a referenced result */ | 1019 | /* cfg80211_bss_update gives us a referenced result */ |
@@ -973,6 +1035,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, | |||
973 | bool signal_valid; | 1035 | bool signal_valid; |
974 | size_t ielen = len - offsetof(struct ieee80211_mgmt, | 1036 | size_t ielen = len - offsetof(struct ieee80211_mgmt, |
975 | u.probe_resp.variable); | 1037 | u.probe_resp.variable); |
1038 | int bss_type; | ||
976 | 1039 | ||
977 | BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != | 1040 | BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != |
978 | offsetof(struct ieee80211_mgmt, u.beacon.variable)); | 1041 | offsetof(struct ieee80211_mgmt, u.beacon.variable)); |
@@ -1025,8 +1088,15 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, | |||
1025 | if (!res) | 1088 | if (!res) |
1026 | return NULL; | 1089 | return NULL; |
1027 | 1090 | ||
1028 | if (res->pub.capability & WLAN_CAPABILITY_ESS) | 1091 | if (channel->band == IEEE80211_BAND_60GHZ) { |
1029 | regulatory_hint_found_beacon(wiphy, channel, gfp); | 1092 | bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK; |
1093 | if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || | ||
1094 | bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) | ||
1095 | regulatory_hint_found_beacon(wiphy, channel, gfp); | ||
1096 | } else { | ||
1097 | if (res->pub.capability & WLAN_CAPABILITY_ESS) | ||
1098 | regulatory_hint_found_beacon(wiphy, channel, gfp); | ||
1099 | } | ||
1030 | 1100 | ||
1031 | trace_cfg80211_return_bss(&res->pub); | 1101 | trace_cfg80211_return_bss(&res->pub); |
1032 | /* cfg80211_bss_update gives us a referenced result */ | 1102 | /* cfg80211_bss_update gives us a referenced result */ |
@@ -1237,17 +1307,17 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
1237 | kfree(creq); | 1307 | kfree(creq); |
1238 | return err; | 1308 | return err; |
1239 | } | 1309 | } |
1240 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); | 1310 | EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan); |
1241 | 1311 | ||
1242 | static void ieee80211_scan_add_ies(struct iw_request_info *info, | 1312 | static char *ieee80211_scan_add_ies(struct iw_request_info *info, |
1243 | const struct cfg80211_bss_ies *ies, | 1313 | const struct cfg80211_bss_ies *ies, |
1244 | char **current_ev, char *end_buf) | 1314 | char *current_ev, char *end_buf) |
1245 | { | 1315 | { |
1246 | const u8 *pos, *end, *next; | 1316 | const u8 *pos, *end, *next; |
1247 | struct iw_event iwe; | 1317 | struct iw_event iwe; |
1248 | 1318 | ||
1249 | if (!ies) | 1319 | if (!ies) |
1250 | return; | 1320 | return current_ev; |
1251 | 1321 | ||
1252 | /* | 1322 | /* |
1253 | * If needed, fragment the IEs buffer (at IE boundaries) into short | 1323 | * If needed, fragment the IEs buffer (at IE boundaries) into short |
@@ -1264,10 +1334,11 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, | |||
1264 | memset(&iwe, 0, sizeof(iwe)); | 1334 | memset(&iwe, 0, sizeof(iwe)); |
1265 | iwe.cmd = IWEVGENIE; | 1335 | iwe.cmd = IWEVGENIE; |
1266 | iwe.u.data.length = next - pos; | 1336 | iwe.u.data.length = next - pos; |
1267 | *current_ev = iwe_stream_add_point(info, *current_ev, | 1337 | current_ev = iwe_stream_add_point_check(info, current_ev, |
1268 | end_buf, &iwe, | 1338 | end_buf, &iwe, |
1269 | (void *)pos); | 1339 | (void *)pos); |
1270 | 1340 | if (IS_ERR(current_ev)) | |
1341 | return current_ev; | ||
1271 | pos = next; | 1342 | pos = next; |
1272 | } | 1343 | } |
1273 | 1344 | ||
@@ -1275,10 +1346,14 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, | |||
1275 | memset(&iwe, 0, sizeof(iwe)); | 1346 | memset(&iwe, 0, sizeof(iwe)); |
1276 | iwe.cmd = IWEVGENIE; | 1347 | iwe.cmd = IWEVGENIE; |
1277 | iwe.u.data.length = end - pos; | 1348 | iwe.u.data.length = end - pos; |
1278 | *current_ev = iwe_stream_add_point(info, *current_ev, | 1349 | current_ev = iwe_stream_add_point_check(info, current_ev, |
1279 | end_buf, &iwe, | 1350 | end_buf, &iwe, |
1280 | (void *)pos); | 1351 | (void *)pos); |
1352 | if (IS_ERR(current_ev)) | ||
1353 | return current_ev; | ||
1281 | } | 1354 | } |
1355 | |||
1356 | return current_ev; | ||
1282 | } | 1357 | } |
1283 | 1358 | ||
1284 | static char * | 1359 | static char * |
@@ -1289,7 +1364,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | |||
1289 | const struct cfg80211_bss_ies *ies; | 1364 | const struct cfg80211_bss_ies *ies; |
1290 | struct iw_event iwe; | 1365 | struct iw_event iwe; |
1291 | const u8 *ie; | 1366 | const u8 *ie; |
1292 | u8 *buf, *cfg, *p; | 1367 | u8 buf[50]; |
1368 | u8 *cfg, *p, *tmp; | ||
1293 | int rem, i, sig; | 1369 | int rem, i, sig; |
1294 | bool ismesh = false; | 1370 | bool ismesh = false; |
1295 | 1371 | ||
@@ -1297,22 +1373,28 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | |||
1297 | iwe.cmd = SIOCGIWAP; | 1373 | iwe.cmd = SIOCGIWAP; |
1298 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | 1374 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; |
1299 | memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN); | 1375 | memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN); |
1300 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | 1376 | current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe, |
1301 | IW_EV_ADDR_LEN); | 1377 | IW_EV_ADDR_LEN); |
1378 | if (IS_ERR(current_ev)) | ||
1379 | return current_ev; | ||
1302 | 1380 | ||
1303 | memset(&iwe, 0, sizeof(iwe)); | 1381 | memset(&iwe, 0, sizeof(iwe)); |
1304 | iwe.cmd = SIOCGIWFREQ; | 1382 | iwe.cmd = SIOCGIWFREQ; |
1305 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq); | 1383 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq); |
1306 | iwe.u.freq.e = 0; | 1384 | iwe.u.freq.e = 0; |
1307 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | 1385 | current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe, |
1308 | IW_EV_FREQ_LEN); | 1386 | IW_EV_FREQ_LEN); |
1387 | if (IS_ERR(current_ev)) | ||
1388 | return current_ev; | ||
1309 | 1389 | ||
1310 | memset(&iwe, 0, sizeof(iwe)); | 1390 | memset(&iwe, 0, sizeof(iwe)); |
1311 | iwe.cmd = SIOCGIWFREQ; | 1391 | iwe.cmd = SIOCGIWFREQ; |
1312 | iwe.u.freq.m = bss->pub.channel->center_freq; | 1392 | iwe.u.freq.m = bss->pub.channel->center_freq; |
1313 | iwe.u.freq.e = 6; | 1393 | iwe.u.freq.e = 6; |
1314 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | 1394 | current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe, |
1315 | IW_EV_FREQ_LEN); | 1395 | IW_EV_FREQ_LEN); |
1396 | if (IS_ERR(current_ev)) | ||
1397 | return current_ev; | ||
1316 | 1398 | ||
1317 | if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) { | 1399 | if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) { |
1318 | memset(&iwe, 0, sizeof(iwe)); | 1400 | memset(&iwe, 0, sizeof(iwe)); |
@@ -1341,8 +1423,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | |||
1341 | /* not reached */ | 1423 | /* not reached */ |
1342 | break; | 1424 | break; |
1343 | } | 1425 | } |
1344 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | 1426 | current_ev = iwe_stream_add_event_check(info, current_ev, |
1345 | &iwe, IW_EV_QUAL_LEN); | 1427 | end_buf, &iwe, |
1428 | IW_EV_QUAL_LEN); | ||
1429 | if (IS_ERR(current_ev)) | ||
1430 | return current_ev; | ||
1346 | } | 1431 | } |
1347 | 1432 | ||
1348 | memset(&iwe, 0, sizeof(iwe)); | 1433 | memset(&iwe, 0, sizeof(iwe)); |
@@ -1352,8 +1437,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | |||
1352 | else | 1437 | else |
1353 | iwe.u.data.flags = IW_ENCODE_DISABLED; | 1438 | iwe.u.data.flags = IW_ENCODE_DISABLED; |
1354 | iwe.u.data.length = 0; | 1439 | iwe.u.data.length = 0; |
1355 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | 1440 | current_ev = iwe_stream_add_point_check(info, current_ev, end_buf, |
1356 | &iwe, ""); | 1441 | &iwe, ""); |
1442 | if (IS_ERR(current_ev)) | ||
1443 | return current_ev; | ||
1357 | 1444 | ||
1358 | rcu_read_lock(); | 1445 | rcu_read_lock(); |
1359 | ies = rcu_dereference(bss->pub.ies); | 1446 | ies = rcu_dereference(bss->pub.ies); |
@@ -1371,66 +1458,91 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | |||
1371 | iwe.cmd = SIOCGIWESSID; | 1458 | iwe.cmd = SIOCGIWESSID; |
1372 | iwe.u.data.length = ie[1]; | 1459 | iwe.u.data.length = ie[1]; |
1373 | iwe.u.data.flags = 1; | 1460 | iwe.u.data.flags = 1; |
1374 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | 1461 | current_ev = iwe_stream_add_point_check(info, |
1375 | &iwe, (u8 *)ie + 2); | 1462 | current_ev, |
1463 | end_buf, &iwe, | ||
1464 | (u8 *)ie + 2); | ||
1465 | if (IS_ERR(current_ev)) | ||
1466 | goto unlock; | ||
1376 | break; | 1467 | break; |
1377 | case WLAN_EID_MESH_ID: | 1468 | case WLAN_EID_MESH_ID: |
1378 | memset(&iwe, 0, sizeof(iwe)); | 1469 | memset(&iwe, 0, sizeof(iwe)); |
1379 | iwe.cmd = SIOCGIWESSID; | 1470 | iwe.cmd = SIOCGIWESSID; |
1380 | iwe.u.data.length = ie[1]; | 1471 | iwe.u.data.length = ie[1]; |
1381 | iwe.u.data.flags = 1; | 1472 | iwe.u.data.flags = 1; |
1382 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | 1473 | current_ev = iwe_stream_add_point_check(info, |
1383 | &iwe, (u8 *)ie + 2); | 1474 | current_ev, |
1475 | end_buf, &iwe, | ||
1476 | (u8 *)ie + 2); | ||
1477 | if (IS_ERR(current_ev)) | ||
1478 | goto unlock; | ||
1384 | break; | 1479 | break; |
1385 | case WLAN_EID_MESH_CONFIG: | 1480 | case WLAN_EID_MESH_CONFIG: |
1386 | ismesh = true; | 1481 | ismesh = true; |
1387 | if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) | 1482 | if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) |
1388 | break; | 1483 | break; |
1389 | buf = kmalloc(50, GFP_ATOMIC); | ||
1390 | if (!buf) | ||
1391 | break; | ||
1392 | cfg = (u8 *)ie + 2; | 1484 | cfg = (u8 *)ie + 2; |
1393 | memset(&iwe, 0, sizeof(iwe)); | 1485 | memset(&iwe, 0, sizeof(iwe)); |
1394 | iwe.cmd = IWEVCUSTOM; | 1486 | iwe.cmd = IWEVCUSTOM; |
1395 | sprintf(buf, "Mesh Network Path Selection Protocol ID: " | 1487 | sprintf(buf, "Mesh Network Path Selection Protocol ID: " |
1396 | "0x%02X", cfg[0]); | 1488 | "0x%02X", cfg[0]); |
1397 | iwe.u.data.length = strlen(buf); | 1489 | iwe.u.data.length = strlen(buf); |
1398 | current_ev = iwe_stream_add_point(info, current_ev, | 1490 | current_ev = iwe_stream_add_point_check(info, |
1399 | end_buf, | 1491 | current_ev, |
1400 | &iwe, buf); | 1492 | end_buf, |
1493 | &iwe, buf); | ||
1494 | if (IS_ERR(current_ev)) | ||
1495 | goto unlock; | ||
1401 | sprintf(buf, "Path Selection Metric ID: 0x%02X", | 1496 | sprintf(buf, "Path Selection Metric ID: 0x%02X", |
1402 | cfg[1]); | 1497 | cfg[1]); |
1403 | iwe.u.data.length = strlen(buf); | 1498 | iwe.u.data.length = strlen(buf); |
1404 | current_ev = iwe_stream_add_point(info, current_ev, | 1499 | current_ev = iwe_stream_add_point_check(info, |
1405 | end_buf, | 1500 | current_ev, |
1406 | &iwe, buf); | 1501 | end_buf, |
1502 | &iwe, buf); | ||
1503 | if (IS_ERR(current_ev)) | ||
1504 | goto unlock; | ||
1407 | sprintf(buf, "Congestion Control Mode ID: 0x%02X", | 1505 | sprintf(buf, "Congestion Control Mode ID: 0x%02X", |
1408 | cfg[2]); | 1506 | cfg[2]); |
1409 | iwe.u.data.length = strlen(buf); | 1507 | iwe.u.data.length = strlen(buf); |
1410 | current_ev = iwe_stream_add_point(info, current_ev, | 1508 | current_ev = iwe_stream_add_point_check(info, |
1411 | end_buf, | 1509 | current_ev, |
1412 | &iwe, buf); | 1510 | end_buf, |
1511 | &iwe, buf); | ||
1512 | if (IS_ERR(current_ev)) | ||
1513 | goto unlock; | ||
1413 | sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]); | 1514 | sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]); |
1414 | iwe.u.data.length = strlen(buf); | 1515 | iwe.u.data.length = strlen(buf); |
1415 | current_ev = iwe_stream_add_point(info, current_ev, | 1516 | current_ev = iwe_stream_add_point_check(info, |
1416 | end_buf, | 1517 | current_ev, |
1417 | &iwe, buf); | 1518 | end_buf, |
1519 | &iwe, buf); | ||
1520 | if (IS_ERR(current_ev)) | ||
1521 | goto unlock; | ||
1418 | sprintf(buf, "Authentication ID: 0x%02X", cfg[4]); | 1522 | sprintf(buf, "Authentication ID: 0x%02X", cfg[4]); |
1419 | iwe.u.data.length = strlen(buf); | 1523 | iwe.u.data.length = strlen(buf); |
1420 | current_ev = iwe_stream_add_point(info, current_ev, | 1524 | current_ev = iwe_stream_add_point_check(info, |
1421 | end_buf, | 1525 | current_ev, |
1422 | &iwe, buf); | 1526 | end_buf, |
1527 | &iwe, buf); | ||
1528 | if (IS_ERR(current_ev)) | ||
1529 | goto unlock; | ||
1423 | sprintf(buf, "Formation Info: 0x%02X", cfg[5]); | 1530 | sprintf(buf, "Formation Info: 0x%02X", cfg[5]); |
1424 | iwe.u.data.length = strlen(buf); | 1531 | iwe.u.data.length = strlen(buf); |
1425 | current_ev = iwe_stream_add_point(info, current_ev, | 1532 | current_ev = iwe_stream_add_point_check(info, |
1426 | end_buf, | 1533 | current_ev, |
1427 | &iwe, buf); | 1534 | end_buf, |
1535 | &iwe, buf); | ||
1536 | if (IS_ERR(current_ev)) | ||
1537 | goto unlock; | ||
1428 | sprintf(buf, "Capabilities: 0x%02X", cfg[6]); | 1538 | sprintf(buf, "Capabilities: 0x%02X", cfg[6]); |
1429 | iwe.u.data.length = strlen(buf); | 1539 | iwe.u.data.length = strlen(buf); |
1430 | current_ev = iwe_stream_add_point(info, current_ev, | 1540 | current_ev = iwe_stream_add_point_check(info, |
1431 | end_buf, | 1541 | current_ev, |
1432 | &iwe, buf); | 1542 | end_buf, |
1433 | kfree(buf); | 1543 | &iwe, buf); |
1544 | if (IS_ERR(current_ev)) | ||
1545 | goto unlock; | ||
1434 | break; | 1546 | break; |
1435 | case WLAN_EID_SUPP_RATES: | 1547 | case WLAN_EID_SUPP_RATES: |
1436 | case WLAN_EID_EXT_SUPP_RATES: | 1548 | case WLAN_EID_EXT_SUPP_RATES: |
@@ -1445,8 +1557,14 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | |||
1445 | for (i = 0; i < ie[1]; i++) { | 1557 | for (i = 0; i < ie[1]; i++) { |
1446 | iwe.u.bitrate.value = | 1558 | iwe.u.bitrate.value = |
1447 | ((ie[i + 2] & 0x7f) * 500000); | 1559 | ((ie[i + 2] & 0x7f) * 500000); |
1560 | tmp = p; | ||
1448 | p = iwe_stream_add_value(info, current_ev, p, | 1561 | p = iwe_stream_add_value(info, current_ev, p, |
1449 | end_buf, &iwe, IW_EV_PARAM_LEN); | 1562 | end_buf, &iwe, |
1563 | IW_EV_PARAM_LEN); | ||
1564 | if (p == tmp) { | ||
1565 | current_ev = ERR_PTR(-E2BIG); | ||
1566 | goto unlock; | ||
1567 | } | ||
1450 | } | 1568 | } |
1451 | current_ev = p; | 1569 | current_ev = p; |
1452 | break; | 1570 | break; |
@@ -1465,31 +1583,35 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, | |||
1465 | iwe.u.mode = IW_MODE_MASTER; | 1583 | iwe.u.mode = IW_MODE_MASTER; |
1466 | else | 1584 | else |
1467 | iwe.u.mode = IW_MODE_ADHOC; | 1585 | iwe.u.mode = IW_MODE_ADHOC; |
1468 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | 1586 | current_ev = iwe_stream_add_event_check(info, current_ev, |
1469 | &iwe, IW_EV_UINT_LEN); | 1587 | end_buf, &iwe, |
1470 | } | 1588 | IW_EV_UINT_LEN); |
1471 | 1589 | if (IS_ERR(current_ev)) | |
1472 | buf = kmalloc(31, GFP_ATOMIC); | 1590 | goto unlock; |
1473 | if (buf) { | ||
1474 | memset(&iwe, 0, sizeof(iwe)); | ||
1475 | iwe.cmd = IWEVCUSTOM; | ||
1476 | sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf)); | ||
1477 | iwe.u.data.length = strlen(buf); | ||
1478 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1479 | &iwe, buf); | ||
1480 | memset(&iwe, 0, sizeof(iwe)); | ||
1481 | iwe.cmd = IWEVCUSTOM; | ||
1482 | sprintf(buf, " Last beacon: %ums ago", | ||
1483 | elapsed_jiffies_msecs(bss->ts)); | ||
1484 | iwe.u.data.length = strlen(buf); | ||
1485 | current_ev = iwe_stream_add_point(info, current_ev, | ||
1486 | end_buf, &iwe, buf); | ||
1487 | kfree(buf); | ||
1488 | } | 1591 | } |
1489 | 1592 | ||
1490 | ieee80211_scan_add_ies(info, ies, ¤t_ev, end_buf); | 1593 | memset(&iwe, 0, sizeof(iwe)); |
1594 | iwe.cmd = IWEVCUSTOM; | ||
1595 | sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf)); | ||
1596 | iwe.u.data.length = strlen(buf); | ||
1597 | current_ev = iwe_stream_add_point_check(info, current_ev, end_buf, | ||
1598 | &iwe, buf); | ||
1599 | if (IS_ERR(current_ev)) | ||
1600 | goto unlock; | ||
1601 | memset(&iwe, 0, sizeof(iwe)); | ||
1602 | iwe.cmd = IWEVCUSTOM; | ||
1603 | sprintf(buf, " Last beacon: %ums ago", | ||
1604 | elapsed_jiffies_msecs(bss->ts)); | ||
1605 | iwe.u.data.length = strlen(buf); | ||
1606 | current_ev = iwe_stream_add_point_check(info, current_ev, | ||
1607 | end_buf, &iwe, buf); | ||
1608 | if (IS_ERR(current_ev)) | ||
1609 | goto unlock; | ||
1610 | |||
1611 | current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf); | ||
1612 | |||
1613 | unlock: | ||
1491 | rcu_read_unlock(); | 1614 | rcu_read_unlock(); |
1492 | |||
1493 | return current_ev; | 1615 | return current_ev; |
1494 | } | 1616 | } |
1495 | 1617 | ||
@@ -1501,19 +1623,27 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev, | |||
1501 | char *current_ev = buf; | 1623 | char *current_ev = buf; |
1502 | char *end_buf = buf + len; | 1624 | char *end_buf = buf + len; |
1503 | struct cfg80211_internal_bss *bss; | 1625 | struct cfg80211_internal_bss *bss; |
1626 | int err = 0; | ||
1504 | 1627 | ||
1505 | spin_lock_bh(&rdev->bss_lock); | 1628 | spin_lock_bh(&rdev->bss_lock); |
1506 | cfg80211_bss_expire(rdev); | 1629 | cfg80211_bss_expire(rdev); |
1507 | 1630 | ||
1508 | list_for_each_entry(bss, &rdev->bss_list, list) { | 1631 | list_for_each_entry(bss, &rdev->bss_list, list) { |
1509 | if (buf + len - current_ev <= IW_EV_ADDR_LEN) { | 1632 | if (buf + len - current_ev <= IW_EV_ADDR_LEN) { |
1510 | spin_unlock_bh(&rdev->bss_lock); | 1633 | err = -E2BIG; |
1511 | return -E2BIG; | 1634 | break; |
1512 | } | 1635 | } |
1513 | current_ev = ieee80211_bss(&rdev->wiphy, info, bss, | 1636 | current_ev = ieee80211_bss(&rdev->wiphy, info, bss, |
1514 | current_ev, end_buf); | 1637 | current_ev, end_buf); |
1638 | if (IS_ERR(current_ev)) { | ||
1639 | err = PTR_ERR(current_ev); | ||
1640 | break; | ||
1641 | } | ||
1515 | } | 1642 | } |
1516 | spin_unlock_bh(&rdev->bss_lock); | 1643 | spin_unlock_bh(&rdev->bss_lock); |
1644 | |||
1645 | if (err) | ||
1646 | return err; | ||
1517 | return current_ev - buf; | 1647 | return current_ev - buf; |
1518 | } | 1648 | } |
1519 | 1649 | ||
@@ -1545,5 +1675,5 @@ int cfg80211_wext_giwscan(struct net_device *dev, | |||
1545 | 1675 | ||
1546 | return res; | 1676 | return res; |
1547 | } | 1677 | } |
1548 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); | 1678 | EXPORT_WEXT_HANDLER(cfg80211_wext_giwscan); |
1549 | #endif | 1679 | #endif |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 0ab3711c79a0..ea1da6621ff0 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -257,19 +257,15 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev) | |||
257 | { | 257 | { |
258 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | 258 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
259 | struct cfg80211_bss *bss; | 259 | struct cfg80211_bss *bss; |
260 | u16 capa = WLAN_CAPABILITY_ESS; | ||
261 | 260 | ||
262 | ASSERT_WDEV_LOCK(wdev); | 261 | ASSERT_WDEV_LOCK(wdev); |
263 | 262 | ||
264 | if (wdev->conn->params.privacy) | ||
265 | capa |= WLAN_CAPABILITY_PRIVACY; | ||
266 | |||
267 | bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel, | 263 | bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel, |
268 | wdev->conn->params.bssid, | 264 | wdev->conn->params.bssid, |
269 | wdev->conn->params.ssid, | 265 | wdev->conn->params.ssid, |
270 | wdev->conn->params.ssid_len, | 266 | wdev->conn->params.ssid_len, |
271 | WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, | 267 | IEEE80211_BSS_TYPE_ESS, |
272 | capa); | 268 | IEEE80211_PRIVACY(wdev->conn->params.privacy)); |
273 | if (!bss) | 269 | if (!bss) |
274 | return NULL; | 270 | return NULL; |
275 | 271 | ||
@@ -637,8 +633,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
637 | WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); | 633 | WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); |
638 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 634 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
639 | wdev->ssid, wdev->ssid_len, | 635 | wdev->ssid, wdev->ssid_len, |
640 | WLAN_CAPABILITY_ESS, | 636 | IEEE80211_BSS_TYPE_ESS, |
641 | WLAN_CAPABILITY_ESS); | 637 | IEEE80211_PRIVACY_ANY); |
642 | if (bss) | 638 | if (bss) |
643 | cfg80211_hold_bss(bss_from_pub(bss)); | 639 | cfg80211_hold_bss(bss_from_pub(bss)); |
644 | } | 640 | } |
@@ -795,8 +791,8 @@ void cfg80211_roamed(struct net_device *dev, | |||
795 | struct cfg80211_bss *bss; | 791 | struct cfg80211_bss *bss; |
796 | 792 | ||
797 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, | 793 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid, |
798 | wdev->ssid_len, WLAN_CAPABILITY_ESS, | 794 | wdev->ssid_len, |
799 | WLAN_CAPABILITY_ESS); | 795 | IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); |
800 | if (WARN_ON(!bss)) | 796 | if (WARN_ON(!bss)) |
801 | return; | 797 | return; |
802 | 798 | ||
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index a00ee8897dc6..af3617c9879e 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -628,6 +628,7 @@ DECLARE_EVENT_CLASS(station_add_change, | |||
628 | __field(u8, plink_state) | 628 | __field(u8, plink_state) |
629 | __field(u8, uapsd_queues) | 629 | __field(u8, uapsd_queues) |
630 | __array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap)) | 630 | __array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap)) |
631 | __array(char, vlan, IFNAMSIZ) | ||
631 | ), | 632 | ), |
632 | TP_fast_assign( | 633 | TP_fast_assign( |
633 | WIPHY_ASSIGN; | 634 | WIPHY_ASSIGN; |
@@ -645,16 +646,19 @@ DECLARE_EVENT_CLASS(station_add_change, | |||
645 | if (params->ht_capa) | 646 | if (params->ht_capa) |
646 | memcpy(__entry->ht_capa, params->ht_capa, | 647 | memcpy(__entry->ht_capa, params->ht_capa, |
647 | sizeof(struct ieee80211_ht_cap)); | 648 | sizeof(struct ieee80211_ht_cap)); |
649 | memset(__entry->vlan, 0, sizeof(__entry->vlan)); | ||
650 | if (params->vlan) | ||
651 | memcpy(__entry->vlan, params->vlan->name, IFNAMSIZ); | ||
648 | ), | 652 | ), |
649 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT | 653 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT |
650 | ", station flags mask: %u, station flags set: %u, " | 654 | ", station flags mask: %u, station flags set: %u, " |
651 | "station modify mask: %u, listen interval: %d, aid: %u, " | 655 | "station modify mask: %u, listen interval: %d, aid: %u, " |
652 | "plink action: %u, plink state: %u, uapsd queues: %u", | 656 | "plink action: %u, plink state: %u, uapsd queues: %u, vlan:%s", |
653 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), | 657 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), |
654 | __entry->sta_flags_mask, __entry->sta_flags_set, | 658 | __entry->sta_flags_mask, __entry->sta_flags_set, |
655 | __entry->sta_modify_mask, __entry->listen_interval, | 659 | __entry->sta_modify_mask, __entry->listen_interval, |
656 | __entry->aid, __entry->plink_action, __entry->plink_state, | 660 | __entry->aid, __entry->plink_action, __entry->plink_state, |
657 | __entry->uapsd_queues) | 661 | __entry->uapsd_queues, __entry->vlan) |
658 | ); | 662 | ); |
659 | 663 | ||
660 | DEFINE_EVENT(station_add_change, rdev_add_station, | 664 | DEFINE_EVENT(station_add_change, rdev_add_station, |
@@ -2637,28 +2641,30 @@ DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_stopped, | |||
2637 | TRACE_EVENT(cfg80211_get_bss, | 2641 | TRACE_EVENT(cfg80211_get_bss, |
2638 | TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, | 2642 | TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, |
2639 | const u8 *bssid, const u8 *ssid, size_t ssid_len, | 2643 | const u8 *bssid, const u8 *ssid, size_t ssid_len, |
2640 | u16 capa_mask, u16 capa_val), | 2644 | enum ieee80211_bss_type bss_type, |
2641 | TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, capa_mask, capa_val), | 2645 | enum ieee80211_privacy privacy), |
2646 | TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, bss_type, privacy), | ||
2642 | TP_STRUCT__entry( | 2647 | TP_STRUCT__entry( |
2643 | WIPHY_ENTRY | 2648 | WIPHY_ENTRY |
2644 | CHAN_ENTRY | 2649 | CHAN_ENTRY |
2645 | MAC_ENTRY(bssid) | 2650 | MAC_ENTRY(bssid) |
2646 | __dynamic_array(u8, ssid, ssid_len) | 2651 | __dynamic_array(u8, ssid, ssid_len) |
2647 | __field(u16, capa_mask) | 2652 | __field(enum ieee80211_bss_type, bss_type) |
2648 | __field(u16, capa_val) | 2653 | __field(enum ieee80211_privacy, privacy) |
2649 | ), | 2654 | ), |
2650 | TP_fast_assign( | 2655 | TP_fast_assign( |
2651 | WIPHY_ASSIGN; | 2656 | WIPHY_ASSIGN; |
2652 | CHAN_ASSIGN(channel); | 2657 | CHAN_ASSIGN(channel); |
2653 | MAC_ASSIGN(bssid, bssid); | 2658 | MAC_ASSIGN(bssid, bssid); |
2654 | memcpy(__get_dynamic_array(ssid), ssid, ssid_len); | 2659 | memcpy(__get_dynamic_array(ssid), ssid, ssid_len); |
2655 | __entry->capa_mask = capa_mask; | 2660 | __entry->bss_type = bss_type; |
2656 | __entry->capa_val = capa_val; | 2661 | __entry->privacy = privacy; |
2657 | ), | 2662 | ), |
2658 | TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT ", buf: %#.2x, " | 2663 | TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT |
2659 | "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG, | 2664 | ", buf: %#.2x, bss_type: %d, privacy: %d", |
2660 | MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0], | 2665 | WIPHY_PR_ARG, CHAN_PR_ARG, MAC_PR_ARG(bssid), |
2661 | __entry->capa_mask, __entry->capa_val) | 2666 | ((u8 *)__get_dynamic_array(ssid))[0], __entry->bss_type, |
2667 | __entry->privacy) | ||
2662 | ); | 2668 | ); |
2663 | 2669 | ||
2664 | TRACE_EVENT(cfg80211_inform_bss_width_frame, | 2670 | TRACE_EVENT(cfg80211_inform_bss_width_frame, |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 6903dbdcb8c1..f218b151530a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -1296,6 +1296,7 @@ bool ieee80211_operating_class_to_band(u8 operating_class, | |||
1296 | switch (operating_class) { | 1296 | switch (operating_class) { |
1297 | case 112: | 1297 | case 112: |
1298 | case 115 ... 127: | 1298 | case 115 ... 127: |
1299 | case 128 ... 130: | ||
1299 | *band = IEEE80211_BAND_5GHZ; | 1300 | *band = IEEE80211_BAND_5GHZ; |
1300 | return true; | 1301 | return true; |
1301 | case 81: | 1302 | case 81: |
@@ -1313,6 +1314,135 @@ bool ieee80211_operating_class_to_band(u8 operating_class, | |||
1313 | } | 1314 | } |
1314 | EXPORT_SYMBOL(ieee80211_operating_class_to_band); | 1315 | EXPORT_SYMBOL(ieee80211_operating_class_to_band); |
1315 | 1316 | ||
1317 | bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, | ||
1318 | u8 *op_class) | ||
1319 | { | ||
1320 | u8 vht_opclass; | ||
1321 | u16 freq = chandef->center_freq1; | ||
1322 | |||
1323 | if (freq >= 2412 && freq <= 2472) { | ||
1324 | if (chandef->width > NL80211_CHAN_WIDTH_40) | ||
1325 | return false; | ||
1326 | |||
1327 | /* 2.407 GHz, channels 1..13 */ | ||
1328 | if (chandef->width == NL80211_CHAN_WIDTH_40) { | ||
1329 | if (freq > chandef->chan->center_freq) | ||
1330 | *op_class = 83; /* HT40+ */ | ||
1331 | else | ||
1332 | *op_class = 84; /* HT40- */ | ||
1333 | } else { | ||
1334 | *op_class = 81; | ||
1335 | } | ||
1336 | |||
1337 | return true; | ||
1338 | } | ||
1339 | |||
1340 | if (freq == 2484) { | ||
1341 | if (chandef->width > NL80211_CHAN_WIDTH_40) | ||
1342 | return false; | ||
1343 | |||
1344 | *op_class = 82; /* channel 14 */ | ||
1345 | return true; | ||
1346 | } | ||
1347 | |||
1348 | switch (chandef->width) { | ||
1349 | case NL80211_CHAN_WIDTH_80: | ||
1350 | vht_opclass = 128; | ||
1351 | break; | ||
1352 | case NL80211_CHAN_WIDTH_160: | ||
1353 | vht_opclass = 129; | ||
1354 | break; | ||
1355 | case NL80211_CHAN_WIDTH_80P80: | ||
1356 | vht_opclass = 130; | ||
1357 | break; | ||
1358 | case NL80211_CHAN_WIDTH_10: | ||
1359 | case NL80211_CHAN_WIDTH_5: | ||
1360 | return false; /* unsupported for now */ | ||
1361 | default: | ||
1362 | vht_opclass = 0; | ||
1363 | break; | ||
1364 | } | ||
1365 | |||
1366 | /* 5 GHz, channels 36..48 */ | ||
1367 | if (freq >= 5180 && freq <= 5240) { | ||
1368 | if (vht_opclass) { | ||
1369 | *op_class = vht_opclass; | ||
1370 | } else if (chandef->width == NL80211_CHAN_WIDTH_40) { | ||
1371 | if (freq > chandef->chan->center_freq) | ||
1372 | *op_class = 116; | ||
1373 | else | ||
1374 | *op_class = 117; | ||
1375 | } else { | ||
1376 | *op_class = 115; | ||
1377 | } | ||
1378 | |||
1379 | return true; | ||
1380 | } | ||
1381 | |||
1382 | /* 5 GHz, channels 52..64 */ | ||
1383 | if (freq >= 5260 && freq <= 5320) { | ||
1384 | if (vht_opclass) { | ||
1385 | *op_class = vht_opclass; | ||
1386 | } else if (chandef->width == NL80211_CHAN_WIDTH_40) { | ||
1387 | if (freq > chandef->chan->center_freq) | ||
1388 | *op_class = 119; | ||
1389 | else | ||
1390 | *op_class = 120; | ||
1391 | } else { | ||
1392 | *op_class = 118; | ||
1393 | } | ||
1394 | |||
1395 | return true; | ||
1396 | } | ||
1397 | |||
1398 | /* 5 GHz, channels 100..144 */ | ||
1399 | if (freq >= 5500 && freq <= 5720) { | ||
1400 | if (vht_opclass) { | ||
1401 | *op_class = vht_opclass; | ||
1402 | } else if (chandef->width == NL80211_CHAN_WIDTH_40) { | ||
1403 | if (freq > chandef->chan->center_freq) | ||
1404 | *op_class = 122; | ||
1405 | else | ||
1406 | *op_class = 123; | ||
1407 | } else { | ||
1408 | *op_class = 121; | ||
1409 | } | ||
1410 | |||
1411 | return true; | ||
1412 | } | ||
1413 | |||
1414 | /* 5 GHz, channels 149..169 */ | ||
1415 | if (freq >= 5745 && freq <= 5845) { | ||
1416 | if (vht_opclass) { | ||
1417 | *op_class = vht_opclass; | ||
1418 | } else if (chandef->width == NL80211_CHAN_WIDTH_40) { | ||
1419 | if (freq > chandef->chan->center_freq) | ||
1420 | *op_class = 126; | ||
1421 | else | ||
1422 | *op_class = 127; | ||
1423 | } else if (freq <= 5805) { | ||
1424 | *op_class = 124; | ||
1425 | } else { | ||
1426 | *op_class = 125; | ||
1427 | } | ||
1428 | |||
1429 | return true; | ||
1430 | } | ||
1431 | |||
1432 | /* 56.16 GHz, channel 1..4 */ | ||
1433 | if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) { | ||
1434 | if (chandef->width >= NL80211_CHAN_WIDTH_40) | ||
1435 | return false; | ||
1436 | |||
1437 | *op_class = 180; | ||
1438 | return true; | ||
1439 | } | ||
1440 | |||
1441 | /* not supported yet */ | ||
1442 | return false; | ||
1443 | } | ||
1444 | EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); | ||
1445 | |||
1316 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 1446 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
1317 | u32 beacon_int) | 1447 | u32 beacon_int) |
1318 | { | 1448 | { |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 5b24d39d7903..fff1bef6ed6d 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -63,7 +63,7 @@ int cfg80211_wext_giwname(struct net_device *dev, | |||
63 | 63 | ||
64 | return 0; | 64 | return 0; |
65 | } | 65 | } |
66 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwname); | 66 | EXPORT_WEXT_HANDLER(cfg80211_wext_giwname); |
67 | 67 | ||
68 | int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | 68 | int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, |
69 | u32 *mode, char *extra) | 69 | u32 *mode, char *extra) |
@@ -99,7 +99,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | |||
99 | 99 | ||
100 | return cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); | 100 | return cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); |
101 | } | 101 | } |
102 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); | 102 | EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode); |
103 | 103 | ||
104 | int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, | 104 | int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, |
105 | u32 *mode, char *extra) | 105 | u32 *mode, char *extra) |
@@ -134,7 +134,7 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, | |||
134 | } | 134 | } |
135 | return 0; | 135 | return 0; |
136 | } | 136 | } |
137 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode); | 137 | EXPORT_WEXT_HANDLER(cfg80211_wext_giwmode); |
138 | 138 | ||
139 | 139 | ||
140 | int cfg80211_wext_giwrange(struct net_device *dev, | 140 | int cfg80211_wext_giwrange(struct net_device *dev, |
@@ -248,7 +248,7 @@ int cfg80211_wext_giwrange(struct net_device *dev, | |||
248 | 248 | ||
249 | return 0; | 249 | return 0; |
250 | } | 250 | } |
251 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); | 251 | EXPORT_WEXT_HANDLER(cfg80211_wext_giwrange); |
252 | 252 | ||
253 | 253 | ||
254 | /** | 254 | /** |
@@ -303,7 +303,7 @@ int cfg80211_wext_siwrts(struct net_device *dev, | |||
303 | 303 | ||
304 | return err; | 304 | return err; |
305 | } | 305 | } |
306 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts); | 306 | EXPORT_WEXT_HANDLER(cfg80211_wext_siwrts); |
307 | 307 | ||
308 | int cfg80211_wext_giwrts(struct net_device *dev, | 308 | int cfg80211_wext_giwrts(struct net_device *dev, |
309 | struct iw_request_info *info, | 309 | struct iw_request_info *info, |
@@ -317,7 +317,7 @@ int cfg80211_wext_giwrts(struct net_device *dev, | |||
317 | 317 | ||
318 | return 0; | 318 | return 0; |
319 | } | 319 | } |
320 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts); | 320 | EXPORT_WEXT_HANDLER(cfg80211_wext_giwrts); |
321 | 321 | ||
322 | int cfg80211_wext_siwfrag(struct net_device *dev, | 322 | int cfg80211_wext_siwfrag(struct net_device *dev, |
323 | struct iw_request_info *info, | 323 | struct iw_request_info *info, |
@@ -343,7 +343,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev, | |||
343 | 343 | ||
344 | return err; | 344 | return err; |
345 | } | 345 | } |
346 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag); | 346 | EXPORT_WEXT_HANDLER(cfg80211_wext_siwfrag); |
347 | 347 | ||
348 | int cfg80211_wext_giwfrag(struct net_device *dev, | 348 | int cfg80211_wext_giwfrag(struct net_device *dev, |
349 | struct iw_request_info *info, | 349 | struct iw_request_info *info, |
@@ -357,7 +357,7 @@ int cfg80211_wext_giwfrag(struct net_device *dev, | |||
357 | 357 | ||
358 | return 0; | 358 | return 0; |
359 | } | 359 | } |
360 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag); | 360 | EXPORT_WEXT_HANDLER(cfg80211_wext_giwfrag); |
361 | 361 | ||
362 | static int cfg80211_wext_siwretry(struct net_device *dev, | 362 | static int cfg80211_wext_siwretry(struct net_device *dev, |
363 | struct iw_request_info *info, | 363 | struct iw_request_info *info, |
@@ -427,7 +427,7 @@ int cfg80211_wext_giwretry(struct net_device *dev, | |||
427 | 427 | ||
428 | return 0; | 428 | return 0; |
429 | } | 429 | } |
430 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 430 | EXPORT_WEXT_HANDLER(cfg80211_wext_giwretry); |
431 | 431 | ||
432 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 432 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
433 | struct net_device *dev, bool pairwise, | 433 | struct net_device *dev, bool pairwise, |
diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h index ebcacca2f731..94c7405a5413 100644 --- a/net/wireless/wext-compat.h +++ b/net/wireless/wext-compat.h | |||
@@ -4,6 +4,12 @@ | |||
4 | #include <net/iw_handler.h> | 4 | #include <net/iw_handler.h> |
5 | #include <linux/wireless.h> | 5 | #include <linux/wireless.h> |
6 | 6 | ||
7 | #ifdef CONFIG_CFG80211_WEXT_EXPORT | ||
8 | #define EXPORT_WEXT_HANDLER(h) EXPORT_SYMBOL_GPL(h) | ||
9 | #else | ||
10 | #define EXPORT_WEXT_HANDLER(h) | ||
11 | #endif /* CONFIG_CFG80211_WEXT_EXPORT */ | ||
12 | |||
7 | int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | 13 | int cfg80211_ibss_wext_siwfreq(struct net_device *dev, |
8 | struct iw_request_info *info, | 14 | struct iw_request_info *info, |
9 | struct iw_freq *freq, char *extra); | 15 | struct iw_freq *freq, char *extra); |