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