diff options
Diffstat (limited to 'net/mac80211/mlme.c')
| -rw-r--r-- | net/mac80211/mlme.c | 137 | 
1 files changed, 113 insertions, 24 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d595265d6c22..d6470c7fd6ce 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -749,7 +749,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)  		container_of(work, struct ieee80211_local,  			     dynamic_ps_enable_work);  	struct ieee80211_sub_if_data *sdata = local->ps_sdata; -	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; +	struct ieee80211_if_managed *ifmgd;  	unsigned long flags;  	int q; @@ -757,26 +757,39 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)  	if (!sdata)  		return; +	ifmgd = &sdata->u.mgd; +  	if (local->hw.conf.flags & IEEE80211_CONF_PS)  		return; -	/* -	 * transmission can be stopped by others which leads to -	 * dynamic_ps_timer expiry. Postpond the ps timer if it -	 * is not the actual idle state. -	 */ -	spin_lock_irqsave(&local->queue_stop_reason_lock, flags); -	for (q = 0; q < local->hw.queues; q++) { -		if (local->queue_stop_reasons[q]) { -			spin_unlock_irqrestore(&local->queue_stop_reason_lock, -					       flags); +	if (!local->disable_dynamic_ps && +	    local->hw.conf.dynamic_ps_timeout > 0) { +		/* don't enter PS if TX frames are pending */ +		if (drv_tx_frames_pending(local)) {  			mod_timer(&local->dynamic_ps_timer, jiffies +  				  msecs_to_jiffies(  				  local->hw.conf.dynamic_ps_timeout));  			return;  		} + +		/* +		 * transmission can be stopped by others which leads to +		 * dynamic_ps_timer expiry. Postpone the ps timer if it +		 * is not the actual idle state. +		 */ +		spin_lock_irqsave(&local->queue_stop_reason_lock, flags); +		for (q = 0; q < local->hw.queues; q++) { +			if (local->queue_stop_reasons[q]) { +				spin_unlock_irqrestore(&local->queue_stop_reason_lock, +						       flags); +				mod_timer(&local->dynamic_ps_timer, jiffies + +					  msecs_to_jiffies( +					  local->hw.conf.dynamic_ps_timeout)); +				return; +			} +		} +		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);  	} -	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);  	if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&  	    (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { @@ -801,7 +814,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)  		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);  	} -	netif_tx_wake_all_queues(sdata->dev); +	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) +		netif_tx_wake_all_queues(sdata->dev);  }  void ieee80211_dynamic_ps_timer(unsigned long data) @@ -903,6 +917,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,  			    params.aifs, params.cw_min, params.cw_max,  			    params.txop, params.uapsd);  #endif +		local->tx_conf[queue] = params;  		if (drv_conf_tx(local, queue, ¶ms))  			wiphy_debug(local->hw.wiphy,  				    "failed to set TX queue parameters for queue %d\n", @@ -1204,7 +1219,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)  		ieee80211_send_nullfunc(sdata->local, sdata, 0);  	} else {  		ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); -		ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); +		ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0, +					 (u32) -1, true);  	}  	ifmgd->probe_send_count++; @@ -1289,7 +1305,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,  	ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);  	skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, -					ssid + 2, ssid[1], NULL, 0); +					(u32) -1, ssid + 2, ssid[1], +					NULL, 0, true);  	return skb;  } @@ -1748,6 +1765,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  		ifmgd->ave_beacon_signal = rx_status->signal * 16;  		ifmgd->last_cqm_event_signal = 0;  		ifmgd->count_beacon_signal = 1; +		ifmgd->last_ave_beacon_signal = 0;  	} else {  		ifmgd->ave_beacon_signal =  			(IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + @@ -1755,6 +1773,28 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,  			 ifmgd->ave_beacon_signal) / 16;  		ifmgd->count_beacon_signal++;  	} + +	if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold && +	    ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { +		int sig = ifmgd->ave_beacon_signal; +		int last_sig = ifmgd->last_ave_beacon_signal; + +		/* +		 * if signal crosses either of the boundaries, invoke callback +		 * with appropriate parameters +		 */ +		if (sig > ifmgd->rssi_max_thold && +		    (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { +			ifmgd->last_ave_beacon_signal = sig; +			drv_rssi_callback(local, RSSI_EVENT_HIGH); +		} else if (sig < ifmgd->rssi_min_thold && +			   (last_sig >= ifmgd->rssi_max_thold || +			   last_sig == 0)) { +			ifmgd->last_ave_beacon_signal = sig; +			drv_rssi_callback(local, RSSI_EVENT_LOW); +		} +	} +  	if (bss_conf->cqm_rssi_thold &&  	    ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&  	    !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { @@ -2014,7 +2054,7 @@ static void ieee80211_sta_timer(unsigned long data)  }  static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, -					  u8 *bssid) +					  u8 *bssid, u8 reason)  {  	struct ieee80211_local *local = sdata->local;  	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -2032,8 +2072,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,  	 * but that's not a problem.  	 */  	ieee80211_send_deauth_disassoc(sdata, bssid, -			IEEE80211_STYPE_DEAUTH, -			WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, +			IEEE80211_STYPE_DEAUTH, reason,  			NULL, true);  	mutex_lock(&ifmgd->mtx);  } @@ -2079,7 +2118,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)  					    " AP %pM, disconnecting.\n",  					    sdata->name, bssid);  #endif -				ieee80211_sta_connection_lost(sdata, bssid); +				ieee80211_sta_connection_lost(sdata, bssid, +					WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);  			}  		} else if (time_is_after_jiffies(ifmgd->probe_timeout))  			run_again(ifmgd, ifmgd->probe_timeout); @@ -2091,7 +2131,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)  				    sdata->name,  				    bssid, probe_wait_ms);  #endif -			ieee80211_sta_connection_lost(sdata, bssid); +			ieee80211_sta_connection_lost(sdata, bssid, +				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);  		} else if (ifmgd->probe_send_count < max_tries) {  #ifdef CONFIG_MAC80211_VERBOSE_DEBUG  			wiphy_debug(local->hw.wiphy, @@ -2113,7 +2154,8 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)  				    sdata->name,  				    bssid, probe_wait_ms); -			ieee80211_sta_connection_lost(sdata, bssid); +			ieee80211_sta_connection_lost(sdata, bssid, +				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);  		}  	} @@ -2200,12 +2242,34 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)  {  	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; +	if (!ifmgd->associated) +		return; + +	if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { +		sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; +		mutex_lock(&ifmgd->mtx); +		if (ifmgd->associated) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG +			wiphy_debug(sdata->local->hw.wiphy, +				    "%s: driver requested disconnect after resume.\n", +				    sdata->name); +#endif +			ieee80211_sta_connection_lost(sdata, +				ifmgd->associated->bssid, +				WLAN_REASON_UNSPECIFIED); +			mutex_unlock(&ifmgd->mtx); +			return; +		} +		mutex_unlock(&ifmgd->mtx); +	} +  	if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))  		add_timer(&ifmgd->timer);  	if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))  		add_timer(&ifmgd->chswitch_timer);  	ieee80211_sta_reset_beacon_monitor(sdata);  	ieee80211_restart_sta_timer(sdata); +	ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work);  }  #endif @@ -2271,14 +2335,16 @@ static enum work_done_result  ieee80211_probe_auth_done(struct ieee80211_work *wk,  			  struct sk_buff *skb)  { +	struct ieee80211_local *local = wk->sdata->local; +  	if (!skb) {  		cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); -		return WORK_DONE_DESTROY; +		goto destroy;  	}  	if (wk->type == IEEE80211_WORK_AUTH) {  		cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); -		return WORK_DONE_DESTROY; +		goto destroy;  	}  	mutex_lock(&wk->sdata->u.mgd.mtx); @@ -2288,6 +2354,12 @@ ieee80211_probe_auth_done(struct ieee80211_work *wk,  	wk->type = IEEE80211_WORK_AUTH;  	wk->probe_auth.tries = 0;  	return WORK_DONE_REQUEUE; + destroy: +	if (wk->probe_auth.synced) +		drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, +				   IEEE80211_TX_SYNC_AUTH); + +	return WORK_DONE_DESTROY;  }  int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, @@ -2360,6 +2432,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,  static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,  						  struct sk_buff *skb)  { +	struct ieee80211_local *local = wk->sdata->local;  	struct ieee80211_mgmt *mgmt;  	struct ieee80211_rx_status *rx_status;  	struct ieee802_11_elems elems; @@ -2367,7 +2440,7 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,  	if (!skb) {  		cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); -		return WORK_DONE_DESTROY; +		goto destroy;  	}  	if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { @@ -2387,6 +2460,10 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,  	status = le16_to_cpu(mgmt->u.assoc_resp.status_code);  	if (status == WLAN_STATUS_SUCCESS) { +		if (wk->assoc.synced) +			drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, +					   IEEE80211_TX_SYNC_ASSOC); +  		mutex_lock(&wk->sdata->u.mgd.mtx);  		if (!ieee80211_assoc_success(wk, mgmt, skb->len)) {  			mutex_unlock(&wk->sdata->u.mgd.mtx); @@ -2400,6 +2477,11 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,  	}  	cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); + destroy: +	if (wk->assoc.synced) +		drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, +				   IEEE80211_TX_SYNC_ASSOC); +  	return WORK_DONE_DESTROY;  } @@ -2652,3 +2734,10 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,  	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);  }  EXPORT_SYMBOL(ieee80211_cqm_rssi_notify); + +unsigned char ieee80211_get_operstate(struct ieee80211_vif *vif) +{ +	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); +	return sdata->dev->operstate; +} +EXPORT_SYMBOL(ieee80211_get_operstate);  |