aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-02-07 16:24:55 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-15 03:41:34 -0500
commitbee7f58699a406a4210ba9e0367bae7ac666abd0 (patch)
tree9925ff46a41d09667fe797460b2d3ccb07fed4dd
parent18942d3be0e0e67aa40550ce3266e48b51845d52 (diff)
mac80211: handle operating mode notif in beacon/assoc response
In beacons and association response frames an AP may include an operating mode notification element to advertise changes in the number of spatial streams it can receive. Handle this using the existing function that handles the action frame, but only handle NSS changes, not bandwidth changes which aren't allowed here. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/mlme.c26
-rw-r--r--net/mac80211/rx.c3
-rw-r--r--net/mac80211/util.c6
-rw-r--r--net/mac80211/vht.c6
5 files changed, 38 insertions, 6 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4947c91c6c86..892bac64a189 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1197,6 +1197,7 @@ struct ieee802_11_elems {
1197 u8 *pwr_constr_elem; 1197 u8 *pwr_constr_elem;
1198 u8 *quiet_elem; /* first quite element */ 1198 u8 *quiet_elem; /* first quite element */
1199 u8 *timeout_int; 1199 u8 *timeout_int;
1200 u8 *opmode_notif;
1200 1201
1201 /* length of them, respectively */ 1202 /* length of them, respectively */
1202 u8 ssid_len; 1203 u8 ssid_len;
@@ -1435,7 +1436,7 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
1435void ieee80211_sta_set_rx_nss(struct sta_info *sta); 1436void ieee80211_sta_set_rx_nss(struct sta_info *sta);
1436void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, 1437void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
1437 struct sta_info *sta, u8 opmode, 1438 struct sta_info *sta, u8 opmode,
1438 enum ieee80211_band band); 1439 enum ieee80211_band band, bool nss_only);
1439 1440
1440/* Spectrum management */ 1441/* Spectrum management */
1441void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, 1442void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e6da6bf8cc27..f2c6f7794f35 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2217,6 +2217,21 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
2217 elems.ht_operation, 2217 elems.ht_operation,
2218 cbss->bssid, false); 2218 cbss->bssid, false);
2219 2219
2220 /*
2221 * If an operating mode notification IE is present, override the
2222 * NSS calculation (that would be done in rate_control_rate_init())
2223 * and use the # of streams from that element.
2224 */
2225 if (elems.opmode_notif &&
2226 !(*elems.opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)) {
2227 u8 nss;
2228
2229 nss = *elems.opmode_notif & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK;
2230 nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
2231 nss += 1;
2232 sta->sta.rx_nss = nss;
2233 }
2234
2220 rate_control_rate_init(sta); 2235 rate_control_rate_init(sta);
2221 2236
2222 if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) 2237 if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
@@ -2489,6 +2504,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2489 struct ieee80211_local *local = sdata->local; 2504 struct ieee80211_local *local = sdata->local;
2490 struct ieee80211_chanctx_conf *chanctx_conf; 2505 struct ieee80211_chanctx_conf *chanctx_conf;
2491 struct ieee80211_channel *chan; 2506 struct ieee80211_channel *chan;
2507 struct sta_info *sta;
2492 u32 changed = 0; 2508 u32 changed = 0;
2493 bool erp_valid; 2509 bool erp_valid;
2494 u8 erp_value = 0; 2510 u8 erp_value = 0;
@@ -2728,14 +2744,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
2728 le16_to_cpu(mgmt->u.beacon.capab_info), 2744 le16_to_cpu(mgmt->u.beacon.capab_info),
2729 erp_valid, erp_value); 2745 erp_valid, erp_value);
2730 2746
2731
2732 mutex_lock(&local->sta_mtx); 2747 mutex_lock(&local->sta_mtx);
2748 sta = sta_info_get(sdata, bssid);
2749
2733 if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && 2750 if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param &&
2734 !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) 2751 !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
2735 changed |= ieee80211_config_ht_tx(sdata, 2752 changed |= ieee80211_config_ht_tx(sdata, sta,
2736 sta_info_get(sdata, bssid),
2737 elems.ht_operation, 2753 elems.ht_operation,
2738 bssid, true); 2754 bssid, true);
2755
2756 if (sta && elems.opmode_notif)
2757 ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
2758 rx_status->band, true);
2739 mutex_unlock(&local->sta_mtx); 2759 mutex_unlock(&local->sta_mtx);
2740 2760
2741 if (elems.country_elem && elems.pwr_constr_elem && 2761 if (elems.country_elem && elems.pwr_constr_elem &&
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1617e0bd4ca6..30f1ba6de8f3 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2459,7 +2459,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
2459 opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode; 2459 opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
2460 2460
2461 ieee80211_vht_handle_opmode(rx->sdata, rx->sta, 2461 ieee80211_vht_handle_opmode(rx->sdata, rx->sta,
2462 opmode, status->band); 2462 opmode, status->band,
2463 false);
2463 goto handled; 2464 goto handled;
2464 } 2465 }
2465 default: 2466 default:
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index b231bc2ed740..e24ff38606a9 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -787,6 +787,12 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
787 else 787 else
788 elem_parse_failed = true; 788 elem_parse_failed = true;
789 break; 789 break;
790 case WLAN_EID_OPMODE_NOTIF:
791 if (elen > 0)
792 elems->opmode_notif = pos;
793 else
794 elem_parse_failed = true;
795 break;
790 case WLAN_EID_MESH_ID: 796 case WLAN_EID_MESH_ID:
791 elems->mesh_id = pos; 797 elems->mesh_id = pos;
792 elems->mesh_id_len = elen; 798 elems->mesh_id_len = elen;
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index 0951f74e7ff5..a9549fcc5a04 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -141,7 +141,7 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta)
141 141
142void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, 142void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
143 struct sta_info *sta, u8 opmode, 143 struct sta_info *sta, u8 opmode,
144 enum ieee80211_band band) 144 enum ieee80211_band band, bool nss_only)
145{ 145{
146 struct ieee80211_local *local = sdata->local; 146 struct ieee80211_local *local = sdata->local;
147 struct ieee80211_supported_band *sband; 147 struct ieee80211_supported_band *sband;
@@ -164,6 +164,9 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
164 changed |= IEEE80211_RC_NSS_CHANGED; 164 changed |= IEEE80211_RC_NSS_CHANGED;
165 } 165 }
166 166
167 if (nss_only)
168 goto change;
169
167 switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { 170 switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
168 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: 171 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
169 sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; 172 sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
@@ -185,6 +188,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
185 changed |= IEEE80211_RC_NSS_CHANGED; 188 changed |= IEEE80211_RC_NSS_CHANGED;
186 } 189 }
187 190
191 change:
188 if (changed) 192 if (changed)
189 rate_control_rate_update(local, sband, sta, changed); 193 rate_control_rate_update(local, sband, sta, changed);
190} 194}