mac80211 uAPSD support
Subsystems (4)
Johannes Berg
maintainerv2 cover mac80211 uAPSD support
Sorry for the resend!
This fixes a stupid bug that made resume crash.
johannes
Johannes Berg
maintainerPATCH v2 1/16 mac80211: let drivers inform it about per TID buffered frames
From: Johannes Berg <[email protected]>
For uAPSD implementation, it is necessary to know on which ACs frames are buffered. mac80211 obviously knows about the frames it has buffered itself, but with aggregation many drivers buffer frames. Thus, mac80211 needs to be informed about this.
For now, since we don't have APSD in any form, this will unconditionally set the TIM bit for the station but later with uAPSD only some ACs might cause the TIM bit to be set.
ath9k is the only driver using this API and I only modify it in the most basic way, it won't be able to implement uAPSD with this yet. But it can't do that anyway since there's no way to selectively release frames to the peer yet.
Since drivers will buffer frames per TID, let them inform mac80211 on a per TID basis, mac80211 will then sort out the AC mapping itself.
--- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++- drivers/net/wireless/ath/ath9k/main.c | 3 +-- drivers/net/wireless/ath/ath9k/xmit.c | 14 +++++++------- include/net/mac80211.h | 30 ++++++++++++++++++++++++------ net/mac80211/sta_info.c | 8 ++++++-- 5 files changed, 40 insertions(+), 18 deletions(-)
include/net/mac80211.h +24 -6
@@ -2361,17 +2361,35 @@ static inline int ieee80211_sta_ps_trans#define IEEE80211_TX_STATUS_HEADROOM 13/** -* ieee80211_sta_set_tim - set the TIM bit for a sleeping station +* ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames * @sta: &struct ieee80211_sta pointer for the sleeping station +* @tid: the TID that has buffered frames +* @buffered: indicates whether or not frames are buffered for this TID * * If a driver buffers frames for a powersave station instead of passing -* them back to mac80211 for retransmission, the station needs to be told -* to wake up using the TIM bitmap in the beacon. +* them back to mac80211 for retransmission, the station may still need +* to be told that there are buffered frames via the TIM bit. * -* This function sets the station's TIM bit - it will be cleared when the -* station wakes up. +* This function informs mac80211 whether or not there are frames that are +* buffered in the driver for a given TID; mac80211 can then use this data +* to set the TIM bit (NOTE: This may call back into the driver's set_tim +* call! Beware of the locking!) +* +* If all frames are released to the station (due to PS-poll or uAPSD) +* then the driver needs to inform mac80211 that there no longer are +* frames buffered. However, when the station wakes up mac80211 assumes +* that all buffered frames will be transmitted and clears this data, +* drivers need to make sure they inform mac80211 about all buffered +* frames on the sleep transition (sta_notify() with %STA_NOTIFY_SLEEP). +* +* Note that technically mac80211 only needs to know this per AC, not per +* TID, but since driver buffering will inevitably happen per TID (since +* it is related to aggregation) it is easier to make mac80211 map the +* TID to the AC as required instead of keeping track in all drivers that +* use this API. */ -void ieee80211_sta_set_tim (struct ieee80211_sta *sta); +void ieee80211_sta_set_buffered (struct ieee80211_sta *sta, +u8 tid,bool buffered);/** * ieee80211_tx_status - transmit status callback
net/mac80211/sta_info.c +6 -2
@@ -1117,11 +1117,15 @@ void ieee80211_sta_block_awake(struct ie }EXPORT_SYMBOL (ieee80211_sta_block_awake); -void ieee80211_sta_set_tim (struct ieee80211_sta *pubsta) +void ieee80211_sta_set_buffered (struct ieee80211_sta *pubsta, +u8 tid,bool buffered) { struct sta_info *sta = container_of(pubsta, struct sta_info, sta); +if (!buffered) +return ; +set_sta_flags (sta,WLAN_STA_PS_DRIVER_BUF );sta_info_set_tim_bit (sta); } -EXPORT_SYMBOL (ieee80211_sta_set_tim); +EXPORT_SYMBOL (ieee80211_sta_set_buffered);
drivers/net/wireless/ath/ath9k/ath9k.h +2 -1
@@ -340,7 +340,8 @@ void ath_tx_aggr_stop(struct ath_softc *void ath_tx_aggr_resume (struct ath_softc *sc,struct ieee80211_sta *sta,u16 tid);void ath_tx_aggr_wakeup (struct ath_softc *sc,struct ath_node *an); -bool ath_tx_aggr_sleep (struct ath_softc *sc,struct ath_node *an); +void ath_tx_aggr_sleep (struct ieee80211_sta *sta,struct ath_softc *sc, +struct ath_node *an);/********/ /* VIFs */
drivers/net/wireless/ath/ath9k/main.c +1 -2
@@ -1833,8 +1833,7 @@ static void ath9k_sta_notify(struct ieeeswitch (cmd) {case STA_NOTIFY_SLEEP : an->sleeping = true; -if (ath_tx_aggr_sleep (sc, an)) -ieee80211_sta_set_tim (sta); +ath_tx_aggr_sleep (sta, sc, an);break ;case STA_NOTIFY_AWAKE : an->sleeping = false;
drivers/net/wireless/ath/ath9k/xmit.c +7 -7
@@ -542,7 +542,7 @@ static void ath_tx_complete_aggr(struct/* prepend un-acked frames to the beginning of the pending frame queue */ if (!skb_queue_empty (&bf_pending)) {if (an->sleeping) -ieee80211_sta_set_tim (sta); +ieee80211_sta_set_buffered (sta, tid->tidno, true);spin_lock_bh (&txq->axq_lock);if (clear_filter)
@@ -1153,12 +1153,13 @@ void ath_tx_aggr_stop(struct ath_softc *ath_tx_flush_tid (sc, txtid); } -bool ath_tx_aggr_sleep (struct ath_softc *sc,struct ath_node *an) +void ath_tx_aggr_sleep (struct ieee80211_sta *sta,struct ath_softc *sc, +struct ath_node *an) {struct ath_atx_tid *tid;struct ath_atx_ac *ac;struct ath_txq *txq; -bool buffered = false; +bool buffered;int tidno; for (tidno = 0, tid = &an->tid[tidno];
@@ -1172,8 +1173,7 @@ bool ath_tx_aggr_sleep(struct ath_softcspin_lock_bh (&txq->axq_lock); -if (!skb_queue_empty (&tid->buf_q)) - buffered = true; + buffered = !skb_queue_empty (&tid->buf_q); tid->sched = false;list_del (&tid->list);
@@ -1184,9 +1184,9 @@ bool ath_tx_aggr_sleep(struct ath_softc }spin_unlock_bh (&txq->axq_lock); - } -return buffered; +ieee80211_sta_set_buffered (sta, tidno, buffered); + } }void ath_tx_aggr_wakeup (struct ath_softc *sc,struct ath_node *an)
Johannes Berg
maintainerPATCH v2 2/16 mac80211: unify TIM bit handling
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
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.
--- net/mac80211/sta_info.c | 101 ++++++++++++++++++++---------------------------- net/mac80211/sta_info.h | 3 - net/mac80211/status.c | 1 net/mac80211/tx.c | 15 ++----- 4 files changed, 51 insertions(+), 69 deletions(-)
net/mac80211/sta_info.h +1 -2
@@ -528,8 +528,7 @@ int sta_info_destroy_addr(struct ieee802int sta_info_destroy_addr_bss (struct ieee80211_sub_if_data *sdata,const u8 *addr); -void sta_info_set_tim_bit (struct sta_info *sta); -void sta_info_clear_tim_bit (struct sta_info *sta); +void sta_info_recalc_tim (struct sta_info *sta);void sta_info_init (struct ieee80211_local *local);void sta_info_stop (struct ieee80211_local *local);
net/mac80211/tx.c +6 -9
@@ -469,15 +469,6 @@ ieee80211_tx_h_unicast_ps_buf(struct iee }else 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.vif = &tx->sdata->vif; info->flags |=IEEE80211_TX_INTFL_NEED_TXPROCESSING ;
@@ -488,6 +479,12 @@ ieee80211_tx_h_unicast_ps_buf(struct ieeround_jiffies (jiffies + 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 ; }#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
net/mac80211/sta_info.c +43 -58
175 lines not on this page · raw message
net/mac80211/status.c +1 -0
@@ -106,6 +106,7 @@ static void ieee80211_handle_filtered_frif (test_sta_flags (sta,WLAN_STA_PS_STA ) &&skb_queue_len (&sta->tx_filtered) <STA_MAX_TX_BUFFER ) {skb_queue_tail (&sta->tx_filtered, skb); +sta_info_recalc_tim (sta);return ; }
Johannes Berg
maintainerPATCH v2 3/16 mac80211: also expire filtered frames
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
mac80211 will expire normal PS-buffered frames, but if the device rejected some frames for a sleeping station, these won't be on the ps_tx_buf queue but on the tx_filtered queue instead; this is done to avoid reordering.
However, mac80211 will not expire frames from the filtered queue, let's fix that.
Also add a more comments to what all this expiry is doing and how it works.
--- net/mac80211/sta_info.c | 57 +++++++++++++++++++++++++++++++++++++++++++----- net/mac80211/status.c | 5 ++++ 2 files changed, 57 insertions(+), 5 deletions(-)
net/mac80211/sta_info.c +52 -5
@@ -709,6 +709,39 @@ static bool sta_info_cleanup_expire_buffif (!sta->sdata->bss)return false; +/* +* First check for frames that should expire on the filtered +* queue. Frames here were rejected by the driver and are on +* a separate queue to avoid reordering with normal PS-buffered +* frames. They also aren't accounted for right now in the +* total_ps_buffered counter. +*/ +for (;;) { +spin_lock_irqsave (&sta->tx_filtered.lock, flags); + skb =skb_peek (&sta->tx_filtered); +if (sta_info_buffer_expired (sta, skb)) + skb =__skb_dequeue (&sta->tx_filtered); +else + skb =NULL ; +spin_unlock_irqrestore (&sta->tx_filtered.lock, flags); + +/* +* Frames are queued in order, so if this one +* hasn't expired yet we can stop testing. If +* we actually reached the end of the queue we +* also need to stop, of course. +*/ +if (!skb) +break ; +dev_kfree_skb (skb); + } + +/* +* Now also check the normal PS-buffered queue, this will +* only find something if the filtered queue was emptied +* since the filtered frames are all before the normal PS +* buffered frames. +*/ for (;;) {spin_lock_irqsave (&sta->ps_tx_buf.lock, flags); skb =skb_peek (&sta->ps_tx_buf);
@@ -718,6 +751,11 @@ static bool sta_info_cleanup_expire_buff skb =NULL ;spin_unlock_irqrestore (&sta->ps_tx_buf.lock, flags); +/* +* frames are queued in order, so if this one +* hasn't expired yet (or we reached the end of +* the queue) we can stop testing +*/ if (!skb)break ;
@@ -727,13 +765,22 @@ static bool sta_info_cleanup_expire_buff sta->sta.addr);#endif dev_kfree_skb (skb); - -/* if the queue is now empty recalc TIM bit */ -if (skb_queue_empty (&sta->ps_tx_buf)) -sta_info_recalc_tim (sta); } -return !skb_queue_empty (&sta->ps_tx_buf); +/* +* Finally, recalculate the TIM bit for this station -- it might +* now be clear because the station was too slow to retrieve its +* frames. +*/ +sta_info_recalc_tim (sta); + +/* +* Return whether there are any frames still buffered, this is +* used to check whether the cleanup timer still needs to run, +* if there are no frames we don't need to rearm the timer. +*/ +return !(skb_queue_empty (&sta->ps_tx_buf) && +skb_queue_empty (&sta->tx_filtered)); }static int __must_check __sta_info_destroy (struct sta_info *sta)
net/mac80211/status.c +5 -0
@@ -107,6 +107,11 @@ static void ieee80211_handle_filtered_fr skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {skb_queue_tail (&sta->tx_filtered, skb);sta_info_recalc_tim (sta); + +if (!timer_pending (&local->sta_cleanup)) +mod_timer (&local->sta_cleanup, +round_jiffies (jiffies + +STA_INFO_CLEANUP_INTERVAL ));return ; }
Johannes Berg
maintainerPATCH v2 4/16 mac80211: split PS buffers into ACs
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
For uAPSD support we'll need to have per-AC PS buffers. As this is a major undertaking, split the buffers before really adding support for uAPSD. This already makes some reference to the uapsd_queues variable, but for now that will never be non-zero.
Since book-keeping is complicated, also change the logic for keeping a maximum of frames only and allow 64 frames per AC (up from 128 for a station).
--- include/net/mac80211.h | 1 net/mac80211/debugfs_sta.c | 10 +- net/mac80211/sta_info.c | 204 +++++++++++++++++++++++++++++++++------------ net/mac80211/sta_info.h | 24 ++--- net/mac80211/status.c | 17 +++ net/mac80211/tx.c | 42 +++++---- 6 files changed, 214 insertions(+), 84 deletions(-)
net/mac80211/sta_info.c +154 -50
@@ -309,8 +309,10 @@ struct sta_info *sta_info_alloc(struct i*/ sta->timer_to_tid[i] = i; } -skb_queue_head_init (&sta->ps_tx_buf); -skb_queue_head_init (&sta->tx_filtered); +for (i =0 ; i <IEEE80211_NUM_ACS ; i++) { +skb_queue_head_init (&sta->ps_tx_buf[i]); +skb_queue_head_init (&sta->tx_filtered[i]); + }for (i =0 ; i <NUM_RX_DATA_QUEUES ; i++) sta->last_seq_ctrl[i] =cpu_to_le16 (USHRT_MAX );
@@ -641,12 +643,32 @@ static inline void __bss_tim_clear(struc bss->tim[aid /8 ] &= ~(1 << (aid %8 )); } +static unsigned long ieee80211_tids_for_ac (int ac) +{ +/* If we ever support TIDs > 7, this obviously needs to be adjusted */ +switch (ac) { +case IEEE80211_AC_VO : +return BIT (6 ) |BIT (7 ); +case IEEE80211_AC_VI : +return BIT (4 ) |BIT (5 ); +case IEEE80211_AC_BE : +return BIT (0 ) |BIT (3 ); +case IEEE80211_AC_BK : +return BIT (1 ) |BIT (2 ); +default : +WARN_ON (1 ); +return 0 ; + } +} +void sta_info_recalc_tim (struct sta_info *sta) {struct ieee80211_local *local = sta->local;struct ieee80211_if_ap *bss = sta->sdata->bss;unsigned long flags; -bool have_data = false; +bool indicate_tim = false; +u8 ignore_for_tim = sta->sta.uapsd_queues; +int ac;if (WARN_ON_ONCE (!sta->sdata->bss))return ;
@@ -658,21 +680,43 @@ void sta_info_recalc_tim(struct sta_infoif (sta->dead) goto done; - 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 all ACs are delivery-enabled then we should build +* the TIM bit for all ACs anyway; if only some are then +* we ignore those and build the TIM bit using only the +* non-enabled ones. +*/ +if (ignore_for_tim ==BIT (IEEE80211_NUM_ACS ) -1 ) + ignore_for_tim =0 ; + +for (ac =0 ; ac <IEEE80211_NUM_ACS ; ac++) { +unsigned long tids; + +if (ignore_for_tim &BIT (ac)) +continue ; + + indicate_tim |= !skb_queue_empty (&sta->tx_filtered[ac]) || + !skb_queue_empty (&sta->ps_tx_buf[ac]); +if (indicate_tim) +break ; + + tids =ieee80211_tids_for_ac (ac); + + indicate_tim |= + sta->driver_buffered_tids & tids; + } done:spin_lock_irqsave (&local->sta_lock, flags); -if (have_data) +if (indicate_tim)__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); +drv_set_tim (local, &sta->sta, indicate_tim); local->tim_in_locked_section = false; }
@@ -699,16 +743,12 @@ static bool sta_info_buffer_expired(stru } -static bool sta_info_cleanup_expire_buffered (struct ieee80211_local *local, -struct sta_info *sta) +static bool sta_info_cleanup_expire_buffered_ac (struct ieee80211_local *local, +struct sta_info *sta,int ac) {unsigned long flags;struct sk_buff *skb; -/* This is only necessary for stations on BSS interfaces */ -if (!sta->sdata->bss) -return false; -/* * First check for frames that should expire on the filtered * queue. Frames here were rejected by the driver and are on
@@ -717,13 +757,13 @@ static bool sta_info_cleanup_expire_buff* total_ps_buffered counter. */ for (;;) { -spin_lock_irqsave (&sta->tx_filtered.lock, flags); - skb =skb_peek (&sta->tx_filtered); +spin_lock_irqsave (&sta->tx_filtered[ac].lock, flags); + skb =skb_peek (&sta->tx_filtered[ac]);if (sta_info_buffer_expired (sta, skb)) - skb =__skb_dequeue (&sta->tx_filtered); + skb =__skb_dequeue (&sta->tx_filtered[ac]);else skb =NULL ; -spin_unlock_irqrestore (&sta->tx_filtered.lock, flags); +spin_unlock_irqrestore (&sta->tx_filtered[ac].lock, flags);/* * Frames are queued in order, so if this one
@@ -743,13 +783,13 @@ static bool sta_info_cleanup_expire_buff* buffered frames. */ for (;;) { -spin_lock_irqsave (&sta->ps_tx_buf.lock, flags); - skb =skb_peek (&sta->ps_tx_buf); +spin_lock_irqsave (&sta->ps_tx_buf[ac].lock, flags); + skb =skb_peek (&sta->ps_tx_buf[ac]);if (sta_info_buffer_expired (sta, skb)) - skb =__skb_dequeue (&sta->ps_tx_buf); + skb =__skb_dequeue (&sta->ps_tx_buf[ac]);else skb =NULL ; -spin_unlock_irqrestore (&sta->ps_tx_buf.lock, flags); +spin_unlock_irqrestore (&sta->ps_tx_buf[ac].lock, flags);/* * frames are queued in order, so if this one
@@ -779,8 +819,25 @@ static bool sta_info_cleanup_expire_buff* used to check whether the cleanup timer still needs to run, * if there are no frames we don't need to rearm the timer. */ -return !(skb_queue_empty (&sta->ps_tx_buf) && -skb_queue_empty (&sta->tx_filtered)); +return !(skb_queue_empty (&sta->ps_tx_buf[ac]) && +skb_queue_empty (&sta->tx_filtered[ac])); +} + +static bool sta_info_cleanup_expire_buffered (struct ieee80211_local *local, +struct sta_info *sta) +{ +bool have_buffered = false; +int ac; + +/* This is only necessary for stations on BSS interfaces */ +if (!sta->sdata->bss) +return false; + +for (ac =0 ; ac <IEEE80211_NUM_ACS ; ac++) + have_buffered |= +sta_info_cleanup_expire_buffered_ac (local, sta, ac); + +return have_buffered; }static int __must_check __sta_info_destroy (struct sta_info *sta)
@@ -788,7 +845,7 @@ static int __must_check __sta_info_destrstruct ieee80211_local *local;struct ieee80211_sub_if_data *sdata;unsigned long flags; -int ret, i; +int ret, i, ac;might_sleep ();
@@ -856,9 +913,11 @@ static int __must_check __sta_info_destr*/ 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); +for (ac =0 ; ac <IEEE80211_NUM_ACS ; ac++) { + local->total_ps_buffered -=skb_queue_len (&sta->ps_tx_buf[ac]); +__skb_queue_purge (&sta->ps_tx_buf[ac]); +__skb_queue_purge (&sta->tx_filtered[ac]); + }#ifdef CONFIG_MAC80211_MESH if (ieee80211_vif_is_mesh (&sdata->vif))
@@ -1055,17 +1114,33 @@ void ieee80211_sta_ps_deliver_wakeup(str {struct ieee80211_sub_if_data *sdata = sta->sdata;struct ieee80211_local *local = sdata->local; -int sent, buffered; +struct sk_buff_head pending; +int filtered =0 , buffered =0 , ac; + +BUILD_BUG_ON (BITS_TO_LONGS (STA_TID_NUM ) >1 ); + sta->driver_buffered_tids =0 ; -clear_sta_flags (sta,WLAN_STA_PS_DRIVER_BUF );if (!(local->hw.flags &IEEE80211_HW_AP_LINK_PS ))drv_sta_notify (local, sdata,STA_NOTIFY_AWAKE , &sta->sta); +skb_queue_head_init (&pending); +/* Send all buffered frames to the station */ - sent =ieee80211_add_pending_skbs (local, &sta->tx_filtered); - buffered =ieee80211_add_pending_skbs_fn (local, &sta->ps_tx_buf, - clear_sta_ps_flags, sta); - sent += buffered; +for (ac =0 ; ac <IEEE80211_NUM_ACS ; ac++) { +int count =skb_queue_len (&pending), tmp; + +skb_queue_splice_tail_init (&sta->tx_filtered[ac], &pending); + tmp =skb_queue_len (&pending); + filtered += tmp - count; + count = tmp; + +skb_queue_splice_tail_init (&sta->ps_tx_buf[ac], &pending); + tmp =skb_queue_len (&pending); + buffered += tmp - count; + } + +ieee80211_add_pending_skbs_fn (local, &pending, clear_sta_ps_flags, sta); + local->total_ps_buffered -= buffered;sta_info_recalc_tim (sta);
@@ -1073,7 +1148,7 @@ void ieee80211_sta_ps_deliver_wakeup(str#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk (KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames " "since STA not sleeping anymore\n" , sdata->name, - sta->sta.addr, sta->sta.aid, sent - buffered, buffered); + sta->sta.addr, sta->sta.aid, filtered, buffered);#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ }
@@ -1081,17 +1156,43 @@ void ieee80211_sta_ps_deliver_poll_respo {struct ieee80211_sub_if_data *sdata = sta->sdata;struct ieee80211_local *local = sdata->local; -struct sk_buff *skb; -int no_pending_pkts; +struct sk_buff *skb =NULL ; +bool more_data = false; +int ac; +u8 ignore_for_response = sta->sta.uapsd_queues; - skb =skb_dequeue (&sta->tx_filtered); -if (!skb) { - skb =skb_dequeue (&sta->ps_tx_buf); -if (skb) - local->total_ps_buffered--; +/* +* If all ACs are delivery-enabled then we should reply +* from any of them, if only some are enabled we reply +* only from the non-enabled ones. +*/ +if (ignore_for_response ==BIT (IEEE80211_NUM_ACS ) -1 ) + ignore_for_response =0 ; + +/* +* Get response frame and more data bit for it. +*/ +for (ac =0 ; ac <IEEE80211_NUM_ACS ; ac++) { +if (ignore_for_response &BIT (ac)) +continue ; + +if (!skb) { + skb =skb_dequeue (&sta->tx_filtered[ac]); +if (!skb) { + skb =skb_dequeue (&sta->ps_tx_buf[ac]); +if (skb) + local->total_ps_buffered--; + } + } + +/* FIXME: take into account driver-buffered frames */ + +if (!skb_queue_empty (&sta->tx_filtered[ac]) || + !skb_queue_empty (&sta->ps_tx_buf[ac])) { + more_data = true; +break ; + } } - no_pending_pkts =skb_queue_empty (&sta->tx_filtered) && -skb_queue_empty (&sta->ps_tx_buf);if (skb) {struct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb);
@@ -1105,14 +1206,13 @@ void ieee80211_sta_ps_deliver_poll_respo info->flags |=IEEE80211_TX_CTL_PSPOLL_RESPONSE ;#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG -printk (KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n" , - sta->sta.addr, sta->sta.aid, -skb_queue_len (&sta->ps_tx_buf)); +printk (KERN_DEBUG "STA %pM aid %d: PS Poll\n" , + sta->sta.addr, sta->sta.aid);#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ /* Use MoreData flag to indicate whether there are more * buffered frames for this STA */ -if (no_pending_pkts) +if (!more_data) hdr->frame_control &=cpu_to_le16 (~IEEE80211_FCTL_MOREDATA );else hdr->frame_control |=cpu_to_le16 (IEEE80211_FCTL_MOREDATA );
@@ -1154,10 +1254,14 @@ void ieee80211_sta_set_buffered(struct i { struct sta_info *sta = container_of(pubsta, struct sta_info, sta); -if (!buffered) +if (WARN_ON (tid >=STA_TID_NUM ))return ; -set_sta_flags (sta,WLAN_STA_PS_DRIVER_BUF ); +if (buffered) +set_bit (tid, &sta->driver_buffered_tids); +else +clear_bit (tid, &sta->driver_buffered_tids); +sta_info_recalc_tim (sta); }EXPORT_SYMBOL (ieee80211_sta_set_buffered);
net/mac80211/sta_info.h +12 -12
@@ -43,8 +43,6 @@* be in the queues * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping * station in power-save mode, reply when the driver unblocks. -* @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal -* buffers. Automatically cleared on station wake-up. * @WLAN_STA_TDLS_PEER: Station is a TDLS peer. * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct * packets. This means the link is enabled.
@@ -63,7 +61,6 @@ enum ieee80211_sta_info_flags {WLAN_STA_BLOCK_BA =1 <<11 ,WLAN_STA_PS_DRIVER =1 <<12 ,WLAN_STA_PSPOLL =1 <<13 , -WLAN_STA_PS_DRIVER_BUF =1 <<14 ,WLAN_STA_TDLS_PEER =1 <<15 , WLAN_STA_TDLS_PEER_AUTH = 1<<16, };
@@ -212,11 +209,13 @@ struct sta_ampdu_mlme {* @drv_unblock_wk: used for driver PS unblocking * @listen_interval: listen interval of this station, when we're acting as AP * @flags: STA flags, see &enum ieee80211_sta_info_flags -* @ps_tx_buf: buffer of frames to transmit to this station -* when it leaves power saving state -* @tx_filtered: buffer of frames we already tried to transmit -* but were filtered by hardware due to STA having entered -* power saving state +* @ps_tx_buf: buffers (per AC) of frames to transmit to this station +* when it leaves power saving state or polls +* @tx_filtered: buffers (per AC) of frames we already tried to +* transmit but were filtered by hardware due to STA having +* entered power saving state, these are also delivered to +* the station when it leaves powersave or polls for frames +* @driver_buffered_tids: bitmap of TIDs the driver has data buffered on * @rx_packets: Number of MSDUs received from this STA * @rx_bytes: Number of bytes received from this STA * @wep_weak_iv_count: number of weak WEP IVs received from this station
@@ -286,8 +285,9 @@ struct sta_info {* STA powersave frame queues, no more than the internal * locking required. */ -struct sk_buff_head ps_tx_buf; -struct sk_buff_head tx_filtered; +struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS ]; +struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS ]; +unsigned long driver_buffered_tids;/* Updated from RX path only, no locking requirements */ unsigned long rx_packets, rx_bytes;
@@ -434,8 +434,8 @@ rcu_dereference_protected_tid_tx(struct#define STA_HASH (sta) (sta[5]) -/* Maximum number of frames to buffer per power saving station */ -#define STA_MAX_TX_BUFFER 128 +/* Maximum number of frames to buffer per power saving station per AC */ +#define STA_MAX_TX_BUFFER 64/* Minimum buffered frame expiry time. If STA uses listen interval that is * smaller than this value, the minimum value here is used instead. */
include/net/mac80211.h +1 -0
@@ -109,6 +109,7 @@ enum ieee80211_ac_numbers {IEEE80211_AC_BE =2 , IEEE80211_AC_BK = 3, }; +#define IEEE80211_NUM_ACS 4/** * struct ieee80211_tx_queue_params - transmit queue configuration
net/mac80211/status.c +14 -3
@@ -14,6 +14,7 @@#include "rate.h" #include "mesh.h" #include "led.h" +#include "wme.h" void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
@@ -43,6 +44,8 @@ static void ieee80211_handle_filtered_fr struct sk_buff *skb) {struct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb); +struct ieee80211_hdr *hdr = (void *)skb->data; +int ac;/* * This skb 'survived' a round-trip through the driver, and
@@ -62,6 +65,14 @@ static void ieee80211_handle_filtered_fr sta->tx_filtered_count++; +if (ieee80211_is_data_qos (hdr->frame_control)) { +int tid = *ieee80211_get_qos_ctl (hdr) & +IEEE80211_QOS_CTL_TID_MASK ; + ac = ieee802_1d_to_ac[tid &7 ]; + }else { + ac =IEEE80211_AC_BE ; + } +/* * Clear the TX filter mask for this STA when sending the next * packet. If the STA went to power save mode, this will happen
@@ -104,8 +115,8 @@ static void ieee80211_handle_filtered_fr* unknown. */ if (test_sta_flags (sta,WLAN_STA_PS_STA ) && -skb_queue_len (&sta->tx_filtered) <STA_MAX_TX_BUFFER ) { -skb_queue_tail (&sta->tx_filtered, skb); +skb_queue_len (&sta->tx_filtered[ac]) <STA_MAX_TX_BUFFER ) { +skb_queue_tail (&sta->tx_filtered[ac], skb);sta_info_recalc_tim (sta);if (!timer_pending (&local->sta_cleanup))
@@ -127,7 +138,7 @@ static void ieee80211_handle_filtered_frif (net_ratelimit ())wiphy_debug (local->hw.wiphy,"dropped TX filtered frame, queue_len=%d PS=%d @%lu\n" , -skb_queue_len (&sta->tx_filtered), +skb_queue_len (&sta->tx_filtered[ac]), !!test_sta_flags (sta,WLAN_STA_PS_STA ), jiffies);#endif dev_kfree_skb (skb);
net/mac80211/debugfs_sta.c +8 -2
@@ -78,8 +78,14 @@ static ssize_t sta_num_ps_buf_frames_rea size_t count, loff_t *ppos) { struct sta_info *sta = file->private_data; -return mac80211_format_buffer (userbuf, count, ppos,"%u\n" , -skb_queue_len (&sta->ps_tx_buf)); +char buf[17 *IEEE80211_NUM_ACS ], *p = buf; +int ac; + +for (ac =0 ; ac <IEEE80211_NUM_ACS ; ac++) + p +=scnprintf (p,sizeof (buf)+buf-p,"AC%d: %d\n" , ac, +skb_queue_len (&sta->ps_tx_buf[ac]) + +skb_queue_len (&sta->tx_filtered[ac])); +return simple_read_from_buffer (userbuf, count, ppos, buf, p - buf); }STA_OPS (num_ps_buf_frames);
net/mac80211/tx.c +25 -17
67 lines not on this page · raw message
Johannes Berg
maintainerPATCH v2 5/16 mac80211: remove return value from add_pending_skbs
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
Now that we no longer use the return value, we no
longer need to maintain it either, so remove it.
--- net/mac80211/ieee80211_i.h | 10 +++++----- net/mac80211/util.c | 17 +++++++---------- 2 files changed, 12 insertions(+), 15 deletions(-)
net/mac80211/ieee80211_i.h +5 -5
@@ -1303,11 +1303,11 @@ void ieee80211_stop_queue_by_reason(stru enum queue_stop_reason reason);void ieee80211_add_pending_skb (struct ieee80211_local *local,struct sk_buff *skb); -int ieee80211_add_pending_skbs (struct ieee80211_local *local, -struct sk_buff_head *skbs); -int ieee80211_add_pending_skbs_fn (struct ieee80211_local *local, -struct sk_buff_head *skbs, -void (*fn)(void *data),void *data); +void ieee80211_add_pending_skbs (struct ieee80211_local *local, +struct sk_buff_head *skbs); +void ieee80211_add_pending_skbs_fn (struct ieee80211_local *local, +struct sk_buff_head *skbs, +void (*fn)(void *data),void *data); void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg,
net/mac80211/util.c +7 -10
@@ -367,14 +367,14 @@ void ieee80211_add_pending_skb(struct iespin_unlock_irqrestore (&local->queue_stop_reason_lock, flags); } -int ieee80211_add_pending_skbs_fn (struct ieee80211_local *local, -struct sk_buff_head *skbs, -void (*fn)(void *data),void *data) +void ieee80211_add_pending_skbs_fn (struct ieee80211_local *local, +struct sk_buff_head *skbs, +void (*fn)(void *data),void *data) {struct ieee80211_hw *hw = &local->hw;struct sk_buff *skb;unsigned long flags; -int queue, ret =0 , i; +int queue, i;spin_lock_irqsave (&local->queue_stop_reason_lock, flags);for (i =0 ; i < hw->queues; i++)
@@ -389,7 +389,6 @@ int ieee80211_add_pending_skbs_fn(structcontinue ; } - ret++; queue =skb_get_queue_mapping (skb);__skb_queue_tail (&local->pending[queue], skb); }
@@ -401,14 +400,12 @@ int ieee80211_add_pending_skbs_fn(struct__ieee80211_wake_queue (hw, i,IEEE80211_QUEUE_STOP_REASON_SKB_ADD );spin_unlock_irqrestore (&local->queue_stop_reason_lock, flags); - -return ret; } -int ieee80211_add_pending_skbs (struct ieee80211_local *local, -struct sk_buff_head *skbs) +void ieee80211_add_pending_skbs (struct ieee80211_local *local, +struct sk_buff_head *skbs) { -return ieee80211_add_pending_skbs_fn (local, skbs,NULL ,NULL ); +ieee80211_add_pending_skbs_fn (local, skbs,NULL ,NULL ); } void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
Johannes Berg
maintainerPATCH v2 6/16 mac80211: clear more-data bit on filtered frames
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
It doesn't seem likely, but maybe possible, that the more-data bit needs to be recomputed due to changes in the queued frames. Clear it for filtered frames to ensure that we never send it incorrectly. It'll be set again as necessary when we retransmit this frame.
The more likely case is maybe where the station woke up after the filtered frame in which case more-data should be clear when the frame is transmitted to the station since it is now awake.
--- net/mac80211/status.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
net/mac80211/status.c +10 -0
@@ -65,6 +65,16 @@ static void ieee80211_handle_filtered_fr sta->tx_filtered_count++; +/* +* Clear more-data bit on filtered frames, it might be set +* but later frames might time out so it might have to be +* clear again ... It's all rather unlikely (this frame +* should time out first, right?) but let's not confuse +* peers unnecessarily. +*/ +if (hdr->frame_control &cpu_to_le16 (IEEE80211_FCTL_MOREDATA )) + hdr->frame_control &= ~cpu_to_le16 (IEEE80211_FCTL_MOREDATA ); +if (ieee80211_is_data_qos (hdr->frame_control)) {int tid = *ieee80211_get_qos_ctl (hdr) &IEEE80211_QOS_CTL_TID_MASK ;
Johannes Berg
maintainerPATCH v2 7/16 mac80211: allow releasing driver-buffered frames
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
If there are frames for a station buffered in the driver, mac80211 announces those in the TIM IE but there's no way to release them. Add new API to release such frames and use it when the station polls for a frame.
Since the API will soon also be used for uAPSD it is easily extensible.
Note that before this change drivers announcing driver-buffered frames in the TIM bit actually will respond to a PS-Poll with a potentially lower priority frame (if there are any frames buffered in mac80211), after this patch a driver that hasn't been changed will no longer respond at all. This only affects ath9k, which will need to be fixed to implement the new API.
--- include/net/mac80211.h | 31 ++++++++++++++++ net/mac80211/driver-ops.h | 15 ++++++++ net/mac80211/driver-trace.h | 35 ++++++++++++++++++ net/mac80211/sta_info.c | 82 +++++++++++++++++++++++++++++++++++--------- 4 files changed, 147 insertions(+), 16 deletions(-)
net/mac80211/sta_info.c +66 -16
@@ -1157,8 +1157,10 @@ void ieee80211_sta_ps_deliver_poll_respostruct ieee80211_sub_if_data *sdata = sta->sdata;struct ieee80211_local *local = sdata->local;struct sk_buff *skb =NULL ; +bool found = false;bool more_data = false;int ac; +unsigned long driver_release_tids =0 ;u8 ignore_for_response = sta->sta.uapsd_queues;/*
@@ -1173,19 +1175,40 @@ void ieee80211_sta_ps_deliver_poll_respo* Get response frame and more data bit for it. */ for (ac =0 ; ac <IEEE80211_NUM_ACS ; ac++) { +unsigned long tids; +if (ignore_for_response &BIT (ac))continue ; -if (!skb) { - skb =skb_dequeue (&sta->tx_filtered[ac]); -if (!skb) { - skb =skb_dequeue (&sta->ps_tx_buf[ac]); + tids =ieee80211_tids_for_ac (ac); + +if (!found) { + driver_release_tids = sta->driver_buffered_tids & tids; +if (driver_release_tids) { + found = true; + }else { + skb =skb_dequeue (&sta->tx_filtered[ac]); +if (!skb) { + skb =skb_dequeue (&sta->ps_tx_buf[ac]); +if (skb) + local->total_ps_buffered--; + }if (skb) - local->total_ps_buffered--; + found = true; } - } -/* FIXME: take into account driver-buffered frames */ +/* +* If the driver has data on more than one TID then +* certainly there's more data if we release just a +* single frame now (from a single TID). +*/ +if (hweight16 (driver_release_tids) >1 ) { + more_data = true; + driver_release_tids = +BIT (ffs (driver_release_tids) -1 ); +break ; + } + }if (!skb_queue_empty (&sta->tx_filtered[ac]) || !skb_queue_empty (&sta->ps_tx_buf[ac])) {
@@ -1194,6 +1217,22 @@ void ieee80211_sta_ps_deliver_poll_respo } } +if (!found) { +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG +/* +* FIXME: This can be the result of a race condition between +* us expiring a frame and the station polling for it. +* Should we send it a null-func frame indicating we +* have nothing buffered for it? +*/ +printk (KERN_DEBUG "%s: STA %pM sent PS Poll even " +"though there are no buffered frames for it\n" , + sdata->name, sta->sta.addr); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + +return ; + } +if (skb) {struct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb); struct ieee80211_hdr *hdr =
@@ -1220,18 +1259,29 @@ void ieee80211_sta_ps_deliver_poll_respoieee80211_add_pending_skb (local, skb);sta_info_recalc_tim (sta); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG }else {/* -* FIXME: This can be the result of a race condition between -* us expiring a frame and the station polling for it. -* Should we send it a null-func frame indicating we -* have nothing buffered for it? +* We need to release a frame that is buffered somewhere in the +* driver ... it'll have to handle that. +* Note that, as per the comment above, it'll also have to see +* if there is more than just one frame on the specific TID that +* we're releasing from, and it needs to set the more-data bit +* accordingly if we tell it that there's no more data. If we do +* tell it there's more data, then of course the more-data bit +* needs to be set anyway. +*/ +drv_release_buffered_frames (local, sta, driver_release_tids, +1 ,IEEE80211_FRAME_RELEASE_PSPOLL , + more_data); + +/* +* Note that we don't recalculate the TIM bit here as it would +* most likely have no effect at all unless the driver told us +* that the TID became empty before returning here from the +* release function. +* Either way, however, when the driver tells us that the TID +* became empty we'll do the TIM recalculation. */ -printk (KERN_DEBUG "%s: STA %pM sent PS Poll even " -"though there are no buffered frames for it\n" , - sdata->name, sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } }
include/net/mac80211.h +31 -0
@@ -1622,6 +1622,14 @@ enum ieee80211_tx_sync_type { };/** +* enum ieee80211_frame_release_type - frame release reason +* @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll +*/ +enum ieee80211_frame_release_type { +IEEE80211_FRAME_RELEASE_PSPOLL , +}; + +/** * struct ieee80211_ops - callbacks from mac80211 to the driver * * This structure contains various callbacks that the driver may
@@ -1931,6 +1939,23 @@ enum ieee80211_tx_sync_type {* The callback can sleep. * @rssi_callback: Notify driver when the average RSSI goes above/below * thresholds that were registered previously. The callback can sleep. +* +* @release_buffered_frames: Release buffered frames according to the given +* parameters. In the case where the driver buffers some frames for +* sleeping stations mac80211 will use this callback to tell the driver +* to release some frames, either for PS-poll or uAPSD. +* Note that if the @more_data paramter is %false the driver must check +* if there are more frames on the given TIDs, and if there are more than +* the frames being released then it must still set the more-data bit in +* the frame. If the @more_data parameter is %true, then of course the +* more-data bit must always be set. +* The @tids parameter tells the driver which TIDs to release frames +* from, for PS-poll it will always have only a single bit set. +* In the case this is used for uAPSD, the @num_frames parameter may be +* bigger than one, but the driver may send fewer frames (it must send +* at least one, however). In this case it is also responsible for +* setting the EOSP flag in the QoS header of the frames. +* This callback must be atomic. */ struct ieee80211_ops {void (*tx)(struct ieee80211_hw *hw,struct sk_buff *skb);
@@ -2045,6 +2070,12 @@ struct ieee80211_ops { const struct cfg80211_bitrate_mask *mask);void (*rssi_callback)(struct ieee80211_hw *hw,enum ieee80211_rssi_event rssi_event); + +void (*release_buffered_frames)(struct ieee80211_hw *hw, +struct ieee80211_sta *sta, +u16 tids,int num_frames, +enum ieee80211_frame_release_type reason, +bool more_data); };/**
net/mac80211/driver-ops.h +15 -0
@@ -670,4 +670,19 @@ static inline void drv_rssi_callback(str local->ops->rssi_callback (&local->hw, event); trace_drv_return_void(local); } + +static inline void +drv_release_buffered_frames (struct ieee80211_local *local, +struct sta_info *sta,u16 tids,int num_frames, +enum ieee80211_frame_release_type reason, +bool more_data) +{ +trace_drv_release_buffered_frames (local, &sta->sta, tids, num_frames, + reason, more_data); +if (local->ops->release_buffered_frames) + local->ops->release_buffered_frames (&local->hw, &sta->sta, tids, + num_frames, reason, + more_data); +trace_drv_return_void (local); +}#endif /* __MAC80211_DRIVER_OPS */
net/mac80211/driver-trace.h +35 -0
@@ -1129,6 +1129,41 @@ TRACE_EVENT(drv_rssi_callback, ) ); +TRACE_EVENT (drv_release_buffered_frames, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sta *sta, + u16 tids, int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data), + +TP_ARGS (local, sta, tids, num_frames, reason, more_data), + +TP_STRUCT__entry ( + LOCAL_ENTRY + STA_ENTRY + __field(u16, tids) + __field(int, num_frames) + __field(int, reason) +__field (bool, more_data) + ), + +TP_fast_assign ( + LOCAL_ASSIGN; + STA_ASSIGN; + __entry->tids = tids; + __entry->num_frames = num_frames; + __entry->reason = reason; + __entry->more_data = more_data; + ), + +TP_printk ( + LOCAL_PR_FMT STA_PR_FMT +" TIDs:0x%.4x frames:%d reason:%d more:%d" , +LOCAL_PR_ARG ,STA_PR_ARG , __entry->tids, __entry->num_frames, + __entry->reason, __entry->more_data + ) +); +/* * Tracing for API calls that drivers call. */
Johannes Berg
maintainerPATCH v2 8/16 mac80211: implement uAPSD
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
Add uAPSD support to mac80211. This is probably not possible with all devices, so advertising it with the cfg80211 flag will be left up to drivers that want it.
Due to my previous patches it is now a fairly straight-forward extension. Drivers need to have accurate TX status reporting for the EOSP frame. For drivers that buffer themselves, the provided APIs allow releasing the right number of frames, but then drivers need to set EOSP and more-data themselves. This is documented in more detail in the new code itself.
--- drivers/net/wireless/iwlegacy/iwl-4965-tx.c | 2 drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 2 drivers/net/wireless/p54/txrx.c | 2 include/net/mac80211.h | 24 ++- net/mac80211/rx.c | 102 ++++++++++++---- net/mac80211/sta_info.c | 170 ++++++++++++++++++++-------- net/mac80211/sta_info.h | 8 + net/mac80211/status.c | 15 ++ net/mac80211/tx.c | 8 - 9 files changed, 244 insertions(+), 89 deletions(-)
net/mac80211/rx.c +74 -28
@@ -1163,6 +1163,79 @@ int ieee80211_sta_ps_transition(struct iEXPORT_SYMBOL (ieee80211_sta_ps_transition); static ieee80211_rx_result debug_noinline +ieee80211_rx_h_uapsd_and_pspoll (struct ieee80211_rx_data *rx) +{ +struct ieee80211_sub_if_data *sdata = rx->sdata; +struct ieee80211_hdr *hdr = (void *)rx->skb->data; +struct ieee80211_rx_status *status =IEEE80211_SKB_RXCB (rx->skb); +int tid, ac; + +if (!rx->sta || !(status->rx_flags &IEEE80211_RX_RA_MATCH )) +return RX_CONTINUE ; + +if (sdata->vif.type !=NL80211_IFTYPE_AP && + sdata->vif.type !=NL80211_IFTYPE_AP_VLAN ) +return RX_CONTINUE ; + +/* +* The device handles station powersave, so don't do anything about +* uAPSD and PS-Poll frames (the latter shouldn't even come up from +* it to mac80211 since they're handled.) +*/ +if (sdata->local->hw.flags &IEEE80211_HW_AP_LINK_PS ) +return RX_CONTINUE ; + +/* +* Don't do anything if the station isn't already asleep. In +* the uAPSD case, the station will probably be marked asleep, +* in the PS-Poll case the station must be confused ... +*/ +if (!test_sta_flags (rx->sta,WLAN_STA_PS_STA )) +return RX_CONTINUE ; + +if (unlikely (ieee80211_is_pspoll (hdr->frame_control))) { +if (!test_sta_flags (rx->sta,WLAN_STA_PS_DRIVER )) +ieee80211_sta_ps_deliver_poll_response (rx->sta); +else +set_sta_flags (rx->sta,WLAN_STA_PSPOLL ); + +/* Free PS Poll skb here instead of returning RX_DROP that would +* count as an dropped frame. */ +dev_kfree_skb (rx->skb); + +return RX_QUEUED ; + }else if (!ieee80211_has_morefrags (hdr->frame_control) && + !(status->rx_flags &IEEE80211_RX_DEFERRED_RELEASE ) && +ieee80211_has_pm (hdr->frame_control) && + (ieee80211_is_data_qos (hdr->frame_control) || +ieee80211_is_qos_nullfunc (hdr->frame_control))) { + tid = *ieee80211_get_qos_ctl (hdr) &IEEE80211_QOS_CTL_TID_MASK ; + ac = ieee802_1d_to_ac[tid &7 ]; + +/* +* If this AC is not trigger-enabled do nothing. +* +* NB: This could/should check a separate bitmap of trigger- +* enabled queues, but for now we only implement uAPSD w/o +* TSPEC changes to the ACs, so they're always the same. +*/ +if (!(rx->sta->sta.uapsd_queues &BIT (ac))) +return RX_CONTINUE ; + +/* if we are in a service period, do nothing */ +if (test_sta_flags (rx->sta,WLAN_STA_SP )) +return RX_CONTINUE ; + +if (!test_sta_flags (rx->sta,WLAN_STA_PS_DRIVER )) +ieee80211_sta_ps_deliver_uapsd (rx->sta); +else +set_sta_flags (rx->sta,WLAN_STA_UAPSD ); + } + +return RX_CONTINUE ; +} + +static ieee80211_rx_result debug_noinlineieee80211_rx_h_sta_process (struct ieee80211_rx_data *rx) {struct sta_info *sta = rx->sta;
@@ -1473,33 +1546,6 @@ ieee80211_rx_h_defragment(struct ieee802 } static ieee80211_rx_result debug_noinline -ieee80211_rx_h_ps_poll (struct ieee80211_rx_data *rx) -{ -struct ieee80211_sub_if_data *sdata = rx->sdata; -__le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; -struct ieee80211_rx_status *status =IEEE80211_SKB_RXCB (rx->skb); - -if (likely (!rx->sta || !ieee80211_is_pspoll (fc) || - !(status->rx_flags &IEEE80211_RX_RA_MATCH ))) -return RX_CONTINUE ; - -if ((sdata->vif.type !=NL80211_IFTYPE_AP ) && - (sdata->vif.type !=NL80211_IFTYPE_AP_VLAN )) -return RX_DROP_UNUSABLE ; - -if (!test_sta_flags (rx->sta,WLAN_STA_PS_DRIVER )) -ieee80211_sta_ps_deliver_poll_response (rx->sta); -else -set_sta_flags (rx->sta,WLAN_STA_PSPOLL ); - -/* Free PS Poll skb here instead of returning RX_DROP that would -* count as an dropped frame. */ -dev_kfree_skb (rx->skb); - -return RX_QUEUED ; -} - -static ieee80211_rx_result debug_noinlineieee80211_rx_h_remove_qos_control (struct ieee80211_rx_data *rx) {u8 *data = rx->skb->data;
@@ -2567,9 +2613,9 @@ static void ieee80211_rx_handlers(struct CALL_RXH(ieee80211_rx_h_decrypt) CALL_RXH(ieee80211_rx_h_check_more_data) + CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll) CALL_RXH(ieee80211_rx_h_sta_process) CALL_RXH(ieee80211_rx_h_defragment) - CALL_RXH(ieee80211_rx_h_ps_poll) CALL_RXH(ieee80211_rx_h_michael_mic_verify)/* must be after MMIC verify so header is counted in MPDU mic */ #ifdef CONFIG_MAC80211_MESH
net/mac80211/sta_info.c +125 -45
242 lines not on this page · raw message
net/mac80211/sta_info.h +8 -0
@@ -46,6 +46,11 @@* @WLAN_STA_TDLS_PEER: Station is a TDLS peer. * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct * packets. This means the link is enabled. +* @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was +* keeping station in power-save mode, reply when the driver +* unblocks the station. +* @WLAN_STA_SP: Station is in a service period, so don't try to +* reply to other uAPSD trigger frames. */ enum ieee80211_sta_info_flags {WLAN_STA_AUTH =1 <<0 ,
@@ -63,6 +68,8 @@ enum ieee80211_sta_info_flags {WLAN_STA_PSPOLL =1 <<13 ,WLAN_STA_TDLS_PEER =1 <<15 ,WLAN_STA_TDLS_PEER_AUTH =1 <<16 , +WLAN_STA_UAPSD =1 <<17 , + WLAN_STA_SP = 1<<18, };#define STA_TID_NUM 16
@@ -539,5 +546,6 @@ void ieee80211_sta_expire(struct ieee802void ieee80211_sta_ps_deliver_wakeup (struct sta_info *sta);void ieee80211_sta_ps_deliver_poll_response (struct sta_info *sta); +void ieee80211_sta_ps_deliver_uapsd (struct sta_info *sta);#endif /* STA_INFO_H */
drivers/net/wireless/iwlegacy/iwl-4965-tx.c +1 -1
@@ -335,7 +335,7 @@ int iwl4965_tx_skb(struct iwl_priv *priv sta_priv = (void *)sta->drv_priv;if (sta_priv && sta_priv->asleep && - (info->flags &IEEE80211_TX_CTL_PSPOLL_RESPONSE )) { + (info->flags &IEEE80211_TX_CTL_POLL_RESPONSE )) {/* * This sends an asynchronous command to the device, * but we can rely on it being processed before the
drivers/net/wireless/iwlwifi/iwl-agn-tx.c +1 -1
@@ -300,7 +300,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, sta_priv = (void *)info->control.sta->drv_priv;if (sta_priv && sta_priv->asleep && - (info->flags &IEEE80211_TX_CTL_PSPOLL_RESPONSE )) { + (info->flags &IEEE80211_TX_CTL_POLL_RESPONSE )) {/* * This sends an asynchronous command to the device, * but we can rely on it being processed before the
drivers/net/wireless/p54/txrx.c +1 -1
@@ -689,7 +689,7 @@ static void p54_tx_80211_header(struct pif (!(info->flags &IEEE80211_TX_CTL_ASSIGN_SEQ )) *flags |=P54_HDR_FLAG_DATA_OUT_SEQNR ; -if (info->flags &IEEE80211_TX_CTL_PSPOLL_RESPONSE ) +if (info->flags &IEEE80211_TX_CTL_POLL_RESPONSE ) *flags |=P54_HDR_FLAG_DATA_OUT_NOCANCEL ;if (info->flags &IEEE80211_TX_CTL_CLEAR_PS_FILT )
include/net/mac80211.h +17 -7
@@ -339,9 +339,9 @@ struct ieee80211_bss_conf {* used to indicate that a frame was already retried due to PS * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, * used to indicate frame should not be encrypted -* @IEEE80211_TX_CTL_PSPOLL_RESPONSE: (internal?) -* This frame is a response to a PS-poll frame and should be sent -* although the station is in powersave mode. +* @IEEE80211_TX_CTL_POLL_RESPONSE: This frame is a response to a poll +* frame (PS-Poll or uAPSD) and should be sent although the station +* is in powersave mode. * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the * transmit function after the current frame, this can be used * by drivers to kick the DMA queue only if unset or when the
@@ -367,6 +367,10 @@ struct ieee80211_bss_conf {* @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate. * This flag is actually used for management frame especially for P2P * frames not being sent at CCK rate in 2GHz band. +* @IEEE80211_TX_STATUS_EOSP: This packet marks the end of service period, +* when its status is reported the service period ends. For frames in +* an SP that mac80211 transmits, it is already set; for driver frames +* the driver may set this flag. * * Note: If you have to add new flags to the enumeration, then don't * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -388,7 +392,7 @@ enum mac80211_tx_control_flags {IEEE80211_TX_INTFL_NEED_TXPROCESSING =BIT (14 ),IEEE80211_TX_INTFL_RETRIED =BIT (15 ),IEEE80211_TX_INTFL_DONT_ENCRYPT =BIT (16 ), -IEEE80211_TX_CTL_PSPOLL_RESPONSE =BIT (17 ), +IEEE80211_TX_CTL_POLL_RESPONSE =BIT (17 ),IEEE80211_TX_CTL_MORE_FRAMES =BIT (18 ),IEEE80211_TX_INTFL_RETRANSMISSION =BIT (19 ), IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20),
@@ -398,6 +402,7 @@ enum mac80211_tx_control_flags {IEEE80211_TX_CTL_TX_OFFCHAN =BIT (25 ),IEEE80211_TX_INTFL_TKIP_MIC_FAILURE =BIT (26 ),IEEE80211_TX_CTL_NO_CCK_RATE =BIT (27 ), + IEEE80211_TX_STATUS_EOSP = BIT(28), };#define IEEE80211_TX_CTL_STBC_SHIFT 23
@@ -411,9 +416,9 @@ enum mac80211_tx_control_flags {IEEE80211_TX_CTL_SEND_AFTER_DTIM |IEEE80211_TX_CTL_AMPDU | \IEEE80211_TX_STAT_TX_FILTERED |IEEE80211_TX_STAT_ACK | \IEEE80211_TX_STAT_AMPDU |IEEE80211_TX_STAT_AMPDU_NO_BACK | \ -IEEE80211_TX_CTL_RATE_CTRL_PROBE |IEEE80211_TX_CTL_PSPOLL_RESPONSE | \ +IEEE80211_TX_CTL_RATE_CTRL_PROBE |IEEE80211_TX_CTL_POLL_RESPONSE | \IEEE80211_TX_CTL_MORE_FRAMES |IEEE80211_TX_CTL_LDPC | \ - IEEE80211_TX_CTL_STBC) + IEEE80211_TX_CTL_STBC | IEEE80211_TX_STATUS_EOSP)/** * enum mac80211_rate_control_flags - per-rate flags set by the
@@ -1624,9 +1629,12 @@ enum ieee80211_tx_sync_type {/** * enum ieee80211_frame_release_type - frame release reason * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll +* @IEEE80211_FRAME_RELEASE_UAPSD: frame(s) released due to +* frame received on trigger-enabled AC */ enum ieee80211_frame_release_type {IEEE80211_FRAME_RELEASE_PSPOLL , +IEEE80211_FRAME_RELEASE_UAPSD , };/**
@@ -1954,7 +1962,9 @@ enum ieee80211_frame_release_type {* In the case this is used for uAPSD, the @num_frames parameter may be * bigger than one, but the driver may send fewer frames (it must send * at least one, however). In this case it is also responsible for -* setting the EOSP flag in the QoS header of the frames. +* setting the EOSP flag in the QoS header of the frames. Also, when the +* service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP +* on the last frame in the SP. * This callback must be atomic. */ struct ieee80211_ops {
net/mac80211/tx.c +4 -4
@@ -456,7 +456,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee staflags =get_sta_flags (sta);if (unlikely ((staflags & (WLAN_STA_PS_STA |WLAN_STA_PS_DRIVER )) && - !(info->flags &IEEE80211_TX_CTL_PSPOLL_RESPONSE ))) { + !(info->flags &IEEE80211_TX_CTL_POLL_RESPONSE ))) {int ac =skb_get_queue_mapping (tx->skb);#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -497,9 +497,9 @@ ieee80211_tx_h_unicast_ps_buf(struct iee }#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(staflags & WLAN_STA_PS_STA)) { -printk (KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " -"set -> send frame\n" , tx->sdata->name, - sta->sta.addr); +printk (KERN_DEBUG +"%s: STA %pM in PS mode, but polling/in SP -> send frame\n" , + tx->sdata->name, sta->sta.addr); }#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
net/mac80211/status.c +13 -2
@@ -76,8 +76,16 @@ static void ieee80211_handle_filtered_fr hdr->frame_control &= ~cpu_to_le16 (IEEE80211_FCTL_MOREDATA );if (ieee80211_is_data_qos (hdr->frame_control)) { -int tid = *ieee80211_get_qos_ctl (hdr) & -IEEE80211_QOS_CTL_TID_MASK ; +u8 *p =ieee80211_get_qos_ctl (hdr); +int tid = *p &IEEE80211_QOS_CTL_TID_MASK ; + +/* +* Clear EOSP if set, this could happen e.g. +* if an absence period (us being a P2P GO) +* shortens the SP. +*/ +if (*p &IEEE80211_QOS_CTL_EOSP ) + *p &= ~IEEE80211_QOS_CTL_EOSP ; ac = ieee802_1d_to_ac[tid &7 ]; }else { ac =IEEE80211_AC_BE ;
@@ -276,6 +284,9 @@ void ieee80211_tx_status(struct ieee8021if (memcmp (hdr->addr2, sta->sdata->vif.addr,ETH_ALEN ))continue ; +if (info->flags &IEEE80211_TX_STATUS_EOSP ) +clear_sta_flags (sta,WLAN_STA_SP ); + acked = !!(info->flags &IEEE80211_TX_STAT_ACK );if (!acked &&test_sta_flags (sta,WLAN_STA_PS_STA )) {/*
Johannes Berg
maintainerPATCH v2 9/16 mac80211: send (QoS) Null if no buffered frames
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
For PS-poll, there's a possible race between us expiring a frame and the station polling for it -- send it a null frame in that case.
For uAPSD, the standard says that we have to send a frame in each SP, so send null if we don't have any other frames.
--- net/mac80211/ieee80211_i.h | 1 net/mac80211/sta_info.c | 100 ++++++++++++++++++++++++++++++++++++++++----- net/mac80211/tx.c | 3 - 3 files changed, 92 insertions(+), 12 deletions(-)
net/mac80211/tx.c +1 -2
@@ -1520,8 +1520,7 @@ static int ieee80211_skb_resize(struct ireturn 0 ; } -static void ieee80211_xmit (struct ieee80211_sub_if_data *sdata, -struct sk_buff *skb) +void ieee80211_xmit (struct ieee80211_sub_if_data *sdata,struct sk_buff *skb) {struct ieee80211_local *local = sdata->local;struct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb);
net/mac80211/ieee80211_i.h +1 -0
@@ -1272,6 +1272,7 @@ void mac80211_ev_michael_mic_failure(str struct ieee80211_hdr *hdr, const u8 *tsc, gfp_t gfp);void ieee80211_set_wmm_default (struct ieee80211_sub_if_data *sdata); +void ieee80211_xmit (struct ieee80211_sub_if_data *sdata,struct sk_buff *skb);void ieee80211_tx_skb (struct ieee80211_sub_if_data *sdata,struct sk_buff *skb);void ieee802_11_parse_elems (u8 *start,size_t len,struct ieee802_11_elems *elems);
net/mac80211/sta_info.c +90 -10
131 lines not on this page · raw message
Johannes Berg
maintainerPATCH v2 10/16 mac80211: reply only once to each PS-poll
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
If a PS-poll frame is retried (but was received) there is no way to detect that since it has no sequence number. As a consequence, the standard asks us to not react to PS-poll frames until the response to one made it out (was ACKed or lost).
Implement this by using the WLAN_STA_SP flags to also indicate a PS-Poll "service period" and the IEEE80211_TX_STATUS_EOSP flag for the response packet to indicate the end of the "SP" as usual.
We could use separate flags, but that will most likely completely confuse drivers, and while the standard doesn't exclude simultaneously polling using uAPSD and PS-Poll, doing that seems quite problematic.
--- include/net/mac80211.h | 9 ++++++++- net/mac80211/rx.c | 10 ++++++---- net/mac80211/sta_info.c | 22 +++++++++++----------- net/mac80211/sta_info.h | 2 +- 4 files changed, 26 insertions(+), 17 deletions(-)
net/mac80211/rx.c +6 -4
@@ -1194,10 +1194,12 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ireturn RX_CONTINUE ;if (unlikely (ieee80211_is_pspoll (hdr->frame_control))) { -if (!test_sta_flags (rx->sta,WLAN_STA_PS_DRIVER )) -ieee80211_sta_ps_deliver_poll_response (rx->sta); -else -set_sta_flags (rx->sta,WLAN_STA_PSPOLL ); +if (!test_sta_flags (rx->sta,WLAN_STA_SP )) { +if (!test_sta_flags (rx->sta,WLAN_STA_PS_DRIVER )) +ieee80211_sta_ps_deliver_poll_response (rx->sta); +else +set_sta_flags (rx->sta,WLAN_STA_PSPOLL ); + }/* Free PS Poll skb here instead of returning RX_DROP that would * count as an dropped frame. */
net/mac80211/sta_info.h +1 -1
@@ -50,7 +50,7 @@* keeping station in power-save mode, reply when the driver * unblocks the station. * @WLAN_STA_SP: Station is in a service period, so don't try to -* reply to other uAPSD trigger frames. +* reply to other uAPSD trigger frames or PS-Poll. */ enum ieee80211_sta_info_flags {WLAN_STA_AUTH =1 <<0 ,
include/net/mac80211.h +8 -1
@@ -370,7 +370,8 @@ struct ieee80211_bss_conf {* @IEEE80211_TX_STATUS_EOSP: This packet marks the end of service period, * when its status is reported the service period ends. For frames in * an SP that mac80211 transmits, it is already set; for driver frames -* the driver may set this flag. +* the driver may set this flag. It is also used to do the same for +* PS-Poll responses. * * Note: If you have to add new flags to the enumeration, then don't * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -1959,6 +1960,12 @@ enum ieee80211_frame_release_type {* more-data bit must always be set. * The @tids parameter tells the driver which TIDs to release frames * from, for PS-poll it will always have only a single bit set. +* In the case this is used for a PS-poll initiated release, the +* @num_frames parameter will always be 1 so code can be shared. In +* this case the driver must also set %IEEE80211_TX_STATUS_EOSP flag +* on the TX status (and must report TX status) so that the PS-poll +* period is properly ended. This is used to avoid sending multiple +* responses for a retried PS-poll frame. * In the case this is used for uAPSD, the @num_frames parameter may be * bigger than one, but the driver may send fewer frames (it must send * at least one, however). In this case it is also responsible for
net/mac80211/sta_info.c +11 -11
@@ -1217,13 +1217,12 @@ static void ieee80211_send_null_response/* * Tell TX path to send this frame even though the * STA may still remain is PS mode after this frame -* exchange. +* exchange. Also set EOSP to indicate this packet +* ends the poll/service period. */ - info->flags |=IEEE80211_TX_CTL_POLL_RESPONSE ; - -if (uapsd) - info->flags |=IEEE80211_TX_STATUS_EOSP | -IEEE80211_TX_CTL_REQ_TX_STATUS ; + info->flags |=IEEE80211_TX_CTL_POLL_RESPONSE | +IEEE80211_TX_STATUS_EOSP | +IEEE80211_TX_CTL_REQ_TX_STATUS ;ieee80211_xmit (sdata, skb); }
@@ -1241,6 +1240,9 @@ ieee80211_sta_ps_deliver_response(structunsigned long driver_release_tids =0 ;struct sk_buff_head frames; +/* Service or PS-Poll period starts */ +set_sta_flags (sta,WLAN_STA_SP ); +__skb_queue_head_init (&frames);/*
@@ -1357,10 +1359,11 @@ ieee80211_sta_ps_deliver_response(struct/* set EOSP for the frame */ u8 *p =ieee80211_get_qos_ctl (hdr); *p |=IEEE80211_QOS_CTL_EOSP ; - info->flags |=IEEE80211_TX_STATUS_EOSP | -IEEE80211_TX_CTL_REQ_TX_STATUS ; } + info->flags |=IEEE80211_TX_STATUS_EOSP | +IEEE80211_TX_CTL_REQ_TX_STATUS ; +__skb_queue_tail (&pending, skb); }
@@ -1422,9 +1425,6 @@ void ieee80211_sta_ps_deliver_uapsd(struif (!delivery_enabled)return ; -/* Ohh, finally, the service period starts :-) */ -set_sta_flags (sta,WLAN_STA_SP ); -switch (sta->sta.max_sp) {case 1 : n_frames =2 ;
Johannes Berg
maintainerPATCH v2 11/16 mac80211: optimise station flags
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
The flaglock in struct sta_info has long been something that I wanted to get rid of, this finally does the conversion to atomic bitops.
The conversion itself is straight-forward in most places, a few things needed to change a bit since we can no longer use multiple bits at the same time.
On x86-64, this is a fairly significant code size reduction:
text data bss dec hex
427861 23648 1008 452517 6e7a5 before 425383 23648 976 450007 6ddd7 after
--- net/mac80211/agg-rx.c | 2 net/mac80211/agg-tx.c | 2 net/mac80211/cfg.c | 44 ++++++++++--------- net/mac80211/debugfs_sta.c | 20 ++++---- net/mac80211/ht.c | 2 net/mac80211/ibss.c | 4 - net/mac80211/iface.c | 4 - net/mac80211/key.c | 4 - net/mac80211/mesh_plink.c | 8 ++- net/mac80211/mlme.c | 22 ++++----- net/mac80211/pm.c | 2 net/mac80211/rx.c | 28 ++++++------ net/mac80211/sta_info.c | 35 ++++++++------- net/mac80211/sta_info.h | 104 ++++++++++++++------------------------------- net/mac80211/status.c | 12 ++--- net/mac80211/tx.c | 68 ++++++++++++++++------------- net/mac80211/util.c | 2 net/mac80211/wme.c | 4 - 18 files changed, 173 insertions(+), 194 deletions(-)
net/mac80211/mlme.c +10 -12
@@ -627,7 +627,7 @@ static bool ieee80211_powersave_allowed( {struct ieee80211_if_managed *mgd = &sdata->u.mgd;struct sta_info *sta =NULL ; -u32 sta_flags =0 ; +bool authorized = false;if (!mgd->powersave)return false;
@@ -645,13 +645,10 @@ static bool ieee80211_powersave_allowed(rcu_read_lock (); sta =sta_info_get (sdata, mgd->bssid);if (sta) - sta_flags =get_sta_flags (sta); + authorized =test_sta_flag (sta,WLAN_STA_AUTHORIZED );rcu_read_unlock (); -if (!(sta_flags &WLAN_STA_AUTHORIZED )) -return false; - -return true; +return authorized; }/* need to hold RTNL or interface lock */
@@ -1095,7 +1092,7 @@ static void ieee80211_set_disassoc(strucmutex_lock (&local->sta_mtx); sta =sta_info_get (sdata, bssid);if (sta) { -set_sta_flags (sta,WLAN_STA_BLOCK_BA ); +set_sta_flag (sta,WLAN_STA_BLOCK_BA );ieee80211_sta_tear_down_BA_sessions (sta, tx); }mutex_unlock (&local->sta_mtx);
@@ -1513,10 +1510,11 @@ static bool ieee80211_assoc_success(strureturn false; } -set_sta_flags (sta,WLAN_STA_AUTH |WLAN_STA_ASSOC | -WLAN_STA_ASSOC_AP ); +set_sta_flag (sta,WLAN_STA_AUTH ); +set_sta_flag (sta,WLAN_STA_ASSOC ); +set_sta_flag (sta,WLAN_STA_ASSOC_AP );if (!(ifmgd->flags &IEEE80211_STA_CONTROL_PORT )) -set_sta_flags (sta,WLAN_STA_AUTHORIZED ); +set_sta_flag (sta,WLAN_STA_AUTHORIZED ); rates =0 ; basic_rates =0 ;
@@ -1575,10 +1573,10 @@ static bool ieee80211_assoc_success(strurate_control_rate_init (sta);if (ifmgd->flags &IEEE80211_STA_MFP_ENABLED ) -set_sta_flags (sta,WLAN_STA_MFP ); +set_sta_flag (sta,WLAN_STA_MFP );if (elems.wmm_param) -set_sta_flags (sta,WLAN_STA_WME ); +set_sta_flag (sta,WLAN_STA_WME );/* sta_info_reinsert will also unlock the mutex lock */ err =sta_info_reinsert (sta);
net/mac80211/sta_info.c +19 -16
@@ -244,22 +244,22 @@ static void sta_unblock(struct work_struif (sta->dead)return ; -if (!test_sta_flags (sta,WLAN_STA_PS_STA )) +if (!test_sta_flag (sta,WLAN_STA_PS_STA ))ieee80211_sta_ps_deliver_wakeup (sta); -else if (test_and_clear_sta_flags (sta,WLAN_STA_PSPOLL )) { -clear_sta_flags (sta,WLAN_STA_PS_DRIVER ); +else if (test_and_clear_sta_flag (sta,WLAN_STA_PSPOLL )) { +clear_sta_flag (sta,WLAN_STA_PS_DRIVER );local_bh_disable ();ieee80211_sta_ps_deliver_poll_response (sta);local_bh_enable (); - }else if (test_and_clear_sta_flags (sta,WLAN_STA_UAPSD )) { -clear_sta_flags (sta,WLAN_STA_PS_DRIVER ); + }else if (test_and_clear_sta_flag (sta,WLAN_STA_UAPSD )) { +clear_sta_flag (sta,WLAN_STA_PS_DRIVER );local_bh_disable ();ieee80211_sta_ps_deliver_uapsd (sta);local_bh_enable (); }else -clear_sta_flags (sta,WLAN_STA_PS_DRIVER ); +clear_sta_flag (sta,WLAN_STA_PS_DRIVER ); } static int sta_prepare_rate_control(struct ieee80211_local *local,
@@ -292,7 +292,6 @@ struct sta_info *sta_info_alloc(struct ireturn NULL ;spin_lock_init (&sta->lock); -spin_lock_init (&sta->flaglock);INIT_WORK (&sta->drv_unblock_wk, sta_unblock);INIT_WORK (&sta->ampdu_mlme.work, ieee80211_ba_session_work);mutex_init (&sta->ampdu_mlme.mtx);
@@ -871,7 +870,7 @@ static int __must_check __sta_info_destr* sessions -- block that to make sure the tear-down * will be sufficient. */ -set_sta_flags (sta,WLAN_STA_BLOCK_BA ); +set_sta_flag (sta,WLAN_STA_BLOCK_BA );ieee80211_sta_tear_down_BA_sessions (sta, true);spin_lock_irqsave (&local->sta_lock, flags);
@@ -892,10 +891,13 @@ static int __must_check __sta_info_destr sta->dead = true; -if (test_and_clear_sta_flags (sta, -WLAN_STA_PS_STA |WLAN_STA_PS_DRIVER )) { +if (test_sta_flag (sta,WLAN_STA_PS_STA ) || +test_sta_flag (sta,WLAN_STA_PS_DRIVER )) {BUG_ON (!sdata->bss); +clear_sta_flag (sta,WLAN_STA_PS_STA ); +clear_sta_flag (sta,WLAN_STA_PS_DRIVER ); +atomic_dec (&sdata->bss->num_sta_ps);sta_info_recalc_tim (sta); }
@@ -1116,7 +1118,8 @@ static void clear_sta_ps_flags(void *_st {struct sta_info *sta = _sta; -clear_sta_flags (sta,WLAN_STA_PS_DRIVER |WLAN_STA_PS_STA ); +clear_sta_flag (sta,WLAN_STA_PS_DRIVER ); +clear_sta_flag (sta,WLAN_STA_PS_STA ); }/* powersave support code */
@@ -1127,7 +1130,7 @@ void ieee80211_sta_ps_deliver_wakeup(strstruct sk_buff_head pending;int filtered =0 , buffered =0 , ac; -clear_sta_flags (sta,WLAN_STA_SP ); +clear_sta_flag (sta,WLAN_STA_SP );BUILD_BUG_ON (BITS_TO_LONGS (STA_TID_NUM ) >1 ); sta->driver_buffered_tids =0 ;
@@ -1173,7 +1176,7 @@ static void ieee80211_send_null_responsestruct sk_buff *skb;int size =sizeof (*nullfunc);__le16 fc; -bool qos =test_sta_flags (sta,WLAN_STA_WME ); +bool qos =test_sta_flag (sta,WLAN_STA_WME );struct ieee80211_tx_info *info;if (qos) {
@@ -1241,7 +1244,7 @@ ieee80211_sta_ps_deliver_response(structstruct sk_buff_head frames;/* Service or PS-Poll period starts */ -set_sta_flags (sta,WLAN_STA_SP ); +set_sta_flag (sta,WLAN_STA_SP );__skb_queue_head_init (&frames);
@@ -1453,8 +1456,8 @@ void ieee80211_sta_block_awake(struct ietrace_api_sta_block_awake (sta->local, pubsta, block);if (block) -set_sta_flags (sta,WLAN_STA_PS_DRIVER ); -else if (test_sta_flags (sta,WLAN_STA_PS_DRIVER )) +set_sta_flag (sta,WLAN_STA_PS_DRIVER ); +else if (test_sta_flag (sta,WLAN_STA_PS_DRIVER ))ieee80211_queue_work (hw, &sta->drv_unblock_wk); }EXPORT_SYMBOL (ieee80211_sta_block_awake);
net/mac80211/sta_info.h +34 -70
152 lines not on this page · raw message
net/mac80211/agg-rx.c +1 -1
@@ -223,7 +223,7 @@ void ieee80211_process_addba_request(str status =WLAN_STATUS_REQUEST_DECLINED ; -if (test_sta_flags (sta,WLAN_STA_BLOCK_BA )) { +if (test_sta_flag (sta,WLAN_STA_BLOCK_BA )) {#ifdef CONFIG_MAC80211_HT_DEBUG printk (KERN_DEBUG "Suspend in progress. " "Denying ADDBA request\n" );
net/mac80211/agg-tx.c +1 -1
@@ -382,7 +382,7 @@ int ieee80211_start_tx_ba_session(struct sdata->vif.type != NL80211_IFTYPE_AP)return -EINVAL ; -if (test_sta_flags (sta,WLAN_STA_BLOCK_BA )) { +if (test_sta_flag (sta,WLAN_STA_BLOCK_BA )) {#ifdef CONFIG_MAC80211_HT_DEBUG printk (KERN_DEBUG "BA sessions blocked. " "Denying BA session request\n" );
net/mac80211/ht.c +1 -1
@@ -130,7 +130,7 @@ void ieee80211_ba_session_work(struct wo* down by the code that set the flag, so this * need not run. */ -if (test_sta_flags (sta,WLAN_STA_BLOCK_BA )) +if (test_sta_flag (sta,WLAN_STA_BLOCK_BA ))return ;mutex_lock (&sta->ampdu_mlme.mtx);
net/mac80211/ibss.c +2 -2
@@ -314,7 +314,7 @@ static void ieee80211_rx_bss_info(struct }if (sta && elems->wmm_info) -set_sta_flags (sta,WLAN_STA_WME ); +set_sta_flag (sta,WLAN_STA_WME );rcu_read_unlock (); }
@@ -452,7 +452,7 @@ struct sta_info *ieee80211_ibss_add_sta(return NULL ; sta->last_rx = jiffies; -set_sta_flags (sta,WLAN_STA_AUTHORIZED ); +set_sta_flag (sta,WLAN_STA_AUTHORIZED );/* make sure mandatory rates are always added */ sta->sta.supp_rates[band] = supp_rates |
net/mac80211/key.c +2 -2
@@ -464,7 +464,7 @@ int ieee80211_key_link(struct ieee80211_* some hardware cannot handle TKIP with QoS, so * we indicate whether QoS could be in use. */ -if (test_sta_flags (sta,WLAN_STA_WME )) +if (test_sta_flag (sta,WLAN_STA_WME )) key->conf.flags |=IEEE80211_KEY_FLAG_WMM_STA ; }else {if (sdata->vif.type ==NL80211_IFTYPE_STATION ) {
@@ -478,7 +478,7 @@ int ieee80211_key_link(struct ieee80211_/* same here, the AP could be using QoS */ ap =sta_info_get (key->sdata, key->sdata->u.mgd.bssid);if (ap) { -if (test_sta_flags (ap,WLAN_STA_WME )) +if (test_sta_flag (ap,WLAN_STA_WME )) key->conf.flags |=IEEE80211_KEY_FLAG_WMM_STA ; }
net/mac80211/mesh_plink.c +5 -3
@@ -92,7 +92,9 @@ static struct sta_info *mesh_plink_allocif (!sta)return NULL ; - sta->flags =WLAN_STA_AUTHORIZED |WLAN_STA_AUTH |WLAN_STA_WME ; +set_sta_flag (sta,WLAN_STA_AUTH ); +set_sta_flag (sta,WLAN_STA_AUTHORIZED ); +set_sta_flag (sta,WLAN_STA_WME ); sta->sta.supp_rates[local->hw.conf.channel->band] = rates;rate_control_rate_init (sta);
@@ -383,7 +385,7 @@ int mesh_plink_open(struct sta_info *sta__le16 llid;struct ieee80211_sub_if_data *sdata = sta->sdata; -if (!test_sta_flags (sta,WLAN_STA_AUTH )) +if (!test_sta_flag (sta,WLAN_STA_AUTH ))return -EPERM ;spin_lock_bh (&sta->lock);
@@ -503,7 +505,7 @@ void mesh_rx_plink_frame(struct ieee8021return ; } -if (sta && !test_sta_flags (sta,WLAN_STA_AUTH )) { +if (sta && !test_sta_flag (sta,WLAN_STA_AUTH )) {mpl_dbg ("Mesh plink: Action frame from non-authed peer\n" );rcu_read_unlock ();return ;
net/mac80211/pm.c +1 -1
@@ -42,7 +42,7 @@ int __ieee80211_suspend(struct ieee80211if (hw->flags &IEEE80211_HW_AMPDU_AGGREGATION ) {mutex_lock (&local->sta_mtx);list_for_each_entry (sta, &local->sta_list, list) { -set_sta_flags (sta,WLAN_STA_BLOCK_BA ); +set_sta_flag (sta,WLAN_STA_BLOCK_BA );ieee80211_sta_tear_down_BA_sessions (sta, true); }mutex_unlock (&local->sta_mtx);
net/mac80211/rx.c +14 -14
@@ -841,7 +841,7 @@ ieee80211_rx_h_check(struct ieee80211_rx ieee80211_is_pspoll(hdr->frame_control)) && rx->sdata->vif.type !=NL80211_IFTYPE_ADHOC && rx->sdata->vif.type !=NL80211_IFTYPE_WDS && - (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { + (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { if (rx->sta && rx->sta->dummy && ieee80211_is_data_present(hdr->frame_control)) {u16 ethertype;
@@ -1110,7 +1110,7 @@ static void ap_sta_ps_start(struct sta_istruct ieee80211_local *local = sdata->local;atomic_inc (&sdata->bss->num_sta_ps); -set_sta_flags (sta,WLAN_STA_PS_STA ); +set_sta_flag (sta,WLAN_STA_PS_STA );if (!(local->hw.flags &IEEE80211_HW_AP_LINK_PS ))drv_sta_notify (local, sdata,STA_NOTIFY_SLEEP , &sta->sta);#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -1130,7 +1130,7 @@ static void ap_sta_ps_end(struct sta_inf sdata->name, sta->sta.addr, sta->sta.aid);#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ -if (test_sta_flags (sta,WLAN_STA_PS_DRIVER )) { +if (test_sta_flag (sta,WLAN_STA_PS_DRIVER )) {#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk (KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n" , sdata->name, sta->sta.addr, sta->sta.aid);
@@ -1149,7 +1149,7 @@ int ieee80211_sta_ps_transition(struct iWARN_ON (!(sta_inf->local->hw.flags &IEEE80211_HW_AP_LINK_PS ));/* Don't let the same PS state be set twice */ - in_ps =test_sta_flags (sta_inf,WLAN_STA_PS_STA ); + in_ps =test_sta_flag (sta_inf,WLAN_STA_PS_STA );if ((start && in_ps) || (!start && !in_ps))return -EINVAL ;
@@ -1190,15 +1190,15 @@ ieee80211_rx_h_uapsd_and_pspoll(struct i* the uAPSD case, the station will probably be marked asleep, * in the PS-Poll case the station must be confused ... */ -if (!test_sta_flags (rx->sta,WLAN_STA_PS_STA )) +if (!test_sta_flag (rx->sta,WLAN_STA_PS_STA ))return RX_CONTINUE ;if (unlikely (ieee80211_is_pspoll (hdr->frame_control))) { -if (!test_sta_flags (rx->sta,WLAN_STA_SP )) { -if (!test_sta_flags (rx->sta,WLAN_STA_PS_DRIVER )) +if (!test_sta_flag (rx->sta,WLAN_STA_SP )) { +if (!test_sta_flag (rx->sta,WLAN_STA_PS_DRIVER ))ieee80211_sta_ps_deliver_poll_response (rx->sta);else -set_sta_flags (rx->sta,WLAN_STA_PSPOLL ); +set_sta_flag (rx->sta,WLAN_STA_PSPOLL ); }/* Free PS Poll skb here instead of returning RX_DROP that would
@@ -1225,13 +1225,13 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ireturn RX_CONTINUE ;/* if we are in a service period, do nothing */ -if (test_sta_flags (rx->sta,WLAN_STA_SP )) +if (test_sta_flag (rx->sta,WLAN_STA_SP ))return RX_CONTINUE ; -if (!test_sta_flags (rx->sta,WLAN_STA_PS_DRIVER )) +if (!test_sta_flag (rx->sta,WLAN_STA_PS_DRIVER ))ieee80211_sta_ps_deliver_uapsd (rx->sta);else -set_sta_flags (rx->sta,WLAN_STA_UAPSD ); +set_sta_flag (rx->sta,WLAN_STA_UAPSD ); }return RX_CONTINUE ;
@@ -1295,7 +1295,7 @@ ieee80211_rx_h_sta_process(struct ieee80 !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && (rx->sdata->vif.type == NL80211_IFTYPE_AP || rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { -if (test_sta_flags (sta,WLAN_STA_PS_STA )) { +if (test_sta_flag (sta,WLAN_STA_PS_STA )) {/* * Ignore doze->wake transitions that are * indicated by non-data frames, the standard
@@ -1570,7 +1570,7 @@ static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) {if (unlikely (!rx->sta || - !test_sta_flags (rx->sta,WLAN_STA_AUTHORIZED ))) + !test_sta_flag (rx->sta,WLAN_STA_AUTHORIZED )))return -EACCES ;return 0 ;
@@ -1613,7 +1613,7 @@ ieee80211_drop_unencrypted_mgmt(struct iif (status->flag &RX_FLAG_DECRYPTED )return 0 ; -if (rx->sta &&test_sta_flags (rx->sta,WLAN_STA_MFP )) { +if (rx->sta &&test_sta_flag (rx->sta,WLAN_STA_MFP )) {if (unlikely (!ieee80211_has_protected (fc) &&ieee80211_is_unicast_robust_mgmt_frame (rx->skb) && rx->key)) {
net/mac80211/status.c +6 -6
@@ -96,7 +96,7 @@ static void ieee80211_handle_filtered_fr* packet. If the STA went to power save mode, this will happen * when it wakes up for the next time. */ -set_sta_flags (sta,WLAN_STA_CLEAR_PS_FILT ); +set_sta_flag (sta,WLAN_STA_CLEAR_PS_FILT );/* * This code races in the following way:
@@ -132,7 +132,7 @@ static void ieee80211_handle_filtered_fr* changes before calling TX status events if ordering can be * unknown. */ -if (test_sta_flags (sta,WLAN_STA_PS_STA ) && +if (test_sta_flag (sta,WLAN_STA_PS_STA ) &&skb_queue_len (&sta->tx_filtered[ac]) <STA_MAX_TX_BUFFER ) {skb_queue_tail (&sta->tx_filtered[ac], skb);sta_info_recalc_tim (sta);
@@ -144,7 +144,7 @@ static void ieee80211_handle_filtered_frreturn ; } -if (!test_sta_flags (sta,WLAN_STA_PS_STA ) && +if (!test_sta_flag (sta,WLAN_STA_PS_STA ) && !(info->flags &IEEE80211_TX_INTFL_RETRIED )) {/* Software retry the packet once */ info->flags |=IEEE80211_TX_INTFL_RETRIED ;
@@ -157,7 +157,7 @@ static void ieee80211_handle_filtered_frwiphy_debug (local->hw.wiphy,"dropped TX filtered frame, queue_len=%d PS=%d @%lu\n" ,skb_queue_len (&sta->tx_filtered[ac]), - !!test_sta_flags (sta,WLAN_STA_PS_STA ), jiffies); + !!test_sta_flag (sta,WLAN_STA_PS_STA ), jiffies);#endif dev_kfree_skb (skb); }
@@ -285,10 +285,10 @@ void ieee80211_tx_status(struct ieee8021continue ;if (info->flags &IEEE80211_TX_STATUS_EOSP ) -clear_sta_flags (sta,WLAN_STA_SP ); +clear_sta_flag (sta,WLAN_STA_SP ); acked = !!(info->flags &IEEE80211_TX_STAT_ACK ); -if (!acked &&test_sta_flags (sta,WLAN_STA_PS_STA )) { +if (!acked &&test_sta_flag (sta,WLAN_STA_PS_STA )) {/* * The STA is in power save mode, so assume * that this TX packet failed because of that.
net/mac80211/tx.c +38 -30
188 lines not on this page · raw message
net/mac80211/util.c +1 -1
@@ -1122,7 +1122,7 @@ int ieee80211_reconfig(struct ieee80211_list_for_each_entry (sta, &local->sta_list, list) {ieee80211_sta_tear_down_BA_sessions (sta, true); -clear_sta_flags (sta,WLAN_STA_BLOCK_BA ); +clear_sta_flag (sta,WLAN_STA_BLOCK_BA ); }mutex_unlock (&local->sta_mtx);
net/mac80211/cfg.c +24 -20
106 lines not on this page · raw message
net/mac80211/wme.c +2 -2
@@ -72,7 +72,7 @@ u16 ieee80211_select_queue(struct ieee80case NL80211_IFTYPE_AP_VLAN : sta =rcu_dereference (sdata->u.vlan.sta);if (sta) { - qos =get_sta_flags (sta) &WLAN_STA_WME ; + qos =test_sta_flag (sta,WLAN_STA_WME );break ; }case NL80211_IFTYPE_AP :
@@ -99,7 +99,7 @@ u16 ieee80211_select_queue(struct ieee80if (!sta && ra && !is_multicast_ether_addr (ra)) { sta =sta_info_get (sdata, ra);if (sta) - qos =get_sta_flags (sta) &WLAN_STA_WME ; + qos =test_sta_flag (sta,WLAN_STA_WME ); }rcu_read_unlock ();
net/mac80211/debugfs_sta.c +10 -10
@@ -58,17 +58,17 @@ static ssize_t sta_flags_read(struct fil {char buf[100 ];struct sta_info *sta = file->private_data; -u32 staflags =get_sta_flags (sta); +int res =scnprintf (buf,sizeof (buf),"%s%s%s%s%s%s%s%s%s" , - staflags &WLAN_STA_AUTH ?"AUTH\n" :"" , - staflags &WLAN_STA_ASSOC ?"ASSOC\n" :"" , - staflags &WLAN_STA_PS_STA ?"PS (sta)\n" :"" , - staflags &WLAN_STA_PS_DRIVER ?"PS (driver)\n" :"" , - staflags &WLAN_STA_AUTHORIZED ?"AUTHORIZED\n" :"" , - staflags &WLAN_STA_SHORT_PREAMBLE ?"SHORT PREAMBLE\n" :"" , - staflags &WLAN_STA_WME ?"WME\n" :"" , - staflags &WLAN_STA_WDS ?"WDS\n" :"" , - staflags &WLAN_STA_MFP ?"MFP\n" :"" ); +test_sta_flag (sta,WLAN_STA_AUTH ) ?"AUTH\n" :"" , +test_sta_flag (sta,WLAN_STA_ASSOC ) ?"ASSOC\n" :"" , +test_sta_flag (sta,WLAN_STA_PS_STA ) ?"PS (sta)\n" :"" , +test_sta_flag (sta,WLAN_STA_PS_DRIVER ) ?"PS (driver)\n" :"" , +test_sta_flag (sta,WLAN_STA_AUTHORIZED ) ?"AUTHORIZED\n" :"" , +test_sta_flag (sta,WLAN_STA_SHORT_PREAMBLE ) ?"SHORT PREAMBLE\n" :"" , +test_sta_flag (sta,WLAN_STA_WME ) ?"WME\n" :"" , +test_sta_flag (sta,WLAN_STA_WDS ) ?"WDS\n" :"" , +test_sta_flag (sta,WLAN_STA_MFP ) ?"MFP\n" :"" );return simple_read_from_buffer (userbuf, count, ppos, buf, res); }STA_OPS (flags);
net/mac80211/iface.c +2 -2
@@ -299,8 +299,8 @@ static int ieee80211_do_open(struct net_ goto err_del_interface; } -/* no locking required since STA is not live yet */ - sta->flags |=WLAN_STA_AUTHORIZED ; +/* no atomic bitop required since STA is not live yet */ +set_sta_flag (sta,WLAN_STA_AUTHORIZED ); res =sta_info_insert (sta);if (res) {
Johannes Berg
maintainerPATCH v2 12/16 mac80211: add missing station flags to debugfs
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
My work and some previous work didn't add
all the flags, add them now and while at it
simplify the code.
--- net/mac80211/debugfs_sta.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-)
net/mac80211/debugfs_sta.c +14 -11
@@ -56,19 +56,22 @@ STA_FILE(last_signal, last_signal, D);static ssize_t sta_flags_read (struct file *file,char __user *userbuf,size_t count,loff_t *ppos) { -char buf[100 ]; +char buf[121 ];struct sta_info *sta = file->private_data; -int res =scnprintf (buf,sizeof (buf),"%s%s%s%s%s%s%s%s%s" , -test_sta_flag (sta,WLAN_STA_AUTH ) ?"AUTH\n" :"" , -test_sta_flag (sta,WLAN_STA_ASSOC ) ?"ASSOC\n" :"" , -test_sta_flag (sta,WLAN_STA_PS_STA ) ?"PS (sta)\n" :"" , -test_sta_flag (sta,WLAN_STA_PS_DRIVER ) ?"PS (driver)\n" :"" , -test_sta_flag (sta,WLAN_STA_AUTHORIZED ) ?"AUTHORIZED\n" :"" , -test_sta_flag (sta,WLAN_STA_SHORT_PREAMBLE ) ?"SHORT PREAMBLE\n" :"" , -test_sta_flag (sta,WLAN_STA_WME ) ?"WME\n" :"" , -test_sta_flag (sta,WLAN_STA_WDS ) ?"WDS\n" :"" , -test_sta_flag (sta,WLAN_STA_MFP ) ?"MFP\n" :"" ); +#define TEST (flg) \ + test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" + +int res =scnprintf (buf,sizeof (buf), +"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" , +TEST (AUTH ),TEST (ASSOC ),TEST (PS_STA ), +TEST (PS_DRIVER ),TEST (AUTHORIZED ), +TEST (SHORT_PREAMBLE ),TEST (ASSOC_AP ), +TEST (WME ),TEST (WDS ),TEST (CLEAR_PS_FILT ), +TEST (MFP ),TEST (BLOCK_BA ),TEST (PSPOLL ), +TEST (UAPSD ),TEST (SP ),TEST (TDLS_PEER ), +TEST (TDLS_PEER_AUTH )); +#undef TESTreturn simple_read_from_buffer (userbuf, count, ppos, buf, res); }STA_OPS (flags);
Johannes Berg
maintainerPATCH v2 13/16 mac80211: explicitly notify drivers of frame release
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
iwlwifi needs to know the number of frames that are going to be sent to a station while it is asleep so it can properly handle the uCode blocking of that station.
Before uAPSD, we got by by telling the device that a single frame was going to be released whenever we encountered IEEE80211_TX_CTL_POLL_RESPONSE. With uAPSD, however, that is no longer possible since there could be more than a single frame.
To support this model, add a new callback to notify drivers when frames are going to be released.
--- include/net/mac80211.h | 17 +++++++++++++++++ net/mac80211/driver-ops.h | 15 +++++++++++++++ net/mac80211/driver-trace.h | 22 +++++++++++++++++++++- net/mac80211/sta_info.c | 34 +++++++++++++++++++++++++--------- 4 files changed, 78 insertions(+), 10 deletions(-)
include/net/mac80211.h +17 -0
@@ -1973,6 +1973,18 @@ enum ieee80211_frame_release_type {* service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP * on the last frame in the SP. * This callback must be atomic. +* @allow_buffered_frames: Prepare device to allow the given number of frames +* to go out to the given station. The frames will be sent by mac80211 +* via the usual TX path after this call. The TX information for frames +* released will also have the %IEEE80211_TX_CTL_POLL_RESPONSE flag set +* and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case +* frames from multiple TIDs are released and the driver might reorder +* them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag +* on the last frame and clear it on all others and also handle the EOSP +* bit in the QoS header correctly. +* The @tids parameter is a bitmap and tells the driver which TIDs the +* frames will be on; it will at most have two bits set. +* This callback must be atomic. */ struct ieee80211_ops {void (*tx)(struct ieee80211_hw *hw,struct sk_buff *skb);
@@ -2088,6 +2100,11 @@ struct ieee80211_ops {void (*rssi_callback)(struct ieee80211_hw *hw,enum ieee80211_rssi_event rssi_event); +void (*allow_buffered_frames)(struct ieee80211_hw *hw, +struct ieee80211_sta *sta, +u16 tids,int num_frames, +enum ieee80211_frame_release_type reason, +bool more_data); void (*release_buffered_frames)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tids, int num_frames,
net/mac80211/driver-ops.h +15 -0
@@ -685,4 +685,19 @@ drv_release_buffered_frames(struct ieee8 more_data); trace_drv_return_void(local); } + +static inline void +drv_allow_buffered_frames (struct ieee80211_local *local, +struct sta_info *sta,u16 tids,int num_frames, +enum ieee80211_frame_release_type reason, +bool more_data) +{ +trace_drv_allow_buffered_frames (local, &sta->sta, tids, num_frames, + reason, more_data); +if (local->ops->allow_buffered_frames) + local->ops->allow_buffered_frames (&local->hw, &sta->sta, + tids, num_frames, reason, + more_data); +trace_drv_return_void (local); +}#endif /* __MAC80211_DRIVER_OPS */
net/mac80211/driver-trace.h +21 -1
@@ -1129,7 +1129,7 @@ TRACE_EVENT(drv_rssi_callback, ) ); -TRACE_EVENT(drv_release_buffered_frames, +DECLARE_EVENT_CLASS(release_evt, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta, u16 tids, int num_frames,
@@ -1164,6 +1164,26 @@ TRACE_EVENT(drv_release_buffered_frames, ) ); +DEFINE_EVENT (release_evt, drv_release_buffered_frames, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sta *sta, + u16 tids, int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data), + +TP_ARGS (local, sta, tids, num_frames, reason, more_data) +); + +DEFINE_EVENT (release_evt, drv_allow_buffered_frames, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sta *sta, + u16 tids, int num_frames, + enum ieee80211_frame_release_type reason, + bool more_data), + +TP_ARGS (local, sta, tids, num_frames, reason, more_data) +); +/* * Tracing for API calls that drivers call. */
net/mac80211/sta_info.c +25 -9
@@ -1169,7 +1169,7 @@ void ieee80211_sta_ps_deliver_wakeup(strstatic void ieee80211_send_null_response (struct ieee80211_sub_if_data *sdata,struct sta_info *sta,int tid, -bool uapsd) +enum ieee80211_frame_release_type reason) {struct ieee80211_local *local = sdata->local;struct ieee80211_qos_hdr *nullfunc;
@@ -1210,7 +1210,7 @@ static void ieee80211_send_null_response nullfunc->qos_ctrl =cpu_to_le16 (tid); -if (uapsd) +if (reason ==IEEE80211_FRAME_RELEASE_UAPSD ) nullfunc->qos_ctrl |=cpu_to_le16 (IEEE80211_QOS_CTL_EOSP ); }
@@ -1227,6 +1227,8 @@ static void ieee80211_send_null_responseIEEE80211_TX_STATUS_EOSP |IEEE80211_TX_CTL_REQ_TX_STATUS ; +drv_allow_buffered_frames (local, sta,BIT (tid),1 , reason, false); +ieee80211_xmit (sdata, skb); }
@@ -1324,20 +1326,24 @@ ieee80211_sta_ps_deliver_response(struct/* This will evaluate to 1, 3, 5 or 7. */ tid =7 - ((ffs (~ignored_acs) -1 ) <<1 ); -ieee80211_send_null_response (sdata, sta, tid, - reason ==IEEE80211_FRAME_RELEASE_UAPSD ); +ieee80211_send_null_response (sdata, sta, tid, reason);return ; }if (!driver_release_tids) {struct sk_buff_head pending;struct sk_buff *skb; +int num =0 ; +u16 tids =0 ;skb_queue_head_init (&pending);while ((skb =__skb_dequeue (&frames))) {struct ieee80211_tx_info *info =IEEE80211_SKB_CB (skb);struct ieee80211_hdr *hdr = (void *) skb->data; +u8 *qoshdr =NULL ; + + num++;/* * Tell TX path to send this frame even though the
@@ -1357,19 +1363,29 @@ ieee80211_sta_ps_deliver_response(struct hdr->frame_control |=cpu_to_le16 (IEEE80211_FCTL_MOREDATA ); +if (ieee80211_is_data_qos (hdr->frame_control) || +ieee80211_is_qos_nullfunc (hdr->frame_control)) + qoshdr =ieee80211_get_qos_ctl (hdr); + +/* set EOSP for the frame */ if (reason ==IEEE80211_FRAME_RELEASE_UAPSD && -skb_queue_empty (&frames)) { -/* set EOSP for the frame */ -u8 *p =ieee80211_get_qos_ctl (hdr); - *p |=IEEE80211_QOS_CTL_EOSP ; - } + qoshdr &&skb_queue_empty (&frames)) + *qoshdr |=IEEE80211_QOS_CTL_EOSP ; info->flags |=IEEE80211_TX_STATUS_EOSP |IEEE80211_TX_CTL_REQ_TX_STATUS ; +if (qoshdr) + tids |=BIT (*qoshdr &IEEE80211_QOS_CTL_TID_MASK ); +else + tids |=BIT (0 ); +__skb_queue_tail (&pending, skb); } +drv_allow_buffered_frames (local, sta, tids, num, + reason, more_data); +ieee80211_add_pending_skbs (local, &pending);sta_info_recalc_tim (sta);
Johannes Berg
maintainerPATCH v2 14/16 mac80211: allow out-of-band EOSP notification
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
iwlwifi has a separate EOSP notification from the device, and to make use of that properly it needs to be passed to mac80211. To be able to mix with tx_status_irqsafe and rx_irqsafe it also needs to be an "_irqsafe" version in the sense that it goes through the tasklet, the actual flag clearing would be IRQ-safe but doing it directly would cause reordering issues.
This is needed in the case of a P2P GO going into an absence period without transmitting any frames that should be driver-released as in this case there's no other way to inform mac80211 that the service period ended. Note that for drivers that don't use the _irqsafe functions another version of this function will be required.
--- include/net/mac80211.h | 24 ++++++++++++++++++++++-- net/mac80211/driver-trace.h | 22 ++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 5 +++++ net/mac80211/main.c | 14 ++++++++++++++ net/mac80211/sta_info.c | 25 +++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 2 deletions(-)
net/mac80211/sta_info.c +25 -0
@@ -1478,6 +1478,31 @@ void ieee80211_sta_block_awake(struct ie }EXPORT_SYMBOL (ieee80211_sta_block_awake); +void ieee80211_sta_eosp_irqsafe (struct ieee80211_sta *pubsta) +{ + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); +struct ieee80211_local *local = sta->local; +struct sk_buff *skb; +struct skb_eosp_msg_data *data; + +trace_api_eosp (local, pubsta); + + skb =alloc_skb (0 ,GFP_ATOMIC ); +if (!skb) { +/* too bad ... but race is better than loss */ +clear_sta_flag (sta,WLAN_STA_SP ); +return ; + } + + data = (void *)skb->cb; +memcpy (data->sta, pubsta->addr,ETH_ALEN ); +memcpy (data->iface, sta->sdata->vif.addr,ETH_ALEN ); + skb->pkt_type =IEEE80211_EOSP_MSG ; +skb_queue_tail (&local->skb_queue, skb); +tasklet_schedule (&local->tasklet); +} +EXPORT_SYMBOL (ieee80211_sta_eosp_irqsafe); +void ieee80211_sta_set_buffered (struct ieee80211_sta *pubsta,u8 tid,bool buffered) {
include/net/mac80211.h +22 -2
@@ -1971,7 +1971,8 @@ enum ieee80211_frame_release_type {* at least one, however). In this case it is also responsible for * setting the EOSP flag in the QoS header of the frames. Also, when the * service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP -* on the last frame in the SP. +* on the last frame in the SP. Alternatively, it may call the function +* ieee80211_sta_eosp_irqsafe() to inform mac80211 of the end of the SP. * This callback must be atomic. * @allow_buffered_frames: Prepare device to allow the given number of frames * to go out to the given station. The frames will be sent by mac80211
@@ -1981,7 +1982,8 @@ enum ieee80211_frame_release_type {* frames from multiple TIDs are released and the driver might reorder * them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag * on the last frame and clear it on all others and also handle the EOSP -* bit in the QoS header correctly. +* bit in the QoS header correctly. Alternatively, it can also call the +* ieee80211_sta_eosp_irqsafe() function. * The @tids parameter is a bitmap and tells the driver which TIDs the * frames will be on; it will at most have two bits set. * This callback must be atomic.
@@ -3113,6 +3115,24 @@ void ieee80211_sta_block_awake(struct ie struct ieee80211_sta *pubsta, bool block);/** +* ieee80211_sta_eosp - notify mac80211 about end of SP +* @pubsta: the station +* +* When a device transmits frames in a way that it can't tell +* mac80211 in the TX status about the EOSP, it must clear the +* %IEEE80211_TX_STATUS_EOSP bit and call this function instead. +* This applies for PS-Poll as well as uAPSD. +* +* Note that there is no non-_irqsafe version right now as +* it wasn't needed, but just like _tx_status() and _rx() +* must not be mixed in irqsafe/non-irqsafe versions, this +* function must not be mixed with those either. Use the +* all irqsafe, or all non-irqsafe, don't mix! If you need +* the non-irqsafe version of this, you need to add it. +*/ +void ieee80211_sta_eosp_irqsafe (struct ieee80211_sta *pubsta); + +/** * ieee80211_iter_keys - iterate keys programmed into the device * @hw: pointer obtained from ieee80211_alloc_hw() * @vif: virtual interface to iterate, may be %NULL for all
net/mac80211/main.c +14 -0
@@ -325,6 +325,8 @@ u32 ieee80211_reset_erp_info(struct ieeestatic void ieee80211_tasklet_handler (unsigned long data) {struct ieee80211_local *local = (struct ieee80211_local *) data; +struct sta_info *sta, *tmp; +struct skb_eosp_msg_data *eosp_data;struct sk_buff *skb; while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -340,6 +342,18 @@ static void ieee80211_tasklet_handler(un skb->pkt_type =0 ;ieee80211_tx_status (local_to_hw (local), skb);break ; +case IEEE80211_EOSP_MSG : + eosp_data = (void *)skb->cb; +for_each_sta_info (local, eosp_data->sta, sta, tmp) { +/* skip wrong virtual interface */ +if (memcmp (eosp_data->iface, + sta->sdata->vif.addr,ETH_ALEN )) +continue ; +clear_sta_flag (sta,WLAN_STA_SP ); +break ; + } +dev_kfree_skb (skb); +break ;default :WARN (1 ,"mac80211: Packet is of unknown type %d\n" , skb->pkt_type);
net/mac80211/ieee80211_i.h +5 -0
@@ -664,6 +664,11 @@ enum sdata_queue_type {enum {IEEE80211_RX_MSG =1 ,IEEE80211_TX_STATUS_MSG =2 , +IEEE80211_EOSP_MSG =3 , +}; + +struct skb_eosp_msg_data { +u8 sta[ETH_ALEN ], iface[ETH_ALEN ]; };enum queue_stop_reason {
net/mac80211/driver-trace.h +22 -0
@@ -1498,6 +1498,28 @@ TRACE_EVENT(api_enable_rssi_reports, ) ); +TRACE_EVENT (api_eosp, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sta *sta), + +TP_ARGS (local, sta), + +TP_STRUCT__entry ( +LOCAL_ENTRY + STA_ENTRY + ), + +TP_fast_assign ( + LOCAL_ASSIGN; + STA_ASSIGN; + ), + +TP_printk ( + LOCAL_PR_FMT STA_PR_FMT, +LOCAL_PR_ARG ,STA_PR_FMT + ) +); +/* * Tracing for internal functions * (which may also be called in response to driver calls)
Johannes Berg
maintainerPATCH v2 15/16 mac80211: document client powersave
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
With the addition of uAPSD and driver buffering the powersave handling has gotten quite complex. Add a section to the documentation to explain it for anyone wanting to implement it.
--- Documentation/DocBook/80211.tmpl | 11 ++++ include/net/mac80211.h | 89 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-)
Documentation/DocBook/80211.tmpl +10 -1
@@ -450,8 +450,18 @@ MISSING Insert notes about VLAN interfaces with hw crypto here or in the hw crypto chapter. </para> + <section id="ps-client"> + <title>support for powersaving clients</title> +!Pinclude/net/mac80211.h AP support for powersaving clients + </section> !Finclude/net/mac80211.h ieee80211_get_buffered_bc !Finclude/net/mac80211.h ieee80211_beacon_get +!Finclude/net/mac80211.h ieee80211_sta_eosp_irqsafe +!Finclude/net/mac80211.h ieee80211_frame_release_type +!Finclude/net/mac80211.h ieee80211_sta_ps_transition +!Finclude/net/mac80211.h ieee80211_sta_ps_transition_ni +!Finclude/net/mac80211.h ieee80211_sta_set_buffered +!Finclude/net/mac80211.h ieee80211_sta_block_awake </chapter> <chapter id="multi-iface">
@@ -477,7 +487,6 @@ MISSING !Finclude/net/mac80211.h sta_notify_cmd !Finclude/net/mac80211.h ieee80211_find_sta !Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr -!Finclude/net/mac80211.h ieee80211_sta_block_awake </chapter> <chapter id="hardware-scan-offload">
include/net/mac80211.h +89 -0
95 lines not on this page · raw message
Johannes Berg
maintainerPATCH v2 16/16 mac80211: dont assign seqno to or aggregate QoS Null frames
In reply to Johannes BergFrom: Johannes Berg <[email protected]>
802.11 says:
"Sequence numbers for QoS (+)Null frames may be set to any value."
However, if we use the normal counters then peers will get confused with aggregation since there'll be holes in the sequence number sequence.
To avoid that, neither assign a sequence number to QoS null frames nor put them on aggregation.
--- net/mac80211/tx.c | 4 ++++ 1 file changed, 4 insertions(+)
net/mac80211/tx.c +4 -0
@@ -804,6 +804,9 @@ ieee80211_tx_h_sequence(struct ieee80211if (ieee80211_hdrlen (hdr->frame_control) <24 )return TX_CONTINUE ; +if (ieee80211_is_qos_nullfunc (hdr->frame_control)) +return TX_CONTINUE ; +/* * Anything but QoS data that has a sequence number field * (is long enough) gets a sequence number from the global
@@ -1236,6 +1239,7 @@ ieee80211_tx_prepare(struct ieee80211_su tx->sta =sta_info_get (sdata, hdr->addr1);if (tx->sta &&ieee80211_is_data_qos (hdr->frame_control) && + !ieee80211_is_qos_nullfunc (hdr->frame_control) && (local->hw.flags &IEEE80211_HW_AMPDU_AGGREGATION ) && !(local->hw.flags &IEEE80211_HW_TX_AMPDU_SETUP_IN_HW )) {struct tid_ampdu_tx *tid_tx;