diff options
author | Bob Copeland <me@bobcopeland.com> | 2009-05-18 10:59:52 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-20 14:46:28 -0400 |
commit | 1071db863b129847cedb65339d1e87ecf5952a8b (patch) | |
tree | f383e088fe7d19bf4f8a59ada10bcd6deb196464 | |
parent | 4de2dc74a1c7dedcfbe8290316f1a239a7c86554 (diff) |
ath5k: update beacons in AP mode
ath5k only generated the beacon when bss_info_changed() was called,
but for AP mode this is not enough, because the TIM IE would never
get updated and consequently PS mode clients wouldn't know about
buffered frames. Instead, get a new beacon on every SWBA interrupt.
Signed-off-by: Bob Copeland <me@bobcopeland.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index dbfe9f45050e..fb5193764afa 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -242,8 +242,8 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, | |||
242 | static u64 ath5k_get_tsf(struct ieee80211_hw *hw); | 242 | static u64 ath5k_get_tsf(struct ieee80211_hw *hw); |
243 | static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); | 243 | static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); |
244 | static void ath5k_reset_tsf(struct ieee80211_hw *hw); | 244 | static void ath5k_reset_tsf(struct ieee80211_hw *hw); |
245 | static int ath5k_beacon_update(struct ath5k_softc *sc, | 245 | static int ath5k_beacon_update(struct ieee80211_hw *hw, |
246 | struct sk_buff *skb); | 246 | struct ieee80211_vif *vif); |
247 | static void ath5k_bss_info_changed(struct ieee80211_hw *hw, | 247 | static void ath5k_bss_info_changed(struct ieee80211_hw *hw, |
248 | struct ieee80211_vif *vif, | 248 | struct ieee80211_vif *vif, |
249 | struct ieee80211_bss_conf *bss_conf, | 249 | struct ieee80211_bss_conf *bss_conf, |
@@ -2127,8 +2127,10 @@ ath5k_beacon_send(struct ath5k_softc *sc) | |||
2127 | /* NB: hw still stops DMA, so proceed */ | 2127 | /* NB: hw still stops DMA, so proceed */ |
2128 | } | 2128 | } |
2129 | 2129 | ||
2130 | /* Note: Beacon buffer is updated on beacon_update when mac80211 | 2130 | /* refresh the beacon for AP mode */ |
2131 | * calls config_interface */ | 2131 | if (sc->opmode == NL80211_IFTYPE_AP) |
2132 | ath5k_beacon_update(sc->hw, sc->vif); | ||
2133 | |||
2132 | ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); | 2134 | ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); |
2133 | ath5k_hw_start_tx_dma(ah, sc->bhalq); | 2135 | ath5k_hw_start_tx_dma(ah, sc->bhalq); |
2134 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", | 2136 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", |
@@ -3047,28 +3049,55 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) | |||
3047 | ath5k_hw_reset_tsf(sc->ah); | 3049 | ath5k_hw_reset_tsf(sc->ah); |
3048 | } | 3050 | } |
3049 | 3051 | ||
3052 | /* | ||
3053 | * Updates the beacon that is sent by ath5k_beacon_send. For adhoc, | ||
3054 | * this is called only once at config_bss time, for AP we do it every | ||
3055 | * SWBA interrupt so that the TIM will reflect buffered frames. | ||
3056 | * | ||
3057 | * Called with the beacon lock. | ||
3058 | */ | ||
3050 | static int | 3059 | static int |
3051 | ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb) | 3060 | ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
3052 | { | 3061 | { |
3053 | unsigned long flags; | ||
3054 | int ret; | 3062 | int ret; |
3063 | struct ath5k_softc *sc = hw->priv; | ||
3064 | struct sk_buff *skb = ieee80211_beacon_get(hw, vif); | ||
3065 | |||
3066 | if (!skb) { | ||
3067 | ret = -ENOMEM; | ||
3068 | goto out; | ||
3069 | } | ||
3055 | 3070 | ||
3056 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); | 3071 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); |
3057 | 3072 | ||
3058 | spin_lock_irqsave(&sc->block, flags); | ||
3059 | ath5k_txbuf_free(sc, sc->bbuf); | 3073 | ath5k_txbuf_free(sc, sc->bbuf); |
3060 | sc->bbuf->skb = skb; | 3074 | sc->bbuf->skb = skb; |
3061 | ret = ath5k_beacon_setup(sc, sc->bbuf); | 3075 | ret = ath5k_beacon_setup(sc, sc->bbuf); |
3062 | if (ret) | 3076 | if (ret) |
3063 | sc->bbuf->skb = NULL; | 3077 | sc->bbuf->skb = NULL; |
3078 | out: | ||
3079 | return ret; | ||
3080 | } | ||
3081 | |||
3082 | /* | ||
3083 | * Update the beacon and reconfigure the beacon queues. | ||
3084 | */ | ||
3085 | static void | ||
3086 | ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | ||
3087 | { | ||
3088 | int ret; | ||
3089 | unsigned long flags; | ||
3090 | struct ath5k_softc *sc = hw->priv; | ||
3091 | |||
3092 | spin_lock_irqsave(&sc->block, flags); | ||
3093 | ret = ath5k_beacon_update(hw, vif); | ||
3064 | spin_unlock_irqrestore(&sc->block, flags); | 3094 | spin_unlock_irqrestore(&sc->block, flags); |
3065 | if (!ret) { | 3095 | if (ret == 0) { |
3066 | ath5k_beacon_config(sc); | 3096 | ath5k_beacon_config(sc); |
3067 | mmiowb(); | 3097 | mmiowb(); |
3068 | } | 3098 | } |
3069 | |||
3070 | return ret; | ||
3071 | } | 3099 | } |
3100 | |||
3072 | static void | 3101 | static void |
3073 | set_beacon_filter(struct ieee80211_hw *hw, bool enable) | 3102 | set_beacon_filter(struct ieee80211_hw *hw, bool enable) |
3074 | { | 3103 | { |
@@ -3118,10 +3147,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, | |||
3118 | (vif->type == NL80211_IFTYPE_ADHOC || | 3147 | (vif->type == NL80211_IFTYPE_ADHOC || |
3119 | vif->type == NL80211_IFTYPE_MESH_POINT || | 3148 | vif->type == NL80211_IFTYPE_MESH_POINT || |
3120 | vif->type == NL80211_IFTYPE_AP)) { | 3149 | vif->type == NL80211_IFTYPE_AP)) { |
3121 | struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); | 3150 | ath5k_beacon_reconfig(hw, vif); |
3122 | |||
3123 | if (beacon) | ||
3124 | ath5k_beacon_update(sc, beacon); | ||
3125 | } | 3151 | } |
3126 | 3152 | ||
3127 | unlock: | 3153 | unlock: |