Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef96a842 authored by Ben Greear's avatar Ben Greear Committed by John W. Linville
Browse files

mac80211: Support ht-cap over-rides.



This implements ht-cap over-rides for mac80211 drivers.
HT may be disabled, making an /a/b/g/n station act like an
a/b/g station.  HT40 may be disabled forcing the station to
be HT20 even if the AP and local hardware support HT40.

MAX-AMSDU may be disabled.
AMPDU-Density may be increased.
AMPDU-Factor may be decreased.

This has been successfully tested with ath9k using patched
wpa_supplicant and iw.

Signed-off-by: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 7e7c8926
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);

+82 −1
Original line number Diff line number Diff line
@@ -18,7 +18,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)
{
@@ -102,6 +177,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)
+9 −2
Original line number Diff line number Diff line
@@ -449,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 {
@@ -1252,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,
@@ -1407,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,
+14 −0
Original line number Diff line number Diff line
@@ -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)
{
@@ -631,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);

+1 −1
Original line number Diff line number Diff line
@@ -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;
}
Loading