diff options
Diffstat (limited to 'net/mac80211/work.c')
| -rw-r--r-- | net/mac80211/work.c | 153 | 
1 files changed, 20 insertions, 133 deletions
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 6c53b6d1002..c6dd01a0529 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -94,7 +94,8 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,  /* frame sending functions */ -static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie, +static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, +				struct sk_buff *skb, const u8 *ht_info_ie,  				struct ieee80211_supported_band *sband,  				struct ieee80211_channel *channel,  				enum ieee80211_smps_mode smps) @@ -102,8 +103,10 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,  	struct ieee80211_ht_info *ht_info;  	u8 *pos;  	u32 flags = channel->flags; -	u16 cap = sband->ht_cap.cap; -	__le16 tmp; +	u16 cap; +	struct ieee80211_sta_ht_cap ht_cap; + +	BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));  	if (!sband->ht_cap.ht_supported)  		return; @@ -114,9 +117,13 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,  	if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))  		return; +	memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); +	ieee80211_apply_htcap_overrides(sdata, &ht_cap); +  	ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);  	/* determine capability flags */ +	cap = ht_cap.cap;  	switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {  	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: @@ -154,34 +161,8 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,  	}  	/* reserve and fill IE */ -  	pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); -	*pos++ = WLAN_EID_HT_CAPABILITY; -	*pos++ = sizeof(struct ieee80211_ht_cap); -	memset(pos, 0, sizeof(struct ieee80211_ht_cap)); - -	/* capability flags */ -	tmp = cpu_to_le16(cap); -	memcpy(pos, &tmp, sizeof(u16)); -	pos += sizeof(u16); - -	/* AMPDU parameters */ -	*pos++ = sband->ht_cap.ampdu_factor | -		 (sband->ht_cap.ampdu_density << -			IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); - -	/* MCS set */ -	memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); -	pos += sizeof(sband->ht_cap.mcs); - -	/* extended capabilities */ -	pos += sizeof(__le16); - -	/* BF capabilities */ -	pos += sizeof(__le32); - -	/* antenna selection */ -	pos += sizeof(u8); +	ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);  }  static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, @@ -356,7 +337,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,  	if (wk->assoc.use_11n && wk->assoc.wmm_used &&  	    local->hw.queues >= 4) -		ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie, +		ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie,  				    sband, wk->chan, wk->assoc.smps);  	/* if present, add any custom non-vendor IEs that go after HT */ @@ -881,44 +862,6 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,  	kfree_skb(skb);  } -static bool ieee80211_work_ct_coexists(enum nl80211_channel_type wk_ct, -				       enum nl80211_channel_type oper_ct) -{ -	switch (wk_ct) { -	case NL80211_CHAN_NO_HT: -		return true; -	case NL80211_CHAN_HT20: -		if (oper_ct != NL80211_CHAN_NO_HT) -			return true; -		return false; -	case NL80211_CHAN_HT40MINUS: -	case NL80211_CHAN_HT40PLUS: -		return (wk_ct == oper_ct); -	} -	WARN_ON(1); /* shouldn't get here */ -	return false; -} - -static enum nl80211_channel_type -ieee80211_calc_ct(enum nl80211_channel_type wk_ct, -		  enum nl80211_channel_type oper_ct) -{ -	switch (wk_ct) { -	case NL80211_CHAN_NO_HT: -		return oper_ct; -	case NL80211_CHAN_HT20: -		if (oper_ct != NL80211_CHAN_NO_HT) -			return oper_ct; -		return wk_ct; -	case NL80211_CHAN_HT40MINUS: -	case NL80211_CHAN_HT40PLUS: -		return wk_ct; -	} -	WARN_ON(1); /* shouldn't get here */ -	return wk_ct; -} - -  static void ieee80211_work_timer(unsigned long data)  {  	struct ieee80211_local *local = (void *) data; @@ -969,51 +912,12 @@ static void ieee80211_work_work(struct work_struct *work)  		}  		if (!started && !local->tmp_channel) { -			bool on_oper_chan; -			bool tmp_chan_changed = false; -			bool on_oper_chan2; -			enum nl80211_channel_type wk_ct; -			on_oper_chan = ieee80211_cfg_on_oper_channel(local); - -			/* Work with existing channel type if possible. */ -			wk_ct = wk->chan_type; -			if (wk->chan == local->hw.conf.channel) -				wk_ct = ieee80211_calc_ct(wk->chan_type, -						local->hw.conf.channel_type); - -			if (local->tmp_channel) -				if ((local->tmp_channel != wk->chan) || -				    (local->tmp_channel_type != wk_ct)) -					tmp_chan_changed = true; +			ieee80211_offchannel_stop_vifs(local, true);  			local->tmp_channel = wk->chan; -			local->tmp_channel_type = wk_ct; -			/* -			 * Leave the station vifs in awake mode if they -			 * happen to be on the same channel as -			 * the requested channel. -			 */ -			on_oper_chan2 = ieee80211_cfg_on_oper_channel(local); -			if (on_oper_chan != on_oper_chan2) { -				if (on_oper_chan2) { -					/* going off oper channel, PS too */ -					ieee80211_offchannel_stop_vifs(local, -								       true); -					ieee80211_hw_config(local, 0); -				} else { -					/* going on channel, but leave PS -					 * off-channel. */ -					ieee80211_hw_config(local, 0); -					ieee80211_offchannel_return(local, -								    true, -								    false); -				} -			} else if (tmp_chan_changed) -				/* Still off-channel, but on some other -				 * channel, so update hardware. -				 * PS should already be off-channel. -				 */ -				ieee80211_hw_config(local, 0); +			local->tmp_channel_type = wk->chan_type; + +			ieee80211_hw_config(local, 0);  			started = true;  			wk->timeout = jiffies; @@ -1082,34 +986,17 @@ static void ieee80211_work_work(struct work_struct *work)  	list_for_each_entry(wk, &local->work_list, list) {  		if (!wk->started)  			continue; -		if (wk->chan != local->tmp_channel) -			continue; -		if (!ieee80211_work_ct_coexists(wk->chan_type, -						local->tmp_channel_type)) +		if (wk->chan != local->tmp_channel || +		    wk->chan_type != local->tmp_channel_type)  			continue;  		remain_off_channel = true;  	}  	if (!remain_off_channel && local->tmp_channel) {  		local->tmp_channel = NULL; -		/* If tmp_channel wasn't operating channel, then -		 * we need to go back on-channel. -		 * NOTE:  If we can ever be here while scannning, -		 * or if the hw_config() channel config logic changes, -		 * then we may need to do a more thorough check to see if -		 * we still need to do a hardware config.  Currently, -		 * we cannot be here while scanning, however. -		 */ -		if (!ieee80211_cfg_on_oper_channel(local)) -			ieee80211_hw_config(local, 0); +		ieee80211_hw_config(local, 0); -		/* At the least, we need to disable offchannel_ps, -		 * so just go ahead and run the entire offchannel -		 * return logic here.  We *could* skip enabling -		 * beaconing if we were already on-oper-channel -		 * as a future optimization. -		 */ -		ieee80211_offchannel_return(local, true, true); +		ieee80211_offchannel_return(local, true);  		/* give connection some time to breathe */  		run_again(local, jiffies + HZ/2);  |