mac80211: support HT notify channel width action
authorJohannes Berg <johannes.berg@intel.com>
Fri, 28 Dec 2012 11:12:10 +0000 (12:12 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 3 Jan 2013 12:01:44 +0000 (13:01 +0100)
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>
include/linux/ieee80211.h
net/mac80211/rx.c

index 5db76ebe8810d3915f6e19741e6124ff1fe79314..ccf9ee1dca8cbce8941d8a42a3ebc32d21a71015 100644 (file)
@@ -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 {
@@ -821,6 +826,10 @@ struct ieee80211_mgmt {
                                        u8 action;
                                        u8 smps_control;
                                } __packed ht_smps;
+                               struct {
+                                       u8 action_code;
+                                       u8 chanwidth;
+                               } __packed ht_notify_cw;
                                struct {
                                        u8 action_code;
                                        u8 dialog_token;
index 580704eba8b8495e0bdbf2268dfdc197b9983797..a19089565c4b84ed35a7b2c685d16c487a3ef356 100644 (file)
@@ -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;
                }