summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-12-28 12:12:10 +0100
committerJohannes Berg <johannes.berg@intel.com>2013-01-03 13:01:44 +0100
commitec61cd63dd3f3bf982180b2bcc1b325160d73837 (patch)
tree19fa85aa9fc26698bd9635b8f260b09df368ccda
parent598a5938e04ce30d837dca4c3c3326c69435342a (diff)
mac80211: support HT notify channel width action
Support the HT notify channel width action frame to update the rate scaling about the bandwidth the peer can receive in. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/linux/ieee80211.h9
-rw-r--r--net/mac80211/rx.c31
2 files changed, 39 insertions, 1 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 5db76ebe881..ccf9ee1dca8 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -701,6 +701,11 @@ enum ieee80211_rann_flags {
RANN_FLAG_IS_GATE = 1 << 0,
};
+enum ieee80211_ht_chanwidth_values {
+ IEEE80211_HT_CHANWIDTH_20MHZ = 0,
+ IEEE80211_HT_CHANWIDTH_ANY = 1,
+};
+
#define WLAN_SA_QUERY_TR_ID_LEN 2
struct ieee80211_mgmt {
@@ -823,6 +828,10 @@ struct ieee80211_mgmt {
} __packed ht_smps;
struct {
u8 action_code;
+ u8 chanwidth;
+ } __packed ht_notify_cw;
+ struct {
+ u8 action_code;
u8 dialog_token;
__le16 capability;
u8 variable[0];
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 580704eba8b..a19089565c4 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2353,7 +2353,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
sdata->vif.type != NL80211_IFTYPE_ADHOC)
break;
- /* verify action & smps_control are present */
+ /* verify action & smps_control/chanwidth are present */
if (len < IEEE80211_MIN_ACTION_SIZE + 2)
goto invalid;
@@ -2392,6 +2392,35 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
IEEE80211_RC_SMPS_CHANGED);
goto handled;
}
+ case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
+ struct ieee80211_supported_band *sband;
+ u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
+ bool old_40mhz, new_40mhz;
+
+ /* If it doesn't support 40 MHz it can't change ... */
+ if (!rx->sta->supports_40mhz)
+ goto handled;
+
+ old_40mhz = rx->sta->sta.ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ new_40mhz = chanwidth == IEEE80211_HT_CHANWIDTH_ANY;
+
+ if (old_40mhz == new_40mhz)
+ goto handled;
+
+ if (new_40mhz)
+ rx->sta->sta.ht_cap.cap |=
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ else
+ rx->sta->sta.ht_cap.cap &=
+ ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ sband = rx->local->hw.wiphy->bands[status->band];
+
+ rate_control_rate_update(local, sband, rx->sta,
+ IEEE80211_RC_BW_CHANGED);
+ goto handled;
+ }
default:
goto invalid;
}