summaryrefslogtreecommitdiff
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/agg-rx.c8
-rw-r--r--net/mac80211/agg-tx.c12
-rw-r--r--net/mac80211/cfg.c33
-rw-r--r--net/mac80211/chan.c74
-rw-r--r--net/mac80211/debugfs.c2
-rw-r--r--net/mac80211/debugfs_key.c2
-rw-r--r--net/mac80211/debugfs_netdev.c17
-rw-r--r--net/mac80211/debugfs_sta.c4
-rw-r--r--net/mac80211/ieee80211_i.h24
-rw-r--r--net/mac80211/iface.c56
-rw-r--r--net/mac80211/key.c49
-rw-r--r--net/mac80211/main.c22
-rw-r--r--net/mac80211/mesh.c30
-rw-r--r--net/mac80211/mesh_pathtbl.c4
-rw-r--r--net/mac80211/mlme.c123
-rw-r--r--net/mac80211/pm.c15
-rw-r--r--net/mac80211/rx.c41
-rw-r--r--net/mac80211/trace.h23
-rw-r--r--net/mac80211/tx.c60
-rw-r--r--net/mac80211/util.c75
-rw-r--r--net/mac80211/vht.c14
-rw-r--r--net/mac80211/wme.c18
22 files changed, 438 insertions, 268 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index cd4cf84a7f99..cce28e3b2232 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -250,10 +250,10 @@ static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
- capab = (u16)(amsdu << 0); /* bit 0 A-MSDU support */
- capab |= (u16)(policy << 1); /* bit 1 aggregation policy */
- capab |= (u16)(tid << 2); /* bit 5:2 TID number */
- capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */
+ capab = u16_encode_bits(amsdu, IEEE80211_ADDBA_PARAM_AMSDU_MASK);
+ capab |= u16_encode_bits(policy, IEEE80211_ADDBA_PARAM_POLICY_MASK);
+ capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
+ capab |= u16_encode_bits(buf_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index b37c8a983d88..430a58587538 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -95,10 +95,10 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
mgmt->u.action.u.addba_req.dialog_token = dialog_token;
- capab = (u16)(1 << 0); /* bit 0 A-MSDU support */
- capab |= (u16)(1 << 1); /* bit 1 aggregation policy */
- capab |= (u16)(tid << 2); /* bit 5:2 TID number */
- capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
+ capab = IEEE80211_ADDBA_PARAM_AMSDU_MASK;
+ capab |= IEEE80211_ADDBA_PARAM_POLICY_MASK;
+ capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
+ capab |= u16_encode_bits(agg_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
@@ -950,8 +950,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
- tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
- buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+ tid = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_TID_MASK);
+ buf_size = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
txq = sta->sta.txq[tid];
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7276e66ae435..c4c70e30ad7f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -405,6 +405,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
case WLAN_CIPHER_SUITE_WEP104:
if (WARN_ON_ONCE(fips_enabled))
return -EINVAL;
+ break;
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_AES_CMAC:
@@ -1121,10 +1122,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->vif.bss_conf.enable_beacon = true;
sdata->vif.bss_conf.allow_p2p_go_ps = sdata->vif.p2p;
sdata->vif.bss_conf.twt_responder = params->twt_responder;
- memcpy(&sdata->vif.bss_conf.he_obss_pd, &params->he_obss_pd,
- sizeof(struct ieee80211_he_obss_pd));
- memcpy(&sdata->vif.bss_conf.he_bss_color, &params->he_bss_color,
- sizeof(struct ieee80211_he_bss_color));
+ sdata->vif.bss_conf.he_obss_pd = params->he_obss_pd;
+ sdata->vif.bss_conf.he_bss_color = params->he_bss_color;
sdata->vif.bss_conf.s1g = params->chandef.chan->band ==
NL80211_BAND_S1GHZ;
@@ -2708,16 +2707,6 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy,
return 0;
}
-static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
- const u8 *addr)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- memcpy(&sdata->u.wds.remote_addr, addr, ETH_ALEN);
-
- return 0;
-}
-
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -3307,6 +3296,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
if (cfg80211_get_chandef_type(&params->chandef) !=
cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
return -EINVAL;
+ break;
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20_NOHT:
@@ -3458,7 +3448,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
IEEE80211_QUEUE_STOP_REASON_CSA);
cfg80211_ch_switch_started_notify(sdata->dev, &sdata->csa_chandef,
- params->count);
+ params->count, params->block_tx);
if (changed) {
ieee80211_bss_info_change_notify(sdata, changed);
@@ -4083,6 +4073,17 @@ static int ieee80211_reset_tid_config(struct wiphy *wiphy,
return ret;
}
+static int ieee80211_set_sar_specs(struct wiphy *wiphy,
+ struct cfg80211_sar_specs *sar)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ if (!local->ops->set_sar_specs)
+ return -EOPNOTSUPP;
+
+ return local->ops->set_sar_specs(&local->hw, sar);
+}
+
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -4138,7 +4139,6 @@ const struct cfg80211_ops mac80211_config_ops = {
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
- .set_wds_peer = ieee80211_set_wds_peer,
.rfkill_poll = ieee80211_rfkill_poll,
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
@@ -4186,4 +4186,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.probe_mesh_link = ieee80211_probe_mesh_link,
.set_tid_config = ieee80211_set_tid_config,
.reset_tid_config = ieee80211_reset_tid_config,
+ .set_sar_specs = ieee80211_set_sar_specs,
};
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 8f48aff74c7b..907bb1f748a1 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -9,6 +9,7 @@
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
+#include "rate.h"
static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
@@ -191,11 +192,13 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
return NULL;
}
-enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
+static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta)
{
- switch (sta->bandwidth) {
+ enum ieee80211_sta_rx_bandwidth width = ieee80211_sta_cap_rx_bw(sta);
+
+ switch (width) {
case IEEE80211_STA_RX_BW_20:
- if (sta->ht_cap.ht_supported)
+ if (sta->sta.ht_cap.ht_supported)
return NL80211_CHAN_WIDTH_20;
else
return NL80211_CHAN_WIDTH_20_NOHT;
@@ -232,7 +235,7 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
!(sta->sdata->bss && sta->sdata->bss == sdata->bss))
continue;
- max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
+ max_bw = max(max_bw, ieee80211_get_sta_bw(sta));
}
rcu_read_unlock();
@@ -275,11 +278,11 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
case NL80211_IFTYPE_NAN:
continue;
case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
width = vif->bss_conf.chandef.width;
break;
+ case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_MONITOR:
@@ -343,10 +346,42 @@ void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH);
}
+static void ieee80211_chan_bw_change(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx)
+{
+ struct sta_info *sta;
+ struct ieee80211_supported_band *sband =
+ local->hw.wiphy->bands[ctx->conf.def.chan->band];
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sta, &local->sta_list,
+ list) {
+ enum ieee80211_sta_rx_bandwidth new_sta_bw;
+
+ if (!ieee80211_sdata_running(sta->sdata))
+ continue;
+
+ if (rcu_access_pointer(sta->sdata->vif.chanctx_conf) !=
+ &ctx->conf)
+ continue;
+
+ new_sta_bw = ieee80211_sta_cur_vht_bw(sta);
+ if (new_sta_bw == sta->sta.bandwidth)
+ continue;
+
+ sta->sta.bandwidth = new_sta_bw;
+ rate_control_rate_update(local, sband, sta,
+ IEEE80211_RC_BW_CHANGED);
+ }
+ rcu_read_unlock();
+}
+
static void ieee80211_change_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
const struct cfg80211_chan_def *chandef)
{
+ enum nl80211_chan_width width;
+
if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) {
ieee80211_recalc_chanctx_min_def(local, ctx);
return;
@@ -354,7 +389,25 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
+ width = ctx->conf.def.width;
ctx->conf.def = *chandef;
+
+ /* expected to handle only 20/40/80/160 channel widths */
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ case NL80211_CHAN_WIDTH_40:
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ if (chandef->width < width)
+ ieee80211_chan_bw_change(local, ctx);
+
drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
ieee80211_recalc_chanctx_min_def(local, ctx);
@@ -362,6 +415,9 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
local->_oper_chandef = *chandef;
ieee80211_hw_config(local, 0);
}
+
+ if (chandef->width > width)
+ ieee80211_chan_bw_change(local, ctx);
}
static struct ieee80211_chanctx *
@@ -743,7 +799,6 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
continue;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
break;
@@ -1052,8 +1107,14 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
if (WARN_ON(!chandef))
return -EINVAL;
+ if (old_ctx->conf.def.width > new_ctx->conf.def.width)
+ ieee80211_chan_bw_change(local, new_ctx);
+
ieee80211_change_chanctx(local, new_ctx, chandef);
+ if (old_ctx->conf.def.width < new_ctx->conf.def.width)
+ ieee80211_chan_bw_change(local, new_ctx);
+
vif_chsw[0].vif = &sdata->vif;
vif_chsw[0].old_ctx = &old_ctx->conf;
vif_chsw[0].new_ctx = &new_ctx->conf;
@@ -1444,6 +1505,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
ieee80211_recalc_smps_chanctx(local, ctx);
ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx);
+ ieee80211_chan_bw_change(local, ctx);
list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
reserved_chanctx_list) {
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 90470392fdaa..48f144f107d5 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -53,7 +53,7 @@ static const struct file_operations name## _ops = { \
DEBUGFS_READONLY_FILE_OPS(name)
#define DEBUGFS_ADD(name) \
- debugfs_create_file(#name, 0400, phyd, local, &name## _ops);
+ debugfs_create_file(#name, 0400, phyd, local, &name## _ops)
#define DEBUGFS_ADD_MODE(name, mode) \
debugfs_create_file(#name, mode, phyd, local, &name## _ops);
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 98a713475e0f..f53dec8a3d5c 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -319,7 +319,7 @@ KEY_OPS(key);
#define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, key->debugfs.dir, \
- key, &key_##name##_ops);
+ key, &key_##name##_ops)
#define DEBUGFS_ADD_W(name) \
debugfs_create_file(#name, 0600, key->debugfs.dir, \
key, &key_##name##_ops);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index fe8a7a87e513..0ad3860852ff 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -574,9 +574,6 @@ static ssize_t ieee80211_if_parse_tsf(
IEEE80211_IF_FILE_RW(tsf);
-/* WDS attributes */
-IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
-
#ifdef CONFIG_MAC80211_MESH
IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);
@@ -645,7 +642,7 @@ IEEE80211_IF_FILE(dot11MeshConnectedToAuthServer,
#define DEBUGFS_ADD_MODE(name, mode) \
debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \
- sdata, &name##_ops);
+ sdata, &name##_ops)
#define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
@@ -701,11 +698,6 @@ static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD_MODE(tsf, 0600);
}
-static void add_wds_files(struct ieee80211_sub_if_data *sdata)
-{
- DEBUGFS_ADD(peer);
-}
-
#ifdef CONFIG_MAC80211_MESH
static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
@@ -719,7 +711,7 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
struct dentry *dir = debugfs_create_dir("mesh_stats",
sdata->vif.debugfs_dir);
#define MESHSTATS_ADD(name)\
- debugfs_create_file(#name, 0400, dir, sdata, &name##_ops);
+ debugfs_create_file(#name, 0400, dir, sdata, &name##_ops)
MESHSTATS_ADD(fwded_mcast);
MESHSTATS_ADD(fwded_unicast);
@@ -736,7 +728,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
sdata->vif.debugfs_dir);
#define MESHPARAMS_ADD(name) \
- debugfs_create_file(#name, 0600, dir, sdata, &name##_ops);
+ debugfs_create_file(#name, 0600, dir, sdata, &name##_ops)
MESHPARAMS_ADD(dot11MeshMaxRetries);
MESHPARAMS_ADD(dot11MeshRetryTimeout);
@@ -805,9 +797,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
case NL80211_IFTYPE_AP_VLAN:
add_vlan_files(sdata);
break;
- case NL80211_IFTYPE_WDS:
- add_wds_files(sdata);
- break;
default:
break;
}
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 829dcad69c2c..eb4bb79d936a 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -274,7 +274,7 @@ static ssize_t sta_aql_read(struct file *file, char __user *userbuf,
"Q limit[low/high]: VO: %u/%u VI: %u/%u BE: %u/%u BK: %u/%u\n",
q_depth[0], q_depth[1], q_depth[2], q_depth[3],
q_limit_l[0], q_limit_h[0], q_limit_l[1], q_limit_h[1],
- q_limit_l[2], q_limit_h[2], q_limit_l[3], q_limit_h[3]),
+ q_limit_l[2], q_limit_h[2], q_limit_l[3], q_limit_h[3]);
rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
kfree(buf);
@@ -985,7 +985,7 @@ STA_OPS(he_capa);
#define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, \
- sta->debugfs_dir, sta, &sta_ ##name## _ops);
+ sta->debugfs_dir, sta, &sta_ ##name## _ops)
#define DEBUGFS_ADD_COUNTER(name, field) \
debugfs_create_ulong(#name, 0400, sta->debugfs_dir, &sta->field);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2a21226fb518..8bf9c0e974d6 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -311,11 +311,6 @@ struct ieee80211_if_ap {
bool multicast_to_unicast;
};
-struct ieee80211_if_wds {
- struct sta_info *sta;
- u8 remote_addr[ETH_ALEN];
-};
-
struct ieee80211_if_vlan {
struct list_head list; /* write-protected with RTNL and local->mtx */
@@ -457,7 +452,9 @@ struct ieee80211_if_managed {
unsigned long probe_timeout;
int probe_send_count;
bool nullfunc_failed;
- bool connection_loss;
+ u8 connection_loss:1,
+ driver_disconnect:1,
+ reconnect:1;
struct cfg80211_bss *associated;
struct ieee80211_mgd_auth_data *auth_data;
@@ -985,7 +982,6 @@ struct ieee80211_sub_if_data {
union {
struct ieee80211_if_ap ap;
- struct ieee80211_if_wds wds;
struct ieee80211_if_vlan vlan;
struct ieee80211_if_managed mgd;
struct ieee80211_if_ibss ibss;
@@ -1593,13 +1589,8 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
{
WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START &&
status->flag & RX_FLAG_MACTIME_END);
- if (status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END))
- return true;
- /* can't handle non-legacy preamble yet */
- if (status->flag & RX_FLAG_MACTIME_PLCP_START &&
- status->encoding == RX_ENC_LEGACY)
- return true;
- return false;
+ return !!(status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END |
+ RX_FLAG_MACTIME_PLCP_START));
}
void ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata);
@@ -1795,7 +1786,7 @@ static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
/* tx handling */
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
-void ieee80211_tx_pending(unsigned long data);
+void ieee80211_tx_pending(struct tasklet_struct *t);
netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct net_device *dev);
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
@@ -2146,7 +2137,7 @@ void ieee80211_txq_remove_vlan(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
void ieee80211_fill_txq_stats(struct cfg80211_txq_stats *txqstats,
struct txq_info *txqi);
-void ieee80211_wake_txqs(unsigned long data);
+void ieee80211_wake_txqs(struct tasklet_struct *t);
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
const u8 *extra, size_t extra_len, const u8 *bssid,
@@ -2286,7 +2277,6 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
enum ieee80211_chanctx_mode chanmode,
u8 radar_detect);
int ieee80211_max_num_channels(struct ieee80211_local *local);
-enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta);
void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 1be775979132..3b9ec4ef81c3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -230,10 +230,6 @@ static inline int identical_mac_addr_allowed(int type1, int type2)
type2 == NL80211_IFTYPE_MONITOR ||
type1 == NL80211_IFTYPE_P2P_DEVICE ||
type2 == NL80211_IFTYPE_P2P_DEVICE ||
- (type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_WDS) ||
- (type1 == NL80211_IFTYPE_WDS &&
- (type2 == NL80211_IFTYPE_WDS ||
- type2 == NL80211_IFTYPE_AP)) ||
(type1 == NL80211_IFTYPE_AP && type2 == NL80211_IFTYPE_AP_VLAN) ||
(type1 == NL80211_IFTYPE_AP_VLAN &&
(type2 == NL80211_IFTYPE_AP ||
@@ -417,15 +413,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
* (because if we remove a STA after ops->remove_interface()
* the driver will have removed the vif info already!)
*
- * In WDS mode a station must exist here and be flushed, for
- * AP_VLANs stations may exist since there's nothing else that
+ * For AP_VLANs stations may exist since there's nothing else that
* would have removed them, but in other modes there shouldn't
* be any stations.
*/
flushed = sta_info_flush(sdata);
- WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
- ((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
- (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)));
+ WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN && flushed > 0);
/* don't count this interface for allmulti while it is down */
if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
@@ -552,8 +545,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
* When we get here, the interface is marked down.
* Free the remaining keys, if there are any
* (which can happen in AP mode if userspace sets
- * keys before the interface is operating, and maybe
- * also in WDS mode)
+ * keys before the interface is operating)
*
* Force the key freeing to always synchronize_net()
* to wait for the RX path in case it is using this
@@ -948,6 +940,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
return ret;
}
+ set_bit(SDATA_STATE_RUNNING, &sdata->state);
+
ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR);
if (ret) {
kfree(sdata);
@@ -1020,16 +1014,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct net_device *dev = wdev->netdev;
struct ieee80211_local *local = sdata->local;
- struct sta_info *sta;
u32 changed = 0;
int res;
u32 hw_reconf_flags = 0;
switch (sdata->vif.type) {
- case NL80211_IFTYPE_WDS:
- if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
- return -ENOLINK;
- break;
case NL80211_IFTYPE_AP_VLAN: {
struct ieee80211_sub_if_data *master;
@@ -1078,6 +1067,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_WDS:
/* cannot happen */
WARN_ON(1);
break;
@@ -1196,7 +1186,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
case NL80211_IFTYPE_OCB:
netif_carrier_off(dev);
break;
- case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_NAN:
break;
@@ -1218,28 +1207,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
set_bit(SDATA_STATE_RUNNING, &sdata->state);
switch (sdata->vif.type) {
- case NL80211_IFTYPE_WDS:
- /* Create STA entry for the WDS peer */
- sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
- GFP_KERNEL);
- if (!sta) {
- res = -ENOMEM;
- goto err_del_interface;
- }
-
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
-
- res = sta_info_insert(sta);
- if (res) {
- /* STA has been freed */
- goto err_del_interface;
- }
-
- rate_control_rate_init(sta);
- netif_carrier_on(dev);
- break;
case NL80211_IFTYPE_P2P_DEVICE:
rcu_assign_pointer(local->p2p_sdata, sdata);
break;
@@ -1356,6 +1323,7 @@ static void ieee80211_iface_work(struct work_struct *work)
while ((skb = skb_dequeue(&sdata->skb_queue))) {
struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ kcov_remote_start_common(skb_get_kcov_handle(skb));
if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK) {
int len = skb->len;
@@ -1465,6 +1433,7 @@ static void ieee80211_iface_work(struct work_struct *work)
}
kfree_skb(skb);
+ kcov_remote_stop();
}
/* then other type-dependent work */
@@ -1574,9 +1543,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->u.mntr.flags = MONITOR_FLAG_CONTROL |
MONITOR_FLAG_OTHER_BSS;
break;
- case NL80211_IFTYPE_WDS:
- sdata->vif.bss_conf.bssid = NULL;
- break;
case NL80211_IFTYPE_NAN:
idr_init(&sdata->u.nan.function_inst_ids);
spin_lock_init(&sdata->u.nan.func_lock);
@@ -1587,6 +1553,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.bssid = sdata->vif.addr;
break;
case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_WDS:
case NUM_NL80211_IFTYPES:
WARN_ON(1);
break;
@@ -1631,9 +1598,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_OCB:
/*
* Could probably support everything
- * but WDS here (WDS do_open can fail
- * under memory pressure, which this
- * code isn't prepared to handle).
+ * but here.
*/
break;
case NL80211_IFTYPE_P2P_CLIENT:
@@ -1726,7 +1691,6 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
case NL80211_IFTYPE_MONITOR:
/* doesn't matter */
break;
- case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_AP_VLAN:
/* match up with an AP interface */
list_for_each_entry(sdata, &local->interfaces, list) {
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 8c5f829ff6d7..a4817aa4b171 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -1300,3 +1300,52 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
return &key->conf;
}
EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_add);
+
+void ieee80211_key_mic_failure(struct ieee80211_key_conf *keyconf)
+{
+ struct ieee80211_key *key;
+
+ key = container_of(keyconf, struct ieee80211_key, conf);
+
+ switch (key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ key->u.aes_cmac.icverrors++;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ key->u.aes_gmac.icverrors++;
+ break;
+ default:
+ /* ignore the others for now, we don't keep counters now */
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(ieee80211_key_mic_failure);
+
+void ieee80211_key_replay(struct ieee80211_key_conf *keyconf)
+{
+ struct ieee80211_key *key;
+
+ key = container_of(keyconf, struct ieee80211_key, conf);
+
+ switch (key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ key->u.ccmp.replays++;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ key->u.aes_cmac.replays++;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ key->u.aes_gmac.replays++;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP:
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ key->u.gcmp.replays++;
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(ieee80211_key_replay);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 523380aed92e..dee88ec566ad 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -220,9 +220,9 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
BSS_CHANGED_ERP_SLOT;
}
-static void ieee80211_tasklet_handler(unsigned long data)
+static void ieee80211_tasklet_handler(struct tasklet_struct *t)
{
- struct ieee80211_local *local = (struct ieee80211_local *) data;
+ struct ieee80211_local *local = from_tasklet(local, t, tasklet);
struct sk_buff *skb;
while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -733,16 +733,12 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
skb_queue_head_init(&local->pending[i]);
atomic_set(&local->agg_queue_stop[i], 0);
}
- tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
- (unsigned long)local);
+ tasklet_setup(&local->tx_pending_tasklet, ieee80211_tx_pending);
if (ops->wake_tx_queue)
- tasklet_init(&local->wake_txqs_tasklet, ieee80211_wake_txqs,
- (unsigned long)local);
+ tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs);
- tasklet_init(&local->tasklet,
- ieee80211_tasklet_handler,
- (unsigned long) local);
+ tasklet_setup(&local->tasklet, ieee80211_tasklet_handler);
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);
@@ -935,14 +931,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
return -EINVAL;
}
} else {
- /*
- * WDS is currently prohibited when channel contexts are used
- * because there's no clear definition of which channel WDS
- * type interfaces use
- */
- if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
- return -EINVAL;
-
/* DFS is not supported with multi-channel combinations yet */
for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
const struct ieee80211_iface_combination *comb;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index ce5825d6f1d1..97095b7c9c64 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -667,6 +667,35 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
}
}
+static void
+ieee80211_mesh_update_bss_params(struct ieee80211_sub_if_data *sdata,
+ u8 *ie, u8 ie_len)
+{
+ struct ieee80211_supported_band *sband;
+ const u8 *cap;
+ const struct ieee80211_he_operation *he_oper = NULL;
+
+ sband = ieee80211_get_sband(sdata);
+ if (!sband)
+ return;
+
+ if (!ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT) ||
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
+ return;
+
+ sdata->vif.bss_conf.he_support = true;
+
+ cap = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION, ie, ie_len);
+ if (cap && cap[1] >= ieee80211_he_oper_size(&cap[3]))
+ he_oper = (void *)(cap + 3);
+
+ if (he_oper)
+ sdata->vif.bss_conf.he_oper.params =
+ __le32_to_cpu(he_oper->he_oper_params);
+}
+
/**
* ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
* @hdr: 802.11 frame header
@@ -943,6 +972,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
bcn->tail_len = skb->len;
memcpy(bcn->tail, skb->data, bcn->tail_len);
+ ieee80211_mesh_update_bss_params(sdata, bcn->tail, bcn->tail_len);
bcn->meshconf = (struct ieee80211_meshconf_ie *)
(bcn->tail + ifmsh->meshconf_offset);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 48f31ac9233c..620ecf922408 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -60,6 +60,7 @@ static struct mesh_table *mesh_table_alloc(void)
atomic_set(&newtbl->entries, 0);
spin_lock_init(&newtbl->gates_lock);
spin_lock_init(&newtbl->walk_lock);
+ rhashtable_init(&newtbl->rhead, &mesh_rht_params);
return newtbl;
}
@@ -773,9 +774,6 @@ int mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata)
goto free_path;
}
- rhashtable_init(&tbl_path->rhead, &mesh_rht_params);
- rhashtable_init(&tbl_mpp->rhead, &mesh_rht_params);
-
sdata->u.mesh.mesh_paths = tbl_path;
sdata->u.mesh.mpp_paths = tbl_mpp;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6adfcb9c06dc..0e4d950cf907 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1417,6 +1417,17 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return;
}
+ if (sdata->vif.bss_conf.chandef.chan->band !=
+ csa_ie.chandef.chan->band) {
+ sdata_info(sdata,
+ "AP %pM switches to different band (%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);
+ goto lock_and_drop_connection;
+ }
+
if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
IEEE80211_CHAN_DISABLED)) {
sdata_info(sdata,
@@ -1429,9 +1440,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
csa_ie.chandef.width, csa_ie.chandef.center_freq1,
csa_ie.chandef.freq1_offset,
csa_ie.chandef.center_freq2);
- ieee80211_queue_work(&local->hw,
- &ifmgd->csa_connection_drop_work);
- return;
+ goto lock_and_drop_connection;
}
if (cfg80211_chandef_identical(&csa_ie.chandef,
@@ -1493,6 +1502,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
sdata->csa_chandef = csa_ie.chandef;
sdata->csa_block_tx = csa_ie.mode;
ifmgd->csa_ignored_same_chan = false;
+ ifmgd->beacon_crc_valid = false;
if (sdata->csa_block_tx)
ieee80211_stop_vif_queues(local, sdata,
@@ -1500,7 +1510,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&local->mtx);
cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef,
- csa_ie.count);
+ csa_ie.count, csa_ie.mode);
if (local->ops->channel_switch) {
/* use driver's channel switch callback */
@@ -1516,6 +1526,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
TU_TO_EXP_TIME((csa_ie.count - 1) *
cbss->beacon_interval));
return;
+ lock_and_drop_connection:
+ mutex_lock(&local->mtx);
+ mutex_lock(&local->chanctx_mtx);
drop_connection:
/*
* This is just so that the disconnect flow will know that
@@ -1560,9 +1573,17 @@ ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
chan_increment = 1;
break;
case NL80211_BAND_5GHZ:
- case NL80211_BAND_6GHZ:
chan_increment = 4;
break;
+ case NL80211_BAND_6GHZ:
+ /*
+ * In the 6 GHz band, the "maximum transmit power level"
+ * field in the triplets is reserved, and thus will be
+ * zero and we shouldn't use it to control TX power.
+ * The actual TX power will be given in the transmit
+ * power envelope element instead.
+ */
+ return false;
}
/* find channel */
@@ -2382,6 +2403,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
/* clear bssid only after building the needed mgmt frames */
eth_zero_addr(ifmgd->bssid);
+ sdata->vif.bss_conf.ssid_len = 0;
+
/* remove AP and TDLS peers */
sta_info_flush(sdata);
@@ -2720,7 +2743,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get);
static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata,
const u8 *buf, size_t len, bool tx,
- u16 reason)
+ u16 reason, bool reconnect)
{
struct ieee80211_event event = {
.type = MLME_EVENT,
@@ -2729,7 +2752,7 @@ static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata,
};
if (tx)
- cfg80211_tx_mlme_mgmt(sdata->dev, buf, len);
+ cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, reconnect);
else
cfg80211_rx_mlme_mgmt(sdata->dev, buf, len);
@@ -2751,13 +2774,18 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
tx = !sdata->csa_block_tx;
- /* AP is probably out of range (or not reachable for another reason) so
- * remove the bss struct for that AP.
- */
- cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated);
+ if (!ifmgd->driver_disconnect) {
+ /*
+ * AP is probably out of range (or not reachable for another
+ * reason) so remove the bss struct for that AP.
+ */
+ cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated);
+ }
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+ ifmgd->driver_disconnect ?
+ WLAN_REASON_DEAUTH_LEAVING :
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
tx, frame_buf);
mutex_lock(&local->mtx);
sdata->vif.csa_active = false;
@@ -2770,7 +2798,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&local->mtx);
ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx,
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+ ifmgd->reconnect);
+ ifmgd->reconnect = false;
sdata_unlock(sdata);
}
@@ -2789,6 +2819,13 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
sdata_info(sdata, "Connection to AP %pM lost\n",
ifmgd->bssid);
__ieee80211_disconnect(sdata);
+ ifmgd->connection_loss = false;
+ } else if (ifmgd->driver_disconnect) {
+ sdata_info(sdata,
+ "Driver requested disconnection from AP %pM\n",
+ ifmgd->bssid);
+ __ieee80211_disconnect(sdata);
+ ifmgd->driver_disconnect = false;
} else {
ieee80211_mgd_probe_ap(sdata, true);
}
@@ -2827,6 +2864,21 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif)
}
EXPORT_SYMBOL(ieee80211_connection_loss);
+void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_hw *hw = &sdata->local->hw;
+
+ trace_api_disconnect(sdata, reconnect);
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+ return;
+
+ sdata->u.mgd.driver_disconnect = true;
+ sdata->u.mgd.reconnect = reconnect;
+ ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
+}
+EXPORT_SYMBOL(ieee80211_disconnect);
static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
bool assoc)
@@ -3130,7 +3182,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false,
- reason_code);
+ reason_code, false);
return;
}
@@ -3179,7 +3231,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
- ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code);
+ ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code,
+ false);
}
static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
@@ -3199,8 +3252,8 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
*have_higher_than_11mbit = true;
/*
- * Skip HT, VHT and HE BSS membership selectors since they're
- * not rates.
+ * Skip HT, VHT, HE and SAE H2E only BSS membership selectors
+ * since they're not rates.
*
* Note: Even though the membership selector and the basic
* rate flag share the same bit, they are not exactly
@@ -3208,7 +3261,8 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
*/
if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) ||
supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY) ||
- supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY))
+ supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY) ||
+ supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E))
continue;
for (j = 0; j < sband->n_bitrates; j++) {
@@ -3494,14 +3548,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
le32_get_bits(elems->he_operation->he_oper_params,
IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
- bss_conf->multi_sta_back_32bit =
- sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
- IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP;
-
- bss_conf->ack_enabled =
- sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
- IEEE80211_HE_MAC_CAP2_ACK_EN;
-
bss_conf->uora_exists = !!elems->uora_element;
if (elems->uora_element)
bss_conf->uora_ocw_range = elems->uora_element[0];
@@ -4199,7 +4245,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
true, deauth_buf);
ieee80211_report_disconnect(sdata, deauth_buf,
sizeof(deauth_buf), true,
- WLAN_REASON_DEAUTH_LEAVING);
+ WLAN_REASON_DEAUTH_LEAVING,
+ false);
return;
}
@@ -4344,7 +4391,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
tx, frame_buf);
ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
- reason);
+ reason, false);
}
static int ieee80211_auth(struct ieee80211_sub_if_data *sdata)
@@ -4716,7 +4763,8 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
if (ifmgd->auth_data)
ieee80211_destroy_auth_data(sdata, false);
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
- IEEE80211_DEAUTH_FRAME_LEN);
+ IEEE80211_DEAUTH_FRAME_LEN,
+ false);
}
/* This is a bit of a hack - we should find a better and more generic
@@ -5430,7 +5478,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- WLAN_REASON_UNSPECIFIED);
+ WLAN_REASON_UNSPECIFIED,
+ false);
}
sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
@@ -5471,6 +5520,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgd_assoc_data *assoc_data;
const struct cfg80211_bss_ies *beacon_ies;
struct ieee80211_supported_band *sband;
+ struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
const u8 *ssidie, *ht_ie, *vht_ie;
int i, err;
bool override = false;
@@ -5488,6 +5538,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
}
memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]);
assoc_data->ssid_len = ssidie[1];
+ memcpy(bss_conf->ssid, assoc_data->ssid, assoc_data->ssid_len);
+ bss_conf->ssid_len = assoc_data->ssid_len;
rcu_read_unlock();
if (ifmgd->associated) {
@@ -5502,7 +5554,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- WLAN_REASON_UNSPECIFIED);
+ WLAN_REASON_UNSPECIFIED,
+ false);
}
if (ifmgd->auth_data && !ifmgd->auth_data->done) {
@@ -5801,7 +5854,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_destroy_auth_data(sdata, false);
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- req->reason_code);
+ req->reason_code, false);
return 0;
}
@@ -5821,7 +5874,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_destroy_assoc_data(sdata, false, true);
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- req->reason_code);
+ req->reason_code, false);
return 0;
}
@@ -5836,7 +5889,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
req->reason_code, tx, frame_buf);
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- req->reason_code);
+ req->reason_code, false);
return 0;
}
@@ -5869,7 +5922,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
frame_buf);
ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
- req->reason_code);
+ req->reason_code, false);
return 0;
}
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 38c45e1dafd8..ae378a41c927 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -150,21 +150,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
case NL80211_IFTYPE_STATION:
ieee80211_mgd_quiesce(sdata);
break;
- case NL80211_IFTYPE_WDS:
- /* tear down aggregation sessions and remove STAs */
- mutex_lock(&local->sta_mtx);
- sta = sdata->u.wds.sta;
- if (sta && sta->uploaded) {
- enum ieee80211_sta_state state;
-
- state = sta->sta_state;
- for (; state > IEEE80211_STA_NOTEXIST; state--)
- WARN_ON(drv_sta_state(local, sta->sdata,
- sta, state,
- state - 1));
- }
- mutex_unlock(&local->sta_mtx);
- break;
default:
break;
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1e2e5a406d58..13b9bcc4865d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -32,16 +32,6 @@
#include "wme.h"
#include "rate.h"
-static inline void ieee80211_rx_stats(struct net_device *dev, u32 len)
-{
- struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
-
- u64_stats_update_begin(&tstats->syncp);
- tstats->rx_packets++;
- tstats->rx_bytes += len;
- u64_stats_update_end(&tstats->syncp);
-}
-
/*
* monitor mode reception
*
@@ -842,7 +832,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
if (skb) {
skb->dev = sdata->dev;
- ieee80211_rx_stats(skb->dev, skb->len);
+ dev_sw_netstats_rx_add(skb->dev, skb->len);
netif_receive_skb(skb);
}
}
@@ -1477,7 +1467,6 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
if (unlikely((ieee80211_is_data(hdr->frame_control) ||
ieee80211_is_pspoll(hdr->frame_control)) &&
rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
rx->sdata->vif.type != NL80211_IFTYPE_OCB &&
(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
/*
@@ -1758,7 +1747,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
} else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
sta->rx_stats.last_rx = jiffies;
} else if (!ieee80211_is_s1g_beacon(hdr->frame_control) &&
- is_multicast_ether_addr(hdr->addr1)) {
+ !is_multicast_ether_addr(hdr->addr1)) {
/*
* Mesh beacons will update last_rx when if they are found to
* match the current local configuration when processed.
@@ -2560,7 +2549,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
skb = rx->skb;
xmit_skb = NULL;
- ieee80211_rx_stats(dev, skb->len);
+ dev_sw_netstats_rx_add(dev, skb->len);
if (rx->sta) {
/* The seqno index has the same property as needed
@@ -3699,7 +3688,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
}
prev_dev = sdata->dev;
- ieee80211_rx_stats(sdata->dev, skb->len);
+ dev_sw_netstats_rx_add(sdata->dev, skb->len);
}
if (prev_dev) {
@@ -4080,10 +4069,6 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
return false;
return true;
- case NL80211_IFTYPE_WDS:
- if (bssid || !ieee80211_is_data(hdr->frame_control))
- return false;
- return ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2);
case NL80211_IFTYPE_P2P_DEVICE:
return ieee80211_is_public_action(hdr, skb->len) ||
ieee80211_is_probe_req(hdr->frame_control) ||
@@ -4416,7 +4401,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
skb->dev = fast_rx->dev;
- ieee80211_rx_stats(fast_rx->dev, skb->len);
+ dev_sw_netstats_rx_add(fast_rx->dev, skb->len);
/* The seqno index has the same property as needed
* for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
@@ -4742,6 +4727,8 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
status->rx_flags = 0;
+ kcov_remote_start_common(skb_get_kcov_handle(skb));
+
/*
* Frames with failed FCS/PLCP checksum are not returned,
* all other frames are returned without radiotap header
@@ -4749,15 +4736,15 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
* Also, frames with less than 16 bytes are dropped.
*/
skb = ieee80211_rx_monitor(local, skb, rate);
- if (!skb)
- return;
-
- ieee80211_tpt_led_trig_rx(local,
- ((struct ieee80211_hdr *)skb->data)->frame_control,
- skb->len);
+ if (skb) {
+ ieee80211_tpt_led_trig_rx(local,
+ ((struct ieee80211_hdr *)skb->data)->frame_control,
+ skb->len);
- __ieee80211_rx_handle_packet(hw, pubsta, skb, list);
+ __ieee80211_rx_handle_packet(hw, pubsta, skb, list);
+ }
+ kcov_remote_stop();
return;
drop:
kfree_skb(skb);
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 89723907a094..601322e16957 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2,7 +2,7 @@
/*
* Portions of this file
* Copyright(c) 2016-2017 Intel Deutschland GmbH
-* Copyright (C) 2018 - 2019 Intel Corporation
+* Copyright (C) 2018 - 2020 Intel Corporation
*/
#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
@@ -2086,6 +2086,27 @@ TRACE_EVENT(api_connection_loss,
)
);
+TRACE_EVENT(api_disconnect,
+ TP_PROTO(struct ieee80211_sub_if_data *sdata, bool reconnect),
+
+ TP_ARGS(sdata, reconnect),
+
+ TP_STRUCT__entry(
+ VIF_ENTRY
+ __field(int, reconnect)
+ ),
+
+ TP_fast_assign(
+ VIF_ASSIGN;
+ __entry->reconnect = reconnect;
+ ),
+
+ TP_printk(
+ VIF_PR_FMT " reconnect:%d",
+ VIF_PR_ARG, __entry->reconnect
+ )
+);
+
TRACE_EVENT(api_cqm_rssi_notify,
TP_PROTO(struct ieee80211_sub_if_data *sdata,
enum nl80211_cqm_rssi_threshold_event rssi_event,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 56a4d0d20a26..6422da6690f7 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -38,16 +38,6 @@
/* misc utils */
-static inline void ieee80211_tx_stats(struct net_device *dev, u32 len)
-{
- struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
-
- u64_stats_update_begin(&tstats->syncp);
- tstats->tx_packets++;
- tstats->tx_bytes += len;
- u64_stats_update_end(&tstats->syncp);
-}
-
static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
struct sk_buff *skb, int group_addr,
int next_frag_len)
@@ -319,9 +309,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (tx->sdata->vif.type == NL80211_IFTYPE_OCB)
return TX_CONTINUE;
- if (tx->sdata->vif.type == NL80211_IFTYPE_WDS)
- return TX_CONTINUE;
-
if (tx->flags & IEEE80211_TX_PS_BUFFERED)
return TX_CONTINUE;
@@ -2113,6 +2100,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
info->flags |= IEEE80211_TX_CTL_NO_ACK;
if (txflags & IEEE80211_RADIOTAP_F_TX_NOSEQNO)
info->control.flags |= IEEE80211_TX_CTRL_NO_SEQNO;
+ if (txflags & IEEE80211_RADIOTAP_F_TX_ORDER)
+ info->control.flags |=
+ IEEE80211_TX_CTRL_DONT_REORDER;
break;
case IEEE80211_RADIOTAP_RATE:
@@ -2279,11 +2269,13 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
payload[7]);
}
- /*
- * Initialize skb->priority for QoS frames. This is put in the TID field
- * of the frame before passing it to the driver.
+ /* Initialize skb->priority for QoS frames. If the DONT_REORDER flag
+ * is set, stick to the default value for skb->priority to assure
+ * frames injected with this flag are not reordered relative to each
+ * other.
*/
- if (ieee80211_is_data_qos(hdr->frame_control)) {
+ if (ieee80211_is_data_qos(hdr->frame_control) &&
+ !(info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER)) {
u8 *p = ieee80211_get_qos_ctl(hdr);
skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
}
@@ -2295,8 +2287,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
* we handle as though they are non-injected frames.
* This code here isn't entirely correct, the local MAC address
* isn't always enough to find the interface to use; for proper
- * VLAN/WDS support we will need a different mechanism (which
- * likely isn't going to be monitor interfaces).
+ * VLAN support we have an nl80211-based mechanism.
*
* This is necessary, for example, for old hostapd versions that
* don't use nl80211-based management TX/RX.
@@ -2307,8 +2298,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
if (!ieee80211_sdata_running(tmp_sdata))
continue;
if (tmp_sdata->vif.type == NL80211_IFTYPE_MONITOR ||
- tmp_sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
- tmp_sdata->vif.type == NL80211_IFTYPE_WDS)
+ tmp_sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
continue;
if (ether_addr_equal(tmp_sdata->vif.addr, hdr->addr2)) {
sdata = tmp_sdata;
@@ -2402,9 +2392,6 @@ int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
}
sta = sta_info_get_bss(sdata, skb->data);
break;
- case NL80211_IFTYPE_WDS:
- sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
- break;
#ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT:
/* determined much later */
@@ -2580,20 +2567,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
hdrlen = 24;
band = chanctx_conf->def.chan->band;
break;
- case NL80211_IFTYPE_WDS:
- fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
- /* RA TA DA SA */
- memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
- memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
- memcpy(hdr.addr3, skb->data, ETH_ALEN);
- memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
- hdrlen = 30;
- /*
- * This is the exception! WDS style interfaces are prohibited
- * when channel contexts are in used so this must be valid
- */
- band = local->hw.conf.chandef.chan->band;
- break;
#ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT:
if (!is_multicast_ether_addr(skb->data)) {
@@ -3403,7 +3376,7 @@ static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
if (key)
info->control.hw_key = &key->conf;
- ieee80211_tx_stats(skb->dev, skb->len);
+ dev_sw_netstats_tx_add(skb->dev, 1, skb->len);
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
@@ -4021,7 +3994,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
goto out;
}
- ieee80211_tx_stats(dev, skb->len);
+ dev_sw_netstats_tx_add(dev, 1, skb->len);
ieee80211_xmit(sdata, sta, skb);
}
@@ -4248,7 +4221,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
- ieee80211_tx_stats(dev, skb->len);
+ dev_sw_netstats_tx_add(dev, 1, skb->len);
sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
@@ -4418,9 +4391,10 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
/*
* Transmit all pending packets. Called from tasklet.
*/
-void ieee80211_tx_pending(unsigned long data)
+void ieee80211_tx_pending(struct tasklet_struct *t)
{
- struct ieee80211_local *local = (struct ieee80211_local *)data;
+ struct ieee80211_local *local = from_tasklet(local, t,
+ tx_pending_tasklet);
unsigned long flags;
int i;
bool txok;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 49342060490f..8d3ae6b2f95f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -386,9 +386,10 @@ _ieee80211_wake_txqs(struct ieee80211_local *local, unsigned long *flags)
rcu_read_unlock();
}
-void ieee80211_wake_txqs(unsigned long data)
+void ieee80211_wake_txqs(struct tasklet_struct *t)
{
- struct ieee80211_local *local = (struct ieee80211_local *)data;
+ struct ieee80211_local *local = from_tasklet(local, t,
+ wake_txqs_tasklet);
unsigned long flags;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
@@ -2513,7 +2514,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
return res;
}
break;
- case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_P2P_DEVICE:
@@ -2523,6 +2523,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_WDS:
WARN_ON(1);
break;
}
@@ -3455,7 +3456,7 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
*chandef = he_chandef;
- return false;
+ return true;
}
bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper,
@@ -3665,6 +3666,7 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
u64 ts = status->mactime;
struct rate_info ri;
u16 rate;
+ u8 n_ltf;
if (WARN_ON(!ieee80211_have_rx_timestamp(status)))
return 0;
@@ -3675,11 +3677,58 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
/* Fill cfg80211 rate info */
switch (status->encoding) {
+ case RX_ENC_HE:
+ ri.flags |= RATE_INFO_FLAGS_HE_MCS;
+ ri.mcs = status->rate_idx;
+ ri.nss = status->nss;
+ ri.he_ru_alloc = status->he_ru;
+ if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
+ ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+ /*
+ * See P802.11ax_D6.0, section 27.3.4 for
+ * VHT PPDU format.
+ */
+ if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
+ mpdu_offset += 2;
+ ts += 36;
+
+ /*
+ * TODO:
+ * For HE MU PPDU, add the HE-SIG-B.
+ * For HE ER PPDU, add 8us for the HE-SIG-A.
+ * For HE TB PPDU, add 4us for the HE-STF.
+ * Add the HE-LTF durations - variable.
+ */
+ }
+
+ break;
case RX_ENC_HT:
ri.mcs = status->rate_idx;
ri.flags |= RATE_INFO_FLAGS_MCS;
if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+ /*
+ * See P802.11REVmd_D3.0, section 19.3.2 for
+ * HT PPDU format.
+ */
+ if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
+ mpdu_offset += 2;
+ if (status->enc_flags & RX_ENC_FLAG_HT_GF)
+ ts += 24;
+ else
+ ts += 32;
+
+ /*
+ * Add Data HT-LTFs per streams
+ * TODO: add Extension HT-LTFs, 4us per LTF
+ */
+ n_ltf = ((ri.mcs >> 3) & 3) + 1;
+ n_ltf = n_ltf == 3 ? 4 : n_ltf;
+ ts += n_ltf * 4;
+ }
+
break;
case RX_ENC_VHT:
ri.flags |= RATE_INFO_FLAGS_VHT_MCS;
@@ -3687,6 +3736,23 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
ri.nss = status->nss;
if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+ /*
+ * See P802.11REVmd_D3.0, section 21.3.2 for
+ * VHT PPDU format.
+ */
+ if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
+ mpdu_offset += 2;
+ ts += 36;
+
+ /*
+ * Add VHT-LTFs per streams
+ */
+ n_ltf = (ri.nss != 1) && (ri.nss % 2) ?
+ ri.nss + 1 : ri.nss;
+ ts += 4 * n_ltf;
+ }
+
break;
default:
WARN_ON(1);
@@ -3710,7 +3776,6 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
- /* TODO: handle HT/VHT preambles */
if (status->band == NL80211_BAND_5GHZ) {
ts += 20 << shift;
mpdu_offset += 2;
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index fb0e3a657d2d..c3ca97373774 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -465,12 +465,18 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
* IEEE80211-2016 specification makes higher bandwidth operation
* possible on the TDLS link if the peers have wider bandwidth
* capability.
+ *
+ * However, in this case, and only if the TDLS peer is authorized,
+ * limit to the tdls_chandef so that the configuration here isn't
+ * wider than what's actually requested on the channel context.
*/
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
- test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW))
- return bw;
-
- bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width));
+ test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) &&
+ test_sta_flag(sta, WLAN_STA_AUTHORIZED) &&
+ sta->tdls_chandef.chan)
+ bw = min(bw, ieee80211_chan_width_to_rx_bw(sta->tdls_chandef.width));
+ else
+ bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width));
return bw;
}
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 2fb99325135a..9ea6004abe1b 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -118,9 +118,11 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr)
{
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *p;
- if (local->hw.queues < IEEE80211_NUM_ACS)
+ if ((info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER) ||
+ local->hw.queues < IEEE80211_NUM_ACS)
return 0;
if (!ieee80211_is_data(hdr->frame_control)) {
@@ -141,6 +143,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct mac80211_qos_map *qos_map;
bool qos;
@@ -153,7 +156,7 @@ u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
else
qos = false;
- if (!qos) {
+ if (!qos || (info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER)) {
skb->priority = 0; /* required for correct WPA/11i MIC */
return IEEE80211_AC_BE;
}
@@ -202,9 +205,6 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP:
ra = skb->data;
break;
- case NL80211_IFTYPE_WDS:
- ra = sdata->u.wds.remote_addr;
- break;
case NL80211_IFTYPE_STATION:
/* might be a TDLS station */
sta = sta_info_get(sdata, skb->data);
@@ -249,6 +249,14 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
p = ieee80211_get_qos_ctl(hdr);
+ /* don't overwrite the QoS field of injected frames */
+ if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+ /* do take into account Ack policy of injected frames */
+ if (*p & IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ return;
+ }
+
/* set up the first byte */
/*