mac80211: recalculate min channel width on VHT opmode changes
When an associated station changes its VHT operating mode this
can/will affect the bandwidth it's using, and consequently we
must recalculate the minimum bandwidth we need to use. Failure
to do so can lead to one of two scenarios:
 1) we use a too high bandwidth, this is benign
 2) we use a too narrow bandwidth, causing rate control and
    actual PHY configuration to be out of sync, which can in
    turn cause problems/crashes
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
			
			
This commit is contained in:
		| @@ -6,6 +6,7 @@ | ||||
|  * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> | ||||
|  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||||
|  * Copyright 2013-2014  Intel Mobile Communications GmbH | ||||
|  * Copyright (c) 2016        Intel Deutschland GmbH | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
| @@ -1295,6 +1296,26 @@ static void ieee80211_iface_work(struct work_struct *work) | ||||
| 		} else if (ieee80211_is_action(mgmt->frame_control) && | ||||
| 			   mgmt->u.action.category == WLAN_CATEGORY_VHT) { | ||||
| 			switch (mgmt->u.action.u.vht_group_notif.action_code) { | ||||
| 			case WLAN_VHT_ACTION_OPMODE_NOTIF: { | ||||
| 				struct ieee80211_rx_status *status; | ||||
| 				enum nl80211_band band; | ||||
| 				u8 opmode; | ||||
| 
 | ||||
| 				status = IEEE80211_SKB_RXCB(skb); | ||||
| 				band = status->band; | ||||
| 				opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode; | ||||
| 
 | ||||
| 				mutex_lock(&local->sta_mtx); | ||||
| 				sta = sta_info_get_bss(sdata, mgmt->sa); | ||||
| 
 | ||||
| 				if (sta) | ||||
| 					ieee80211_vht_handle_opmode(sdata, sta, | ||||
| 								    opmode, | ||||
| 								    band); | ||||
| 
 | ||||
| 				mutex_unlock(&local->sta_mtx); | ||||
| 				break; | ||||
| 			} | ||||
| 			case WLAN_VHT_ACTION_GROUPID_MGMT: | ||||
| 				ieee80211_process_mu_groups(sdata, mgmt); | ||||
| 				break; | ||||
|   | ||||
| @@ -2881,17 +2881,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | ||||
| 
 | ||||
| 		switch (mgmt->u.action.u.vht_opmode_notif.action_code) { | ||||
| 		case WLAN_VHT_ACTION_OPMODE_NOTIF: { | ||||
| 			u8 opmode; | ||||
| 
 | ||||
| 			/* verify opmode is present */ | ||||
| 			if (len < IEEE80211_MIN_ACTION_SIZE + 2) | ||||
| 				goto invalid; | ||||
| 
 | ||||
| 			opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode; | ||||
| 
 | ||||
| 			ieee80211_vht_handle_opmode(rx->sdata, rx->sta, | ||||
| 						    opmode, status->band); | ||||
| 			goto handled; | ||||
| 			goto queue; | ||||
| 		} | ||||
| 		case WLAN_VHT_ACTION_GROUPID_MGMT: { | ||||
| 			if (len < IEEE80211_MIN_ACTION_SIZE + 25) | ||||
|   | ||||
| @@ -527,8 +527,10 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | ||||
| 
 | ||||
| 	u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band); | ||||
| 
 | ||||
| 	if (changed > 0) | ||||
| 	if (changed > 0) { | ||||
| 		ieee80211_recalc_min_chandef(sdata); | ||||
| 		rate_control_rate_update(local, sband, sta, changed); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ieee80211_get_vht_mask_from_cap(__le16 vht_cap, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user