diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 26 | ||||
-rw-r--r-- | net/mac80211/rx.c | 3 | ||||
-rw-r--r-- | net/mac80211/util.c | 6 | ||||
-rw-r--r-- | net/mac80211/vht.c | 6 |
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); | |||
1435 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); | 1436 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); |
1436 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 1437 | void 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 */ |
1441 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1442 | void 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 | ||
142 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 142 | void 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 | } |