Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
@@ -832,7 +832,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
if (params->ht_capa)
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
params->ht_capa,
|
||||
&sta->sta.ht_cap);
|
||||
|
||||
|
@@ -63,10 +63,10 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
|
||||
test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
|
||||
|
||||
int res = scnprintf(buf, sizeof(buf),
|
||||
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
|
||||
TEST(PS_DRIVER), TEST(AUTHORIZED),
|
||||
TEST(SHORT_PREAMBLE), TEST(ASSOC_AP),
|
||||
TEST(SHORT_PREAMBLE),
|
||||
TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
|
||||
TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
|
||||
TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
|
||||
|
@@ -15,6 +15,14 @@ static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
|
||||
local->ops->tx(&local->hw, skb);
|
||||
}
|
||||
|
||||
static inline void drv_tx_frags(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct sk_buff_head *skbs)
|
||||
{
|
||||
local->ops->tx_frags(&local->hw, vif, sta, skbs);
|
||||
}
|
||||
|
||||
static inline int drv_start(struct ieee80211_local *local)
|
||||
{
|
||||
int ret;
|
||||
|
@@ -19,7 +19,82 @@
|
||||
#include "ieee80211_i.h"
|
||||
#include "rate.h"
|
||||
|
||||
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
|
||||
bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
const __le16 flg = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40);
|
||||
if ((sdata->u.mgd.ht_capa_mask.cap_info & flg) &&
|
||||
!(sdata->u.mgd.ht_capa.cap_info & flg))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta_ht_cap *ht_cap,
|
||||
u16 flag)
|
||||
{
|
||||
__le16 le_flag = cpu_to_le16(flag);
|
||||
if (sdata->u.mgd.ht_capa_mask.cap_info & le_flag) {
|
||||
if (!(sdata->u.mgd.ht_capa.cap_info & le_flag))
|
||||
ht_cap->cap &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta_ht_cap *ht_cap)
|
||||
{
|
||||
u8 *scaps = (u8 *)(&sdata->u.mgd.ht_capa.mcs.rx_mask);
|
||||
u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask);
|
||||
int i;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION) {
|
||||
WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION);
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTE: If you add more over-rides here, update register_hw
|
||||
* ht_capa_mod_msk logic in main.c as well.
|
||||
* And, if this method can ever change ht_cap.ht_supported, fix
|
||||
* the check in ieee80211_add_ht_ie.
|
||||
*/
|
||||
|
||||
/* check for HT over-rides, MCS rates first. */
|
||||
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
|
||||
u8 m = smask[i];
|
||||
ht_cap->mcs.rx_mask[i] &= ~m; /* turn off all masked bits */
|
||||
/* Add back rates that are supported */
|
||||
ht_cap->mcs.rx_mask[i] |= (m & scaps[i]);
|
||||
}
|
||||
|
||||
/* Force removal of HT-40 capabilities? */
|
||||
__check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SUP_WIDTH_20_40);
|
||||
__check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_40);
|
||||
|
||||
/* Allow user to disable the max-AMSDU bit. */
|
||||
__check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU);
|
||||
|
||||
/* Allow user to decrease AMPDU factor */
|
||||
if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
|
||||
IEEE80211_HT_AMPDU_PARM_FACTOR) {
|
||||
u8 n = sdata->u.mgd.ht_capa.ampdu_params_info
|
||||
& IEEE80211_HT_AMPDU_PARM_FACTOR;
|
||||
if (n < ht_cap->ampdu_factor)
|
||||
ht_cap->ampdu_factor = n;
|
||||
}
|
||||
|
||||
/* Allow the user to increase AMPDU density. */
|
||||
if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
|
||||
IEEE80211_HT_AMPDU_PARM_DENSITY) {
|
||||
u8 n = (sdata->u.mgd.ht_capa.ampdu_params_info &
|
||||
IEEE80211_HT_AMPDU_PARM_DENSITY)
|
||||
>> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
|
||||
if (n > ht_cap->ampdu_density)
|
||||
ht_cap->ampdu_density = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_ht_cap *ht_cap_ie,
|
||||
struct ieee80211_sta_ht_cap *ht_cap)
|
||||
{
|
||||
@@ -103,6 +178,12 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
|
||||
/* handle MCS rate 32 too */
|
||||
if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
|
||||
ht_cap->mcs.rx_mask[32/8] |= 1;
|
||||
|
||||
/*
|
||||
* If user has specified capability over-rides, take care
|
||||
* of that here.
|
||||
*/
|
||||
ieee80211_apply_htcap_overrides(sdata, ht_cap);
|
||||
}
|
||||
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
|
||||
|
@@ -142,6 +142,7 @@ typedef unsigned __bitwise__ ieee80211_tx_result;
|
||||
|
||||
struct ieee80211_tx_data {
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff_head skbs;
|
||||
struct ieee80211_local *local;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta;
|
||||
@@ -448,6 +449,9 @@ struct ieee80211_if_managed {
|
||||
*/
|
||||
int rssi_min_thold, rssi_max_thold;
|
||||
int last_ave_beacon_signal;
|
||||
|
||||
struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
|
||||
struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
|
||||
};
|
||||
|
||||
struct ieee80211_if_ibss {
|
||||
@@ -1039,6 +1043,69 @@ struct ieee80211_ra_tid {
|
||||
u16 tid;
|
||||
};
|
||||
|
||||
/* Parsed Information Elements */
|
||||
struct ieee802_11_elems {
|
||||
u8 *ie_start;
|
||||
size_t total_len;
|
||||
|
||||
/* pointers to IEs */
|
||||
u8 *ssid;
|
||||
u8 *supp_rates;
|
||||
u8 *fh_params;
|
||||
u8 *ds_params;
|
||||
u8 *cf_params;
|
||||
struct ieee80211_tim_ie *tim;
|
||||
u8 *ibss_params;
|
||||
u8 *challenge;
|
||||
u8 *wpa;
|
||||
u8 *rsn;
|
||||
u8 *erp_info;
|
||||
u8 *ext_supp_rates;
|
||||
u8 *wmm_info;
|
||||
u8 *wmm_param;
|
||||
struct ieee80211_ht_cap *ht_cap_elem;
|
||||
struct ieee80211_ht_info *ht_info_elem;
|
||||
struct ieee80211_meshconf_ie *mesh_config;
|
||||
u8 *mesh_id;
|
||||
u8 *peering;
|
||||
u8 *preq;
|
||||
u8 *prep;
|
||||
u8 *perr;
|
||||
struct ieee80211_rann_ie *rann;
|
||||
u8 *ch_switch_elem;
|
||||
u8 *country_elem;
|
||||
u8 *pwr_constr_elem;
|
||||
u8 *quiet_elem; /* first quite element */
|
||||
u8 *timeout_int;
|
||||
|
||||
/* length of them, respectively */
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
u8 fh_params_len;
|
||||
u8 ds_params_len;
|
||||
u8 cf_params_len;
|
||||
u8 tim_len;
|
||||
u8 ibss_params_len;
|
||||
u8 challenge_len;
|
||||
u8 wpa_len;
|
||||
u8 rsn_len;
|
||||
u8 erp_info_len;
|
||||
u8 ext_supp_rates_len;
|
||||
u8 wmm_info_len;
|
||||
u8 wmm_param_len;
|
||||
u8 mesh_id_len;
|
||||
u8 peering_len;
|
||||
u8 preq_len;
|
||||
u8 prep_len;
|
||||
u8 perr_len;
|
||||
u8 ch_switch_elem_len;
|
||||
u8 country_elem_len;
|
||||
u8 pwr_constr_elem_len;
|
||||
u8 quiet_elem_len;
|
||||
u8 num_of_quiet_elem; /* can be more the one */
|
||||
u8 timeout_int_len;
|
||||
};
|
||||
|
||||
static inline struct ieee80211_local *hw_to_local(
|
||||
struct ieee80211_hw *hw)
|
||||
{
|
||||
@@ -1188,7 +1255,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
|
||||
/* HT */
|
||||
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
|
||||
bool ieee80111_cfg_override_disables_ht40(struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta_ht_cap *ht_cap);
|
||||
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_ht_cap *ht_cap_ie,
|
||||
struct ieee80211_sta_ht_cap *ht_cap);
|
||||
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
|
||||
@@ -1343,7 +1414,7 @@ void ieee80211_recalc_smps(struct ieee80211_local *local);
|
||||
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
|
||||
const u8 *ids, int n_ids, size_t offset);
|
||||
size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
|
||||
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
|
||||
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||
u16 cap);
|
||||
u8 *ieee80211_ie_build_ht_info(u8 *pos,
|
||||
struct ieee80211_sta_ht_cap *ht_cap,
|
||||
|
@@ -474,7 +474,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
|
||||
synchronize_rcu();
|
||||
kfree(old_beacon);
|
||||
kfree(old_probe_resp);
|
||||
kfree_skb(old_probe_resp);
|
||||
|
||||
/* down all dependent devices, that is VLANs */
|
||||
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
|
||||
|
@@ -558,6 +558,19 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
|
||||
.ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR |
|
||||
IEEE80211_HT_AMPDU_PARM_DENSITY,
|
||||
|
||||
.cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
|
||||
IEEE80211_HT_CAP_MAX_AMSDU |
|
||||
IEEE80211_HT_CAP_SGI_40),
|
||||
.mcs = {
|
||||
.rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, },
|
||||
},
|
||||
};
|
||||
|
||||
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
const struct ieee80211_ops *ops)
|
||||
{
|
||||
@@ -594,7 +607,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
wiphy->flags |= WIPHY_FLAG_NETNS_OK |
|
||||
WIPHY_FLAG_4ADDR_AP |
|
||||
WIPHY_FLAG_4ADDR_STATION |
|
||||
WIPHY_FLAG_REPORTS_OBSS;
|
||||
WIPHY_FLAG_REPORTS_OBSS |
|
||||
WIPHY_FLAG_OFFCHAN_TX |
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
|
||||
|
||||
wiphy->features = NL80211_FEATURE_SK_TX_STATUS;
|
||||
|
||||
@@ -609,7 +624,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
|
||||
local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
|
||||
|
||||
BUG_ON(!ops->tx);
|
||||
BUG_ON(!ops->tx && !ops->tx_frags);
|
||||
BUG_ON(!ops->start);
|
||||
BUG_ON(!ops->stop);
|
||||
BUG_ON(!ops->config);
|
||||
@@ -629,6 +644,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
||||
local->user_power_level = -1;
|
||||
local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
|
||||
local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
|
||||
wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
|
||||
|
||||
INIT_LIST_HEAD(&local->interfaces);
|
||||
|
||||
|
@@ -366,7 +366,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,
|
||||
return -ENOMEM;
|
||||
|
||||
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
|
||||
ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
|
||||
ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -867,10 +867,11 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_bh(&mpath->state_lock);
|
||||
spin_lock(&mpath->state_lock);
|
||||
if (mpath->flags & MESH_PATH_REQ_QUEUED) {
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
spin_unlock(&mpath->state_lock);
|
||||
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
|
||||
kfree(preq_node);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -878,7 +879,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
|
||||
preq_node->flags = flags;
|
||||
|
||||
mpath->flags |= MESH_PATH_REQ_QUEUED;
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
spin_unlock(&mpath->state_lock);
|
||||
|
||||
list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
|
||||
++ifmsh->preq_queue_len;
|
||||
|
@@ -69,8 +69,6 @@ static inline struct mesh_table *resize_dereference_mpp_paths(void)
|
||||
lockdep_is_held(&pathtbl_resize_lock));
|
||||
}
|
||||
|
||||
static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath);
|
||||
|
||||
/*
|
||||
* CAREFUL -- "tbl" must not be an expression,
|
||||
* in particular not an rcu_dereference(), since
|
||||
@@ -420,21 +418,18 @@ static void mesh_gate_node_reclaim(struct rcu_head *rp)
|
||||
}
|
||||
|
||||
/**
|
||||
* mesh_gate_add - mark mpath as path to a mesh gate and add to known_gates
|
||||
* @mesh_tbl: table which contains known_gates list
|
||||
* @mpath: mpath to known mesh gate
|
||||
*
|
||||
* Returns: 0 on success
|
||||
*
|
||||
* mesh_path_add_gate - add the given mpath to a mesh gate to our path table
|
||||
* @mpath: gate path to add to table
|
||||
*/
|
||||
static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath)
|
||||
int mesh_path_add_gate(struct mesh_path *mpath)
|
||||
{
|
||||
struct mesh_table *tbl;
|
||||
struct mpath_node *gate, *new_gate;
|
||||
struct hlist_node *n;
|
||||
int err;
|
||||
|
||||
rcu_read_lock();
|
||||
tbl = rcu_dereference(tbl);
|
||||
tbl = rcu_dereference(mesh_paths);
|
||||
|
||||
hlist_for_each_entry_rcu(gate, n, tbl->known_gates, list)
|
||||
if (gate->mpath == mpath) {
|
||||
@@ -478,8 +473,6 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
|
||||
struct mpath_node *gate;
|
||||
struct hlist_node *p, *q;
|
||||
|
||||
tbl = rcu_dereference(tbl);
|
||||
|
||||
hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list)
|
||||
if (gate->mpath == mpath) {
|
||||
spin_lock_bh(&tbl->gates_lock);
|
||||
@@ -497,16 +490,6 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* mesh_path_add_gate - add the given mpath to a mesh gate to our path table
|
||||
* @mpath: gate path to add to table
|
||||
*/
|
||||
int mesh_path_add_gate(struct mesh_path *mpath)
|
||||
{
|
||||
return mesh_gate_add(mesh_paths, mpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* mesh_gate_num - number of gates known to this interface
|
||||
* @sdata: subif data
|
||||
|
@@ -101,7 +101,8 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
set_sta_flag(sta, WLAN_STA_WME);
|
||||
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
|
||||
if (elems->ht_cap_elem)
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sband, elems->ht_cap_elem,
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
elems->ht_cap_elem,
|
||||
&sta->sta.ht_cap);
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
|
@@ -209,6 +209,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
|
||||
channel_type = NL80211_CHAN_HT20;
|
||||
|
||||
if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
|
||||
!ieee80111_cfg_override_disables_ht40(sdata) &&
|
||||
(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
|
||||
(hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
|
||||
switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
||||
@@ -1120,6 +1121,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
/* on the next assoc, re-program HT parameters */
|
||||
sdata->ht_opmode_valid = false;
|
||||
memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
|
||||
memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
|
||||
|
||||
local->power_constr_level = 0;
|
||||
|
||||
@@ -1359,9 +1362,6 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
|
||||
ieee80211_set_disassoc(sdata, true, true);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
/*
|
||||
* must be outside lock due to cfg80211,
|
||||
* but that's not a problem.
|
||||
@@ -1370,6 +1370,10 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
|
||||
IEEE80211_STYPE_DEAUTH,
|
||||
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
|
||||
NULL, true);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
void ieee80211_beacon_connection_loss_work(struct work_struct *work)
|
||||
@@ -1575,7 +1579,6 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
|
||||
|
||||
set_sta_flag(sta, WLAN_STA_AUTH);
|
||||
set_sta_flag(sta, WLAN_STA_ASSOC);
|
||||
set_sta_flag(sta, WLAN_STA_ASSOC_AP);
|
||||
if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
|
||||
set_sta_flag(sta, WLAN_STA_AUTHORIZED);
|
||||
|
||||
@@ -1613,7 +1616,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
|
||||
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
|
||||
|
||||
if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
elems.ht_cap_elem, &sta->sta.ht_cap);
|
||||
|
||||
ap_ht_cap_flags = sta->sta.ht_cap.cap;
|
||||
@@ -1982,7 +1985,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
elems.ht_cap_elem, &sta->sta.ht_cap);
|
||||
|
||||
ap_ht_cap_flags = sta->sta.ht_cap.cap;
|
||||
@@ -2136,9 +2139,6 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_set_disassoc(sdata, true, true);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
/*
|
||||
* must be outside lock due to cfg80211,
|
||||
* but that's not a problem.
|
||||
@@ -2146,6 +2146,11 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_send_deauth_disassoc(sdata, bssid,
|
||||
IEEE80211_STYPE_DEAUTH, reason,
|
||||
NULL, true);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
mutex_lock(&ifmgd->mtx);
|
||||
}
|
||||
|
||||
@@ -2640,6 +2645,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
|
||||
|
||||
|
||||
if (req->flags & ASSOC_REQ_DISABLE_HT)
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
|
||||
|
||||
memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
|
||||
memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
|
||||
sizeof(ifmgd->ht_capa_mask));
|
||||
|
||||
if (req->ie && req->ie_len) {
|
||||
memcpy(wk->ie, req->ie, req->ie_len);
|
||||
wk->ie_len = req->ie_len;
|
||||
|
@@ -212,8 +212,6 @@ static void ieee80211_hw_roc_start(struct work_struct *work)
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
if (local->hw_roc_skb) {
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev);
|
||||
ieee80211_tx_skb(sdata, local->hw_roc_skb);
|
||||
@@ -227,6 +225,8 @@ static void ieee80211_hw_roc_start(struct work_struct *work)
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
|
@@ -36,8 +36,17 @@
|
||||
/* Transmit duration for the raw data part of an average sized packet */
|
||||
#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
|
||||
|
||||
/*
|
||||
* Define group sort order: HT40 -> SGI -> #streams
|
||||
*/
|
||||
#define GROUP_IDX(_streams, _sgi, _ht40) \
|
||||
MINSTREL_MAX_STREAMS * 2 * _ht40 + \
|
||||
MINSTREL_MAX_STREAMS * _sgi + \
|
||||
_streams - 1
|
||||
|
||||
/* MCS rate information for an MCS group */
|
||||
#define MCS_GROUP(_streams, _sgi, _ht40) { \
|
||||
#define MCS_GROUP(_streams, _sgi, _ht40) \
|
||||
[GROUP_IDX(_streams, _sgi, _ht40)] = { \
|
||||
.streams = _streams, \
|
||||
.flags = \
|
||||
(_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
|
||||
@@ -58,6 +67,9 @@
|
||||
* To enable sufficiently targeted rate sampling, MCS rates are divided into
|
||||
* groups, based on the number of streams and flags (HT40, SGI) that they
|
||||
* use.
|
||||
*
|
||||
* Sortorder has to be fixed for GROUP_IDX macro to be applicable:
|
||||
* HT40 -> SGI -> #streams
|
||||
*/
|
||||
const struct mcs_group minstrel_mcs_groups[] = {
|
||||
MCS_GROUP(1, 0, 0),
|
||||
@@ -102,21 +114,9 @@ minstrel_ewma(int old, int new, int weight)
|
||||
static int
|
||||
minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
|
||||
{
|
||||
int streams = (rate->idx / MCS_GROUP_RATES) + 1;
|
||||
u32 flags = IEEE80211_TX_RC_SHORT_GI | IEEE80211_TX_RC_40_MHZ_WIDTH;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) {
|
||||
if (minstrel_mcs_groups[i].streams != streams)
|
||||
continue;
|
||||
if (minstrel_mcs_groups[i].flags != (rate->flags & flags))
|
||||
continue;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1,
|
||||
!!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
|
||||
!!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
|
||||
}
|
||||
|
||||
static inline struct minstrel_rate_stats *
|
||||
@@ -130,7 +130,7 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
|
||||
* Recalculate success probabilities and counters for a rate using EWMA
|
||||
*/
|
||||
static void
|
||||
minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr)
|
||||
minstrel_calc_rate_ewma(struct minstrel_rate_stats *mr)
|
||||
{
|
||||
if (unlikely(mr->attempts > 0)) {
|
||||
mr->sample_skipped = 0;
|
||||
@@ -156,8 +156,7 @@ minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr
|
||||
* the expected number of retransmissions and their expected length
|
||||
*/
|
||||
static void
|
||||
minstrel_ht_calc_tp(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
|
||||
int group, int rate)
|
||||
minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
|
||||
{
|
||||
struct minstrel_rate_stats *mr;
|
||||
unsigned int usecs;
|
||||
@@ -226,8 +225,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||
mr = &mg->rates[i];
|
||||
mr->retry_updated = false;
|
||||
index = MCS_GROUP_RATES * group + i;
|
||||
minstrel_calc_rate_ewma(mp, mr);
|
||||
minstrel_ht_calc_tp(mp, mi, group, i);
|
||||
minstrel_calc_rate_ewma(mr);
|
||||
minstrel_ht_calc_tp(mi, group, i);
|
||||
|
||||
if (!mr->cur_tp)
|
||||
continue;
|
||||
@@ -300,10 +299,10 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||
static bool
|
||||
minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate)
|
||||
{
|
||||
if (!rate->count)
|
||||
if (rate->idx < 0)
|
||||
return false;
|
||||
|
||||
if (rate->idx < 0)
|
||||
if (!rate->count)
|
||||
return false;
|
||||
|
||||
return !!(rate->flags & IEEE80211_TX_RC_MCS);
|
||||
@@ -357,7 +356,7 @@ minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx,
|
||||
}
|
||||
|
||||
static void
|
||||
minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb)
|
||||
minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
@@ -455,7 +454,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
|
||||
minstrel_ht_update_stats(mp, mi);
|
||||
if (!(info->flags & IEEE80211_TX_CTL_AMPDU))
|
||||
minstrel_aggr_check(mp, sta, skb);
|
||||
minstrel_aggr_check(sta, skb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,7 +514,6 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
|
||||
static void
|
||||
minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
|
||||
struct ieee80211_tx_rate *rate, int index,
|
||||
struct ieee80211_tx_rate_control *txrc,
|
||||
bool sample, bool rtscts)
|
||||
{
|
||||
const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
|
||||
@@ -628,11 +626,11 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
||||
if (sample_idx >= 0) {
|
||||
sample = true;
|
||||
minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx,
|
||||
txrc, true, false);
|
||||
true, false);
|
||||
info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
||||
} else {
|
||||
minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate,
|
||||
txrc, false, false);
|
||||
false, false);
|
||||
}
|
||||
|
||||
if (mp->hw->max_rates >= 3) {
|
||||
@@ -643,13 +641,13 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
||||
*/
|
||||
if (sample_idx >= 0)
|
||||
minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate,
|
||||
txrc, false, false);
|
||||
false, false);
|
||||
else
|
||||
minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2,
|
||||
txrc, false, true);
|
||||
false, true);
|
||||
|
||||
minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate,
|
||||
txrc, false, !sample);
|
||||
false, !sample);
|
||||
|
||||
ar[3].count = 0;
|
||||
ar[3].idx = -1;
|
||||
@@ -660,7 +658,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
||||
* max_tp_rate -> max_prob_rate by default.
|
||||
*/
|
||||
minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_prob_rate,
|
||||
txrc, false, !sample);
|
||||
false, !sample);
|
||||
|
||||
ar[2].count = 0;
|
||||
ar[2].idx = -1;
|
||||
|
@@ -30,7 +30,6 @@
|
||||
* when virtual port control is not in use.
|
||||
* @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
|
||||
* frames.
|
||||
* @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
|
||||
* @WLAN_STA_WME: Station is a QoS-STA.
|
||||
* @WLAN_STA_WDS: Station is one of our WDS peers.
|
||||
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
|
||||
@@ -60,7 +59,6 @@ enum ieee80211_sta_info_flags {
|
||||
WLAN_STA_PS_STA,
|
||||
WLAN_STA_AUTHORIZED,
|
||||
WLAN_STA_SHORT_PREAMBLE,
|
||||
WLAN_STA_ASSOC_AP,
|
||||
WLAN_STA_WME,
|
||||
WLAN_STA_WDS,
|
||||
WLAN_STA_CLEAR_PS_FILT,
|
||||
|
@@ -36,7 +36,8 @@
|
||||
|
||||
/* misc utils */
|
||||
|
||||
static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
||||
static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
|
||||
struct sk_buff *skb, int group_addr,
|
||||
int next_frag_len)
|
||||
{
|
||||
int rate, mrate, erp, dur, i;
|
||||
@@ -44,7 +45,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
||||
struct ieee80211_local *local = tx->local;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
/* assume HW handles this */
|
||||
if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
|
||||
@@ -76,7 +77,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
|
||||
* at the highest possible rate belonging to the PHY rates in the
|
||||
* BSSBasicRateSet
|
||||
*/
|
||||
hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
if (ieee80211_is_ctl(hdr->frame_control)) {
|
||||
/* TODO: These control frames are not currently sent by
|
||||
* mac80211, but should they be implemented, this function
|
||||
@@ -572,8 +573,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
||||
switch (tx->key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
if (ieee80211_is_auth(hdr->frame_control))
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
if (!ieee80211_is_data_present(hdr->frame_control))
|
||||
tx->key = NULL;
|
||||
@@ -844,11 +843,13 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static int ieee80211_fragment(struct ieee80211_local *local,
|
||||
static int ieee80211_fragment(struct ieee80211_tx_data *tx,
|
||||
struct sk_buff *skb, int hdrlen,
|
||||
int frag_threshold)
|
||||
{
|
||||
struct sk_buff *tail = skb, *tmp;
|
||||
struct ieee80211_local *local = tx->local;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct sk_buff *tmp;
|
||||
int per_fragm = frag_threshold - hdrlen - FCS_LEN;
|
||||
int pos = hdrlen + per_fragm;
|
||||
int rem = skb->len - hdrlen - per_fragm;
|
||||
@@ -856,6 +857,8 @@ static int ieee80211_fragment(struct ieee80211_local *local,
|
||||
if (WARN_ON(rem < 0))
|
||||
return -EINVAL;
|
||||
|
||||
/* first fragment was already added to queue by caller */
|
||||
|
||||
while (rem) {
|
||||
int fraglen = per_fragm;
|
||||
|
||||
@@ -868,12 +871,21 @@ static int ieee80211_fragment(struct ieee80211_local *local,
|
||||
IEEE80211_ENCRYPT_TAILROOM);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
tail->next = tmp;
|
||||
tail = tmp;
|
||||
|
||||
__skb_queue_tail(&tx->skbs, tmp);
|
||||
|
||||
skb_reserve(tmp, local->tx_headroom +
|
||||
IEEE80211_ENCRYPT_HEADROOM);
|
||||
/* copy control information */
|
||||
memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
|
||||
|
||||
info = IEEE80211_SKB_CB(tmp);
|
||||
info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
||||
IEEE80211_TX_CTL_FIRST_FRAGMENT);
|
||||
|
||||
if (rem)
|
||||
info->flags |= IEEE80211_TX_CTL_MORE_FRAMES;
|
||||
|
||||
skb_copy_queue_mapping(tmp, skb);
|
||||
tmp->priority = skb->priority;
|
||||
tmp->dev = skb->dev;
|
||||
@@ -885,6 +897,7 @@ static int ieee80211_fragment(struct ieee80211_local *local,
|
||||
pos += fraglen;
|
||||
}
|
||||
|
||||
/* adjust first fragment's length */
|
||||
skb->len = hdrlen + per_fragm;
|
||||
return 0;
|
||||
}
|
||||
@@ -899,6 +912,10 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
||||
int hdrlen;
|
||||
int fragnum;
|
||||
|
||||
/* no matter what happens, tx->skb moves to tx->skbs */
|
||||
__skb_queue_tail(&tx->skbs, skb);
|
||||
tx->skb = NULL;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_DONTFRAG)
|
||||
return TX_CONTINUE;
|
||||
|
||||
@@ -927,21 +944,21 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
||||
* of the fragments then we will simply pretend to accept the skb
|
||||
* but store it away as pending.
|
||||
*/
|
||||
if (ieee80211_fragment(tx->local, skb, hdrlen, frag_threshold))
|
||||
if (ieee80211_fragment(tx, skb, hdrlen, frag_threshold))
|
||||
return TX_DROP;
|
||||
|
||||
/* update duration/seq/flags of fragments */
|
||||
fragnum = 0;
|
||||
do {
|
||||
|
||||
skb_queue_walk(&tx->skbs, skb) {
|
||||
int next_len;
|
||||
const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
|
||||
|
||||
hdr = (void *)skb->data;
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (skb->next) {
|
||||
if (!skb_queue_is_last(&tx->skbs, skb)) {
|
||||
hdr->frame_control |= morefrags;
|
||||
next_len = skb->next->len;
|
||||
/*
|
||||
* No multi-rate retries for fragmented frames, that
|
||||
* would completely throw off the NAV at other STAs.
|
||||
@@ -956,10 +973,9 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
||||
hdr->frame_control &= ~morefrags;
|
||||
next_len = 0;
|
||||
}
|
||||
hdr->duration_id = ieee80211_duration(tx, 0, next_len);
|
||||
hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG);
|
||||
fragnum++;
|
||||
} while ((skb = skb->next));
|
||||
}
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
@@ -967,16 +983,16 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct sk_buff *skb = tx->skb;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!tx->sta)
|
||||
return TX_CONTINUE;
|
||||
|
||||
tx->sta->tx_packets++;
|
||||
do {
|
||||
skb_queue_walk(&tx->skbs, skb) {
|
||||
tx->sta->tx_fragments++;
|
||||
tx->sta->tx_bytes += skb->len;
|
||||
} while ((skb = skb->next));
|
||||
}
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
@@ -1015,21 +1031,25 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct sk_buff *skb = tx->skb;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int next_len;
|
||||
bool group_addr;
|
||||
|
||||
do {
|
||||
skb_queue_walk(&tx->skbs, skb) {
|
||||
hdr = (void *) skb->data;
|
||||
if (unlikely(ieee80211_is_pspoll(hdr->frame_control)))
|
||||
break; /* must not overwrite AID */
|
||||
next_len = skb->next ? skb->next->len : 0;
|
||||
if (!skb_queue_is_last(&tx->skbs, skb)) {
|
||||
struct sk_buff *next = skb_queue_next(&tx->skbs, skb);
|
||||
next_len = next->len;
|
||||
} else
|
||||
next_len = 0;
|
||||
group_addr = is_multicast_ether_addr(hdr->addr1);
|
||||
|
||||
hdr->duration_id =
|
||||
ieee80211_duration(tx, group_addr, next_len);
|
||||
} while ((skb = skb->next));
|
||||
ieee80211_duration(tx, skb, group_addr, next_len);
|
||||
}
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
@@ -1108,6 +1128,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
||||
tx->local = local;
|
||||
tx->sdata = sdata;
|
||||
tx->channel = local->hw.conf.channel;
|
||||
__skb_queue_head_init(&tx->skbs);
|
||||
|
||||
/*
|
||||
* If this flag is set to true anywhere, and we get here,
|
||||
@@ -1180,22 +1201,18 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns false if the frame couldn't be transmitted but was queued instead.
|
||||
*/
|
||||
static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp,
|
||||
struct sta_info *sta, bool txpending)
|
||||
static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct sk_buff_head *skbs,
|
||||
bool txpending)
|
||||
{
|
||||
struct sk_buff *skb = *skbp, *next;
|
||||
struct sk_buff *skb, *tmp;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
unsigned long flags;
|
||||
int len;
|
||||
bool fragm = false;
|
||||
|
||||
while (skb) {
|
||||
skb_queue_walk_safe(skbs, skb, tmp) {
|
||||
int q = skb_get_queue_mapping(skb);
|
||||
__le16 fc;
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
if (local->queue_stop_reasons[q] ||
|
||||
@@ -1205,24 +1222,10 @@ static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp,
|
||||
* transmission from the tx-pending tasklet when the
|
||||
* queue is woken again.
|
||||
*/
|
||||
|
||||
do {
|
||||
next = skb->next;
|
||||
skb->next = NULL;
|
||||
/*
|
||||
* NB: If txpending is true, next must already
|
||||
* be NULL since we must've gone through this
|
||||
* loop before already; therefore we can just
|
||||
* queue the frame to the head without worrying
|
||||
* about reordering of fragments.
|
||||
*/
|
||||
if (unlikely(txpending))
|
||||
__skb_queue_head(&local->pending[q],
|
||||
skb);
|
||||
else
|
||||
__skb_queue_tail(&local->pending[q],
|
||||
skb);
|
||||
} while ((skb = next));
|
||||
if (txpending)
|
||||
skb_queue_splice(skbs, &local->pending[q]);
|
||||
else
|
||||
skb_queue_splice_tail(skbs, &local->pending[q]);
|
||||
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
|
||||
flags);
|
||||
@@ -1231,57 +1234,81 @@ static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp,
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
info->control.vif = vif;
|
||||
info->control.sta = sta;
|
||||
|
||||
if (fragm)
|
||||
info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
||||
IEEE80211_TX_CTL_FIRST_FRAGMENT);
|
||||
|
||||
next = skb->next;
|
||||
len = skb->len;
|
||||
|
||||
if (next)
|
||||
info->flags |= IEEE80211_TX_CTL_MORE_FRAMES;
|
||||
|
||||
sdata = vif_to_sdata(info->control.vif);
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
info->control.vif = NULL;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
info->control.vif = &container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data, u.ap)->vif;
|
||||
break;
|
||||
default:
|
||||
/* keep */
|
||||
break;
|
||||
}
|
||||
|
||||
if (sta && sta->uploaded)
|
||||
info->control.sta = &sta->sta;
|
||||
else
|
||||
info->control.sta = NULL;
|
||||
|
||||
fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
|
||||
__skb_unlink(skb, skbs);
|
||||
drv_tx(local, skb);
|
||||
|
||||
ieee80211_tpt_led_trig_tx(local, fc, len);
|
||||
*skbp = skb = next;
|
||||
ieee80211_led_tx(local, 1);
|
||||
fragm = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns false if the frame couldn't be transmitted but was queued instead.
|
||||
*/
|
||||
static bool __ieee80211_tx(struct ieee80211_local *local,
|
||||
struct sk_buff_head *skbs, int led_len,
|
||||
struct sta_info *sta, bool txpending)
|
||||
{
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_vif *vif;
|
||||
struct ieee80211_sta *pubsta;
|
||||
struct sk_buff *skb;
|
||||
bool result = true;
|
||||
__le16 fc;
|
||||
|
||||
if (WARN_ON(skb_queue_empty(skbs)))
|
||||
return true;
|
||||
|
||||
skb = skb_peek(skbs);
|
||||
fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
sdata = vif_to_sdata(info->control.vif);
|
||||
if (sta && !sta->uploaded)
|
||||
sta = NULL;
|
||||
|
||||
if (sta)
|
||||
pubsta = &sta->sta;
|
||||
else
|
||||
pubsta = NULL;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
sdata = NULL;
|
||||
vif = NULL;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
sdata = container_of(sdata->bss,
|
||||
struct ieee80211_sub_if_data, u.ap);
|
||||
/* fall through */
|
||||
default:
|
||||
vif = &sdata->vif;
|
||||
break;
|
||||
}
|
||||
|
||||
if (local->ops->tx_frags)
|
||||
drv_tx_frags(local, vif, pubsta, skbs);
|
||||
else
|
||||
result = ieee80211_tx_frags(local, vif, pubsta, skbs,
|
||||
txpending);
|
||||
|
||||
ieee80211_tpt_led_trig_tx(local, fc, led_len);
|
||||
ieee80211_led_tx(local, 1);
|
||||
|
||||
WARN_ON(!skb_queue_empty(skbs));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke TX handlers, return 0 on success and non-zero if the
|
||||
* frame was dropped or queued.
|
||||
*/
|
||||
static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct sk_buff *skb = tx->skb;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
ieee80211_tx_result res = TX_DROP;
|
||||
|
||||
#define CALL_TXH(txh) \
|
||||
@@ -1315,13 +1342,10 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
||||
txh_done:
|
||||
if (unlikely(res == TX_DROP)) {
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_drop);
|
||||
while (skb) {
|
||||
struct sk_buff *next;
|
||||
|
||||
next = skb->next;
|
||||
dev_kfree_skb(skb);
|
||||
skb = next;
|
||||
}
|
||||
if (tx->skb)
|
||||
dev_kfree_skb(tx->skb);
|
||||
else
|
||||
__skb_queue_purge(&tx->skbs);
|
||||
return -1;
|
||||
} else if (unlikely(res == TX_QUEUED)) {
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_queued);
|
||||
@@ -1342,6 +1366,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_tx_result res_prepare;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
bool result = true;
|
||||
int led_len;
|
||||
|
||||
if (unlikely(skb->len < 10)) {
|
||||
dev_kfree_skb(skb);
|
||||
@@ -1351,6 +1376,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
||||
rcu_read_lock();
|
||||
|
||||
/* initialises tx */
|
||||
led_len = skb->len;
|
||||
res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
|
||||
|
||||
if (unlikely(res_prepare == TX_DROP)) {
|
||||
@@ -1364,7 +1390,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
||||
info->band = tx.channel->band;
|
||||
|
||||
if (!invoke_tx_handlers(&tx))
|
||||
result = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
|
||||
result = __ieee80211_tx(local, &tx.skbs, led_len,
|
||||
tx.sta, txpending);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return result;
|
||||
@@ -2112,10 +2139,15 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
|
||||
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
|
||||
result = ieee80211_tx(sdata, skb, true);
|
||||
} else {
|
||||
struct sk_buff_head skbs;
|
||||
|
||||
__skb_queue_head_init(&skbs);
|
||||
__skb_queue_tail(&skbs, skb);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
sta = sta_info_get(sdata, hdr->addr1);
|
||||
|
||||
result = __ieee80211_tx(local, &skb, sta, true);
|
||||
result = __ieee80211_tx(local, &skbs, skb->len, sta, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/rtnetlink.h>
|
||||
@@ -96,13 +97,13 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
|
||||
|
||||
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct sk_buff *skb = tx->skb;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
do {
|
||||
skb_queue_walk(&tx->skbs, skb) {
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
} while ((skb = skb->next));
|
||||
}
|
||||
}
|
||||
|
||||
int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
|
||||
@@ -564,6 +565,172 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_queue_delayed_work);
|
||||
|
||||
u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc)
|
||||
{
|
||||
size_t left = len;
|
||||
u8 *pos = start;
|
||||
bool calc_crc = filter != 0;
|
||||
|
||||
memset(elems, 0, sizeof(*elems));
|
||||
elems->ie_start = start;
|
||||
elems->total_len = len;
|
||||
|
||||
while (left >= 2) {
|
||||
u8 id, elen;
|
||||
|
||||
id = *pos++;
|
||||
elen = *pos++;
|
||||
left -= 2;
|
||||
|
||||
if (elen > left)
|
||||
break;
|
||||
|
||||
if (calc_crc && id < 64 && (filter & (1ULL << id)))
|
||||
crc = crc32_be(crc, pos - 2, elen + 2);
|
||||
|
||||
switch (id) {
|
||||
case WLAN_EID_SSID:
|
||||
elems->ssid = pos;
|
||||
elems->ssid_len = elen;
|
||||
break;
|
||||
case WLAN_EID_SUPP_RATES:
|
||||
elems->supp_rates = pos;
|
||||
elems->supp_rates_len = elen;
|
||||
break;
|
||||
case WLAN_EID_FH_PARAMS:
|
||||
elems->fh_params = pos;
|
||||
elems->fh_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_DS_PARAMS:
|
||||
elems->ds_params = pos;
|
||||
elems->ds_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_CF_PARAMS:
|
||||
elems->cf_params = pos;
|
||||
elems->cf_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_TIM:
|
||||
if (elen >= sizeof(struct ieee80211_tim_ie)) {
|
||||
elems->tim = (void *)pos;
|
||||
elems->tim_len = elen;
|
||||
}
|
||||
break;
|
||||
case WLAN_EID_IBSS_PARAMS:
|
||||
elems->ibss_params = pos;
|
||||
elems->ibss_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_CHALLENGE:
|
||||
elems->challenge = pos;
|
||||
elems->challenge_len = elen;
|
||||
break;
|
||||
case WLAN_EID_VENDOR_SPECIFIC:
|
||||
if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
|
||||
pos[2] == 0xf2) {
|
||||
/* Microsoft OUI (00:50:F2) */
|
||||
|
||||
if (calc_crc)
|
||||
crc = crc32_be(crc, pos - 2, elen + 2);
|
||||
|
||||
if (pos[3] == 1) {
|
||||
/* OUI Type 1 - WPA IE */
|
||||
elems->wpa = pos;
|
||||
elems->wpa_len = elen;
|
||||
} else if (elen >= 5 && pos[3] == 2) {
|
||||
/* OUI Type 2 - WMM IE */
|
||||
if (pos[4] == 0) {
|
||||
elems->wmm_info = pos;
|
||||
elems->wmm_info_len = elen;
|
||||
} else if (pos[4] == 1) {
|
||||
elems->wmm_param = pos;
|
||||
elems->wmm_param_len = elen;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WLAN_EID_RSN:
|
||||
elems->rsn = pos;
|
||||
elems->rsn_len = elen;
|
||||
break;
|
||||
case WLAN_EID_ERP_INFO:
|
||||
elems->erp_info = pos;
|
||||
elems->erp_info_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_SUPP_RATES:
|
||||
elems->ext_supp_rates = pos;
|
||||
elems->ext_supp_rates_len = elen;
|
||||
break;
|
||||
case WLAN_EID_HT_CAPABILITY:
|
||||
if (elen >= sizeof(struct ieee80211_ht_cap))
|
||||
elems->ht_cap_elem = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_HT_INFORMATION:
|
||||
if (elen >= sizeof(struct ieee80211_ht_info))
|
||||
elems->ht_info_elem = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_MESH_ID:
|
||||
elems->mesh_id = pos;
|
||||
elems->mesh_id_len = elen;
|
||||
break;
|
||||
case WLAN_EID_MESH_CONFIG:
|
||||
if (elen >= sizeof(struct ieee80211_meshconf_ie))
|
||||
elems->mesh_config = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_PEER_MGMT:
|
||||
elems->peering = pos;
|
||||
elems->peering_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PREQ:
|
||||
elems->preq = pos;
|
||||
elems->preq_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PREP:
|
||||
elems->prep = pos;
|
||||
elems->prep_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PERR:
|
||||
elems->perr = pos;
|
||||
elems->perr_len = elen;
|
||||
break;
|
||||
case WLAN_EID_RANN:
|
||||
if (elen >= sizeof(struct ieee80211_rann_ie))
|
||||
elems->rann = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_CHANNEL_SWITCH:
|
||||
elems->ch_switch_elem = pos;
|
||||
elems->ch_switch_elem_len = elen;
|
||||
break;
|
||||
case WLAN_EID_QUIET:
|
||||
if (!elems->quiet_elem) {
|
||||
elems->quiet_elem = pos;
|
||||
elems->quiet_elem_len = elen;
|
||||
}
|
||||
elems->num_of_quiet_elem++;
|
||||
break;
|
||||
case WLAN_EID_COUNTRY:
|
||||
elems->country_elem = pos;
|
||||
elems->country_elem_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PWR_CONSTRAINT:
|
||||
elems->pwr_constr_elem = pos;
|
||||
elems->pwr_constr_elem_len = elen;
|
||||
break;
|
||||
case WLAN_EID_TIMEOUT_INTERVAL:
|
||||
elems->timeout_int = pos;
|
||||
elems->timeout_int_len = elen;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
left -= elen;
|
||||
pos += elen;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
void ieee802_11_parse_elems(u8 *start, size_t len,
|
||||
struct ieee802_11_elems *elems)
|
||||
{
|
||||
@@ -813,7 +980,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
||||
}
|
||||
|
||||
if (sband->ht_cap.ht_supported)
|
||||
pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
|
||||
pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
|
||||
sband->ht_cap.cap);
|
||||
|
||||
/*
|
||||
* If adding more here, adjust code in main.c
|
||||
@@ -1356,7 +1524,7 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
|
||||
|
||||
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
|
||||
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||
u16 cap)
|
||||
{
|
||||
__le16 tmp;
|
||||
@@ -1371,13 +1539,13 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
|
||||
pos += sizeof(u16);
|
||||
|
||||
/* AMPDU parameters */
|
||||
*pos++ = sband->ht_cap.ampdu_factor |
|
||||
(sband->ht_cap.ampdu_density <<
|
||||
*pos++ = ht_cap->ampdu_factor |
|
||||
(ht_cap->ampdu_density <<
|
||||
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
|
||||
|
||||
/* MCS set */
|
||||
memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
|
||||
pos += sizeof(sband->ht_cap.mcs);
|
||||
memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
|
||||
pos += sizeof(ht_cap->mcs);
|
||||
|
||||
/* extended capabilities */
|
||||
pos += sizeof(__le16);
|
||||
|
@@ -330,13 +330,12 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
|
||||
|
||||
ieee80211_tx_set_protected(tx);
|
||||
|
||||
skb = tx->skb;
|
||||
do {
|
||||
skb_queue_walk(&tx->skbs, skb) {
|
||||
if (wep_encrypt_skb(tx, skb) < 0) {
|
||||
I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
|
||||
return TX_DROP;
|
||||
}
|
||||
} while ((skb = skb->next));
|
||||
}
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
@@ -94,7 +94,8 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
|
||||
|
||||
/* frame sending functions */
|
||||
|
||||
static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
|
||||
static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, const u8 *ht_info_ie,
|
||||
struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_channel *channel,
|
||||
enum ieee80211_smps_mode smps)
|
||||
@@ -102,7 +103,10 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
|
||||
struct ieee80211_ht_info *ht_info;
|
||||
u8 *pos;
|
||||
u32 flags = channel->flags;
|
||||
u16 cap = sband->ht_cap.cap;
|
||||
u16 cap;
|
||||
struct ieee80211_sta_ht_cap ht_cap;
|
||||
|
||||
BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
|
||||
|
||||
if (!sband->ht_cap.ht_supported)
|
||||
return;
|
||||
@@ -113,9 +117,13 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
|
||||
if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
|
||||
return;
|
||||
|
||||
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
|
||||
ieee80211_apply_htcap_overrides(sdata, &ht_cap);
|
||||
|
||||
ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
|
||||
|
||||
/* determine capability flags */
|
||||
cap = ht_cap.cap;
|
||||
|
||||
switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
||||
@@ -154,7 +162,7 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
|
||||
|
||||
/* reserve and fill IE */
|
||||
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
|
||||
ieee80211_ie_build_ht_cap(pos, sband, cap);
|
||||
ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
|
||||
}
|
||||
|
||||
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
@@ -329,7 +337,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (wk->assoc.use_11n && wk->assoc.wmm_used &&
|
||||
local->hw.queues >= 4)
|
||||
ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie,
|
||||
ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie,
|
||||
sband, wk->chan, wk->assoc.smps);
|
||||
|
||||
/* if present, add any custom non-vendor IEs that go after HT */
|
||||
|
@@ -223,14 +223,14 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
||||
ieee80211_tx_result
|
||||
ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct sk_buff *skb = tx->skb;
|
||||
struct sk_buff *skb;
|
||||
|
||||
ieee80211_tx_set_protected(tx);
|
||||
|
||||
do {
|
||||
skb_queue_walk(&tx->skbs, skb) {
|
||||
if (tkip_encrypt_skb(tx, skb) < 0)
|
||||
return TX_DROP;
|
||||
} while ((skb = skb->next));
|
||||
}
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
@@ -449,14 +449,14 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
||||
ieee80211_tx_result
|
||||
ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct sk_buff *skb = tx->skb;
|
||||
struct sk_buff *skb;
|
||||
|
||||
ieee80211_tx_set_protected(tx);
|
||||
|
||||
do {
|
||||
skb_queue_walk(&tx->skbs, skb) {
|
||||
if (ccmp_encrypt_skb(tx, skb) < 0)
|
||||
return TX_DROP;
|
||||
} while ((skb = skb->next));
|
||||
}
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
@@ -554,15 +554,22 @@ static inline void bip_ipn_swap(u8 *d, const u8 *s)
|
||||
ieee80211_tx_result
|
||||
ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct sk_buff *skb = tx->skb;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_key *key = tx->key;
|
||||
struct ieee80211_mmie *mmie;
|
||||
u8 aad[20];
|
||||
u64 pn64;
|
||||
|
||||
if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
|
||||
return TX_DROP;
|
||||
|
||||
skb = skb_peek(&tx->skbs);
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (info->control.hw_key)
|
||||
return 0;
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
|
||||
return TX_DROP;
|
||||
|
@@ -341,13 +341,17 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
const u8 *bssid, const u8 *prev_bssid,
|
||||
const u8 *ssid, int ssid_len,
|
||||
const u8 *ie, int ie_len, bool use_mfp,
|
||||
struct cfg80211_crypto_settings *crypt);
|
||||
struct cfg80211_crypto_settings *crypt,
|
||||
u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
|
||||
struct ieee80211_ht_cap *ht_capa_mask);
|
||||
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, struct ieee80211_channel *chan,
|
||||
const u8 *bssid, const u8 *prev_bssid,
|
||||
const u8 *ssid, int ssid_len,
|
||||
const u8 *ie, int ie_len, bool use_mfp,
|
||||
struct cfg80211_crypto_settings *crypt);
|
||||
struct cfg80211_crypto_settings *crypt,
|
||||
u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
|
||||
struct ieee80211_ht_cap *ht_capa_mask);
|
||||
int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, const u8 *bssid,
|
||||
const u8 *ie, int ie_len, u16 reason,
|
||||
@@ -379,6 +383,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
||||
bool channel_type_valid, unsigned int wait,
|
||||
const u8 *buf, size_t len, bool no_cck,
|
||||
bool dont_wait_for_ack, u64 *cookie);
|
||||
void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
|
||||
const struct ieee80211_ht_cap *ht_capa_mask);
|
||||
|
||||
/* SME */
|
||||
int __cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
|
@@ -501,13 +501,32 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Do a logical ht_capa &= ht_capa_mask. */
|
||||
void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
|
||||
const struct ieee80211_ht_cap *ht_capa_mask)
|
||||
{
|
||||
int i;
|
||||
u8 *p1, *p2;
|
||||
if (!ht_capa_mask) {
|
||||
memset(ht_capa, 0, sizeof(*ht_capa));
|
||||
return;
|
||||
}
|
||||
|
||||
p1 = (u8*)(ht_capa);
|
||||
p2 = (u8*)(ht_capa_mask);
|
||||
for (i = 0; i<sizeof(*ht_capa); i++)
|
||||
p1[i] &= p2[i];
|
||||
}
|
||||
|
||||
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
const u8 *bssid, const u8 *prev_bssid,
|
||||
const u8 *ssid, int ssid_len,
|
||||
const u8 *ie, int ie_len, bool use_mfp,
|
||||
struct cfg80211_crypto_settings *crypt)
|
||||
struct cfg80211_crypto_settings *crypt,
|
||||
u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
|
||||
struct ieee80211_ht_cap *ht_capa_mask)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_assoc_request req;
|
||||
@@ -537,6 +556,15 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
memcpy(&req.crypto, crypt, sizeof(req.crypto));
|
||||
req.use_mfp = use_mfp;
|
||||
req.prev_bssid = prev_bssid;
|
||||
req.flags = assoc_flags;
|
||||
if (ht_capa)
|
||||
memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa));
|
||||
if (ht_capa_mask)
|
||||
memcpy(&req.ht_capa_mask, ht_capa_mask,
|
||||
sizeof(req.ht_capa_mask));
|
||||
cfg80211_oper_and_ht_capa(&req.ht_capa_mask,
|
||||
rdev->wiphy.ht_capa_mod_mask);
|
||||
|
||||
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
if (!req.bss) {
|
||||
@@ -574,14 +602,17 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
const u8 *bssid, const u8 *prev_bssid,
|
||||
const u8 *ssid, int ssid_len,
|
||||
const u8 *ie, int ie_len, bool use_mfp,
|
||||
struct cfg80211_crypto_settings *crypt)
|
||||
struct cfg80211_crypto_settings *crypt,
|
||||
u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
|
||||
struct ieee80211_ht_cap *ht_capa_mask)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
|
||||
ssid, ssid_len, ie, ie_len, use_mfp, crypt);
|
||||
ssid, ssid_len, ie, ie_len, use_mfp, crypt,
|
||||
assoc_flags, ht_capa, ht_capa_mask);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
return err;
|
||||
|
@@ -199,6 +199,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
||||
[NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
|
||||
.len = IEEE80211_MAX_DATA_LEN },
|
||||
[NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_HT_CAPABILITY_MASK] = {
|
||||
.len = NL80211_HT_CAPABILITY_LEN
|
||||
},
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@@ -881,7 +886,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
CMD(set_pmksa, SET_PMKSA);
|
||||
CMD(del_pmksa, DEL_PMKSA);
|
||||
CMD(flush_pmksa, FLUSH_PMKSA);
|
||||
CMD(remain_on_channel, REMAIN_ON_CHANNEL);
|
||||
if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
|
||||
CMD(remain_on_channel, REMAIN_ON_CHANNEL);
|
||||
CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
|
||||
CMD(mgmt_tx, FRAME);
|
||||
CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
|
||||
@@ -903,6 +909,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
CMD(testmode_cmd, TESTMODE);
|
||||
#endif
|
||||
|
||||
#undef CMD
|
||||
|
||||
if (dev->ops->connect || dev->ops->auth) {
|
||||
@@ -917,11 +927,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
|
||||
nla_nest_end(msg, nl_cmds);
|
||||
|
||||
if (dev->ops->remain_on_channel)
|
||||
if (dev->ops->remain_on_channel &&
|
||||
dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
|
||||
dev->wiphy.max_remain_on_channel_duration);
|
||||
|
||||
if (dev->ops->mgmt_tx_cancel_wait)
|
||||
if (dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)
|
||||
NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
|
||||
|
||||
if (mgmt_stypes) {
|
||||
@@ -1025,6 +1036,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features);
|
||||
|
||||
if (dev->wiphy.ht_capa_mod_mask)
|
||||
NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
|
||||
sizeof(*dev->wiphy.ht_capa_mod_mask),
|
||||
dev->wiphy.ht_capa_mod_mask);
|
||||
|
||||
return genlmsg_end(msg, hdr);
|
||||
|
||||
nla_put_failure:
|
||||
@@ -2478,26 +2494,34 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
|
||||
/*
|
||||
* Get vlan interface making sure it is running and on the right wiphy.
|
||||
*/
|
||||
static int get_vlan(struct genl_info *info,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct net_device **vlan)
|
||||
static struct net_device *get_vlan(struct genl_info *info,
|
||||
struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
|
||||
*vlan = NULL;
|
||||
struct net_device *v;
|
||||
int ret;
|
||||
|
||||
if (vlanattr) {
|
||||
*vlan = dev_get_by_index(genl_info_net(info),
|
||||
nla_get_u32(vlanattr));
|
||||
if (!*vlan)
|
||||
return -ENODEV;
|
||||
if (!(*vlan)->ieee80211_ptr)
|
||||
return -EINVAL;
|
||||
if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
|
||||
return -EINVAL;
|
||||
if (!netif_running(*vlan))
|
||||
return -ENETDOWN;
|
||||
if (!vlanattr)
|
||||
return NULL;
|
||||
|
||||
v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
|
||||
if (!v)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (!netif_running(v)) {
|
||||
ret = -ENETDOWN;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return v;
|
||||
error:
|
||||
dev_put(v);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
||||
@@ -2547,9 +2571,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
||||
params.plink_state =
|
||||
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
|
||||
|
||||
err = get_vlan(info, rdev, ¶ms.vlan);
|
||||
if (err)
|
||||
goto out;
|
||||
params.vlan = get_vlan(info, rdev);
|
||||
if (IS_ERR(params.vlan))
|
||||
return PTR_ERR(params.vlan);
|
||||
|
||||
/* validate settings */
|
||||
err = 0;
|
||||
@@ -2717,9 +2741,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||
(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)))
|
||||
return -EINVAL;
|
||||
|
||||
err = get_vlan(info, rdev, ¶ms.vlan);
|
||||
if (err)
|
||||
goto out;
|
||||
params.vlan = get_vlan(info, rdev);
|
||||
if (IS_ERR(params.vlan))
|
||||
return PTR_ERR(params.vlan);
|
||||
|
||||
/* validate settings */
|
||||
err = 0;
|
||||
@@ -3382,6 +3406,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2,
|
||||
cfg80211_regdomain->alpha2);
|
||||
if (cfg80211_regdomain->dfs_region)
|
||||
NLA_PUT_U8(msg, NL80211_ATTR_DFS_REGION,
|
||||
cfg80211_regdomain->dfs_region);
|
||||
|
||||
nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
|
||||
if (!nl_reg_rules)
|
||||
@@ -3440,6 +3467,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
char *alpha2 = NULL;
|
||||
int rem_reg_rules = 0, r = 0;
|
||||
u32 num_rules = 0, rule_idx = 0, size_of_regd;
|
||||
u8 dfs_region = 0;
|
||||
struct ieee80211_regdomain *rd = NULL;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
|
||||
@@ -3450,6 +3478,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_DFS_REGION])
|
||||
dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
|
||||
|
||||
nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
|
||||
rem_reg_rules) {
|
||||
num_rules++;
|
||||
@@ -3477,6 +3508,13 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
rd->alpha2[0] = alpha2[0];
|
||||
rd->alpha2[1] = alpha2[1];
|
||||
|
||||
/*
|
||||
* Disable DFS master mode if the DFS region was
|
||||
* not supported or known on this kernel.
|
||||
*/
|
||||
if (reg_supported_dfs_region(dfs_region))
|
||||
rd->dfs_region = dfs_region;
|
||||
|
||||
nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
|
||||
rem_reg_rules) {
|
||||
nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
|
||||
@@ -4384,6 +4422,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
|
||||
const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
|
||||
int err, ssid_len, ie_len = 0;
|
||||
bool use_mfp = false;
|
||||
u32 flags = 0;
|
||||
struct ieee80211_ht_cap *ht_capa = NULL;
|
||||
struct ieee80211_ht_cap *ht_capa_mask = NULL;
|
||||
|
||||
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
|
||||
return -EINVAL;
|
||||
@@ -4427,11 +4468,25 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
|
||||
if (info->attrs[NL80211_ATTR_PREV_BSSID])
|
||||
prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
|
||||
|
||||
if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
|
||||
flags |= ASSOC_REQ_DISABLE_HT;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
|
||||
ht_capa_mask =
|
||||
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
|
||||
if (!ht_capa_mask)
|
||||
return -EINVAL;
|
||||
ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
|
||||
}
|
||||
|
||||
err = nl80211_crypto_settings(rdev, info, &crypto, 1);
|
||||
if (!err)
|
||||
err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
|
||||
ssid, ssid_len, ie, ie_len, use_mfp,
|
||||
&crypto);
|
||||
&crypto, flags, ht_capa,
|
||||
ht_capa_mask);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -4921,6 +4976,22 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
||||
return PTR_ERR(connkeys);
|
||||
}
|
||||
|
||||
if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
|
||||
connect.flags |= ASSOC_REQ_DISABLE_HT;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
|
||||
memcpy(&connect.ht_capa_mask,
|
||||
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
|
||||
sizeof(connect.ht_capa_mask));
|
||||
|
||||
if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
|
||||
if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
|
||||
return -EINVAL;
|
||||
memcpy(&connect.ht_capa,
|
||||
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
|
||||
sizeof(connect.ht_capa));
|
||||
}
|
||||
|
||||
err = cfg80211_connect(rdev, dev, &connect, connkeys);
|
||||
if (err)
|
||||
kfree(connkeys);
|
||||
@@ -5108,7 +5179,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
|
||||
duration > rdev->wiphy.max_remain_on_channel_duration)
|
||||
return -EINVAL;
|
||||
|
||||
if (!rdev->ops->remain_on_channel)
|
||||
if (!rdev->ops->remain_on_channel ||
|
||||
!(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
|
||||
@@ -5321,7 +5393,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_DURATION]) {
|
||||
if (!rdev->ops->mgmt_tx_cancel_wait)
|
||||
if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
|
||||
return -EINVAL;
|
||||
wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
|
||||
}
|
||||
@@ -5339,6 +5411,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
|
||||
|
||||
if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
|
||||
return -EINVAL;
|
||||
|
||||
no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
|
||||
|
||||
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
|
||||
|
@@ -1123,6 +1123,8 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,
|
||||
if (ignore_reg_update(wiphy, initiator))
|
||||
return;
|
||||
|
||||
last_request->dfs_region = cfg80211_regdomain->dfs_region;
|
||||
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
if (wiphy->bands[band])
|
||||
handle_band(wiphy, band, initiator);
|
||||
@@ -1948,6 +1950,42 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
|
||||
}
|
||||
}
|
||||
|
||||
bool reg_supported_dfs_region(u8 dfs_region)
|
||||
{
|
||||
switch (dfs_region) {
|
||||
case NL80211_DFS_UNSET:
|
||||
case NL80211_DFS_FCC:
|
||||
case NL80211_DFS_ETSI:
|
||||
case NL80211_DFS_JP:
|
||||
return true;
|
||||
default:
|
||||
REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n",
|
||||
dfs_region);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_dfs_region(u8 dfs_region)
|
||||
{
|
||||
if (!dfs_region)
|
||||
return;
|
||||
|
||||
switch (dfs_region) {
|
||||
case NL80211_DFS_FCC:
|
||||
pr_info(" DFS Master region FCC");
|
||||
break;
|
||||
case NL80211_DFS_ETSI:
|
||||
pr_info(" DFS Master region ETSI");
|
||||
break;
|
||||
case NL80211_DFS_JP:
|
||||
pr_info(" DFS Master region JP");
|
||||
break;
|
||||
default:
|
||||
pr_info(" DFS Master region Uknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_regdomain(const struct ieee80211_regdomain *rd)
|
||||
{
|
||||
|
||||
@@ -1975,6 +2013,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
|
||||
pr_info("Regulatory domain changed to country: %c%c\n",
|
||||
rd->alpha2[0], rd->alpha2[1]);
|
||||
}
|
||||
print_dfs_region(rd->dfs_region);
|
||||
print_rd_rules(rd);
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,7 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain;
|
||||
|
||||
bool is_world_regdom(const char *alpha2);
|
||||
bool reg_is_valid_request(const char *alpha2);
|
||||
bool reg_supported_dfs_region(u8 dfs_region);
|
||||
|
||||
int regulatory_hint_user(const char *alpha2);
|
||||
|
||||
|
@@ -190,7 +190,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
|
||||
prev_bssid,
|
||||
params->ssid, params->ssid_len,
|
||||
params->ie, params->ie_len,
|
||||
false, ¶ms->crypto);
|
||||
false, ¶ms->crypto,
|
||||
params->flags, ¶ms->ht_capa,
|
||||
¶ms->ht_capa_mask);
|
||||
if (err)
|
||||
__cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
|
||||
NULL, 0,
|
||||
@@ -774,6 +776,9 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
wdev->connect_keys = NULL;
|
||||
}
|
||||
|
||||
cfg80211_oper_and_ht_capa(&connect->ht_capa_mask,
|
||||
rdev->wiphy.ht_capa_mod_mask);
|
||||
|
||||
if (connkeys && connkeys->def >= 0) {
|
||||
int idx;
|
||||
u32 cipher;
|
||||
|
@@ -7,7 +7,6 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/ip.h>
|
||||
#include "core.h"
|
||||
@@ -240,17 +239,6 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
|
||||
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
||||
const unsigned char rfc1042_header[] __aligned(2) =
|
||||
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
||||
EXPORT_SYMBOL(rfc1042_header);
|
||||
|
||||
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
|
||||
const unsigned char bridge_tunnel_header[] __aligned(2) =
|
||||
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
|
||||
EXPORT_SYMBOL(bridge_tunnel_header);
|
||||
|
||||
unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc)
|
||||
{
|
||||
unsigned int hdrlen = 24;
|
||||
@@ -1051,169 +1039,13 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
u64 filter, u32 crc)
|
||||
{
|
||||
size_t left = len;
|
||||
u8 *pos = start;
|
||||
bool calc_crc = filter != 0;
|
||||
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
|
||||
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
||||
const unsigned char rfc1042_header[] __aligned(2) =
|
||||
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
||||
EXPORT_SYMBOL(rfc1042_header);
|
||||
|
||||
memset(elems, 0, sizeof(*elems));
|
||||
elems->ie_start = start;
|
||||
elems->total_len = len;
|
||||
|
||||
while (left >= 2) {
|
||||
u8 id, elen;
|
||||
|
||||
id = *pos++;
|
||||
elen = *pos++;
|
||||
left -= 2;
|
||||
|
||||
if (elen > left)
|
||||
break;
|
||||
|
||||
if (calc_crc && id < 64 && (filter & (1ULL << id)))
|
||||
crc = crc32_be(crc, pos - 2, elen + 2);
|
||||
|
||||
switch (id) {
|
||||
case WLAN_EID_SSID:
|
||||
elems->ssid = pos;
|
||||
elems->ssid_len = elen;
|
||||
break;
|
||||
case WLAN_EID_SUPP_RATES:
|
||||
elems->supp_rates = pos;
|
||||
elems->supp_rates_len = elen;
|
||||
break;
|
||||
case WLAN_EID_FH_PARAMS:
|
||||
elems->fh_params = pos;
|
||||
elems->fh_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_DS_PARAMS:
|
||||
elems->ds_params = pos;
|
||||
elems->ds_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_CF_PARAMS:
|
||||
elems->cf_params = pos;
|
||||
elems->cf_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_TIM:
|
||||
if (elen >= sizeof(struct ieee80211_tim_ie)) {
|
||||
elems->tim = (void *)pos;
|
||||
elems->tim_len = elen;
|
||||
}
|
||||
break;
|
||||
case WLAN_EID_IBSS_PARAMS:
|
||||
elems->ibss_params = pos;
|
||||
elems->ibss_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_CHALLENGE:
|
||||
elems->challenge = pos;
|
||||
elems->challenge_len = elen;
|
||||
break;
|
||||
case WLAN_EID_VENDOR_SPECIFIC:
|
||||
if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
|
||||
pos[2] == 0xf2) {
|
||||
/* Microsoft OUI (00:50:F2) */
|
||||
|
||||
if (calc_crc)
|
||||
crc = crc32_be(crc, pos - 2, elen + 2);
|
||||
|
||||
if (pos[3] == 1) {
|
||||
/* OUI Type 1 - WPA IE */
|
||||
elems->wpa = pos;
|
||||
elems->wpa_len = elen;
|
||||
} else if (elen >= 5 && pos[3] == 2) {
|
||||
/* OUI Type 2 - WMM IE */
|
||||
if (pos[4] == 0) {
|
||||
elems->wmm_info = pos;
|
||||
elems->wmm_info_len = elen;
|
||||
} else if (pos[4] == 1) {
|
||||
elems->wmm_param = pos;
|
||||
elems->wmm_param_len = elen;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WLAN_EID_RSN:
|
||||
elems->rsn = pos;
|
||||
elems->rsn_len = elen;
|
||||
break;
|
||||
case WLAN_EID_ERP_INFO:
|
||||
elems->erp_info = pos;
|
||||
elems->erp_info_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_SUPP_RATES:
|
||||
elems->ext_supp_rates = pos;
|
||||
elems->ext_supp_rates_len = elen;
|
||||
break;
|
||||
case WLAN_EID_HT_CAPABILITY:
|
||||
if (elen >= sizeof(struct ieee80211_ht_cap))
|
||||
elems->ht_cap_elem = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_HT_INFORMATION:
|
||||
if (elen >= sizeof(struct ieee80211_ht_info))
|
||||
elems->ht_info_elem = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_MESH_ID:
|
||||
elems->mesh_id = pos;
|
||||
elems->mesh_id_len = elen;
|
||||
break;
|
||||
case WLAN_EID_MESH_CONFIG:
|
||||
if (elen >= sizeof(struct ieee80211_meshconf_ie))
|
||||
elems->mesh_config = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_PEER_MGMT:
|
||||
elems->peering = pos;
|
||||
elems->peering_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PREQ:
|
||||
elems->preq = pos;
|
||||
elems->preq_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PREP:
|
||||
elems->prep = pos;
|
||||
elems->prep_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PERR:
|
||||
elems->perr = pos;
|
||||
elems->perr_len = elen;
|
||||
break;
|
||||
case WLAN_EID_RANN:
|
||||
if (elen >= sizeof(struct ieee80211_rann_ie))
|
||||
elems->rann = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_CHANNEL_SWITCH:
|
||||
elems->ch_switch_elem = pos;
|
||||
elems->ch_switch_elem_len = elen;
|
||||
break;
|
||||
case WLAN_EID_QUIET:
|
||||
if (!elems->quiet_elem) {
|
||||
elems->quiet_elem = pos;
|
||||
elems->quiet_elem_len = elen;
|
||||
}
|
||||
elems->num_of_quiet_elem++;
|
||||
break;
|
||||
case WLAN_EID_COUNTRY:
|
||||
elems->country_elem = pos;
|
||||
elems->country_elem_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PWR_CONSTRAINT:
|
||||
elems->pwr_constr_elem = pos;
|
||||
elems->pwr_constr_elem_len = elen;
|
||||
break;
|
||||
case WLAN_EID_TIMEOUT_INTERVAL:
|
||||
elems->timeout_int = pos;
|
||||
elems->timeout_int_len = elen;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
left -= elen;
|
||||
pos += elen;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee802_11_parse_elems_crc);
|
||||
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
|
||||
const unsigned char bridge_tunnel_header[] __aligned(2) =
|
||||
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
|
||||
EXPORT_SYMBOL(bridge_tunnel_header);
|
||||
|
Reference in New Issue
Block a user