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> 170d174406SJohannes Berg #include <linux/timer.h> 18f0706e82SJiri Benc 19f0706e82SJiri Benc #include <net/mac80211.h> 20f0706e82SJiri Benc #include "ieee80211_i.h" 21f0706e82SJiri Benc #include "ieee80211_rate.h" 22f0706e82SJiri Benc #include "sta_info.h" 23e9f207f0SJiri 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 */ 35be8755e1SMichael Wu static int 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) 42be8755e1SMichael Wu return -ENOENT; 43be8755e1SMichael Wu if (s == sta) { 44f0706e82SJiri Benc local->sta_hash[STA_HASH(sta->addr)] = s->hnext; 45be8755e1SMichael Wu return 0; 46f0706e82SJiri Benc } 47f0706e82SJiri Benc 48be8755e1SMichael Wu while (s->hnext && s->hnext != sta) 49f0706e82SJiri Benc s = s->hnext; 50be8755e1SMichael Wu if (s->hnext) { 51be8755e1SMichael Wu s->hnext = sta->hnext; 52be8755e1SMichael Wu return 0; 53f0706e82SJiri Benc } 54f0706e82SJiri Benc 55be8755e1SMichael Wu return -ENOENT; 56f0706e82SJiri Benc } 57f0706e82SJiri Benc 58*43ba7e95SJohannes Berg /* must hold local->sta_lock */ 59*43ba7e95SJohannes Berg static struct sta_info *__sta_info_find(struct ieee80211_local *local, 60*43ba7e95SJohannes Berg u8 *addr) 61*43ba7e95SJohannes Berg { 62*43ba7e95SJohannes Berg struct sta_info *sta; 63*43ba7e95SJohannes Berg 64*43ba7e95SJohannes Berg sta = local->sta_hash[STA_HASH(addr)]; 65*43ba7e95SJohannes Berg while (sta) { 66*43ba7e95SJohannes Berg if (compare_ether_addr(sta->addr, addr) == 0) 67*43ba7e95SJohannes Berg break; 68*43ba7e95SJohannes Berg sta = sta->hnext; 69*43ba7e95SJohannes Berg } 70*43ba7e95SJohannes Berg return sta; 71*43ba7e95SJohannes Berg } 72*43ba7e95SJohannes Berg 73f0706e82SJiri Benc struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) 74f0706e82SJiri Benc { 75f0706e82SJiri Benc struct sta_info *sta; 76f0706e82SJiri Benc 77be8755e1SMichael Wu read_lock_bh(&local->sta_lock); 78*43ba7e95SJohannes Berg sta = __sta_info_find(local, addr); 79*43ba7e95SJohannes Berg if (sta) 80f0706e82SJiri Benc __sta_info_get(sta); 81be8755e1SMichael Wu read_unlock_bh(&local->sta_lock); 82f0706e82SJiri Benc 83f0706e82SJiri Benc return sta; 84f0706e82SJiri Benc } 85f0706e82SJiri Benc EXPORT_SYMBOL(sta_info_get); 86f0706e82SJiri Benc 87f0706e82SJiri Benc 88f0706e82SJiri Benc static void sta_info_release(struct kref *kref) 89f0706e82SJiri Benc { 90f0706e82SJiri Benc struct sta_info *sta = container_of(kref, struct sta_info, kref); 91f0706e82SJiri Benc struct ieee80211_local *local = sta->local; 92f0706e82SJiri Benc struct sk_buff *skb; 9307db2183SRon Rindjunsky int i; 94f0706e82SJiri Benc 95f0706e82SJiri Benc /* free sta structure; it has already been removed from 96f0706e82SJiri Benc * hash table etc. external structures. Make sure that all 97f0706e82SJiri Benc * buffered frames are release (one might have been added 98f0706e82SJiri Benc * after sta_info_free() was called). */ 99f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { 100f0706e82SJiri Benc local->total_ps_buffered--; 101f0706e82SJiri Benc dev_kfree_skb_any(skb); 102f0706e82SJiri Benc } 103f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { 104f0706e82SJiri Benc dev_kfree_skb_any(skb); 105f0706e82SJiri Benc } 106fe3bf0f5SRon Rindjunsky for (i = 0; i < STA_TID_NUM; i++) { 10707db2183SRon Rindjunsky del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); 108fe3bf0f5SRon Rindjunsky del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); 109fe3bf0f5SRon Rindjunsky } 110f0706e82SJiri Benc rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); 111f0706e82SJiri Benc rate_control_put(sta->rate_ctrl); 112f0706e82SJiri Benc kfree(sta); 113f0706e82SJiri Benc } 114f0706e82SJiri Benc 115f0706e82SJiri Benc 116f0706e82SJiri Benc void sta_info_put(struct sta_info *sta) 117f0706e82SJiri Benc { 118f0706e82SJiri Benc kref_put(&sta->kref, sta_info_release); 119f0706e82SJiri Benc } 120f0706e82SJiri Benc EXPORT_SYMBOL(sta_info_put); 121f0706e82SJiri Benc 122f0706e82SJiri Benc 123f0706e82SJiri Benc struct sta_info *sta_info_add(struct ieee80211_local *local, 124f0706e82SJiri Benc struct net_device *dev, u8 *addr, gfp_t gfp) 125f0706e82SJiri Benc { 126f0706e82SJiri Benc struct sta_info *sta; 12716c5f15cSRon Rindjunsky int i; 1280795af57SJoe Perches DECLARE_MAC_BUF(mac); 129f0706e82SJiri Benc 130f0706e82SJiri Benc sta = kzalloc(sizeof(*sta), gfp); 131f0706e82SJiri Benc if (!sta) 132*43ba7e95SJohannes Berg return ERR_PTR(-ENOMEM); 133f0706e82SJiri Benc 134f0706e82SJiri Benc kref_init(&sta->kref); 135f0706e82SJiri Benc 136f0706e82SJiri Benc sta->rate_ctrl = rate_control_get(local->rate_ctrl); 137f0706e82SJiri Benc sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); 138f0706e82SJiri Benc if (!sta->rate_ctrl_priv) { 139f0706e82SJiri Benc rate_control_put(sta->rate_ctrl); 140f0706e82SJiri Benc kfree(sta); 141*43ba7e95SJohannes Berg return ERR_PTR(-ENOMEM); 142f0706e82SJiri Benc } 143f0706e82SJiri Benc 144f0706e82SJiri Benc memcpy(sta->addr, addr, ETH_ALEN); 145f0706e82SJiri Benc sta->local = local; 146f0706e82SJiri Benc sta->dev = dev; 14716c5f15cSRon Rindjunsky spin_lock_init(&sta->ampdu_mlme.ampdu_rx); 148fe3bf0f5SRon Rindjunsky spin_lock_init(&sta->ampdu_mlme.ampdu_tx); 14916c5f15cSRon Rindjunsky for (i = 0; i < STA_TID_NUM; i++) { 15016c5f15cSRon Rindjunsky /* timer_to_tid must be initialized with identity mapping to 15116c5f15cSRon Rindjunsky * enable session_timer's data differentiation. refer to 15216c5f15cSRon Rindjunsky * sta_rx_agg_session_timer_expired for useage */ 15316c5f15cSRon Rindjunsky sta->timer_to_tid[i] = i; 154fe3bf0f5SRon Rindjunsky /* tid to tx queue: initialize according to HW (0 is valid) */ 155fe3bf0f5SRon Rindjunsky sta->tid_to_tx_q[i] = local->hw.queues; 15616c5f15cSRon Rindjunsky /* rx timers */ 15716c5f15cSRon Rindjunsky sta->ampdu_mlme.tid_rx[i].session_timer.function = 15816c5f15cSRon Rindjunsky sta_rx_agg_session_timer_expired; 15916c5f15cSRon Rindjunsky sta->ampdu_mlme.tid_rx[i].session_timer.data = 16016c5f15cSRon Rindjunsky (unsigned long)&sta->timer_to_tid[i]; 16116c5f15cSRon Rindjunsky init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer); 162fe3bf0f5SRon Rindjunsky /* tx timers */ 163fe3bf0f5SRon Rindjunsky sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function = 164fe3bf0f5SRon Rindjunsky sta_addba_resp_timer_expired; 165fe3bf0f5SRon Rindjunsky sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data = 166fe3bf0f5SRon Rindjunsky (unsigned long)&sta->timer_to_tid[i]; 167fe3bf0f5SRon Rindjunsky init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); 16816c5f15cSRon Rindjunsky } 169f0706e82SJiri Benc skb_queue_head_init(&sta->ps_tx_buf); 170f0706e82SJiri Benc skb_queue_head_init(&sta->tx_filtered); 171be8755e1SMichael Wu write_lock_bh(&local->sta_lock); 172*43ba7e95SJohannes Berg /* mark sta as used (by caller) */ 173*43ba7e95SJohannes Berg __sta_info_get(sta); 174*43ba7e95SJohannes Berg /* check if STA exists already */ 175*43ba7e95SJohannes Berg if (__sta_info_find(local, addr)) { 176*43ba7e95SJohannes Berg write_unlock_bh(&local->sta_lock); 177*43ba7e95SJohannes Berg sta_info_put(sta); 178*43ba7e95SJohannes Berg return ERR_PTR(-EEXIST); 179*43ba7e95SJohannes Berg } 180f0706e82SJiri Benc list_add(&sta->list, &local->sta_list); 181f0706e82SJiri Benc local->num_sta++; 182f0706e82SJiri Benc sta_info_hash_add(local, sta); 18332bfd35dSJohannes Berg if (local->ops->sta_notify) { 18432bfd35dSJohannes Berg struct ieee80211_sub_if_data *sdata; 18532bfd35dSJohannes Berg 18632bfd35dSJohannes Berg sdata = IEEE80211_DEV_TO_SUB_IF(dev); 18751fb61e7SJohannes Berg if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) 18832bfd35dSJohannes Berg sdata = sdata->u.vlan.ap; 18932bfd35dSJohannes Berg 19032bfd35dSJohannes Berg local->ops->sta_notify(local_to_hw(local), &sdata->vif, 191478f8d2bSTomas Winkler STA_NOTIFY_ADD, addr); 19232bfd35dSJohannes Berg } 193be8755e1SMichael Wu write_unlock_bh(&local->sta_lock); 194f0706e82SJiri Benc 195f0706e82SJiri Benc #ifdef CONFIG_MAC80211_VERBOSE_DEBUG 1960795af57SJoe Perches printk(KERN_DEBUG "%s: Added STA %s\n", 197dd1cd4c6SJohannes Berg wiphy_name(local->hw.wiphy), print_mac(mac, addr)); 198f0706e82SJiri Benc #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 199f0706e82SJiri Benc 200e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 201e9f207f0SJiri Benc /* debugfs entry adding might sleep, so schedule process 202e9f207f0SJiri Benc * context task for adding entry for STAs that do not yet 203e9f207f0SJiri Benc * have one. */ 204e9f207f0SJiri Benc queue_work(local->hw.workqueue, &local->sta_debugfs_add); 205e9f207f0SJiri Benc #endif 206e9f207f0SJiri Benc 207f0706e82SJiri Benc return sta; 208f0706e82SJiri Benc } 209f0706e82SJiri Benc 210004c872eSJohannes Berg static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) 211004c872eSJohannes Berg { 212004c872eSJohannes Berg /* 213004c872eSJohannes Berg * This format has been mandated by the IEEE specifications, 214004c872eSJohannes Berg * so this line may not be changed to use the __set_bit() format. 215004c872eSJohannes Berg */ 216004c872eSJohannes Berg bss->tim[aid / 8] |= (1 << (aid % 8)); 217004c872eSJohannes Berg } 218004c872eSJohannes Berg 219004c872eSJohannes Berg static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) 220004c872eSJohannes Berg { 221004c872eSJohannes Berg /* 222004c872eSJohannes Berg * This format has been mandated by the IEEE specifications, 223004c872eSJohannes Berg * so this line may not be changed to use the __clear_bit() format. 224004c872eSJohannes Berg */ 225004c872eSJohannes Berg bss->tim[aid / 8] &= ~(1 << (aid % 8)); 226004c872eSJohannes Berg } 227004c872eSJohannes Berg 228004c872eSJohannes Berg static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, 229004c872eSJohannes Berg struct sta_info *sta) 230004c872eSJohannes Berg { 231004c872eSJohannes Berg if (bss) 232004c872eSJohannes Berg __bss_tim_set(bss, sta->aid); 233004c872eSJohannes Berg if (sta->local->ops->set_tim) 234004c872eSJohannes Berg sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); 235004c872eSJohannes Berg } 236004c872eSJohannes Berg 237004c872eSJohannes Berg void sta_info_set_tim_bit(struct sta_info *sta) 238004c872eSJohannes Berg { 239004c872eSJohannes Berg struct ieee80211_sub_if_data *sdata; 240004c872eSJohannes Berg 241004c872eSJohannes Berg sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 242004c872eSJohannes Berg 243004c872eSJohannes Berg read_lock_bh(&sta->local->sta_lock); 244004c872eSJohannes Berg __sta_info_set_tim_bit(sdata->bss, sta); 245004c872eSJohannes Berg read_unlock_bh(&sta->local->sta_lock); 246004c872eSJohannes Berg } 247004c872eSJohannes Berg 248004c872eSJohannes Berg static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, 249004c872eSJohannes Berg struct sta_info *sta) 250004c872eSJohannes Berg { 251004c872eSJohannes Berg if (bss) 252004c872eSJohannes Berg __bss_tim_clear(bss, sta->aid); 253004c872eSJohannes Berg if (sta->local->ops->set_tim) 254004c872eSJohannes Berg sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); 255004c872eSJohannes Berg } 256004c872eSJohannes Berg 257004c872eSJohannes Berg void sta_info_clear_tim_bit(struct sta_info *sta) 258004c872eSJohannes Berg { 259004c872eSJohannes Berg struct ieee80211_sub_if_data *sdata; 260004c872eSJohannes Berg 261004c872eSJohannes Berg sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 262004c872eSJohannes Berg 263004c872eSJohannes Berg read_lock_bh(&sta->local->sta_lock); 264004c872eSJohannes Berg __sta_info_clear_tim_bit(sdata->bss, sta); 265004c872eSJohannes Berg read_unlock_bh(&sta->local->sta_lock); 266004c872eSJohannes Berg } 267004c872eSJohannes Berg 268be8755e1SMichael Wu /* Caller must hold local->sta_lock */ 269be8755e1SMichael Wu void sta_info_remove(struct sta_info *sta) 270f0706e82SJiri Benc { 271f0706e82SJiri Benc struct ieee80211_local *local = sta->local; 272f0706e82SJiri Benc struct ieee80211_sub_if_data *sdata; 273f0706e82SJiri Benc 274be8755e1SMichael Wu /* don't do anything if we've been removed already */ 275be8755e1SMichael Wu if (sta_info_hash_del(local, sta)) 276be8755e1SMichael Wu return; 277be8755e1SMichael Wu 278f0706e82SJiri Benc list_del(&sta->list); 279f0706e82SJiri Benc sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 280f0706e82SJiri Benc if (sta->flags & WLAN_STA_PS) { 281f0706e82SJiri Benc sta->flags &= ~WLAN_STA_PS; 282f0706e82SJiri Benc if (sdata->bss) 283f0706e82SJiri Benc atomic_dec(&sdata->bss->num_sta_ps); 284004c872eSJohannes Berg __sta_info_clear_tim_bit(sdata->bss, sta); 285f0706e82SJiri Benc } 286f0706e82SJiri Benc local->num_sta--; 287f0706e82SJiri Benc } 288f0706e82SJiri Benc 289be8755e1SMichael Wu void sta_info_free(struct sta_info *sta) 290f0706e82SJiri Benc { 291f0706e82SJiri Benc struct sk_buff *skb; 292f0706e82SJiri Benc struct ieee80211_local *local = sta->local; 2930795af57SJoe Perches DECLARE_MAC_BUF(mac); 294f0706e82SJiri Benc 295be8755e1SMichael Wu might_sleep(); 296be8755e1SMichael Wu 297be8755e1SMichael Wu write_lock_bh(&local->sta_lock); 298f0706e82SJiri Benc sta_info_remove(sta); 299be8755e1SMichael Wu write_unlock_bh(&local->sta_lock); 300f0706e82SJiri Benc 301f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { 302f0706e82SJiri Benc local->total_ps_buffered--; 303be8755e1SMichael Wu dev_kfree_skb(skb); 304f0706e82SJiri Benc } 305f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { 306be8755e1SMichael Wu dev_kfree_skb(skb); 307f0706e82SJiri Benc } 308f0706e82SJiri Benc 309be8755e1SMichael Wu #ifdef CONFIG_MAC80211_VERBOSE_DEBUG 3100795af57SJoe Perches printk(KERN_DEBUG "%s: Removed STA %s\n", 311dd1cd4c6SJohannes Berg wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); 312be8755e1SMichael Wu #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 313be8755e1SMichael Wu 314be8755e1SMichael Wu ieee80211_key_free(sta->key); 315be8755e1SMichael Wu sta->key = NULL; 316be8755e1SMichael Wu 31732bfd35dSJohannes Berg if (local->ops->sta_notify) { 31832bfd35dSJohannes Berg struct ieee80211_sub_if_data *sdata; 31932bfd35dSJohannes Berg 32032bfd35dSJohannes Berg sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 32132bfd35dSJohannes Berg 32251fb61e7SJohannes Berg if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) 32332bfd35dSJohannes Berg sdata = sdata->u.vlan.ap; 32432bfd35dSJohannes Berg 32532bfd35dSJohannes Berg local->ops->sta_notify(local_to_hw(local), &sdata->vif, 326478f8d2bSTomas Winkler STA_NOTIFY_REMOVE, sta->addr); 32732bfd35dSJohannes Berg } 328478f8d2bSTomas Winkler 329be8755e1SMichael Wu rate_control_remove_sta_debugfs(sta); 330be8755e1SMichael Wu ieee80211_sta_debugfs_remove(sta); 331be8755e1SMichael Wu 332be8755e1SMichael Wu sta_info_put(sta); 333f0706e82SJiri Benc } 334f0706e82SJiri Benc 335f0706e82SJiri Benc 336f0706e82SJiri Benc static inline int sta_info_buffer_expired(struct ieee80211_local *local, 337f0706e82SJiri Benc struct sta_info *sta, 338f0706e82SJiri Benc struct sk_buff *skb) 339f0706e82SJiri Benc { 340f0706e82SJiri Benc struct ieee80211_tx_packet_data *pkt_data; 341f0706e82SJiri Benc int timeout; 342f0706e82SJiri Benc 343f0706e82SJiri Benc if (!skb) 344f0706e82SJiri Benc return 0; 345f0706e82SJiri Benc 346f0706e82SJiri Benc pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; 347f0706e82SJiri Benc 348f0706e82SJiri Benc /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */ 349f0706e82SJiri Benc timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 / 350f0706e82SJiri Benc 15625) * HZ; 351f0706e82SJiri Benc if (timeout < STA_TX_BUFFER_EXPIRE) 352f0706e82SJiri Benc timeout = STA_TX_BUFFER_EXPIRE; 353f0706e82SJiri Benc return time_after(jiffies, pkt_data->jiffies + timeout); 354f0706e82SJiri Benc } 355f0706e82SJiri Benc 356f0706e82SJiri Benc 357f0706e82SJiri Benc static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, 358f0706e82SJiri Benc struct sta_info *sta) 359f0706e82SJiri Benc { 360f0706e82SJiri Benc unsigned long flags; 361f0706e82SJiri Benc struct sk_buff *skb; 362836341a7SJohannes Berg struct ieee80211_sub_if_data *sdata; 3630795af57SJoe Perches DECLARE_MAC_BUF(mac); 364f0706e82SJiri Benc 365f0706e82SJiri Benc if (skb_queue_empty(&sta->ps_tx_buf)) 366f0706e82SJiri Benc return; 367f0706e82SJiri Benc 368f0706e82SJiri Benc for (;;) { 369f0706e82SJiri Benc spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); 370f0706e82SJiri Benc skb = skb_peek(&sta->ps_tx_buf); 371836341a7SJohannes Berg if (sta_info_buffer_expired(local, sta, skb)) 372f0706e82SJiri Benc skb = __skb_dequeue(&sta->ps_tx_buf); 373836341a7SJohannes Berg else 374f0706e82SJiri Benc skb = NULL; 375f0706e82SJiri Benc spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags); 376f0706e82SJiri Benc 377836341a7SJohannes Berg if (!skb) 378836341a7SJohannes Berg break; 379836341a7SJohannes Berg 380836341a7SJohannes Berg sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 381f0706e82SJiri Benc local->total_ps_buffered--; 382f0706e82SJiri Benc printk(KERN_DEBUG "Buffered frame expired (STA " 3830795af57SJoe Perches "%s)\n", print_mac(mac, sta->addr)); 384f0706e82SJiri Benc dev_kfree_skb(skb); 385836341a7SJohannes Berg 386004c872eSJohannes Berg if (skb_queue_empty(&sta->ps_tx_buf)) 387004c872eSJohannes Berg sta_info_clear_tim_bit(sta); 388f0706e82SJiri Benc } 389f0706e82SJiri Benc } 390f0706e82SJiri Benc 391f0706e82SJiri Benc 392f0706e82SJiri Benc static void sta_info_cleanup(unsigned long data) 393f0706e82SJiri Benc { 394f0706e82SJiri Benc struct ieee80211_local *local = (struct ieee80211_local *) data; 395f0706e82SJiri Benc struct sta_info *sta; 396f0706e82SJiri Benc 397be8755e1SMichael Wu read_lock_bh(&local->sta_lock); 398f0706e82SJiri Benc list_for_each_entry(sta, &local->sta_list, list) { 399f0706e82SJiri Benc __sta_info_get(sta); 400f0706e82SJiri Benc sta_info_cleanup_expire_buffered(local, sta); 401f0706e82SJiri Benc sta_info_put(sta); 402f0706e82SJiri Benc } 403be8755e1SMichael Wu read_unlock_bh(&local->sta_lock); 404f0706e82SJiri Benc 4050d174406SJohannes Berg local->sta_cleanup.expires = 4060d174406SJohannes Berg round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); 407f0706e82SJiri Benc add_timer(&local->sta_cleanup); 408f0706e82SJiri Benc } 409f0706e82SJiri Benc 410e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 411e9f207f0SJiri Benc static void sta_info_debugfs_add_task(struct work_struct *work) 412e9f207f0SJiri Benc { 413e9f207f0SJiri Benc struct ieee80211_local *local = 414e9f207f0SJiri Benc container_of(work, struct ieee80211_local, sta_debugfs_add); 415e9f207f0SJiri Benc struct sta_info *sta, *tmp; 416e9f207f0SJiri Benc 417e9f207f0SJiri Benc while (1) { 418e9f207f0SJiri Benc sta = NULL; 419be8755e1SMichael Wu read_lock_bh(&local->sta_lock); 420e9f207f0SJiri Benc list_for_each_entry(tmp, &local->sta_list, list) { 421be8755e1SMichael Wu if (!tmp->debugfs.dir) { 422e9f207f0SJiri Benc sta = tmp; 423e9f207f0SJiri Benc __sta_info_get(sta); 424e9f207f0SJiri Benc break; 425e9f207f0SJiri Benc } 426e9f207f0SJiri Benc } 427be8755e1SMichael Wu read_unlock_bh(&local->sta_lock); 428e9f207f0SJiri Benc 429e9f207f0SJiri Benc if (!sta) 430e9f207f0SJiri Benc break; 431e9f207f0SJiri Benc 432e9f207f0SJiri Benc ieee80211_sta_debugfs_add(sta); 433e9f207f0SJiri Benc rate_control_add_sta_debugfs(sta); 434e9f207f0SJiri Benc sta_info_put(sta); 435e9f207f0SJiri Benc } 436e9f207f0SJiri Benc } 437e9f207f0SJiri Benc #endif 438e9f207f0SJiri Benc 439f0706e82SJiri Benc void sta_info_init(struct ieee80211_local *local) 440f0706e82SJiri Benc { 441be8755e1SMichael Wu rwlock_init(&local->sta_lock); 442f0706e82SJiri Benc INIT_LIST_HEAD(&local->sta_list); 443f0706e82SJiri Benc 444b24b8a24SPavel Emelyanov setup_timer(&local->sta_cleanup, sta_info_cleanup, 445b24b8a24SPavel Emelyanov (unsigned long)local); 4460d174406SJohannes Berg local->sta_cleanup.expires = 4470d174406SJohannes Berg round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); 448e9f207f0SJiri Benc 449e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 450e9f207f0SJiri Benc INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task); 451e9f207f0SJiri Benc #endif 452f0706e82SJiri Benc } 453f0706e82SJiri Benc 454f0706e82SJiri Benc int sta_info_start(struct ieee80211_local *local) 455f0706e82SJiri Benc { 456f0706e82SJiri Benc add_timer(&local->sta_cleanup); 457f0706e82SJiri Benc return 0; 458f0706e82SJiri Benc } 459f0706e82SJiri Benc 460f0706e82SJiri Benc void sta_info_stop(struct ieee80211_local *local) 461f0706e82SJiri Benc { 462f0706e82SJiri Benc del_timer(&local->sta_cleanup); 463be8755e1SMichael Wu sta_info_flush(local, NULL); 464f0706e82SJiri Benc } 465f0706e82SJiri Benc 466f0706e82SJiri Benc /** 467f0706e82SJiri Benc * sta_info_flush - flush matching STA entries from the STA table 468f0706e82SJiri Benc * @local: local interface data 469f0706e82SJiri Benc * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs 470f0706e82SJiri Benc */ 471f0706e82SJiri Benc void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) 472f0706e82SJiri Benc { 473f0706e82SJiri Benc struct sta_info *sta, *tmp; 474be8755e1SMichael Wu LIST_HEAD(tmp_list); 475f0706e82SJiri Benc 476be8755e1SMichael Wu write_lock_bh(&local->sta_lock); 477f0706e82SJiri Benc list_for_each_entry_safe(sta, tmp, &local->sta_list, list) 478be8755e1SMichael Wu if (!dev || dev == sta->dev) { 479be8755e1SMichael Wu __sta_info_get(sta); 480be8755e1SMichael Wu sta_info_remove(sta); 481be8755e1SMichael Wu list_add_tail(&sta->list, &tmp_list); 482be8755e1SMichael Wu } 483be8755e1SMichael Wu write_unlock_bh(&local->sta_lock); 484be8755e1SMichael Wu 485be8755e1SMichael Wu list_for_each_entry_safe(sta, tmp, &tmp_list, list) { 486be8755e1SMichael Wu sta_info_free(sta); 487be8755e1SMichael Wu sta_info_put(sta); 488be8755e1SMichael Wu } 489f0706e82SJiri Benc } 490