]> err.no Git - linux-2.6/blobdiff - net/mac80211/tx.c
mac80211: Set IEEE80211_TXPD_REQ_TX_STATUS for all TX frames
[linux-2.6] / net / mac80211 / tx.c
index 33e314f3aab701be22a10926d83db78bddeca7fe..4c25fd5d76a7dbb70b5990eb1a6ecadf7e948174 100644 (file)
 #include <asm/unaligned.h>
 
 #include "ieee80211_i.h"
-#include "ieee80211_led.h"
+#include "led.h"
 #include "mesh.h"
 #include "wep.h"
 #include "wpa.h"
 #include "wme.h"
-#include "ieee80211_rate.h"
+#include "rate.h"
 
 #define IEEE80211_TX_OK                0
 #define IEEE80211_TX_AGAIN     1
@@ -256,7 +256,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
        if (tx->flags & IEEE80211_TX_PS_BUFFERED)
                return TX_CONTINUE;
 
-       sta_flags = tx->sta ? tx->sta->flags : 0;
+       sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
 
        if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
                if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
@@ -327,10 +327,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
                }
                total += skb_queue_len(&ap->ps_bc_buf);
        }
-       rcu_read_unlock();
 
-       read_lock_bh(&local->sta_lock);
-       list_for_each_entry(sta, &local->sta_list, list) {
+       list_for_each_entry_rcu(sta, &local->sta_list, list) {
                skb = skb_dequeue(&sta->ps_tx_buf);
                if (skb) {
                        purged++;
@@ -338,7 +336,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
                }
                total += skb_queue_len(&sta->ps_tx_buf);
        }
-       read_unlock_bh(&local->sta_lock);
+
+       rcu_read_unlock();
 
        local->total_ps_buffered = total;
        printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
@@ -392,6 +391,7 @@ static ieee80211_tx_result
 ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 {
        struct sta_info *sta = tx->sta;
+       u32 staflags;
        DECLARE_MAC_BUF(mac);
 
        if (unlikely(!sta ||
@@ -399,8 +399,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                      (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
                return TX_CONTINUE;
 
-       if (unlikely((sta->flags & WLAN_STA_PS) &&
-                    !(sta->flags & WLAN_STA_PSPOLL))) {
+       staflags = get_sta_flags(sta);
+
+       if (unlikely((staflags & WLAN_STA_PS) &&
+                    !(staflags & WLAN_STA_PSPOLL))) {
                struct ieee80211_tx_packet_data *pkt_data;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
@@ -431,13 +433,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                return TX_QUEUED;
        }
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       else if (unlikely(sta->flags & WLAN_STA_PS)) {
+       else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) {
                printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
                       "set -> send frame\n", tx->dev->name,
                       print_mac(mac, sta->addr));
        }
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-       sta->flags &= ~WLAN_STA_PSPOLL;
+       clear_sta_flags(sta, WLAN_STA_PSPOLL);
 
        return TX_CONTINUE;
 }
@@ -698,7 +700,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
        if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
            (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
            tx->sdata->bss_conf.use_short_preamble &&
-           (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
+           (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
                tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
        }
 
@@ -742,6 +744,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
        }
 
        if (tx->sta) {
+               control->aid = tx->sta->aid;
                tx->sta->tx_packets++;
                tx->sta->tx_fragments++;
                tx->sta->tx_bytes += tx->skb->len;
@@ -1025,10 +1028,8 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
 
        if (!tx->sta)
                control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
-       else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) {
+       else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
                control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
-               tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT;
-       }
 
        hdrlen = ieee80211_get_hdrlen(tx->fc);
        if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
@@ -1141,20 +1142,17 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
                return 0;
        }
 
+       rcu_read_lock();
+
        /* initialises tx */
        res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
 
        if (res_prepare == TX_DROP) {
                dev_kfree_skb(skb);
+               rcu_read_unlock();
                return 0;
        }
 
-       /*
-        * key references are protected using RCU and this requires that
-        * we are in a read-site RCU section during receive processing
-        */
-       rcu_read_lock();
-
        sta = tx.sta;
        tx.channel = local->hw.conf.channel;
 
@@ -1167,9 +1165,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 
        skb = tx.skb; /* handlers are allowed to change skb */
 
-       if (sta)
-               sta_info_put(sta);
-
        if (unlikely(res == TX_DROP)) {
                I802_DEBUG_INC(local->tx_handlers_drop);
                goto drop;
@@ -1342,6 +1337,8 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
        pkt_data->ifindex = dev->ifindex;
 
        pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+       /* Interfaces should always request a status report */
+       pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
 
        /*
         * fix up the pointers accounting for the radiotap
@@ -1489,15 +1486,15 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
         * in AP mode)
         */
        if (!is_multicast_ether_addr(hdr.addr1)) {
+               rcu_read_lock();
                sta = sta_info_get(local, hdr.addr1);
-               if (sta) {
-                       sta_flags = sta->flags;
-                       sta_info_put(sta);
-               }
+               if (sta)
+                       sta_flags = get_sta_flags(sta);
+               rcu_read_unlock();
        }
 
-       /* receiver is QoS enabled, use a QoS type frame */
-       if (sta_flags & WLAN_STA_WME) {
+       /* receiver and we are QoS enabled, use a QoS type frame */
+       if (sta_flags & WLAN_STA_WME && local->hw.queues >= 4) {
                fc |= IEEE80211_STYPE_QOS_DATA;
                hdrlen += 2;
        }
@@ -1623,6 +1620,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        if (ethertype == ETH_P_PAE)
                pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
 
+       /* Interfaces should always request a status report */
+       pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
+
        skb->dev = local->mdev;
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
@@ -1722,7 +1722,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
 
        /* Generate bitmap for TIM only if there are any STAs in power save
         * mode. */
-       read_lock_bh(&local->sta_lock);
        if (atomic_read(&bss->num_sta_ps) > 0)
                /* in the hope that this is faster than
                 * checking byte-for-byte */
@@ -1773,7 +1772,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
                *pos++ = aid0; /* Bitmap control */
                *pos++ = 0; /* Part Virt Bitmap */
        }
-       read_unlock_bh(&local->sta_lock);
 }
 
 struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
@@ -1821,7 +1819,22 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                        ieee80211_include_sequence(sdata,
                                        (struct ieee80211_hdr *)skb->data);
 
-                       ieee80211_beacon_add_tim(local, ap, skb, beacon);
+                       /*
+                        * Not very nice, but we want to allow the driver to call
+                        * ieee80211_beacon_get() as a response to the set_tim()
+                        * callback. That, however, is already invoked under the
+                        * sta_lock to guarantee consistent and race-free update
+                        * of the tim bitmap in mac80211 and the driver.
+                        */
+                       if (local->tim_in_locked_section) {
+                               ieee80211_beacon_add_tim(local, ap, skb, beacon);
+                       } else {
+                               unsigned long flags;
+
+                               spin_lock_irqsave(&local->sta_lock, flags);
+                               ieee80211_beacon_add_tim(local, ap, skb, beacon);
+                               spin_unlock_irqrestore(&local->sta_lock, flags);
+                       }
 
                        if (beacon->tail)
                                memcpy(skb_put(skb, beacon->tail_len),
@@ -1965,7 +1978,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
                rcu_read_unlock();
                return NULL;
        }
-       rcu_read_unlock();
 
        if (bss->dtim_count != 0)
                return NULL; /* send buffered bc/mc only after DTIM beacon */
@@ -2010,8 +2022,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
                skb = NULL;
        }
 
-       if (sta)
-               sta_info_put(sta);
+       rcu_read_unlock();
 
        return skb;
 }