diff options
Diffstat (limited to 'net/mac80211/ht.c')
-rw-r--r-- | net/mac80211/ht.c | 181 |
1 files changed, 75 insertions, 106 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index e2d121b..42c3e59 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -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 |