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" 22*e9f207f0SJiri Benc #include "debugfs_key.h" 23*e9f207f0SJiri Benc #include "debugfs_sta.h" 24f0706e82SJiri Benc 25f0706e82SJiri Benc /* Caller must hold local->sta_lock */ 26f0706e82SJiri Benc static void sta_info_hash_add(struct ieee80211_local *local, 27f0706e82SJiri Benc struct sta_info *sta) 28f0706e82SJiri Benc { 29f0706e82SJiri Benc sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; 30f0706e82SJiri Benc local->sta_hash[STA_HASH(sta->addr)] = sta; 31f0706e82SJiri Benc } 32f0706e82SJiri Benc 33f0706e82SJiri Benc 34f0706e82SJiri Benc /* Caller must hold local->sta_lock */ 35f0706e82SJiri Benc static void sta_info_hash_del(struct ieee80211_local *local, 36f0706e82SJiri Benc struct sta_info *sta) 37f0706e82SJiri Benc { 38f0706e82SJiri Benc struct sta_info *s; 39f0706e82SJiri Benc 40f0706e82SJiri Benc s = local->sta_hash[STA_HASH(sta->addr)]; 41f0706e82SJiri Benc if (!s) 42f0706e82SJiri Benc return; 43f0706e82SJiri Benc if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) { 44f0706e82SJiri Benc local->sta_hash[STA_HASH(sta->addr)] = s->hnext; 45f0706e82SJiri Benc return; 46f0706e82SJiri Benc } 47f0706e82SJiri Benc 48f0706e82SJiri Benc while (s->hnext && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) 49f0706e82SJiri Benc s = s->hnext; 50f0706e82SJiri Benc if (s->hnext) 51f0706e82SJiri Benc s->hnext = s->hnext->hnext; 52f0706e82SJiri Benc else 53f0706e82SJiri Benc printk(KERN_ERR "%s: could not remove STA " MAC_FMT " from " 54f0706e82SJiri Benc "hash table\n", local->mdev->name, MAC_ARG(sta->addr)); 55f0706e82SJiri Benc } 56f0706e82SJiri Benc 57f0706e82SJiri Benc static inline void __sta_info_get(struct sta_info *sta) 58f0706e82SJiri Benc { 59f0706e82SJiri Benc kref_get(&sta->kref); 60f0706e82SJiri Benc } 61f0706e82SJiri Benc 62f0706e82SJiri Benc struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) 63f0706e82SJiri Benc { 64f0706e82SJiri Benc struct sta_info *sta; 65f0706e82SJiri Benc 66f0706e82SJiri Benc spin_lock_bh(&local->sta_lock); 67f0706e82SJiri Benc sta = local->sta_hash[STA_HASH(addr)]; 68f0706e82SJiri Benc while (sta) { 69f0706e82SJiri Benc if (memcmp(sta->addr, addr, ETH_ALEN) == 0) { 70f0706e82SJiri Benc __sta_info_get(sta); 71f0706e82SJiri Benc break; 72f0706e82SJiri Benc } 73f0706e82SJiri Benc sta = sta->hnext; 74f0706e82SJiri Benc } 75f0706e82SJiri Benc spin_unlock_bh(&local->sta_lock); 76f0706e82SJiri Benc 77f0706e82SJiri Benc return sta; 78f0706e82SJiri Benc } 79f0706e82SJiri Benc EXPORT_SYMBOL(sta_info_get); 80f0706e82SJiri Benc 81f0706e82SJiri Benc int sta_info_min_txrate_get(struct ieee80211_local *local) 82f0706e82SJiri Benc { 83f0706e82SJiri Benc struct sta_info *sta; 84f0706e82SJiri Benc struct ieee80211_hw_mode *mode; 85f0706e82SJiri Benc int min_txrate = 9999999; 86f0706e82SJiri Benc int i; 87f0706e82SJiri Benc 88f0706e82SJiri Benc spin_lock_bh(&local->sta_lock); 89f0706e82SJiri Benc mode = local->oper_hw_mode; 90f0706e82SJiri Benc for (i = 0; i < STA_HASH_SIZE; i++) { 91f0706e82SJiri Benc sta = local->sta_hash[i]; 92f0706e82SJiri Benc while (sta) { 93f0706e82SJiri Benc if (sta->txrate < min_txrate) 94f0706e82SJiri Benc min_txrate = sta->txrate; 95f0706e82SJiri Benc sta = sta->hnext; 96f0706e82SJiri Benc } 97f0706e82SJiri Benc } 98f0706e82SJiri Benc spin_unlock_bh(&local->sta_lock); 99f0706e82SJiri Benc if (min_txrate == 9999999) 100f0706e82SJiri Benc min_txrate = 0; 101f0706e82SJiri Benc 102f0706e82SJiri Benc return mode->rates[min_txrate].rate; 103f0706e82SJiri Benc } 104f0706e82SJiri Benc 105f0706e82SJiri Benc 106f0706e82SJiri Benc static void sta_info_release(struct kref *kref) 107f0706e82SJiri Benc { 108f0706e82SJiri Benc struct sta_info *sta = container_of(kref, struct sta_info, kref); 109f0706e82SJiri Benc struct ieee80211_local *local = sta->local; 110f0706e82SJiri Benc struct sk_buff *skb; 111f0706e82SJiri Benc 112f0706e82SJiri Benc /* free sta structure; it has already been removed from 113f0706e82SJiri Benc * hash table etc. external structures. Make sure that all 114f0706e82SJiri Benc * buffered frames are release (one might have been added 115f0706e82SJiri Benc * after sta_info_free() was called). */ 116f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { 117f0706e82SJiri Benc local->total_ps_buffered--; 118f0706e82SJiri Benc dev_kfree_skb_any(skb); 119f0706e82SJiri Benc } 120f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { 121f0706e82SJiri Benc dev_kfree_skb_any(skb); 122f0706e82SJiri Benc } 123f0706e82SJiri Benc rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); 124f0706e82SJiri Benc rate_control_put(sta->rate_ctrl); 125*e9f207f0SJiri Benc if (sta->key) 126*e9f207f0SJiri Benc ieee80211_debugfs_key_sta_del(sta->key, sta); 127f0706e82SJiri Benc kfree(sta); 128f0706e82SJiri Benc } 129f0706e82SJiri Benc 130f0706e82SJiri Benc 131f0706e82SJiri Benc void sta_info_put(struct sta_info *sta) 132f0706e82SJiri Benc { 133f0706e82SJiri Benc kref_put(&sta->kref, sta_info_release); 134f0706e82SJiri Benc } 135f0706e82SJiri Benc EXPORT_SYMBOL(sta_info_put); 136f0706e82SJiri Benc 137f0706e82SJiri Benc 138f0706e82SJiri Benc struct sta_info * sta_info_add(struct ieee80211_local *local, 139f0706e82SJiri Benc struct net_device *dev, u8 *addr, gfp_t gfp) 140f0706e82SJiri Benc { 141f0706e82SJiri Benc struct sta_info *sta; 142f0706e82SJiri Benc 143f0706e82SJiri Benc sta = kzalloc(sizeof(*sta), gfp); 144f0706e82SJiri Benc if (!sta) 145f0706e82SJiri Benc return NULL; 146f0706e82SJiri Benc 147f0706e82SJiri Benc kref_init(&sta->kref); 148f0706e82SJiri Benc 149f0706e82SJiri Benc sta->rate_ctrl = rate_control_get(local->rate_ctrl); 150f0706e82SJiri Benc sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); 151f0706e82SJiri Benc if (!sta->rate_ctrl_priv) { 152f0706e82SJiri Benc rate_control_put(sta->rate_ctrl); 153f0706e82SJiri Benc kref_put(&sta->kref, sta_info_release); 154f0706e82SJiri Benc kfree(sta); 155f0706e82SJiri Benc return NULL; 156f0706e82SJiri Benc } 157f0706e82SJiri Benc 158f0706e82SJiri Benc memcpy(sta->addr, addr, ETH_ALEN); 159f0706e82SJiri Benc sta->local = local; 160f0706e82SJiri Benc sta->dev = dev; 161f0706e82SJiri Benc skb_queue_head_init(&sta->ps_tx_buf); 162f0706e82SJiri Benc skb_queue_head_init(&sta->tx_filtered); 163f0706e82SJiri Benc __sta_info_get(sta); /* sta used by caller, decremented by 164f0706e82SJiri Benc * sta_info_put() */ 165f0706e82SJiri Benc spin_lock_bh(&local->sta_lock); 166f0706e82SJiri Benc list_add(&sta->list, &local->sta_list); 167f0706e82SJiri Benc local->num_sta++; 168f0706e82SJiri Benc sta_info_hash_add(local, sta); 169f0706e82SJiri Benc spin_unlock_bh(&local->sta_lock); 170f0706e82SJiri Benc if (local->ops->sta_table_notification) 171f0706e82SJiri Benc local->ops->sta_table_notification(local_to_hw(local), 172f0706e82SJiri Benc local->num_sta); 173f0706e82SJiri Benc sta->key_idx_compression = HW_KEY_IDX_INVALID; 174f0706e82SJiri Benc 175f0706e82SJiri Benc #ifdef CONFIG_MAC80211_VERBOSE_DEBUG 176f0706e82SJiri Benc printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n", 177f0706e82SJiri Benc local->mdev->name, MAC_ARG(addr)); 178f0706e82SJiri Benc #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 179f0706e82SJiri Benc 180*e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 181*e9f207f0SJiri Benc if (!in_interrupt()) { 182*e9f207f0SJiri Benc sta->debugfs_registered = 1; 183*e9f207f0SJiri Benc ieee80211_sta_debugfs_add(sta); 184*e9f207f0SJiri Benc rate_control_add_sta_debugfs(sta); 185*e9f207f0SJiri Benc } else { 186*e9f207f0SJiri Benc /* debugfs entry adding might sleep, so schedule process 187*e9f207f0SJiri Benc * context task for adding entry for STAs that do not yet 188*e9f207f0SJiri Benc * have one. */ 189*e9f207f0SJiri Benc queue_work(local->hw.workqueue, &local->sta_debugfs_add); 190*e9f207f0SJiri Benc } 191*e9f207f0SJiri Benc #endif 192*e9f207f0SJiri Benc 193f0706e82SJiri Benc return sta; 194f0706e82SJiri Benc } 195f0706e82SJiri Benc 196*e9f207f0SJiri Benc static void finish_sta_info_free(struct ieee80211_local *local, 197*e9f207f0SJiri Benc struct sta_info *sta) 198*e9f207f0SJiri Benc { 199*e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_VERBOSE_DEBUG 200*e9f207f0SJiri Benc printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", 201*e9f207f0SJiri Benc local->mdev->name, MAC_ARG(sta->addr)); 202*e9f207f0SJiri Benc #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 203*e9f207f0SJiri Benc 204*e9f207f0SJiri Benc if (sta->key) { 205*e9f207f0SJiri Benc ieee80211_debugfs_key_remove(sta->key); 206*e9f207f0SJiri Benc ieee80211_key_free(sta->key); 207*e9f207f0SJiri Benc sta->key = NULL; 208*e9f207f0SJiri Benc } 209*e9f207f0SJiri Benc 210*e9f207f0SJiri Benc rate_control_remove_sta_debugfs(sta); 211*e9f207f0SJiri Benc ieee80211_sta_debugfs_remove(sta); 212*e9f207f0SJiri Benc 213*e9f207f0SJiri Benc sta_info_put(sta); 214*e9f207f0SJiri Benc } 215*e9f207f0SJiri Benc 216f0706e82SJiri Benc static void sta_info_remove(struct sta_info *sta) 217f0706e82SJiri Benc { 218f0706e82SJiri Benc struct ieee80211_local *local = sta->local; 219f0706e82SJiri Benc struct ieee80211_sub_if_data *sdata; 220f0706e82SJiri Benc 221f0706e82SJiri Benc sta_info_hash_del(local, sta); 222f0706e82SJiri Benc list_del(&sta->list); 223f0706e82SJiri Benc sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 224f0706e82SJiri Benc if (sta->flags & WLAN_STA_PS) { 225f0706e82SJiri Benc sta->flags &= ~WLAN_STA_PS; 226f0706e82SJiri Benc if (sdata->bss) 227f0706e82SJiri Benc atomic_dec(&sdata->bss->num_sta_ps); 228f0706e82SJiri Benc } 229f0706e82SJiri Benc local->num_sta--; 230f0706e82SJiri Benc sta_info_remove_aid_ptr(sta); 231f0706e82SJiri Benc } 232f0706e82SJiri Benc 233f0706e82SJiri Benc void sta_info_free(struct sta_info *sta, int locked) 234f0706e82SJiri Benc { 235f0706e82SJiri Benc struct sk_buff *skb; 236f0706e82SJiri Benc struct ieee80211_local *local = sta->local; 237f0706e82SJiri Benc 238f0706e82SJiri Benc if (!locked) { 239f0706e82SJiri Benc spin_lock_bh(&local->sta_lock); 240f0706e82SJiri Benc sta_info_remove(sta); 241f0706e82SJiri Benc spin_unlock_bh(&local->sta_lock); 242f0706e82SJiri Benc } else { 243f0706e82SJiri Benc sta_info_remove(sta); 244f0706e82SJiri Benc } 245f0706e82SJiri Benc if (local->ops->sta_table_notification) 246f0706e82SJiri Benc local->ops->sta_table_notification(local_to_hw(local), 247f0706e82SJiri Benc local->num_sta); 248f0706e82SJiri Benc 249f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { 250f0706e82SJiri Benc local->total_ps_buffered--; 251f0706e82SJiri Benc dev_kfree_skb_any(skb); 252f0706e82SJiri Benc } 253f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { 254f0706e82SJiri Benc dev_kfree_skb_any(skb); 255f0706e82SJiri Benc } 256f0706e82SJiri Benc 257f0706e82SJiri Benc if (sta->key) { 258f0706e82SJiri Benc if (local->ops->set_key) { 259f0706e82SJiri Benc struct ieee80211_key_conf *key; 260f0706e82SJiri Benc key = ieee80211_key_data2conf(local, sta->key); 261f0706e82SJiri Benc if (key) { 262f0706e82SJiri Benc local->ops->set_key(local_to_hw(local), 263f0706e82SJiri Benc DISABLE_KEY, 264f0706e82SJiri Benc sta->addr, key, sta->aid); 265f0706e82SJiri Benc kfree(key); 266f0706e82SJiri Benc } 267f0706e82SJiri Benc } 268f0706e82SJiri Benc } else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) { 269f0706e82SJiri Benc struct ieee80211_key_conf conf; 270f0706e82SJiri Benc memset(&conf, 0, sizeof(conf)); 271f0706e82SJiri Benc conf.hw_key_idx = sta->key_idx_compression; 272f0706e82SJiri Benc conf.alg = ALG_NULL; 273f0706e82SJiri Benc conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; 274f0706e82SJiri Benc local->ops->set_key(local_to_hw(local), DISABLE_KEY, 275f0706e82SJiri Benc sta->addr, &conf, sta->aid); 276f0706e82SJiri Benc sta->key_idx_compression = HW_KEY_IDX_INVALID; 277f0706e82SJiri Benc } 278f0706e82SJiri Benc 279*e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 280*e9f207f0SJiri Benc if (in_atomic()) { 281*e9f207f0SJiri Benc list_add(&sta->list, &local->deleted_sta_list); 282*e9f207f0SJiri Benc queue_work(local->hw.workqueue, &local->sta_debugfs_add); 283*e9f207f0SJiri Benc } else 284*e9f207f0SJiri Benc #endif 285*e9f207f0SJiri Benc finish_sta_info_free(local, sta); 286f0706e82SJiri Benc } 287f0706e82SJiri Benc 288f0706e82SJiri Benc 289f0706e82SJiri Benc static inline int sta_info_buffer_expired(struct ieee80211_local *local, 290f0706e82SJiri Benc struct sta_info *sta, 291f0706e82SJiri Benc struct sk_buff *skb) 292f0706e82SJiri Benc { 293f0706e82SJiri Benc struct ieee80211_tx_packet_data *pkt_data; 294f0706e82SJiri Benc int timeout; 295f0706e82SJiri Benc 296f0706e82SJiri Benc if (!skb) 297f0706e82SJiri Benc return 0; 298f0706e82SJiri Benc 299f0706e82SJiri Benc pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; 300f0706e82SJiri Benc 301f0706e82SJiri Benc /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */ 302f0706e82SJiri Benc timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 / 303f0706e82SJiri Benc 15625) * HZ; 304f0706e82SJiri Benc if (timeout < STA_TX_BUFFER_EXPIRE) 305f0706e82SJiri Benc timeout = STA_TX_BUFFER_EXPIRE; 306f0706e82SJiri Benc return time_after(jiffies, pkt_data->jiffies + timeout); 307f0706e82SJiri Benc } 308f0706e82SJiri Benc 309f0706e82SJiri Benc 310f0706e82SJiri Benc static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, 311f0706e82SJiri Benc struct sta_info *sta) 312f0706e82SJiri Benc { 313f0706e82SJiri Benc unsigned long flags; 314f0706e82SJiri Benc struct sk_buff *skb; 315f0706e82SJiri Benc 316f0706e82SJiri Benc if (skb_queue_empty(&sta->ps_tx_buf)) 317f0706e82SJiri Benc return; 318f0706e82SJiri Benc 319f0706e82SJiri Benc for (;;) { 320f0706e82SJiri Benc spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); 321f0706e82SJiri Benc skb = skb_peek(&sta->ps_tx_buf); 322f0706e82SJiri Benc if (sta_info_buffer_expired(local, sta, skb)) { 323f0706e82SJiri Benc skb = __skb_dequeue(&sta->ps_tx_buf); 324f0706e82SJiri Benc if (skb_queue_empty(&sta->ps_tx_buf)) 325f0706e82SJiri Benc sta->flags &= ~WLAN_STA_TIM; 326f0706e82SJiri Benc } else 327f0706e82SJiri Benc skb = NULL; 328f0706e82SJiri Benc spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags); 329f0706e82SJiri Benc 330f0706e82SJiri Benc if (skb) { 331f0706e82SJiri Benc local->total_ps_buffered--; 332f0706e82SJiri Benc printk(KERN_DEBUG "Buffered frame expired (STA " 333f0706e82SJiri Benc MAC_FMT ")\n", MAC_ARG(sta->addr)); 334f0706e82SJiri Benc dev_kfree_skb(skb); 335f0706e82SJiri Benc } else 336f0706e82SJiri Benc break; 337f0706e82SJiri Benc } 338f0706e82SJiri Benc } 339f0706e82SJiri Benc 340f0706e82SJiri Benc 341f0706e82SJiri Benc static void sta_info_cleanup(unsigned long data) 342f0706e82SJiri Benc { 343f0706e82SJiri Benc struct ieee80211_local *local = (struct ieee80211_local *) data; 344f0706e82SJiri Benc struct sta_info *sta; 345f0706e82SJiri Benc 346f0706e82SJiri Benc spin_lock_bh(&local->sta_lock); 347f0706e82SJiri Benc list_for_each_entry(sta, &local->sta_list, list) { 348f0706e82SJiri Benc __sta_info_get(sta); 349f0706e82SJiri Benc sta_info_cleanup_expire_buffered(local, sta); 350f0706e82SJiri Benc sta_info_put(sta); 351f0706e82SJiri Benc } 352f0706e82SJiri Benc spin_unlock_bh(&local->sta_lock); 353f0706e82SJiri Benc 354f0706e82SJiri Benc local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; 355f0706e82SJiri Benc add_timer(&local->sta_cleanup); 356f0706e82SJiri Benc } 357f0706e82SJiri Benc 358*e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 359*e9f207f0SJiri Benc static void sta_info_debugfs_add_task(struct work_struct *work) 360*e9f207f0SJiri Benc { 361*e9f207f0SJiri Benc struct ieee80211_local *local = 362*e9f207f0SJiri Benc container_of(work, struct ieee80211_local, sta_debugfs_add); 363*e9f207f0SJiri Benc struct sta_info *sta, *tmp; 364*e9f207f0SJiri Benc 365*e9f207f0SJiri Benc while (1) { 366*e9f207f0SJiri Benc spin_lock_bh(&local->sta_lock); 367*e9f207f0SJiri Benc if (!list_empty(&local->deleted_sta_list)) { 368*e9f207f0SJiri Benc sta = list_entry(local->deleted_sta_list.next, 369*e9f207f0SJiri Benc struct sta_info, list); 370*e9f207f0SJiri Benc list_del(local->deleted_sta_list.next); 371*e9f207f0SJiri Benc } else 372*e9f207f0SJiri Benc sta = NULL; 373*e9f207f0SJiri Benc spin_unlock_bh(&local->sta_lock); 374*e9f207f0SJiri Benc if (!sta) 375*e9f207f0SJiri Benc break; 376*e9f207f0SJiri Benc finish_sta_info_free(local, sta); 377*e9f207f0SJiri Benc } 378*e9f207f0SJiri Benc 379*e9f207f0SJiri Benc while (1) { 380*e9f207f0SJiri Benc sta = NULL; 381*e9f207f0SJiri Benc spin_lock_bh(&local->sta_lock); 382*e9f207f0SJiri Benc list_for_each_entry(tmp, &local->sta_list, list) { 383*e9f207f0SJiri Benc if (!tmp->debugfs_registered) { 384*e9f207f0SJiri Benc sta = tmp; 385*e9f207f0SJiri Benc __sta_info_get(sta); 386*e9f207f0SJiri Benc break; 387*e9f207f0SJiri Benc } 388*e9f207f0SJiri Benc } 389*e9f207f0SJiri Benc spin_unlock_bh(&local->sta_lock); 390*e9f207f0SJiri Benc 391*e9f207f0SJiri Benc if (!sta) 392*e9f207f0SJiri Benc break; 393*e9f207f0SJiri Benc 394*e9f207f0SJiri Benc sta->debugfs_registered = 1; 395*e9f207f0SJiri Benc ieee80211_sta_debugfs_add(sta); 396*e9f207f0SJiri Benc rate_control_add_sta_debugfs(sta); 397*e9f207f0SJiri Benc sta_info_put(sta); 398*e9f207f0SJiri Benc } 399*e9f207f0SJiri Benc } 400*e9f207f0SJiri Benc #endif 401*e9f207f0SJiri Benc 402f0706e82SJiri Benc void sta_info_init(struct ieee80211_local *local) 403f0706e82SJiri Benc { 404f0706e82SJiri Benc spin_lock_init(&local->sta_lock); 405f0706e82SJiri Benc INIT_LIST_HEAD(&local->sta_list); 406f0706e82SJiri Benc INIT_LIST_HEAD(&local->deleted_sta_list); 407f0706e82SJiri Benc 408f0706e82SJiri Benc init_timer(&local->sta_cleanup); 409f0706e82SJiri Benc local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; 410f0706e82SJiri Benc local->sta_cleanup.data = (unsigned long) local; 411f0706e82SJiri Benc local->sta_cleanup.function = sta_info_cleanup; 412*e9f207f0SJiri Benc 413*e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 414*e9f207f0SJiri Benc INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task); 415*e9f207f0SJiri Benc #endif 416f0706e82SJiri Benc } 417f0706e82SJiri Benc 418f0706e82SJiri Benc int sta_info_start(struct ieee80211_local *local) 419f0706e82SJiri Benc { 420f0706e82SJiri Benc add_timer(&local->sta_cleanup); 421f0706e82SJiri Benc return 0; 422f0706e82SJiri Benc } 423f0706e82SJiri Benc 424f0706e82SJiri Benc void sta_info_stop(struct ieee80211_local *local) 425f0706e82SJiri Benc { 426f0706e82SJiri Benc struct sta_info *sta, *tmp; 427f0706e82SJiri Benc 428f0706e82SJiri Benc del_timer(&local->sta_cleanup); 429f0706e82SJiri Benc 430f0706e82SJiri Benc list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { 431*e9f207f0SJiri Benc /* sta_info_free must be called with 0 as the last 432*e9f207f0SJiri Benc * parameter to ensure all debugfs sta entries are 433*e9f207f0SJiri Benc * unregistered. We don't need locking at this 434*e9f207f0SJiri Benc * point. */ 435f0706e82SJiri Benc sta_info_free(sta, 0); 436f0706e82SJiri Benc } 437f0706e82SJiri Benc } 438f0706e82SJiri Benc 439f0706e82SJiri Benc void sta_info_remove_aid_ptr(struct sta_info *sta) 440f0706e82SJiri Benc { 441f0706e82SJiri Benc struct ieee80211_sub_if_data *sdata; 442f0706e82SJiri Benc 443f0706e82SJiri Benc if (sta->aid <= 0) 444f0706e82SJiri Benc return; 445f0706e82SJiri Benc 446f0706e82SJiri Benc sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 447f0706e82SJiri Benc 448f0706e82SJiri Benc if (sdata->local->ops->set_tim) 449f0706e82SJiri Benc sdata->local->ops->set_tim(local_to_hw(sdata->local), 450f0706e82SJiri Benc sta->aid, 0); 451f0706e82SJiri Benc if (sdata->bss) 452f0706e82SJiri Benc __bss_tim_clear(sdata->bss, sta->aid); 453f0706e82SJiri Benc } 454f0706e82SJiri Benc 455f0706e82SJiri Benc 456f0706e82SJiri Benc /** 457f0706e82SJiri Benc * sta_info_flush - flush matching STA entries from the STA table 458f0706e82SJiri Benc * @local: local interface data 459f0706e82SJiri Benc * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs 460f0706e82SJiri Benc */ 461f0706e82SJiri Benc void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) 462f0706e82SJiri Benc { 463f0706e82SJiri Benc struct sta_info *sta, *tmp; 464f0706e82SJiri Benc 465f0706e82SJiri Benc spin_lock_bh(&local->sta_lock); 466f0706e82SJiri Benc list_for_each_entry_safe(sta, tmp, &local->sta_list, list) 467f0706e82SJiri Benc if (!dev || dev == sta->dev) 468f0706e82SJiri Benc sta_info_free(sta, 1); 469f0706e82SJiri Benc spin_unlock_bh(&local->sta_lock); 470f0706e82SJiri Benc } 471