summaryrefslogtreecommitdiff
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/Kconfig12
-rw-r--r--net/mac80211/aes_ccm.c169
-rw-r--r--net/mac80211/aes_ccm.h14
-rw-r--r--net/mac80211/cfg.c234
-rw-r--r--net/mac80211/chan.c5
-rw-r--r--net/mac80211/debug.h10
-rw-r--r--net/mac80211/debugfs.c55
-rw-r--r--net/mac80211/debugfs_netdev.c25
-rw-r--r--net/mac80211/driver-ops.h27
-rw-r--r--net/mac80211/ht.c41
-rw-r--r--net/mac80211/ibss.c594
-rw-r--r--net/mac80211/ieee80211_i.h71
-rw-r--r--net/mac80211/iface.c7
-rw-r--r--net/mac80211/key.c2
-rw-r--r--net/mac80211/key.h2
-rw-r--r--net/mac80211/mesh.c302
-rw-r--r--net/mac80211/mesh_plink.c3
-rw-r--r--net/mac80211/mesh_ps.c33
-rw-r--r--net/mac80211/mlme.c453
-rw-r--r--net/mac80211/rate.c15
-rw-r--r--net/mac80211/rate.h12
-rw-r--r--net/mac80211/rc80211_minstrel.c14
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c23
-rw-r--r--net/mac80211/rc80211_pid_debugfs.c26
-rw-r--r--net/mac80211/rx.c42
-rw-r--r--net/mac80211/scan.c3
-rw-r--r--net/mac80211/spectmgmt.c169
-rw-r--r--net/mac80211/sta_info.c72
-rw-r--r--net/mac80211/sta_info.h5
-rw-r--r--net/mac80211/status.c31
-rw-r--r--net/mac80211/trace.h39
-rw-r--r--net/mac80211/tx.c84
-rw-r--r--net/mac80211/util.c286
-rw-r--r--net/mac80211/vht.c4
-rw-r--r--net/mac80211/wpa.c44
35 files changed, 746 insertions, 2182 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 97b5dca..62535fe 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -4,7 +4,6 @@ config MAC80211
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_AES
- select CRYPTO_CCM
select CRC32
select AVERAGE
---help---
@@ -259,17 +258,6 @@ config MAC80211_MESH_SYNC_DEBUG
Do not select this option.
-config MAC80211_MESH_CSA_DEBUG
- bool "Verbose mesh channel switch debugging"
- depends on MAC80211_DEBUG_MENU
- depends on MAC80211_MESH
- ---help---
- Selecting this option causes mac80211 to print out very verbose mesh
- channel switch debugging messages (when mac80211 is taking part in a
- mesh network).
-
- Do not select this option.
-
config MAC80211_MESH_PS_DEBUG
bool "Verbose mesh powersave debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
index 7c7df47..be7614b9 100644
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
@@ -2,8 +2,6 @@
* Copyright 2003-2004, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
- * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -19,75 +17,134 @@
#include "key.h"
#include "aes_ccm.h"
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
- u8 *data, size_t data_len, u8 *mic)
+static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a)
{
- struct scatterlist assoc, pt, ct[2];
- struct {
- struct aead_request req;
- u8 priv[crypto_aead_reqsize(tfm)];
- } aead_req;
+ int i;
+ u8 *b_0, *aad, *b, *s_0;
+
+ b_0 = scratch + 3 * AES_BLOCK_SIZE;
+ aad = scratch + 4 * AES_BLOCK_SIZE;
+ b = scratch;
+ s_0 = scratch + AES_BLOCK_SIZE;
+
+ crypto_cipher_encrypt_one(tfm, b, b_0);
- memset(&aead_req, 0, sizeof(aead_req));
+ /* Extra Authenticate-only data (always two AES blocks) */
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ aad[i] ^= b[i];
+ crypto_cipher_encrypt_one(tfm, b, aad);
- sg_init_one(&pt, data, data_len);
- sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
- sg_init_table(ct, 2);
- sg_set_buf(&ct[0], data, data_len);
- sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
+ aad += AES_BLOCK_SIZE;
- aead_request_set_tfm(&aead_req.req, tfm);
- aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
- aead_request_set_crypt(&aead_req.req, &pt, ct, data_len, b_0);
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ aad[i] ^= b[i];
+ crypto_cipher_encrypt_one(tfm, a, aad);
- crypto_aead_encrypt(&aead_req.req);
+ /* Mask out bits from auth-only-b_0 */
+ b_0[0] &= 0x07;
+
+ /* S_0 is used to encrypt T (= MIC) */
+ b_0[14] = 0;
+ b_0[15] = 0;
+ crypto_cipher_encrypt_one(tfm, s_0, b_0);
}
-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
- u8 *data, size_t data_len, u8 *mic)
+
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
+ u8 *data, size_t data_len,
+ u8 *cdata, u8 *mic)
{
- struct scatterlist assoc, pt, ct[2];
- struct {
- struct aead_request req;
- u8 priv[crypto_aead_reqsize(tfm)];
- } aead_req;
-
- memset(&aead_req, 0, sizeof(aead_req));
-
- sg_init_one(&pt, data, data_len);
- sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
- sg_init_table(ct, 2);
- sg_set_buf(&ct[0], data, data_len);
- sg_set_buf(&ct[1], mic, IEEE80211_CCMP_MIC_LEN);
-
- aead_request_set_tfm(&aead_req.req, tfm);
- aead_request_set_assoc(&aead_req.req, &assoc, assoc.length);
- aead_request_set_crypt(&aead_req.req, ct, &pt,
- data_len + IEEE80211_CCMP_MIC_LEN, b_0);
-
- return crypto_aead_decrypt(&aead_req.req);
+ int i, j, last_len, num_blocks;
+ u8 *pos, *cpos, *b, *s_0, *e, *b_0;
+
+ b = scratch;
+ s_0 = scratch + AES_BLOCK_SIZE;
+ e = scratch + 2 * AES_BLOCK_SIZE;
+ b_0 = scratch + 3 * AES_BLOCK_SIZE;
+
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
+ last_len = data_len % AES_BLOCK_SIZE;
+ aes_ccm_prepare(tfm, scratch, b);
+
+ /* Process payload blocks */
+ pos = data;
+ cpos = cdata;
+ for (j = 1; j <= num_blocks; j++) {
+ int blen = (j == num_blocks && last_len) ?
+ last_len : AES_BLOCK_SIZE;
+
+ /* Authentication followed by encryption */
+ for (i = 0; i < blen; i++)
+ b[i] ^= pos[i];
+ crypto_cipher_encrypt_one(tfm, b, b);
+
+ b_0[14] = (j >> 8) & 0xff;
+ b_0[15] = j & 0xff;
+ crypto_cipher_encrypt_one(tfm, e, b_0);
+ for (i = 0; i < blen; i++)
+ *cpos++ = *pos++ ^ e[i];
+ }
+
+ for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++)
+ mic[i] = b[i] ^ s_0[i];
}
-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[])
+
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
+ u8 *cdata, size_t data_len, u8 *mic, u8 *data)
{
- struct crypto_aead *tfm;
- int err;
+ int i, j, last_len, num_blocks;
+ u8 *pos, *cpos, *b, *s_0, *a, *b_0;
+
+ b = scratch;
+ s_0 = scratch + AES_BLOCK_SIZE;
+ a = scratch + 2 * AES_BLOCK_SIZE;
+ b_0 = scratch + 3 * AES_BLOCK_SIZE;
+
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
+ last_len = data_len % AES_BLOCK_SIZE;
+ aes_ccm_prepare(tfm, scratch, a);
+
+ /* Process payload blocks */
+ cpos = cdata;
+ pos = data;
+ for (j = 1; j <= num_blocks; j++) {
+ int blen = (j == num_blocks && last_len) ?
+ last_len : AES_BLOCK_SIZE;
+
+ /* Decryption followed by authentication */
+ b_0[14] = (j >> 8) & 0xff;
+ b_0[15] = j & 0xff;
+ crypto_cipher_encrypt_one(tfm, b, b_0);
+ for (i = 0; i < blen; i++) {
+ *pos = *cpos++ ^ b[i];
+ a[i] ^= *pos++;
+ }
+ crypto_cipher_encrypt_one(tfm, a, a);
+ }
+
+ for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++) {
+ if ((mic[i] ^ s_0[i]) != a[i])
+ return -1;
+ }
+
+ return 0;
+}
- tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
- return tfm;
- err = crypto_aead_setkey(tfm, key, WLAN_KEY_LEN_CCMP);
- if (!err)
- err = crypto_aead_setauthsize(tfm, IEEE80211_CCMP_MIC_LEN);
- if (!err)
- return tfm;
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[])
+{
+ struct crypto_cipher *tfm;
- crypto_free_aead(tfm);
- return ERR_PTR(err);
+ tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
+ if (!IS_ERR(tfm))
+ crypto_cipher_setkey(tfm, key, WLAN_KEY_LEN_CCMP);
+
+ return tfm;
}
-void ieee80211_aes_key_free(struct crypto_aead *tfm)
+
+void ieee80211_aes_key_free(struct crypto_cipher *tfm)
{
- crypto_free_aead(tfm);
+ crypto_free_cipher(tfm);
}
diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h
index 2c7ab19..5b7d744 100644
--- a/net/mac80211/aes_ccm.h
+++ b/net/mac80211/aes_ccm.h
@@ -12,11 +12,13 @@
#include <linux/crypto.h>
-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[]);
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
- u8 *data, size_t data_len, u8 *mic);
-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
- u8 *data, size_t data_len, u8 *mic);
-void ieee80211_aes_key_free(struct crypto_aead *tfm);
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]);
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
+ u8 *data, size_t data_len,
+ u8 *cdata, u8 *mic);
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
+ u8 *cdata, size_t data_len,
+ u8 *mic, u8 *data);
+void ieee80211_aes_key_free(struct crypto_cipher *tfm);
#endif /* AES_CCM_H */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 95667b0..629dee7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1059,7 +1059,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
/* abort any running channel switch */
sdata->vif.csa_active = false;
cancel_work_sync(&sdata->csa_finalize_work);
- cancel_work_sync(&sdata->u.ap.request_smps_work);
/* turn off carrier for this interface and dependent VLANs */
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
@@ -1343,8 +1342,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
sta->plink_state = params->plink_state;
ieee80211_mps_sta_status_update(sta);
- changed |= ieee80211_mps_set_sta_local_pm(sta,
- NL80211_MESH_POWER_UNKNOWN);
+ changed |=
+ ieee80211_mps_local_status_update(sdata);
break;
default:
/* nothing */
@@ -1554,20 +1553,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
mutex_unlock(&local->sta_mtx);
- if ((sdata->vif.type == NL80211_IFTYPE_AP ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
- sta->known_smps_mode != sta->sdata->bss->req_smps &&
- test_sta_flag(sta, WLAN_STA_AUTHORIZED) &&
- sta_info_tx_streams(sta) != 1) {
- ht_dbg(sta->sdata,
- "%pM just authorized and MIMO capable - update SMPS\n",
- sta->sta.addr);
- ieee80211_send_smps_action(sta->sdata,
- sta->sdata->bss->req_smps,
- sta->sta.addr,
- sta->sdata->vif.bss_conf.bssid);
- }
-
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
ieee80211_recalc_ps(local, -1);
@@ -2352,92 +2337,8 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy,
}
#endif
-int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_smps_mode smps_mode)
-{
- struct sta_info *sta;
- enum ieee80211_smps_mode old_req;
- int i;
-
- if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP))
- return -EINVAL;
-
- if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
- return 0;
-
- old_req = sdata->u.ap.req_smps;
- sdata->u.ap.req_smps = smps_mode;
-
- /* AUTOMATIC doesn't mean much for AP - don't allow it */
- if (old_req == smps_mode ||
- smps_mode == IEEE80211_SMPS_AUTOMATIC)
- return 0;
-
- /* If no associated stations, there's no need to do anything */
- if (!atomic_read(&sdata->u.ap.num_mcast_sta)) {
- sdata->smps_mode = smps_mode;
- ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
- return 0;
- }
-
- ht_dbg(sdata,
- "SMSP %d requested in AP mode, sending Action frame to %d stations\n",
- smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));
-
- mutex_lock(&sdata->local->sta_mtx);
- for (i = 0; i < STA_HASH_SIZE; i++) {
- for (sta = rcu_dereference_protected(sdata->local->sta_hash[i],
- lockdep_is_held(&sdata->local->sta_mtx));
- sta;
- sta = rcu_dereference_protected(sta->hnext,
- lockdep_is_held(&sdata->local->sta_mtx))) {
- /*
- * Only stations associated to our AP and
- * associated VLANs
- */
- if (sta->sdata->bss != &sdata->u.ap)
- continue;
-
- /* This station doesn't support MIMO - skip it */
- if (sta_info_tx_streams(sta) == 1)
- continue;
-
- /*
- * Don't wake up a STA just to send the action frame
- * unless we are getting more restrictive.
- */
- if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
- !ieee80211_smps_is_restrictive(sta->known_smps_mode,
- smps_mode)) {
- ht_dbg(sdata,
- "Won't send SMPS to sleeping STA %pM\n",
- sta->sta.addr);
- continue;
- }
-
- /*
- * If the STA is not authorized, wait until it gets
- * authorized and the action frame will be sent then.
- */
- if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
- continue;
-
- ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr);
- ieee80211_send_smps_action(sdata, smps_mode,
- sta->sta.addr,
- sdata->vif.bss_conf.bssid);
- }
- }
- mutex_unlock(&sdata->local->sta_mtx);
-
- sdata->smps_mode = smps_mode;
- ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
-
- return 0;
-}
-
-int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_smps_mode smps_mode)
+int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_smps_mode smps_mode)
{
const u8 *ap;
enum ieee80211_smps_mode old_req;
@@ -2445,9 +2346,6 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
lockdep_assert_held(&sdata->wdev.mtx);
- if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION))
- return -EINVAL;
-
old_req = sdata->u.mgd.req_smps;
sdata->u.mgd.req_smps = smps_mode;
@@ -2504,7 +2402,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
/* no change, but if automatic follow powersave */
sdata_lock(sdata);
- __ieee80211_request_smps_mgd(sdata, sdata->u.mgd.req_smps);
+ __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
sdata_unlock(sdata);
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
@@ -2962,55 +2860,35 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
container_of(work, struct ieee80211_sub_if_data,
csa_finalize_work);
struct ieee80211_local *local = sdata->local;
- int err, changed = 0;
+ int err, changed;
if (!ieee80211_sdata_running(sdata))
return;
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
+ return;
+
sdata->radar_required = sdata->csa_radar_required;
err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
&changed);
if (WARN_ON(err < 0))
return;
- if (!local->use_chanctx) {
- local->_oper_chandef = local->csa_chandef;
- ieee80211_hw_config(local, 0);
- }
-
- ieee80211_bss_info_change_notify(sdata, changed);
-
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_AP:
- err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
- if (err < 0)
- return;
- changed |= err;
- kfree(sdata->u.ap.next_beacon);
- sdata->u.ap.next_beacon = NULL;
-
- ieee80211_bss_info_change_notify(sdata, err);
- break;
- case NL80211_IFTYPE_ADHOC:
- ieee80211_ibss_finish_csa(sdata);
- break;
-#ifdef CONFIG_MAC80211_MESH
- case NL80211_IFTYPE_MESH_POINT:
- err = ieee80211_mesh_finish_csa(sdata);
- if (err < 0)
- return;
- break;
-#endif
- default:
- WARN_ON(1);
+ err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
+ if (err < 0)
return;
- }
+
+ changed |= err;
+ kfree(sdata->u.ap.next_beacon);
+ sdata->u.ap.next_beacon = NULL;
sdata->vif.csa_active = false;
ieee80211_wake_queues_by_reason(&sdata->local->hw,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
+ ieee80211_bss_info_change_notify(sdata, changed);
+
cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
}
@@ -3021,7 +2899,6 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
- struct ieee80211_if_mesh __maybe_unused *ifmsh;
int err, num_chanctx;
if (!list_empty(&local->roc_list) || local->scanning)
@@ -3059,76 +2936,20 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
if (sdata->vif.csa_active)
return -EBUSY;
+ /* only handle AP for now. */
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
- sdata->csa_counter_offset_beacon =
- params->counter_offset_beacon;
- sdata->csa_counter_offset_presp = params->counter_offset_presp;
- sdata->u.ap.next_beacon =
- cfg80211_beacon_dup(&params->beacon_after);
- if (!sdata->u.ap.next_beacon)
- return -ENOMEM;
-
- err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
- if (err < 0) {
- kfree(sdata->u.ap.next_beacon);
- return err;
- }
break;
- case NL80211_IFTYPE_ADHOC:
- if (!sdata->vif.bss_conf.ibss_joined)
- return -EINVAL;
-
- if (params->chandef.width != sdata->u.ibss.chandef.width)
- return -EINVAL;
-
- switch (params->chandef.width) {
- case NL80211_CHAN_WIDTH_40:
- if (cfg80211_get_chandef_type(&params->chandef) !=
- cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
- return -EINVAL;
- case NL80211_CHAN_WIDTH_5:
- case NL80211_CHAN_WIDTH_10:
- case NL80211_CHAN_WIDTH_20_NOHT:
- case NL80211_CHAN_WIDTH_20:
- break;
- default:
- return -EINVAL;
- }
-
- /* changes into another band are not supported */
- if (sdata->u.ibss.chandef.chan->band !=
- params->chandef.chan->band)
- return -EINVAL;
-
- err = ieee80211_ibss_csa_beacon(sdata, params);
- if (err < 0)
- return err;
- break;
-#ifdef CONFIG_MAC80211_MESH
- case NL80211_IFTYPE_MESH_POINT:
- ifmsh = &sdata->u.mesh;
-
- if (!ifmsh->mesh_id)
- return -EINVAL;
-
- if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
- return -EINVAL;
-
- /* changes into another band are not supported */
- if (sdata->vif.bss_conf.chandef.chan->band !=
- params->chandef.chan->band)
- return -EINVAL;
-
- err = ieee80211_mesh_csa_beacon(sdata, params, true);
- if (err < 0)
- return err;
- break;
-#endif
default:
return -EOPNOTSUPP;
}
+ sdata->u.ap.next_beacon = cfg80211_beacon_dup(&params->beacon_after);
+ if (!sdata->u.ap.next_beacon)
+ return -ENOMEM;
+
+ sdata->csa_counter_offset_beacon = params->counter_offset_beacon;
+ sdata->csa_counter_offset_presp = params->counter_offset_presp;
sdata->csa_radar_required = params->radar_required;
if (params->block_tx)
@@ -3136,6 +2957,10 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
+ err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
+ if (err < 0)
+ return err;
+
local->csa_chandef = params->chandef;
sdata->vif.csa_active = true;
@@ -3189,8 +3014,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
need_offchan = true;
if (!ieee80211_is_action(mgmt->frame_control) ||
mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||
- mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED ||
- mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
+ mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED)
break;
rcu_read_lock();
sta = sta_info_get(sdata, mgmt->da);
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 03ba6b5..3a4764b 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -453,6 +453,11 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
drv_change_chanctx(local, ctx, chanctx_changed);
+ if (!local->use_chanctx) {
+ local->_oper_chandef = *chandef;
+ ieee80211_hw_config(local, 0);
+ }
+
ieee80211_recalc_chanctx_chantype(local, ctx);
ieee80211_recalc_smps_chanctx(local, ctx);
ieee80211_recalc_radar_chanctx(local, ctx);
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 493d680..4ccc5ed 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -44,12 +44,6 @@
#define MAC80211_MESH_SYNC_DEBUG 0
#endif
-#ifdef CONFIG_MAC80211_MESH_CSA_DEBUG
-#define MAC80211_MESH_CSA_DEBUG 1
-#else
-#define MAC80211_MESH_CSA_DEBUG 0
-#endif
-
#ifdef CONFIG_MAC80211_MESH_PS_DEBUG
#define MAC80211_MESH_PS_DEBUG 1
#else
@@ -163,10 +157,6 @@ do { \
_sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \
sdata, fmt, ##__VA_ARGS__)
-#define mcsa_dbg(sdata, fmt, ...) \
- _sdata_dbg(MAC80211_MESH_CSA_DEBUG, \
- sdata, fmt, ##__VA_ARGS__)
-
#define mps_dbg(sdata, fmt, ...) \
_sdata_dbg(MAC80211_MESH_PS_DEBUG, \
sdata, fmt, ##__VA_ARGS__)
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 5c090e4..b0e32d6 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -103,57 +103,54 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf,
if (!buf)
return 0;
- sf += scnprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);
+ sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);
if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
- sf += scnprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");
+ sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
- sf += scnprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n");
+ sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n");
if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)
- sf += scnprintf(buf + sf, mxln - sf,
- "HOST_BCAST_PS_BUFFERING\n");
+ sf += snprintf(buf + sf, mxln - sf,
+ "HOST_BCAST_PS_BUFFERING\n");
if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)
- sf += scnprintf(buf + sf, mxln - sf,
- "2GHZ_SHORT_SLOT_INCAPABLE\n");
+ sf += snprintf(buf + sf, mxln - sf,
+ "2GHZ_SHORT_SLOT_INCAPABLE\n");
if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)
- sf += scnprintf(buf + sf, mxln - sf,
- "2GHZ_SHORT_PREAMBLE_INCAPABLE\n");
+ sf += snprintf(buf + sf, mxln - sf,
+ "2GHZ_SHORT_PREAMBLE_INCAPABLE\n");
if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
- sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");
+ sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");
if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
- sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");
+ sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");
if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC)
- sf += scnprintf(buf + sf, mxln - sf,
- "NEED_DTIM_BEFORE_ASSOC\n");
+ sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_BEFORE_ASSOC\n");
if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)
- sf += scnprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");
+ sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");
if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)
- sf += scnprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");
+ sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");
if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS)
- sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");
if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
- sf += scnprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");
+ sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
- sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE)
- sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
+ sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS)
- sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n");
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n");
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
- sf += scnprintf(buf + sf, mxln - sf,
- "SUPPORTS_DYNAMIC_SMPS\n");
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n");
if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
- sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");
if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
- sf += scnprintf(buf + sf, mxln - sf,
- "REPORTS_TX_ACK_STATUS\n");
+ sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n");
if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
- sf += scnprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n");
+ sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n");
if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)
- sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");
+ sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");
if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
- sf += scnprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");
+ sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");
if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)
- sf += scnprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n");
+ sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n");
rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
kfree(buf);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 04b5a14..cafe614 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -224,15 +224,12 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
smps_mode == IEEE80211_SMPS_AUTOMATIC))
return -EINVAL;
- if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- sdata->vif.type != NL80211_IFTYPE_AP)
+ /* supported only on managed interfaces for now */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EOPNOTSUPP;
sdata_lock(sdata);
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- err = __ieee80211_request_smps_mgd(sdata, smps_mode);
- else
- err = __ieee80211_request_smps_ap(sdata, smps_mode);
+ err = __ieee80211_request_smps(sdata, smps_mode);
sdata_unlock(sdata);
return err;
@@ -248,15 +245,12 @@ static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
char *buf, int buflen)
{
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- return snprintf(buf, buflen, "request: %s\nused: %s\n",
- smps_modes[sdata->u.mgd.req_smps],
- smps_modes[sdata->smps_mode]);
- if (sdata->vif.type == NL80211_IFTYPE_AP)
- return snprintf(buf, buflen, "request: %s\nused: %s\n",
- smps_modes[sdata->u.ap.req_smps],
- smps_modes[sdata->smps_mode]);
- return -EINVAL;
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return -EOPNOTSUPP;
+
+ return snprintf(buf, buflen, "request: %s\nused: %s\n",
+ smps_modes[sdata->u.mgd.req_smps],
+ smps_modes[sdata->smps_mode]);
}
static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
@@ -569,7 +563,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(num_mcast_sta);
- DEBUGFS_ADD_MODE(smps, 0600);
DEBUGFS_ADD(num_sta_ps);
DEBUGFS_ADD(dtim_count);
DEBUGFS_ADD(num_buffered_multicast);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 5d03c47..b3ea11f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1085,31 +1085,4 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata,
}
}
-static inline int drv_join_ibss(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
-{
- int ret = 0;
-
- might_sleep();
- check_sdata_in_driver(sdata);
-
- trace_drv_join_ibss(local, sdata, &sdata->vif.bss_conf);
- if (local->ops->join_ibss)
- ret = local->ops->join_ibss(&local->hw, &sdata->vif);
- trace_drv_return_int(local, ret);
- return ret;
-}
-
-static inline void drv_leave_ibss(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
-{
- might_sleep();
- check_sdata_in_driver(sdata);
-
- trace_drv_leave_ibss(local, sdata);
- if (local->ops->leave_ibss)
- local->ops->leave_ibss(&local->hw, &sdata->vif);
- trace_drv_return_void(local);
-}
-
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 9a8be8f..529bf58 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -448,25 +448,14 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
return 0;
}
-void ieee80211_request_smps_mgd_work(struct work_struct *work)
+void ieee80211_request_smps_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data,
u.mgd.request_smps_work);
sdata_lock(sdata);
- __ieee80211_request_smps_mgd(sdata, sdata->u.mgd.driver_smps_mode);
- sdata_unlock(sdata);
-}
-
-void ieee80211_request_smps_ap_work(struct work_struct *work)
-{
- struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data,
- u.ap.request_smps_work);
-
- sdata_lock(sdata);
- __ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode);
+ __ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode);
sdata_unlock(sdata);
}
@@ -475,29 +464,19 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION &&
- vif->type != NL80211_IFTYPE_AP))
+ if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
return;
if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
smps_mode = IEEE80211_SMPS_AUTOMATIC;
- if (vif->type == NL80211_IFTYPE_STATION) {
- if (sdata->u.mgd.driver_smps_mode == smps_mode)
- return;
- sdata->u.mgd.driver_smps_mode = smps_mode;
- ieee80211_queue_work(&sdata->local->hw,
- &sdata->u.mgd.request_smps_work);
- } else {
- /* AUTOMATIC is meaningless in AP mode */
- if (WARN_ON_ONCE(smps_mode == IEEE80211_SMPS_AUTOMATIC))
- return;
- if (sdata->u.ap.driver_smps_mode == smps_mode)
- return;
- sdata->u.ap.driver_smps_mode = smps_mode;
- ieee80211_queue_work(&sdata->local->hw,
- &sdata->u.ap.request_smps_work);
- }
+ if (sdata->u.mgd.driver_smps_mode == smps_mode)
+ return;
+
+ sdata->u.mgd.driver_smps_mode = smps_mode;
+
+ ieee80211_queue_work(&sdata->local->hw,
+ &sdata->u.mgd.request_smps_work);
}
/* this might change ... don't want non-open drivers using it */
EXPORT_SYMBOL_GPL(ieee80211_request_smps);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 531be04..a12afe7 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -39,8 +39,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
const int beacon_int, const u32 basic_rates,
const u16 capability, u64 tsf,
struct cfg80211_chan_def *chandef,
- bool *have_higher_than_11mbit,
- struct cfg80211_csa_settings *csa_settings)
+ bool *have_higher_than_11mbit)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
@@ -60,7 +59,6 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
2 + 8 /* max Supported Rates */ +
3 /* max DS params */ +
4 /* IBSS params */ +
- 5 /* Channel Switch Announcement */ +
2 + (IEEE80211_MAX_SUPP_RATES - 8) +
2 + sizeof(struct ieee80211_ht_cap) +
2 + sizeof(struct ieee80211_ht_operation) +
@@ -137,16 +135,6 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
*pos++ = 0;
*pos++ = 0;
- if (csa_settings) {
- *pos++ = WLAN_EID_CHANNEL_SWITCH;
- *pos++ = 3;
- *pos++ = csa_settings->block_tx ? 1 : 0;
- *pos++ = ieee80211_frequency_to_channel(
- csa_settings->chandef.chan->center_freq);
- sdata->csa_counter_offset_beacon = (pos - presp->head);
- *pos++ = csa_settings->count;
- }
-
/* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */
if (rates_n > 8) {
*pos++ = WLAN_EID_EXT_SUPP_RATES;
@@ -229,8 +217,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct beacon_data *presp;
enum nl80211_bss_scan_width scan_width;
bool have_higher_than_11mbit;
- bool radar_required = false;
- int err;
sdata_assert_lock(sdata);
@@ -249,7 +235,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_IBSS |
BSS_CHANGED_BEACON_ENABLED);
- drv_leave_ibss(local, sdata);
}
presp = rcu_dereference_protected(ifibss->presp,
@@ -274,23 +259,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
}
chandef.width = NL80211_CHAN_WIDTH_20;
chandef.center_freq1 = chan->center_freq;
- /* check again for downgraded chandef */
- if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
- sdata_info(sdata,
- "Failed to join IBSS, beacons forbidden\n");
- return;
- }
- }
-
- err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
- &chandef);
- if (err > 0) {
- if (!ifibss->userspace_handles_dfs) {
- sdata_info(sdata,
- "Failed to join IBSS, DFS channel without control program\n");
- return;
- }
- radar_required = true;
}
ieee80211_vif_release_channel(sdata);
@@ -308,14 +276,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,
capability, tsf, &chandef,
- &have_higher_than_11mbit, NULL);
+ &have_higher_than_11mbit);
if (!presp)
return;
rcu_assign_pointer(ifibss->presp, presp);
mgmt = (void *)presp->head;
- sdata->radar_required = radar_required;
sdata->vif.bss_conf.enable_beacon = true;
sdata->vif.bss_conf.beacon_int = beacon_int;
sdata->vif.bss_conf.basic_rates = basic_rates;
@@ -350,27 +317,12 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
- ieee80211_set_wmm_default(sdata, true);
-
sdata->vif.bss_conf.ibss_joined = true;
sdata->vif.bss_conf.ibss_creator = creator;
-
- err = drv_join_ibss(local, sdata);
- if (err) {
- sdata->vif.bss_conf.ibss_joined = false;
- sdata->vif.bss_conf.ibss_creator = false;
- sdata->vif.bss_conf.enable_beacon = false;
- sdata->vif.bss_conf.ssid_len = 0;
- RCU_INIT_POINTER(ifibss->presp, NULL);
- kfree_rcu(presp, rcu_head);
- ieee80211_vif_release_channel(sdata);
- sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",
- err);
- return;
- }
-
ieee80211_bss_info_change_notify(sdata, bss_change);
+ ieee80211_set_wmm_default(sdata, true);
+
ifibss->state = IEEE80211_IBSS_MLME_JOINED;
mod_timer(&ifibss->timer,
round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
@@ -464,115 +416,6 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
tsf, false);
}
-int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_csa_settings *csa_settings)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- struct beacon_data *presp, *old_presp;
- struct cfg80211_bss *cbss;
- const struct cfg80211_bss_ies *ies;
- u16 capability;
- u64 tsf;
- int ret = 0;
-
- sdata_assert_lock(sdata);
-
- capability = WLAN_CAPABILITY_IBSS;
-
- if (ifibss->privacy)
- capability |= WLAN_CAPABILITY_PRIVACY;
-
- cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan,
- ifibss->bssid, ifibss->ssid,
- ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
- WLAN_CAPABILITY_PRIVACY,
- capability);
-
- if (WARN_ON(!cbss)) {
- ret = -EINVAL;
- goto out;
- }
-
- rcu_read_lock();
- ies = rcu_dereference(cbss->ies);
- tsf = ies->tsf;
- rcu_read_unlock();
- cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
-
- old_presp = rcu_dereference_protected(ifibss->presp,
- lockdep_is_held(&sdata->wdev.mtx));
-
- presp = ieee80211_ibss_build_presp(sdata,
- sdata->vif.bss_conf.beacon_int,
- sdata->vif.bss_conf.basic_rates,
- capability, tsf, &ifibss->chandef,
- NULL, csa_settings);
- if (!presp) {
- ret = -ENOMEM;
- goto out;
- }
-
- rcu_assign_pointer(ifibss->presp, presp);
- if (old_presp)
- kfree_rcu(old_presp, rcu_head);
-
- /* it might not send the beacon for a while. send an action frame
- * immediately to announce the channel switch.
- */
- if (csa_settings)
- ieee80211_send_action_csa(sdata, csa_settings);
-
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
- out:
- return ret;
-}
-
-int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- struct cfg80211_bss *cbss;
- int err;
- u16 capability;
-
- sdata_lock(sdata);
- /* update cfg80211 bss information with the new channel */
- if (!is_zero_ether_addr(ifibss->bssid)) {
- capability = WLAN_CAPABILITY_IBSS;
-
- if (ifibss->privacy)
- capability |= WLAN_CAPABILITY_PRIVACY;
-
- cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
- ifibss->chandef.chan,
- ifibss->bssid, ifibss->ssid,
- ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
- WLAN_CAPABILITY_PRIVACY,
- capability);
- /* XXX: should not really modify cfg80211 data */
- if (cbss) {
- cbss->channel = sdata->local->csa_chandef.chan;
- cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
- }
- }
-
- ifibss->chandef = sdata->local->csa_chandef;
-
- /* generate the beacon */
- err = ieee80211_ibss_csa_beacon(sdata, NULL);
- sdata_unlock(sdata);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-
- cancel_work_sync(&ifibss->csa_connection_drop_work);
-}
-
static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
__acquires(RCU)
{
@@ -656,315 +499,6 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
return ieee80211_ibss_finish_sta(sta);
}
-static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_local *local = sdata->local;
- int active = 0;
- struct sta_info *sta;
-
- sdata_assert_lock(sdata);
-
- rcu_read_lock();
-
- list_for_each_entry_rcu(sta, &local->sta_list, list) {
- if (sta->sdata == sdata &&
- time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
- jiffies)) {
- active++;
- break;
- }
- }
-
- rcu_read_unlock();
-
- return active;
-}
-
-static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- struct ieee80211_local *local = sdata->local;
- struct cfg80211_bss *cbss;
- struct beacon_data *presp;
- struct sta_info *sta;
- int active_ibss;
- u16 capability;
-
- active_ibss = ieee80211_sta_active_ibss(sdata);
-
- if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
- capability = WLAN_CAPABILITY_IBSS;
-
- if (ifibss->privacy)
- capability |= WLAN_CAPABILITY_PRIVACY;
-
- cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
- ifibss->bssid, ifibss->ssid,
- ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
- WLAN_CAPABILITY_PRIVACY,
- capability);
-
- if (cbss) {
- cfg80211_unlink_bss(local->hw.wiphy, cbss);
- cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
- }
- }
-
- ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
-
- sta_info_flush(sdata);
-
- spin_lock_bh(&ifibss->incomplete_lock);
- while (!list_empty(&ifibss->incomplete_stations)) {
- sta = list_first_entry(&ifibss->incomplete_stations,
- struct sta_info, list);
- list_del(&sta->list);
- spin_unlock_bh(&ifibss->incomplete_lock);
-
- sta_info_free(local, sta);
- spin_lock_bh(&ifibss->incomplete_lock);
- }
- spin_unlock_bh(&ifibss->incomplete_lock);
-
- netif_carrier_off(sdata->dev);
-
- sdata->vif.bss_conf.ibss_joined = false;
- sdata->vif.bss_conf.ibss_creator = false;
- sdata->vif.bss_conf.enable_beacon = false;
- sdata->vif.bss_conf.ssid_len = 0;
-
- /* remove beacon */
- presp = rcu_dereference_protected(ifibss->presp,
- lockdep_is_held(&sdata->wdev.mtx));
- RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
- if (presp)
- kfree_rcu(presp, rcu_head);
-
- clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
- BSS_CHANGED_IBSS);
- drv_leave_ibss(local, sdata);
- ieee80211_vif_release_channel(sdata);
-}
-
-static void ieee80211_csa_connection_drop_work(struct work_struct *work)
-{
- struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data,
- u.ibss.csa_connection_drop_work);
-
- ieee80211_ibss_disconnect(sdata);
- synchronize_rcu();
- skb_queue_purge(&sdata->skb_queue);
-
- /* trigger a scan to find another IBSS network to join */
- ieee80211_queue_work(&sdata->local->hw, &sdata->work);
-}
-
-static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- int err;
-
- /* if the current channel is a DFS channel, mark the channel as
- * unavailable.
- */
- err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
- &ifibss->chandef);
- if (err > 0)
- cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef,
- GFP_ATOMIC);
-}
-
-static bool
-ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
- struct ieee802_11_elems *elems,
- bool beacon)
-{
- struct cfg80211_csa_settings params;
- struct ieee80211_csa_ie csa_ie;
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- struct ieee80211_chanctx_conf *chanctx_conf;
- struct ieee80211_chanctx *chanctx;
- enum nl80211_channel_type ch_type;
- int err, num_chanctx;
- u32 sta_flags;
-
- if (sdata->vif.csa_active)
- return true;
-
- if (!sdata->vif.bss_conf.ibss_joined)
- return false;
-
- sta_flags = IEEE80211_STA_DISABLE_VHT;
- switch (ifibss->chandef.width) {
- case NL80211_CHAN_WIDTH_5:
- case NL80211_CHAN_WIDTH_10:
- case NL80211_CHAN_WIDTH_20_NOHT:
- sta_flags |= IEEE80211_STA_DISABLE_HT;
- /* fall through */
- case NL80211_CHAN_WIDTH_20:
- sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
- break;
- default:
- break;
- }
-
- memset(&params, 0, sizeof(params));
- memset(&csa_ie, 0, sizeof(csa_ie));
- err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
- ifibss->chandef.chan->band,
- sta_flags, ifibss->bssid, &csa_ie);
- /* can't switch to destination channel, fail */
- if (err < 0)
- goto disconnect;
-
- /* did not contain a CSA */
- if (err)
- return false;
-
- params.count = csa_ie.count;
- params.chandef = csa_ie.chandef;
-
- if (ifibss->chandef.chan->band != params.chandef.chan->band)
- goto disconnect;
-
- switch (ifibss->chandef.width) {
- case NL80211_CHAN_WIDTH_20_NOHT:
- case NL80211_CHAN_WIDTH_20:
- case NL80211_CHAN_WIDTH_40:
- /* keep our current HT mode (HT20/HT40+/HT40-), even if
- * another mode has been announced. The mode is not adopted
- * within the beacon while doing CSA and we should therefore
- * keep the mode which we announce.
- */
- ch_type = cfg80211_get_chandef_type(&ifibss->chandef);
- cfg80211_chandef_create(&params.chandef, params.chandef.chan,
- ch_type);
- break;
- case NL80211_CHAN_WIDTH_5:
- case NL80211_CHAN_WIDTH_10:
- if (params.chandef.width != ifibss->chandef.width) {
- sdata_info(sdata,
- "IBSS %pM received channel switch from incompatible channel width (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
- ifibss->bssid,
- params.chandef.chan->center_freq,
- params.chandef.width,
- params.chandef.center_freq1,
- params.chandef.center_freq2);
- goto disconnect;
- }
- break;
- default:
- /* should not happen, sta_flags should prevent VHT modes. */
- WARN_ON(1);
- goto disconnect;
- }
-
- if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef)) {
- sdata_info(sdata,
- "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
- ifibss->bssid,
- params.chandef.chan->center_freq,
- params.chandef.width,
- params.chandef.center_freq1,
- params.chandef.center_freq2);
- goto disconnect;
- }
-
- err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
- &params.chandef);
- if (err < 0)
- goto disconnect;
- if (err) {
- /* IBSS-DFS only allowed with a control program */
- if (!ifibss->userspace_handles_dfs)
- goto disconnect;
-
- params.radar_required = true;
- }
-
- rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
- if (!chanctx_conf) {
- rcu_read_unlock();
- goto disconnect;
- }
-
- /* don't handle for multi-VIF cases */
- chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
- if (chanctx->refcount > 1) {
- rcu_read_unlock();
- goto disconnect;
- }
- num_chanctx = 0;
- list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
- num_chanctx++;
-
- if (num_chanctx > 1) {
- rcu_read_unlock();
- goto disconnect;
- }
- rcu_read_unlock();
-
- /* all checks done, now perform the channel switch. */
- ibss_dbg(sdata,
- "received channel switch announcement to go to channel %d MHz\n",
- params.chandef.chan->center_freq);
-
- params.block_tx = !!csa_ie.mode;
-
- ieee80211_ibss_csa_beacon(sdata, &params);
- sdata->csa_radar_required = params.radar_required;
-
- if (params.block_tx)
- ieee80211_stop_queues_by_reason(&sdata->local->hw,
- IEEE80211_MAX_QUEUE_MAP,
- IEEE80211_QUEUE_STOP_REASON_CSA);
-
- sdata->local->csa_chandef = params.chandef;
- sdata->vif.csa_active = true;
-
- ieee80211_bss_info_change_notify(sdata, err);
- drv_channel_switch_beacon(sdata, &params.chandef);
-
- ieee80211_ibss_csa_mark_radar(sdata);
-
- return true;
-disconnect:
- ibss_dbg(sdata, "Can't handle channel switch, disconnect\n");
- ieee80211_queue_work(&sdata->local->hw,
- &ifibss->csa_connection_drop_work);
-
- ieee80211_ibss_csa_mark_radar(sdata);
-
- return true;
-}
-
-static void
-ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt, size_t len,
- struct ieee80211_rx_status *rx_status,
- struct ieee802_11_elems *elems)
-{
- int required_len;
-
- if (len < IEEE80211_MIN_ACTION_SIZE + 1)
- return;
-
- /* CSA is the only action we handle for now */
- if (mgmt->u.action.u.measurement.action_code !=
- WLAN_ACTION_SPCT_CHL_SWITCH)
- return;
-
- required_len = IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.chan_switch);
- if (len < required_len)
- return;
-
- ieee80211_ibss_process_chanswitch(sdata, elems, false);
-}
-
static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len)
@@ -1127,6 +661,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
/* check if we need to merge IBSS */
+ /* we use a fixed BSSID */
+ if (sdata->u.ibss.fixed_bssid)
+ goto put_bss;
+
/* not an IBSS */
if (!(cbss->capability & WLAN_CAPABILITY_IBSS))
goto put_bss;
@@ -1142,18 +680,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.ssid_len))
goto put_bss;
- /* process channel switch */
- if (ieee80211_ibss_process_chanswitch(sdata, elems, true))
- goto put_bss;
-
/* same BSSID */
if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid))
goto put_bss;
- /* we use a fixed BSSID */
- if (sdata->u.ibss.fixed_bssid)
- goto put_bss;
-
if (ieee80211_have_rx_timestamp(rx_status)) {
/* time when timestamp field was received */
rx_timestamp =
@@ -1245,6 +775,30 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
ieee80211_queue_work(&local->hw, &sdata->work);
}
+static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ int active = 0;
+ struct sta_info *sta;
+
+ sdata_assert_lock(sdata);
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (sta->sdata == sdata &&
+ time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
+ jiffies)) {
+ active++;
+ break;
+ }
+ }
+
+ rcu_read_unlock();
+
+ return active;
+}
+
static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
@@ -1522,8 +1076,6 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct ieee80211_rx_status *rx_status;
struct ieee80211_mgmt *mgmt;
u16 fc;
- struct ieee802_11_elems elems;
- int ies_len;
rx_status = IEEE80211_SKB_RXCB(skb);
mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -1549,27 +1101,6 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
case IEEE80211_STYPE_DEAUTH:
ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len);
break;
- case IEEE80211_STYPE_ACTION:
- switch (mgmt->u.action.category) {
- case WLAN_CATEGORY_SPECTRUM_MGMT:
- ies_len = skb->len -
- offsetof(struct ieee80211_mgmt,
- u.action.u.chan_switch.variable);
-
- if (ies_len < 0)
- break;
-
- ieee802_11_parse_elems(
- mgmt->u.action.u.chan_switch.variable,
- ies_len, true, &elems);
-
- if (elems.parse_error)
- break;
-
- ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
- rx_status, &elems);
- break;
- }
}
mgmt_out:
@@ -1636,8 +1167,6 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
(unsigned long) sdata);
INIT_LIST_HEAD(&ifibss->incomplete_stations);
spin_lock_init(&ifibss->incomplete_lock);
- INIT_WORK(&ifibss->csa_connection_drop_work,
- ieee80211_csa_connection_drop_work);
}
/* scan finished notification */
@@ -1673,7 +1202,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.privacy = params->privacy;
sdata->u.ibss.control_port = params->control_port;
- sdata->u.ibss.userspace_handles_dfs = params->userspace_handles_dfs;
sdata->u.ibss.basic_rates = params->basic_rates;
/* fix basic_rates if channel does not support these rates */
@@ -1737,19 +1265,73 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct ieee80211_local *local = sdata->local;
+ struct cfg80211_bss *cbss;
+ u16 capability;
+ int active_ibss;
+ struct sta_info *sta;
+ struct beacon_data *presp;
- ieee80211_ibss_disconnect(sdata);
- ifibss->ssid_len = 0;
+ active_ibss = ieee80211_sta_active_ibss(sdata);
+
+ if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
+ capability = WLAN_CAPABILITY_IBSS;
+
+ if (ifibss->privacy)
+ capability |= WLAN_CAPABILITY_PRIVACY;
+
+ cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
+ ifibss->bssid, ifibss->ssid,
+ ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+ WLAN_CAPABILITY_PRIVACY,
+ capability);
+
+ if (cbss) {
+ cfg80211_unlink_bss(local->hw.wiphy, cbss);
+ cfg80211_put_bss(local->hw.wiphy, cbss);
+ }
+ }
+
+ ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
memset(ifibss->bssid, 0, ETH_ALEN);
+ ifibss->ssid_len = 0;
+
+ sta_info_flush(sdata);
+
+ spin_lock_bh(&ifibss->incomplete_lock);
+ while (!list_empty(&ifibss->incomplete_stations)) {
+ sta = list_first_entry(&ifibss->incomplete_stations,
+ struct sta_info, list);
+ list_del(&sta->list);
+ spin_unlock_bh(&ifibss->incomplete_lock);
+
+ sta_info_free(local, sta);
+ spin_lock_bh(&ifibss->incomplete_lock);
+ }
+ spin_unlock_bh(&ifibss->incomplete_lock);
+
+ netif_carrier_off(sdata->dev);
/* remove beacon */
kfree(sdata->u.ibss.ie);
+ presp = rcu_dereference_protected(ifibss->presp,
+ lockdep_is_held(&sdata->wdev.mtx));
+ RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
/* on the next join, re-program HT parameters */
memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
+ sdata->vif.bss_conf.ibss_joined = false;
+ sdata->vif.bss_conf.ibss_creator = false;
+ sdata->vif.bss_conf.enable_beacon = false;
+ sdata->vif.bss_conf.ssid_len = 0;
+ clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_IBSS);
+ ieee80211_vif_release_channel(sdata);
synchronize_rcu();
+ kfree(presp);
skb_queue_purge(&sdata->skb_queue);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 29dc505..611abfc 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -262,10 +262,6 @@ struct ieee80211_if_ap {
struct ps_data ps;
atomic_t num_mcast_sta; /* number of stations receiving multicast */
- enum ieee80211_smps_mode req_smps, /* requested smps mode */
- driver_smps_mode; /* smps mode request */
-
- struct work_struct request_smps_work;
};
struct ieee80211_if_wds {
@@ -326,6 +322,7 @@ struct ieee80211_roc_work {
/* flags used in struct ieee80211_if_managed.flags */
enum ieee80211_sta_flags {
+ IEEE80211_STA_BEACON_POLL = BIT(0),
IEEE80211_STA_CONNECTION_POLL = BIT(1),
IEEE80211_STA_CONTROL_PORT = BIT(2),
IEEE80211_STA_DISABLE_HT = BIT(4),
@@ -338,7 +335,6 @@ enum ieee80211_sta_flags {
IEEE80211_STA_DISABLE_VHT = BIT(11),
IEEE80211_STA_DISABLE_80P80MHZ = BIT(12),
IEEE80211_STA_DISABLE_160MHZ = BIT(13),
- IEEE80211_STA_DISABLE_WMM = BIT(14),
};
struct ieee80211_mgd_auth_data {
@@ -491,7 +487,6 @@ struct ieee80211_if_managed {
struct ieee80211_if_ibss {
struct timer_list timer;
- struct work_struct csa_connection_drop_work;
unsigned long last_scan_completed;
@@ -502,7 +497,6 @@ struct ieee80211_if_ibss {
bool privacy;
bool control_port;
- bool userspace_handles_dfs;
u8 bssid[ETH_ALEN] __aligned(2);
u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -544,11 +538,6 @@ struct ieee80211_mesh_sync_ops {
/* add other framework functions here */
};
-struct mesh_csa_settings {
- struct rcu_head rcu_head;
- struct cfg80211_csa_settings settings;
-};
-
struct ieee80211_if_mesh {
struct timer_list housekeeping_timer;
struct timer_list mesh_path_timer;
@@ -609,11 +598,6 @@ struct ieee80211_if_mesh {
int ps_peers_light_sleep;
int ps_peers_deep_sleep;
struct ps_data ps;
- /* Channel Switching Support */
- struct mesh_csa_settings __rcu *csa;
- bool chsw_init;
- u8 chsw_ttl;
- u16 pre_value;
};
#ifdef CONFIG_MAC80211_MESH
@@ -1222,14 +1206,6 @@ struct ieee80211_ra_tid {
u16 tid;
};
-/* this struct holds the value parsing from channel switch IE */
-struct ieee80211_csa_ie {
- struct cfg80211_chan_def chandef;
- u8 mode;
- u8 count;
- u8 ttl;
-};
-
/* Parsed Information Elements */
struct ieee802_11_elems {
const u8 *ie_start;
@@ -1266,7 +1242,6 @@ struct ieee802_11_elems {
const struct ieee80211_timeout_interval_ie *timeout_int;
const u8 *opmode_notif;
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
- const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
/* length of them, respectively */
u8 ssid_len;
@@ -1358,19 +1333,11 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
-int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_csa_settings *csa_settings);
-int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);
-void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
/* mesh code */
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
-int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_csa_settings *csa_settings,
- bool csa_action);
-int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata);
/* scan/BSS handling */
void ieee80211_scan_work(struct work_struct *work);
@@ -1467,10 +1434,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps, const u8 *da,
const u8 *bssid);
-void ieee80211_request_smps_ap_work(struct work_struct *work);
-void ieee80211_request_smps_mgd_work(struct work_struct *work);
-bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
- enum ieee80211_smps_mode smps_mode_new);
+void ieee80211_request_smps_work(struct work_struct *work);
void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
u16 initiator, u16 reason, bool stop);
@@ -1520,28 +1484,6 @@ void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len);
-/**
- * ieee80211_parse_ch_switch_ie - parses channel switch IEs
- * @sdata: the sdata of the interface which has received the frame
- * @elems: parsed 802.11 elements received with the frame
- * @beacon: indicates if the frame was a beacon or probe response
- * @current_band: indicates the current band
- * @sta_flags: contains information about own capabilities and restrictions
- * to decide which channel switch announcements can be accepted. Only the
- * following subset of &enum ieee80211_sta_flags are evaluated:
- * %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT,
- * %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ,
- * %IEEE80211_STA_DISABLE_160MHZ.
- * @bssid: the currently connected bssid (for reporting)
- * @csa_ie: parsed 802.11 csa elements on count, mode, chandef and mesh ttl.
- All of them will be filled with if success only.
- * Return: 0 on success, <0 on error and >0 if there is nothing to parse.
- */
-int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
- struct ieee802_11_elems *elems, bool beacon,
- enum ieee80211_band current_band,
- u32 sta_flags, u8 *bssid,
- struct ieee80211_csa_ie *csa_ie);
/* Suspend/resume and hw reconfiguration */
int ieee80211_reconfig(struct ieee80211_local *local);
@@ -1687,10 +1629,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems,
enum ieee80211_band band, u32 *basic_rates);
-int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_smps_mode smps_mode);
-int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_smps_mode smps_mode);
+int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_smps_mode smps_mode);
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
@@ -1717,7 +1657,6 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
const struct ieee80211_ht_operation *ht_oper,
struct cfg80211_chan_def *chandef);
-u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
int __must_check
ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
@@ -1746,8 +1685,6 @@ void ieee80211_dfs_cac_timer(unsigned long data);
void ieee80211_dfs_cac_timer_work(struct work_struct *work);
void ieee80211_dfs_cac_cancel(struct ieee80211_local *local);
void ieee80211_dfs_radar_detected_work(struct work_struct *work);
-int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_csa_settings *csa_settings);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index ff101ea..fcecd63 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -766,10 +766,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_mgd_stop(sdata);
- if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- ieee80211_ibss_stop(sdata);
-
-
/*
* Remove all stations associated with this interface.
*
@@ -1293,10 +1289,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP:
skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
INIT_LIST_HEAD(&sdata->u.ap.vlans);
- INIT_WORK(&sdata->u.ap.request_smps_work,
- ieee80211_request_smps_ap_work);
sdata->vif.bss_conf.bssid = sdata->vif.addr;
- sdata->u.ap.req_smps = IEEE80211_SMPS_OFF;
break;
case NL80211_IFTYPE_P2P_CLIENT:
type = NL80211_IFTYPE_STATION;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 3e51dd7..620677e 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -879,7 +879,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
keyconf->keylen, keyconf->key,
0, NULL);
if (IS_ERR(key))
- return ERR_CAST(key);
+ return ERR_PTR(PTR_ERR(key));
if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)
key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index aaae0ed..036d57e 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -83,7 +83,7 @@ struct ieee80211_key {
* Management frames.
*/
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
- struct crypto_aead *tfm;
+ struct crypto_cipher *tfm;
u32 replays; /* dot11RSNAStatsCCMPReplays */
} ccmp;
struct {
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 896fe3b..707ac61 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -12,7 +12,6 @@
#include <asm/unaligned.h>
#include "ieee80211_i.h"
#include "mesh.h"
-#include "driver-ops.h"
static int mesh_allocated;
static struct kmem_cache *rm_cache;
@@ -611,7 +610,6 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
struct ieee80211_chanctx_conf *chanctx_conf;
- struct mesh_csa_settings *csa;
enum ieee80211_band band;
u8 *pos;
struct ieee80211_sub_if_data *sdata;
@@ -626,10 +624,6 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
head_len = hdr_len +
2 + /* NULL SSID */
- /* Channel Switch Announcement */
- 2 + sizeof(struct ieee80211_channel_sw_ie) +
- /* Mesh Channel Swith Parameters */
- 2 + sizeof(struct ieee80211_mesh_chansw_params_ie) +
2 + 8 + /* supported rates */
2 + 3; /* DS params */
tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
@@ -671,38 +665,6 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;
- rcu_read_lock();
- csa = rcu_dereference(ifmsh->csa);
- if (csa) {
- __le16 pre_value;
-
- pos = skb_put(skb, 13);
- memset(pos, 0, 13);
- *pos++ = WLAN_EID_CHANNEL_SWITCH;
- *pos++ = 3;
- *pos++ = 0x0;
- *pos++ = ieee80211_frequency_to_channel(
- csa->settings.chandef.chan->center_freq);
- sdata->csa_counter_offset_beacon = hdr_len + 6;
- *pos++ = csa->settings.count;
- *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
- *pos++ = 6;
- if (ifmsh->chsw_init) {
- *pos++ = ifmsh->mshcfg.dot11MeshTTL;
- *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
- } else {
- *pos++ = ifmsh->chsw_ttl;
- }
- *pos++ |= csa->settings.block_tx ?
- WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
- put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
- pos += 2;
- pre_value = cpu_to_le16(ifmsh->pre_value);
- memcpy(pos, &pre_value, 2);
- pos += 2;
- }
- rcu_read_unlock();
-
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
mesh_add_ds_params_ie(sdata, skb))
goto out_free;
@@ -850,127 +812,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
ieee80211_configure_filter(local);
}
-static bool
-ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
- struct ieee802_11_elems *elems, bool beacon)
-{
- struct cfg80211_csa_settings params;
- struct ieee80211_csa_ie csa_ie;
- struct ieee80211_chanctx_conf *chanctx_conf;
- struct ieee80211_chanctx *chanctx;
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
- int err, num_chanctx;
- u32 sta_flags;
-
- if (sdata->vif.csa_active)
- return true;
-
- if (!ifmsh->mesh_id)
- return false;
-
- sta_flags = IEEE80211_STA_DISABLE_VHT;
- switch (sdata->vif.bss_conf.chandef.width) {
- case NL80211_CHAN_WIDTH_20_NOHT:
- sta_flags |= IEEE80211_STA_DISABLE_HT;
- case NL80211_CHAN_WIDTH_20:
- sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
- break;
- default:
- break;
- }
-
- memset(&params, 0, sizeof(params));
- memset(&csa_ie, 0, sizeof(csa_ie));
- err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, band,
- sta_flags, sdata->vif.addr,
- &csa_ie);
- if (err < 0)
- return false;
- if (err)
- return false;
-
- params.chandef = csa_ie.chandef;
- params.count = csa_ie.count;
-
- if (sdata->vif.bss_conf.chandef.chan->band !=
- params.chandef.chan->band)
- return false;
-
- if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
- IEEE80211_CHAN_DISABLED)) {
- sdata_info(sdata,
- "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting\n",
- sdata->vif.addr,
- params.chandef.chan->center_freq,
- params.chandef.width,
- params.chandef.center_freq1,
- params.chandef.center_freq2);
- return false;
- }
-
- err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
- &params.chandef);
- if (err < 0)
- return false;
- if (err) {
- params.radar_required = true;
- /* TODO: DFS not (yet) supported */
- return false;
- }
-
- rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
- if (!chanctx_conf)
- goto failed_chswitch;
-
- /* don't handle for multi-VIF cases */
- chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
- if (chanctx->refcount > 1)
- goto failed_chswitch;
-
- num_chanctx = 0;
- list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
- num_chanctx++;
-
- if (num_chanctx > 1)
- goto failed_chswitch;
-
- rcu_read_unlock();
-
- mcsa_dbg(sdata,
- "received channel switch announcement to go to channel %d MHz\n",
- params.chandef.chan->center_freq);
-
- params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
- if (beacon)
- ifmsh->chsw_ttl = csa_ie.ttl - 1;
- else
- ifmsh->chsw_ttl = 0;
-
- if (ifmsh->chsw_ttl > 0)
- if (ieee80211_mesh_csa_beacon(sdata, &params, false) < 0)
- return false;
-
- sdata->csa_radar_required = params.radar_required;
-
- if (params.block_tx)
- ieee80211_stop_queues_by_reason(&sdata->local->hw,
- IEEE80211_MAX_QUEUE_MAP,
- IEEE80211_QUEUE_STOP_REASON_CSA);
-
- sdata->local->csa_chandef = params.chandef;
- sdata->vif.csa_active = true;
-
- ieee80211_bss_info_change_notify(sdata, err);
- drv_channel_switch_beacon(sdata, &params.chandef);
-
- return true;
-failed_chswitch:
- rcu_read_unlock();
- return false;
-}
-
static void
ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len)
@@ -1077,142 +918,6 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (ifmsh->sync_ops)
ifmsh->sync_ops->rx_bcn_presp(sdata,
stype, mgmt, &elems, rx_status);
-
- if (!ifmsh->chsw_init)
- ieee80211_mesh_process_chnswitch(sdata, &elems, true);
-}
-
-int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- struct mesh_csa_settings *tmp_csa_settings;
- int ret = 0;
-
- /* Reset the TTL value and Initiator flag */
- ifmsh->chsw_init = false;
- ifmsh->chsw_ttl = 0;
-
- /* Remove the CSA and MCSP elements from the beacon */
- tmp_csa_settings = rcu_dereference(ifmsh->csa);
- rcu_assign_pointer(ifmsh->csa, NULL);
- kfree_rcu(tmp_csa_settings, rcu_head);
- ret = ieee80211_mesh_rebuild_beacon(sdata);
- if (ret)
- return -EINVAL;
-
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
-
- mcsa_dbg(sdata, "complete switching to center freq %d MHz",
- sdata->vif.bss_conf.chandef.chan->center_freq);
- return 0;
-}
-
-int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_csa_settings *csa_settings,
- bool csa_action)
-{
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- struct mesh_csa_settings *tmp_csa_settings;
- int ret = 0;
-
- tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
- GFP_ATOMIC);
- if (!tmp_csa_settings)
- return -ENOMEM;
-
- memcpy(&tmp_csa_settings->settings, csa_settings,
- sizeof(struct cfg80211_csa_settings));
-
- rcu_assign_pointer(ifmsh->csa, tmp_csa_settings);
-
- ret = ieee80211_mesh_rebuild_beacon(sdata);
- if (ret) {
- tmp_csa_settings = rcu_dereference(ifmsh->csa);
- rcu_assign_pointer(ifmsh->csa, NULL);
- kfree_rcu(tmp_csa_settings, rcu_head);
- return ret;
- }
-
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
-
- if (csa_action)
- ieee80211_send_action_csa(sdata, csa_settings);
-
- return 0;
-}
-
-static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt, size_t len)
-{
- struct ieee80211_mgmt *mgmt_fwd;
- struct sk_buff *skb;
- struct ieee80211_local *local = sdata->local;
- u8 *pos = mgmt->u.action.u.chan_switch.variable;
- size_t offset_ttl;
-
- skb = dev_alloc_skb(local->tx_headroom + len);
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, local->tx_headroom);
- mgmt_fwd = (struct ieee80211_mgmt *) skb_put(skb, len);
-
- /* offset_ttl is based on whether the secondary channel
- * offset is available or not. Substract 1 from the mesh TTL
- * and disable the initiator flag before forwarding.
- */
- offset_ttl = (len < 42) ? 7 : 10;
- *(pos + offset_ttl) -= 1;
- *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
- sdata->u.mesh.chsw_ttl = *(pos + offset_ttl);
-
- memcpy(mgmt_fwd, mgmt, len);
- eth_broadcast_addr(mgmt_fwd->da);
- memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN);
- memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN);
-
- ieee80211_tx_skb(sdata, skb);
- return 0;
-}
-
-static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt, size_t len)
-{
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- struct ieee802_11_elems elems;
- u16 pre_value;
- bool fwd_csa = true;
- size_t baselen;
- u8 *pos, ttl;
-
- if (mgmt->u.action.u.measurement.action_code !=
- WLAN_ACTION_SPCT_CHL_SWITCH)
- return;
-
- pos = mgmt->u.action.u.chan_switch.variable;
- baselen = offsetof(struct ieee80211_mgmt,
- u.action.u.chan_switch.variable);
- ieee802_11_parse_elems(pos, len - baselen, false, &elems);
-
- ttl = elems.mesh_chansw_params_ie->mesh_ttl;
- if (!--ttl)
- fwd_csa = false;
-
- pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
- if (ifmsh->pre_value >= pre_value)
- return;
-
- ifmsh->pre_value = pre_value;
-
- if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
- mcsa_dbg(sdata, "Failed to process CSA action frame");
- return;
- }
-
- /* forward or re-broadcast the CSA frame */
- if (fwd_csa) {
- if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
- mcsa_dbg(sdata, "Failed to forward the CSA frame");
- }
}
static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
@@ -1234,9 +939,6 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
if (mesh_action_is_path_sel(mgmt))
mesh_rx_path_sel_frame(sdata, mgmt, len);
break;
- case WLAN_CATEGORY_SPECTRUM_MGMT:
- mesh_rx_csa_frame(sdata, mgmt, len);
- break;
}
}
@@ -1354,11 +1056,13 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
(unsigned long) sdata);
ifmsh->accepting_plinks = true;
+ ifmsh->preq_id = 0;
+ ifmsh->sn = 0;
+ ifmsh->num_gates = 0;
atomic_set(&ifmsh->mpaths, 0);
mesh_rmc_init(sdata);
ifmsh->last_preq = jiffies;
ifmsh->next_perr = jiffies;
- ifmsh->chsw_init = false;
/* Allocate all mesh structures when creating the first mesh interface. */
if (!mesh_allocated)
ieee80211s_init();
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 4301aa5..6b65d50 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -222,8 +222,7 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta)
mesh_path_flush_by_nexthop(sta);
ieee80211_mps_sta_status_update(sta);
- changed |= ieee80211_mps_set_sta_local_pm(sta,
- NL80211_MESH_POWER_UNKNOWN);
+ changed |= ieee80211_mps_local_status_update(sdata);
return changed;
}
diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c
index 0f79b78..22290a9 100644
--- a/net/mac80211/mesh_ps.c
+++ b/net/mac80211/mesh_ps.c
@@ -152,9 +152,6 @@ u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta,
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
- if (sta->local_pm == pm)
- return 0;
-
mps_dbg(sdata, "local STA operates in mode %d with %pM\n",
pm, sta->sta.addr);
@@ -248,14 +245,6 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
do_buffer = (pm != NL80211_MESH_POWER_ACTIVE);
- /* clear the MPSP flags for non-peers or active STA */
- if (sta->plink_state != NL80211_PLINK_ESTAB) {
- clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
- clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT);
- } else if (!do_buffer) {
- clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
- }
-
/* Don't let the same PS state be set twice */
if (test_sta_flag(sta, WLAN_STA_PS_STA) == do_buffer)
return;
@@ -268,6 +257,14 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
} else {
ieee80211_sta_ps_deliver_wakeup(sta);
}
+
+ /* clear the MPSP flags for non-peers or active STA */
+ if (sta->plink_state != NL80211_PLINK_ESTAB) {
+ clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
+ clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT);
+ } else if (!do_buffer) {
+ clear_sta_flag(sta, WLAN_STA_MPSP_OWNER);
+ }
}
static void mps_set_sta_peer_pm(struct sta_info *sta,
@@ -447,7 +444,8 @@ static void mpsp_qos_null_append(struct sta_info *sta,
*/
static void mps_frame_deliver(struct sta_info *sta, int n_frames)
{
- struct ieee80211_local *local = sta->sdata->local;
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_local *local = sdata->local;
int ac;
struct sk_buff_head frames;
struct sk_buff *skb;
@@ -560,10 +558,10 @@ void ieee80211_mpsp_trigger_process(u8 *qc, struct sta_info *sta,
}
/**
- * ieee80211_mps_frame_release - release frames buffered due to mesh power save
+ * ieee80211_mps_frame_release - release buffered frames in response to beacon
*
* @sta: mesh STA
- * @elems: IEs of beacon or probe response
+ * @elems: beacon IEs
*
* For peers if we have individually-addressed frames buffered or the peer
* indicates buffered frames, send a corresponding MPSP trigger frame. Since
@@ -590,10 +588,9 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
(!elems->awake_window || !le16_to_cpu(*elems->awake_window)))
return;
- if (!test_sta_flag(sta, WLAN_STA_MPSP_OWNER))
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- buffer_local += skb_queue_len(&sta->ps_tx_buf[ac]) +
- skb_queue_len(&sta->tx_filtered[ac]);
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ buffer_local += skb_queue_len(&sta->ps_tx_buf[ac]) +
+ skb_queue_len(&sta->tx_filtered[ac]);
if (!has_buffered && !buffer_local)
return;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d7504ab..86e4ad5 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -145,6 +145,66 @@ static int ecw2cw(int ecw)
return (1 << ecw) - 1;
}
+static u32 chandef_downgrade(struct cfg80211_chan_def *c)
+{
+ u32 ret;
+ int tmp;
+
+ switch (c->width) {
+ case NL80211_CHAN_WIDTH_20:
+ c->width = NL80211_CHAN_WIDTH_20_NOHT;
+ ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ c->width = NL80211_CHAN_WIDTH_20;
+ c->center_freq1 = c->chan->center_freq;
+ ret = IEEE80211_STA_DISABLE_40MHZ |
+ IEEE80211_STA_DISABLE_VHT;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
+ /* n_P40 */
+ tmp /= 2;
+ /* freq_P40 */
+ c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;
+ c->width = NL80211_CHAN_WIDTH_40;
+ ret = IEEE80211_STA_DISABLE_VHT;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ c->center_freq2 = 0;
+ c->width = NL80211_CHAN_WIDTH_80;
+ ret = IEEE80211_STA_DISABLE_80P80MHZ |
+ IEEE80211_STA_DISABLE_160MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ /* n_P20 */
+ tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
+ /* n_P80 */
+ tmp /= 4;
+ c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;
+ c->width = NL80211_CHAN_WIDTH_80;
+ ret = IEEE80211_STA_DISABLE_80P80MHZ |
+ IEEE80211_STA_DISABLE_160MHZ;
+ break;
+ default:
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ WARN_ON_ONCE(1);
+ c->width = NL80211_CHAN_WIDTH_20_NOHT;
+ ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+ break;
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+ WARN_ON_ONCE(1);
+ /* keep c->width */
+ ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+ break;
+ }
+
+ WARN_ON_ONCE(!cfg80211_chandef_valid(c));
+
+ return ret;
+}
+
static u32
ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
@@ -292,7 +352,7 @@ out:
break;
}
- ret |= ieee80211_chandef_downgrade(chandef);
+ ret |= chandef_downgrade(chandef);
}
if (chandef->width != vht_chandef.width && !tracking)
@@ -346,13 +406,13 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
*/
if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
chandef.width == NL80211_CHAN_WIDTH_80P80)
- flags |= ieee80211_chandef_downgrade(&chandef);
+ flags |= chandef_downgrade(&chandef);
if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
chandef.width == NL80211_CHAN_WIDTH_160)
- flags |= ieee80211_chandef_downgrade(&chandef);
+ flags |= chandef_downgrade(&chandef);
if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
chandef.width > NL80211_CHAN_WIDTH_20)
- flags |= ieee80211_chandef_downgrade(&chandef);
+ flags |= chandef_downgrade(&chandef);
if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef))
return 0;
@@ -833,7 +893,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
- if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
ieee80211_tx_skb(sdata, skb);
@@ -876,8 +937,6 @@ static void ieee80211_chswitch_work(struct work_struct *work)
container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- u32 changed = 0;
- int ret;
if (!ieee80211_sdata_running(sdata))
return;
@@ -886,39 +945,24 @@ static void ieee80211_chswitch_work(struct work_struct *work)
if (!ifmgd->associated)
goto out;
- ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
- &changed);
- if (ret) {
- sdata_info(sdata,
- "vif channel switch failed, disconnecting\n");
- ieee80211_queue_work(&sdata->local->hw,
- &ifmgd->csa_connection_drop_work);
- goto out;
- }
+ local->_oper_chandef = local->csa_chandef;
- if (!local->use_chanctx) {
- local->_oper_chandef = local->csa_chandef;
- /* Call "hw_config" only if doing sw channel switch.
- * Otherwise update the channel directly
- */
- if (!local->ops->channel_switch)
- ieee80211_hw_config(local, 0);
- else
- local->hw.conf.chandef = local->_oper_chandef;
+ if (!local->ops->channel_switch) {
+ /* call "hw_config" only if doing sw channel switch */
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+ } else {
+ /* update the device channel directly */
+ local->hw.conf.chandef = local->_oper_chandef;
}
/* XXX: shouldn't really modify cfg80211-owned data! */
- ifmgd->associated->channel = local->csa_chandef.chan;
+ ifmgd->associated->channel = local->_oper_chandef.chan;
/* XXX: wait for a beacon first? */
ieee80211_wake_queues_by_reason(&local->hw,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
-
- ieee80211_bss_info_change_notify(sdata, changed);
-
out:
- sdata->vif.csa_active = false;
ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
sdata_unlock(sdata);
}
@@ -956,10 +1000,20 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct cfg80211_bss *cbss = ifmgd->associated;
+ struct ieee80211_bss *bss;
struct ieee80211_chanctx *chanctx;
- enum ieee80211_band current_band;
- struct ieee80211_csa_ie csa_ie;
- int res;
+ enum ieee80211_band new_band;
+ int new_freq;
+ u8 new_chan_no;
+ u8 count;
+ u8 mode;
+ struct ieee80211_channel *new_chan;
+ struct cfg80211_chan_def new_chandef = {};
+ struct cfg80211_chan_def new_vht_chandef = {};
+ const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
+ const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
+ const struct ieee80211_ht_operation *ht_oper;
+ int secondary_channel_offset = -1;
sdata_assert_lock(sdata);
@@ -973,53 +1027,181 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
return;
- current_band = cbss->channel->band;
- memset(&csa_ie, 0, sizeof(csa_ie));
- res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band,
- ifmgd->flags,
- ifmgd->associated->bssid, &csa_ie);
- if (res < 0)
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
- if (res)
+ sec_chan_offs = elems->sec_chan_offs;
+ wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
+ ht_oper = elems->ht_operation;
+
+ if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
+ IEEE80211_STA_DISABLE_40MHZ)) {
+ sec_chan_offs = NULL;
+ wide_bw_chansw_ie = NULL;
+ /* only used for bandwidth here */
+ ht_oper = NULL;
+ }
+
+ if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
+ wide_bw_chansw_ie = NULL;
+
+ if (elems->ext_chansw_ie) {
+ if (!ieee80211_operating_class_to_band(
+ elems->ext_chansw_ie->new_operating_class,
+ &new_band)) {
+ sdata_info(sdata,
+ "cannot understand ECSA IE operating class %d, disconnecting\n",
+ elems->ext_chansw_ie->new_operating_class);
+ ieee80211_queue_work(&local->hw,
+ &ifmgd->csa_connection_drop_work);
+ }
+ new_chan_no = elems->ext_chansw_ie->new_ch_num;
+ count = elems->ext_chansw_ie->count;
+ mode = elems->ext_chansw_ie->mode;
+ } else if (elems->ch_switch_ie) {
+ new_band = cbss->channel->band;
+ new_chan_no = elems->ch_switch_ie->new_ch_num;
+ count = elems->ch_switch_ie->count;
+ mode = elems->ch_switch_ie->mode;
+ } else {
+ /* nothing here we understand */
return;
+ }
- if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
- IEEE80211_CHAN_DISABLED)) {
+ bss = (void *)cbss->priv;
+
+ new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
+ new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
+ if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
sdata_info(sdata,
- "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
- ifmgd->associated->bssid,
- csa_ie.chandef.chan->center_freq,
- csa_ie.chandef.width, csa_ie.chandef.center_freq1,
- csa_ie.chandef.center_freq2);
+ "AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
+ ifmgd->associated->bssid, new_freq);
ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
return;
}
- ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
- sdata->vif.csa_active = true;
+ if (!beacon && sec_chan_offs) {
+ secondary_channel_offset = sec_chan_offs->sec_chan_offs;
+ } else if (beacon && ht_oper) {
+ secondary_channel_offset =
+ ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
+ } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+ /*
+ * If it's not a beacon, HT is enabled and the IE not present,
+ * it's 20 MHz, 802.11-2012 8.5.2.6:
+ * This element [the Secondary Channel Offset Element] is
+ * present when switching to a 40 MHz channel. It may be
+ * present when switching to a 20 MHz channel (in which
+ * case the secondary channel offset is set to SCN).
+ */
+ secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ }
- mutex_lock(&local->chanctx_mtx);
- if (local->use_chanctx) {
- u32 num_chanctx = 0;
- list_for_each_entry(chanctx, &local->chanctx_list, list)
- num_chanctx++;
+ switch (secondary_channel_offset) {
+ default:
+ /* secondary_channel_offset was present but is invalid */
+ case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+ cfg80211_chandef_create(&new_chandef, new_chan,
+ NL80211_CHAN_HT20);
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ cfg80211_chandef_create(&new_chandef, new_chan,
+ NL80211_CHAN_HT40PLUS);
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ cfg80211_chandef_create(&new_chandef, new_chan,
+ NL80211_CHAN_HT40MINUS);
+ break;
+ case -1:
+ cfg80211_chandef_create(&new_chandef, new_chan,
+ NL80211_CHAN_NO_HT);
+ /* keep width for 5/10 MHz channels */
+ switch (sdata->vif.bss_conf.chandef.width) {
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+ new_chandef.width = sdata->vif.bss_conf.chandef.width;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (wide_bw_chansw_ie) {
+ new_vht_chandef.chan = new_chan;
+ new_vht_chandef.center_freq1 =
+ ieee80211_channel_to_frequency(
+ wide_bw_chansw_ie->new_center_freq_seg0,
+ new_band);
- if (num_chanctx > 1 ||
- !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
+ switch (wide_bw_chansw_ie->new_channel_width) {
+ default:
+ /* hmmm, ignore VHT and use HT if present */
+ case IEEE80211_VHT_CHANWIDTH_USE_HT:
+ new_vht_chandef.chan = NULL;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80MHZ:
+ new_vht_chandef.width = NL80211_CHAN_WIDTH_80;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_160MHZ:
+ new_vht_chandef.width = NL80211_CHAN_WIDTH_160;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+ /* field is otherwise reserved */
+ new_vht_chandef.center_freq2 =
+ ieee80211_channel_to_frequency(
+ wide_bw_chansw_ie->new_center_freq_seg1,
+ new_band);
+ new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
+ break;
+ }
+ if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
+ new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
+ chandef_downgrade(&new_vht_chandef);
+ if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
+ new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
+ chandef_downgrade(&new_vht_chandef);
+ if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
+ new_vht_chandef.width > NL80211_CHAN_WIDTH_20)
+ chandef_downgrade(&new_vht_chandef);
+ }
+
+ /* if VHT data is there validate & use it */
+ if (new_vht_chandef.chan) {
+ if (!cfg80211_chandef_compatible(&new_vht_chandef,
+ &new_chandef)) {
sdata_info(sdata,
- "not handling chan-switch with channel contexts\n");
+ "AP %pM CSA has inconsistent channel data, disconnecting\n",
+ ifmgd->associated->bssid);
ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
- mutex_unlock(&local->chanctx_mtx);
return;
}
+ new_chandef = new_vht_chandef;
}
- if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
+ if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef,
+ IEEE80211_CHAN_DISABLED)) {
+ sdata_info(sdata,
+ "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+ ifmgd->associated->bssid, new_freq,
+ new_chandef.width, new_chandef.center_freq1,
+ new_chandef.center_freq2);
+ ieee80211_queue_work(&local->hw,
+ &ifmgd->csa_connection_drop_work);
+ return;
+ }
+
+ ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+
+ if (local->use_chanctx) {
+ sdata_info(sdata,
+ "not handling channel switch with channel contexts\n");
ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
+ return;
+ }
+
+ mutex_lock(&local->chanctx_mtx);
+ if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
mutex_unlock(&local->chanctx_mtx);
return;
}
@@ -1035,9 +1217,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
mutex_unlock(&local->chanctx_mtx);
- local->csa_chandef = csa_ie.chandef;
+ local->csa_chandef = new_chandef;
- if (csa_ie.mode)
+ if (mode)
ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -1046,9 +1228,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
/* use driver's channel switch callback */
struct ieee80211_channel_switch ch_switch = {
.timestamp = timestamp,
- .block_tx = csa_ie.mode,
- .chandef = csa_ie.chandef,
- .count = csa_ie.count,
+ .block_tx = mode,
+ .chandef = new_chandef,
+ .count = count,
};
drv_channel_switch(local, &ch_switch);
@@ -1056,11 +1238,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
/* channel switch handled in software */
- if (csa_ie.count <= 1)
+ if (count <= 1)
ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work);
else
mod_timer(&ifmgd->chswitch_timer,
- TU_TO_EXP_TIME(csa_ie.count * cbss->beacon_interval));
+ TU_TO_EXP_TIME(count * cbss->beacon_interval));
}
static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
@@ -1192,7 +1374,8 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
if (!mgd->associated)
return false;
- if (mgd->flags & IEEE80211_STA_CONNECTION_POLL)
+ if (mgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
return false;
if (!mgd->have_beacon)
@@ -1508,7 +1691,8 @@ static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
{
lockdep_assert_held(&sdata->local->mtx);
- sdata->u.mgd.flags &= ~IEEE80211_STA_CONNECTION_POLL;
+ sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+ IEEE80211_STA_BEACON_POLL);
ieee80211_run_deferred_scan(sdata->local);
}
@@ -1770,8 +1954,11 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
struct ieee80211_local *local = sdata->local;
mutex_lock(&local->mtx);
- if (!(ifmgd->flags & IEEE80211_STA_CONNECTION_POLL))
- goto out;
+ if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))) {
+ mutex_unlock(&local->mtx);
+ return;
+ }
__ieee80211_stop_poll(sdata);
@@ -1907,9 +2094,15 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
* because otherwise we would reset the timer every time and
* never check whether we received a probe response!
*/
- if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
already = true;
+ if (beacon)
+ ifmgd->flags |= IEEE80211_STA_BEACON_POLL;
+ else
+ ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
+
mutex_unlock(&sdata->local->mtx);
if (already)
@@ -1981,7 +2174,6 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
true, frame_buf);
ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
- sdata->vif.csa_active = false;
ieee80211_wake_queues_by_reason(&sdata->local->hw,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -2525,7 +2717,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
*/
ifmgd->wmm_last_param_set = -1;
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && elems.wmm_param)
+ if (elems.wmm_param)
ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
elems.wmm_param_len);
else
@@ -2869,10 +3061,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}
}
- if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
+ if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
mlme_dbg_ratelimited(sdata,
"cancelling AP probe due to a received beacon\n");
- ieee80211_reset_ap_probe(sdata);
+ mutex_lock(&local->mtx);
+ ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
+ ieee80211_run_deferred_scan(local);
+ mutex_unlock(&local->mtx);
+
+ mutex_lock(&local->iflist_mtx);
+ ieee80211_recalc_ps(local, -1);
+ mutex_unlock(&local->iflist_mtx);
}
/*
@@ -2953,8 +3152,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
&elems, true);
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
- ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
+ if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
elems.wmm_param_len))
changed |= BSS_CHANGED_QOS;
@@ -3345,7 +3543,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
} else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
run_again(sdata, ifmgd->assoc_data->timeout);
- if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL &&
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL) &&
ifmgd->associated) {
u8 bssid[ETH_ALEN];
int max_tries;
@@ -3498,7 +3697,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ieee80211_beacon_connection_loss_work);
INIT_WORK(&ifmgd->csa_connection_drop_work,
ieee80211_csa_connection_drop_work);
- INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work);
+ INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
(unsigned long) sdata);
setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
@@ -3677,7 +3876,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
return ret;
while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
- ifmgd->flags |= ieee80211_chandef_downgrade(&chandef);
+ ifmgd->flags |= chandef_downgrade(&chandef);
ret = ieee80211_vif_use_channel(sdata, &chandef,
IEEE80211_CHANCTX_SHARED);
}
@@ -3936,44 +4135,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
return err;
}
-static bool ieee80211_usable_wmm_params(struct ieee80211_sub_if_data *sdata,
- const u8 *wmm_param, int len)
-{
- const u8 *pos;
- size_t left;
-
- if (len < 8)
- return false;
-
- if (wmm_param[5] != 1 /* version */)
- return false;
-
- pos = wmm_param + 8;
- left = len - 8;
-
- for (; left >= 4; left -= 4, pos += 4) {
- u8 aifsn = pos[0] & 0x0f;
- u8 ecwmin = pos[1] & 0x0f;
- u8 ecwmax = (pos[1] & 0xf0) >> 4;
- int aci = (pos[0] >> 5) & 0x03;
-
- if (aifsn < 2) {
- sdata_info(sdata,
- "AP has invalid WMM params (AIFSN=%d for ACI %d), disabling WMM\n",
- aifsn, aci);
- return false;
- }
- if (ecwmin > ecwmax) {
- sdata_info(sdata,
- "AP has invalid WMM params (ECWmin/max=%d/%d for ACI %d), disabling WMM\n",
- ecwmin, ecwmax, aci);
- return false;
- }
- }
-
- return true;
-}
-
int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
struct cfg80211_assoc_request *req)
{
@@ -4031,45 +4192,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
}
/* prepare assoc data */
-
+
ifmgd->beacon_crc_valid = false;
- assoc_data->wmm = bss->wmm_used &&
- (local->hw.queues >= IEEE80211_NUM_ACS);
- if (assoc_data->wmm) {
- /* try to check validity of WMM params IE */
- const struct cfg80211_bss_ies *ies;
- const u8 *wp, *start, *end;
-
- rcu_read_lock();
- ies = rcu_dereference(req->bss->ies);
- start = ies->data;
- end = start + ies->len;
-
- while (true) {
- wp = cfg80211_find_vendor_ie(
- WLAN_OUI_MICROSOFT,
- WLAN_OUI_TYPE_MICROSOFT_WMM,
- start, end - start);
- if (!wp)
- break;
- start = wp + wp[1] + 2;
- /* if this IE is too short, try the next */
- if (wp[1] <= 4)
- continue;
- /* if this IE is WMM params, we found what we wanted */
- if (wp[6] == 1)
- break;
- }
-
- if (!wp || !ieee80211_usable_wmm_params(sdata, wp + 2,
- wp[1] - 2)) {
- assoc_data->wmm = false;
- ifmgd->flags |= IEEE80211_STA_DISABLE_WMM;
- }
- rcu_read_unlock();
- }
-
/*
* IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode.
* We still associate in non-HT mode (11a/b/g) if any one of these
@@ -4099,22 +4224,18 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
/* Also disable HT if we don't support it or the AP doesn't use WMM */
sband = local->hw.wiphy->bands[req->bss->channel->band];
if (!sband->ht_cap.ht_supported ||
- local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
- ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
+ local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
- if (!bss->wmm_used &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
+ if (!bss->wmm_used)
netdev_info(sdata->dev,
"disabling HT as WMM/QoS is not supported by the AP\n");
}
/* disable VHT if we don't support it or the AP doesn't use WMM */
if (!sband->vht_cap.vht_supported ||
- local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
- ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
+ local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
- if (!bss->wmm_used &&
- !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
+ if (!bss->wmm_used)
netdev_info(sdata->dev,
"disabling VHT as WMM/QoS is not supported by the AP\n");
}
@@ -4143,6 +4264,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
sdata->smps_mode = ifmgd->req_smps;
assoc_data->capability = req->bss->capability;
+ assoc_data->wmm = bss->wmm_used &&
+ (local->hw.queues >= IEEE80211_NUM_ACS);
assoc_data->supp_rates = bss->supp_rates;
assoc_data->supp_rates_len = bss->supp_rates_len;
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 22b223f..e126605 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -235,8 +235,7 @@ static void rc_send_low_basicrate(s8 *idx, u32 basic_rates,
static void __rate_control_send_low(struct ieee80211_hw *hw,
struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta,
- struct ieee80211_tx_info *info,
- u32 rate_mask)
+ struct ieee80211_tx_info *info)
{
int i;
u32 rate_flags =
@@ -248,12 +247,6 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
info->control.rates[0].idx = 0;
for (i = 0; i < sband->n_bitrates; i++) {
- if (!(rate_mask & BIT(i)))
- continue;
-
- if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
- continue;
-
if (!rate_supported(sta, sband->band, i))
continue;
@@ -281,8 +274,7 @@ bool rate_control_send_low(struct ieee80211_sta *pubsta,
bool use_basicrate = false;
if (!pubsta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {
- __rate_control_send_low(txrc->hw, sband, pubsta, info,
- txrc->rate_idx_mask);
+ __rate_control_send_low(txrc->hw, sband, pubsta, info);
if (!pubsta && txrc->bss) {
mcast_rate = txrc->bss_conf->mcast_rate[sband->band];
@@ -664,8 +656,7 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
rate_control_apply_mask(sdata, sta, sband, info, dest, max_rates);
if (dest[0].idx < 0)
- __rate_control_send_low(&sdata->local->hw, sband, sta, info,
- sdata->rc_rateidx_mask[info->band]);
+ __rate_control_send_low(&sdata->local->hw, sband, sta, info);
if (sta)
rate_fixup_ratelist(vif, sband, info, dest, max_rates);
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 505bc0d..5dedc56 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -144,8 +144,8 @@ void rate_control_deinitialize(struct ieee80211_local *local);
/* Rate control algorithms */
#ifdef CONFIG_MAC80211_RC_PID
-int rc80211_pid_init(void);
-void rc80211_pid_exit(void);
+extern int rc80211_pid_init(void);
+extern void rc80211_pid_exit(void);
#else
static inline int rc80211_pid_init(void)
{
@@ -157,8 +157,8 @@ static inline void rc80211_pid_exit(void)
#endif
#ifdef CONFIG_MAC80211_RC_MINSTREL
-int rc80211_minstrel_init(void);
-void rc80211_minstrel_exit(void);
+extern int rc80211_minstrel_init(void);
+extern void rc80211_minstrel_exit(void);
#else
static inline int rc80211_minstrel_init(void)
{
@@ -170,8 +170,8 @@ static inline void rc80211_minstrel_exit(void)
#endif
#ifdef CONFIG_MAC80211_RC_MINSTREL_HT
-int rc80211_minstrel_ht_init(void);
-void rc80211_minstrel_ht_exit(void);
+extern int rc80211_minstrel_ht_init(void);
+extern void rc80211_minstrel_ht_exit(void);
#else
static inline int rc80211_minstrel_ht_init(void)
{
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 7fa1b36..8b5f7ef 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -203,15 +203,6 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate));
mi->max_prob_rate = tmp_prob_rate;
-#ifdef CONFIG_MAC80211_DEBUGFS
- /* use fixed index if set */
- if (mp->fixed_rate_idx != -1) {
- mi->max_tp_rate[0] = mp->fixed_rate_idx;
- mi->max_tp_rate[1] = mp->fixed_rate_idx;
- mi->max_prob_rate = mp->fixed_rate_idx;
- }
-#endif
-
/* Reset update timer */
mi->stats_update = jiffies;
@@ -319,11 +310,6 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
/* increase sum packet counter */
mi->packet_count++;
-#ifdef CONFIG_MAC80211_DEBUGFS
- if (mp->fixed_rate_idx != -1)
- return;
-#endif
-
delta = (mi->packet_count * sampling_ratio / 100) -
(mi->sample_count + mi->sample_deferred / 2);
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 5d60779..7c323f2 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -365,14 +365,6 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
}
}
-#ifdef CONFIG_MAC80211_DEBUGFS
- /* use fixed index if set */
- if (mp->fixed_rate_idx != -1) {
- mi->max_tp_rate = mp->fixed_rate_idx;
- mi->max_tp_rate2 = mp->fixed_rate_idx;
- mi->max_prob_rate = mp->fixed_rate_idx;
- }
-#endif
mi->stats_update = jiffies;
}
@@ -782,11 +774,6 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
info->flags |= mi->tx_flags;
minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
-#ifdef CONFIG_MAC80211_DEBUGFS
- if (mp->fixed_rate_idx != -1)
- return;
-#endif
-
/* Don't use EAPOL frames for sampling on non-mrr hw */
if (mp->hw->max_rates == 1 &&
(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))
@@ -794,6 +781,16 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
else
sample_idx = minstrel_get_sample_rate(mp, mi);
+#ifdef CONFIG_MAC80211_DEBUGFS
+ /* use fixed index if set */
+ if (mp->fixed_rate_idx != -1) {
+ mi->max_tp_rate = mp->fixed_rate_idx;
+ mi->max_tp_rate2 = mp->fixed_rate_idx;
+ mi->max_prob_rate = mp->fixed_rate_idx;
+ sample_idx = -1;
+ }
+#endif
+
mi->total_packets++;
/* wraparound */
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c
index 6ff1346..c97a065 100644
--- a/net/mac80211/rc80211_pid_debugfs.c
+++ b/net/mac80211/rc80211_pid_debugfs.c
@@ -167,29 +167,29 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
* provide large enough buffers. */
length = length < RC_PID_PRINT_BUF_SIZE ?
length : RC_PID_PRINT_BUF_SIZE;
- p = scnprintf(pb, length, "%u %lu ", ev->id, ev->timestamp);
+ p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp);
switch (ev->type) {
case RC_PID_EVENT_TYPE_TX_STATUS:
- p += scnprintf(pb + p, length - p, "tx_status %u %u",
- !(ev->data.flags & IEEE80211_TX_STAT_ACK),
- ev->data.tx_status.status.rates[0].idx);
+ p += snprintf(pb + p, length - p, "tx_status %u %u",
+ !(ev->data.flags & IEEE80211_TX_STAT_ACK),
+ ev->data.tx_status.status.rates[0].idx);
break;
case RC_PID_EVENT_TYPE_RATE_CHANGE:
- p += scnprintf(pb + p, length - p, "rate_change %d %d",
- ev->data.index, ev->data.rate);
+ p += snprintf(pb + p, length - p, "rate_change %d %d",
+ ev->data.index, ev->data.rate);
break;
case RC_PID_EVENT_TYPE_TX_RATE:
- p += scnprintf(pb + p, length - p, "tx_rate %d %d",
- ev->data.index, ev->data.rate);
+ p += snprintf(pb + p, length - p, "tx_rate %d %d",
+ ev->data.index, ev->data.rate);
break;
case RC_PID_EVENT_TYPE_PF_SAMPLE:
- p += scnprintf(pb + p, length - p,
- "pf_sample %d %d %d %d",
- ev->data.pf_sample, ev->data.prop_err,
- ev->data.int_err, ev->data.der_err);
+ p += snprintf(pb + p, length - p,
+ "pf_sample %d %d %d %d",
+ ev->data.pf_sample, ev->data.prop_err,
+ ev->data.int_err, ev->data.der_err);
break;
}
- p += scnprintf(pb + p, length - p, "\n");
+ p += snprintf(pb + p, length - p, "\n");
spin_unlock_irqrestore(&events->lock, status);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index caecef8..674eac1 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -995,9 +995,8 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
rx->sta->num_duplicates++;
}
return RX_DROP_UNUSABLE;
- } else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
+ } else
rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
- }
}
if (unlikely(rx->skb->len < 16)) {
@@ -2403,8 +2402,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
- mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED &&
- mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
+ mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED)
return RX_DROP_UNUSABLE;
if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
@@ -2568,49 +2566,31 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
goto queue;
case WLAN_CATEGORY_SPECTRUM_MGMT:
+ if (status->band != IEEE80211_BAND_5GHZ)
+ break;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ break;
+
/* verify action_code is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
break;
switch (mgmt->u.action.u.measurement.action_code) {
case WLAN_ACTION_SPCT_MSR_REQ:
- if (status->band != IEEE80211_BAND_5GHZ)
- break;
-
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.measurement)))
break;
-
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
- break;
-
ieee80211_process_measurement_req(sdata, mgmt, len);
goto handled;
- case WLAN_ACTION_SPCT_CHL_SWITCH: {
- u8 *bssid;
- if (len < (IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.chan_switch)))
- break;
-
- if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
- break;
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- bssid = sdata->u.mgd.bssid;
- else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
- bssid = sdata->u.ibss.bssid;
- else if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
- bssid = mgmt->sa;
- else
+ case WLAN_ACTION_SPCT_CHL_SWITCH:
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
- if (!ether_addr_equal(mgmt->bssid, bssid))
+ if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid))
break;
goto queue;
- }
}
break;
case WLAN_CATEGORY_SA_QUERY:
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 5ad66a8..d2d17a4 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -394,7 +394,8 @@ static bool ieee80211_can_scan(struct ieee80211_local *local,
return false;
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
- sdata->u.mgd.flags & IEEE80211_STA_CONNECTION_POLL)
+ sdata->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
return false;
return true;
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index a40da20..578eea3 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -21,175 +21,6 @@
#include "sta_info.h"
#include "wme.h"
-int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
- struct ieee802_11_elems *elems, bool beacon,
- enum ieee80211_band current_band,
- u32 sta_flags, u8 *bssid,
- struct ieee80211_csa_ie *csa_ie)
-{
- enum ieee80211_band new_band;
- int new_freq;
- u8 new_chan_no;
- struct ieee80211_channel *new_chan;
- struct cfg80211_chan_def new_vht_chandef = {};
- const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
- const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
- const struct ieee80211_ht_operation *ht_oper;
- int secondary_channel_offset = -1;
-
- sec_chan_offs = elems->sec_chan_offs;
- wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
- ht_oper = elems->ht_operation;
-
- if (sta_flags & (IEEE80211_STA_DISABLE_HT |
- IEEE80211_STA_DISABLE_40MHZ)) {
- sec_chan_offs = NULL;
- wide_bw_chansw_ie = NULL;
- /* only used for bandwidth here */
- ht_oper = NULL;
- }
-
- if (sta_flags & IEEE80211_STA_DISABLE_VHT)
- wide_bw_chansw_ie = NULL;
-
- if (elems->ext_chansw_ie) {
- if (!ieee80211_operating_class_to_band(
- elems->ext_chansw_ie->new_operating_class,
- &new_band)) {
- sdata_info(sdata,
- "cannot understand ECSA IE operating class %d, disconnecting\n",
- elems->ext_chansw_ie->new_operating_class);
- return -EINVAL;
- }
- new_chan_no = elems->ext_chansw_ie->new_ch_num;
- csa_ie->count = elems->ext_chansw_ie->count;
- csa_ie->mode = elems->ext_chansw_ie->mode;
- } else if (elems->ch_switch_ie) {
- new_band = current_band;
- new_chan_no = elems->ch_switch_ie->new_ch_num;
- csa_ie->count = elems->ch_switch_ie->count;
- csa_ie->mode = elems->ch_switch_ie->mode;
- } else {
- /* nothing here we understand */
- return 1;
- }
-
- /* Mesh Channel Switch Parameters Element */
- if (elems->mesh_chansw_params_ie) {
- csa_ie->ttl = elems->mesh_chansw_params_ie->mesh_ttl;
- csa_ie->mode = elems->mesh_chansw_params_ie->mesh_flags;
- }
-
- new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
- new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
- if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
- sdata_info(sdata,
- "BSS %pM switches to unsupported channel (%d MHz), disconnecting\n",
- bssid, new_freq);
- return -EINVAL;
- }
-
- if (!beacon && sec_chan_offs) {
- secondary_channel_offset = sec_chan_offs->sec_chan_offs;
- } else if (beacon && ht_oper) {
- secondary_channel_offset =
- ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
- } else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) {
- /* If it's not a beacon, HT is enabled and the IE not present,
- * it's 20 MHz, 802.11-2012 8.5.2.6:
- * This element [the Secondary Channel Offset Element] is
- * present when switching to a 40 MHz channel. It may be
- * present when switching to a 20 MHz channel (in which
- * case the secondary channel offset is set to SCN).
- */
- secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
- }
-
- switch (secondary_channel_offset) {
- default:
- /* secondary_channel_offset was present but is invalid */
- case IEEE80211_HT_PARAM_CHA_SEC_NONE:
- cfg80211_chandef_create(&csa_ie->chandef, new_chan,
- NL80211_CHAN_HT20);
- break;
- case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- cfg80211_chandef_create(&csa_ie->chandef, new_chan,
- NL80211_CHAN_HT40PLUS);
- break;
- case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- cfg80211_chandef_create(&csa_ie->chandef, new_chan,
- NL80211_CHAN_HT40MINUS);
- break;
- case -1:
- cfg80211_chandef_create(&csa_ie->chandef, new_chan,
- NL80211_CHAN_NO_HT);
- /* keep width for 5/10 MHz channels */
- switch (sdata->vif.bss_conf.chandef.width) {
- case NL80211_CHAN_WIDTH_5:
- case NL80211_CHAN_WIDTH_10:
- csa_ie->chandef.width =
- sdata->vif.bss_conf.chandef.width;
- break;
- default:
- break;
- }
- break;
- }
-
- if (wide_bw_chansw_ie) {
- new_vht_chandef.chan = new_chan;
- new_vht_chandef.center_freq1 =
- ieee80211_channel_to_frequency(
- wide_bw_chansw_ie->new_center_freq_seg0,
- new_band);
-
- switch (wide_bw_chansw_ie->new_channel_width) {
- default:
- /* hmmm, ignore VHT and use HT if present */
- case IEEE80211_VHT_CHANWIDTH_USE_HT:
- new_vht_chandef.chan = NULL;
- break;
- case IEEE80211_VHT_CHANWIDTH_80MHZ:
- new_vht_chandef.width = NL80211_CHAN_WIDTH_80;
- break;
- case IEEE80211_VHT_CHANWIDTH_160MHZ:
- new_vht_chandef.width = NL80211_CHAN_WIDTH_160;
- break;
- case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
- /* field is otherwise reserved */
- new_vht_chandef.center_freq2 =
- ieee80211_channel_to_frequency(
- wide_bw_chansw_ie->new_center_freq_seg1,
- new_band);
- new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
- break;
- }
- if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
- new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
- ieee80211_chandef_downgrade(&new_vht_chandef);
- if (sta_flags & IEEE80211_STA_DISABLE_160MHZ &&
- new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
- ieee80211_chandef_downgrade(&new_vht_chandef);
- if (sta_flags & IEEE80211_STA_DISABLE_40MHZ &&
- new_vht_chandef.width > NL80211_CHAN_WIDTH_20)
- ieee80211_chandef_downgrade(&new_vht_chandef);
- }
-
- /* if VHT data is there validate & use it */
- if (new_vht_chandef.chan) {
- if (!cfg80211_chandef_compatible(&new_vht_chandef,
- &csa_ie->chandef)) {
- sdata_info(sdata,
- "BSS %pM: CSA has inconsistent channel data, disconnecting\n",
- bssid);
- return -EINVAL;
- }
- csa_ie->chandef = new_vht_chandef;
- }
-
- return 0;
-}
-
static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata,
struct ieee80211_msrment_ie *request_ie,
const u8 *da, const u8 *bssid,
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 1eb66e2..aeb967a 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -385,30 +385,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
sta->sta.smps_mode = IEEE80211_SMPS_OFF;
- if (sdata->vif.type == NL80211_IFTYPE_AP ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
- struct ieee80211_supported_band *sband =
- local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
- u8 smps = (sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >>
- IEEE80211_HT_CAP_SM_PS_SHIFT;
- /*
- * Assume that hostapd advertises our caps in the beacon and
- * this is the known_smps_mode for a station that just assciated
- */
- switch (smps) {
- case WLAN_HT_SMPS_CONTROL_DISABLED:
- sta->known_smps_mode = IEEE80211_SMPS_OFF;
- break;
- case WLAN_HT_SMPS_CONTROL_STATIC:
- sta->known_smps_mode = IEEE80211_SMPS_STATIC;
- break;
- case WLAN_HT_SMPS_CONTROL_DYNAMIC:
- sta->known_smps_mode = IEEE80211_SMPS_DYNAMIC;
- break;
- default:
- WARN_ON(1);
- }
- }
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
@@ -1093,19 +1069,6 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
- /* This station just woke up and isn't aware of our SMPS state */
- if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
- sdata->smps_mode) &&
- sta->known_smps_mode != sdata->bss->req_smps &&
- sta_info_tx_streams(sta) != 1) {
- ht_dbg(sdata,
- "%pM just woke up and MIMO capable - update SMPS\n",
- sta->sta.addr);
- ieee80211_send_smps_action(sdata, sdata->bss->req_smps,
- sta->sta.addr,
- sdata->vif.bss_conf.bssid);
- }
-
local->total_ps_buffered -= buffered;
sta_info_recalc_tim(sta);
@@ -1557,38 +1520,3 @@ int sta_info_move_state(struct sta_info *sta,
return 0;
}
-
-u8 sta_info_tx_streams(struct sta_info *sta)
-{
- struct ieee80211_sta_ht_cap *ht_cap = &sta->sta.ht_cap;
- u8 rx_streams;
-
- if (!sta->sta.ht_cap.ht_supported)
- return 1;
-
- if (sta->sta.vht_cap.vht_supported) {
- int i;
- u16 tx_mcs_map =
- le16_to_cpu(sta->sta.vht_cap.vht_mcs.tx_mcs_map);
-
- for (i = 7; i >= 0; i--)
- if ((tx_mcs_map & (0x3 << (i * 2))) !=
- IEEE80211_VHT_MCS_NOT_SUPPORTED)
- return i + 1;
- }
-
- if (ht_cap->mcs.rx_mask[3])
- rx_streams = 4;
- else if (ht_cap->mcs.rx_mask[2])
- rx_streams = 3;
- else if (ht_cap->mcs.rx_mask[1])
- rx_streams = 2;
- else
- rx_streams = 1;
-
- if (!(ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_RX_DIFF))
- return rx_streams;
-
- return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
- >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
-}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 3ef06a2..4208dbd 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -301,8 +301,6 @@ struct sta_ampdu_mlme {
* @chains: chains ever used for RX from this station
* @chain_signal_last: last signal (per chain)
* @chain_signal_avg: signal average (per chain)
- * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
- * AP only.
*/
struct sta_info {
/* General information, mostly static */
@@ -413,8 +411,6 @@ struct sta_info {
unsigned int lost_packets;
unsigned int beacon_loss_count;
- enum ieee80211_smps_mode known_smps_mode;
-
/* keep last! */
struct ieee80211_sta sta;
};
@@ -617,7 +613,6 @@ void sta_set_rate_info_rx(struct sta_info *sta,
struct rate_info *rinfo);
void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
unsigned long exp_time);
-u8 sta_info_tx_streams(struct sta_info *sta);
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 52a152b..78dc2e9 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -194,36 +194,29 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_HT &&
mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS &&
+ sdata->vif.type == NL80211_IFTYPE_STATION &&
ieee80211_sdata_running(sdata)) {
- enum ieee80211_smps_mode smps_mode;
-
+ /*
+ * This update looks racy, but isn't -- if we come
+ * here we've definitely got a station that we're
+ * talking to, and on a managed interface that can
+ * only be the AP. And the only other place updating
+ * this variable in managed mode is before association.
+ */
switch (mgmt->u.action.u.ht_smps.smps_control) {
case WLAN_HT_SMPS_CONTROL_DYNAMIC:
- smps_mode = IEEE80211_SMPS_DYNAMIC;
+ sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
break;
case WLAN_HT_SMPS_CONTROL_STATIC:
- smps_mode = IEEE80211_SMPS_STATIC;
+ sdata->smps_mode = IEEE80211_SMPS_STATIC;
break;
case WLAN_HT_SMPS_CONTROL_DISABLED:
default: /* shouldn't happen since we don't send that */
- smps_mode = IEEE80211_SMPS_OFF;
+ sdata->smps_mode = IEEE80211_SMPS_OFF;
break;
}
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- /*
- * This update looks racy, but isn't -- if we come
- * here we've definitely got a station that we're
- * talking to, and on a managed interface that can
- * only be the AP. And the only other place updating
- * this variable in managed mode is before association.
- */
- sdata->smps_mode = smps_mode;
- ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
- } else if (sdata->vif.type == NL80211_IFTYPE_AP ||
- sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
- sta->known_smps_mode = smps_mode;
- }
+ ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
}
}
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index d4cee98..1aba645 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -77,13 +77,13 @@ DECLARE_EVENT_CLASS(local_sdata_addr_evt,
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
- __array(char, addr, ETH_ALEN)
+ __array(char, addr, 6)
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
- memcpy(__entry->addr, sdata->vif.addr, ETH_ALEN);
+ memcpy(__entry->addr, sdata->vif.addr, 6);
),
TP_printk(
@@ -1475,41 +1475,6 @@ DEFINE_EVENT(local_sdata_evt, drv_ipv6_addr_change,
);
#endif
-TRACE_EVENT(drv_join_ibss,
- TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct ieee80211_bss_conf *info),
-
- TP_ARGS(local, sdata, info),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- VIF_ENTRY
- __field(u8, dtimper)
- __field(u16, bcnint)
- __dynamic_array(u8, ssid, info->ssid_len);
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- VIF_ASSIGN;
- __entry->dtimper = info->dtim_period;
- __entry->bcnint = info->beacon_int;
- memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
- ),
-
- TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT,
- LOCAL_PR_ARG, VIF_PR_ARG
- )
-);
-
-DEFINE_EVENT(local_sdata_evt, drv_leave_ibss,
- TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata),
- TP_ARGS(local, sdata)
-);
-
/*
* Tracing for API calls that drivers call.
*/
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c558b24..70b5a05 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1367,35 +1367,6 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
return 0;
}
-bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, struct sk_buff *skb,
- int band, struct ieee80211_sta **sta)
-{
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_data tx;
-
- if (ieee80211_tx_prepare(sdata, &tx, skb) == TX_DROP)
- return false;
-
- info->band = band;
- info->control.vif = vif;
- info->hw_queue = vif->hw_queue[skb_get_queue_mapping(skb)];
-
- if (invoke_tx_handlers(&tx))
- return false;
-
- if (sta) {
- if (tx.sta)
- *sta = &tx.sta->sta;
- else
- *sta = NULL;
- }
-
- return true;
-}
-EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
-
/*
* Returns false if the frame couldn't be transmitted but was queued instead.
*/
@@ -2011,7 +1982,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
* EAPOL frames from the local station.
*/
if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&
- !multicast && !authorized &&
+ !is_multicast_ether_addr(hdr.addr1) && !authorized &&
(cpu_to_be16(ethertype) != sdata->control_port_protocol ||
!ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -2387,35 +2358,15 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
struct probe_resp *resp;
int counter_offset_beacon = sdata->csa_counter_offset_beacon;
int counter_offset_presp = sdata->csa_counter_offset_presp;
- u8 *beacon_data;
- size_t beacon_data_len;
-
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_AP:
- beacon_data = beacon->tail;
- beacon_data_len = beacon->tail_len;
- break;
- case NL80211_IFTYPE_ADHOC:
- beacon_data = beacon->head;
- beacon_data_len = beacon->head_len;
- break;
- case NL80211_IFTYPE_MESH_POINT:
- beacon_data = beacon->head;
- beacon_data_len = beacon->head_len;
- break;
- default:
- return;
- }
- if (WARN_ON(counter_offset_beacon >= beacon_data_len))
- return;
/* warn if the driver did not check for/react to csa completeness */
- if (WARN_ON(beacon_data[counter_offset_beacon] == 0))
+ if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0))
return;
- beacon_data[counter_offset_beacon]--;
+ ((u8 *)beacon->tail)[counter_offset_beacon]--;
- if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) {
+ if (sdata->vif.type == NL80211_IFTYPE_AP &&
+ counter_offset_presp) {
rcu_read_lock();
resp = rcu_dereference(sdata->u.ap.probe_resp);
@@ -2450,24 +2401,6 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
goto out;
beacon_data = beacon->tail;
beacon_data_len = beacon->tail_len;
- } else if (vif->type == NL80211_IFTYPE_ADHOC) {
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-
- beacon = rcu_dereference(ifibss->presp);
- if (!beacon)
- goto out;
-
- beacon_data = beacon->head;
- beacon_data_len = beacon->head_len;
- } else if (vif->type == NL80211_IFTYPE_MESH_POINT) {
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-
- beacon = rcu_dereference(ifmsh->beacon);
- if (!beacon)
- goto out;
-
- beacon_data = beacon->head;
- beacon_data_len = beacon->head_len;
} else {
WARN_ON(1);
goto out;
@@ -2552,10 +2485,6 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
if (!presp)
goto out;
- if (sdata->vif.csa_active)
- ieee80211_update_csa(sdata, presp);
-
-
skb = dev_alloc_skb(local->tx_headroom + presp->head_len);
if (!skb)
goto out;
@@ -2573,9 +2502,6 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
if (!bcn)
goto out;
- if (sdata->vif.csa_active)
- ieee80211_update_csa(sdata, bcn);
-
if (ifmsh->sync_ops)
ifmsh->sync_ops->adjust_tbtt(
sdata);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 592a181..69e4ef5 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -300,6 +300,9 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
if (!sdata->dev)
continue;
+ if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+ continue;
+
if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE &&
local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
continue;
@@ -564,15 +567,18 @@ void ieee80211_flush_queues(struct ieee80211_local *local,
IEEE80211_QUEUE_STOP_REASON_FLUSH);
}
-static void __iterate_active_interfaces(struct ieee80211_local *local,
- u32 iter_flags,
- void (*iterator)(void *data, u8 *mac,
- struct ieee80211_vif *vif),
- void *data)
+void ieee80211_iterate_active_interfaces(
+ struct ieee80211_hw *hw, u32 iter_flags,
+ void (*iterator)(void *data, u8 *mac,
+ struct ieee80211_vif *vif),
+ void *data)
{
+ struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ mutex_lock(&local->iflist_mtx);
+
+ list_for_each_entry(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
@@ -591,25 +597,13 @@ static void __iterate_active_interfaces(struct ieee80211_local *local,
&sdata->vif);
}
- sdata = rcu_dereference_check(local->monitor_sdata,
- lockdep_is_held(&local->iflist_mtx) ||
- lockdep_rtnl_is_held());
+ sdata = rcu_dereference_protected(local->monitor_sdata,
+ lockdep_is_held(&local->iflist_mtx));
if (sdata &&
(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
sdata->flags & IEEE80211_SDATA_IN_DRIVER))
iterator(data, sdata->vif.addr, &sdata->vif);
-}
-
-void ieee80211_iterate_active_interfaces(
- struct ieee80211_hw *hw, u32 iter_flags,
- void (*iterator)(void *data, u8 *mac,
- struct ieee80211_vif *vif),
- void *data)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- mutex_lock(&local->iflist_mtx);
- __iterate_active_interfaces(local, iter_flags, iterator, data);
mutex_unlock(&local->iflist_mtx);
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
@@ -621,26 +615,38 @@ void ieee80211_iterate_active_interfaces_atomic(
void *data)
{
struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_sub_if_data *sdata;
rcu_read_lock();
- __iterate_active_interfaces(local, iter_flags, iterator, data);
- rcu_read_unlock();
-}
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
-void ieee80211_iterate_active_interfaces_rtnl(
- struct ieee80211_hw *hw, u32 iter_flags,
- void (*iterator)(void *data, u8 *mac,
- struct ieee80211_vif *vif),
- void *data)
-{
- struct ieee80211_local *local = hw_to_local(hw);
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_MONITOR:
+ if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+ continue;
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ continue;
+ default:
+ break;
+ }
+ if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
+ !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+ continue;
+ if (ieee80211_sdata_running(sdata))
+ iterator(data, sdata->vif.addr,
+ &sdata->vif);
+ }
- ASSERT_RTNL();
+ sdata = rcu_dereference(local->monitor_sdata);
+ if (sdata &&
+ (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
+ sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+ iterator(data, sdata->vif.addr, &sdata->vif);
- __iterate_active_interfaces(local, iter_flags, iterator, data);
+ rcu_read_unlock();
}
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
+EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
/*
* Nothing should have been stuffed into the workqueue during
@@ -740,7 +746,6 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
case WLAN_EID_TIMEOUT_INTERVAL:
case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
- case WLAN_EID_CHAN_SWITCH_PARAM:
/*
* not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
* that if the content gets bigger it might be needed more than once
@@ -906,14 +911,6 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
}
elems->sec_chan_offs = (void *)pos;
break;
- case WLAN_EID_CHAN_SWITCH_PARAM:
- if (elen !=
- sizeof(*elems->mesh_chansw_params_ie)) {
- elem_parse_failed = true;
- break;
- }
- elems->mesh_chansw_params_ie = (void *)pos;
- break;
case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
if (!action ||
elen != sizeof(*elems->wide_bw_chansw_ie)) {
@@ -1010,21 +1007,14 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
*/
enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
- /* Set defaults according to 802.11-2007 Table 7-37 */
- aCWmax = 1023;
- if (use_11b)
- aCWmin = 31;
- else
- aCWmin = 15;
-
- /* Confiure old 802.11b/g medium access rules. */
- qparam.cw_max = aCWmax;
- qparam.cw_min = aCWmin;
- qparam.txop = 0;
- qparam.aifs = 2;
-
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- /* Update if QoS is enabled. */
+ /* Set defaults according to 802.11-2007 Table 7-37 */
+ aCWmax = 1023;
+ if (use_11b)
+ aCWmin = 31;
+ else
+ aCWmin = 15;
+
if (enable_qos) {
switch (ac) {
case IEEE80211_AC_BK:
@@ -1060,6 +1050,12 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
qparam.aifs = 2;
break;
}
+ } else {
+ /* Confiure old 802.11b/g medium access rules. */
+ qparam.cw_max = aCWmax;
+ qparam.cw_min = aCWmin;
+ qparam.txop = 0;
+ qparam.aifs = 2;
}
qparam.uapsd = false;
@@ -1088,8 +1084,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt;
int err;
- /* 24 + 6 = header + auth_algo + auth_transaction + status_code */
- skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 6 + extra_len);
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ sizeof(*mgmt) + 6 + extra_len);
if (!skb)
return;
@@ -2300,175 +2296,3 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw)
ieee80211_queue_work(hw, &local->radar_detected_work);
}
EXPORT_SYMBOL(ieee80211_radar_detected);
-
-u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
-{
- u32 ret;
- int tmp;
-
- switch (c->width) {
- case NL80211_CHAN_WIDTH_20:
- c->width = NL80211_CHAN_WIDTH_20_NOHT;
- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
- break;
- case NL80211_CHAN_WIDTH_40:
- c->width = NL80211_CHAN_WIDTH_20;
- c->center_freq1 = c->chan->center_freq;
- ret = IEEE80211_STA_DISABLE_40MHZ |
- IEEE80211_STA_DISABLE_VHT;
- break;
- case NL80211_CHAN_WIDTH_80:
- tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
- /* n_P40 */
- tmp /= 2;
- /* freq_P40 */
- c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;
- c->width = NL80211_CHAN_WIDTH_40;
- ret = IEEE80211_STA_DISABLE_VHT;
- break;
- case NL80211_CHAN_WIDTH_80P80:
- c->center_freq2 = 0;
- c->width = NL80211_CHAN_WIDTH_80;
- ret = IEEE80211_STA_DISABLE_80P80MHZ |
- IEEE80211_STA_DISABLE_160MHZ;
- break;
- case NL80211_CHAN_WIDTH_160:
- /* n_P20 */
- tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
- /* n_P80 */
- tmp /= 4;
- c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;
- c->width = NL80211_CHAN_WIDTH_80;
- ret = IEEE80211_STA_DISABLE_80P80MHZ |
- IEEE80211_STA_DISABLE_160MHZ;
- break;
- default:
- case NL80211_CHAN_WIDTH_20_NOHT:
- WARN_ON_ONCE(1);
- c->width = NL80211_CHAN_WIDTH_20_NOHT;
- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
- break;
- case NL80211_CHAN_WIDTH_5:
- case NL80211_CHAN_WIDTH_10:
- WARN_ON_ONCE(1);
- /* keep c->width */
- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
- break;
- }
-
- WARN_ON_ONCE(!cfg80211_chandef_valid(c));
-
- return ret;
-}
-
-/*
- * Returns true if smps_mode_new is strictly more restrictive than
- * smps_mode_old.
- */
-bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
- enum ieee80211_smps_mode smps_mode_new)
-{
- if (WARN_ON_ONCE(smps_mode_old == IEEE80211_SMPS_AUTOMATIC ||
- smps_mode_new == IEEE80211_SMPS_AUTOMATIC))
- return false;
-
- switch (smps_mode_old) {
- case IEEE80211_SMPS_STATIC:
- return false;
- case IEEE80211_SMPS_DYNAMIC:
- return smps_mode_new == IEEE80211_SMPS_STATIC;
- case IEEE80211_SMPS_OFF:
- return smps_mode_new != IEEE80211_SMPS_OFF;
- default:
- WARN_ON(1);
- }
-
- return false;
-}
-
-int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_csa_settings *csa_settings)
-{
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- struct ieee80211_local *local = sdata->local;
- int freq;
- int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +
- sizeof(mgmt->u.action.u.chan_switch);
- u8 *pos;
-
- if (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
- return -EOPNOTSUPP;
-
- skb = dev_alloc_skb(local->tx_headroom + hdr_len +
- 5 + /* channel switch announcement element */
- 3 + /* secondary channel offset element */
- 8); /* mesh channel switch parameters element */
- if (!skb)
- return -ENOMEM;
-
- skb_reserve(skb, local->tx_headroom);
- mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len);
- memset(mgmt, 0, hdr_len);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ACTION);
-
- eth_broadcast_addr(mgmt->da);
- memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
- } else {
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
- }
- mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
- mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
- pos = skb_put(skb, 5);
- *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */
- *pos++ = 3; /* IE length */
- *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */
- freq = csa_settings->chandef.chan->center_freq;
- *pos++ = ieee80211_frequency_to_channel(freq); /* channel */
- *pos++ = csa_settings->count; /* count */
-
- if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {
- enum nl80211_channel_type ch_type;
-
- skb_put(skb, 3);
- *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */
- *pos++ = 1; /* IE length */
- ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);
- if (ch_type == NL80211_CHAN_HT40PLUS)
- *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
- else
- *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- }
-
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- __le16 pre_value;
-
- skb_put(skb, 8);
- *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */
- *pos++ = 6; /* IE length */
- *pos++ = sdata->u.mesh.mshcfg.dot11MeshTTL; /* Mesh TTL */
- *pos = 0x00; /* Mesh Flag: Tx Restrict, Initiator, Reason */
- *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
- *pos++ |= csa_settings->block_tx ?
- WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
- put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
- pos += 2;
- if (!ifmsh->pre_value)
- ifmsh->pre_value = 1;
- else
- ifmsh->pre_value++;
- pre_value = cpu_to_le16(ifmsh->pre_value);
- memcpy(pos, &pre_value, 2); /* Precedence Value */
- pos += 2;
- ifmsh->chsw_init = true;
- }
-
- ieee80211_tx_skb(sdata, skb);
- return 0;
-}
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index de01127..97c2894 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -185,13 +185,13 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
vht_cap->cap |= cap_info &
(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+ IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX |
IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX);
}
if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
vht_cap->cap |= cap_info &
- (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
- IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX);
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
vht_cap->cap |= cap_info &
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index d657282..c9edfcb 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -301,16 +301,22 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
}
-static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
+static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
int encrypted)
{
__le16 mask_fc;
int a4_included, mgmt;
u8 qos_tid;
- u16 len_a;
+ u8 *b_0, *aad;
+ u16 data_len, len_a;
unsigned int hdrlen;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ memset(scratch, 0, 6 * AES_BLOCK_SIZE);
+
+ b_0 = scratch + 3 * AES_BLOCK_SIZE;
+ aad = scratch + 4 * AES_BLOCK_SIZE;
+
/*
* Mask FC: zero subtype b4 b5 b6 (if not mgmt)
* Retry, PwrMgt, MoreData; set Protected
@@ -332,21 +338,20 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
else
qos_tid = 0;
- /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
- * mode authentication are not allowed to collide, yet both are derived
- * from this vector b_0. We only set L := 1 here to indicate that the
- * data size can be represented in (L+1) bytes. The CCM layer will take
- * care of storing the data length in the top (L+1) bytes and setting
- * and clearing the other bits as is required to derive the two IVs.
- */
- b_0[0] = 0x1;
+ data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN;
+ if (encrypted)
+ data_len -= IEEE80211_CCMP_MIC_LEN;
+ /* First block, b_0 */
+ b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
/* Nonce: Nonce Flags | A2 | PN
* Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
*/
b_0[1] = qos_tid | (mgmt << 4);
memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
+ /* l(m) */
+ put_unaligned_be16(data_len, &b_0[14]);
/* AAD (extra authenticate-only data) / masked 802.11 header
* FC | A1 | A2 | A3 | SC | [A4] | [QC] */
@@ -402,8 +407,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
u8 *pos;
u8 pn[6];
u64 pn64;
- u8 aad[2 * AES_BLOCK_SIZE];
- u8 b_0[AES_BLOCK_SIZE];
+ u8 scratch[6 * AES_BLOCK_SIZE];
if (info->control.hw_key &&
!(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
@@ -456,9 +460,9 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
return 0;
pos += IEEE80211_CCMP_HDR_LEN;
- ccmp_special_blocks(skb, pn, b_0, aad, 0);
- ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
- skb_put(skb, IEEE80211_CCMP_MIC_LEN));
+ ccmp_special_blocks(skb, pn, scratch, 0);
+ ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, pos, len,
+ pos, skb_put(skb, IEEE80211_CCMP_MIC_LEN));
return 0;
}
@@ -521,16 +525,16 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
}
if (!(status->flag & RX_FLAG_DECRYPTED)) {
- u8 aad[2 * AES_BLOCK_SIZE];
- u8 b_0[AES_BLOCK_SIZE];
+ u8 scratch[6 * AES_BLOCK_SIZE];
/* hardware didn't decrypt/verify MIC */
- ccmp_special_blocks(skb, pn, b_0, aad, 1);
+ ccmp_special_blocks(skb, pn, scratch, 1);
if (ieee80211_aes_ccm_decrypt(
- key->u.ccmp.tfm, b_0, aad,
+ key->u.ccmp.tfm, scratch,
skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN,
data_len,
- skb->data + skb->len - IEEE80211_CCMP_MIC_LEN))
+ skb->data + skb->len - IEEE80211_CCMP_MIC_LEN,
+ skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN))
return RX_DROP_UNUSABLE;
}