xref: /openbmc/linux/net/mac80211/sta_info.c (revision f0706e828e96d0fa4e80c0d25aa98523f6d589a0)
1*f0706e82SJiri Benc /*
2*f0706e82SJiri Benc  * Copyright 2002-2005, Instant802 Networks, Inc.
3*f0706e82SJiri Benc  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
4*f0706e82SJiri Benc  *
5*f0706e82SJiri Benc  * This program is free software; you can redistribute it and/or modify
6*f0706e82SJiri Benc  * it under the terms of the GNU General Public License version 2 as
7*f0706e82SJiri Benc  * published by the Free Software Foundation.
8*f0706e82SJiri Benc  */
9*f0706e82SJiri Benc 
10*f0706e82SJiri Benc #include <linux/module.h>
11*f0706e82SJiri Benc #include <linux/init.h>
12*f0706e82SJiri Benc #include <linux/netdevice.h>
13*f0706e82SJiri Benc #include <linux/types.h>
14*f0706e82SJiri Benc #include <linux/slab.h>
15*f0706e82SJiri Benc #include <linux/skbuff.h>
16*f0706e82SJiri Benc #include <linux/if_arp.h>
17*f0706e82SJiri Benc 
18*f0706e82SJiri Benc #include <net/mac80211.h>
19*f0706e82SJiri Benc #include "ieee80211_i.h"
20*f0706e82SJiri Benc #include "ieee80211_rate.h"
21*f0706e82SJiri Benc #include "sta_info.h"
22*f0706e82SJiri Benc 
23*f0706e82SJiri Benc /* Caller must hold local->sta_lock */
24*f0706e82SJiri Benc static void sta_info_hash_add(struct ieee80211_local *local,
25*f0706e82SJiri Benc 			      struct sta_info *sta)
26*f0706e82SJiri Benc {
27*f0706e82SJiri Benc 	sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
28*f0706e82SJiri Benc 	local->sta_hash[STA_HASH(sta->addr)] = sta;
29*f0706e82SJiri Benc }
30*f0706e82SJiri Benc 
31*f0706e82SJiri Benc 
32*f0706e82SJiri Benc /* Caller must hold local->sta_lock */
33*f0706e82SJiri Benc static void sta_info_hash_del(struct ieee80211_local *local,
34*f0706e82SJiri Benc 			      struct sta_info *sta)
35*f0706e82SJiri Benc {
36*f0706e82SJiri Benc 	struct sta_info *s;
37*f0706e82SJiri Benc 
38*f0706e82SJiri Benc 	s = local->sta_hash[STA_HASH(sta->addr)];
39*f0706e82SJiri Benc 	if (!s)
40*f0706e82SJiri Benc 		return;
41*f0706e82SJiri Benc 	if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) {
42*f0706e82SJiri Benc 		local->sta_hash[STA_HASH(sta->addr)] = s->hnext;
43*f0706e82SJiri Benc 		return;
44*f0706e82SJiri Benc 	}
45*f0706e82SJiri Benc 
46*f0706e82SJiri Benc 	while (s->hnext && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
47*f0706e82SJiri Benc 		s = s->hnext;
48*f0706e82SJiri Benc 	if (s->hnext)
49*f0706e82SJiri Benc 		s->hnext = s->hnext->hnext;
50*f0706e82SJiri Benc 	else
51*f0706e82SJiri Benc 		printk(KERN_ERR "%s: could not remove STA " MAC_FMT " from "
52*f0706e82SJiri Benc 		       "hash table\n", local->mdev->name, MAC_ARG(sta->addr));
53*f0706e82SJiri Benc }
54*f0706e82SJiri Benc 
55*f0706e82SJiri Benc static inline void __sta_info_get(struct sta_info *sta)
56*f0706e82SJiri Benc {
57*f0706e82SJiri Benc 	kref_get(&sta->kref);
58*f0706e82SJiri Benc }
59*f0706e82SJiri Benc 
60*f0706e82SJiri Benc struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
61*f0706e82SJiri Benc {
62*f0706e82SJiri Benc 	struct sta_info *sta;
63*f0706e82SJiri Benc 
64*f0706e82SJiri Benc 	spin_lock_bh(&local->sta_lock);
65*f0706e82SJiri Benc 	sta = local->sta_hash[STA_HASH(addr)];
66*f0706e82SJiri Benc 	while (sta) {
67*f0706e82SJiri Benc 		if (memcmp(sta->addr, addr, ETH_ALEN) == 0) {
68*f0706e82SJiri Benc 			__sta_info_get(sta);
69*f0706e82SJiri Benc 			break;
70*f0706e82SJiri Benc 		}
71*f0706e82SJiri Benc 		sta = sta->hnext;
72*f0706e82SJiri Benc 	}
73*f0706e82SJiri Benc 	spin_unlock_bh(&local->sta_lock);
74*f0706e82SJiri Benc 
75*f0706e82SJiri Benc 	return sta;
76*f0706e82SJiri Benc }
77*f0706e82SJiri Benc EXPORT_SYMBOL(sta_info_get);
78*f0706e82SJiri Benc 
79*f0706e82SJiri Benc int sta_info_min_txrate_get(struct ieee80211_local *local)
80*f0706e82SJiri Benc {
81*f0706e82SJiri Benc 	struct sta_info *sta;
82*f0706e82SJiri Benc 	struct ieee80211_hw_mode *mode;
83*f0706e82SJiri Benc 	int min_txrate = 9999999;
84*f0706e82SJiri Benc 	int i;
85*f0706e82SJiri Benc 
86*f0706e82SJiri Benc 	spin_lock_bh(&local->sta_lock);
87*f0706e82SJiri Benc 	mode = local->oper_hw_mode;
88*f0706e82SJiri Benc 	for (i = 0; i < STA_HASH_SIZE; i++) {
89*f0706e82SJiri Benc 		sta = local->sta_hash[i];
90*f0706e82SJiri Benc 		while (sta) {
91*f0706e82SJiri Benc 			if (sta->txrate < min_txrate)
92*f0706e82SJiri Benc 				min_txrate = sta->txrate;
93*f0706e82SJiri Benc 			sta = sta->hnext;
94*f0706e82SJiri Benc 		}
95*f0706e82SJiri Benc 	}
96*f0706e82SJiri Benc 	spin_unlock_bh(&local->sta_lock);
97*f0706e82SJiri Benc 	if (min_txrate == 9999999)
98*f0706e82SJiri Benc 		min_txrate = 0;
99*f0706e82SJiri Benc 
100*f0706e82SJiri Benc 	return mode->rates[min_txrate].rate;
101*f0706e82SJiri Benc }
102*f0706e82SJiri Benc 
103*f0706e82SJiri Benc 
104*f0706e82SJiri Benc static void sta_info_release(struct kref *kref)
105*f0706e82SJiri Benc {
106*f0706e82SJiri Benc 	struct sta_info *sta = container_of(kref, struct sta_info, kref);
107*f0706e82SJiri Benc 	struct ieee80211_local *local = sta->local;
108*f0706e82SJiri Benc 	struct sk_buff *skb;
109*f0706e82SJiri Benc 
110*f0706e82SJiri Benc 	/* free sta structure; it has already been removed from
111*f0706e82SJiri Benc 	 * hash table etc. external structures. Make sure that all
112*f0706e82SJiri Benc 	 * buffered frames are release (one might have been added
113*f0706e82SJiri Benc 	 * after sta_info_free() was called). */
114*f0706e82SJiri Benc 	while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
115*f0706e82SJiri Benc 		local->total_ps_buffered--;
116*f0706e82SJiri Benc 		dev_kfree_skb_any(skb);
117*f0706e82SJiri Benc 	}
118*f0706e82SJiri Benc 	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
119*f0706e82SJiri Benc 		dev_kfree_skb_any(skb);
120*f0706e82SJiri Benc 	}
121*f0706e82SJiri Benc 	rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
122*f0706e82SJiri Benc 	rate_control_put(sta->rate_ctrl);
123*f0706e82SJiri Benc 	kfree(sta);
124*f0706e82SJiri Benc }
125*f0706e82SJiri Benc 
126*f0706e82SJiri Benc 
127*f0706e82SJiri Benc void sta_info_put(struct sta_info *sta)
128*f0706e82SJiri Benc {
129*f0706e82SJiri Benc 	kref_put(&sta->kref, sta_info_release);
130*f0706e82SJiri Benc }
131*f0706e82SJiri Benc EXPORT_SYMBOL(sta_info_put);
132*f0706e82SJiri Benc 
133*f0706e82SJiri Benc 
134*f0706e82SJiri Benc struct sta_info * sta_info_add(struct ieee80211_local *local,
135*f0706e82SJiri Benc 			       struct net_device *dev, u8 *addr, gfp_t gfp)
136*f0706e82SJiri Benc {
137*f0706e82SJiri Benc 	struct sta_info *sta;
138*f0706e82SJiri Benc 
139*f0706e82SJiri Benc 	sta = kzalloc(sizeof(*sta), gfp);
140*f0706e82SJiri Benc 	if (!sta)
141*f0706e82SJiri Benc 		return NULL;
142*f0706e82SJiri Benc 
143*f0706e82SJiri Benc 	kref_init(&sta->kref);
144*f0706e82SJiri Benc 
145*f0706e82SJiri Benc 	sta->rate_ctrl = rate_control_get(local->rate_ctrl);
146*f0706e82SJiri Benc 	sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp);
147*f0706e82SJiri Benc 	if (!sta->rate_ctrl_priv) {
148*f0706e82SJiri Benc 		rate_control_put(sta->rate_ctrl);
149*f0706e82SJiri Benc 		kref_put(&sta->kref, sta_info_release);
150*f0706e82SJiri Benc 		kfree(sta);
151*f0706e82SJiri Benc 		return NULL;
152*f0706e82SJiri Benc 	}
153*f0706e82SJiri Benc 
154*f0706e82SJiri Benc 	memcpy(sta->addr, addr, ETH_ALEN);
155*f0706e82SJiri Benc 	sta->local = local;
156*f0706e82SJiri Benc 	sta->dev = dev;
157*f0706e82SJiri Benc 	skb_queue_head_init(&sta->ps_tx_buf);
158*f0706e82SJiri Benc 	skb_queue_head_init(&sta->tx_filtered);
159*f0706e82SJiri Benc 	__sta_info_get(sta);	/* sta used by caller, decremented by
160*f0706e82SJiri Benc 				 * sta_info_put() */
161*f0706e82SJiri Benc 	spin_lock_bh(&local->sta_lock);
162*f0706e82SJiri Benc 	list_add(&sta->list, &local->sta_list);
163*f0706e82SJiri Benc 	local->num_sta++;
164*f0706e82SJiri Benc 	sta_info_hash_add(local, sta);
165*f0706e82SJiri Benc 	spin_unlock_bh(&local->sta_lock);
166*f0706e82SJiri Benc 	if (local->ops->sta_table_notification)
167*f0706e82SJiri Benc 		local->ops->sta_table_notification(local_to_hw(local),
168*f0706e82SJiri Benc 						  local->num_sta);
169*f0706e82SJiri Benc 	sta->key_idx_compression = HW_KEY_IDX_INVALID;
170*f0706e82SJiri Benc 
171*f0706e82SJiri Benc #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
172*f0706e82SJiri Benc 	printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n",
173*f0706e82SJiri Benc 	       local->mdev->name, MAC_ARG(addr));
174*f0706e82SJiri Benc #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
175*f0706e82SJiri Benc 
176*f0706e82SJiri Benc 	return sta;
177*f0706e82SJiri Benc }
178*f0706e82SJiri Benc 
179*f0706e82SJiri Benc static void sta_info_remove(struct sta_info *sta)
180*f0706e82SJiri Benc {
181*f0706e82SJiri Benc 	struct ieee80211_local *local = sta->local;
182*f0706e82SJiri Benc 	struct ieee80211_sub_if_data *sdata;
183*f0706e82SJiri Benc 
184*f0706e82SJiri Benc 	sta_info_hash_del(local, sta);
185*f0706e82SJiri Benc 	list_del(&sta->list);
186*f0706e82SJiri Benc 	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
187*f0706e82SJiri Benc 	if (sta->flags & WLAN_STA_PS) {
188*f0706e82SJiri Benc 		sta->flags &= ~WLAN_STA_PS;
189*f0706e82SJiri Benc 		if (sdata->bss)
190*f0706e82SJiri Benc 			atomic_dec(&sdata->bss->num_sta_ps);
191*f0706e82SJiri Benc 	}
192*f0706e82SJiri Benc 	local->num_sta--;
193*f0706e82SJiri Benc 	sta_info_remove_aid_ptr(sta);
194*f0706e82SJiri Benc }
195*f0706e82SJiri Benc 
196*f0706e82SJiri Benc void sta_info_free(struct sta_info *sta, int locked)
197*f0706e82SJiri Benc {
198*f0706e82SJiri Benc 	struct sk_buff *skb;
199*f0706e82SJiri Benc 	struct ieee80211_local *local = sta->local;
200*f0706e82SJiri Benc 
201*f0706e82SJiri Benc 	if (!locked) {
202*f0706e82SJiri Benc 		spin_lock_bh(&local->sta_lock);
203*f0706e82SJiri Benc 		sta_info_remove(sta);
204*f0706e82SJiri Benc 		spin_unlock_bh(&local->sta_lock);
205*f0706e82SJiri Benc 	} else {
206*f0706e82SJiri Benc 		sta_info_remove(sta);
207*f0706e82SJiri Benc 	}
208*f0706e82SJiri Benc 	if (local->ops->sta_table_notification)
209*f0706e82SJiri Benc 		local->ops->sta_table_notification(local_to_hw(local),
210*f0706e82SJiri Benc 						  local->num_sta);
211*f0706e82SJiri Benc 
212*f0706e82SJiri Benc 	while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
213*f0706e82SJiri Benc 		local->total_ps_buffered--;
214*f0706e82SJiri Benc 		dev_kfree_skb_any(skb);
215*f0706e82SJiri Benc 	}
216*f0706e82SJiri Benc 	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
217*f0706e82SJiri Benc 		dev_kfree_skb_any(skb);
218*f0706e82SJiri Benc 	}
219*f0706e82SJiri Benc 
220*f0706e82SJiri Benc 	if (sta->key) {
221*f0706e82SJiri Benc 		if (local->ops->set_key) {
222*f0706e82SJiri Benc 			struct ieee80211_key_conf *key;
223*f0706e82SJiri Benc 			key = ieee80211_key_data2conf(local, sta->key);
224*f0706e82SJiri Benc 			if (key) {
225*f0706e82SJiri Benc 				local->ops->set_key(local_to_hw(local),
226*f0706e82SJiri Benc 						   DISABLE_KEY,
227*f0706e82SJiri Benc 						   sta->addr, key, sta->aid);
228*f0706e82SJiri Benc 				kfree(key);
229*f0706e82SJiri Benc 			}
230*f0706e82SJiri Benc 		}
231*f0706e82SJiri Benc 	} else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) {
232*f0706e82SJiri Benc 		struct ieee80211_key_conf conf;
233*f0706e82SJiri Benc 		memset(&conf, 0, sizeof(conf));
234*f0706e82SJiri Benc 		conf.hw_key_idx = sta->key_idx_compression;
235*f0706e82SJiri Benc 		conf.alg = ALG_NULL;
236*f0706e82SJiri Benc 		conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
237*f0706e82SJiri Benc 		local->ops->set_key(local_to_hw(local), DISABLE_KEY,
238*f0706e82SJiri Benc 				   sta->addr, &conf, sta->aid);
239*f0706e82SJiri Benc 		sta->key_idx_compression = HW_KEY_IDX_INVALID;
240*f0706e82SJiri Benc 	}
241*f0706e82SJiri Benc 
242*f0706e82SJiri Benc #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
243*f0706e82SJiri Benc 	printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
244*f0706e82SJiri Benc 	       local->mdev->name, MAC_ARG(sta->addr));
245*f0706e82SJiri Benc #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
246*f0706e82SJiri Benc 
247*f0706e82SJiri Benc 	if (sta->key) {
248*f0706e82SJiri Benc 		ieee80211_key_free(sta->key);
249*f0706e82SJiri Benc 		sta->key = NULL;
250*f0706e82SJiri Benc 	}
251*f0706e82SJiri Benc 
252*f0706e82SJiri Benc 	sta_info_put(sta);
253*f0706e82SJiri Benc }
254*f0706e82SJiri Benc 
255*f0706e82SJiri Benc 
256*f0706e82SJiri Benc static inline int sta_info_buffer_expired(struct ieee80211_local *local,
257*f0706e82SJiri Benc 					  struct sta_info *sta,
258*f0706e82SJiri Benc 					  struct sk_buff *skb)
259*f0706e82SJiri Benc {
260*f0706e82SJiri Benc 	struct ieee80211_tx_packet_data *pkt_data;
261*f0706e82SJiri Benc 	int timeout;
262*f0706e82SJiri Benc 
263*f0706e82SJiri Benc 	if (!skb)
264*f0706e82SJiri Benc 		return 0;
265*f0706e82SJiri Benc 
266*f0706e82SJiri Benc 	pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
267*f0706e82SJiri Benc 
268*f0706e82SJiri Benc 	/* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
269*f0706e82SJiri Benc 	timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 /
270*f0706e82SJiri Benc 		   15625) * HZ;
271*f0706e82SJiri Benc 	if (timeout < STA_TX_BUFFER_EXPIRE)
272*f0706e82SJiri Benc 		timeout = STA_TX_BUFFER_EXPIRE;
273*f0706e82SJiri Benc 	return time_after(jiffies, pkt_data->jiffies + timeout);
274*f0706e82SJiri Benc }
275*f0706e82SJiri Benc 
276*f0706e82SJiri Benc 
277*f0706e82SJiri Benc static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
278*f0706e82SJiri Benc 					     struct sta_info *sta)
279*f0706e82SJiri Benc {
280*f0706e82SJiri Benc 	unsigned long flags;
281*f0706e82SJiri Benc 	struct sk_buff *skb;
282*f0706e82SJiri Benc 
283*f0706e82SJiri Benc 	if (skb_queue_empty(&sta->ps_tx_buf))
284*f0706e82SJiri Benc 		return;
285*f0706e82SJiri Benc 
286*f0706e82SJiri Benc 	for (;;) {
287*f0706e82SJiri Benc 		spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
288*f0706e82SJiri Benc 		skb = skb_peek(&sta->ps_tx_buf);
289*f0706e82SJiri Benc 		if (sta_info_buffer_expired(local, sta, skb)) {
290*f0706e82SJiri Benc 			skb = __skb_dequeue(&sta->ps_tx_buf);
291*f0706e82SJiri Benc 			if (skb_queue_empty(&sta->ps_tx_buf))
292*f0706e82SJiri Benc 				sta->flags &= ~WLAN_STA_TIM;
293*f0706e82SJiri Benc 		} else
294*f0706e82SJiri Benc 			skb = NULL;
295*f0706e82SJiri Benc 		spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
296*f0706e82SJiri Benc 
297*f0706e82SJiri Benc 		if (skb) {
298*f0706e82SJiri Benc 			local->total_ps_buffered--;
299*f0706e82SJiri Benc 			printk(KERN_DEBUG "Buffered frame expired (STA "
300*f0706e82SJiri Benc 			       MAC_FMT ")\n", MAC_ARG(sta->addr));
301*f0706e82SJiri Benc 			dev_kfree_skb(skb);
302*f0706e82SJiri Benc 		} else
303*f0706e82SJiri Benc 			break;
304*f0706e82SJiri Benc 	}
305*f0706e82SJiri Benc }
306*f0706e82SJiri Benc 
307*f0706e82SJiri Benc 
308*f0706e82SJiri Benc static void sta_info_cleanup(unsigned long data)
309*f0706e82SJiri Benc {
310*f0706e82SJiri Benc 	struct ieee80211_local *local = (struct ieee80211_local *) data;
311*f0706e82SJiri Benc 	struct sta_info *sta;
312*f0706e82SJiri Benc 
313*f0706e82SJiri Benc 	spin_lock_bh(&local->sta_lock);
314*f0706e82SJiri Benc 	list_for_each_entry(sta, &local->sta_list, list) {
315*f0706e82SJiri Benc 		__sta_info_get(sta);
316*f0706e82SJiri Benc 		sta_info_cleanup_expire_buffered(local, sta);
317*f0706e82SJiri Benc 		sta_info_put(sta);
318*f0706e82SJiri Benc 	}
319*f0706e82SJiri Benc 	spin_unlock_bh(&local->sta_lock);
320*f0706e82SJiri Benc 
321*f0706e82SJiri Benc 	local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
322*f0706e82SJiri Benc 	add_timer(&local->sta_cleanup);
323*f0706e82SJiri Benc }
324*f0706e82SJiri Benc 
325*f0706e82SJiri Benc void sta_info_init(struct ieee80211_local *local)
326*f0706e82SJiri Benc {
327*f0706e82SJiri Benc 	spin_lock_init(&local->sta_lock);
328*f0706e82SJiri Benc 	INIT_LIST_HEAD(&local->sta_list);
329*f0706e82SJiri Benc 	INIT_LIST_HEAD(&local->deleted_sta_list);
330*f0706e82SJiri Benc 
331*f0706e82SJiri Benc 	init_timer(&local->sta_cleanup);
332*f0706e82SJiri Benc 	local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
333*f0706e82SJiri Benc 	local->sta_cleanup.data = (unsigned long) local;
334*f0706e82SJiri Benc 	local->sta_cleanup.function = sta_info_cleanup;
335*f0706e82SJiri Benc }
336*f0706e82SJiri Benc 
337*f0706e82SJiri Benc int sta_info_start(struct ieee80211_local *local)
338*f0706e82SJiri Benc {
339*f0706e82SJiri Benc 	add_timer(&local->sta_cleanup);
340*f0706e82SJiri Benc 	return 0;
341*f0706e82SJiri Benc }
342*f0706e82SJiri Benc 
343*f0706e82SJiri Benc void sta_info_stop(struct ieee80211_local *local)
344*f0706e82SJiri Benc {
345*f0706e82SJiri Benc 	struct sta_info *sta, *tmp;
346*f0706e82SJiri Benc 
347*f0706e82SJiri Benc 	del_timer(&local->sta_cleanup);
348*f0706e82SJiri Benc 
349*f0706e82SJiri Benc 	list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
350*f0706e82SJiri Benc 		/*  We don't need locking at this point. */
351*f0706e82SJiri Benc 		sta_info_free(sta, 0);
352*f0706e82SJiri Benc 	}
353*f0706e82SJiri Benc }
354*f0706e82SJiri Benc 
355*f0706e82SJiri Benc void sta_info_remove_aid_ptr(struct sta_info *sta)
356*f0706e82SJiri Benc {
357*f0706e82SJiri Benc 	struct ieee80211_sub_if_data *sdata;
358*f0706e82SJiri Benc 
359*f0706e82SJiri Benc 	if (sta->aid <= 0)
360*f0706e82SJiri Benc 		return;
361*f0706e82SJiri Benc 
362*f0706e82SJiri Benc 	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
363*f0706e82SJiri Benc 
364*f0706e82SJiri Benc 	if (sdata->local->ops->set_tim)
365*f0706e82SJiri Benc 		sdata->local->ops->set_tim(local_to_hw(sdata->local),
366*f0706e82SJiri Benc 					  sta->aid, 0);
367*f0706e82SJiri Benc 	if (sdata->bss)
368*f0706e82SJiri Benc 		__bss_tim_clear(sdata->bss, sta->aid);
369*f0706e82SJiri Benc }
370*f0706e82SJiri Benc 
371*f0706e82SJiri Benc 
372*f0706e82SJiri Benc /**
373*f0706e82SJiri Benc  * sta_info_flush - flush matching STA entries from the STA table
374*f0706e82SJiri Benc  * @local: local interface data
375*f0706e82SJiri Benc  * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs
376*f0706e82SJiri Benc  */
377*f0706e82SJiri Benc void sta_info_flush(struct ieee80211_local *local, struct net_device *dev)
378*f0706e82SJiri Benc {
379*f0706e82SJiri Benc 	struct sta_info *sta, *tmp;
380*f0706e82SJiri Benc 
381*f0706e82SJiri Benc 	spin_lock_bh(&local->sta_lock);
382*f0706e82SJiri Benc 	list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
383*f0706e82SJiri Benc 		if (!dev || dev == sta->dev)
384*f0706e82SJiri Benc 			sta_info_free(sta, 1);
385*f0706e82SJiri Benc 	spin_unlock_bh(&local->sta_lock);
386*f0706e82SJiri Benc }
387