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

Commit 1d8d3dec authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

mac80211: handle SMPS action frames



When a peer changes SMPS state we should update
rate control so it doesn't have to detect it by
itself. It can't detect "dynamic" mode anyway
since that just requires rts-cts handshaking.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 645d3590
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -3502,9 +3502,12 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn);
 *
 * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have
 *	changed, rate control algorithm can update its internal state if needed.
 * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed, the rate
 *	control algorithm needs to adjust accordingly.
 */
enum rate_control_changed {
	IEEE80211_RC_HT_CHANGED = BIT(0)
	IEEE80211_RC_HT_CHANGED		= BIT(0),
	IEEE80211_RC_SMPS_CHANGED	= BIT(1),
};

/**
+58 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include "wpa.h"
#include "tkip.h"
#include "wme.h"
#include "rate.h"

/*
 * monitor mode reception
@@ -2233,6 +2234,63 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
		return RX_DROP_UNUSABLE;

	switch (mgmt->u.action.category) {
	case WLAN_CATEGORY_HT:
		/* reject HT action frames from stations not supporting HT */
		if (!rx->sta->sta.ht_cap.ht_supported)
			goto invalid;

		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
		    sdata->vif.type != NL80211_IFTYPE_AP &&
		    sdata->vif.type != NL80211_IFTYPE_ADHOC)
			break;

		/* verify action & smps_control are present */
		if (len < IEEE80211_MIN_ACTION_SIZE + 2)
			goto invalid;

		switch (mgmt->u.action.u.ht_smps.action) {
		case WLAN_HT_ACTION_SMPS: {
			struct ieee80211_supported_band *sband;
			u8 smps;

			/* convert to HT capability */
			switch (mgmt->u.action.u.ht_smps.smps_control) {
			case WLAN_HT_SMPS_CONTROL_DISABLED:
				smps = WLAN_HT_CAP_SM_PS_DISABLED;
				break;
			case WLAN_HT_SMPS_CONTROL_STATIC:
				smps = WLAN_HT_CAP_SM_PS_STATIC;
				break;
			case WLAN_HT_SMPS_CONTROL_DYNAMIC:
				smps = WLAN_HT_CAP_SM_PS_DYNAMIC;
				break;
			default:
				goto invalid;
			}
			smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT;

			/* if no change do nothing */
			if ((rx->sta->sta.ht_cap.cap &
					IEEE80211_HT_CAP_SM_PS) == smps)
				goto handled;

			rx->sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS;
			rx->sta->sta.ht_cap.cap |= smps;

			sband = rx->local->hw.wiphy->bands[status->band];

			rate_control_rate_update(local, sband, rx->sta,
						 IEEE80211_RC_SMPS_CHANGED,
						 local->_oper_channel_type);
			goto handled;
		}
		default:
			goto invalid;
		}

		break;
	case WLAN_CATEGORY_BACK:
		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
		    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&