diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2606ca282c5e..5b9e7a262448 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -308,6 +308,8 @@ struct ieee80211_tx_control { * set_retry_limit configured * long retry value */ #define IEEE80211_TXCTL_EAPOL_FRAME (1<<11) /* internal to mac80211 */ +#define IEEE80211_TXCTL_SEND_AFTER_DTIM (1<<12) /* send this frame after DTIM + * beacon */ u32 flags; /* tx control flags defined * above */ u8 key_idx; /* keyidx from hw->set_key(), undefined if diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e177a8dc23b9..f7aff2e97eea 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -322,16 +322,27 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) wiphy_name(local->hw.wiphy), purged); } -static inline ieee80211_txrx_result +static ieee80211_txrx_result ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) { - /* broadcast/multicast frame */ - /* If any of the associated stations is in power save mode, - * the frame is buffered to be sent after DTIM beacon frame */ - if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) && - tx->sdata->type != IEEE80211_IF_TYPE_WDS && - tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) && - !(tx->fc & IEEE80211_FCTL_ORDER)) { + /* + * broadcast/multicast frame + * + * If any of the associated stations is in power save mode, + * the frame is buffered to be sent after DTIM beacon frame. + * This is done either by the hardware or us. + */ + + /* not AP/IBSS or ordered frame */ + if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER)) + return TXRX_CONTINUE; + + /* no stations in PS mode */ + if (!atomic_read(&tx->sdata->bss->num_sta_ps)) + return TXRX_CONTINUE; + + /* buffered in mac80211 */ + if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) { if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) purge_old_ps_buffers(tx->local); if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= @@ -348,10 +359,13 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) return TXRX_QUEUED; } + /* buffered in hardware */ + tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; + return TXRX_CONTINUE; } -static inline ieee80211_txrx_result +static ieee80211_txrx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) { struct sta_info *sta = tx->sta;