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" 24*ee385855SLuis Carlos Cobo #ifdef CONFIG_MAC80211_MESH 25*ee385855SLuis Carlos Cobo #include "mesh.h" 26*ee385855SLuis Carlos Cobo #endif 27f0706e82SJiri Benc 28f0706e82SJiri Benc /* Caller must hold local->sta_lock */ 29f0706e82SJiri Benc static void sta_info_hash_add(struct ieee80211_local *local, 30f0706e82SJiri Benc struct sta_info *sta) 31f0706e82SJiri Benc { 32f0706e82SJiri Benc sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; 33f0706e82SJiri Benc local->sta_hash[STA_HASH(sta->addr)] = sta; 34f0706e82SJiri Benc } 35f0706e82SJiri Benc 36f0706e82SJiri Benc 37f0706e82SJiri Benc /* Caller must hold local->sta_lock */ 38be8755e1SMichael Wu static int sta_info_hash_del(struct ieee80211_local *local, 39f0706e82SJiri Benc struct sta_info *sta) 40f0706e82SJiri Benc { 41f0706e82SJiri Benc struct sta_info *s; 42f0706e82SJiri Benc 43f0706e82SJiri Benc s = local->sta_hash[STA_HASH(sta->addr)]; 44f0706e82SJiri Benc if (!s) 45be8755e1SMichael Wu return -ENOENT; 46be8755e1SMichael Wu if (s == sta) { 47f0706e82SJiri Benc local->sta_hash[STA_HASH(sta->addr)] = s->hnext; 48be8755e1SMichael Wu return 0; 49f0706e82SJiri Benc } 50f0706e82SJiri Benc 51be8755e1SMichael Wu while (s->hnext && s->hnext != sta) 52f0706e82SJiri Benc s = s->hnext; 53be8755e1SMichael Wu if (s->hnext) { 54be8755e1SMichael Wu s->hnext = sta->hnext; 55be8755e1SMichael Wu return 0; 56f0706e82SJiri Benc } 57f0706e82SJiri Benc 58be8755e1SMichael Wu return -ENOENT; 59f0706e82SJiri Benc } 60f0706e82SJiri Benc 6143ba7e95SJohannes Berg /* must hold local->sta_lock */ 6243ba7e95SJohannes Berg static struct sta_info *__sta_info_find(struct ieee80211_local *local, 6343ba7e95SJohannes Berg u8 *addr) 6443ba7e95SJohannes Berg { 6543ba7e95SJohannes Berg struct sta_info *sta; 6643ba7e95SJohannes Berg 6743ba7e95SJohannes Berg sta = local->sta_hash[STA_HASH(addr)]; 6843ba7e95SJohannes Berg while (sta) { 6943ba7e95SJohannes Berg if (compare_ether_addr(sta->addr, addr) == 0) 7043ba7e95SJohannes Berg break; 7143ba7e95SJohannes Berg sta = sta->hnext; 7243ba7e95SJohannes Berg } 7343ba7e95SJohannes Berg return sta; 7443ba7e95SJohannes Berg } 7543ba7e95SJohannes Berg 76f0706e82SJiri Benc struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) 77f0706e82SJiri Benc { 78f0706e82SJiri Benc struct sta_info *sta; 79f0706e82SJiri Benc 80be8755e1SMichael Wu read_lock_bh(&local->sta_lock); 8143ba7e95SJohannes Berg sta = __sta_info_find(local, addr); 8243ba7e95SJohannes Berg if (sta) 83f0706e82SJiri Benc __sta_info_get(sta); 84be8755e1SMichael Wu read_unlock_bh(&local->sta_lock); 85f0706e82SJiri Benc 86f0706e82SJiri Benc return sta; 87f0706e82SJiri Benc } 88f0706e82SJiri Benc EXPORT_SYMBOL(sta_info_get); 89f0706e82SJiri Benc 90*ee385855SLuis Carlos Cobo struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, 91*ee385855SLuis Carlos Cobo struct net_device *dev) 92*ee385855SLuis Carlos Cobo { 93*ee385855SLuis Carlos Cobo struct sta_info *sta; 94*ee385855SLuis Carlos Cobo int i = 0; 95*ee385855SLuis Carlos Cobo 96*ee385855SLuis Carlos Cobo read_lock_bh(&local->sta_lock); 97*ee385855SLuis Carlos Cobo list_for_each_entry(sta, &local->sta_list, list) { 98*ee385855SLuis Carlos Cobo if (i < idx) { 99*ee385855SLuis Carlos Cobo ++i; 100*ee385855SLuis Carlos Cobo continue; 101*ee385855SLuis Carlos Cobo } else if (!dev || dev == sta->dev) { 102*ee385855SLuis Carlos Cobo __sta_info_get(sta); 103*ee385855SLuis Carlos Cobo read_unlock_bh(&local->sta_lock); 104*ee385855SLuis Carlos Cobo return sta; 105*ee385855SLuis Carlos Cobo } 106*ee385855SLuis Carlos Cobo } 107*ee385855SLuis Carlos Cobo read_unlock_bh(&local->sta_lock); 108*ee385855SLuis Carlos Cobo 109*ee385855SLuis Carlos Cobo return NULL; 110*ee385855SLuis Carlos Cobo } 111f0706e82SJiri Benc 112f0706e82SJiri Benc static void sta_info_release(struct kref *kref) 113f0706e82SJiri Benc { 114f0706e82SJiri Benc struct sta_info *sta = container_of(kref, struct sta_info, kref); 115f0706e82SJiri Benc struct ieee80211_local *local = sta->local; 116f0706e82SJiri Benc struct sk_buff *skb; 11707db2183SRon Rindjunsky int i; 118f0706e82SJiri Benc 119f0706e82SJiri Benc /* free sta structure; it has already been removed from 120f0706e82SJiri Benc * hash table etc. external structures. Make sure that all 121f0706e82SJiri Benc * buffered frames are release (one might have been added 122f0706e82SJiri Benc * after sta_info_free() was called). */ 123f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { 124f0706e82SJiri Benc local->total_ps_buffered--; 125f0706e82SJiri Benc dev_kfree_skb_any(skb); 126f0706e82SJiri Benc } 127f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { 128f0706e82SJiri Benc dev_kfree_skb_any(skb); 129f0706e82SJiri Benc } 130fe3bf0f5SRon Rindjunsky for (i = 0; i < STA_TID_NUM; i++) { 13107db2183SRon Rindjunsky del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); 132fe3bf0f5SRon Rindjunsky del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); 133fe3bf0f5SRon Rindjunsky } 134f0706e82SJiri Benc rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); 135f0706e82SJiri Benc rate_control_put(sta->rate_ctrl); 136f0706e82SJiri Benc kfree(sta); 137f0706e82SJiri Benc } 138f0706e82SJiri Benc 139f0706e82SJiri Benc 140f0706e82SJiri Benc void sta_info_put(struct sta_info *sta) 141f0706e82SJiri Benc { 142f0706e82SJiri Benc kref_put(&sta->kref, sta_info_release); 143f0706e82SJiri Benc } 144f0706e82SJiri Benc EXPORT_SYMBOL(sta_info_put); 145f0706e82SJiri Benc 146f0706e82SJiri Benc 147f0706e82SJiri Benc struct sta_info *sta_info_add(struct ieee80211_local *local, 148f0706e82SJiri Benc struct net_device *dev, u8 *addr, gfp_t gfp) 149f0706e82SJiri Benc { 150f0706e82SJiri Benc struct sta_info *sta; 15116c5f15cSRon Rindjunsky int i; 1520795af57SJoe Perches DECLARE_MAC_BUF(mac); 153f0706e82SJiri Benc 154f0706e82SJiri Benc sta = kzalloc(sizeof(*sta), gfp); 155f0706e82SJiri Benc if (!sta) 15643ba7e95SJohannes Berg return ERR_PTR(-ENOMEM); 157f0706e82SJiri Benc 158f0706e82SJiri Benc kref_init(&sta->kref); 159f0706e82SJiri Benc 160f0706e82SJiri Benc sta->rate_ctrl = rate_control_get(local->rate_ctrl); 161f0706e82SJiri Benc sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); 162f0706e82SJiri Benc if (!sta->rate_ctrl_priv) { 163f0706e82SJiri Benc rate_control_put(sta->rate_ctrl); 164f0706e82SJiri Benc kfree(sta); 16543ba7e95SJohannes Berg return ERR_PTR(-ENOMEM); 166f0706e82SJiri Benc } 167f0706e82SJiri Benc 168f0706e82SJiri Benc memcpy(sta->addr, addr, ETH_ALEN); 169f0706e82SJiri Benc sta->local = local; 170f0706e82SJiri Benc sta->dev = dev; 17116c5f15cSRon Rindjunsky spin_lock_init(&sta->ampdu_mlme.ampdu_rx); 172fe3bf0f5SRon Rindjunsky spin_lock_init(&sta->ampdu_mlme.ampdu_tx); 17316c5f15cSRon Rindjunsky for (i = 0; i < STA_TID_NUM; i++) { 17416c5f15cSRon Rindjunsky /* timer_to_tid must be initialized with identity mapping to 17516c5f15cSRon Rindjunsky * enable session_timer's data differentiation. refer to 17616c5f15cSRon Rindjunsky * sta_rx_agg_session_timer_expired for useage */ 17716c5f15cSRon Rindjunsky sta->timer_to_tid[i] = i; 178fe3bf0f5SRon Rindjunsky /* tid to tx queue: initialize according to HW (0 is valid) */ 179fe3bf0f5SRon Rindjunsky sta->tid_to_tx_q[i] = local->hw.queues; 18016c5f15cSRon Rindjunsky /* rx timers */ 18116c5f15cSRon Rindjunsky sta->ampdu_mlme.tid_rx[i].session_timer.function = 18216c5f15cSRon Rindjunsky sta_rx_agg_session_timer_expired; 18316c5f15cSRon Rindjunsky sta->ampdu_mlme.tid_rx[i].session_timer.data = 18416c5f15cSRon Rindjunsky (unsigned long)&sta->timer_to_tid[i]; 18516c5f15cSRon Rindjunsky init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer); 186fe3bf0f5SRon Rindjunsky /* tx timers */ 187fe3bf0f5SRon Rindjunsky sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function = 188fe3bf0f5SRon Rindjunsky sta_addba_resp_timer_expired; 189fe3bf0f5SRon Rindjunsky sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data = 190fe3bf0f5SRon Rindjunsky (unsigned long)&sta->timer_to_tid[i]; 191fe3bf0f5SRon Rindjunsky init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); 19216c5f15cSRon Rindjunsky } 193f0706e82SJiri Benc skb_queue_head_init(&sta->ps_tx_buf); 194f0706e82SJiri Benc skb_queue_head_init(&sta->tx_filtered); 195be8755e1SMichael Wu write_lock_bh(&local->sta_lock); 19643ba7e95SJohannes Berg /* mark sta as used (by caller) */ 19743ba7e95SJohannes Berg __sta_info_get(sta); 19843ba7e95SJohannes Berg /* check if STA exists already */ 19943ba7e95SJohannes Berg if (__sta_info_find(local, addr)) { 20043ba7e95SJohannes Berg write_unlock_bh(&local->sta_lock); 20143ba7e95SJohannes Berg sta_info_put(sta); 20243ba7e95SJohannes Berg return ERR_PTR(-EEXIST); 20343ba7e95SJohannes Berg } 204f0706e82SJiri Benc list_add(&sta->list, &local->sta_list); 205f0706e82SJiri Benc local->num_sta++; 206f0706e82SJiri Benc sta_info_hash_add(local, sta); 20732bfd35dSJohannes Berg if (local->ops->sta_notify) { 20832bfd35dSJohannes Berg struct ieee80211_sub_if_data *sdata; 20932bfd35dSJohannes Berg 21032bfd35dSJohannes Berg sdata = IEEE80211_DEV_TO_SUB_IF(dev); 21151fb61e7SJohannes Berg if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) 21232bfd35dSJohannes Berg sdata = sdata->u.vlan.ap; 21332bfd35dSJohannes Berg 21432bfd35dSJohannes Berg local->ops->sta_notify(local_to_hw(local), &sdata->vif, 215478f8d2bSTomas Winkler STA_NOTIFY_ADD, addr); 21632bfd35dSJohannes Berg } 217be8755e1SMichael Wu write_unlock_bh(&local->sta_lock); 218f0706e82SJiri Benc 219f0706e82SJiri Benc #ifdef CONFIG_MAC80211_VERBOSE_DEBUG 2200795af57SJoe Perches printk(KERN_DEBUG "%s: Added STA %s\n", 221dd1cd4c6SJohannes Berg wiphy_name(local->hw.wiphy), print_mac(mac, addr)); 222f0706e82SJiri Benc #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 223f0706e82SJiri Benc 224e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 225e9f207f0SJiri Benc /* debugfs entry adding might sleep, so schedule process 226e9f207f0SJiri Benc * context task for adding entry for STAs that do not yet 227e9f207f0SJiri Benc * have one. */ 228e9f207f0SJiri Benc queue_work(local->hw.workqueue, &local->sta_debugfs_add); 229e9f207f0SJiri Benc #endif 230e9f207f0SJiri Benc 231f0706e82SJiri Benc return sta; 232f0706e82SJiri Benc } 233f0706e82SJiri Benc 234004c872eSJohannes Berg static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) 235004c872eSJohannes Berg { 236004c872eSJohannes Berg /* 237004c872eSJohannes Berg * This format has been mandated by the IEEE specifications, 238004c872eSJohannes Berg * so this line may not be changed to use the __set_bit() format. 239004c872eSJohannes Berg */ 240004c872eSJohannes Berg bss->tim[aid / 8] |= (1 << (aid % 8)); 241004c872eSJohannes Berg } 242004c872eSJohannes Berg 243004c872eSJohannes Berg static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) 244004c872eSJohannes Berg { 245004c872eSJohannes Berg /* 246004c872eSJohannes Berg * This format has been mandated by the IEEE specifications, 247004c872eSJohannes Berg * so this line may not be changed to use the __clear_bit() format. 248004c872eSJohannes Berg */ 249004c872eSJohannes Berg bss->tim[aid / 8] &= ~(1 << (aid % 8)); 250004c872eSJohannes Berg } 251004c872eSJohannes Berg 252004c872eSJohannes Berg static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, 253004c872eSJohannes Berg struct sta_info *sta) 254004c872eSJohannes Berg { 255004c872eSJohannes Berg if (bss) 256004c872eSJohannes Berg __bss_tim_set(bss, sta->aid); 257004c872eSJohannes Berg if (sta->local->ops->set_tim) 258004c872eSJohannes Berg sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); 259004c872eSJohannes Berg } 260004c872eSJohannes Berg 261004c872eSJohannes Berg void sta_info_set_tim_bit(struct sta_info *sta) 262004c872eSJohannes Berg { 263004c872eSJohannes Berg struct ieee80211_sub_if_data *sdata; 264004c872eSJohannes Berg 265004c872eSJohannes Berg sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 266004c872eSJohannes Berg 267004c872eSJohannes Berg read_lock_bh(&sta->local->sta_lock); 268004c872eSJohannes Berg __sta_info_set_tim_bit(sdata->bss, sta); 269004c872eSJohannes Berg read_unlock_bh(&sta->local->sta_lock); 270004c872eSJohannes Berg } 271004c872eSJohannes Berg 272004c872eSJohannes Berg static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, 273004c872eSJohannes Berg struct sta_info *sta) 274004c872eSJohannes Berg { 275004c872eSJohannes Berg if (bss) 276004c872eSJohannes Berg __bss_tim_clear(bss, sta->aid); 277004c872eSJohannes Berg if (sta->local->ops->set_tim) 278004c872eSJohannes Berg sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); 279004c872eSJohannes Berg } 280004c872eSJohannes Berg 281004c872eSJohannes Berg void sta_info_clear_tim_bit(struct sta_info *sta) 282004c872eSJohannes Berg { 283004c872eSJohannes Berg struct ieee80211_sub_if_data *sdata; 284004c872eSJohannes Berg 285004c872eSJohannes Berg sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 286004c872eSJohannes Berg 287004c872eSJohannes Berg read_lock_bh(&sta->local->sta_lock); 288004c872eSJohannes Berg __sta_info_clear_tim_bit(sdata->bss, sta); 289004c872eSJohannes Berg read_unlock_bh(&sta->local->sta_lock); 290004c872eSJohannes Berg } 291004c872eSJohannes Berg 292be8755e1SMichael Wu /* Caller must hold local->sta_lock */ 293be8755e1SMichael Wu void sta_info_remove(struct sta_info *sta) 294f0706e82SJiri Benc { 295f0706e82SJiri Benc struct ieee80211_local *local = sta->local; 296f0706e82SJiri Benc struct ieee80211_sub_if_data *sdata; 297f0706e82SJiri Benc 298be8755e1SMichael Wu /* don't do anything if we've been removed already */ 299be8755e1SMichael Wu if (sta_info_hash_del(local, sta)) 300be8755e1SMichael Wu return; 301be8755e1SMichael Wu 302f0706e82SJiri Benc list_del(&sta->list); 303f0706e82SJiri Benc sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 304f0706e82SJiri Benc if (sta->flags & WLAN_STA_PS) { 305f0706e82SJiri Benc sta->flags &= ~WLAN_STA_PS; 306f0706e82SJiri Benc if (sdata->bss) 307f0706e82SJiri Benc atomic_dec(&sdata->bss->num_sta_ps); 308004c872eSJohannes Berg __sta_info_clear_tim_bit(sdata->bss, sta); 309f0706e82SJiri Benc } 310f0706e82SJiri Benc local->num_sta--; 311*ee385855SLuis Carlos Cobo 312*ee385855SLuis Carlos Cobo #ifdef CONFIG_MAC80211_MESH 313*ee385855SLuis Carlos Cobo if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) 314*ee385855SLuis Carlos Cobo mesh_accept_plinks_update(sdata->dev); 315*ee385855SLuis Carlos Cobo #endif 316f0706e82SJiri Benc } 317f0706e82SJiri Benc 318be8755e1SMichael Wu void sta_info_free(struct sta_info *sta) 319f0706e82SJiri Benc { 320f0706e82SJiri Benc struct sk_buff *skb; 321f0706e82SJiri Benc struct ieee80211_local *local = sta->local; 322*ee385855SLuis Carlos Cobo struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 323*ee385855SLuis Carlos Cobo 3240795af57SJoe Perches DECLARE_MAC_BUF(mac); 325f0706e82SJiri Benc 326be8755e1SMichael Wu might_sleep(); 327be8755e1SMichael Wu 328be8755e1SMichael Wu write_lock_bh(&local->sta_lock); 329f0706e82SJiri Benc sta_info_remove(sta); 330be8755e1SMichael Wu write_unlock_bh(&local->sta_lock); 331f0706e82SJiri Benc 332*ee385855SLuis Carlos Cobo #ifdef CONFIG_MAC80211_MESH 333*ee385855SLuis Carlos Cobo if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { 334*ee385855SLuis Carlos Cobo spin_lock_bh(&sta->plink_lock); 335*ee385855SLuis Carlos Cobo mesh_plink_deactivate(sta); 336*ee385855SLuis Carlos Cobo spin_unlock_bh(&sta->plink_lock); 337*ee385855SLuis Carlos Cobo } 338*ee385855SLuis Carlos Cobo #endif 339*ee385855SLuis Carlos Cobo 340f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { 341f0706e82SJiri Benc local->total_ps_buffered--; 342be8755e1SMichael Wu dev_kfree_skb(skb); 343f0706e82SJiri Benc } 344f0706e82SJiri Benc while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { 345be8755e1SMichael Wu dev_kfree_skb(skb); 346f0706e82SJiri Benc } 347f0706e82SJiri Benc 348be8755e1SMichael Wu #ifdef CONFIG_MAC80211_VERBOSE_DEBUG 3490795af57SJoe Perches printk(KERN_DEBUG "%s: Removed STA %s\n", 350dd1cd4c6SJohannes Berg wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); 351be8755e1SMichael Wu #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 352be8755e1SMichael Wu 353be8755e1SMichael Wu ieee80211_key_free(sta->key); 354db4d1169SJohannes Berg WARN_ON(sta->key); 355be8755e1SMichael Wu 35632bfd35dSJohannes Berg if (local->ops->sta_notify) { 35732bfd35dSJohannes Berg 35851fb61e7SJohannes Berg if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) 35932bfd35dSJohannes Berg sdata = sdata->u.vlan.ap; 36032bfd35dSJohannes Berg 36132bfd35dSJohannes Berg local->ops->sta_notify(local_to_hw(local), &sdata->vif, 362478f8d2bSTomas Winkler STA_NOTIFY_REMOVE, sta->addr); 36332bfd35dSJohannes Berg } 364478f8d2bSTomas Winkler 365be8755e1SMichael Wu rate_control_remove_sta_debugfs(sta); 366be8755e1SMichael Wu ieee80211_sta_debugfs_remove(sta); 367be8755e1SMichael Wu 368be8755e1SMichael Wu sta_info_put(sta); 369f0706e82SJiri Benc } 370f0706e82SJiri Benc 371f0706e82SJiri Benc 372f0706e82SJiri Benc static inline int sta_info_buffer_expired(struct ieee80211_local *local, 373f0706e82SJiri Benc struct sta_info *sta, 374f0706e82SJiri Benc struct sk_buff *skb) 375f0706e82SJiri Benc { 376f0706e82SJiri Benc struct ieee80211_tx_packet_data *pkt_data; 377f0706e82SJiri Benc int timeout; 378f0706e82SJiri Benc 379f0706e82SJiri Benc if (!skb) 380f0706e82SJiri Benc return 0; 381f0706e82SJiri Benc 382f0706e82SJiri Benc pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; 383f0706e82SJiri Benc 384f0706e82SJiri Benc /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */ 385f0706e82SJiri Benc timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 / 386f0706e82SJiri Benc 15625) * HZ; 387f0706e82SJiri Benc if (timeout < STA_TX_BUFFER_EXPIRE) 388f0706e82SJiri Benc timeout = STA_TX_BUFFER_EXPIRE; 389f0706e82SJiri Benc return time_after(jiffies, pkt_data->jiffies + timeout); 390f0706e82SJiri Benc } 391f0706e82SJiri Benc 392f0706e82SJiri Benc 393f0706e82SJiri Benc static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, 394f0706e82SJiri Benc struct sta_info *sta) 395f0706e82SJiri Benc { 396f0706e82SJiri Benc unsigned long flags; 397f0706e82SJiri Benc struct sk_buff *skb; 398836341a7SJohannes Berg struct ieee80211_sub_if_data *sdata; 3990795af57SJoe Perches DECLARE_MAC_BUF(mac); 400f0706e82SJiri Benc 401f0706e82SJiri Benc if (skb_queue_empty(&sta->ps_tx_buf)) 402f0706e82SJiri Benc return; 403f0706e82SJiri Benc 404f0706e82SJiri Benc for (;;) { 405f0706e82SJiri Benc spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); 406f0706e82SJiri Benc skb = skb_peek(&sta->ps_tx_buf); 407836341a7SJohannes Berg if (sta_info_buffer_expired(local, sta, skb)) 408f0706e82SJiri Benc skb = __skb_dequeue(&sta->ps_tx_buf); 409836341a7SJohannes Berg else 410f0706e82SJiri Benc skb = NULL; 411f0706e82SJiri Benc spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags); 412f0706e82SJiri Benc 413836341a7SJohannes Berg if (!skb) 414836341a7SJohannes Berg break; 415836341a7SJohannes Berg 416836341a7SJohannes Berg sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 417f0706e82SJiri Benc local->total_ps_buffered--; 418f0706e82SJiri Benc printk(KERN_DEBUG "Buffered frame expired (STA " 4190795af57SJoe Perches "%s)\n", print_mac(mac, sta->addr)); 420f0706e82SJiri Benc dev_kfree_skb(skb); 421836341a7SJohannes Berg 422004c872eSJohannes Berg if (skb_queue_empty(&sta->ps_tx_buf)) 423004c872eSJohannes Berg sta_info_clear_tim_bit(sta); 424f0706e82SJiri Benc } 425f0706e82SJiri Benc } 426f0706e82SJiri Benc 427f0706e82SJiri Benc 428f0706e82SJiri Benc static void sta_info_cleanup(unsigned long data) 429f0706e82SJiri Benc { 430f0706e82SJiri Benc struct ieee80211_local *local = (struct ieee80211_local *) data; 431f0706e82SJiri Benc struct sta_info *sta; 432f0706e82SJiri Benc 433be8755e1SMichael Wu read_lock_bh(&local->sta_lock); 434f0706e82SJiri Benc list_for_each_entry(sta, &local->sta_list, list) { 435f0706e82SJiri Benc __sta_info_get(sta); 436f0706e82SJiri Benc sta_info_cleanup_expire_buffered(local, sta); 437f0706e82SJiri Benc sta_info_put(sta); 438f0706e82SJiri Benc } 439be8755e1SMichael Wu read_unlock_bh(&local->sta_lock); 440f0706e82SJiri Benc 4410d174406SJohannes Berg local->sta_cleanup.expires = 4420d174406SJohannes Berg round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); 443f0706e82SJiri Benc add_timer(&local->sta_cleanup); 444f0706e82SJiri Benc } 445f0706e82SJiri Benc 446e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 447e9f207f0SJiri Benc static void sta_info_debugfs_add_task(struct work_struct *work) 448e9f207f0SJiri Benc { 449e9f207f0SJiri Benc struct ieee80211_local *local = 450e9f207f0SJiri Benc container_of(work, struct ieee80211_local, sta_debugfs_add); 451e9f207f0SJiri Benc struct sta_info *sta, *tmp; 452e9f207f0SJiri Benc 453e9f207f0SJiri Benc while (1) { 454e9f207f0SJiri Benc sta = NULL; 455be8755e1SMichael Wu read_lock_bh(&local->sta_lock); 456e9f207f0SJiri Benc list_for_each_entry(tmp, &local->sta_list, list) { 457be8755e1SMichael Wu if (!tmp->debugfs.dir) { 458e9f207f0SJiri Benc sta = tmp; 459e9f207f0SJiri Benc __sta_info_get(sta); 460e9f207f0SJiri Benc break; 461e9f207f0SJiri Benc } 462e9f207f0SJiri Benc } 463be8755e1SMichael Wu read_unlock_bh(&local->sta_lock); 464e9f207f0SJiri Benc 465e9f207f0SJiri Benc if (!sta) 466e9f207f0SJiri Benc break; 467e9f207f0SJiri Benc 468e9f207f0SJiri Benc ieee80211_sta_debugfs_add(sta); 469e9f207f0SJiri Benc rate_control_add_sta_debugfs(sta); 470e9f207f0SJiri Benc sta_info_put(sta); 471e9f207f0SJiri Benc } 472e9f207f0SJiri Benc } 473e9f207f0SJiri Benc #endif 474e9f207f0SJiri Benc 475f0706e82SJiri Benc void sta_info_init(struct ieee80211_local *local) 476f0706e82SJiri Benc { 477be8755e1SMichael Wu rwlock_init(&local->sta_lock); 478f0706e82SJiri Benc INIT_LIST_HEAD(&local->sta_list); 479f0706e82SJiri Benc 480b24b8a24SPavel Emelyanov setup_timer(&local->sta_cleanup, sta_info_cleanup, 481b24b8a24SPavel Emelyanov (unsigned long)local); 4820d174406SJohannes Berg local->sta_cleanup.expires = 4830d174406SJohannes Berg round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); 484e9f207f0SJiri Benc 485e9f207f0SJiri Benc #ifdef CONFIG_MAC80211_DEBUGFS 486e9f207f0SJiri Benc INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task); 487e9f207f0SJiri Benc #endif 488f0706e82SJiri Benc } 489f0706e82SJiri Benc 490f0706e82SJiri Benc int sta_info_start(struct ieee80211_local *local) 491f0706e82SJiri Benc { 492f0706e82SJiri Benc add_timer(&local->sta_cleanup); 493f0706e82SJiri Benc return 0; 494f0706e82SJiri Benc } 495f0706e82SJiri Benc 496f0706e82SJiri Benc void sta_info_stop(struct ieee80211_local *local) 497f0706e82SJiri Benc { 498f0706e82SJiri Benc del_timer(&local->sta_cleanup); 499be8755e1SMichael Wu sta_info_flush(local, NULL); 500f0706e82SJiri Benc } 501f0706e82SJiri Benc 502f0706e82SJiri Benc /** 503f0706e82SJiri Benc * sta_info_flush - flush matching STA entries from the STA table 504f0706e82SJiri Benc * @local: local interface data 505f0706e82SJiri Benc * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs 506f0706e82SJiri Benc */ 507f0706e82SJiri Benc void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) 508f0706e82SJiri Benc { 509f0706e82SJiri Benc struct sta_info *sta, *tmp; 510be8755e1SMichael Wu LIST_HEAD(tmp_list); 511f0706e82SJiri Benc 512be8755e1SMichael Wu write_lock_bh(&local->sta_lock); 513f0706e82SJiri Benc list_for_each_entry_safe(sta, tmp, &local->sta_list, list) 514be8755e1SMichael Wu if (!dev || dev == sta->dev) { 515be8755e1SMichael Wu __sta_info_get(sta); 516be8755e1SMichael Wu sta_info_remove(sta); 517be8755e1SMichael Wu list_add_tail(&sta->list, &tmp_list); 518be8755e1SMichael Wu } 519be8755e1SMichael Wu write_unlock_bh(&local->sta_lock); 520be8755e1SMichael Wu 521be8755e1SMichael Wu list_for_each_entry_safe(sta, tmp, &tmp_list, list) { 522be8755e1SMichael Wu sta_info_free(sta); 523be8755e1SMichael Wu sta_info_put(sta); 524be8755e1SMichael Wu } 525f0706e82SJiri Benc } 526