mac80211: unify TIM bit handling
Currently, the TIM bit for a given station is set and cleared all over the place. Since the logic to set/clear it will become much more complex when we add uAPSD support, as a first step let's collect the entire logic in one place. This requires a few small adjustments to other places. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
042ec45337
commit
c868cb35d0
4 changed files with 51 additions and 69 deletions
|
@ -641,54 +641,42 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
|
||||||
bss->tim[aid / 8] &= ~(1 << (aid % 8));
|
bss->tim[aid / 8] &= ~(1 << (aid % 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
|
void sta_info_recalc_tim(struct sta_info *sta)
|
||||||
struct sta_info *sta)
|
|
||||||
{
|
|
||||||
BUG_ON(!bss);
|
|
||||||
|
|
||||||
__bss_tim_set(bss, sta->sta.aid);
|
|
||||||
|
|
||||||
if (sta->local->ops->set_tim) {
|
|
||||||
sta->local->tim_in_locked_section = true;
|
|
||||||
drv_set_tim(sta->local, &sta->sta, true);
|
|
||||||
sta->local->tim_in_locked_section = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sta_info_set_tim_bit(struct sta_info *sta)
|
|
||||||
{
|
{
|
||||||
|
struct ieee80211_local *local = sta->local;
|
||||||
|
struct ieee80211_if_ap *bss = sta->sdata->bss;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
bool have_data = false;
|
||||||
|
|
||||||
BUG_ON(!sta->sdata->bss);
|
if (WARN_ON_ONCE(!sta->sdata->bss))
|
||||||
|
return;
|
||||||
|
|
||||||
spin_lock_irqsave(&sta->local->sta_lock, flags);
|
/* No need to do anything if the driver does all */
|
||||||
__sta_info_set_tim_bit(sta->sdata->bss, sta);
|
if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
|
||||||
spin_unlock_irqrestore(&sta->local->sta_lock, flags);
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
|
if (sta->dead)
|
||||||
struct sta_info *sta)
|
goto done;
|
||||||
{
|
|
||||||
BUG_ON(!bss);
|
|
||||||
|
|
||||||
__bss_tim_clear(bss, sta->sta.aid);
|
have_data = test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF) ||
|
||||||
|
!skb_queue_empty(&sta->tx_filtered) ||
|
||||||
|
!skb_queue_empty(&sta->ps_tx_buf);
|
||||||
|
|
||||||
if (sta->local->ops->set_tim) {
|
done:
|
||||||
sta->local->tim_in_locked_section = true;
|
spin_lock_irqsave(&local->sta_lock, flags);
|
||||||
drv_set_tim(sta->local, &sta->sta, false);
|
|
||||||
sta->local->tim_in_locked_section = false;
|
if (have_data)
|
||||||
|
__bss_tim_set(bss, sta->sta.aid);
|
||||||
|
else
|
||||||
|
__bss_tim_clear(bss, sta->sta.aid);
|
||||||
|
|
||||||
|
if (local->ops->set_tim) {
|
||||||
|
local->tim_in_locked_section = true;
|
||||||
|
drv_set_tim(local, &sta->sta, have_data);
|
||||||
|
local->tim_in_locked_section = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void sta_info_clear_tim_bit(struct sta_info *sta)
|
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
BUG_ON(!sta->sdata->bss);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&sta->local->sta_lock, flags);
|
|
||||||
__sta_info_clear_tim_bit(sta->sdata->bss, sta);
|
|
||||||
spin_unlock_irqrestore(&sta->local->sta_lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
|
static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
|
||||||
|
@ -717,6 +705,10 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
/* This is only necessary for stations on BSS interfaces */
|
||||||
|
if (!sta->sdata->bss)
|
||||||
|
return false;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
|
spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
|
||||||
skb = skb_peek(&sta->ps_tx_buf);
|
skb = skb_peek(&sta->ps_tx_buf);
|
||||||
|
@ -736,9 +728,9 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
|
||||||
#endif
|
#endif
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
|
|
||||||
if (skb_queue_empty(&sta->ps_tx_buf) &&
|
/* if the queue is now empty recalc TIM bit */
|
||||||
!test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
|
if (skb_queue_empty(&sta->ps_tx_buf))
|
||||||
sta_info_clear_tim_bit(sta);
|
sta_info_recalc_tim(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !skb_queue_empty(&sta->ps_tx_buf);
|
return !skb_queue_empty(&sta->ps_tx_buf);
|
||||||
|
@ -748,7 +740,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local;
|
struct ieee80211_local *local;
|
||||||
struct ieee80211_sub_if_data *sdata;
|
struct ieee80211_sub_if_data *sdata;
|
||||||
struct sk_buff *skb;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
|
@ -792,7 +783,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
|
||||||
BUG_ON(!sdata->bss);
|
BUG_ON(!sdata->bss);
|
||||||
|
|
||||||
atomic_dec(&sdata->bss->num_sta_ps);
|
atomic_dec(&sdata->bss->num_sta_ps);
|
||||||
sta_info_clear_tim_bit(sta);
|
sta_info_recalc_tim(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
local->num_sta--;
|
local->num_sta--;
|
||||||
|
@ -818,6 +809,10 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
|
||||||
*/
|
*/
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
|
||||||
|
local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf);
|
||||||
|
__skb_queue_purge(&sta->ps_tx_buf);
|
||||||
|
__skb_queue_purge(&sta->tx_filtered);
|
||||||
|
|
||||||
#ifdef CONFIG_MAC80211_MESH
|
#ifdef CONFIG_MAC80211_MESH
|
||||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||||
mesh_accept_plinks_update(sdata);
|
mesh_accept_plinks_update(sdata);
|
||||||
|
@ -840,14 +835,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
|
|
||||||
local->total_ps_buffered--;
|
|
||||||
dev_kfree_skb_any(skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL)
|
|
||||||
dev_kfree_skb_any(skb);
|
|
||||||
|
|
||||||
__sta_info_free(local, sta);
|
__sta_info_free(local, sta);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1027,9 +1014,6 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||||||
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
|
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
|
||||||
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
|
drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
|
||||||
|
|
||||||
if (!skb_queue_empty(&sta->ps_tx_buf))
|
|
||||||
sta_info_clear_tim_bit(sta);
|
|
||||||
|
|
||||||
/* Send all buffered frames to the station */
|
/* Send all buffered frames to the station */
|
||||||
sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
|
sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
|
||||||
buffered = ieee80211_add_pending_skbs_fn(local, &sta->ps_tx_buf,
|
buffered = ieee80211_add_pending_skbs_fn(local, &sta->ps_tx_buf,
|
||||||
|
@ -1037,6 +1021,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||||||
sent += buffered;
|
sent += buffered;
|
||||||
local->total_ps_buffered -= buffered;
|
local->total_ps_buffered -= buffered;
|
||||||
|
|
||||||
|
sta_info_recalc_tim(sta);
|
||||||
|
|
||||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||||
printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
|
printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
|
||||||
"since STA not sleeping anymore\n", sdata->name,
|
"since STA not sleeping anymore\n", sdata->name,
|
||||||
|
@ -1086,8 +1072,7 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
|
||||||
|
|
||||||
ieee80211_add_pending_skb(local, skb);
|
ieee80211_add_pending_skb(local, skb);
|
||||||
|
|
||||||
if (no_pending_pkts)
|
sta_info_recalc_tim(sta);
|
||||||
sta_info_clear_tim_bit(sta);
|
|
||||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
|
@ -1126,6 +1111,6 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
|
set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
|
||||||
sta_info_set_tim_bit(sta);
|
sta_info_recalc_tim(sta);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
|
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
|
||||||
|
|
|
@ -528,8 +528,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
|
||||||
int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
|
int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
|
||||||
const u8 *addr);
|
const u8 *addr);
|
||||||
|
|
||||||
void sta_info_set_tim_bit(struct sta_info *sta);
|
void sta_info_recalc_tim(struct sta_info *sta);
|
||||||
void sta_info_clear_tim_bit(struct sta_info *sta);
|
|
||||||
|
|
||||||
void sta_info_init(struct ieee80211_local *local);
|
void sta_info_init(struct ieee80211_local *local);
|
||||||
void sta_info_stop(struct ieee80211_local *local);
|
void sta_info_stop(struct ieee80211_local *local);
|
||||||
|
|
|
@ -106,6 +106,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
|
||||||
if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
|
if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
|
||||||
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
|
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
|
||||||
skb_queue_tail(&sta->tx_filtered, skb);
|
skb_queue_tail(&sta->tx_filtered, skb);
|
||||||
|
sta_info_recalc_tim(sta);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -469,15 +469,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
||||||
} else
|
} else
|
||||||
tx->local->total_ps_buffered++;
|
tx->local->total_ps_buffered++;
|
||||||
|
|
||||||
/*
|
|
||||||
* Queue frame to be sent after STA wakes up/polls,
|
|
||||||
* but don't set the TIM bit if the driver is blocking
|
|
||||||
* wakeup or poll response transmissions anyway.
|
|
||||||
*/
|
|
||||||
if (skb_queue_empty(&sta->ps_tx_buf) &&
|
|
||||||
!(staflags & WLAN_STA_PS_DRIVER))
|
|
||||||
sta_info_set_tim_bit(sta);
|
|
||||||
|
|
||||||
info->control.jiffies = jiffies;
|
info->control.jiffies = jiffies;
|
||||||
info->control.vif = &tx->sdata->vif;
|
info->control.vif = &tx->sdata->vif;
|
||||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||||
|
@ -488,6 +479,12 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
||||||
round_jiffies(jiffies +
|
round_jiffies(jiffies +
|
||||||
STA_INFO_CLEANUP_INTERVAL));
|
STA_INFO_CLEANUP_INTERVAL));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We queued up some frames, so the TIM bit might
|
||||||
|
* need to be set, recalculate it.
|
||||||
|
*/
|
||||||
|
sta_info_recalc_tim(sta);
|
||||||
|
|
||||||
return TX_QUEUED;
|
return TX_QUEUED;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
|
||||||
|
|
Loading…
Reference in a new issue