aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2012-03-16 13:45:25 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-03-16 13:45:25 -0400
commit01a282980937f9ca55a3cb06b9c6ff1cc49ea396 (patch)
tree07a043edc861e245a7a9764751af0898a1f1199a /net
parentd5ddb4a59ed43b4c569b4efa8b508d50ef140cc6 (diff)
parent377526578f2c343ea281a918b18ece1fca65005c (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts: drivers/net/wireless/ath/ath9k/hw.c
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/chan.c27
-rw-r--r--net/mac80211/debugfs.c81
-rw-r--r--net/mac80211/debugfs_netdev.c71
-rw-r--r--net/mac80211/driver-ops.h35
-rw-r--r--net/mac80211/driver-trace.h45
-rw-r--r--net/mac80211/ieee80211_i.h34
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/mlme.c382
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c16
-rw-r--r--net/mac80211/rx.c21
-rw-r--r--net/mac80211/tx.c10
-rw-r--r--net/mac80211/wep.c21
-rw-r--r--net/mac80211/wep.h1
-rw-r--r--net/mac80211/wpa.c22
-rw-r--r--net/wireless/nl80211.c8
-rw-r--r--net/wireless/scan.c7
-rw-r--r--net/wireless/wext-sme.c3
17 files changed, 355 insertions, 431 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index d1f7abddb18..e00ce8c3e28 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -3,6 +3,7 @@
*/
#include <linux/nl80211.h>
+#include <net/cfg80211.h>
#include "ieee80211_i.h"
static enum ieee80211_chan_mode
@@ -134,3 +135,29 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,
return result;
}
+
+/*
+ * ieee80211_get_tx_channel_type returns the channel type we should
+ * use for packet transmission, given the channel capability and
+ * whatever regulatory flags we have been given.
+ */
+enum nl80211_channel_type ieee80211_get_tx_channel_type(
+ struct ieee80211_local *local,
+ enum nl80211_channel_type channel_type)
+{
+ switch (channel_type) {
+ case NL80211_CHAN_HT40PLUS:
+ if (local->hw.conf.channel->flags &
+ IEEE80211_CHAN_NO_HT40PLUS)
+ return NL80211_CHAN_HT20;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ if (local->hw.conf.channel->flags &
+ IEEE80211_CHAN_NO_HT40MINUS)
+ return NL80211_CHAN_HT20;
+ break;
+ default:
+ break;
+ }
+ return channel_type;
+}
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 483e96ed95c..cc5b7a6e7e0 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -97,85 +97,6 @@ static const struct file_operations reset_ops = {
.llseek = noop_llseek,
};
-static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- return mac80211_format_buffer(user_buf, count, ppos, "0x%x\n",
- local->uapsd_queues);
-}
-
-static ssize_t uapsd_queues_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- u8 val;
- int ret;
-
- ret = kstrtou8_from_user(user_buf, count, 0, &val);
- if (ret)
- return ret;
-
- if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
- return -ERANGE;
-
- local->uapsd_queues = val;
-
- return count;
-}
-
-static const struct file_operations uapsd_queues_ops = {
- .read = uapsd_queues_read,
- .write = uapsd_queues_write,
- .open = mac80211_open_file_generic,
- .llseek = default_llseek,
-};
-
-static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
-
- return mac80211_format_buffer(user_buf, count, ppos, "0x%x\n",
- local->uapsd_max_sp_len);
-}
-
-static ssize_t uapsd_max_sp_len_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- unsigned long val;
- char buf[10];
- size_t len;
- int ret;
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
-
- ret = kstrtoul(buf, 0, &val);
-
- if (ret)
- return -EINVAL;
-
- if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
- return -ERANGE;
-
- local->uapsd_max_sp_len = val;
-
- return count;
-}
-
-static const struct file_operations uapsd_max_sp_len_ops = {
- .read = uapsd_max_sp_len_read,
- .write = uapsd_max_sp_len_write,
- .open = mac80211_open_file_generic,
- .llseek = default_llseek,
-};
-
static ssize_t channel_type_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -362,8 +283,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(queues);
DEBUGFS_ADD_MODE(reset, 0200);
- DEBUGFS_ADD(uapsd_queues);
- DEBUGFS_ADD(uapsd_max_sp_len);
DEBUGFS_ADD(channel_type);
DEBUGFS_ADD(hwflags);
DEBUGFS_ADD(user_power);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index f6de8a65f40..a32eeda04aa 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -49,16 +49,15 @@ static ssize_t ieee80211_if_write(
size_t count, loff_t *ppos,
ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
{
- u8 *buf;
+ char buf[64];
ssize_t ret;
- buf = kmalloc(count, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ if (count >= sizeof(buf))
+ return -E2BIG;
- ret = -EFAULT;
if (copy_from_user(buf, userbuf, count))
- goto freebuf;
+ return -EFAULT;
+ buf[count] = '\0';
ret = -ENODEV;
rtnl_lock();
@@ -66,8 +65,6 @@ static ssize_t ieee80211_if_write(
ret = (*write)(sdata, buf, count);
rtnl_unlock();
-freebuf:
- kfree(buf);
return ret;
}
@@ -340,6 +337,62 @@ static ssize_t ieee80211_if_parse_tkip_mic_test(
__IEEE80211_IF_FILE_W(tkip_mic_test);
+static ssize_t ieee80211_if_fmt_uapsd_queues(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_queues);
+}
+
+static ssize_t ieee80211_if_parse_uapsd_queues(
+ struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
+{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ u8 val;
+ int ret;
+
+ ret = kstrtou8(buf, 0, &val);
+ if (ret)
+ return ret;
+
+ if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
+ return -ERANGE;
+
+ ifmgd->uapsd_queues = val;
+
+ return buflen;
+}
+__IEEE80211_IF_FILE_W(uapsd_queues);
+
+static ssize_t ieee80211_if_fmt_uapsd_max_sp_len(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ return snprintf(buf, buflen, "0x%x\n", ifmgd->uapsd_max_sp_len);
+}
+
+static ssize_t ieee80211_if_parse_uapsd_max_sp_len(
+ struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
+{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return -EINVAL;
+
+ if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
+ return -ERANGE;
+
+ ifmgd->uapsd_max_sp_len = val;
+
+ return buflen;
+}
+__IEEE80211_IF_FILE_W(uapsd_max_sp_len);
+
/* AP attributes */
IEEE80211_IF_FILE(num_sta_authorized, u.ap.num_sta_authorized, ATOMIC);
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
@@ -472,6 +525,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(ave_beacon);
DEBUGFS_ADD_MODE(smps, 0600);
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
+ DEBUGFS_ADD_MODE(uapsd_queues, 0600);
+ DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600);
}
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 70dfb6415c2..af4691fed64 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -168,41 +168,6 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
trace_drv_return_void(local);
}
-static inline int drv_tx_sync(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- const u8 *bssid,
- enum ieee80211_tx_sync_type type)
-{
- int ret = 0;
-
- might_sleep();
-
- check_sdata_in_driver(sdata);
-
- trace_drv_tx_sync(local, sdata, bssid, type);
- if (local->ops->tx_sync)
- ret = local->ops->tx_sync(&local->hw, &sdata->vif,
- bssid, type);
- trace_drv_return_int(local, ret);
- return ret;
-}
-
-static inline void drv_finish_tx_sync(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- const u8 *bssid,
- enum ieee80211_tx_sync_type type)
-{
- might_sleep();
-
- check_sdata_in_driver(sdata);
-
- trace_drv_finish_tx_sync(local, sdata, bssid, type);
- if (local->ops->finish_tx_sync)
- local->ops->finish_tx_sync(&local->hw, &sdata->vif,
- bssid, type);
- trace_drv_return_void(local);
-}
-
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
struct netdev_hw_addr_list *mc_list)
{
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 384e2f08c18..21d6f5290a1 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -296,7 +296,7 @@ TRACE_EVENT(drv_bss_info_changed,
__entry->dtimper = info->dtim_period;
__entry->bcnint = info->beacon_int;
__entry->assoc_cap = info->assoc_capability;
- __entry->timestamp = info->timestamp;
+ __entry->timestamp = info->last_tsf;
__entry->basic_rates = info->basic_rates;
__entry->enable_beacon = info->enable_beacon;
__entry->ht_operation_mode = info->ht_operation_mode;
@@ -308,49 +308,6 @@ TRACE_EVENT(drv_bss_info_changed,
)
);
-DECLARE_EVENT_CLASS(tx_sync_evt,
- TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- const u8 *bssid,
- enum ieee80211_tx_sync_type type),
- TP_ARGS(local, sdata, bssid, type),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- VIF_ENTRY
- __array(char, bssid, ETH_ALEN)
- __field(u32, sync_type)
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- VIF_ASSIGN;
- memcpy(__entry->bssid, bssid, ETH_ALEN);
- __entry->sync_type = type;
- ),
-
- TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " bssid:%pM type:%d",
- LOCAL_PR_ARG, VIF_PR_ARG, __entry->bssid, __entry->sync_type
- )
-);
-
-DEFINE_EVENT(tx_sync_evt, drv_tx_sync,
- TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- const u8 *bssid,
- enum ieee80211_tx_sync_type type),
- TP_ARGS(local, sdata, bssid, type)
-);
-
-DEFINE_EVENT(tx_sync_evt, drv_finish_tx_sync,
- TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- const u8 *bssid,
- enum ieee80211_tx_sync_type type),
- TP_ARGS(local, sdata, bssid, type)
-);
-
TRACE_EVENT(drv_prepare_multicast,
TP_PROTO(struct ieee80211_local *local, int mc_count),
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 796b13bfc95..d9798a307f2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -388,7 +388,6 @@ struct ieee80211_mgd_auth_data {
u8 key[WLAN_KEY_LEN_WEP104];
u8 key_len, key_idx;
- bool synced;
bool done;
size_t ie_len;
@@ -408,7 +407,7 @@ struct ieee80211_mgd_assoc_data {
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len;
u8 supp_rates_len;
- bool wmm_used, uapsd_used;
+ bool wmm, uapsd;
bool have_beacon;
bool sent_assoc;
bool synced;
@@ -460,6 +459,20 @@ struct ieee80211_if_managed {
IEEE80211_MFP_REQUIRED
} mfp; /* management frame protection */
+ /*
+ * Bitmask of enabled u-apsd queues,
+ * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association
+ * to take effect.
+ */
+ unsigned int uapsd_queues;
+
+ /*
+ * Maximum number of buffered frames AP can deliver during a
+ * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar.
+ * Needs a new association to take effect.
+ */
+ unsigned int uapsd_max_sp_len;
+
int wmm_last_param_set;
u8 use_4addr;
@@ -1018,20 +1031,6 @@ struct ieee80211_local {
*/
unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
- /*
- * Bitmask of enabled u-apsd queues,
- * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association
- * to take effect.
- */
- unsigned int uapsd_queues;
-
- /*
- * Maximum number of buffered frames AP can deliver during a
- * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar.
- * Needs a new association to take effect.
- */
- unsigned int uapsd_max_sp_len;
-
bool pspolling;
bool offchannel_ps_enabled;
/*
@@ -1503,6 +1502,9 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local,
enum nl80211_channel_type chantype);
enum nl80211_channel_type
ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info);
+enum nl80211_channel_type ieee80211_get_tx_channel_type(
+ struct ieee80211_local *local,
+ enum nl80211_channel_type channel_type);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 36fa8051296..b581a24fa15 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -595,8 +595,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
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);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c08924aeac0..576fb25456d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -189,40 +189,35 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
u16 ht_opmode;
bool enable_ht = true;
enum nl80211_channel_type prev_chantype;
- enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+ enum nl80211_channel_type rx_channel_type = NL80211_CHAN_NO_HT;
+ enum nl80211_channel_type tx_channel_type;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
prev_chantype = sdata->vif.bss_conf.channel_type;
- /* HT is not supported */
- if (!sband->ht_cap.ht_supported)
- enable_ht = false;
- if (enable_ht) {
- hti_cfreq = ieee80211_channel_to_frequency(hti->control_chan,
- sband->band);
- /* check that channel matches the right operating channel */
- if (local->hw.conf.channel->center_freq != hti_cfreq) {
- /* Some APs mess this up, evidently.
- * Netgear WNDR3700 sometimes reports 4 higher than
- * the actual channel, for instance.
- */
- printk(KERN_DEBUG
- "%s: Wrong control channel in association"
- " response: configured center-freq: %d"
- " hti-cfreq: %d hti->control_chan: %d"
- " band: %d. Disabling HT.\n",
- sdata->name,
- local->hw.conf.channel->center_freq,
- hti_cfreq, hti->control_chan,
- sband->band);
- enable_ht = false;
- }
+ hti_cfreq = ieee80211_channel_to_frequency(hti->control_chan,
+ sband->band);
+ /* check that channel matches the right operating channel */
+ if (local->hw.conf.channel->center_freq != hti_cfreq) {
+ /* Some APs mess this up, evidently.
+ * Netgear WNDR3700 sometimes reports 4 higher than
+ * the actual channel, for instance.
+ */
+ printk(KERN_DEBUG
+ "%s: Wrong control channel in association"
+ " response: configured center-freq: %d"
+ " hti-cfreq: %d hti->control_chan: %d"
+ " band: %d. Disabling HT.\n",
+ sdata->name,
+ local->hw.conf.channel->center_freq,
+ hti_cfreq, hti->control_chan,
+ sband->band);
+ enable_ht = false;
}
if (enable_ht) {
- channel_type = NL80211_CHAN_HT20;
+ rx_channel_type = NL80211_CHAN_HT20;
if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
!ieee80111_cfg_override_disables_ht40(sdata) &&
@@ -230,29 +225,28 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
(hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- if (!(local->hw.conf.channel->flags &
- IEEE80211_CHAN_NO_HT40PLUS))
- channel_type = NL80211_CHAN_HT40PLUS;
+ rx_channel_type = NL80211_CHAN_HT40PLUS;
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- if (!(local->hw.conf.channel->flags &
- IEEE80211_CHAN_NO_HT40MINUS))
- channel_type = NL80211_CHAN_HT40MINUS;
+ rx_channel_type = NL80211_CHAN_HT40MINUS;
break;
}
}
}
+ tx_channel_type = ieee80211_get_tx_channel_type(local, rx_channel_type);
+
if (local->tmp_channel)
- local->tmp_channel_type = channel_type;
+ local->tmp_channel_type = rx_channel_type;
- if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
+ if (!ieee80211_set_channel_type(local, sdata, rx_channel_type)) {
/* can only fail due to HT40+/- mismatch */
- channel_type = NL80211_CHAN_HT20;
- WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
+ rx_channel_type = NL80211_CHAN_HT20;
+ WARN_ON(!ieee80211_set_channel_type(local, sdata,
+ rx_channel_type));
}
- if (beacon_htcap_ie && (prev_chantype != channel_type)) {
+ if (beacon_htcap_ie && (prev_chantype != rx_channel_type)) {
/*
* Whenever the AP announces the HT mode change that can be
* 40MHz intolerant or etc., it would be safer to stop tx
@@ -270,13 +264,13 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
/* channel_type change automatically detected */
ieee80211_hw_config(local, 0);
- if (prev_chantype != channel_type) {
+ if (prev_chantype != tx_channel_type) {
rcu_read_lock();
sta = sta_info_get(sdata, bssid);
if (sta)
rate_control_rate_update(local, sband, sta,
IEEE80211_RC_HT_CHANGED,
- channel_type);
+ tx_channel_type);
rcu_read_unlock();
if (beacon_htcap_ie)
@@ -289,7 +283,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
/* if bss configuration changed store the new one */
if (sdata->ht_opmode_valid != enable_ht ||
sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
- prev_chantype != channel_type) {
+ prev_chantype != rx_channel_type) {
changed |= BSS_CHANGED_HT;
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
sdata->ht_opmode_valid = enable_ht;
@@ -335,9 +329,6 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
- if (!sband->ht_cap.ht_supported)
- return;
-
if (!ht_info_ie)
return;
@@ -405,7 +396,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
u16 capab;
struct ieee80211_supported_band *sband;
u32 rates = 0;
- struct ieee80211_bss *bss = (void *)assoc_data->bss->priv;
lockdep_assert_held(&ifmgd->mtx);
@@ -566,8 +556,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
offset = noffset;
}
- if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N) &&
- bss->wmm_used && local->hw.queues >= 4)
+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_information_ie,
sband, local->oper_channel, ifmgd->ap_smps);
@@ -581,10 +570,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
offset = noffset;
}
- if (assoc_data->wmm_used && local->hw.queues >= 4) {
- if (assoc_data->uapsd_used) {
- qos_info = local->uapsd_queues;
- qos_info |= (local->uapsd_max_sp_len <<
+ if (assoc_data->wmm) {
+ if (assoc_data->uapsd) {
+ qos_info = ifmgd->uapsd_queues;
+ qos_info |= (ifmgd->uapsd_max_sp_len <<
IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT);
} else {
qos_info = 0;
@@ -1203,7 +1192,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
return;
if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
- uapsd_queues = local->uapsd_queues;
+ uapsd_queues = ifmgd->uapsd_queues;
count = wmm_param[6] & 0x0f;
if (count == ifmgd->wmm_last_param_set)
@@ -1329,7 +1318,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
bss_info_changed |= BSS_CHANGED_ASSOC;
/* set timing information */
bss_conf->beacon_int = cbss->beacon_interval;
- bss_conf->timestamp = cbss->tsf;
+ bss_conf->last_tsf = cbss->tsf;
bss_info_changed |= BSS_CHANGED_BEACON_INT;
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
@@ -1355,15 +1344,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
bss_conf->dtim_period = 0;
bss_conf->assoc = 1;
- /*
- * For now just always ask the driver to update the basic rateset
- * when we have associated, we aren't checking whether it actually
- * changed or not.
- */
- bss_info_changed |= BSS_CHANGED_BASIC_RATES;
-
- /* And the BSSID changed - we're associated now */
- bss_info_changed |= BSS_CHANGED_BSSID;
/* Tell the driver to monitor connection quality (if supported) */
if (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI &&
@@ -1394,7 +1374,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- u32 changed = 0, config_changed = 0;
+ u32 changed = 0;
u8 bssid[ETH_ALEN];
ASSERT_MGD_MTX(ifmgd);
@@ -1454,9 +1434,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_ASSOC;
sdata->vif.bss_conf.assoc = false;
- /* channel(_type) changes are handled by ieee80211_hw_config */
- WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
-
/* on the next assoc, re-program HT parameters */
sdata->ht_opmode_valid = false;
memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
@@ -1469,12 +1446,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
- config_changed |= IEEE80211_CONF_CHANGE_PS;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
local->ps_sdata = NULL;
- ieee80211_hw_config(local, config_changed);
-
/* Disable ARP filtering */
if (sdata->vif.bss_conf.arp_filter_enabled) {
sdata->vif.bss_conf.arp_filter_enabled = false;
@@ -1488,6 +1463,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);
+ /* channel(_type) changes are handled by ieee80211_hw_config */
+ WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
+ ieee80211_hw_config(local, 0);
+
/* disassociated - set to defaults now */
ieee80211_set_wmm_default(sdata, false);
@@ -1770,11 +1749,6 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
lockdep_assert_held(&sdata->u.mgd.mtx);
- if (auth_data->synced)
- drv_finish_tx_sync(sdata->local, sdata,
- auth_data->bss->bssid,
- IEEE80211_TX_SYNC_AUTH);
-
if (!assoc) {
sta_info_destroy_addr(sdata, auth_data->bss->bssid);
@@ -1862,10 +1836,6 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
printk(KERN_DEBUG "%s: authenticated\n", sdata->name);
out:
- if (ifmgd->auth_data->synced)
- drv_finish_tx_sync(sdata->local, sdata, bssid,
- IEEE80211_TX_SYNC_AUTH);
- ifmgd->auth_data->synced = false;
ifmgd->auth_data->done = true;
ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
run_again(ifmgd, ifmgd->auth_data->timeout);
@@ -2005,11 +1975,6 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
lockdep_assert_held(&sdata->u.mgd.mtx);
- if (assoc_data->synced)
- drv_finish_tx_sync(sdata->local, sdata,
- assoc_data->bss->bssid,
- IEEE80211_TX_SYNC_ASSOC);
-
if (!assoc) {
sta_info_destroy_addr(sdata, assoc_data->bss->bssid);
@@ -2030,15 +1995,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband;
struct sta_info *sta;
u8 *pos;
- u32 rates, basic_rates;
u16 capab_info, aid;
struct ieee802_11_elems elems;
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
u32 changed = 0;
int err;
- bool have_higher_than_11mbit = false;
u16 ap_ht_cap_flags;
- int min_rate = INT_MAX, min_rate_index = -1;
/* AssocResp and ReassocResp have identical structure */
@@ -2083,39 +2045,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
return false;
}
- rates = 0;
- basic_rates = 0;
sband = local->hw.wiphy->bands[local->oper_channel->band];
- ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len,
- &rates, &basic_rates, &have_higher_than_11mbit,
- &min_rate, &min_rate_index);
-
- ieee80211_get_rates(sband, elems.ext_supp_rates,
- elems.ext_supp_rates_len, &rates, &basic_rates,
- &have_higher_than_11mbit,
- &min_rate, &min_rate_index);
-
- /*
- * some buggy APs don't advertise basic_rates. use the lowest
- * supported rate instead.
- */
- if (unlikely(!basic_rates) && min_rate_index >= 0) {
- printk(KERN_DEBUG "%s: No basic rates in AssocResp. "
- "Using min supported rate instead.\n", sdata->name);
- basic_rates = BIT(min_rate_index);
- }
-
- sta->sta.supp_rates[local->oper_channel->band] = rates;
- sdata->vif.bss_conf.basic_rates = basic_rates;
-
- /* cf. IEEE 802.11 9.2.12 */
- if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
- have_higher_than_11mbit)
- sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
- else
- 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(sdata, sband,
elems.ht_cap_elem, &sta->sta.ht_cap);
@@ -2162,7 +2093,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_QOS;
if (elems.ht_info_elem && elems.wmm_param &&
- (sdata->local->hw.queues >= 4) &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
cbss->bssid, ap_ht_cap_flags,
@@ -2255,14 +2185,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
} else {
printk(KERN_DEBUG "%s: associated\n", sdata->name);
- /* tell driver about sync done first */
- if (assoc_data->synced) {
- drv_finish_tx_sync(sdata->local, sdata,
- assoc_data->bss->bssid,
- IEEE80211_TX_SYNC_ASSOC);
- assoc_data->synced = false;
- }
-
if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
/* oops -- internal error -- send timeout for now */
ieee80211_destroy_assoc_data(sdata, true);
@@ -2747,14 +2669,6 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
if (WARN_ON_ONCE(!auth_data))
return -EINVAL;
- if (!auth_data->synced) {
- int ret = drv_tx_sync(local, sdata, auth_data->bss->bssid,
- IEEE80211_TX_SYNC_AUTH);
- if (ret)
- return ret;
- }
- auth_data->synced = true;
-
auth_data->tries++;
if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
@@ -2811,14 +2725,6 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
lockdep_assert_held(&sdata->u.mgd.mtx);
- if (!assoc_data->synced) {
- int ret = drv_tx_sync(local, sdata, assoc_data->bss->bssid,
- IEEE80211_TX_SYNC_ASSOC);
- if (ret)
- return ret;
- }
- assoc_data->synced = true;
-
assoc_data->tries++;
if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) {
printk(KERN_DEBUG "%s: association with %pM timed out\n",
@@ -3107,6 +3013,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ifmgd->flags = 0;
ifmgd->powersave = sdata->wdev.ps;
+ ifmgd->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
+ ifmgd->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
mutex_init(&ifmgd->mtx);
@@ -3143,6 +3051,101 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
return 0;
}
+static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_bss *cbss, bool assoc)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_bss *bss = (void *)cbss->priv;
+ struct sta_info *sta;
+ bool have_sta = false;
+ int err;
+
+ if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
+ return -EINVAL;
+
+ if (assoc) {
+ rcu_read_lock();
+ have_sta = sta_info_get(sdata, cbss->bssid);
+ rcu_read_unlock();
+ }
+
+ if (!have_sta) {
+ sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
+ }
+
+ mutex_lock(&local->mtx);
+ ieee80211_recalc_idle(sdata->local);
+ mutex_unlock(&local->mtx);
+
+ /* switch to the right channel */
+ local->oper_channel = cbss->channel;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+
+ if (!have_sta) {
+ struct ieee80211_supported_band *sband;
+ u32 rates = 0, basic_rates = 0;
+ bool have_higher_than_11mbit;
+ int min_rate = INT_MAX, min_rate_index = -1;
+
+ sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
+
+ ieee80211_get_rates(sband, bss->supp_rates,
+ bss->supp_rates_len,
+ &rates, &basic_rates,
+ &have_higher_than_11mbit,
+ &min_rate, &min_rate_index);
+
+ /*
+ * This used to be a workaround for basic rates missing
+ * in the association response frame. Now that we no
+ * longer use the basic rates from there, it probably
+ * doesn't happen any more, but keep the workaround so
+ * in case some *other* APs are buggy in different ways
+ * we can connect -- with a warning.
+ */
+ if (!basic_rates && min_rate_index >= 0) {
+ printk(KERN_DEBUG
+ "%s: No basic rates, using min rate instead.\n",
+ sdata->name);
+ basic_rates = BIT(min_rate_index);
+ }
+
+ sta->sta.supp_rates[cbss->channel->band] = rates;
+ sdata->vif.bss_conf.basic_rates = basic_rates;
+
+ /* cf. IEEE 802.11 9.2.12 */
+ if (local->oper_channel->band == IEEE80211_BAND_2GHZ &&
+ have_higher_than_11mbit)
+ sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+ else
+ sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+
+ memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN);
+
+ /* tell driver about BSSID and basic rates */
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES);
+
+ if (assoc)
+ sta_info_pre_mov