Merge tag 'mac80211-next-for-davem-2019-04-26' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says: ==================== Various updates, notably: * extended key ID support (from 802.11-2016) * per-STA TX power control support * mac80211 TX performance improvements * HE (802.11ax) updates * mesh link probing support * enhancements of multi-BSSID support (also related to HE) * OWE userspace processing support ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -351,6 +351,36 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_set_tx(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *mac_addr, u8 key_idx)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_key *key;
|
||||
struct sta_info *sta;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_EXT_KEY_ID))
|
||||
return -EINVAL;
|
||||
|
||||
sta = sta_info_get_bss(sdata, mac_addr);
|
||||
|
||||
if (!sta)
|
||||
return -EINVAL;
|
||||
|
||||
if (sta->ptk_idx == key_idx)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&local->key_mtx);
|
||||
key = key_mtx_dereference(local, sta->ptk[key_idx]);
|
||||
|
||||
if (key && key->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)
|
||||
ret = ieee80211_set_tx_key(key);
|
||||
|
||||
mutex_unlock(&local->key_mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_idx, bool pairwise, const u8 *mac_addr,
|
||||
struct key_params *params)
|
||||
@@ -365,6 +395,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return -ENETDOWN;
|
||||
|
||||
if (pairwise && params->mode == NL80211_KEY_SET_TX)
|
||||
return ieee80211_set_tx(sdata, mac_addr, key_idx);
|
||||
|
||||
/* reject WEP and TKIP keys if WEP failed to initialize */
|
||||
switch (params->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
@@ -396,6 +429,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
if (pairwise)
|
||||
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
|
||||
|
||||
if (params->mode == NL80211_KEY_NO_TX)
|
||||
key->conf.flags |= IEEE80211_KEY_FLAG_NO_AUTO_TX;
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
if (mac_addr) {
|
||||
@@ -1421,6 +1457,15 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||
if (params->listen_interval >= 0)
|
||||
sta->listen_interval = params->listen_interval;
|
||||
|
||||
if (params->sta_modify_mask & STATION_PARAM_APPLY_STA_TXPOWER) {
|
||||
sta->sta.txpwr.type = params->txpwr.type;
|
||||
if (params->txpwr.type == NL80211_TX_POWER_LIMITED)
|
||||
sta->sta.txpwr.power = params->txpwr.power;
|
||||
ret = drv_sta_set_txpwr(local, sdata, sta);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (params->supported_rates) {
|
||||
ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
|
||||
sband, params->supported_rates,
|
||||
@@ -3990,4 +4035,5 @@ const struct cfg80211_ops mac80211_config_ops = {
|
||||
.get_ftm_responder_stats = ieee80211_get_ftm_responder_stats,
|
||||
.start_pmsr = ieee80211_start_pmsr,
|
||||
.abort_pmsr = ieee80211_abort_pmsr,
|
||||
.probe_mesh_link = ieee80211_probe_mesh_link,
|
||||
};
|
||||
|
@@ -150,6 +150,58 @@ static const struct file_operations aqm_ops = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t force_tx_status_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
char buf[3];
|
||||
int len = 0;
|
||||
|
||||
len = scnprintf(buf, sizeof(buf), "%d\n", (int)local->force_tx_status);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
buf, len);
|
||||
}
|
||||
|
||||
static ssize_t force_tx_status_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_local *local = file->private_data;
|
||||
char buf[3];
|
||||
size_t len;
|
||||
|
||||
if (count > sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(buf, user_buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
len = strlen(buf);
|
||||
if (len > 0 && buf[len - 1] == '\n')
|
||||
buf[len - 1] = 0;
|
||||
|
||||
if (buf[0] == '0' && buf[1] == '\0')
|
||||
local->force_tx_status = 0;
|
||||
else if (buf[0] == '1' && buf[1] == '\0')
|
||||
local->force_tx_status = 1;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations force_tx_status_ops = {
|
||||
.write = force_tx_status_write,
|
||||
.read = force_tx_status_read,
|
||||
.open = simple_open,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static ssize_t reset_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
@@ -221,6 +273,7 @@ static const char *hw_flag_names[] = {
|
||||
FLAG(TX_STATUS_NO_AMPDU_LEN),
|
||||
FLAG(SUPPORTS_MULTI_BSSID),
|
||||
FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
|
||||
FLAG(EXT_KEY_ID_NATIVE),
|
||||
#undef FLAG
|
||||
};
|
||||
|
||||
@@ -382,6 +435,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
||||
DEBUGFS_ADD(hwflags);
|
||||
DEBUGFS_ADD(user_power);
|
||||
DEBUGFS_ADD(power);
|
||||
DEBUGFS_ADD_MODE(force_tx_status, 0600);
|
||||
|
||||
if (local->ops->wake_tx_queue)
|
||||
DEBUGFS_ADD_MODE(aqm, 0600);
|
||||
|
@@ -138,6 +138,27 @@ int drv_sta_state(struct ieee80211_local *local,
|
||||
return ret;
|
||||
}
|
||||
|
||||
__must_check
|
||||
int drv_sta_set_txpwr(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
might_sleep();
|
||||
|
||||
sdata = get_bss_sdata(sdata);
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
trace_drv_sta_set_txpwr(local, sdata, &sta->sta);
|
||||
if (local->ops->sta_set_txpwr)
|
||||
ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif,
|
||||
&sta->sta);
|
||||
trace_drv_return_int(local, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void drv_sta_rc_update(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta, u32 changed)
|
||||
|
@@ -529,6 +529,11 @@ int drv_sta_state(struct ieee80211_local *local,
|
||||
enum ieee80211_sta_state old_state,
|
||||
enum ieee80211_sta_state new_state);
|
||||
|
||||
__must_check
|
||||
int drv_sta_set_txpwr(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta);
|
||||
|
||||
void drv_sta_rc_update(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta, u32 changed);
|
||||
|
@@ -1269,7 +1269,7 @@ struct ieee80211_local {
|
||||
|
||||
/*
|
||||
* Key mutex, protects sdata's key_list and sta_info's
|
||||
* key pointers (write access, they're RCU.)
|
||||
* key pointers and ptk_idx (write access, they're RCU.)
|
||||
*/
|
||||
struct mutex key_mtx;
|
||||
|
||||
@@ -1384,6 +1384,7 @@ struct ieee80211_local {
|
||||
struct dentry *rcdir;
|
||||
struct dentry *keys;
|
||||
} debugfs;
|
||||
bool force_tx_status;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1505,7 +1506,6 @@ struct ieee802_11_elems {
|
||||
const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie;
|
||||
const struct ieee80211_multiple_bssid_configuration *mbssid_config_ie;
|
||||
const struct ieee80211_bssid_index *bssid_index;
|
||||
const u8 *nontransmitted_bssid_profile;
|
||||
u8 max_bssid_indicator;
|
||||
u8 dtim_count;
|
||||
u8 dtim_period;
|
||||
@@ -1761,7 +1761,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
u32 info_flags);
|
||||
u32 info_flags,
|
||||
u32 ctrl_flags);
|
||||
void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
|
||||
struct sk_buff_head *skbs);
|
||||
struct sk_buff *
|
||||
@@ -1778,6 +1779,8 @@ void ieee80211_clear_fast_xmit(struct sta_info *sta);
|
||||
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *buf, size_t len,
|
||||
const u8 *dest, __be16 proto, bool unencrypted);
|
||||
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *buf, size_t len);
|
||||
|
||||
/* HT */
|
||||
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
|
@@ -1225,6 +1225,7 @@ static void ieee80211_if_setup(struct net_device *dev)
|
||||
static void ieee80211_if_setup_no_queue(struct net_device *dev)
|
||||
{
|
||||
ieee80211_if_setup(dev);
|
||||
dev->features |= NETIF_F_LLTX;
|
||||
dev->priv_flags |= IFF_NO_QUEUE;
|
||||
}
|
||||
|
||||
@@ -1762,13 +1763,13 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
txq_size += sizeof(struct txq_info) +
|
||||
local->hw.txq_data_size;
|
||||
|
||||
if (local->ops->wake_tx_queue)
|
||||
if (local->ops->wake_tx_queue) {
|
||||
if_setup = ieee80211_if_setup_no_queue;
|
||||
else
|
||||
} else {
|
||||
if_setup = ieee80211_if_setup;
|
||||
|
||||
if (local->hw.queues >= IEEE80211_NUM_ACS)
|
||||
txqs = IEEE80211_NUM_ACS;
|
||||
if (local->hw.queues >= IEEE80211_NUM_ACS)
|
||||
txqs = IEEE80211_NUM_ACS;
|
||||
}
|
||||
|
||||
ndev = alloc_netdev_mqs(size + txq_size,
|
||||
name, name_assign_type,
|
||||
|
@@ -140,6 +140,12 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
||||
* so clear that flag now to avoid trying to remove
|
||||
* it again later.
|
||||
*/
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
|
||||
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
|
||||
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
||||
increment_tailroom_need_count(sdata);
|
||||
|
||||
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -179,9 +185,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
||||
if (!ret) {
|
||||
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
|
||||
|
||||
if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
|
||||
IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) ||
|
||||
(key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
||||
if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
|
||||
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
|
||||
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
||||
decrease_tailroom_need_count(sdata, 1);
|
||||
|
||||
WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
|
||||
@@ -242,9 +248,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
||||
sta = key->sta;
|
||||
sdata = key->sdata;
|
||||
|
||||
if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
|
||||
IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) ||
|
||||
(key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
||||
if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
|
||||
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
|
||||
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
||||
increment_tailroom_need_count(sdata);
|
||||
|
||||
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
|
||||
@@ -258,9 +264,24 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
||||
sta ? sta->sta.addr : bcast_addr, ret);
|
||||
}
|
||||
|
||||
int ieee80211_set_tx_key(struct ieee80211_key *key)
|
||||
{
|
||||
struct sta_info *sta = key->sta;
|
||||
struct ieee80211_local *local = key->local;
|
||||
struct ieee80211_key *old;
|
||||
|
||||
assert_key_lock(local);
|
||||
|
||||
old = key_mtx_dereference(local, sta->ptk[sta->ptk_idx]);
|
||||
sta->ptk_idx = key->conf.keyidx;
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
|
||||
struct ieee80211_key *new_key,
|
||||
bool ptk0rekey)
|
||||
bool pairwise)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_local *local;
|
||||
@@ -277,8 +298,9 @@ static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
|
||||
assert_key_lock(old_key->local);
|
||||
sta = old_key->sta;
|
||||
|
||||
/* PTK only using key ID 0 needs special handling on rekey */
|
||||
if (new_key && sta && ptk0rekey) {
|
||||
/* Unicast rekey without Extended Key ID needs special handling */
|
||||
if (new_key && sta && pairwise &&
|
||||
rcu_access_pointer(sta->ptk[sta->ptk_idx]) == old_key) {
|
||||
local = old_key->local;
|
||||
sdata = old_key->sdata;
|
||||
|
||||
@@ -394,10 +416,6 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (old) {
|
||||
idx = old->conf.keyidx;
|
||||
/* TODO: proper implement and test "Extended Key ID for
|
||||
* Individually Addressed Frames" from IEEE 802.11-2016.
|
||||
* Till then always assume only key ID 0 is used for
|
||||
* pairwise keys.*/
|
||||
ret = ieee80211_hw_key_replace(old, new, pairwise);
|
||||
} else {
|
||||
/* new must be provided in case old is not */
|
||||
@@ -414,15 +432,20 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
||||
if (sta) {
|
||||
if (pairwise) {
|
||||
rcu_assign_pointer(sta->ptk[idx], new);
|
||||
sta->ptk_idx = idx;
|
||||
if (new) {
|
||||
if (new &&
|
||||
!(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) {
|
||||
sta->ptk_idx = idx;
|
||||
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||
ieee80211_check_fast_xmit(sta);
|
||||
}
|
||||
} else {
|
||||
rcu_assign_pointer(sta->gtk[idx], new);
|
||||
}
|
||||
if (new)
|
||||
/* Only needed for transition from no key -> key.
|
||||
* Still triggers unnecessary when using Extended Key ID
|
||||
* and installing the second key ID the first time.
|
||||
*/
|
||||
if (new && !old)
|
||||
ieee80211_check_fast_rx(sta);
|
||||
} else {
|
||||
defunikey = old &&
|
||||
@@ -738,16 +761,34 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
||||
* can cause warnings to appear.
|
||||
*/
|
||||
bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
|
||||
int ret;
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&sdata->local->key_mtx);
|
||||
|
||||
if (sta && pairwise)
|
||||
if (sta && pairwise) {
|
||||
struct ieee80211_key *alt_key;
|
||||
|
||||
old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
|
||||
else if (sta)
|
||||
alt_key = key_mtx_dereference(sdata->local, sta->ptk[idx ^ 1]);
|
||||
|
||||
/* The rekey code assumes that the old and new key are using
|
||||
* the same cipher. Enforce the assumption for pairwise keys.
|
||||
*/
|
||||
if (key &&
|
||||
((alt_key && alt_key->conf.cipher != key->conf.cipher) ||
|
||||
(old_key && old_key->conf.cipher != key->conf.cipher)))
|
||||
goto out;
|
||||
} else if (sta) {
|
||||
old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
|
||||
else
|
||||
} else {
|
||||
old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
|
||||
}
|
||||
|
||||
/* Non-pairwise keys must also not switch the cipher on rekey */
|
||||
if (!pairwise) {
|
||||
if (key && old_key && old_key->conf.cipher != key->conf.cipher)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Silently accept key re-installation without really installing the
|
||||
@@ -1187,9 +1228,9 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
|
||||
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
|
||||
|
||||
if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
|
||||
IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) ||
|
||||
(key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
||||
if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
|
||||
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
|
||||
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
|
||||
increment_tailroom_need_count(key->sdata);
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@
|
||||
|
||||
#define NUM_DEFAULT_KEYS 4
|
||||
#define NUM_DEFAULT_MGMT_KEYS 2
|
||||
#define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */
|
||||
|
||||
struct ieee80211_local;
|
||||
struct ieee80211_sub_if_data;
|
||||
@@ -146,6 +147,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
|
||||
int ieee80211_key_link(struct ieee80211_key *key,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta);
|
||||
int ieee80211_set_tx_key(struct ieee80211_key *key);
|
||||
void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
|
||||
void ieee80211_key_free_unused(struct ieee80211_key *key);
|
||||
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
|
||||
|
@@ -1051,6 +1051,22 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable Extended Key IDs when driver allowed it, or when it
|
||||
* supports neither HW crypto nor A-MPDUs
|
||||
*/
|
||||
if ((!local->ops->set_key &&
|
||||
!ieee80211_hw_check(hw, AMPDU_AGGREGATION)) ||
|
||||
ieee80211_hw_check(&local->hw, EXT_KEY_ID_NATIVE))
|
||||
wiphy_ext_feature_set(local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_EXT_KEY_ID);
|
||||
|
||||
/* Mac80211 and therefore all cards only using SW crypto are able to
|
||||
* handle PTK rekeys correctly
|
||||
*/
|
||||
if (!local->ops->set_key)
|
||||
wiphy_ext_feature_set(local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
|
||||
|
||||
/*
|
||||
* Calculate scan IE length -- we need this to alloc
|
||||
* memory and to subtract from the driver limit. It
|
||||
|
@@ -278,6 +278,8 @@ mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst);
|
||||
int mesh_path_add_gate(struct mesh_path *mpath);
|
||||
int mesh_path_send_to_gates(struct mesh_path *mpath);
|
||||
int mesh_gate_num(struct ieee80211_sub_if_data *sdata);
|
||||
u32 airtime_link_metric_get(struct ieee80211_local *local,
|
||||
struct sta_info *sta);
|
||||
|
||||
/* Mesh plinks */
|
||||
void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
|
||||
|
@@ -318,8 +318,8 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
|
||||
cfg80211_calculate_bitrate(&rinfo));
|
||||
}
|
||||
|
||||
static u32 airtime_link_metric_get(struct ieee80211_local *local,
|
||||
struct sta_info *sta)
|
||||
u32 airtime_link_metric_get(struct ieee80211_local *local,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
/* This should be adjusted for each device */
|
||||
int device_constant = 1 << ARITH_SHIFT;
|
||||
@@ -1130,16 +1130,17 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
|
||||
struct mesh_path *mpath;
|
||||
struct sk_buff *skb_to_free = NULL;
|
||||
u8 *target_addr = hdr->addr3;
|
||||
int err = 0;
|
||||
|
||||
/* Nulls are only sent to peers for PS and should be pre-addressed */
|
||||
if (ieee80211_is_qos_nullfunc(hdr->frame_control))
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
err = mesh_nexthop_lookup(sdata, skb);
|
||||
if (!err)
|
||||
goto endlookup;
|
||||
/* Allow injected packets to bypass mesh routing */
|
||||
if (info->control.flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP)
|
||||
return 0;
|
||||
|
||||
if (!mesh_nexthop_lookup(sdata, skb))
|
||||
return 0;
|
||||
|
||||
/* no nexthop found, start resolving */
|
||||
mpath = mesh_path_lookup(sdata, target_addr);
|
||||
@@ -1147,8 +1148,7 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
|
||||
mpath = mesh_path_add(sdata, target_addr);
|
||||
if (IS_ERR(mpath)) {
|
||||
mesh_path_discard_frame(sdata, skb);
|
||||
err = PTR_ERR(mpath);
|
||||
goto endlookup;
|
||||
return PTR_ERR(mpath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1161,13 +1161,10 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
|
||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||
ieee80211_set_qos_hdr(sdata, skb);
|
||||
skb_queue_tail(&mpath->frame_queue, skb);
|
||||
err = -ENOENT;
|
||||
if (skb_to_free)
|
||||
mesh_path_discard_frame(sdata, skb_to_free);
|
||||
|
||||
endlookup:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1187,13 +1184,10 @@ int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *next_hop;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u8 *target_addr = hdr->addr3;
|
||||
int err = -ENOENT;
|
||||
|
||||
rcu_read_lock();
|
||||
mpath = mesh_path_lookup(sdata, target_addr);
|
||||
|
||||
if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
|
||||
goto endlookup;
|
||||
return -ENOENT;
|
||||
|
||||
if (time_after(jiffies,
|
||||
mpath->exp_time -
|
||||
@@ -1208,12 +1202,10 @@ int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
|
||||
memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
|
||||
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
|
||||
ieee80211_mps_set_frame_flags(sdata, next_hop, hdr);
|
||||
err = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
endlookup:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
void mesh_path_timer(struct timer_list *t)
|
||||
|
@@ -217,7 +217,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
|
||||
{
|
||||
struct mesh_path *mpath;
|
||||
|
||||
mpath = rhashtable_lookup_fast(&tbl->rhead, dst, mesh_rht_params);
|
||||
mpath = rhashtable_lookup(&tbl->rhead, dst, mesh_rht_params);
|
||||
|
||||
if (mpath && mpath_expired(mpath)) {
|
||||
spin_lock_bh(&mpath->state_lock);
|
||||
|
@@ -1188,9 +1188,6 @@ static void ieee80211_chswitch_work(struct work_struct *work)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX: shouldn't really modify cfg80211-owned data! */
|
||||
ifmgd->associated->channel = sdata->csa_chandef.chan;
|
||||
|
||||
ifmgd->csa_waiting_bcn = true;
|
||||
|
||||
ieee80211_sta_reset_beacon_monitor(sdata);
|
||||
|
@@ -51,8 +51,13 @@
|
||||
MINSTREL_MAX_STREAMS * _sgi + \
|
||||
_streams - 1
|
||||
|
||||
#define _MAX(a, b) (((a)>(b))?(a):(b))
|
||||
|
||||
#define GROUP_SHIFT(duration) \
|
||||
_MAX(0, 16 - __builtin_clz(duration))
|
||||
|
||||
/* MCS rate information for an MCS group */
|
||||
#define MCS_GROUP(_streams, _sgi, _ht40, _s) \
|
||||
#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \
|
||||
[GROUP_IDX(_streams, _sgi, _ht40)] = { \
|
||||
.streams = _streams, \
|
||||
.shift = _s, \
|
||||
@@ -72,6 +77,13 @@
|
||||
} \
|
||||
}
|
||||
|
||||
#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \
|
||||
GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26))
|
||||
|
||||
#define MCS_GROUP(_streams, _sgi, _ht40) \
|
||||
__MCS_GROUP(_streams, _sgi, _ht40, \
|
||||
MCS_GROUP_SHIFT(_streams, _sgi, _ht40))
|
||||
|
||||
#define VHT_GROUP_IDX(_streams, _sgi, _bw) \
|
||||
(MINSTREL_VHT_GROUP_0 + \
|
||||
MINSTREL_MAX_STREAMS * 2 * (_bw) + \
|
||||
@@ -81,7 +93,7 @@
|
||||
#define BW2VBPS(_bw, r3, r2, r1) \
|
||||
(_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
|
||||
|
||||
#define VHT_GROUP(_streams, _sgi, _bw, _s) \
|
||||
#define __VHT_GROUP(_streams, _sgi, _bw, _s) \
|
||||
[VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
|
||||
.streams = _streams, \
|
||||
.shift = _s, \
|
||||
@@ -114,6 +126,14 @@
|
||||
} \
|
||||
}
|
||||
|
||||
#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \
|
||||
GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \
|
||||
BW2VBPS(_bw, 117, 54, 26)))
|
||||
|
||||
#define VHT_GROUP(_streams, _sgi, _bw) \
|
||||
__VHT_GROUP(_streams, _sgi, _bw, \
|
||||
VHT_GROUP_SHIFT(_streams, _sgi, _bw))
|
||||
|
||||
#define CCK_DURATION(_bitrate, _short, _len) \
|
||||
(1000 * (10 /* SIFS */ + \
|
||||
(_short ? 72 + 24 : 144 + 48) + \
|
||||
@@ -129,7 +149,7 @@
|
||||
CCK_ACK_DURATION(55, _short) >> _s, \
|
||||
CCK_ACK_DURATION(110, _short) >> _s
|
||||
|
||||
#define CCK_GROUP(_s) \
|
||||
#define __CCK_GROUP(_s) \
|
||||
[MINSTREL_CCK_GROUP] = { \
|
||||
.streams = 1, \
|
||||
.flags = 0, \
|
||||
@@ -140,6 +160,12 @@
|
||||
} \
|
||||
}
|
||||
|
||||
#define CCK_GROUP_SHIFT \
|
||||
GROUP_SHIFT(CCK_ACK_DURATION(10, false))
|
||||
|
||||
#define CCK_GROUP __CCK_GROUP(CCK_GROUP_SHIFT)
|
||||
|
||||
|
||||
static bool minstrel_vht_only = true;
|
||||
module_param(minstrel_vht_only, bool, 0644);
|
||||
MODULE_PARM_DESC(minstrel_vht_only,
|
||||
@@ -154,47 +180,57 @@ MODULE_PARM_DESC(minstrel_vht_only,
|
||||
* BW -> SGI -> #streams
|
||||
*/
|
||||
const struct mcs_group minstrel_mcs_groups[] = {
|
||||
MCS_GROUP(1, 0, BW_20, 5),
|
||||
MCS_GROUP(2, 0, BW_20, 4),
|
||||
MCS_GROUP(3, 0, BW_20, 4),
|
||||
MCS_GROUP(1, 0, BW_20),
|
||||
MCS_GROUP(2, 0, BW_20),
|
||||
MCS_GROUP(3, 0, BW_20),
|
||||
MCS_GROUP(4, 0, BW_20),
|
||||
|
||||
MCS_GROUP(1, 1, BW_20, 5),
|
||||
MCS_GROUP(2, 1, BW_20, 4),
|
||||
MCS_GROUP(3, 1, BW_20, 4),
|
||||
MCS_GROUP(1, 1, BW_20),
|
||||
MCS_GROUP(2, 1, BW_20),
|
||||
MCS_GROUP(3, 1, BW_20),
|
||||
MCS_GROUP(4, 1, BW_20),
|
||||
|
||||
MCS_GROUP(1, 0, BW_40, 4),
|
||||
MCS_GROUP(2, 0, BW_40, 4),
|
||||
MCS_GROUP(3, 0, BW_40, 4),
|
||||
MCS_GROUP(1, 0, BW_40),
|
||||
MCS_GROUP(2, 0, BW_40),
|
||||
MCS_GROUP(3, 0, BW_40),
|
||||
MCS_GROUP(4, 0, BW_40),
|
||||
|
||||
MCS_GROUP(1, 1, BW_40, 4),
|
||||
MCS_GROUP(2, 1, BW_40, 4),
|
||||
MCS_GROUP(3, 1, BW_40, 4),
|
||||
MCS_GROUP(1, 1, BW_40),
|
||||
MCS_GROUP(2, 1, BW_40),
|
||||
MCS_GROUP(3, 1, BW_40),
|
||||
MCS_GROUP(4, 1, BW_40),
|
||||
|
||||
CCK_GROUP(8),
|
||||
CCK_GROUP,
|
||||
|
||||
VHT_GROUP(1, 0, BW_20, 5),
|
||||
VHT_GROUP(2, 0, BW_20, 4),
|
||||
VHT_GROUP(3, 0, BW_20, 4),
|
||||
VHT_GROUP(1, 0, BW_20),
|
||||
VHT_GROUP(2, 0, BW_20),
|
||||
VHT_GROUP(3, 0, BW_20),
|
||||
VHT_GROUP(4, 0, BW_20),
|
||||
|
||||
VHT_GROUP(1, 1, BW_20, 5),
|
||||
VHT_GROUP(2, 1, BW_20, 4),
|
||||
VHT_GROUP(3, 1, BW_20, 4),
|
||||
VHT_GROUP(1, 1, BW_20),
|
||||
VHT_GROUP(2, 1, BW_20),
|
||||
VHT_GROUP(3, 1, BW_20),
|
||||
VHT_GROUP(4, 1, BW_20),
|
||||
|
||||
VHT_GROUP(1, 0, BW_40, 4),
|
||||
VHT_GROUP(2, 0, BW_40, 4),
|
||||
VHT_GROUP(3, 0, BW_40, 4),
|
||||
VHT_GROUP(1, 0, BW_40),
|
||||
VHT_GROUP(2, 0, BW_40),
|
||||
VHT_GROUP(3, 0, BW_40),
|
||||
VHT_GROUP(4, 0, BW_40),
|
||||
|
||||
VHT_GROUP(1, 1, BW_40, 4),
|
||||
VHT_GROUP(2, 1, BW_40, 4),
|
||||
VHT_GROUP(3, 1, BW_40, 4),
|
||||
VHT_GROUP(1, 1, BW_40),
|
||||
VHT_GROUP(2, 1, BW_40),
|
||||
VHT_GROUP(3, 1, BW_40),
|
||||
VHT_GROUP(4, 1, BW_40),
|
||||
|
||||
VHT_GROUP(1, 0, BW_80, 4),
|
||||
VHT_GROUP(2, 0, BW_80, 4),
|
||||
VHT_GROUP(3, 0, BW_80, 4),
|
||||
VHT_GROUP(1, 0, BW_80),
|
||||
VHT_GROUP(2, 0, BW_80),
|
||||
VHT_GROUP(3, 0, BW_80),
|
||||
VHT_GROUP(4, 0, BW_80),
|
||||
|
||||
VHT_GROUP(1, 1, BW_80, 4),
|
||||
VHT_GROUP(2, 1, BW_80, 4),
|
||||
VHT_GROUP(3, 1, BW_80, 4),
|
||||
VHT_GROUP(1, 1, BW_80),
|
||||
VHT_GROUP(2, 1, BW_80),
|
||||
VHT_GROUP(3, 1, BW_80),
|
||||
VHT_GROUP(4, 1, BW_80),
|
||||
};
|
||||
|
||||
static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
|
||||
|
@@ -13,7 +13,7 @@
|
||||
* The number of streams can be changed to 2 to reduce code
|
||||
* size and memory footprint.
|
||||
*/
|
||||
#define MINSTREL_MAX_STREAMS 3
|
||||
#define MINSTREL_MAX_STREAMS 4
|
||||
#define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */
|
||||
#define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */
|
||||
|
||||
|
@@ -1005,23 +1005,43 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ieee80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
|
||||
struct sk_buff *skb)
|
||||
static int ieee80211_get_keyid(struct sk_buff *skb,
|
||||
const struct ieee80211_cipher_scheme *cs)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
__le16 fc;
|
||||
int hdrlen;
|
||||
int minlen;
|
||||
u8 key_idx_off;
|
||||
u8 key_idx_shift;
|
||||
u8 keyid;
|
||||
|
||||
fc = hdr->frame_control;
|
||||
hdrlen = ieee80211_hdrlen(fc);
|
||||
|
||||
if (skb->len < hdrlen + cs->hdr_len)
|
||||
if (cs) {
|
||||
minlen = hdrlen + cs->hdr_len;
|
||||
key_idx_off = hdrlen + cs->key_idx_off;
|
||||
key_idx_shift = cs->key_idx_shift;
|
||||
} else {
|
||||
/* WEP, TKIP, CCMP and GCMP */
|
||||
minlen = hdrlen + IEEE80211_WEP_IV_LEN;
|
||||
key_idx_off = hdrlen + 3;
|
||||
key_idx_shift = 6;
|
||||
}
|
||||
|
||||
if (unlikely(skb->len < minlen))
|
||||
return -EINVAL;
|
||||
|
||||
skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1);
|
||||
keyid &= cs->key_idx_mask;
|
||||
keyid >>= cs->key_idx_shift;
|
||||
skb_copy_bits(skb, key_idx_off, &keyid, 1);
|
||||
|
||||
if (cs)
|
||||
keyid &= cs->key_idx_mask;
|
||||
keyid >>= key_idx_shift;
|
||||
|
||||
/* cs could use more than the usual two bits for the keyid */
|
||||
if (unlikely(keyid >= NUM_DEFAULT_KEYS))
|
||||
return -EINVAL;
|
||||
|
||||
return keyid;
|
||||
}
|
||||
@@ -1860,9 +1880,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
int keyidx;
|
||||
int hdrlen;
|
||||
ieee80211_rx_result result = RX_DROP_UNUSABLE;
|
||||
struct ieee80211_key *sta_ptk = NULL;
|
||||
struct ieee80211_key *ptk_idx = NULL;
|
||||
int mmie_keyidx = -1;
|
||||
__le16 fc;
|
||||
const struct ieee80211_cipher_scheme *cs = NULL;
|
||||
@@ -1900,21 +1920,24 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
|
||||
if (rx->sta) {
|
||||
int keyid = rx->sta->ptk_idx;
|
||||
sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
|
||||
|
||||
if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) {
|
||||
if (ieee80211_has_protected(fc)) {
|
||||
cs = rx->sta->cipher_scheme;
|
||||
keyid = ieee80211_get_cs_keyid(cs, rx->skb);
|
||||
keyid = ieee80211_get_keyid(rx->skb, cs);
|
||||
|
||||
if (unlikely(keyid < 0))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
ptk_idx = rcu_dereference(rx->sta->ptk[keyid]);
|
||||
}
|
||||
sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
|
||||
}
|
||||
|
||||
if (!ieee80211_has_protected(fc))
|
||||
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
|
||||
|
||||
if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
|
||||
rx->key = sta_ptk;
|
||||
rx->key = ptk_idx ? ptk_idx : sta_ptk;
|
||||
if ((status->flag & RX_FLAG_DECRYPTED) &&
|
||||
(status->flag & RX_FLAG_IV_STRIPPED))
|
||||
return RX_CONTINUE;
|
||||
@@ -1974,8 +1997,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
}
|
||||
return RX_CONTINUE;
|
||||
} else {
|
||||
u8 keyid;
|
||||
|
||||
/*
|
||||
* The device doesn't give us the IV so we won't be
|
||||
* able to look up the key. That's ok though, we
|
||||
@@ -1989,23 +2010,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
||||
(status->flag & RX_FLAG_IV_STRIPPED))
|
||||
return RX_CONTINUE;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(fc);
|
||||
keyidx = ieee80211_get_keyid(rx->skb, cs);
|
||||
|
||||
if (cs) {
|
||||
keyidx = ieee80211_get_cs_keyid(cs, rx->skb);
|
||||
|
||||
if (unlikely(keyidx < 0))
|
||||
return RX_DROP_UNUSABLE;
|
||||
} else {
|
||||
if (rx->skb->len < 8 + hdrlen)
|
||||
return RX_DROP_UNUSABLE; /* TODO: count this? */
|
||||
/*
|
||||
* no need to call ieee80211_wep_get_keyidx,
|
||||
* it verifies a bunch of things we've done already
|
||||
*/
|
||||
skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
|
||||
keyidx = keyid >> 6;
|
||||
}
|
||||
if (unlikely(keyidx < 0))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
/* check per-station GTK first, if multicast packet */
|
||||
if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
|
||||
@@ -4050,12 +4058,8 @@ void ieee80211_check_fast_rx(struct sta_info *sta)
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
break;
|
||||
default:
|
||||
/* we also don't want to deal with WEP or cipher scheme
|
||||
* since those require looking up the key idx in the
|
||||
* frame, rather than assuming the PTK is used
|
||||
* (we need to revisit this once we implement the real
|
||||
* PTK index, which is now valid in the spec, but we
|
||||
* haven't implemented that part yet)
|
||||
/* We also don't want to deal with
|
||||
* WEP or cipher scheme.
|
||||
*/
|
||||
goto clear_rcu;
|
||||
}
|
||||
|
@@ -347,6 +347,15 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
sta->sta.max_rx_aggregation_subframes =
|
||||
local->hw.max_rx_aggregation_subframes;
|
||||
|
||||
/* Extended Key ID needs to install keys for keyid 0 and 1 Rx-only.
|
||||
* The Tx path starts to use a key as soon as the key slot ptk_idx
|
||||
* references to is not NULL. To not use the initial Rx-only key
|
||||
* prematurely for Tx initialize ptk_idx to an impossible PTK keyid
|
||||
* which always will refer to a NULL key.
|
||||
*/
|
||||
BUILD_BUG_ON(ARRAY_SIZE(sta->ptk) <= INVALID_PTK_KEYIDX);
|
||||
sta->ptk_idx = INVALID_PTK_KEYIDX;
|
||||
|
||||
sta->local = local;
|
||||
sta->sdata = sdata;
|
||||
sta->rx_stats.last_rx = jiffies;
|
||||
@@ -2373,6 +2382,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
sinfo->filled |=
|
||||
BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
|
||||
}
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_LINK_METRIC);
|
||||
sinfo->airtime_link_metric =
|
||||
airtime_link_metric_get(local, sta);
|
||||
}
|
||||
}
|
||||
|
||||
u32 sta_get_expected_throughput(struct sta_info *sta)
|
||||
|
@@ -1056,7 +1056,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
/* disable bottom halves when entering the Tx path */
|
||||
local_bh_disable();
|
||||
__ieee80211_subif_start_xmit(skb, dev, flags);
|
||||
__ieee80211_subif_start_xmit(skb, dev, flags, 0);
|
||||
local_bh_enable();
|
||||
|
||||
return ret;
|
||||
|
@@ -828,6 +828,36 @@ TRACE_EVENT(drv_sta_state,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_sta_set_txpwr,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta),
|
||||
|
||||
TP_ARGS(local, sdata, sta),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
STA_ENTRY
|
||||
__field(s16, txpwr)
|
||||
__field(u8, type)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
STA_ASSIGN;
|
||||
__entry->txpwr = sta->txpwr.power;
|
||||
__entry->type = sta->txpwr.type;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " txpwr: %d type %d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
|
||||
__entry->txpwr, __entry->type
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_sta_rc_update,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
|
@@ -1399,11 +1399,15 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local,
|
||||
{
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin = &txqi->tin;
|
||||
u32 flow_idx = fq_flow_idx(fq, skb);
|
||||
|
||||
ieee80211_set_skb_enqueue_time(skb);
|
||||
fq_tin_enqueue(fq, tin, skb,
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
fq_tin_enqueue(fq, tin, flow_idx, skb,
|
||||
fq_skb_free_func,
|
||||
fq_flow_get_default_func);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
|
||||
static bool fq_vlan_filter_func(struct fq *fq, struct fq_tin *tin,
|
||||
@@ -1590,7 +1594,6 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
|
||||
struct sta_info *sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct fq *fq = &local->fq;
|
||||
struct ieee80211_vif *vif;
|
||||
struct txq_info *txqi;
|
||||
|
||||
@@ -1608,9 +1611,7 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
|
||||
if (!txqi)
|
||||
return false;
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_enqueue(local, txqi, skb);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
schedule_and_wake_txq(local, txqi);
|
||||
|
||||
@@ -2431,6 +2432,7 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
|
||||
* @sdata: virtual interface to build the header for
|
||||
* @skb: the skb to build the header in
|
||||
* @info_flags: skb flags to set
|
||||
* @ctrl_flags: info control flags to set
|
||||
*
|
||||
* This function takes the skb with 802.3 header and reformats the header to
|
||||
* the appropriate IEEE 802.11 header based on which interface the packet is
|
||||
@@ -2446,7 +2448,7 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, u32 info_flags,
|
||||
struct sta_info *sta)
|
||||
struct sta_info *sta, u32 ctrl_flags)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_info *info;
|
||||
@@ -2470,6 +2472,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
if (IS_ERR(sta))
|
||||
sta = NULL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
if (local->force_tx_status)
|
||||
info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
#endif
|
||||
|
||||
/* convert Ethernet header to proper 802.11 header (based on
|
||||
* operation mode) */
|
||||
ethertype = (skb->data[12] << 8) | skb->data[13];
|
||||
@@ -2600,6 +2607,13 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
goto free;
|
||||
}
|
||||
band = chanctx_conf->def.chan->band;
|
||||
|
||||
/* For injected frames, fill RA right away as nexthop lookup
|
||||
* will be skipped.
|
||||
*/
|
||||
if ((ctrl_flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP) &&
|
||||
is_zero_ether_addr(hdr.addr1))
|
||||
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
||||
break;
|
||||
#endif
|
||||
case NL80211_IFTYPE_STATION:
|
||||
@@ -2818,6 +2832,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
info->flags = info_flags;
|
||||
info->ack_frame_id = info_id;
|
||||
info->band = band;
|
||||
info->control.flags = ctrl_flags;
|
||||
|
||||
return skb;
|
||||
free:
|
||||
@@ -3000,23 +3015,15 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
|
||||
switch (build.key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
/* add fixed key ID */
|
||||
if (gen_iv) {
|
||||
(build.hdr + build.hdr_len)[3] =
|
||||
0x20 | (build.key->conf.keyidx << 6);
|
||||
if (gen_iv)
|
||||
build.pn_offs = build.hdr_len;
|
||||
}
|
||||
if (gen_iv || iv_spc)
|
||||
build.hdr_len += IEEE80211_CCMP_HDR_LEN;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
/* add fixed key ID */
|
||||
if (gen_iv) {
|
||||
(build.hdr + build.hdr_len)[3] =
|
||||
0x20 | (build.key->conf.keyidx << 6);
|
||||
if (gen_iv)
|
||||
build.pn_offs = build.hdr_len;
|
||||
}
|
||||
if (gen_iv || iv_spc)
|
||||
build.hdr_len += IEEE80211_GCMP_HDR_LEN;
|
||||
break;
|
||||
@@ -3222,6 +3229,7 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
||||
int max_frags = local->hw.max_tx_fragments;
|
||||
int max_amsdu_len = sta->sta.max_amsdu_len;
|
||||
int orig_truesize;
|
||||
u32 flow_idx;
|
||||
__be16 len;
|
||||
void *data;
|
||||
bool ret = false;
|
||||
@@ -3250,6 +3258,8 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
||||
max_amsdu_len = min_t(int, max_amsdu_len,
|
||||
sta->sta.max_tid_amsdu_len[tid]);
|
||||
|
||||
flow_idx = fq_flow_idx(fq, skb);
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
/* TODO: Ideally aggregation should be done on dequeue to remain
|
||||
@@ -3257,7 +3267,8 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
|
||||
tin = &txqi->tin;
|
||||
flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func);
|
||||
flow = fq_flow_classify(fq, tin, flow_idx, skb,
|
||||
fq_flow_get_default_func);
|
||||
head = skb_peek_tail(&flow->queue);
|
||||
if (!head || skb_is_gso(head))
|
||||
goto out;
|
||||
@@ -3386,6 +3397,7 @@ static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
|
||||
pn = atomic64_inc_return(&key->conf.tx_pn);
|
||||
crypto_hdr[0] = pn;
|
||||
crypto_hdr[1] = pn >> 8;
|
||||
crypto_hdr[3] = 0x20 | (key->conf.keyidx << 6);
|
||||
crypto_hdr[4] = pn >> 16;
|
||||
crypto_hdr[5] = pn >> 24;
|
||||
crypto_hdr[6] = pn >> 32;
|
||||
@@ -3478,6 +3490,11 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
||||
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
|
||||
info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
if (local->force_tx_status)
|
||||
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
#endif
|
||||
|
||||
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
||||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||
*ieee80211_get_qos_ctl(hdr) = tid;
|
||||
@@ -3533,6 +3550,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
ieee80211_tx_result r;
|
||||
struct ieee80211_vif *vif = txq->vif;
|
||||
|
||||
begin:
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
|
||||
@@ -3549,11 +3567,12 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
if (skb)
|
||||
goto out;
|
||||
|
||||
begin:
|
||||
skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
@@ -3598,8 +3617,11 @@ begin:
|
||||
|
||||
skb = __skb_dequeue(&tx.skbs);
|
||||
|
||||
if (!skb_queue_empty(&tx.skbs))
|
||||
if (!skb_queue_empty(&tx.skbs)) {
|
||||
spin_lock_bh(&fq->lock);
|
||||
skb_queue_splice_tail(&tx.skbs, &txqi->frags);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
}
|
||||
|
||||
if (skb_has_frag_list(skb) &&
|
||||
@@ -3638,6 +3660,7 @@ begin:
|
||||
}
|
||||
|
||||
IEEE80211_SKB_CB(skb)->control.vif = vif;
|
||||
return skb;
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&fq->lock);
|
||||
@@ -3783,9 +3806,11 @@ EXPORT_SYMBOL(ieee80211_txq_schedule_start);
|
||||
|
||||
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
u32 info_flags)
|
||||
u32 info_flags,
|
||||
u32 ctrl_flags)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
struct sk_buff *next;
|
||||
|
||||
@@ -3799,7 +3824,15 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
|
||||
goto out_free;
|
||||
|
||||
if (!IS_ERR_OR_NULL(sta)) {
|
||||
if (IS_ERR(sta))
|
||||
sta = NULL;
|
||||
|
||||
if (local->ops->wake_tx_queue) {
|
||||
u16 queue = __ieee80211_select_queue(sdata, sta, skb);
|
||||
skb_set_queue_mapping(skb, queue);
|
||||
}
|
||||
|
||||
if (sta) {
|
||||
struct ieee80211_fast_tx *fast_tx;
|
||||
|
||||
sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
|
||||
@@ -3848,7 +3881,8 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
skb->prev = NULL;
|
||||
skb->next = NULL;
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags,
|
||||
sta, ctrl_flags);
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
|
||||
@@ -3988,9 +4022,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
__skb_queue_head_init(&queue);
|
||||
ieee80211_convert_to_unicast(skb, dev, &queue);
|
||||
while ((skb = __skb_dequeue(&queue)))
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0);
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0, 0);
|
||||
} else {
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0);
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0, 0);
|
||||
}
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
@@ -4015,7 +4049,7 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
|
||||
goto out;
|
||||
}
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta, 0);
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
|
||||
@@ -5052,7 +5086,36 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
||||
skb_reset_mac_header(skb);
|
||||
|
||||
local_bh_disable();
|
||||
__ieee80211_subif_start_xmit(skb, skb->dev, flags);
|
||||
__ieee80211_subif_start_xmit(skb, skb->dev, flags, 0);
|
||||
local_bh_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + len +
|
||||
30 + /* header size */
|
||||
18); /* 11s header size */
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
skb_put_data(skb, buf, len);
|
||||
|
||||
skb->dev = dev;
|
||||
skb->protocol = htons(ETH_P_802_3);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_mac_header(skb);
|
||||
|
||||
local_bh_disable();
|
||||
__ieee80211_subif_start_xmit(skb, skb->dev, 0,
|
||||
IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP);
|
||||
local_bh_enable();
|
||||
|
||||
return 0;
|
||||
|
@@ -894,10 +894,10 @@ EXPORT_SYMBOL(ieee80211_queue_delayed_work);
|
||||
static u32
|
||||
_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
u8 *bss_bssid)
|
||||
u64 filter, u32 crc,
|
||||
const struct element *check_inherit)
|
||||
{
|
||||
const struct element *elem, *sub;
|
||||
const struct element *elem;
|
||||
bool calc_crc = filter != 0;
|
||||
DECLARE_BITMAP(seen_elems, 256);
|
||||
const u8 *ie;
|
||||
@@ -910,6 +910,11 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
u8 elen = elem->datalen;
|
||||
const u8 *pos = elem->data;
|
||||
|
||||
if (check_inherit &&
|
||||
!cfg80211_is_element_inherited(elem,
|
||||
check_inherit))
|
||||
continue;
|
||||
|
||||
switch (id) {
|
||||
case WLAN_EID_SSID:
|
||||
case WLAN_EID_SUPP_RATES:
|
||||
@@ -1208,57 +1213,6 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
if (elen >= sizeof(*elems->max_idle_period_ie))
|
||||
elems->max_idle_period_ie = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_MULTIPLE_BSSID:
|
||||
if (!bss_bssid || !transmitter_bssid || elen < 4)
|
||||
break;
|
||||
|
||||
elems->max_bssid_indicator = pos[0];
|
||||
|
||||
for_each_element(sub, pos + 1, elen - 1) {
|
||||
u8 sub_len = sub->datalen;
|
||||
u8 new_bssid[ETH_ALEN];
|
||||
const u8 *index;
|
||||
|
||||
/*
|
||||
* we only expect the "non-transmitted BSSID
|
||||
* profile" subelement (subelement id 0)
|
||||
*/
|
||||
if (sub->id != 0 || sub->datalen < 4) {
|
||||
/* not a valid BSS profile */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
sub->data[1] != 2) {
|
||||
/* The first element of the
|
||||
* Nontransmitted BSSID Profile is not
|
||||
* the Nontransmitted BSSID Capability
|
||||
* element.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* found a Nontransmitted BSSID Profile */
|
||||
index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
|
||||
sub->data, sub_len);
|
||||
if (!index || index[1] < 1 || index[2] == 0) {
|
||||
/* Invalid MBSSID Index element */
|
||||
continue;
|
||||
}
|
||||
|
||||
cfg80211_gen_new_bssid(transmitter_bssid,
|
||||
pos[0],
|
||||
index[2],
|
||||
new_bssid);
|
||||
if (ether_addr_equal(new_bssid, bss_bssid)) {
|
||||
elems->nontransmitted_bssid_profile =
|
||||
(void *)sub;
|
||||
elems->bssid_index_len = index[1];
|
||||
elems->bssid_index = (void *)&index[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WLAN_EID_EXTENSION:
|
||||
if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
|
||||
elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
|
||||
@@ -1300,26 +1254,108 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
return crc;
|
||||
}
|
||||
|
||||
static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
u8 *transmitter_bssid,
|
||||
u8 *bss_bssid,
|
||||
u8 *nontransmitted_profile)
|
||||
{
|
||||
const struct element *elem, *sub;
|
||||
size_t profile_len = 0;
|
||||
bool found = false;
|
||||
|
||||
if (!bss_bssid || !transmitter_bssid)
|
||||
return profile_len;
|
||||
|
||||
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
|
||||
if (elem->datalen < 2)
|
||||
continue;
|
||||
|
||||
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
|
||||
u8 new_bssid[ETH_ALEN];
|
||||
const u8 *index;
|
||||
|
||||
if (sub->id != 0 || sub->datalen < 4) {
|
||||
/* not a valid BSS profile */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
sub->data[1] != 2) {
|
||||
/* The first element of the
|
||||
* Nontransmitted BSSID Profile is not
|
||||
* the Nontransmitted BSSID Capability
|
||||
* element.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(nontransmitted_profile, 0, len);
|
||||
profile_len = cfg80211_merge_profile(start, len,
|
||||
elem,
|
||||
sub,
|
||||
nontransmitted_profile,
|
||||
len);
|
||||
|
||||
/* found a Nontransmitted BSSID Profile */
|
||||
index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
|
||||
nontransmitted_profile,
|
||||
profile_len);
|
||||
if (!index || index[1] < 1 || index[2] == 0) {
|
||||
/* Invalid MBSSID Index element */
|
||||
continue;
|
||||
}
|
||||
|
||||
cfg80211_gen_new_bssid(transmitter_bssid,
|
||||
elem->data[0],
|
||||
index[2],
|
||||
new_bssid);
|
||||
if (ether_addr_equal(new_bssid, bss_bssid)) {
|
||||
found = true;
|
||||
elems->bssid_index_len = index[1];
|
||||
elems->bssid_index = (void *)&index[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found ? profile_len : 0;
|
||||
}
|
||||
|
||||
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
u8 *bss_bssid)
|
||||
{
|
||||
const struct element *non_inherit = NULL;
|
||||
u8 *nontransmitted_profile;
|
||||
int nontransmitted_profile_len = 0;
|
||||
|
||||
memset(elems, 0, sizeof(*elems));
|
||||
elems->ie_start = start;
|
||||
elems->total_len = len;
|
||||
|
||||
nontransmitted_profile = kmalloc(len, GFP_ATOMIC);
|
||||
if (nontransmitted_profile) {
|
||||
nontransmitted_profile_len =
|
||||
ieee802_11_find_bssid_profile(start, len, elems,
|
||||
transmitter_bssid,
|
||||
bss_bssid,
|
||||
nontransmitted_profile);
|
||||
non_inherit =
|
||||
cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
|
||||
nontransmitted_profile,
|
||||
nontransmitted_profile_len);
|
||||
}
|
||||
|
||||
crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
|
||||
crc, transmitter_bssid, bss_bssid);
|
||||
crc, non_inherit);
|
||||
|
||||
/* Override with nontransmitted profile, if found */
|
||||
if (transmitter_bssid && elems->nontransmitted_bssid_profile) {
|
||||
const u8 *profile = elems->nontransmitted_bssid_profile;
|
||||
|
||||
_ieee802_11_parse_elems_crc(&profile[2], profile[1],
|
||||
action, elems, 0, 0,
|
||||
transmitter_bssid, bss_bssid);
|
||||
}
|
||||
if (nontransmitted_profile_len)
|
||||
_ieee802_11_parse_elems_crc(nontransmitted_profile,
|
||||
nontransmitted_profile_len,
|
||||
action, elems, 0, 0, NULL);
|
||||
|
||||
if (elems->tim && !elems->parse_error) {
|
||||
const struct ieee80211_tim_ie *tim_ie = elems->tim;
|
||||
@@ -1339,6 +1375,8 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
offsetofend(struct ieee80211_bssid_index, dtim_count))
|
||||
elems->dtim_count = elems->bssid_index->dtim_count;
|
||||
|
||||
kfree(nontransmitted_profile);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
@@ -141,71 +141,24 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
|
||||
return ieee80211_downgrade_queue(sdata, NULL, skb);
|
||||
}
|
||||
|
||||
/* Indicate which queue to use. */
|
||||
u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta = NULL;
|
||||
const u8 *ra = NULL;
|
||||
bool qos = false;
|
||||
struct mac80211_qos_map *qos_map;
|
||||
u16 ret;
|
||||
bool qos;
|
||||
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
|
||||
skb->priority = 0; /* required for correct WPA/11i MIC */
|
||||
return 0;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
sta = rcu_dereference(sdata->u.vlan.sta);
|
||||
if (sta) {
|
||||
qos = sta->sta.wme;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_AP:
|
||||
ra = skb->data;
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
ra = sdata->u.wds.remote_addr;
|
||||
break;
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
/* all mesh/ocb stations are required to support WME */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
|
||||
sdata->vif.type == NL80211_IFTYPE_OCB)
|
||||
qos = true;
|
||||
break;
|
||||
#endif
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/* might be a TDLS station */
|
||||
sta = sta_info_get(sdata, skb->data);
|
||||
if (sta)
|
||||
qos = sta->sta.wme;
|
||||
|
||||
ra = sdata->u.mgd.bssid;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ra = skb->data;
|
||||
break;
|
||||
case NL80211_IFTYPE_OCB:
|
||||
/* all stations are required to support WME */
|
||||
qos = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sta && ra && !is_multicast_ether_addr(ra)) {
|
||||
sta = sta_info_get(sdata, ra);
|
||||
if (sta)
|
||||
qos = sta->sta.wme;
|
||||
}
|
||||
else if (sta)
|
||||
qos = sta->sta.wme;
|
||||
else
|
||||
qos = false;
|
||||
|
||||
if (!qos) {
|
||||
skb->priority = 0; /* required for correct WPA/11i MIC */
|
||||
ret = IEEE80211_AC_BE;
|
||||
goto out;
|
||||
return IEEE80211_AC_BE;
|
||||
}
|
||||
|
||||
if (skb->protocol == sdata->control_port_protocol) {
|
||||
@@ -220,8 +173,61 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
||||
&qos_map->qos_map : NULL);
|
||||
|
||||
downgrade:
|
||||
ret = ieee80211_downgrade_queue(sdata, sta, skb);
|
||||
out:
|
||||
return ieee80211_downgrade_queue(sdata, sta, skb);
|
||||
}
|
||||
|
||||
|
||||
/* Indicate which queue to use. */
|
||||
u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta = NULL;
|
||||
const u8 *ra = NULL;
|
||||
u16 ret;
|
||||
|
||||
/* when using iTXQ, we can do this later */
|
||||
if (local->ops->wake_tx_queue)
|
||||
return 0;
|
||||
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
|
||||
skb->priority = 0; /* required for correct WPA/11i MIC */
|
||||
return 0;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
sta = rcu_dereference(sdata->u.vlan.sta);
|
||||
if (sta)
|
||||
break;
|
||||
/* fall through */
|
||||
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);
|
||||
if (sta)
|
||||
break;
|
||||
|
||||
ra = sdata->u.mgd.bssid;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ra = skb->data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sta && ra && !is_multicast_ether_addr(ra))
|
||||
sta = sta_info_get(sdata, ra);
|
||||
|
||||
ret = __ieee80211_select_queue(sdata, sta, skb);
|
||||
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
@@ -16,6 +16,8 @@
|
||||
u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_hdr *hdr);
|
||||
u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb);
|
||||
u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
|
Reference in New Issue
Block a user