|
@@ -20,114 +20,38 @@
|
|
|
#include "sta_info.h"
|
|
|
#include "wme.h"
|
|
|
|
|
|
-void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie,
|
|
|
+void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
|
|
|
+ struct ieee80211_ht_cap *ht_cap_ie,
|
|
|
struct ieee80211_sta_ht_cap *ht_cap)
|
|
|
{
|
|
|
+ u8 ampdu_info, tx_mcs_set_cap;
|
|
|
+ int i, max_tx_streams;
|
|
|
|
|
|
BUG_ON(!ht_cap);
|
|
|
|
|
|
memset(ht_cap, 0, sizeof(*ht_cap));
|
|
|
|
|
|
- if (ht_cap_ie) {
|
|
|
- u8 ampdu_info = ht_cap_ie->ampdu_params_info;
|
|
|
-
|
|
|
- ht_cap->ht_supported = true;
|
|
|
- ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info);
|
|
|
- ht_cap->ampdu_factor =
|
|
|
- ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
|
|
|
- ht_cap->ampdu_density =
|
|
|
- (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
|
|
|
- memcpy(&ht_cap->mcs, &ht_cap_ie->mcs, sizeof(ht_cap->mcs));
|
|
|
- } else
|
|
|
- ht_cap->ht_supported = false;
|
|
|
-}
|
|
|
-
|
|
|
-void ieee80211_ht_info_ie_to_ht_bss_info(
|
|
|
- struct ieee80211_ht_info *ht_add_info_ie,
|
|
|
- struct ieee80211_ht_bss_info *bss_info)
|
|
|
-{
|
|
|
- BUG_ON(!bss_info);
|
|
|
-
|
|
|
- memset(bss_info, 0, sizeof(*bss_info));
|
|
|
-
|
|
|
- if (ht_add_info_ie) {
|
|
|
- u16 op_mode;
|
|
|
- op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
|
|
|
-
|
|
|
- bss_info->primary_channel = ht_add_info_ie->control_chan;
|
|
|
- bss_info->bss_cap = ht_add_info_ie->ht_param;
|
|
|
- bss_info->bss_op_mode = (u8)(op_mode & 0xff);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * ieee80211_handle_ht should be called only after the operating band
|
|
|
- * has been determined as ht configuration depends on the hw's
|
|
|
- * HT abilities for a specific band.
|
|
|
- */
|
|
|
-u32 ieee80211_handle_ht(struct ieee80211_local *local,
|
|
|
- struct ieee80211_sta_ht_cap *req_ht_cap,
|
|
|
- struct ieee80211_ht_bss_info *req_bss_cap)
|
|
|
-{
|
|
|
- struct ieee80211_conf *conf = &local->hw.conf;
|
|
|
- struct ieee80211_supported_band *sband;
|
|
|
- struct ieee80211_sta_ht_cap ht_cap;
|
|
|
- struct ieee80211_ht_bss_info ht_bss_conf;
|
|
|
- u32 changed = 0;
|
|
|
- int i;
|
|
|
- u8 max_tx_streams;
|
|
|
- u8 tx_mcs_set_cap;
|
|
|
- bool enable_ht = true;
|
|
|
-
|
|
|
- sband = local->hw.wiphy->bands[conf->channel->band];
|
|
|
-
|
|
|
- memset(&ht_cap, 0, sizeof(ht_cap));
|
|
|
- memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
|
|
|
-
|
|
|
- /* HT is not supported */
|
|
|
- if (!sband->ht_cap.ht_supported)
|
|
|
- enable_ht = false;
|
|
|
-
|
|
|
- /* disable HT */
|
|
|
- if (!enable_ht) {
|
|
|
- if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
|
|
|
- changed |= BSS_CHANGED_HT;
|
|
|
- conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
|
|
|
- conf->ht_cap.ht_supported = false;
|
|
|
- return changed;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
|
|
|
- changed |= BSS_CHANGED_HT;
|
|
|
-
|
|
|
- conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
|
|
|
- ht_cap.ht_supported = true;
|
|
|
+ if (!ht_cap_ie)
|
|
|
+ return;
|
|
|
|
|
|
- ht_cap.cap = req_ht_cap->cap & sband->ht_cap.cap;
|
|
|
- ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS;
|
|
|
- ht_cap.cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
|
|
|
+ ht_cap->ht_supported = true;
|
|
|
|
|
|
- ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
|
|
|
- ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
|
|
|
- ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
|
|
|
+ ht_cap->cap = ht_cap->cap & sband->ht_cap.cap;
|
|
|
+ ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS;
|
|
|
+ ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
|
|
|
|
|
|
- ht_cap.ampdu_factor = req_ht_cap->ampdu_factor;
|
|
|
- ht_cap.ampdu_density = req_ht_cap->ampdu_density;
|
|
|
+ ampdu_info = ht_cap_ie->ampdu_params_info;
|
|
|
+ ht_cap->ampdu_factor =
|
|
|
+ ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
|
|
|
+ ht_cap->ampdu_density =
|
|
|
+ (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
|
|
|
|
|
|
/* own MCS TX capabilities */
|
|
|
tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
|
|
|
|
|
|
- /*
|
|
|
- * configure supported Tx MCS according to requested MCS
|
|
|
- * (based in most cases on Rx capabilities of peer) and self
|
|
|
- * Tx MCS capabilities (as defined by low level driver HW
|
|
|
- * Tx capabilities)
|
|
|
- */
|
|
|
-
|
|
|
/* can we TX with MCS rates? */
|
|
|
if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
|
|
|
- goto check_changed;
|
|
|
+ return;
|
|
|
|
|
|
/* Counting from 0, therefore +1 */
|
|
|
if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
|
|
@@ -145,29 +69,73 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local,
|
|
|
* - remainder are multiple spatial streams using unequal modulation
|
|
|
*/
|
|
|
for (i = 0; i < max_tx_streams; i++)
|
|
|
- ht_cap.mcs.rx_mask[i] =
|
|
|
- sband->ht_cap.mcs.rx_mask[i] &
|
|
|
- req_ht_cap->mcs.rx_mask[i];
|
|
|
+ ht_cap->mcs.rx_mask[i] =
|
|
|
+ sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
|
|
|
|
|
|
if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
|
|
|
for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
|
|
|
i < IEEE80211_HT_MCS_MASK_LEN; i++)
|
|
|
- ht_cap.mcs.rx_mask[i] =
|
|
|
+ ht_cap->mcs.rx_mask[i] =
|
|
|
sband->ht_cap.mcs.rx_mask[i] &
|
|
|
- req_ht_cap->mcs.rx_mask[i];
|
|
|
+ ht_cap_ie->mcs.rx_mask[i];
|
|
|
|
|
|
/* handle MCS rate 32 too */
|
|
|
- if (sband->ht_cap.mcs.rx_mask[32/8] &
|
|
|
- req_ht_cap->mcs.rx_mask[32/8] & 1)
|
|
|
- ht_cap.mcs.rx_mask[32/8] |= 1;
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * ieee80211_enable_ht should be called only after the operating band
|
|
|
+ * has been determined as ht configuration depends on the hw's
|
|
|
+ * HT abilities for a specific band.
|
|
|
+ */
|
|
|
+u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
|
|
|
+ struct ieee80211_ht_info *hti,
|
|
|
+ u16 ap_ht_cap_flags)
|
|
|
+{
|
|
|
+ struct ieee80211_local *local = sdata->local;
|
|
|
+ struct ieee80211_supported_band *sband;
|
|
|
+ struct ieee80211_bss_ht_conf ht;
|
|
|
+ u32 changed = 0;
|
|
|
+ bool enable_ht = true, ht_changed;
|
|
|
+
|
|
|
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
|
|
+
|
|
|
+ memset(&ht, 0, sizeof(ht));
|
|
|
+
|
|
|
+ /* HT is not supported */
|
|
|
+ if (!sband->ht_cap.ht_supported)
|
|
|
+ enable_ht = false;
|
|
|
+
|
|
|
+ /* check that channel matches the right operating channel */
|
|
|
+ if (local->hw.conf.channel->center_freq !=
|
|
|
+ ieee80211_channel_to_frequency(hti->control_chan))
|
|
|
+ enable_ht = false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * XXX: This is totally incorrect when there are multiple virtual
|
|
|
+ * interfaces, needs to be fixed later.
|
|
|
+ */
|
|
|
+ ht_changed = local->hw.conf.ht.enabled != enable_ht;
|
|
|
+ local->hw.conf.ht.enabled = enable_ht;
|
|
|
+ if (ht_changed)
|
|
|
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
|
|
|
+
|
|
|
+ /* disable HT */
|
|
|
+ if (!enable_ht)
|
|
|
+ return 0;
|
|
|
+ ht.secondary_channel_offset =
|
|
|
+ hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
|
|
|
+ ht.width_40_ok =
|
|
|
+ !(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
|
|
|
+ (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
|
|
|
+ (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY);
|
|
|
+ ht.operation_mode = le16_to_cpu(hti->operation_mode);
|
|
|
|
|
|
- check_changed:
|
|
|
/* if bss configuration changed store the new one */
|
|
|
- if (memcmp(&conf->ht_cap, &ht_cap, sizeof(ht_cap)) ||
|
|
|
- memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
|
|
|
+ if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) {
|
|
|
changed |= BSS_CHANGED_HT;
|
|
|
- memcpy(&conf->ht_cap, &ht_cap, sizeof(ht_cap));
|
|
|
- memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
|
|
|
+ sdata->vif.bss_conf.ht = ht;
|
|
|
}
|
|
|
|
|
|
return changed;
|
|
@@ -900,8 +868,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|
|
/* sanity check for incoming parameters:
|
|
|
* check if configuration can support the BA policy
|
|
|
* and if buffer size does not exceeds max value */
|
|
|
+ /* XXX: check own ht delayed BA capability?? */
|
|
|
if (((ba_policy != 1)
|
|
|
- && (!(conf->ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
|
|
|
+ && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
|
|
|
|| (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
|
|
|
status = WLAN_STATUS_INVALID_QOS_PARAM;
|
|
|
#ifdef CONFIG_MAC80211_HT_DEBUG
|