diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
| -rw-r--r-- | net/mac80211/sta_info.c | 52 | 
1 files changed, 31 insertions, 21 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 13e8c30adf0..b83870bf60f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -67,7 +67,8 @@ static int sta_info_hash_del(struct ieee80211_local *local,  {  	struct sta_info *s; -	s = local->sta_hash[STA_HASH(sta->sta.addr)]; +	s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)], +				      lockdep_is_held(&local->sta_lock));  	if (!s)  		return -ENOENT;  	if (s == sta) { @@ -76,9 +77,11 @@ static int sta_info_hash_del(struct ieee80211_local *local,  		return 0;  	} -	while (s->hnext && s->hnext != sta) -		s = s->hnext; -	if (s->hnext) { +	while (rcu_access_pointer(s->hnext) && +	       rcu_access_pointer(s->hnext) != sta) +		s = rcu_dereference_protected(s->hnext, +					lockdep_is_held(&local->sta_lock)); +	if (rcu_access_pointer(s->hnext)) {  		rcu_assign_pointer(s->hnext, sta->hnext);  		return 0;  	} @@ -228,6 +231,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,  {  	struct ieee80211_local *local = sdata->local;  	struct sta_info *sta; +	struct timespec uptime;  	int i;  	sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); @@ -245,6 +249,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,  	sta->sdata = sdata;  	sta->last_rx = jiffies; +	do_posix_clock_monotonic_gettime(&uptime); +	sta->last_connected = uptime.tv_sec;  	ewma_init(&sta->avg_signal, 1024, 8);  	if (sta_prepare_rate_control(local, sta, gfp)) { @@ -271,7 +277,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,  #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */  #ifdef CONFIG_MAC80211_MESH -	sta->plink_state = PLINK_LISTEN; +	sta->plink_state = NL80211_PLINK_LISTEN;  	init_timer(&sta->plink_timer);  #endif @@ -584,7 +590,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,  {  	unsigned long flags;  	struct sk_buff *skb; -	struct ieee80211_sub_if_data *sdata;  	if (skb_queue_empty(&sta->ps_tx_buf))  		return false; @@ -601,7 +606,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,  		if (!skb)  			break; -		sdata = sta->sdata;  		local->total_ps_buffered--;  #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG  		printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", @@ -609,7 +613,8 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,  #endif  		dev_kfree_skb(skb); -		if (skb_queue_empty(&sta->ps_tx_buf)) +		if (skb_queue_empty(&sta->ps_tx_buf) && +		    !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))  			sta_info_clear_tim_bit(sta);  	} @@ -650,10 +655,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)  	if (ret)  		return ret; +	mutex_lock(&local->key_mtx);  	for (i = 0; i < NUM_DEFAULT_KEYS; i++) -		ieee80211_key_free(local, sta->gtk[i]); +		__ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));  	if (sta->ptk) -		ieee80211_key_free(local, sta->ptk); +		__ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); +	mutex_unlock(&local->key_mtx);  	sta->dead = true; @@ -698,6 +705,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)  #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */  	cancel_work_sync(&sta->drv_unblock_wk); +	cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); +  	rate_control_remove_sta_debugfs(sta);  	ieee80211_sta_debugfs_remove(sta); @@ -766,9 +775,8 @@ static void sta_info_cleanup(unsigned long data)  	if (!timer_needed)  		return; -	local->sta_cleanup.expires = -		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); -	add_timer(&local->sta_cleanup); +	mod_timer(&local->sta_cleanup, +		  round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL));  }  void sta_info_init(struct ieee80211_local *local) @@ -781,14 +789,6 @@ void sta_info_init(struct ieee80211_local *local)  	setup_timer(&local->sta_cleanup, sta_info_cleanup,  		    (unsigned long)local); -	local->sta_cleanup.expires = -		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); -} - -int sta_info_start(struct ieee80211_local *local) -{ -	add_timer(&local->sta_cleanup); -	return 0;  }  void sta_info_stop(struct ieee80211_local *local) @@ -900,6 +900,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)  	struct ieee80211_local *local = sdata->local;  	int sent, buffered; +	clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);  	if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))  		drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); @@ -992,3 +993,12 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,  		ieee80211_queue_work(hw, &sta->drv_unblock_wk);  }  EXPORT_SYMBOL(ieee80211_sta_block_awake); + +void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta) +{ +	struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + +	set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); +	sta_info_set_tim_bit(sta); +} +EXPORT_SYMBOL(ieee80211_sta_set_tim);  |