Merge tag 'mac80211-next-for-davem-2015-05-06' of git://git.kernel.org/pub/scm/linux...
authorDavid S. Miller <davem@davemloft.net>
Sat, 9 May 2015 21:27:25 +0000 (17:27 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sat, 9 May 2015 21:27:25 +0000 (17:27 -0400)
Johannes Berg says:

====================
Lots of updates for net-next for this cycle. As usual, we have
a lot of small fixes and cleanups, the bigger items are:
 * proper mac80211 rate control locking, to fix some random crashes
   (this required changing other locking as well)
 * mac80211 "fast-xmit", a mechanism to reduce, in most cases, the
   amount of code we execute while going from ndo_start_xmit() to
   the driver
 * this also clears the way for properly supporting S/G and checksum
   and segmentation offloads
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
76 files changed:
drivers/net/wireless/adm8211.c
drivers/net/wireless/at76c50x-usb.h
drivers/net/wireless/ath/ar5523/ar5523.c
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/led.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/ath/carl9170/led.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/cw1200/sta.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/libertas_tf/main.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/p54/fwio.c
drivers/net/wireless/p54/led.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800soc.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtlwifi/core.h
drivers/net/wireless/ti/wl1251/main.c
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/staging/vt6655/device_main.c
drivers/staging/vt6656/main_usb.c
include/net/cfg80211.h
include/net/mac80211.h
include/uapi/linux/nl80211.h
net/mac80211/Kconfig
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs.c
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.h
net/mac80211/ethtool.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/led.c
net/mac80211/led.h
net/mac80211/main.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/trace.h
net/mac80211/tx.c
net/wireless/chan.c
net/wireless/nl80211.c
net/wireless/reg.c

index f07a618..4135282 100644 (file)
@@ -1353,12 +1353,7 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
 
        new_flags = 0;
 
-       if (*total_flags & FIF_PROMISC_IN_BSS) {
-               new_flags |= FIF_PROMISC_IN_BSS;
-               priv->nar |= ADM8211_NAR_PR;
-               priv->nar &= ~ADM8211_NAR_MM;
-               mc_filter[1] = mc_filter[0] = ~0;
-       } else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
+       if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
                new_flags |= FIF_ALLMULTI;
                priv->nar &= ~ADM8211_NAR_PR;
                priv->nar |= ADM8211_NAR_MM;
index 55090a3..ae03271 100644 (file)
@@ -447,7 +447,7 @@ struct at76_priv {
        int mac80211_registered;
 };
 
-#define AT76_SUPPORTED_FILTERS FIF_PROMISC_IN_BSS
+#define AT76_SUPPORTED_FILTERS 0
 
 #define SCAN_POLL_INTERVAL     (HZ / 4)
 
index 5147ebe..14937cb 100644 (file)
@@ -1319,8 +1319,7 @@ out_unlock:
 
 }
 
-#define AR5523_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
-                                 FIF_ALLMULTI | \
+#define AR5523_SUPPORTED_FILTERS (FIF_ALLMULTI | \
                                  FIF_FCSFAIL | \
                                  FIF_OTHER_BSS)
 
index 973485b..fcd08b2 100644 (file)
@@ -773,7 +773,6 @@ static int ath10k_monitor_recalc(struct ath10k *ar)
        lockdep_assert_held(&ar->conf_mutex);
 
        should_start = ar->monitor ||
-                      ar->filter_flags & FIF_PROMISC_IN_BSS ||
                       test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
 
        ath10k_dbg(ar, ATH10K_DBG_MAC,
@@ -3493,8 +3492,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
  * FIXME: Has to be verified.
  */
 #define SUPPORTED_FILTERS                      \
-       (FIF_PROMISC_IN_BSS |                   \
-       FIF_ALLMULTI |                          \
+       (FIF_ALLMULTI |                         \
        FIF_CONTROL |                           \
        FIF_PSPOLL |                            \
        FIF_OTHER_BSS |                         \
@@ -5500,7 +5498,8 @@ int ath10k_mac_register(struct ath10k *ar)
                        IEEE80211_HW_HAS_RATE_CONTROL |
                        IEEE80211_HW_AP_LINK_PS |
                        IEEE80211_HW_SPECTRUM_MGMT |
-                       IEEE80211_HW_SW_CRYPTO_CONTROL;
+                       IEEE80211_HW_SW_CRYPTO_CONTROL |
+                       IEEE80211_HW_SUPPORT_FAST_XMIT;
 
        ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
 
index 7ca0d6f..e22b0e7 100644 (file)
@@ -1280,7 +1280,6 @@ struct ath5k_hw {
 
        DECLARE_BITMAP(status, 4);
 #define ATH_STAT_INVALID       0               /* disable hardware accesses */
-#define ATH_STAT_PROMISC       1
 #define ATH_STAT_LEDSOFT       2               /* enable LED gpio status */
 #define ATH_STAT_STARTED       3               /* opened & irqs enabled */
 #define ATH_STAT_RESET         4               /* hw reset */
index ca4b7cc..803030f 100644 (file)
@@ -124,7 +124,7 @@ ath5k_led_brightness_set(struct led_classdev *led_dev,
 
 static int
 ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led,
-                  const char *name, char *trigger)
+                  const char *name, const char *trigger)
 {
        int err;
 
index 3b4a646..dc44cfe 100644 (file)
@@ -369,7 +369,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
                       unsigned int *new_flags, u64 multicast)
 {
 #define SUPPORTED_FIF_FLAGS \
-       (FIF_PROMISC_IN_BSS |  FIF_ALLMULTI | FIF_FCSFAIL | \
+       (FIF_ALLMULTI | FIF_FCSFAIL | \
        FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
        FIF_BCN_PRBRESP_PROMISC)
 
@@ -393,16 +393,6 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
                (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
                AR5K_RX_FILTER_MCAST);
 
-       if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
-               if (*new_flags & FIF_PROMISC_IN_BSS)
-                       __set_bit(ATH_STAT_PROMISC, ah->status);
-               else
-                       __clear_bit(ATH_STAT_PROMISC, ah->status);
-       }
-
-       if (test_bit(ATH_STAT_PROMISC, ah->status))
-               rfilt |= AR5K_RX_FILTER_PROM;
-
        /* Note, AR5K_RX_FILTER_MCAST is already enabled */
        if (*new_flags & FIF_ALLMULTI) {
                mfilt[0] =  ~0;
@@ -418,8 +408,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
        if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (ah->nvifs > 1))
                rfilt |= AR5K_RX_FILTER_BEACON;
 
-       /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
-        * set we should only pass on control frames for this
+       /* FIF_CONTROL doc says we should only pass on control frames for this
         * station. This needs testing. I believe right now this
         * enables *all* control frames, which is OK.. but
         * but we should see if we can improve on granularity */
@@ -809,7 +798,6 @@ const struct ieee80211_ops ath5k_hw_ops = {
        .sw_scan_start          = ath5k_sw_scan_start,
        .sw_scan_complete       = ath5k_sw_scan_complete,
        .get_stats              = ath5k_get_stats,
-       /* .get_tkip_seq        = not implemented */
        /* .set_frag_threshold  = not implemented */
        /* .set_rts_threshold   = not implemented */
        /* .sta_add             = not implemented */
index 564923c..b71f307 100644 (file)
@@ -1238,8 +1238,7 @@ out:
 }
 
 #define SUPPORTED_FILTERS                      \
-       (FIF_PROMISC_IN_BSS |                   \
-       FIF_ALLMULTI |                          \
+       (FIF_ALLMULTI |                         \
        FIF_CONTROL |                           \
        FIF_PSPOLL |                            \
        FIF_OTHER_BSS |                         \
index a0f58e2..cc9648f 100644 (file)
@@ -872,14 +872,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
        if (priv->rxfilter & FIF_PROBE_REQ)
                rfilt |= ATH9K_RX_FILTER_PROBEREQ;
 
-       /*
-        * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
-        * mode interface or when in monitor mode. AP mode does not need this
-        * since it receives all in-BSS frames anyway.
-        */
-       if (((ah->opmode != NL80211_IFTYPE_AP) &&
-            (priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
-           ah->is_monitoring)
+       if (ah->is_monitoring)
                rfilt |= ATH9K_RX_FILTER_PROM;
 
        if (priv->rxfilter & FIF_CONTROL)
index b0badef..d285e3a 100644 (file)
@@ -1442,8 +1442,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 }
 
 #define SUPPORTED_FILTERS                      \
-       (FIF_PROMISC_IN_BSS |                   \
-       FIF_ALLMULTI |                          \
+       (FIF_ALLMULTI |                         \
        FIF_CONTROL |                           \
        FIF_PSPOLL |                            \
        FIF_OTHER_BSS |                         \
index 6fb40ef..6c75fb1 100644 (file)
@@ -392,11 +392,6 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
        if (sc->cur_chan->rxfilter & FIF_PROBE_REQ)
                rfilt |= ATH9K_RX_FILTER_PROBEREQ;
 
-       /*
-        * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
-        * mode interface or when in monitor mode. AP mode does not need this
-        * since it receives all in-BSS frames anyway.
-        */
        if (sc->sc_ah->is_monitoring)
                rfilt |= ATH9K_RX_FILTER_PROM;
 
index 47d5c2e..020cd46 100644 (file)
@@ -310,8 +310,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
        if (SUPP(CARL9170FW_RX_FILTER)) {
                ar->fw.rx_filter = true;
                ar->rx_filter_caps = FIF_FCSFAIL | FIF_PLCPFAIL |
-                       FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS |
-                       FIF_PROMISC_IN_BSS;
+                       FIF_CONTROL | FIF_PSPOLL | FIF_OTHER_BSS;
        }
 
        if (SUPP(CARL9170FW_HW_COUNTERS))
index 78dadc7..2c74425 100644 (file)
@@ -122,7 +122,7 @@ static void carl9170_led_set_brightness(struct led_classdev *led,
 }
 
 static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name,
-                                    char *trigger)
+                                    const char *trigger)
 {
        int err;
 
index f1455a0..59db673 100644 (file)
@@ -1011,9 +1011,8 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
        if (multicast != ar->cur_mc_hash)
                WARN_ON(carl9170_update_multicast(ar, multicast));
 
-       if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
-               ar->sniffer_enabled = !!(*new_flags &
-                       (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS));
+       if (changed_flags & FIF_OTHER_BSS) {
+               ar->sniffer_enabled = !!(*new_flags & FIF_OTHER_BSS);
 
                WARN_ON(carl9170_set_operating_mode(ar));
        }
@@ -1033,7 +1032,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
                if (!(*new_flags & FIF_PSPOLL))
                        rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
 
-               if (!(*new_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))) {
+               if (!(*new_flags & FIF_OTHER_BSS)) {
                        rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
                        rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
                }
index b2f9521..f409929 100644 (file)
@@ -3131,8 +3131,6 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
                ctl |= B43_MACCTL_KEEP_BAD;
        if (wl->filter_flags & FIF_PLCPFAIL)
                ctl |= B43_MACCTL_KEEP_BADPLCP;
-       if (wl->filter_flags & FIF_PROMISC_IN_BSS)
-               ctl |= B43_MACCTL_PROMISC;
        if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
                ctl |= B43_MACCTL_BEACPROMISC;
 
@@ -4310,16 +4308,14 @@ static void b43_op_configure_filter(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
-       *fflags &= FIF_PROMISC_IN_BSS |
-                 FIF_ALLMULTI |
+       *fflags &= FIF_ALLMULTI |
                  FIF_FCSFAIL |
                  FIF_PLCPFAIL |
                  FIF_CONTROL |
                  FIF_OTHER_BSS |
                  FIF_BCN_PRBRESP_PROMISC;
 
-       changed &= FIF_PROMISC_IN_BSS |
-                  FIF_ALLMULTI |
+       changed &= FIF_ALLMULTI |
                   FIF_FCSFAIL |
                   FIF_PLCPFAIL |
                   FIF_CONTROL |
index c77b7f5..39d49d6 100644 (file)
@@ -2055,8 +2055,6 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
                ctl |= B43legacy_MACCTL_KEEP_BAD;
        if (wl->filter_flags & FIF_PLCPFAIL)
                ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
-       if (wl->filter_flags & FIF_PROMISC_IN_BSS)
-               ctl |= B43legacy_MACCTL_PROMISC;
        if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
                ctl |= B43legacy_MACCTL_BEACPROMISC;
 
@@ -2922,16 +2920,14 @@ static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
        }
 
        spin_lock_irqsave(&wl->irq_lock, flags);
-       *fflags &= FIF_PROMISC_IN_BSS |
-                 FIF_ALLMULTI |
+       *fflags &= FIF_ALLMULTI |
                  FIF_FCSFAIL |
                  FIF_PLCPFAIL |
                  FIF_CONTROL |
                  FIF_OTHER_BSS |
                  FIF_BCN_PRBRESP_PROMISC;
 
-       changed &= FIF_PROMISC_IN_BSS |
-                  FIF_ALLMULTI |
+       changed &= FIF_ALLMULTI |
                   FIF_FCSFAIL |
                   FIF_PLCPFAIL |
                   FIF_CONTROL |
index 4813506..b46cab2 100644 (file)
@@ -41,8 +41,7 @@
 #define BRCMS_FLUSH_TIMEOUT    500 /* msec */
 
 /* Flags we support */
-#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
-       FIF_ALLMULTI | \
+#define MAC_FILTERS (FIF_ALLMULTI | \
        FIF_FCSFAIL | \
        FIF_CONTROL | \
        FIF_OTHER_BSS | \
@@ -743,8 +742,6 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
        changed_flags &= MAC_FILTERS;
        *total_flags &= MAC_FILTERS;
 
-       if (changed_flags & FIF_PROMISC_IN_BSS)
-               brcms_dbg_info(core, "FIF_PROMISC_IN_BSS\n");
        if (changed_flags & FIF_ALLMULTI)
                brcms_dbg_info(core, "FIF_ALLMULTI\n");
        if (changed_flags & FIF_FCSFAIL)
index 369527e..9728be0 100644 (file)
@@ -3571,7 +3571,7 @@ void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags)
 
        wlc->filter_flags = filter_flags;
 
-       if (filter_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+       if (filter_flags & FIF_OTHER_BSS)
                promisc_bits |= MCTL_PROMISC;
 
        if (filter_flags & FIF_BCN_PRBRESP_PROMISC)
index b0f65fa..b86500b 100644 (file)
@@ -578,13 +578,11 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
 {
        struct cw1200_common *priv = dev->priv;
        bool listening = !!(*total_flags &
-                           (FIF_PROMISC_IN_BSS |
-                            FIF_OTHER_BSS |
+                           (FIF_OTHER_BSS |
                             FIF_BCN_PRBRESP_PROMISC |
                             FIF_PROBE_REQ));
 
-       *total_flags &= FIF_PROMISC_IN_BSS |
-                       FIF_OTHER_BSS |
+       *total_flags &= FIF_OTHER_BSS |
                        FIF_FCSFAIL |
                        FIF_BCN_PRBRESP_PROMISC |
                        FIF_PROBE_REQ;
@@ -592,14 +590,12 @@ void cw1200_configure_filter(struct ieee80211_hw *dev,
        down(&priv->scan.lock);
        mutex_lock(&priv->conf_mutex);
 
-       priv->rx_filter.promiscuous = (*total_flags & FIF_PROMISC_IN_BSS)
-                       ? 1 : 0;
+       priv->rx_filter.promiscuous = 0;
        priv->rx_filter.bssid = (*total_flags & (FIF_OTHER_BSS |
                        FIF_PROBE_REQ)) ? 1 : 0;
        priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0;
        priv->disable_beacon_filter = !(*total_flags &
                                        (FIF_BCN_PRBRESP_PROMISC |
-                                        FIF_PROMISC_IN_BSS |
                                         FIF_PROBE_REQ));
        if (priv->listening != listening) {
                priv->listening = listening;
index e566580..189cdf5 100644 (file)
@@ -3048,7 +3048,7 @@ il3945_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
        D_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", changed_flags,
                   *total_flags);
 
-       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
        CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
        CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
 
@@ -3074,7 +3074,7 @@ il3945_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
         * filters into the device.
         */
        *total_flags &=
-           FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+           FIF_OTHER_BSS | FIF_ALLMULTI |
            FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
index 976f65f..e4b175c 100644 (file)
@@ -6166,7 +6166,7 @@ il4965_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
        D_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", changed_flags,
                   *total_flags);
 
-       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
        /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
        CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
        CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
@@ -6192,7 +6192,7 @@ il4965_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
         * filters into the device.
         */
        *total_flags &=
-           FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+           FIF_OTHER_BSS | FIF_ALLMULTI |
            FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
index 5abd62e..ba7fc42 100644 (file)
@@ -1061,7 +1061,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
        IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
                        changed_flags, *total_flags);
 
-       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_OTHER_BSS, RXON_FILTER_PROMISC_MSK);
        /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
        CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
        CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
@@ -1088,7 +1088,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
         * since we currently do not support programming multicast
         * filters into the device.
         */
-       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI |
                        FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
@@ -1140,7 +1140,6 @@ static void iwlagn_mac_event_callback(struct ieee80211_hw *hw,
                return;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->mutex);
 
        if (priv->lib->bt_params &&
            priv->lib->bt_params->advanced_bt_coexist) {
@@ -1149,13 +1148,12 @@ static void iwlagn_mac_event_callback(struct ieee80211_hw *hw,
                else if (event->u.rssi.data == RSSI_EVENT_HIGH)
                        priv->bt_enable_pspoll = false;
 
-               iwlagn_send_advance_bt_config(priv);
+               queue_work(priv->workqueue, &priv->bt_runtime_config);
        } else {
                IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
                                "ignoring RSSI callback\n");
        }
 
-       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
index 83903a5..0b5a81d 100644 (file)
@@ -248,7 +248,7 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
         */
        if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
            (flags & IEEE80211_CHAN_NO_IR))
-               flags |= IEEE80211_CHAN_GO_CONCURRENT;
+               flags |= IEEE80211_CHAN_IR_CONCURRENT;
 
        return flags;
 }
index ed02e4b..1bdf186 100644 (file)
@@ -439,7 +439,7 @@ static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw,
        return mc_count;
 }
 
-#define SUPPORTED_FIF_FLAGS  (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
+#define SUPPORTED_FIF_FLAGS  FIF_ALLMULTI
 static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
                        unsigned int changed_flags,
                        unsigned int *new_flags,
@@ -458,10 +458,7 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
                return;
        }
 
-       if (*new_flags & (FIF_PROMISC_IN_BSS))
-               priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
-       else
-               priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
+       priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
        if (*new_flags & (FIF_ALLMULTI) ||
            multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
                priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
index d5c0a1a..8d2f6bb 100644 (file)
@@ -1554,8 +1554,6 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
        wiphy_debug(hw->wiphy, "%s\n", __func__);
 
        data->rx_filter = 0;
-       if (*total_flags & FIF_PROMISC_IN_BSS)
-               data->rx_filter |= FIF_PROMISC_IN_BSS;
        if (*total_flags & FIF_ALLMULTI)
                data->rx_filter |= FIF_ALLMULTI;
 
@@ -2399,7 +2397,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
                    IEEE80211_HW_WANT_MONITOR_VIF |
                    IEEE80211_HW_QUEUE_CONTROL |
                    IEEE80211_HW_SUPPORTS_HT_CCK_RATES |
-                   IEEE80211_HW_CHANCTX_STA_CSA;
+                   IEEE80211_HW_CHANCTX_STA_CSA |
+                   IEEE80211_HW_SUPPORT_FAST_XMIT;
        if (rctbl)
                hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
 
@@ -2438,6 +2437,31 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
                        sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz);
                        sband->bitrates = data->rates + 4;
                        sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
+
+                       sband->vht_cap.vht_supported = true;
+                       sband->vht_cap.cap =
+                               IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+                               IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
+                               IEEE80211_VHT_CAP_RXLDPC |
+                               IEEE80211_VHT_CAP_SHORT_GI_80 |
+                               IEEE80211_VHT_CAP_SHORT_GI_160 |
+                               IEEE80211_VHT_CAP_TXSTBC |
+                               IEEE80211_VHT_CAP_RXSTBC_1 |
+                               IEEE80211_VHT_CAP_RXSTBC_2 |
+                               IEEE80211_VHT_CAP_RXSTBC_3 |
+                               IEEE80211_VHT_CAP_RXSTBC_4 |
+                               IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+                       sband->vht_cap.vht_mcs.rx_mcs_map =
+                               cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 14);
+                       sband->vht_cap.vht_mcs.tx_mcs_map =
+                               sband->vht_cap.vht_mcs.rx_mcs_map;
                        break;
                default:
                        continue;
@@ -2458,31 +2482,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
                sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 
                hw->wiphy->bands[band] = sband;
-
-               sband->vht_cap.vht_supported = true;
-               sband->vht_cap.cap =
-                       IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
-                       IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
-                       IEEE80211_VHT_CAP_RXLDPC |
-                       IEEE80211_VHT_CAP_SHORT_GI_80 |
-                       IEEE80211_VHT_CAP_SHORT_GI_160 |
-                       IEEE80211_VHT_CAP_TXSTBC |
-                       IEEE80211_VHT_CAP_RXSTBC_1 |
-                       IEEE80211_VHT_CAP_RXSTBC_2 |
-                       IEEE80211_VHT_CAP_RXSTBC_3 |
-                       IEEE80211_VHT_CAP_RXSTBC_4 |
-                       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
-               sband->vht_cap.vht_mcs.rx_mcs_map =
-                       cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 |
-                                   IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 |
-                                   IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
-                                   IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 |
-                                   IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 |
-                                   IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
-                                   IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
-                                   IEEE80211_VHT_MCS_SUPPORT_0_8 << 14);
-               sband->vht_cap.vht_mcs.tx_mcs_map =
-                       sband->vht_cap.vht_mcs.rx_mcs_map;
        }
 
        /* By default all radios belong to the first group */
index 9592116..b71fc74 100644 (file)
@@ -5192,7 +5192,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
                priv->sniffer_enabled = true;
        }
 
-       *total_flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI |
+       *total_flags &= FIF_ALLMULTI |
                        FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL |
                        FIF_OTHER_BSS;
 
index 275408e..257a9ea 100644 (file)
@@ -351,8 +351,7 @@ int p54_setup_mac(struct p54_common *priv)
                 * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
                 * STSW45X0C LMAC API - page 12
                 */
-               if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
-                    (priv->filter_flags & FIF_OTHER_BSS)) &&
+               if (priv->filter_flags & FIF_OTHER_BSS &&
                    (mode != P54_FILTER_TYPE_PROMISCUOUS))
                        mode |= P54_FILTER_TYPE_TRANSPARENT;
        } else {
index 1f6fd5f..9a8fedd 100644 (file)
@@ -83,7 +83,7 @@ static void p54_led_brightness_set(struct led_classdev *led_dev,
 
 static int p54_register_led(struct p54_common *priv,
                            unsigned int led_index,
-                           char *name, char *trigger)
+                           char *name, const char *trigger)
 {
        struct p54_led_dev *led = &priv->leds[led_index];
        int err;
index e79674f..2947ad2 100644 (file)
@@ -395,13 +395,11 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
 {
        struct p54_common *priv = dev->priv;
 
-       *total_flags &= FIF_PROMISC_IN_BSS |
-                       FIF_ALLMULTI |
-                       FIF_OTHER_BSS;
+       *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS;
 
        priv->filter_flags = *total_flags;
 
-       if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+       if (changed_flags & FIF_OTHER_BSS)
                p54_setup_mac(priv);
 
        if (changed_flags & FIF_ALLMULTI || multicast)
index bdf5590..7da1388 100644 (file)
@@ -273,10 +273,8 @@ static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev,
                           !(filter_flags & FIF_PLCPFAIL));
        rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
                           !(filter_flags & FIF_CONTROL));
-       rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
-                          !(filter_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME, 1);
        rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
-                          !(filter_flags & FIF_PROMISC_IN_BSS) &&
                           !rt2x00dev->intf_ap_count);
        rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
        rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
index 79f4fe6..4ea53aa 100644 (file)
@@ -274,10 +274,8 @@ static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev,
                           !(filter_flags & FIF_PLCPFAIL));
        rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
                           !(filter_flags & FIF_CONTROL));
-       rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
-                          !(filter_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME, 1);
        rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
-                          !(filter_flags & FIF_PROMISC_IN_BSS) &&
                           !rt2x00dev->intf_ap_count);
        rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
        rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST,
index 05c6459..237bbb5 100644 (file)
@@ -434,10 +434,8 @@ static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev,
                           !(filter_flags & FIF_PLCPFAIL));
        rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL,
                           !(filter_flags & FIF_CONTROL));
-       rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME,
-                          !(filter_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME, 1);
        rt2x00_set_field16(&reg, TXRX_CSR2_DROP_TODS,
-                          !(filter_flags & FIF_PROMISC_IN_BSS) &&
                           !rt2x00dev->intf_ap_count);
        rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 1);
        rt2x00_set_field16(&reg, TXRX_CSR2_DROP_MULTICAST,
index be2d54f..dfeca83 100644 (file)
@@ -1513,8 +1513,7 @@ void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
                           !(filter_flags & FIF_FCSFAIL));
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PHY_ERROR,
                           !(filter_flags & FIF_PLCPFAIL));
-       rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME,
-                          !(filter_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME, 1);
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_VER_ERROR, 1);
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_MULTICAST,
@@ -7818,21 +7817,25 @@ EXPORT_SYMBOL_GPL(rt2800_probe_hw);
 /*
  * IEEE80211 stack callback functions.
  */
-void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
-                        u16 *iv16)
+void rt2800_get_key_seq(struct ieee80211_hw *hw,
+                       struct ieee80211_key_conf *key,
+                       struct ieee80211_key_seq *seq)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct mac_iveiv_entry iveiv_entry;
        u32 offset;
 
-       offset = MAC_IVEIV_ENTRY(hw_key_idx);
+       if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
+               return;
+
+       offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
        rt2800_register_multiread(rt2x00dev, offset,
                                      &iveiv_entry, sizeof(iveiv_entry));
 
-       memcpy(iv16, &iveiv_entry.iv[0], sizeof(*iv16));
-       memcpy(iv32, &iveiv_entry.iv[4], sizeof(*iv32));
+       memcpy(&seq->tkip.iv16, &iveiv_entry.iv[0], 2);
+       memcpy(&seq->tkip.iv32, &iveiv_entry.iv[4], 4);
 }
-EXPORT_SYMBOL_GPL(rt2800_get_tkip_seq);
+EXPORT_SYMBOL_GPL(rt2800_get_key_seq);
 
 int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 {
index 3019db6..1609b8a 100644 (file)
@@ -209,8 +209,9 @@ int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
 
 int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
 
-void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
-                        u16 *iv16);
+void rt2800_get_key_seq(struct ieee80211_hw *hw,
+                       struct ieee80211_key_conf *key,
+                       struct ieee80211_key_seq *seq);
 int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
 int rt2800_conf_tx(struct ieee80211_hw *hw,
                   struct ieee80211_vif *vif, u16 queue_idx,
index cc1b3cc..0af2257 100644 (file)
@@ -309,7 +309,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
        .sw_scan_start          = rt2x00mac_sw_scan_start,
        .sw_scan_complete       = rt2x00mac_sw_scan_complete,
        .get_stats              = rt2x00mac_get_stats,
-       .get_tkip_seq           = rt2800_get_tkip_seq,
+       .get_key_seq            = rt2800_get_key_seq,
        .set_rts_threshold      = rt2800_set_rts_threshold,
        .sta_add                = rt2x00mac_sta_add,
        .sta_remove             = rt2x00mac_sta_remove,
index aaa7aa4..a985a5a 100644 (file)
@@ -148,7 +148,7 @@ static const struct ieee80211_ops rt2800soc_mac80211_ops = {
        .sw_scan_start          = rt2x00mac_sw_scan_start,
        .sw_scan_complete       = rt2x00mac_sw_scan_complete,
        .get_stats              = rt2x00mac_get_stats,
-       .get_tkip_seq           = rt2800_get_tkip_seq,
+       .get_key_seq            = rt2800_get_key_seq,
        .set_rts_threshold      = rt2800_set_rts_threshold,
        .sta_add                = rt2x00mac_sta_add,
        .sta_remove             = rt2x00mac_sta_remove,
index 6ec2466..5932306 100644 (file)
@@ -835,7 +835,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
        .sw_scan_start          = rt2x00mac_sw_scan_start,
        .sw_scan_complete       = rt2x00mac_sw_scan_complete,
        .get_stats              = rt2x00mac_get_stats,
-       .get_tkip_seq           = rt2800_get_tkip_seq,
+       .get_key_seq            = rt2800_get_key_seq,
        .set_rts_threshold      = rt2800_set_rts_threshold,
        .sta_add                = rt2x00mac_sta_add,
        .sta_remove             = rt2x00mac_sta_remove,
index 300876d..1b8a459 100644 (file)
@@ -359,8 +359,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
            FIF_PLCPFAIL |
            FIF_CONTROL |
            FIF_PSPOLL |
-           FIF_OTHER_BSS |
-           FIF_PROMISC_IN_BSS;
+           FIF_OTHER_BSS;
 
        /*
         * Apply some rules to the filters:
@@ -369,9 +368,6 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
         * - Multicast filter seems to kill broadcast traffic so never use it.
         */
        *total_flags |= FIF_ALLMULTI;
-       if (*total_flags & FIF_OTHER_BSS ||
-           *total_flags & FIF_PROMISC_IN_BSS)
-               *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
 
        /*
         * If the device has a single filter for all control frames,
index 8194550..c8a9672 100644 (file)
@@ -530,10 +530,8 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
                           !(filter_flags & FIF_PLCPFAIL));
        rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
                           !(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
-       rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
-                          !(filter_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, 1);
        rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
-                          !(filter_flags & FIF_PROMISC_IN_BSS) &&
                           !rt2x00dev->intf_ap_count);
        rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
        rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
index a5458cf..65ce3af 100644 (file)
@@ -480,10 +480,8 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
                           !(filter_flags & FIF_PLCPFAIL));
        rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
                           !(filter_flags & (FIF_CONTROL | FIF_PSPOLL)));
-       rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
-                          !(filter_flags & FIF_PROMISC_IN_BSS));
+       rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME, 1);
        rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
-                          !(filter_flags & FIF_PROMISC_IN_BSS) &&
                           !rt2x00dev->intf_ap_count);
        rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
        rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
index 82733c6..782ac2f 100644 (file)
@@ -27,8 +27,7 @@
 #define __RTL_CORE_H__
 
 #define RTL_SUPPORTED_FILTERS          \
-       (FIF_PROMISC_IN_BSS | \
-       FIF_ALLMULTI | FIF_CONTROL | \
+       (FIF_ALLMULTI | FIF_CONTROL | \
        FIF_OTHER_BSS | \
        FIF_FCSFAIL | \
        FIF_BCN_PRBRESP_PROMISC)
index 5d54d16..f238ee5 100644 (file)
@@ -763,8 +763,7 @@ static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw,
        return (u64)(unsigned long)fp;
 }
 
-#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
-                                 FIF_ALLMULTI | \
+#define WL1251_SUPPORTED_FILTERS (FIF_ALLMULTI | \
                                  FIF_FCSFAIL | \
                                  FIF_BCN_PRBRESP_PROMISC | \
                                  FIF_CONTROL | \
@@ -795,10 +794,6 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
        wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
        wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
 
-       if (*total & FIF_PROMISC_IN_BSS) {
-               wl->rx_config |= CFG_BSSID_FILTER_EN;
-               wl->rx_config |= CFG_RX_ALL_GOOD;
-       }
        if (*total & FIF_ALLMULTI)
                /*
                 * CFG_MC_FILTER_EN in rx_config needs to be 0 to receive
@@ -825,7 +820,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS)
+       if (*total & FIF_ALLMULTI)
                ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0);
        else if (fp)
                ret = wl1251_acx_group_address_tbl(wl, fp->enabled,
index 0be8079..7fe50f8 100644 (file)
@@ -3175,8 +3175,7 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
        return (u64)(unsigned long)fp;
 }
 
-#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
-                                 FIF_ALLMULTI | \
+#define WL1271_SUPPORTED_FILTERS (FIF_ALLMULTI | \
                                  FIF_FCSFAIL | \
                                  FIF_BCN_PRBRESP_PROMISC | \
                                  FIF_CONTROL | \
@@ -6077,7 +6076,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
                IEEE80211_HW_AMPDU_AGGREGATION |
                IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
                IEEE80211_HW_QUEUE_CONTROL |
-               IEEE80211_HW_CHANCTX_STA_CSA;
+               IEEE80211_HW_CHANCTX_STA_CSA |
+               IEEE80211_HW_SUPPORT_FAST_XMIT;
 
        wl->hw->wiphy->cipher_suites = cipher_suites;
        wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
index e7af261..89b6f69 100644 (file)
@@ -1230,7 +1230,7 @@ static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw,
 }
 
 #define SUPPORTED_FIF_FLAGS \
-       (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
+       (FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
        FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
 static void zd_op_configure_filter(struct ieee80211_hw *hw,
                        unsigned int changed_flags,
@@ -1256,7 +1256,7 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
         * we will have some issue with IPv6 which uses multicast for link
         * layer address resolution.
         */
-       if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI))
+       if (*new_flags & FIF_ALLMULTI)
                zd_mc_add_all(&hash);
 
        spin_lock_irqsave(&mac->lock, flags);
index 4bb4f8e..6b2f813 100644 (file)
@@ -1516,21 +1516,12 @@ static void vnt_configure(struct ieee80211_hw *hw,
        struct vnt_private *priv = hw->priv;
        u8 rx_mode = 0;
 
-       *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS |
-               FIF_BCN_PRBRESP_PROMISC;
+       *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC;
 
        VNSvInPortB(priv->PortOffset + MAC_REG_RCR, &rx_mode);
 
        dev_dbg(&priv->pcid->dev, "rx mode in = %x\n", rx_mode);
 
-       if (changed_flags & FIF_PROMISC_IN_BSS) {
-               /* unconditionally log net taps */
-               if (*total_flags & FIF_PROMISC_IN_BSS)
-                       rx_mode |= RCR_UNICAST;
-               else
-                       rx_mode &= ~RCR_UNICAST;
-       }
-
        if (changed_flags & FIF_ALLMULTI) {
                if (*total_flags & FIF_ALLMULTI) {
                        unsigned long flags;
index ab3ab84..0d97b64 100644 (file)
@@ -785,8 +785,7 @@ static void vnt_configure(struct ieee80211_hw *hw,
        u8 rx_mode = 0;
        int rc;
 
-       *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS |
-               FIF_BCN_PRBRESP_PROMISC;
+       *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC;
 
        rc = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_RCR,
                MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode);
@@ -796,14 +795,6 @@ static void vnt_configure(struct ieee80211_hw *hw,
 
        dev_dbg(&priv->usb->dev, "rx mode in = %x\n", rx_mode);
 
-       if (changed_flags & FIF_PROMISC_IN_BSS) {
-               /* unconditionally log net taps */
-               if (*total_flags & FIF_PROMISC_IN_BSS)
-                       rx_mode |= RCR_UNICAST;
-               else
-                       rx_mode &= ~RCR_UNICAST;
-       }
-
        if (changed_flags & FIF_ALLMULTI) {
                if (*total_flags & FIF_ALLMULTI) {
                        if (priv->mc_list_count > 2)
index f8d6813..d63ecec 100644 (file)
@@ -111,7 +111,7 @@ enum ieee80211_band {
  *     This may be due to the driver or due to regulatory bandwidth
  *     restrictions.
  * @IEEE80211_CHAN_INDOOR_ONLY: see %NL80211_FREQUENCY_ATTR_INDOOR_ONLY
- * @IEEE80211_CHAN_GO_CONCURRENT: see %NL80211_FREQUENCY_ATTR_GO_CONCURRENT
+ * @IEEE80211_CHAN_IR_CONCURRENT: see %NL80211_FREQUENCY_ATTR_IR_CONCURRENT
  * @IEEE80211_CHAN_NO_20MHZ: 20 MHz bandwidth is not permitted
  *     on this channel.
  * @IEEE80211_CHAN_NO_10MHZ: 10 MHz bandwidth is not permitted
@@ -129,7 +129,7 @@ enum ieee80211_channel_flags {
        IEEE80211_CHAN_NO_80MHZ         = 1<<7,
        IEEE80211_CHAN_NO_160MHZ        = 1<<8,
        IEEE80211_CHAN_INDOOR_ONLY      = 1<<9,
-       IEEE80211_CHAN_GO_CONCURRENT    = 1<<10,
+       IEEE80211_CHAN_IR_CONCURRENT    = 1<<10,
        IEEE80211_CHAN_NO_20MHZ         = 1<<11,
        IEEE80211_CHAN_NO_10MHZ         = 1<<12,
 };
index b4bef11..67e0df1 100644 (file)
@@ -337,10 +337,16 @@ enum ieee80211_bss_change {
  * enum ieee80211_event_type - event to be notified to the low level driver
  * @RSSI_EVENT: AP's rssi crossed the a threshold set by the driver.
  * @MLME_EVENT: event related to MLME
+ * @BAR_RX_EVENT: a BAR was received
+ * @BA_FRAME_TIMEOUT: Frames were released from the reordering buffer because
+ *     they timed out. This won't be called for each frame released, but only
+ *     once each time the timeout triggers.
  */
 enum ieee80211_event_type {
        RSSI_EVENT,
        MLME_EVENT,
+       BAR_RX_EVENT,
+       BA_FRAME_TIMEOUT,
 };
 
 /**
@@ -354,7 +360,7 @@ enum ieee80211_rssi_event_data {
 };
 
 /**
- * enum ieee80211_rssi_event - data attached to an %RSSI_EVENT
+ * struct ieee80211_rssi_event - data attached to an %RSSI_EVENT
  * @data: See &enum ieee80211_rssi_event_data
  */
 struct ieee80211_rssi_event {
@@ -388,7 +394,7 @@ enum ieee80211_mlme_event_status {
 };
 
 /**
- * enum ieee80211_mlme_event - data attached to an %MLME_EVENT
+ * struct ieee80211_mlme_event - data attached to an %MLME_EVENT
  * @data: See &enum ieee80211_mlme_event_data
  * @status: See &enum ieee80211_mlme_event_status
  * @reason: the reason code if applicable
@@ -400,16 +406,31 @@ struct ieee80211_mlme_event {
 };
 
 /**
+ * struct ieee80211_ba_event - data attached for BlockAck related events
+ * @sta: pointer to the &ieee80211_sta to which this event relates
+ * @tid: the tid
+ * @ssn: the starting sequence number (for %BAR_RX_EVENT)
+ */
+struct ieee80211_ba_event {
+       struct ieee80211_sta *sta;
+       u16 tid;
+       u16 ssn;
+};
+
+/**
  * struct ieee80211_event - event to be sent to the driver
- * @type The event itself. See &enum ieee80211_event_type.
+ * @type: The event itself. See &enum ieee80211_event_type.
  * @rssi: relevant if &type is %RSSI_EVENT
  * @mlme: relevant if &type is %AUTH_EVENT
+ * @ba: relevant if &type is %BAR_RX_EVENT or %BA_FRAME_TIMEOUT
+ * @u:union holding the fields above
  */
 struct ieee80211_event {
        enum ieee80211_event_type type;
        union {
                struct ieee80211_rssi_event rssi;
                struct ieee80211_mlme_event mlme;
+               struct ieee80211_ba_event ba;
        } u;
 };
 
@@ -1480,6 +1501,47 @@ struct ieee80211_key_conf {
        u8 key[0];
 };
 
+#define IEEE80211_MAX_PN_LEN   16
+
+/**
+ * struct ieee80211_key_seq - key sequence counter
+ *
+ * @tkip: TKIP data, containing IV32 and IV16 in host byte order
+ * @ccmp: PN data, most significant byte first (big endian,
+ *     reverse order than in packet)
+ * @aes_cmac: PN data, most significant byte first (big endian,
+ *     reverse order than in packet)
+ * @aes_gmac: PN data, most significant byte first (big endian,
+ *     reverse order than in packet)
+ * @gcmp: PN data, most significant byte first (big endian,
+ *     reverse order than in packet)
+ * @hw: data for HW-only (e.g. cipher scheme) keys
+ */
+struct ieee80211_key_seq {
+       union {
+               struct {
+                       u32 iv32;
+                       u16 iv16;
+               } tkip;
+               struct {
+                       u8 pn[6];
+               } ccmp;
+               struct {
+                       u8 pn[6];
+               } aes_cmac;
+               struct {
+                       u8 pn[6];
+               } aes_gmac;
+               struct {
+                       u8 pn[6];
+               } gcmp;
+               struct {
+                       u8 seq[IEEE80211_MAX_PN_LEN];
+                       u8 seq_len;
+               } hw;
+       };
+};
+
 /**
  * struct ieee80211_cipher_scheme - cipher scheme
  *
@@ -1795,6 +1857,10 @@ struct ieee80211_txq {
  *     the driver returns 1. This also forces the driver to advertise its
  *     supported cipher suites.
  *
+ * @IEEE80211_HW_SUPPORT_FAST_XMIT: The driver/hardware supports fast-xmit,
+ *     this currently requires only the ability to calculate the duration
+ *     for frames.
+ *
  * @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface
  *     queue mapping in order to use different queues (not just one per AC)
  *     for different virtual interfaces. See the doc section on HW queue
@@ -1843,7 +1909,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_WANT_MONITOR_VIF                   = 1<<14,
        IEEE80211_HW_NO_AUTO_VIF                        = 1<<15,
        IEEE80211_HW_SW_CRYPTO_CONTROL                  = 1<<16,
-       /* free slots */
+       IEEE80211_HW_SUPPORT_FAST_XMIT                  = 1<<17,
        IEEE80211_HW_REPORTS_TX_ACK_STATUS              = 1<<18,
        IEEE80211_HW_CONNECTION_MONITOR                 = 1<<19,
        IEEE80211_HW_QUEUE_CONTROL                      = 1<<20,
@@ -1937,8 +2003,8 @@ enum ieee80211_hw_flags {
  *     Use the %IEEE80211_RADIOTAP_VHT_KNOWN_* values.
  *
  * @netdev_features: netdev features to be set in each netdev created
- *     from this HW. Note only HW checksum features are currently
- *     compatible with mac80211. Other feature bits will be rejected.
+ *     from this HW. Note that not all features are usable with mac80211,
+ *     other features will be rejected during HW registration.
  *
  * @uapsd_queues: This bitmap is included in (re)association frame to indicate
  *     for each access category if it is uAPSD trigger-enabled and delivery-
@@ -2502,10 +2568,6 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * stack. It is always safe to pass more frames than requested,
  * but this has negative impact on power consumption.
  *
- * @FIF_PROMISC_IN_BSS: promiscuous mode within your BSS,
- *     think of the BSS as your network segment and then this corresponds
- *     to the regular ethernet device promiscuous mode.
- *
  * @FIF_ALLMULTI: pass all multicast frames, this is used if requested
  *     by the user or if the hardware is not capable of filtering by
  *     multicast address.
@@ -2522,8 +2584,8 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  *     mac80211 needs to do and the amount of CPU wakeups, so you should
  *     honour this flag if possible.
  *
- * @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS
- *     is not set then only those addressed to this station.
+ * @FIF_CONTROL: pass control frames (except for PS Poll) addressed to this
+ *     station
  *
  * @FIF_OTHER_BSS: pass frames destined to other BSSes
  *
@@ -2533,7 +2595,6 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * @FIF_PROBE_REQ: pass probe request frames
  */
 enum ieee80211_filter_flags {
-       FIF_PROMISC_IN_BSS      = 1<<0,
        FIF_ALLMULTI            = 1<<1,
        FIF_FCSFAIL             = 1<<2,
        FIF_PLCPFAIL            = 1<<3,
@@ -2816,9 +2877,9 @@ enum ieee80211_reconfig_type {
  *     Returns zero if statistics are available.
  *     The callback can sleep.
  *
- * @get_tkip_seq: If your device implements TKIP encryption in hardware this
- *     callback should be provided to read the TKIP transmit IVs (both IV32
- *     and IV16) for the given key from hardware.
+ * @get_key_seq: If your device implements encryption in hardware and does
+ *     IV/PN assignment then this callback should be provided to read the
+ *     IV/PN for the given key from hardware.
  *     The callback must be atomic.
  *
  * @set_frag_threshold: Configuration of fragmentation threshold. Assign this
@@ -3001,7 +3062,7 @@ enum ieee80211_reconfig_type {
  *     The callback can sleep.
  * @event_callback: Notify driver about any event in mac80211. See
  *     &enum ieee80211_event_type for the different types.
- *     The callback can sleep.
+ *     The callback must be atomic.
  *
  * @release_buffered_frames: Release buffered frames according to the given
  *     parameters. In the case where the driver buffers some frames for
@@ -3217,8 +3278,9 @@ struct ieee80211_ops {
                                 struct ieee80211_vif *vif);
        int (*get_stats)(struct ieee80211_hw *hw,
                         struct ieee80211_low_level_stats *stats);
-       void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
-                            u32 *iv32, u16 *iv16);
+       void (*get_key_seq)(struct ieee80211_hw *hw,
+                           struct ieee80211_key_conf *key,
+                           struct ieee80211_key_seq *seq);
        int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
        int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
        int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -3466,14 +3528,15 @@ enum ieee80211_tpt_led_trigger_flags {
 };
 
 #ifdef CONFIG_MAC80211_LEDS
-char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
-char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
-char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
-char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
-char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
-                                        unsigned int flags,
-                                        const struct ieee80211_tpt_blink *blink_table,
-                                        unsigned int blink_table_len);
+const char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
+const char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
+const char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
+const char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
+const char *
+__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
+                                  unsigned int flags,
+                                  const struct ieee80211_tpt_blink *blink_table,
+                                  unsigned int blink_table_len);
 #endif
 /**
  * ieee80211_get_tx_led_name - get name of TX LED
@@ -3487,7 +3550,7 @@ char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
  *
  * Return: The name of the LED trigger. %NULL if not configured for LEDs.
  */
-static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
+static inline const char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
 {
 #ifdef CONFIG_MAC80211_LEDS
        return __ieee80211_get_tx_led_name(hw);
@@ -3508,7 +3571,7 @@ static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
  *
  * Return: The name of the LED trigger. %NULL if not configured for LEDs.
  */
-static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
+static inline const char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
 {
 #ifdef CONFIG_MAC80211_LEDS
        return __ieee80211_get_rx_led_name(hw);
@@ -3529,7 +3592,7 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
  *
  * Return: The name of the LED trigger. %NULL if not configured for LEDs.
  */
-static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
+static inline const char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
 {
 #ifdef CONFIG_MAC80211_LEDS
        return __ieee80211_get_assoc_led_name(hw);
@@ -3550,7 +3613,7 @@ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
  *
  * Return: The name of the LED trigger. %NULL if not configured for LEDs.
  */
-static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
+static inline const char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
 {
 #ifdef CONFIG_MAC80211_LEDS
        return __ieee80211_get_radio_led_name(hw);
@@ -3571,7 +3634,7 @@ static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
  *
  * Note: This function must be called before ieee80211_register_hw().
  */
-static inline char *
+static inline const char *
 ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, unsigned int flags,
                                 const struct ieee80211_tpt_blink *blink_table,
                                 unsigned int blink_table_len)
@@ -4252,40 +4315,6 @@ void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf,
                                        u8 *k1, u8 *k2);
 
 /**
- * struct ieee80211_key_seq - key sequence counter
- *
- * @tkip: TKIP data, containing IV32 and IV16 in host byte order
- * @ccmp: PN data, most significant byte first (big endian,
- *     reverse order than in packet)
- * @aes_cmac: PN data, most significant byte first (big endian,
- *     reverse order than in packet)
- * @aes_gmac: PN data, most significant byte first (big endian,
- *     reverse order than in packet)
- * @gcmp: PN data, most significant byte first (big endian,
- *     reverse order than in packet)
- */
-struct ieee80211_key_seq {
-       union {
-               struct {
-                       u32 iv32;
-                       u16 iv16;
-               } tkip;
-               struct {
-                       u8 pn[6];
-               } ccmp;
-               struct {
-                       u8 pn[6];
-               } aes_cmac;
-               struct {
-                       u8 pn[6];
-               } aes_gmac;
-               struct {
-                       u8 pn[6];
-               } gcmp;
-       };
-};
-
-/**
  * ieee80211_get_key_tx_seq - get key TX sequence counter
  *
  * @keyconf: the parameter passed with the set key
index 241220c..c0ab6b0 100644 (file)
@@ -2620,16 +2620,17 @@ enum nl80211_band_attr {
  *     an indoor surroundings, i.e., it is connected to AC power (and not
  *     through portable DC inverters) or is under the control of a master
  *     that is acting as an AP and is connected to AC power.
- * @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this
+ * @NL80211_FREQUENCY_ATTR_IR_CONCURRENT: IR operation is allowed on this
  *     channel if it's connected concurrently to a BSS on the same channel on
  *     the 2 GHz band or to a channel in the same UNII band (on the 5 GHz
- *     band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO on a
- *     channel that has the GO_CONCURRENT attribute set can be done when there
- *     is a clear assessment that the device is operating under the guidance of
- *     an authorized master, i.e., setting up a GO while the device is also
- *     connected to an AP with DFS and radar detection on the UNII band (it is
- *     up to user-space, i.e., wpa_supplicant to perform the required
- *     verifications)
+ *     band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO or TDLS
+ *     off-channel on a channel that has the IR_CONCURRENT attribute set can be
+ *     done when there is a clear assessment that the device is operating under
+ *     the guidance of an authorized master, i.e., setting up a GO or TDLS
+ *     off-channel while the device is also connected to an AP with DFS and
+ *     radar detection on the UNII band (it is up to user-space, i.e.,
+ *     wpa_supplicant to perform the required verifications). Using this
+ *     attribute for IR is disallowed for master interfaces (IBSS, AP).
  * @NL80211_FREQUENCY_ATTR_NO_20MHZ: 20 MHz operation is not allowed
  *     on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
@@ -2641,7 +2642,7 @@ enum nl80211_band_attr {
  * See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122
  * for more information on the FCC description of the relaxations allowed
  * by NL80211_FREQUENCY_ATTR_INDOOR_ONLY and
- * NL80211_FREQUENCY_ATTR_GO_CONCURRENT.
+ * NL80211_FREQUENCY_ATTR_IR_CONCURRENT.
  */
 enum nl80211_frequency_attr {
        __NL80211_FREQUENCY_ATTR_INVALID,
@@ -2659,7 +2660,7 @@ enum nl80211_frequency_attr {
        NL80211_FREQUENCY_ATTR_NO_160MHZ,
        NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
        NL80211_FREQUENCY_ATTR_INDOOR_ONLY,
-       NL80211_FREQUENCY_ATTR_GO_CONCURRENT,
+       NL80211_FREQUENCY_ATTR_IR_CONCURRENT,
        NL80211_FREQUENCY_ATTR_NO_20MHZ,
        NL80211_FREQUENCY_ATTR_NO_10MHZ,
 
@@ -2672,6 +2673,8 @@ enum nl80211_frequency_attr {
 #define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN    NL80211_FREQUENCY_ATTR_NO_IR
 #define NL80211_FREQUENCY_ATTR_NO_IBSS         NL80211_FREQUENCY_ATTR_NO_IR
 #define NL80211_FREQUENCY_ATTR_NO_IR           NL80211_FREQUENCY_ATTR_NO_IR
+#define NL80211_FREQUENCY_ATTR_GO_CONCURRENT \
+                                       NL80211_FREQUENCY_ATTR_IR_CONCURRENT
 
 /**
  * enum nl80211_bitrate_attr - bitrate attributes
@@ -2830,7 +2833,7 @@ enum nl80211_sched_scan_match_attr {
  * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
  *     base on contiguous rules and wider channels will be allowed to cross
  *     multiple contiguous/overlapping frequency ranges.
- * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT
+ * @NL80211_RRF_IR_CONCURRENT: See &NL80211_FREQUENCY_ATTR_IR_CONCURRENT
  * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
  * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
  * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
@@ -2847,7 +2850,7 @@ enum nl80211_reg_rule_flags {
        NL80211_RRF_NO_IR               = 1<<7,
        __NL80211_RRF_NO_IBSS           = 1<<8,
        NL80211_RRF_AUTO_BW             = 1<<11,
-       NL80211_RRF_GO_CONCURRENT       = 1<<12,
+       NL80211_RRF_IR_CONCURRENT       = 1<<12,
        NL80211_RRF_NO_HT40MINUS        = 1<<13,
        NL80211_RRF_NO_HT40PLUS         = 1<<14,
        NL80211_RRF_NO_80MHZ            = 1<<15,
@@ -2859,6 +2862,7 @@ enum nl80211_reg_rule_flags {
 #define NL80211_RRF_NO_IR              NL80211_RRF_NO_IR
 #define NL80211_RRF_NO_HT40            (NL80211_RRF_NO_HT40MINUS |\
                                         NL80211_RRF_NO_HT40PLUS)
+#define NL80211_RRF_GO_CONCURRENT      NL80211_RRF_IR_CONCURRENT
 
 /* For backport compatibility with older userspace */
 #define NL80211_RRF_NO_IR_ALL          (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
index 64a012a..086de49 100644 (file)
@@ -302,6 +302,20 @@ config MAC80211_DEBUG_COUNTERS
        ---help---
          Selecting this option causes mac80211 to keep additional
          and very verbose statistics about TX and RX handler use
-         and show them in debugfs.
+         as well as a few selected dot11 counters. These will be
+         exposed in debugfs.
+
+         Note that some of the counters are not concurrency safe
+         and may thus not always be accurate.
 
          If unsure, say N.
+
+config MAC80211_STA_HASH_MAX_SIZE
+       int "Station hash table maximum size" if MAC80211_DEBUG_MENU
+       default 0
+       ---help---
+         Setting this option to a low value (e.g. 4) allows testing the
+         hash table with collisions relatively deterministically (just
+         connect more stations than the number selected here.)
+
+         If unsure, leave the default of 0.
index 265e427..3469bbd 100644 (file)
@@ -137,6 +137,9 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy,
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        sdata->noack_map = noack_map;
+
+       ieee80211_check_fast_xmit_iface(sdata);
+
        return 0;
 }
 
@@ -309,6 +312,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        u32 iv32;
        u16 iv16;
        int err = -ENOENT;
+       struct ieee80211_key_seq kseq = {};
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -339,10 +343,12 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                iv32 = key->u.tkip.tx.iv32;
                iv16 = key->u.tkip.tx.iv16;
 
-               if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
-                       drv_get_tkip_seq(sdata->local,
-                                        key->conf.hw_key_idx,
-                                        &iv32, &iv16);
+               if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+                   !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+                       drv_get_key_seq(sdata->local, key, &kseq);
+                       iv32 = kseq.tkip.iv32;
+                       iv16 = kseq.tkip.iv16;
+               }
 
                seq[0] = iv16 & 0xff;
                seq[1] = (iv16 >> 8) & 0xff;
@@ -355,52 +361,85 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
-               pn64 = atomic64_read(&key->u.ccmp.tx_pn);
-               seq[0] = pn64;
-               seq[1] = pn64 >> 8;
-               seq[2] = pn64 >> 16;
-               seq[3] = pn64 >> 24;
-               seq[4] = pn64 >> 32;
-               seq[5] = pn64 >> 40;
+               if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+                   !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+                       drv_get_key_seq(sdata->local, key, &kseq);
+                       memcpy(seq, kseq.ccmp.pn, 6);
+               } else {
+                       pn64 = atomic64_read(&key->u.ccmp.tx_pn);
+                       seq[0] = pn64;
+                       seq[1] = pn64 >> 8;
+                       seq[2] = pn64 >> 16;
+                       seq[3] = pn64 >> 24;
+                       seq[4] = pn64 >> 32;
+                       seq[5] = pn64 >> 40;
+               }
                params.seq = seq;
                params.seq_len = 6;
                break;
        case WLAN_CIPHER_SUITE_AES_CMAC:
        case WLAN_CIPHER_SUITE_BIP_CMAC_256:
-               pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
-               seq[0] = pn64;
-               seq[1] = pn64 >> 8;
-               seq[2] = pn64 >> 16;
-               seq[3] = pn64 >> 24;
-               seq[4] = pn64 >> 32;
-               seq[5] = pn64 >> 40;
+               if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+                   !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+                       drv_get_key_seq(sdata->local, key, &kseq);
+                       memcpy(seq, kseq.aes_cmac.pn, 6);
+               } else {
+                       pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
+                       seq[0] = pn64;
+                       seq[1] = pn64 >> 8;
+                       seq[2] = pn64 >> 16;
+                       seq[3] = pn64 >> 24;
+                       seq[4] = pn64 >> 32;
+                       seq[5] = pn64 >> 40;
+               }
                params.seq = seq;
                params.seq_len = 6;
                break;
        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
-               pn64 = atomic64_read(&key->u.aes_gmac.tx_pn);
-               seq[0] = pn64;
-               seq[1] = pn64 >> 8;
-               seq[2] = pn64 >> 16;
-               seq[3] = pn64 >> 24;
-               seq[4] = pn64 >> 32;
-               seq[5] = pn64 >> 40;
+               if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+                   !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+                       drv_get_key_seq(sdata->local, key, &kseq);
+                       memcpy(seq, kseq.aes_gmac.pn, 6);
+               } else {
+                       pn64 = atomic64_read(&key->u.aes_gmac.tx_pn);
+                       seq[0] = pn64;
+                       seq[1] = pn64 >> 8;
+                       seq[2] = pn64 >> 16;
+                       seq[3] = pn64 >> 24;
+                       seq[4] = pn64 >> 32;
+                       seq[5] = pn64 >> 40;
+               }
                params.seq = seq;
                params.seq_len = 6;
                break;
        case WLAN_CIPHER_SUITE_GCMP:
        case WLAN_CIPHER_SUITE_GCMP_256:
-               pn64 = atomic64_read(&key->u.gcmp.tx_pn);
-               seq[0] = pn64;
-               seq[1] = pn64 >> 8;
-               seq[2] = pn64 >> 16;
-               seq[3] = pn64 >> 24;
-               seq[4] = pn64 >> 32;
-               seq[5] = pn64 >> 40;
+               if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+                   !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+                       drv_get_key_seq(sdata->local, key, &kseq);
+                       memcpy(seq, kseq.gcmp.pn, 6);
+               } else {
+                       pn64 = atomic64_read(&key->u.gcmp.tx_pn);
+                       seq[0] = pn64;
+                       seq[1] = pn64 >> 8;
+                       seq[2] = pn64 >> 16;
+                       seq[3] = pn64 >> 24;
+                       seq[4] = pn64 >> 32;
+                       seq[5] = pn64 >> 40;
+               }
                params.seq = seq;
                params.seq_len = 6;
                break;
+       default:
+               if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+                       break;
+               if (WARN_ON(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
+                       break;
+               drv_get_key_seq(sdata->local, key, &kseq);
+               params.seq = kseq.hw.seq;
+               params.seq_len = kseq.hw.seq_len;
+               break;
        }
 
        params.key = key->conf.key;
@@ -2099,10 +2138,14 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
        int err;
 
        if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+               ieee80211_check_fast_xmit_all(local);
+
                err = drv_set_frag_threshold(local, wiphy->frag_threshold);
 
-               if (err)
+               if (err) {
+                       ieee80211_check_fast_xmit_all(local);
                        return err;
+               }
        }
 
        if ((changed & WIPHY_PARAM_COVERAGE_CLASS) ||
@@ -3336,8 +3379,14 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                break;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
-               if (!sdata->u.mgd.associated)
+               sdata_lock(sdata);
+               if (!sdata->u.mgd.associated ||
+                   (params->offchan && params->wait &&
+                    local->ops->remain_on_channel &&
+                    memcmp(sdata->u.mgd.associated->bssid,
+                           mgmt->bssid, ETH_ALEN)))
                        need_offchan = true;
+               sdata_unlock(sdata);
                break;
        case NL80211_IFTYPE_P2P_DEVICE:
                need_offchan = true;
index 5bcd4e5..7e9b624 100644 (file)
@@ -664,6 +664,8 @@ out:
                ieee80211_bss_info_change_notify(sdata,
                                                 BSS_CHANGED_IDLE);
 
+       ieee80211_check_fast_xmit_iface(sdata);
+
        return ret;
 }
 
@@ -1030,6 +1032,8 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
        if (sdata->vif.type == NL80211_IFTYPE_AP)
                __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
 
+       ieee80211_check_fast_xmit_iface(sdata);
+
        if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
                ieee80211_free_chanctx(local, old_ctx);
 
@@ -1376,6 +1380,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
                                __ieee80211_vif_copy_chanctx_to_vlans(sdata,
                                                                      false);
 
+                       ieee80211_check_fast_xmit_iface(sdata);
+
                        sdata->radar_required = sdata->reserved_radar_required;
 
                        if (sdata->vif.bss_conf.chandef.width !=
index 23813eb..b17206d 100644 (file)
@@ -219,8 +219,8 @@ static const struct file_operations stats_ ##name## _ops = {                \
        .llseek = generic_file_llseek,                                  \
 };
 
-#define DEBUGFS_STATS_ADD(name, field)                                 \
-       debugfs_create_u32(#name, 0400, statsd, (u32 *) &field);
+#define DEBUGFS_STATS_ADD(name)                                        \
+       debugfs_create_u32(#name, 0400, statsd, &local->name);
 #define DEBUGFS_DEVSTATS_ADD(name)                                     \
        debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
 
@@ -255,53 +255,31 @@ void debugfs_hw_add(struct ieee80211_local *local)
        if (!statsd)
                return;
 
-       DEBUGFS_STATS_ADD(transmitted_fragment_count,
-               local->dot11TransmittedFragmentCount);
-       DEBUGFS_STATS_ADD(multicast_transmitted_frame_count,
-               local->dot11MulticastTransmittedFrameCount);
-       DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount);
-       DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount);
-       DEBUGFS_STATS_ADD(multiple_retry_count,
-               local->dot11MultipleRetryCount);
-       DEBUGFS_STATS_ADD(frame_duplicate_count,
-               local->dot11FrameDuplicateCount);
-       DEBUGFS_STATS_ADD(received_fragment_count,
-               local->dot11ReceivedFragmentCount);
-       DEBUGFS_STATS_ADD(multicast_received_frame_count,
-               local->dot11MulticastReceivedFrameCount);
-       DEBUGFS_STATS_ADD(transmitted_frame_count,
-               local->dot11TransmittedFrameCount);
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-       DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop);
-       DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued);
-       DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
-               local->tx_handlers_drop_fragment);
-       DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
-               local->tx_handlers_drop_wep);
-       DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc,
-               local->tx_handlers_drop_not_assoc);
-       DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port,
-               local->tx_handlers_drop_unauth_port);
-       DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop);
-       DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued);
-       DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc,
-               local->rx_handlers_drop_nullfunc);
-       DEBUGFS_STATS_ADD(rx_handlers_drop_defrag,
-               local->rx_handlers_drop_defrag);
-       DEBUGFS_STATS_ADD(rx_handlers_drop_short,
-               local->rx_handlers_drop_short);
-       DEBUGFS_STATS_ADD(tx_expand_skb_head,
-               local->tx_expand_skb_head);
-       DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,
-               local->tx_expand_skb_head_cloned);
-       DEBUGFS_STATS_ADD(rx_expand_skb_head,
-               local->rx_expand_skb_head);
-       DEBUGFS_STATS_ADD(rx_expand_skb_head2,
-               local->rx_expand_skb_head2);
-       DEBUGFS_STATS_ADD(rx_handlers_fragments,
-               local->rx_handlers_fragments);
-       DEBUGFS_STATS_ADD(tx_status_drop,
-               local->tx_status_drop);
+       DEBUGFS_STATS_ADD(dot11TransmittedFragmentCount);
+       DEBUGFS_STATS_ADD(dot11MulticastTransmittedFrameCount);
+       DEBUGFS_STATS_ADD(dot11FailedCount);
+       DEBUGFS_STATS_ADD(dot11RetryCount);
+       DEBUGFS_STATS_ADD(dot11MultipleRetryCount);
+       DEBUGFS_STATS_ADD(dot11FrameDuplicateCount);
+       DEBUGFS_STATS_ADD(dot11ReceivedFragmentCount);
+       DEBUGFS_STATS_ADD(dot11MulticastReceivedFrameCount);
+       DEBUGFS_STATS_ADD(dot11TransmittedFrameCount);
+       DEBUGFS_STATS_ADD(tx_handlers_drop);
+       DEBUGFS_STATS_ADD(tx_handlers_queued);
+       DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
+       DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
+       DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
+       DEBUGFS_STATS_ADD(rx_handlers_drop);
+       DEBUGFS_STATS_ADD(rx_handlers_queued);
+       DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
+       DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
+       DEBUGFS_STATS_ADD(rx_handlers_drop_short);
+       DEBUGFS_STATS_ADD(tx_expand_skb_head);
+       DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
+       DEBUGFS_STATS_ADD(rx_expand_skb_head_defrag);
+       DEBUGFS_STATS_ADD(rx_handlers_fragments);
+       DEBUGFS_STATS_ADD(tx_status_drop);
 #endif
        DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
        DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
index 252859e..06d5293 100644 (file)
@@ -29,8 +29,6 @@ static ssize_t sta_ ##name## _read(struct file *file,                 \
                                      format_string, sta->field);       \
 }
 #define STA_READ_D(name, field) STA_READ(name, field, "%d\n")
-#define STA_READ_U(name, field) STA_READ(name, field, "%u\n")
-#define STA_READ_S(name, field) STA_READ(name, field, "%s\n")
 
 #define STA_OPS(name)                                                  \
 static const struct file_operations sta_ ##name## _ops = {             \
@@ -52,10 +50,7 @@ static const struct file_operations sta_ ##name## _ops = {           \
                STA_OPS(name)
 
 STA_FILE(aid, sta.aid, D);
-STA_FILE(dev, sdata->name, S);
-STA_FILE(last_signal, last_signal, D);
 STA_FILE(last_ack_signal, last_ack_signal, D);
-STA_FILE(beacon_loss_count, beacon_loss_count, D);
 
 static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
                              size_t count, loff_t *ppos)
@@ -101,40 +96,6 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file,
 }
 STA_OPS(num_ps_buf_frames);
 
-static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf,
-                                   size_t count, loff_t *ppos)
-{
-       struct sta_info *sta = file->private_data;
-       return mac80211_format_buffer(userbuf, count, ppos, "%d\n",
-                                     jiffies_to_msecs(jiffies - sta->last_rx));
-}
-STA_OPS(inactive_ms);
-
-
-static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf,
-                                       size_t count, loff_t *ppos)
-{
-       struct sta_info *sta = file->private_data;
-       struct timespec uptime;
-       struct tm result;
-       long connected_time_secs;
-       char buf[100];
-       int res;
-       ktime_get_ts(&uptime);
-       connected_time_secs = uptime.tv_sec - sta->last_connected;
-       time_to_tm(connected_time_secs, 0, &result);
-       result.tm_year -= 70;
-       result.tm_mday -= 1;
-       res = scnprintf(buf, sizeof(buf),
-               "years  - %ld\nmonths - %d\ndays   - %d\nclock  - %d:%d:%d\n\n",
-                       result.tm_year, result.tm_mon, result.tm_mday,
-                       result.tm_hour, result.tm_min, result.tm_sec);
-       return simple_read_from_buffer(userbuf, count, ppos, buf, res);
-}
-STA_OPS(connected_time);
-
-
-
 static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
                                      size_t count, loff_t *ppos)
 {
@@ -359,37 +320,6 @@ static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
 }
 STA_OPS(vht_capa);
 
-static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf,
-                                       size_t count, loff_t *ppos)
-{
-       struct sta_info *sta = file->private_data;
-       struct rate_info rinfo;
-       u16 rate;
-       sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo);
-       rate = cfg80211_calculate_bitrate(&rinfo);
-
-       return mac80211_format_buffer(userbuf, count, ppos,
-                                     "%d.%d MBit/s\n",
-                                     rate/10, rate%10);
-}
-STA_OPS(current_tx_rate);
-
-static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf,
-                                    size_t count, loff_t *ppos)
-{
-       struct sta_info *sta = file->private_data;
-       struct rate_info rinfo;
-       u16 rate;
-
-       sta_set_rate_info_rx(sta, &rinfo);
-
-       rate = cfg80211_calculate_bitrate(&rinfo);
-
-       return mac80211_format_buffer(userbuf, count, ppos,
-                                     "%d.%d MBit/s\n",
-                                     rate/10, rate%10);
-}
-STA_OPS(last_rx_rate);
 
 #define DEBUGFS_ADD(name) \
        debugfs_create_file(#name, 0400, \
@@ -432,30 +362,15 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
 
        DEBUGFS_ADD(flags);
        DEBUGFS_ADD(num_ps_buf_frames);
-       DEBUGFS_ADD(inactive_ms);
-       DEBUGFS_ADD(connected_time);
        DEBUGFS_ADD(last_seq_ctrl);
        DEBUGFS_ADD(agg_status);
-       DEBUGFS_ADD(dev);
-       DEBUGFS_ADD(last_signal);
-       DEBUGFS_ADD(beacon_loss_count);
        DEBUGFS_ADD(ht_capa);
        DEBUGFS_ADD(vht_capa);
        DEBUGFS_ADD(last_ack_signal);
-       DEBUGFS_ADD(current_tx_rate);
-       DEBUGFS_ADD(last_rx_rate);
 
-       DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
-       DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);
-       DEBUGFS_ADD_COUNTER(rx_bytes, rx_bytes);
-       DEBUGFS_ADD_COUNTER(tx_bytes, tx_bytes);
        DEBUGFS_ADD_COUNTER(rx_duplicates, num_duplicates);
        DEBUGFS_ADD_COUNTER(rx_fragments, rx_fragments);
-       DEBUGFS_ADD_COUNTER(rx_dropped, rx_dropped);
-       DEBUGFS_ADD_COUNTER(tx_fragments, tx_fragments);
        DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count);
-       DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed);
-       DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count);
 
        if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
                debugfs_create_x32("driver_buffered_tids", 0400,
index 26e1ca8..c01e681 100644 (file)
@@ -417,12 +417,13 @@ static inline int drv_get_stats(struct ieee80211_local *local,
        return ret;
 }
 
-static inline void drv_get_tkip_seq(struct ieee80211_local *local,
-                                   u8 hw_key_idx, u32 *iv32, u16 *iv16)
+static inline void drv_get_key_seq(struct ieee80211_local *local,
+                                  struct ieee80211_key *key,
+                                  struct ieee80211_key_seq *seq)
 {
-       if (local->ops->get_tkip_seq)
-               local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16);
-       trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16);
+       if (local->ops->get_key_seq)
+               local->ops->get_key_seq(&local->hw, &key->conf, seq);
+       trace_drv_get_key_seq(local, &key->conf);
 }
 
 static inline int drv_set_frag_threshold(struct ieee80211_local *local,
index 52bcea6..188faab 100644 (file)
@@ -38,7 +38,7 @@ static void ieee80211_get_ringparam(struct net_device *dev,
 static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
        "rx_packets", "rx_bytes",
        "rx_duplicates", "rx_fragments", "rx_dropped",
-       "tx_packets", "tx_bytes", "tx_fragments",
+       "tx_packets", "tx_bytes",
        "tx_filtered", "tx_retry_failed", "tx_retries",
        "beacon_loss", "sta_state", "txrate", "rxrate", "signal",
        "channel", "noise", "ch_time", "ch_time_busy",
@@ -87,7 +87,6 @@ static void ieee80211_get_stats(struct net_device *dev,
                                                        \
                data[i++] += sinfo.tx_packets;          \
                data[i++] += sinfo.tx_bytes;            \
-               data[i++] += sta->tx_fragments;         \
                data[i++] += sta->tx_filtered_count;    \
                data[i++] += sta->tx_retry_failed;      \
                data[i++] += sta->tx_retry_count;       \
index ab46ab4..241b74f 100644 (file)
@@ -181,8 +181,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
 
 /**
  * enum ieee80211_packet_rx_flags - packet RX flags
- * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed
- *     (incl. multicast frames)
  * @IEEE80211_RX_FRAGMENTED: fragmented frame
  * @IEEE80211_RX_AMSDU: a-MSDU packet
  * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed
@@ -192,7 +190,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
  * @rx_flags field of &struct ieee80211_rx_status.
  */
 enum ieee80211_packet_rx_flags {
-       IEEE80211_RX_RA_MATCH                   = BIT(1),
        IEEE80211_RX_FRAGMENTED                 = BIT(2),
        IEEE80211_RX_AMSDU                      = BIT(3),
        IEEE80211_RX_MALFORMED_ACTION_FRM       = BIT(4),
@@ -725,7 +722,6 @@ struct ieee80211_if_mesh {
  * enum ieee80211_sub_if_data_flags - virtual interface flags
  *
  * @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets
- * @IEEE80211_SDATA_PROMISC: interface is promisc
  * @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode
  * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between
  *     associated stations and deliver multicast frames both
@@ -735,7 +731,6 @@ struct ieee80211_if_mesh {
  */
 enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_ALLMULTI                = BIT(0),
-       IEEE80211_SDATA_PROMISC                 = BIT(1),
        IEEE80211_SDATA_OPERATING_GMODE         = BIT(2),
        IEEE80211_SDATA_DONT_BRIDGE_PACKETS     = BIT(3),
        IEEE80211_SDATA_DISCONNECT_RESUME       = BIT(4),
@@ -1211,8 +1206,8 @@ struct ieee80211_local {
 
        atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES];
 
-       /* number of interfaces with corresponding IFF_ flags */
-       atomic_t iff_allmultis, iff_promiscs;
+       /* number of interfaces with allmulti RX */
+       atomic_t iff_allmultis;
 
        struct rate_control_ref *rate_ctrl;
 
@@ -1264,6 +1259,15 @@ struct ieee80211_local {
        struct list_head chanctx_list;
        struct mutex chanctx_mtx;
 
+#ifdef CONFIG_MAC80211_LEDS
+       struct led_trigger tx_led, rx_led, assoc_led, radio_led;
+       struct led_trigger tpt_led;
+       atomic_t tx_led_active, rx_led_active, assoc_led_active;
+       atomic_t radio_led_active, tpt_led_active;
+       struct tpt_led_trigger *tpt_led_trigger;
+#endif
+
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
        /* SNMP counters */
        /* dot11CountersTable */
        u32 dot11TransmittedFragmentCount;
@@ -1276,18 +1280,9 @@ struct ieee80211_local {
        u32 dot11MulticastReceivedFrameCount;
        u32 dot11TransmittedFrameCount;
 
-#ifdef CONFIG_MAC80211_LEDS
-       struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led;
-       struct tpt_led_trigger *tpt_led_trigger;
-       char tx_led_name[32], rx_led_name[32],
-            assoc_led_name[32], radio_led_name[32];
-#endif
-
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
        /* TX/RX handler statistics */
        unsigned int tx_handlers_drop;
        unsigned int tx_handlers_queued;
-       unsigned int tx_handlers_drop_fragment;
        unsigned int tx_handlers_drop_wep;
        unsigned int tx_handlers_drop_not_assoc;
        unsigned int tx_handlers_drop_unauth_port;
@@ -1298,8 +1293,7 @@ struct ieee80211_local {
        unsigned int rx_handlers_drop_short;
        unsigned int tx_expand_skb_head;
        unsigned int tx_expand_skb_head_cloned;
-       unsigned int rx_expand_skb_head;
-       unsigned int rx_expand_skb_head2;
+       unsigned int rx_expand_skb_head_defrag;
        unsigned int rx_handlers_fragments;
        unsigned int tx_status_drop;
 #define I802_DEBUG_INC(c) (c)++
@@ -1651,6 +1645,11 @@ struct sk_buff *
 ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
                              struct sk_buff *skb, u32 info_flags);
 
+void ieee80211_check_fast_xmit(struct sta_info *sta);
+void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
+void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
+void ieee80211_clear_fast_xmit(struct sta_info *sta);
+
 /* HT */
 void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_sta_ht_cap *ht_cap);
index b4ac596..dc2d713 100644 (file)
@@ -697,9 +697,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
        if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
                atomic_inc(&local->iff_allmultis);
 
-       if (sdata->flags & IEEE80211_SDATA_PROMISC)
-               atomic_inc(&local->iff_promiscs);
-
        if (coming_up)
                local->open_count++;
 
@@ -827,13 +824,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
                     (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1));
 
-       /* don't count this interface for promisc/allmulti while it is down */
+       /* don't count this interface for allmulti while it is down */
        if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
                atomic_dec(&local->iff_allmultis);
 
-       if (sdata->flags & IEEE80211_SDATA_PROMISC)
-               atomic_dec(&local->iff_promiscs);
-
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
                local->fif_pspoll--;
                local->fif_probe_req--;
@@ -1047,12 +1041,10 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
-       int allmulti, promisc, sdata_allmulti, sdata_promisc;
+       int allmulti, sdata_allmulti;
 
        allmulti = !!(dev->flags & IFF_ALLMULTI);
-       promisc = !!(dev->flags & IFF_PROMISC);
        sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
-       sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC);
 
        if (allmulti != sdata_allmulti) {
                if (dev->flags & IFF_ALLMULTI)
@@ -1062,13 +1054,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
                sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
        }
 
-       if (promisc != sdata_promisc) {
-               if (dev->flags & IFF_PROMISC)
-                       atomic_inc(&local->iff_promiscs);
-               else
-                       atomic_dec(&local->iff_promiscs);
-               sdata->flags ^= IEEE80211_SDATA_PROMISC;
-       }
        spin_lock_bh(&local->filter_lock);
        __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
        spin_unlock_bh(&local->filter_lock);
@@ -1109,6 +1094,35 @@ static u16 ieee80211_netdev_select_queue(struct net_device *dev,
        return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
 }
 
+static struct rtnl_link_stats64 *
+ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+       int i;
+
+       for_each_possible_cpu(i) {
+               const struct pcpu_sw_netstats *tstats;
+               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+               unsigned int start;
+
+               tstats = per_cpu_ptr(dev->tstats, i);
+
+               do {
+                       start = u64_stats_fetch_begin_irq(&tstats->syncp);
+                       rx_packets = tstats->rx_packets;
+                       tx_packets = tstats->tx_packets;
+                       rx_bytes = tstats->rx_bytes;
+                       tx_bytes = tstats->tx_bytes;
+               } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
+
+               stats->rx_packets += rx_packets;
+               stats->tx_packets += tx_packets;
+               stats->rx_bytes   += rx_bytes;
+               stats->tx_bytes   += tx_bytes;
+       }
+
+       return stats;
+}
+
 static const struct net_device_ops ieee80211_dataif_ops = {
        .ndo_open               = ieee80211_open,
        .ndo_stop               = ieee80211_stop,
@@ -1118,6 +1132,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
        .ndo_change_mtu         = ieee80211_change_mtu,
        .ndo_set_mac_address    = ieee80211_change_mac,
        .ndo_select_queue       = ieee80211_netdev_select_queue,
+       .ndo_get_stats64        = ieee80211_get_stats64,
 };
 
 static u16 ieee80211_monitor_select_queue(struct net_device *dev,
@@ -1151,14 +1166,21 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
        .ndo_change_mtu         = ieee80211_change_mtu,
        .ndo_set_mac_address    = ieee80211_change_mac,
        .ndo_select_queue       = ieee80211_monitor_select_queue,
+       .ndo_get_stats64        = ieee80211_get_stats64,
 };
 
+static void ieee80211_if_free(struct net_device *dev)
+{
+       free_percpu(dev->tstats);
+       free_netdev(dev);
+}
+
 static void ieee80211_if_setup(struct net_device *dev)
 {
        ether_setup(dev);
        dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->netdev_ops = &ieee80211_dataif_ops;
-       dev->destructor = free_netdev;
+       dev->destructor = ieee80211_if_free;
 }
 
 static void ieee80211_iface_work(struct work_struct *work)
@@ -1699,6 +1721,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                        return -ENOMEM;
                dev_net_set(ndev, wiphy_net(local->hw.wiphy));
 
+               ndev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+               if (!ndev->tstats) {
+                       free_netdev(ndev);
+                       return -ENOMEM;
+               }
+
                ndev->needed_headroom = local->tx_headroom +
                                        4*6 /* four MAC addresses */
                                        + 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
index 2291cd7..2e67737 100644 (file)
@@ -229,6 +229,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
 
        if (uni) {
                rcu_assign_pointer(sdata->default_unicast_key, key);
+               ieee80211_check_fast_xmit_iface(sdata);
                drv_set_default_unicast_key(sdata->local, sdata, idx);
        }
 
@@ -298,6 +299,7 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
                if (pairwise) {
                        rcu_assign_pointer(sta->ptk[idx], new);
                        sta->ptk_idx = idx;
+                       ieee80211_check_fast_xmit(sta);
                } else {
                        rcu_assign_pointer(sta->gtk[idx], new);
                        sta->gtk_idx = idx;
@@ -483,15 +485,17 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                break;
        default:
                if (cs) {
-                       size_t len = (seq_len > MAX_PN_LEN) ?
-                                               MAX_PN_LEN : seq_len;
+                       if (seq_len && seq_len != cs->pn_len) {
+                               kfree(key);
+                               return ERR_PTR(-EINVAL);
+                       }
 
                        key->conf.iv_len = cs->hdr_len;
                        key->conf.icv_len = cs->mic_len;
                        for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
-                               for (j = 0; j < len; j++)
+                               for (j = 0; j < seq_len; j++)
                                        key->u.gen.rx_pn[i][j] =
-                                                       seq[len - j - 1];
+                                                       seq[seq_len - j - 1];
                        key->flags |= KEY_FLAG_CIPHER_SCHEME;
                }
        }
index c5a3183..df430a6 100644 (file)
@@ -18,7 +18,6 @@
 
 #define NUM_DEFAULT_KEYS 4
 #define NUM_DEFAULT_MGMT_KEYS 2
-#define MAX_PN_LEN 16
 
 struct ieee80211_local;
 struct ieee80211_sub_if_data;
@@ -116,7 +115,7 @@ struct ieee80211_key {
                } gcmp;
                struct {
                        /* generic cipher scheme */
-                       u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN];
+                       u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_MAX_PN_LEN];
                } gen;
        } u;
 
index e2b8364..38f0556 100644 (file)
 #include <linux/export.h>
 #include "led.h"
 
-#define MAC80211_BLINK_DELAY 50 /* ms */
-
-void ieee80211_led_rx(struct ieee80211_local *local)
-{
-       unsigned long led_delay = MAC80211_BLINK_DELAY;
-       if (unlikely(!local->rx_led))
-               return;
-       led_trigger_blink_oneshot(local->rx_led, &led_delay, &led_delay, 0);
-}
-
-void ieee80211_led_tx(struct ieee80211_local *local)
-{
-       unsigned long led_delay = MAC80211_BLINK_DELAY;
-       if (unlikely(!local->tx_led))
-               return;
-       led_trigger_blink_oneshot(local->tx_led, &led_delay, &led_delay, 0);
-}
-
 void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
 {
-       if (unlikely(!local->assoc_led))
+       if (!atomic_read(&local->assoc_led_active))
                return;
        if (associated)
-               led_trigger_event(local->assoc_led, LED_FULL);
+               led_trigger_event(&local->assoc_led, LED_FULL);
        else
-               led_trigger_event(local->assoc_led, LED_OFF);
+               led_trigger_event(&local->assoc_led, LED_OFF);
 }
 
 void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
 {
-       if (unlikely(!local->radio_led))
+       if (!atomic_read(&local->radio_led_active))
                return;
        if (enabled)
-               led_trigger_event(local->radio_led, LED_FULL);
+               led_trigger_event(&local->radio_led, LED_FULL);
        else
-               led_trigger_event(local->radio_led, LED_OFF);
+               led_trigger_event(&local->radio_led, LED_OFF);
+}
+
+void ieee80211_alloc_led_names(struct ieee80211_local *local)
+{
+       local->rx_led.name = kasprintf(GFP_KERNEL, "%srx",
+                                      wiphy_name(local->hw.wiphy));
+       local->tx_led.name = kasprintf(GFP_KERNEL, "%stx",
+                                      wiphy_name(local->hw.wiphy));
+       local->assoc_led.name = kasprintf(GFP_KERNEL, "%sassoc",
+                                         wiphy_name(local->hw.wiphy));
+       local->radio_led.name = kasprintf(GFP_KERNEL, "%sradio",
+                                         wiphy_name(local->hw.wiphy));
+}
+
+void ieee80211_free_led_names(struct ieee80211_local *local)
+{
+       kfree(local->rx_led.name);
+       kfree(local->tx_led.name);
+       kfree(local->assoc_led.name);
+       kfree(local->radio_led.name);
+}
+
+static void ieee80211_tx_led_activate(struct led_classdev *led_cdev)
+{
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    tx_led);
+
+       atomic_inc(&local->tx_led_active);
+}
+
+static void ieee80211_tx_led_deactivate(struct led_classdev *led_cdev)
+{
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    tx_led);
+
+       atomic_dec(&local->tx_led_active);
+}
+
+static void ieee80211_rx_led_activate(struct led_classdev *led_cdev)
+{
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    rx_led);
+
+       atomic_inc(&local->rx_led_active);
+}
+
+static void ieee80211_rx_led_deactivate(struct led_classdev *led_cdev)
+{
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    rx_led);
+
+       atomic_dec(&local->rx_led_active);
+}
+
+static void ieee80211_assoc_led_activate(struct led_classdev *led_cdev)
+{
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    assoc_led);
+
+       atomic_inc(&local->assoc_led_active);
+}
+
+static void ieee80211_assoc_led_deactivate(struct led_classdev *led_cdev)
+{
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    assoc_led);
+
+       atomic_dec(&local->assoc_led_active);
+}
+
+static void ieee80211_radio_led_activate(struct led_classdev *led_cdev)
+{
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    radio_led);
+
+       atomic_inc(&local->radio_led_active);
+}
+
+static void ieee80211_radio_led_deactivate(struct led_classdev *led_cdev)
+{
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    radio_led);
+
+       atomic_dec(&local->radio_led_active);
+}
+
+static void ieee80211_tpt_led_activate(struct led_classdev *led_cdev)
+{
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    tpt_led);
+
+       atomic_inc(&local->tpt_led_active);
 }
 
-void ieee80211_led_names(struct ieee80211_local *local)
+static void ieee80211_tpt_led_deactivate(struct led_classdev *led_cdev)
 {
-       snprintf(local->rx_led_name, sizeof(local->rx_led_name),
-                "%srx", wiphy_name(local->hw.wiphy));
-       snprintf(local->tx_led_name, sizeof(local->tx_led_name),
-                "%stx", wiphy_name(local->hw.wiphy));
-       snprintf(local->assoc_led_name, sizeof(local->assoc_led_name),
-                "%sassoc", wiphy_name(local->hw.wiphy));
-       snprintf(local->radio_led_name, sizeof(local->radio_led_name),
-                "%sradio", wiphy_name(local->hw.wiphy));
+       struct ieee80211_local *local = container_of(led_cdev->trigger,
+                                                    struct ieee80211_local,
+                                                    tpt_led);
+
+       atomic_dec(&local->tpt_led_active);
 }
 
 void ieee80211_led_init(struct ieee80211_local *local)
 {
-       local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
-       if (local->rx_led) {
-               local->rx_led->name = local->rx_led_name;
-               if (led_trigger_register(local->rx_led)) {
-                       kfree(local->rx_led);
-                       local->rx_led = NULL;
-               }
+       atomic_set(&local->rx_led_active, 0);
+       local->rx_led.activate = ieee80211_rx_led_activate;
+       local->rx_led.deactivate = ieee80211_rx_led_deactivate;
+       if (local->rx_led.name && led_trigger_register(&local->rx_led)) {
+               kfree(local->rx_led.name);
+               local->rx_led.name = NULL;
        }
 
-       local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
-       if (local->tx_led) {
-               local->tx_led->name = local->tx_led_name;
-               if (led_trigger_register(local->tx_led)) {
-                       kfree(local->tx_led);
-                       local->tx_led = NULL;
-               }
+       atomic_set(&local->tx_led_active, 0);
+       local->tx_led.activate = ieee80211_tx_led_activate;
+       local->tx_led.deactivate = ieee80211_tx_led_deactivate;
+       if (local->tx_led.name && led_trigger_register(&local->tx_led)) {
+               kfree(local->tx_led.name);
+               local->tx_led.name = NULL;
        }
 
-       local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
-       if (local->assoc_led) {
-               local->assoc_led->name = local->assoc_led_name;
-               if (led_trigger_register(local->assoc_led)) {
-                       kfree(local->assoc_led);
-                       local->assoc_led = NULL;
-               }
+       atomic_set(&local->assoc_led_active, 0);
+       local->assoc_led.activate = ieee80211_assoc_led_activate;
+       local->assoc_led.deactivate = ieee80211_assoc_led_deactivate;
+       if (local->assoc_led.name && led_trigger_register(&local->assoc_led)) {
+               kfree(local->assoc_led.name);
+               local->assoc_led.name = NULL;
        }
 
-       local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
-       if (local->radio_led) {
-               local->radio_led->name = local->radio_led_name;
-               if (led_trigger_register(local->radio_led)) {
-                       kfree(local->radio_led);
-                       local->radio_led = NULL;
-               }
+       atomic_set(&local->radio_led_active, 0);
+       local->radio_led.activate = ieee80211_radio_led_activate;
+       local->radio_led.deactivate = ieee80211_radio_led_deactivate;
+       if (local->radio_led.name && led_trigger_register(&local->radio_led)) {
+               kfree(local->radio_led.name);
+               local->radio_led.name = NULL;
        }
 
+       atomic_set(&local->tpt_led_active, 0);
        if (local->tpt_led_trigger) {
-               if (led_trigger_register(&local->tpt_led_trigger->trig)) {
+               local->tpt_led.activate = ieee80211_tpt_led_activate;
+               local->tpt_led.deactivate = ieee80211_tpt_led_deactivate;
+               if (led_trigger_register(&local->tpt_led)) {
                        kfree(local->tpt_led_trigger);
                        local->tpt_led_trigger = NULL;
                }
@@ -110,58 +189,50 @@ void ieee80211_led_init(struct ieee80211_local *local)
 
 void ieee80211_led_exit(struct ieee80211_local *local)
 {
-       if (local->radio_led) {
-               led_trigger_unregister(local->radio_led);
-               kfree(local->radio_led);
-       }
-       if (local->assoc_led) {
-               led_trigger_unregister(local->assoc_led);
-               kfree(local->assoc_led);
-       }
-       if (local->tx_led) {
-               led_trigger_unregister(local->tx_led);
-               kfree(local->tx_led);
-       }
-       if (local->rx_led) {
-               led_trigger_unregister(local->rx_led);
-               kfree(local->rx_led);
-       }
+       if (local->radio_led.name)
+               led_trigger_unregister(&local->radio_led);
+       if (local->assoc_led.name)
+               led_trigger_unregister(&local->assoc_led);
+       if (local->tx_led.name)
+               led_trigger_unregister(&local->tx_led);
+       if (local->rx_led.name)
+               led_trigger_unregister(&local->rx_led);
 
        if (local->tpt_led_trigger) {
-               led_trigger_unregister(&local->tpt_led_trigger->trig);
+               led_trigger_unregister(&local->tpt_led);
                kfree(local->tpt_led_trigger);
        }
 }
 
-char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
+const char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       return local->radio_led_name;
+       return local->radio_led.name;
 }
 EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
 
-char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
+const char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       return local->assoc_led_name;
+       return local->assoc_led.name;
 }
 EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
 
-char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
+const char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       return local->tx_led_name;
+       return local->tx_led.name;
 }
 EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
 
-char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
+const char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       return local->rx_led_name;
+       return local->rx_led.name;
 }
 EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
 
@@ -211,10 +282,11 @@ static void tpt_trig_timer(unsigned long data)
        read_unlock(&tpt_trig->trig.leddev_list_lock);
 }
 
-char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
-                               unsigned int flags,
-                               const struct ieee80211_tpt_blink *blink_table,
-                               unsigned int blink_table_len)
+const char *
+__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
+                                  unsigned int flags,
+                                  const struct ieee80211_tpt_blink *blink_table,
+                                  unsigned int blink_table_len)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct tpt_led_trigger *tpt_trig;
@@ -229,7 +301,7 @@ char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
        snprintf(tpt_trig->name, sizeof(tpt_trig->name),
                 "%stpt", wiphy_name(local->hw.wiphy));
 
-       tpt_trig->trig.name = tpt_trig->name;
+       local->tpt_led.name = tpt_trig->name;
 
        tpt_trig->blink_table = blink_table;
        tpt_trig->blink_table_len = blink_table_len;
index 89f4344..a7893a1 100644 (file)
 #include <linux/leds.h>
 #include "ieee80211_i.h"
 
+#define MAC80211_BLINK_DELAY 50 /* ms */
+
+static inline void ieee80211_led_rx(struct ieee80211_local *local)
+{
+#ifdef CONFIG_MAC80211_LEDS
+       unsigned long led_delay = MAC80211_BLINK_DELAY;
+
+       if (!atomic_read(&local->rx_led_active))
+               return;
+       led_trigger_blink_oneshot(&local->rx_led, &led_delay, &led_delay, 0);
+#endif
+}
+
+static inline void ieee80211_led_tx(struct ieee80211_local *local)
+{
+#ifdef CONFIG_MAC80211_LEDS
+       unsigned long led_delay = MAC80211_BLINK_DELAY;
+
+       if (!atomic_read(&local->tx_led_active))
+               return;
+       led_trigger_blink_oneshot(&local->tx_led, &led_delay, &led_delay, 0);
+#endif
+}
+
 #ifdef CONFIG_MAC80211_LEDS
-void ieee80211_led_rx(struct ieee80211_local *local);
-void ieee80211_led_tx(struct ieee80211_local *local);
 void ieee80211_led_assoc(struct ieee80211_local *local,
                         bool associated);
 void ieee80211_led_radio(struct ieee80211_local *local,
                         bool enabled);
-void ieee80211_led_names(struct ieee80211_local *local);
+void ieee80211_alloc_led_names(struct ieee80211_local *local);
+void ieee80211_free_led_names(struct ieee80211_local *local);
 void ieee80211_led_init(struct ieee80211_local *local);
 void ieee80211_led_exit(struct ieee80211_local *local);
 void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
                                unsigned int types_on, unsigned int types_off);
 #else
-static inline void ieee80211_led_rx(struct ieee80211_local *local)
-{
-}
-static inline void ieee80211_led_tx(struct ieee80211_local *local)
-{
-}
 static inline void ieee80211_led_assoc(struct ieee80211_local *local,
                                       bool associated)
 {
@@ -38,7 +55,10 @@ static inline void ieee80211_led_radio(struct ieee80211_local *local,
                                       bool enabled)
 {
 }
-static inline void ieee80211_led_names(struct ieee80211_local *local)
+static inline void ieee80211_alloc_led_names(struct ieee80211_local *local)
+{
+}
+static inline void ieee80211_free_led_names(struct ieee80211_local *local)
 {
 }
 static inline void ieee80211_led_init(struct ieee80211_local *local)
@@ -58,7 +78,7 @@ static inline void
 ieee80211_tpt_led_trig_tx(struct ieee80211_local *local, __le16 fc, int bytes)
 {
 #ifdef CONFIG_MAC80211_LEDS
-       if (local->tpt_led_trigger && ieee80211_is_data(fc))
+       if (ieee80211_is_data(fc) && atomic_read(&local->tpt_led_active))
                local->tpt_led_trigger->tx_bytes += bytes;
 #endif
 }
@@ -67,7 +87,7 @@ static inline void
 ieee80211_tpt_led_trig_rx(struct ieee80211_local *local, __le16 fc, int bytes)
 {
 #ifdef CONFIG_MAC80211_LEDS
-       if (local->tpt_led_trigger && ieee80211_is_data(fc))
+       if (ieee80211_is_data(fc) && atomic_read(&local->tpt_led_active))
                local->tpt_led_trigger->rx_bytes += bytes;
 #endif
 }
index df3051d..3c956c5 100644 (file)
@@ -41,9 +41,6 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        unsigned int changed_flags;
        unsigned int new_flags = 0;
 
-       if (atomic_read(&local->iff_promiscs))
-               new_flags |= FIF_PROMISC_IN_BSS;
-
        if (atomic_read(&local->iff_allmultis))
                new_flags |= FIF_ALLMULTI;
 
@@ -646,7 +643,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
        skb_queue_head_init(&local->skb_queue);
        skb_queue_head_init(&local->skb_queue_unreliable);
 
-       ieee80211_led_names(local);
+       ieee80211_alloc_led_names(local);
 
        ieee80211_roc_setup(local);
 
@@ -771,8 +768,11 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
                        suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_256;
                }
 
-               for (r = 0; r < local->hw.n_cipher_schemes; r++)
+               for (r = 0; r < local->hw.n_cipher_schemes; r++) {
                        suites[w++] = cs[r].cipher;
+                       if (WARN_ON(cs[r].pn_len > IEEE80211_MAX_PN_LEN))
+                               return -EINVAL;
+               }
        }
 
        local->hw.wiphy->cipher_suites = suites;
@@ -840,7 +840,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        /* Only HW csum features are currently compatible with mac80211 */
        feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                           NETIF_F_HW_CSUM;
+                           NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA |
+                           NETIF_F_GSO_SOFTWARE;
        if (WARN_ON(hw->netdev_features & ~feature_whitelist))
                return -EINVAL;
 
@@ -1209,6 +1210,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
 
        sta_info_stop(local);
 
+       ieee80211_free_led_names(local);
+
        wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
index 60d737f..ac843fc 100644 (file)
@@ -72,10 +72,11 @@ static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,
  *
  * @sta: mesh peer link to restart
  *
- * Locking: this function must be called holding sta->lock
+ * Locking: this function must be called holding sta->plink_lock
  */
 static inline void mesh_plink_fsm_restart(struct sta_info *sta)
 {
+       lockdep_assert_held(&sta->plink_lock);
        sta->plink_state = NL80211_PLINK_LISTEN;
        sta->llid = sta->plid = sta->reason = 0;
        sta->plink_retries = 0;
@@ -213,13 +214,15 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
  * All mesh paths with this peer as next hop will be flushed
  * Returns beacon changed flag if the beacon content changed.
  *
- * Locking: the caller must hold sta->lock
+ * Locking: the caller must hold sta->plink_lock
  */
 static u32 __mesh_plink_deactivate(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        u32 changed = 0;
 
+       lockdep_assert_held(&sta->plink_lock);
+
        if (sta->plink_state == NL80211_PLINK_ESTAB)
                changed = mesh_plink_dec_estab_count(sdata);
        sta->plink_state = NL80211_PLINK_BLOCKED;
@@ -244,13 +247,13 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        u32 changed;
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_bh(&sta->plink_lock);
        changed = __mesh_plink_deactivate(sta);
        sta->reason = WLAN_REASON_MESH_PEER_CANCELED;
        mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
                            sta->sta.addr, sta->llid, sta->plid,
                            sta->reason);
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_bh(&sta->plink_lock);
 
        return changed;
 }
@@ -387,7 +390,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
        sband = local->hw.wiphy->bands[band];
        rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates);
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_bh(&sta->plink_lock);
        sta->last_rx = jiffies;
 
        /* rates and capabilities don't change during peering */
@@ -419,7 +422,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
        else
                rate_control_rate_update(local, sband, sta, changed);
 out:
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_bh(&sta->plink_lock);
 }
 
 static struct sta_info *
@@ -552,7 +555,7 @@ static void mesh_plink_timer(unsigned long data)
        if (sta->sdata->local->quiescing)
                return;
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_bh(&sta->plink_lock);
 
        /* If a timer fires just before a state transition on another CPU,
         * we may have already extended the timeout and changed state by the
@@ -563,7 +566,7 @@ static void mesh_plink_timer(unsigned long data)
                mpl_dbg(sta->sdata,
                        "Ignoring timer for %pM in state %s (timer adjusted)",
                        sta->sta.addr, mplstates[sta->plink_state]);
-               spin_unlock_bh(&sta->lock);
+               spin_unlock_bh(&sta->plink_lock);
                return;
        }
 
@@ -573,7 +576,7 @@ static void mesh_plink_timer(unsigned long data)
                mpl_dbg(sta->sdata,
                        "Ignoring timer for %pM in state %s (timer deleted)",
                        sta->sta.addr, mplstates[sta->plink_state]);
-               spin_unlock_bh(&sta->lock);
+               spin_unlock_bh(&sta->plink_lock);
                return;
        }
 
@@ -619,7 +622,7 @@ static void mesh_plink_timer(unsigned long data)
        default:
                break;
        }
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_bh(&sta->plink_lock);
        if (action)
                mesh_plink_frame_tx(sdata, action, sta->sta.addr,
                                    sta->llid, sta->plid, reason);
@@ -674,16 +677,16 @@ u32 mesh_plink_open(struct sta_info *sta)
        if (!test_sta_flag(sta, WLAN_STA_AUTH))
                return 0;
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_bh(&sta->plink_lock);
        sta->llid = mesh_get_new_llid(sdata);
        if (sta->plink_state != NL80211_PLINK_LISTEN &&
            sta->plink_state != NL80211_PLINK_BLOCKED) {
-               spin_unlock_bh(&sta->lock);
+               spin_unlock_bh(&sta->plink_lock);
                return 0;
        }
        sta->plink_state = NL80211_PLINK_OPN_SNT;
        mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout);
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_bh(&sta->plink_lock);
        mpl_dbg(sdata,
                "Mesh plink: starting establishment with %pM\n",
                sta->sta.addr);
@@ -700,10 +703,10 @@ u32 mesh_plink_block(struct sta_info *sta)
 {
        u32 changed;
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_bh(&sta->plink_lock);
        changed = __mesh_plink_deactivate(sta);
        sta->plink_state = NL80211_PLINK_BLOCKED;
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_bh(&sta->plink_lock);
 
        return changed;
 }
@@ -758,7 +761,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
        mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr,
                mplstates[sta->plink_state], mplevents[event]);
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_bh(&sta->plink_lock);
        switch (sta->plink_state) {
        case NL80211_PLINK_LISTEN:
                switch (event) {
@@ -872,7 +875,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
                 */
                break;
        }
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_bh(&sta->plink_lock);
        if (action) {
                mesh_plink_frame_tx(sdata, action, sta->sta.addr,
                                    sta->llid, sta->plid, sta->reason);
index 26053bf..3294666 100644 (file)
@@ -4307,15 +4307,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
 }
 
 static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
-                                    struct cfg80211_bss *cbss, bool assoc)
+                                    struct cfg80211_bss *cbss, bool assoc,
+                                    bool override)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_bss *bss = (void *)cbss->priv;
        struct sta_info *new_sta = NULL;
        struct ieee80211_supported_band *sband;
-       struct ieee80211_sta_ht_cap sta_ht_cap;
-       bool have_sta = false, is_override = false;
+       bool have_sta = false;
        int err;
 
        sband = local->hw.wiphy->bands[cbss->channel->band];
@@ -4335,14 +4335,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                        return -ENOMEM;
        }
 
-       memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
-       ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
-
-       is_override = (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) !=
-                     (sband->ht_cap.cap &
-                      IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
-       if (new_sta || is_override) {
+       if (new_sta || override) {
                err = ieee80211_prep_channel(sdata, cbss);
                if (err) {
                        if (new_sta)
@@ -4552,7 +4545,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
 
        sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
 
-       err = ieee80211_prep_connection(sdata, req->bss, false);
+       err = ieee80211_prep_connection(sdata, req->bss, false, false);
        if (err)
                goto err_clear;
 
@@ -4624,6 +4617,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_supported_band *sband;
        const u8 *ssidie, *ht_ie, *vht_ie;
        int i, err;
+       bool override = false;
 
        assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL);
        if (!assoc_data)
@@ -4728,14 +4722,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       if (req->flags & ASSOC_REQ_DISABLE_HT) {
-               ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
-               ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
-       }
-
-       if (req->flags & ASSOC_REQ_DISABLE_VHT)
-               ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
-
        /* Also disable HT if we don't support it or the AP doesn't use WMM */
        sband = local->hw.wiphy->bands[req->bss->channel->band];
        if (!sband->ht_cap.ht_supported ||
@@ -4847,7 +4833,36 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        ifmgd->dtim_period = 0;
        ifmgd->have_beacon = false;
 
-       err = ieee80211_prep_connection(sdata, req->bss, true);
+       /* override HT/VHT configuration only if the AP and we support it */
+       if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+               struct ieee80211_sta_ht_cap sta_ht_cap;
+
+               if (req->flags & ASSOC_REQ_DISABLE_HT)
+                       override = true;
+
+               memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
+               ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
+
+               /* check for 40 MHz disable override */
+               if (!(ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ) &&
+                   sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
+                   !(sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+                       override = true;
+
+               if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
+                   req->flags & ASSOC_REQ_DISABLE_VHT)
+                       override = true;
+       }
+
+       if (req->flags & ASSOC_REQ_DISABLE_HT) {
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
+               ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+       }
+
+       if (req->flags & ASSOC_REQ_DISABLE_VHT)
+               ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+
+       err = ieee80211_prep_connection(sdata, req->bss, true, override);
        if (err)
                goto err_clear;
 
index d53355b..de69adf 100644 (file)
@@ -683,7 +683,13 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
        if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
                return;
 
-       ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
+       if (ista) {
+               spin_lock_bh(&sta->rate_ctrl_lock);
+               ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
+               spin_unlock_bh(&sta->rate_ctrl_lock);
+       } else {
+               ref->ops->get_rate(ref->priv, NULL, NULL, txrc);
+       }
 
        if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
                return;
index 38652f0..25c9be5 100644 (file)
@@ -42,10 +42,12 @@ static inline void rate_control_tx_status(struct ieee80211_local *local,
        if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
                return;
 
+       spin_lock_bh(&sta->rate_ctrl_lock);
        if (ref->ops->tx_status)
                ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
        else
                ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
+       spin_unlock_bh(&sta->rate_ctrl_lock);
 }
 
 static inline void
@@ -64,7 +66,9 @@ rate_control_tx_status_noskb(struct ieee80211_local *local,
        if (WARN_ON_ONCE(!ref->ops->tx_status_noskb))
                return;
 
+       spin_lock_bh(&sta->rate_ctrl_lock);
        ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
+       spin_unlock_bh(&sta->rate_ctrl_lock);
 }
 
 static inline void rate_control_rate_init(struct sta_info *sta)
@@ -91,8 +95,10 @@ static inline void rate_control_rate_init(struct sta_info *sta)
 
        sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
 
+       spin_lock_bh(&sta->rate_ctrl_lock);
        ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
                            priv_sta);
+       spin_unlock_bh(&sta->rate_ctrl_lock);
        rcu_read_unlock();
        set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
 }
@@ -115,18 +121,20 @@ static inline void rate_control_rate_update(struct ieee80211_local *local,
                        return;
                }
 
+               spin_lock_bh(&sta->rate_ctrl_lock);
                ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def,
                                      ista, priv_sta, changed);
+               spin_unlock_bh(&sta->rate_ctrl_lock);
                rcu_read_unlock();
        }
        drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
 }
 
 static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
-                                          struct ieee80211_sta *sta,
-                                          gfp_t gfp)
+                                          struct sta_info *sta, gfp_t gfp)
 {
-       return ref->ops->alloc_sta(ref->priv, sta, gfp);
+       spin_lock_init(&sta->rate_ctrl_lock);
+       return ref->ops->alloc_sta(ref->priv, &sta->sta, gfp);
 }
 
 static inline void rate_control_free_sta(struct sta_info *sta)
index 260eed4..aa35977 100644 (file)
 #include "wme.h"
 #include "rate.h"
 
+static inline void ieee80211_rx_stats(struct net_device *dev, u32 len)
+{
+       struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
+
+       u64_stats_update_begin(&tstats->syncp);
+       tstats->rx_packets++;
+       tstats->rx_bytes += len;
+       u64_stats_update_end(&tstats->syncp);
+}
+
 /*
  * monitor mode reception
  *
@@ -529,8 +539,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                }
 
                prev_dev = sdata->dev;
-               sdata->dev->stats.rx_packets++;
-               sdata->dev->stats.rx_bytes += skb->len;
+               ieee80211_rx_stats(sdata->dev, skb->len);
        }
 
        if (prev_dev) {
@@ -981,7 +990,6 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
        struct sk_buff *skb = rx->skb;
        struct ieee80211_local *local = rx->local;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct sta_info *sta = rx->sta;
        struct tid_ampdu_rx *tid_agg_rx;
        u16 sc;
@@ -1016,10 +1024,6 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
            ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
                goto dont_reorder;
 
-       /* not actually part of this BA session */
-       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
-               goto dont_reorder;
-
        /* new, potentially un-ordered, ampdu frame - process it */
 
        /* reset session timer */
@@ -1073,10 +1077,8 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
                if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
                             rx->sta->last_seq_ctrl[rx->seqno_idx] ==
                             hdr->seq_ctrl)) {
-                       if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
-                               rx->local->dot11FrameDuplicateCount++;
-                               rx->sta->num_duplicates++;
-                       }
+                       I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount);
+                       rx->sta->num_duplicates++;
                        return RX_DROP_UNUSABLE;
                } else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
                        rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
@@ -1200,6 +1202,8 @@ static void sta_ps_start(struct sta_info *sta)
        ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
               sta->sta.addr, sta->sta.aid);
 
+       ieee80211_clear_fast_xmit(sta);
+
        if (!sta->sta.txq[0])
                return;
 
@@ -1265,7 +1269,7 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
        int tid, ac;
 
-       if (!rx->sta || !(status->rx_flags & IEEE80211_RX_RA_MATCH))
+       if (!rx->sta)
                return RX_CONTINUE;
 
        if (sdata->vif.type != NL80211_IFTYPE_AP &&
@@ -1367,11 +1371,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                        }
                }
        } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
-               u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
-                                               NL80211_IFTYPE_OCB);
-               /* OCB uses wild-card BSSID */
-               if (is_broadcast_ether_addr(bssid))
-                       sta->last_rx = jiffies;
+               sta->last_rx = jiffies;
        } else if (!is_multicast_ether_addr(hdr->addr1)) {
                /*
                 * Mesh beacons will update last_rx when if they are found to
@@ -1386,9 +1386,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                }
        }
 
-       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
-               return RX_CONTINUE;
-
        if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
                ieee80211_sta_rx_notify(rx->sdata, hdr);
 
@@ -1517,13 +1514,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
         * possible.
         */
 
-       /*
-        * No point in finding a key and decrypting if the frame is neither
-        * addressed to us nor a multicast frame.
-        */
-       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
-               return RX_CONTINUE;
-
        /* start without a key */
        rx->key = NULL;
        fc = hdr->frame_control;
@@ -1795,7 +1785,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        frag = sc & IEEE80211_SCTL_FRAG;
 
        if (is_multicast_ether_addr(hdr->addr1)) {
-               rx->local->dot11MulticastReceivedFrameCount++;
+               I802_DEBUG_INC(rx->local->dot11MulticastReceivedFrameCount);
                goto out_no_led;
        }
 
@@ -1878,7 +1868,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 
        rx->skb = __skb_dequeue(&entry->skb_list);
        if (skb_tailroom(rx->skb) < entry->extra_len) {
-               I802_DEBUG_INC(rx->local->rx_expand_skb_head2);
+               I802_DEBUG_INC(rx->local->rx_expand_skb_head_defrag);
                if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
                                              GFP_ATOMIC))) {
                        I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
@@ -2054,18 +2044,15 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
        struct sk_buff *skb, *xmit_skb;
        struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
        struct sta_info *dsta;
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
-
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += rx->skb->len;
 
        skb = rx->skb;
        xmit_skb = NULL;
 
+       ieee80211_rx_stats(dev, skb->len);
+
        if ((sdata->vif.type == NL80211_IFTYPE_AP ||
             sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
            !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
-           (status->rx_flags & IEEE80211_RX_RA_MATCH) &&
            (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
                if (is_multicast_ether_addr(ehdr->h_dest)) {
                        /*
@@ -2206,7 +2193,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        struct sk_buff *skb = rx->skb, *fwd_skb;
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        u16 q, hdrlen;
 
@@ -2237,8 +2223,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr))
                return RX_DROP_MONITOR;
 
-       if (!ieee80211_is_data(hdr->frame_control) ||
-           !(status->rx_flags & IEEE80211_RX_RA_MATCH))
+       if (!ieee80211_is_data(hdr->frame_control))
                return RX_CONTINUE;
 
        if (!mesh_hdr->ttl)
@@ -2329,11 +2314,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
        ieee80211_add_pending_skb(local, fwd_skb);
  out:
-       if (is_multicast_ether_addr(hdr->addr1) ||
-           sdata->dev->flags & IFF_PROMISC)
+       if (is_multicast_ether_addr(hdr->addr1))
                return RX_CONTINUE;
-       else
-               return RX_DROP_MONITOR;
+       return RX_DROP_MONITOR;
 }
 #endif
 
@@ -2444,6 +2427,9 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
                struct {
                        __le16 control, start_seq_num;
                } __packed bar_data;
+               struct ieee80211_event event = {
+                       .type = BAR_RX_EVENT,
+               };
 
                if (!rx->sta)
                        return RX_DROP_MONITOR;
@@ -2459,6 +2445,9 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
                        return RX_DROP_MONITOR;
 
                start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
+               event.u.ba.tid = tid;
+               event.u.ba.ssn = start_seq_num;
+               event.u.ba.sta = &rx->sta->sta;
 
                /* reset session timer */
                if (tid_agg_rx->timeout)
@@ -2471,6 +2460,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
                                                 start_seq_num, frames);
                spin_unlock(&tid_agg_rx->reorder_lock);
 
+               drv_event_callback(rx->local, rx->sdata, &event);
+
                kfree_skb(skb);
                return RX_QUEUED;
        }
@@ -2560,9 +2551,6 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
                rx->flags |= IEEE80211_RX_BEACON_REPORTED;
        }
 
-       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
-               return RX_DROP_MONITOR;
-
        if (ieee80211_drop_unencrypted_mgmt(rx))
                return RX_DROP_UNUSABLE;
 
@@ -2590,9 +2578,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
            mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
                return RX_DROP_UNUSABLE;
 
-       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
-               return RX_DROP_UNUSABLE;
-
        switch (mgmt->u.action.category) {
        case WLAN_CATEGORY_HT:
                /* reject HT action frames from stations not supporting HT */
@@ -3076,8 +3061,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                }
 
                prev_dev = sdata->dev;
-               sdata->dev->stats.rx_packets++;
-               sdata->dev->stats.rx_bytes += skb->len;
+               ieee80211_rx_stats(sdata->dev, skb->len);
        }
 
        if (prev_dev) {
@@ -3245,16 +3229,25 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
        ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
        spin_unlock(&tid_agg_rx->reorder_lock);
 
+       if (!skb_queue_empty(&frames)) {
+               struct ieee80211_event event = {
+                       .type = BA_FRAME_TIMEOUT,
+                       .u.ba.tid = tid,
+                       .u.ba.sta = &sta->sta,
+               };
+               drv_event_callback(rx.local, rx.sdata, &event);
+       }
+
        ieee80211_rx_handlers(&rx, &frames);
 }
 
 /* main receive path */
 
-static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
-                                struct ieee80211_hdr *hdr)
+static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct sk_buff *skb = rx->skb;
+       struct ieee80211_hdr *hdr = (void *)skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
        int multicast = is_multicast_ether_addr(hdr->addr1);
@@ -3263,30 +3256,23 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
        case NL80211_IFTYPE_STATION:
                if (!bssid && !sdata->u.mgd.use_4addr)
                        return false;
-               if (!multicast &&
-                   !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
-                       if (!(sdata->dev->flags & IFF_PROMISC) ||
-                           sdata->u.mgd.use_4addr)
-                               return false;
-                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
-               }
-               break;
+               if (multicast)
+                       return true;
+               return ether_addr_equal(sdata->vif.addr, hdr->addr1);
        case NL80211_IFTYPE_ADHOC:
                if (!bssid)
                        return false;
                if (ether_addr_equal(sdata->vif.addr, hdr->addr2) ||
                    ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2))
                        return false;
-               if (ieee80211_is_beacon(hdr->frame_control)) {
+               if (ieee80211_is_beacon(hdr->frame_control))
                        return true;
-               } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
+               if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid))
                        return false;
-               } else if (!multicast &&
-                          !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
-                       if (!(sdata->dev->flags & IFF_PROMISC))
-                               return false;
-                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
-               } else if (!rx->sta) {
+               if (!multicast &&
+                   !ether_addr_equal(sdata->vif.addr, hdr->addr1))
+                       return false;
+               if (!rx->sta) {
                        int rate_idx;
                        if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
                                rate_idx = 0; /* TODO: HT/VHT rates */
@@ -3295,25 +3281,18 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
                        ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
                                                 BIT(rate_idx));
                }
-               break;
+               return true;
        case NL80211_IFTYPE_OCB:
                if (!bssid)
                        return false;
-               if (ieee80211_is_beacon(hdr->frame_control)) {
+               if (ieee80211_is_beacon(hdr->frame_control))
                        return false;
-               } else if (!is_broadcast_ether_addr(bssid)) {
-                       ocb_dbg(sdata, "BSSID mismatch in OCB mode!\n");
+               if (!is_broadcast_ether_addr(bssid))
                        return false;
-               } else if (!multicast &&
-                          !ether_addr_equal(sdata->dev->dev_addr,
-                                            hdr->addr1)) {
-                       /* if we are in promisc mode we also accept
-                        * packets not destined for us
-                        */
-                       if (!(sdata->dev->flags & IFF_PROMISC))
-                               return false;
-                       rx->flags &= ~IEEE80211_RX_RA_MATCH;
-               } else if (!rx->sta) {
+               if (!multicast &&
+                   !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1))
+                       return false;
+               if (!rx->sta) {
                        int rate_idx;
                        if (status->flag & RX_FLAG_HT)
                                rate_idx = 0; /* TODO: HT rates */
@@ -3322,22 +3301,17 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
                        ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2,
                                                BIT(rate_idx));
                }
-               break;
+               return true;
        case NL80211_IFTYPE_MESH_POINT:
-               if (!multicast &&
-                   !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
-                       if (!(sdata->dev->flags & IFF_PROMISC))
-                               return false;
-
-                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
-               }
-               break;
+               if (multicast)
+                       return true;
+               return ether_addr_equal(sdata->vif.addr, hdr->addr1);
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_AP:
-               if (!bssid) {
-                       if (!ether_addr_equal(sdata->vif.addr, hdr->addr1))
-                               return false;
-               } else if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) {
+               if (!bssid)
+                       return ether_addr_equal(sdata->vif.addr, hdr->addr1);
+
+               if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) {
                        /*
                         * Accept public action frames even when the
                         * BSSID doesn't match, this is used for P2P
@@ -3349,10 +3323,10 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
                                return false;
                        if (ieee80211_is_public_action(hdr, skb->len))
                                return true;
-                       if (!ieee80211_is_beacon(hdr->frame_control))
-                               return false;
-                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
-               } else if (!ieee80211_has_tods(hdr->frame_control)) {
+                       return ieee80211_is_beacon(hdr->frame_control);
+               }
+
+               if (!ieee80211_has_tods(hdr->frame_control)) {
                        /* ignore data frames to TDLS-peers */
                        if (ieee80211_is_data(hdr->frame_control))
                                return false;
@@ -3361,30 +3335,22 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
                            !ether_addr_equal(bssid, hdr->addr1))
                                return false;
                }
-               break;
+               return true;
        case NL80211_IFTYPE_WDS:
                if (bssid || !ieee80211_is_data(hdr->frame_control))
                        return false;
-               if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2))
-                       return false;
-               break;
+               return ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2);
        case NL80211_IFTYPE_P2P_DEVICE:
-               if (!ieee80211_is_public_action(hdr, skb->len) &&
-                   !ieee80211_is_probe_req(hdr->frame_control) &&
-                   !ieee80211_is_probe_resp(hdr->frame_control) &&
-                   !ieee80211_is_beacon(hdr->frame_control))
-                       return false;
-               if (!ether_addr_equal(sdata->vif.addr, hdr->addr1) &&
-                   !multicast)
-                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
-               break;
+               return ieee80211_is_public_action(hdr, skb->len) ||
+                      ieee80211_is_probe_req(hdr->frame_control) ||
+                      ieee80211_is_probe_resp(hdr->frame_control) ||
+                      ieee80211_is_beacon(hdr->frame_control);
        default:
-               /* should never get here */
-               WARN_ON_ONCE(1);
                break;
        }
 
-       return true;
+       WARN_ON_ONCE(1);
+       return false;
 }
 
 /*
@@ -3398,13 +3364,10 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
 {
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-       struct ieee80211_hdr *hdr = (void *)skb->data;
 
        rx->skb = skb;
-       status->rx_flags |= IEEE80211_RX_RA_MATCH;
 
-       if (!prepare_for_handlers(rx, hdr))
+       if (!ieee80211_accept_frame(rx))
                return false;
 
        if (!consume) {
@@ -3447,7 +3410,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        rx.local = local;
 
        if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
-               local->dot11ReceivedFragmentCount++;
+               I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
 
        if (ieee80211_is_mgmt(fc)) {
                /* drop frame if too short for header */
index 12971b7..aec15d7 100644 (file)
@@ -70,6 +70,7 @@ static const struct rhashtable_params sta_rht_params = {
        .key_offset = offsetof(struct sta_info, sta.addr),
        .key_len = ETH_ALEN,
        .hashfn = sta_addr_hash,
+       .max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE,
 };
 
 /* Caller must hold local->sta_mtx */
@@ -269,7 +270,7 @@ static int sta_prepare_rate_control(struct ieee80211_local *local,
 
        sta->rate_ctrl = local->rate_ctrl;
        sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
-                                                    &sta->sta, gfp);
+                                                    sta, gfp);
        if (!sta->rate_ctrl_priv)
                return -ENOMEM;
 
@@ -295,6 +296,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
        mutex_init(&sta->ampdu_mlme.mtx);
 #ifdef CONFIG_MAC80211_MESH
+       spin_lock_init(&sta->plink_lock);
        if (ieee80211_vif_is_mesh(&sdata->vif) &&
            !sdata->u.mesh.user_mpm)
                init_timer(&sta->plink_timer);
@@ -1200,6 +1202,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
        ps_dbg(sdata,
               "STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n",
               sta->sta.addr, sta->sta.aid, filtered, buffered);
+
+       ieee80211_check_fast_xmit(sta);
 }
 
 static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
@@ -1598,6 +1602,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
 
        if (block) {
                set_sta_flag(sta, WLAN_STA_PS_DRIVER);
+               ieee80211_clear_fast_xmit(sta);
                return;
        }
 
@@ -1615,6 +1620,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
                ieee80211_queue_work(hw, &sta->drv_deliver_wk);
        } else {
                clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+               ieee80211_check_fast_xmit(sta);
        }
 }
 EXPORT_SYMBOL(ieee80211_sta_block_awake);
@@ -1719,6 +1725,7 @@ int sta_info_move_state(struct sta_info *sta,
                             !sta->sdata->u.vlan.sta))
                                atomic_dec(&sta->sdata->bss->num_mcast_sta);
                        clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
+                       ieee80211_clear_fast_xmit(sta);
                }
                break;
        case IEEE80211_STA_AUTHORIZED:
@@ -1728,6 +1735,7 @@ int sta_info_move_state(struct sta_info *sta,
                             !sta->sdata->u.vlan.sta))
                                atomic_inc(&sta->sdata->bss->num_mcast_sta);
                        set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
+                       ieee80211_check_fast_xmit(sta);
                }
                break;
        default:
index 5c164fb..9bd1e97 100644 (file)
@@ -241,6 +241,34 @@ struct sta_ampdu_mlme {
 /* Value to indicate no TID reservation */
 #define IEEE80211_TID_UNRESERVED       0xff
 
+#define IEEE80211_FAST_XMIT_MAX_IV     18
+
+/**
+ * struct ieee80211_fast_tx - TX fastpath information
+ * @key: key to use for hw crypto
+ * @hdr: the 802.11 header to put with the frame
+ * @hdr_len: actual 802.11 header length
+ * @sa_offs: offset of the SA
+ * @da_offs: offset of the DA
+ * @pn_offs: offset where to put PN for crypto (or 0 if not needed)
+ * @band: band this will be transmitted on, for tx_info
+ * @rcu_head: RCU head to free this struct
+ *
+ * This struct is small enough so that the common case (maximum crypto
+ * header length of 8 like for CCMP/GCMP) fits into a single 64-byte
+ * cache line.
+ */
+struct ieee80211_fast_tx {
+       struct ieee80211_key *key;
+       u8 hdr_len;
+       u8 sa_offs, da_offs, pn_offs;
+       u8 band;
+       u8 hdr[30 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
+              sizeof(rfc1042_header)];
+
+       struct rcu_head rcu_head;
+};
+
 /**
  * struct sta_info - STA information
  *
@@ -257,6 +285,8 @@ struct sta_ampdu_mlme {
  * @gtk: group keys negotiated with this station, if any
  * @gtk_idx: last installed group key index
  * @rate_ctrl: rate control algorithm reference
+ * @rate_ctrl_lock: spinlock used to protect rate control data
+ *     (data inside the algorithm, so serializes calls there)
  * @rate_ctrl_priv: rate control private per-STA pointer
  * @last_tx_rate: rate used for last transmit, to report to userspace as
  *     "the" transmit rate
@@ -295,10 +325,10 @@ struct sta_ampdu_mlme {
  * @fail_avg: moving percentage of failed MSDUs
  * @tx_packets: number of RX/TX MSDUs
  * @tx_bytes: number of bytes transmitted to this STA
- * @tx_fragments: number of transmitted MPDUs
  * @tid_seq: per-TID sequence numbers for sending to this STA
  * @ampdu_mlme: A-MPDU state machine state
  * @timer_to_tid: identity mapping to ID timers
+ * @plink_lock: serialize access to plink fields
  * @llid: Local link ID
  * @plid: Peer link ID
  * @reason: Cancel reason on PLINK_HOLDING state
@@ -338,6 +368,7 @@ struct sta_ampdu_mlme {
  *     using IEEE80211_NUM_TID entry for non-QoS frames
  * @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID
  *     entry for non-QoS frames
+ * @fast_tx: TX fastpath information
  */
 struct sta_info {
        /* General information, mostly static */
@@ -352,8 +383,11 @@ struct sta_info {
        u8 ptk_idx;
        struct rate_control_ref *rate_ctrl;
        void *rate_ctrl_priv;
+       spinlock_t rate_ctrl_lock;
        spinlock_t lock;
 
+       struct ieee80211_fast_tx __rcu *fast_tx;
+
        struct work_struct drv_deliver_wk;
 
        u16 listen_interval;
@@ -400,7 +434,6 @@ struct sta_info {
        unsigned int fail_avg;
 
        /* Updated from TX path only, no locking requirements */
-       u32 tx_fragments;
        u64 tx_packets[IEEE80211_NUM_ACS];
        u64 tx_bytes[IEEE80211_NUM_ACS];
        struct ieee80211_tx_rate last_tx_rate;
@@ -422,9 +455,10 @@ struct sta_info {
 
 #ifdef CONFIG_MAC80211_MESH
        /*
-        * Mesh peer link attributes
+        * Mesh peer link attributes, protected by plink_lock.
         * TODO: move to a sub-structure that is referenced with pointer?
         */
+       spinlock_t plink_lock;
        u16 llid;
        u16 plid;
        u16 reason;
@@ -432,6 +466,7 @@ struct sta_info {
        enum nl80211_plink_state plink_state;
        u32 plink_timeout;
        struct timer_list plink_timer;
+
        s64 t_offset;
        s64 t_offset_setpoint;
        /* mesh power save */
index 005fdbe..4615949 100644 (file)
@@ -631,15 +631,15 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
        }
 
        if (acked || noack_success) {
-                   local->dot11TransmittedFrameCount++;
-                   if (!pubsta)
-                           local->dot11MulticastTransmittedFrameCount++;
-                   if (retry_count > 0)
-                           local->dot11RetryCount++;
-                   if (retry_count > 1)
-                           local->dot11MultipleRetryCount++;
+               I802_DEBUG_INC(local->dot11TransmittedFrameCount);
+               if (!pubsta)
+                       I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
+               if (retry_count > 0)
+                       I802_DEBUG_INC(local->dot11RetryCount);
+               if (retry_count > 1)
+                       I802_DEBUG_INC(local->dot11MultipleRetryCount);
        } else {
-               local->dot11FailedCount++;
+               I802_DEBUG_INC(local->dot11FailedCount);
        }
 }
 EXPORT_SYMBOL(ieee80211_tx_status_noskb);
@@ -802,13 +802,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        if ((info->flags & IEEE80211_TX_STAT_ACK) ||
            (info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) {
                if (ieee80211_is_first_frag(hdr->seq_ctrl)) {
-                       local->dot11TransmittedFrameCount++;
+                       I802_DEBUG_INC(local->dot11TransmittedFrameCount);
                        if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
-                               local->dot11MulticastTransmittedFrameCount++;
+                               I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
                        if (retry_count > 0)
-                               local->dot11RetryCount++;
+                               I802_DEBUG_INC(local->dot11RetryCount);
                        if (retry_count > 1)
-                               local->dot11MultipleRetryCount++;
+                               I802_DEBUG_INC(local->dot11MultipleRetryCount);
                }
 
                /* This counter shall be incremented for an acknowledged MPDU
@@ -818,10 +818,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                if (!is_multicast_ether_addr(hdr->addr1) ||
                    ieee80211_is_data(fc) ||
                    ieee80211_is_mgmt(fc))
-                       local->dot11TransmittedFragmentCount++;
+                       I802_DEBUG_INC(local->dot11TransmittedFragmentCount);
        } else {
                if (ieee80211_is_first_frag(hdr->seq_ctrl))
-                       local->dot11FailedCount++;
+                       I802_DEBUG_INC(local->dot11FailedCount);
        }
 
        if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) &&
index 4c2e769..6f14591 100644 (file)
 #define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG,                             \
                        __entry->rx_chains_static, __entry->rx_chains_dynamic
 
+#define KEY_ENTRY      __field(u32, cipher)                                            \
+                       __field(u8, hw_key_idx)                                         \
+                       __field(u8, flags)                                              \
+                       __field(s8, keyidx)
+#define KEY_ASSIGN(k)  __entry->cipher = (k)->cipher;                                  \
+                       __entry->flags = (k)->flags;                                    \
+                       __entry->keyidx = (k)->keyidx;                                  \
+                       __entry->hw_key_idx = (k)->hw_key_idx;
+#define KEY_PR_FMT     " cipher:0x%x, flags=%#x, keyidx=%d, hw_key_idx=%d"
+#define KEY_PR_ARG     __entry->cipher, __entry->flags, __entry->keyidx, __entry->hw_key_idx
+
 
 
 /*
@@ -522,25 +533,19 @@ TRACE_EVENT(drv_set_key,
                LOCAL_ENTRY
                VIF_ENTRY
                STA_ENTRY
-               __field(u32, cipher)
-               __field(u8, hw_key_idx)
-               __field(u8, flags)
-               __field(s8, keyidx)
+               KEY_ENTRY
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
                VIF_ASSIGN;
                STA_ASSIGN;
-               __entry->cipher = key->cipher;
-               __entry->flags = key->flags;
-               __entry->keyidx = key->keyidx;
-               __entry->hw_key_idx = key->hw_key_idx;
+               KEY_ASSIGN(key);
        ),
 
        TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT,
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG
+               LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT KEY_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, KEY_PR_ARG
        )
 );
 
@@ -656,28 +661,25 @@ TRACE_EVENT(drv_get_stats,
        )
 );
 
-TRACE_EVENT(drv_get_tkip_seq,
+TRACE_EVENT(drv_get_key_seq,
        TP_PROTO(struct ieee80211_local *local,
-                u8 hw_key_idx, u32 *iv32, u16 *iv16),
+                struct ieee80211_key_conf *key),
 
-       TP_ARGS(local, hw_key_idx, iv32, iv16),
+       TP_ARGS(local, key),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
-               __field(u8, hw_key_idx)
-               __field(u32, iv32)
-               __field(u16, iv16)
+               KEY_ENTRY
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
-               __entry->hw_key_idx = hw_key_idx;
-               __entry->iv32 = *iv32;
-               __entry->iv16 = *iv16;
+               KEY_ASSIGN(key);
        ),
 
        TP_printk(
-               LOCAL_PR_FMT, LOCAL_PR_ARG
+               LOCAL_PR_FMT KEY_PR_FMT,
+               LOCAL_PR_ARG, KEY_PR_ARG
        )
 );
 
index 667111e..8df1342 100644 (file)
 
 /* misc utils */
 
+static inline void ieee80211_tx_stats(struct net_device *dev, u32 len)
+{
+       struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
+
+       u64_stats_update_begin(&tstats->syncp);
+       tstats->tx_packets++;
+       tstats->tx_bytes += len;
+       u64_stats_update_end(&tstats->syncp);
+}
+
 static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
                                 struct sk_buff *skb, int group_addr,
                                 int next_frag_len)
@@ -987,7 +997,6 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
 
        skb_queue_walk(&tx->skbs, skb) {
                ac = skb_get_queue_mapping(skb);
-               tx->sta->tx_fragments++;
                tx->sta->tx_bytes[ac] += skb->len;
        }
        if (ac >= 0)
@@ -1600,7 +1609,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
        if (skb_cloned(skb) &&
            (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CLONED_SKBS) ||
             !skb_clone_writable(skb, ETH_HLEN) ||
-            sdata->crypto_tx_tailroom_needed_cnt))
+            (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt)))
                I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
        else if (head_need || tail_need)
                I802_DEBUG_INC(local->tx_expand_skb_head);
@@ -2387,12 +2396,460 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
        return ERR_PTR(ret);
 }
 
+/*
+ * fast-xmit overview
+ *
+ * The core idea of this fast-xmit is to remove per-packet checks by checking
+ * them out of band. ieee80211_check_fast_xmit() implements the out-of-band
+ * checks that are needed to get the sta->fast_tx pointer assigned, after which
+ * much less work can be done per packet. For example, fragmentation must be
+ * disabled or the fast_tx pointer will not be set. All the conditions are seen
+ * in the code here.
+ *
+ * Once assigned, the fast_tx data structure also caches the per-packet 802.11
+ * header and other data to aid packet processing in ieee80211_xmit_fast().
+ *
+ * The most difficult part of this is that when any of these assumptions
+ * change, an external trigger (i.e. a call to ieee80211_clear_fast_xmit(),
+ * ieee80211_check_fast_xmit() or friends) is required to reset the data,
+ * since the per-packet code no longer checks the conditions. This is reflected
+ * by the calls to these functions throughout the rest of the code, and must be
+ * maintained if any of the TX path checks change.
+ */
+
+void ieee80211_check_fast_xmit(struct sta_info *sta)
+{
+       struct ieee80211_fast_tx build = {}, *fast_tx = NULL, *old;
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_hdr *hdr = (void *)build.hdr;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       __le16 fc;
+
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORT_FAST_XMIT))
+               return;
+
+       /* Locking here protects both the pointer itself, and against concurrent
+        * invocations winning data access races to, e.g., the key pointer that
+        * is used.
+        * Without it, the invocation of this function right after the key
+        * pointer changes wouldn't be sufficient, as another CPU could access
+        * the pointer, then stall, and then do the cache update after the CPU
+        * that invalidated the key.
+        * With the locking, such scenarios cannot happen as the check for the
+        * key and the fast-tx assignment are done atomically, so the CPU that
+        * modifies the key will either wait or other one will see the key
+        * cleared/changed already.
+        */
+       spin_lock_bh(&sta->lock);
+       if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS &&
+           !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) &&
+           sdata->vif.type == NL80211_IFTYPE_STATION)
+               goto out;
+
+       if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+               goto out;
+
+       if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
+           test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
+           test_sta_flag(sta, WLAN_STA_PS_DELIVER))
+               goto out;
+
+       if (sdata->noack_map)
+               goto out;
+
+       /* fast-xmit doesn't handle fragmentation at all */
+       if (local->hw.wiphy->frag_threshold != (u32)-1 &&
+           !local->ops->set_frag_threshold)
+               goto out;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (!chanctx_conf) {
+               rcu_read_unlock();
+               goto out;
+       }
+       build.band = chanctx_conf->def.chan->band;
+       rcu_read_unlock();
+
+       fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
+
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_ADHOC:
+               /* DA SA BSSID */
+               build.da_offs = offsetof(struct ieee80211_hdr, addr1);
+               build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
+               memcpy(hdr->addr3, sdata->u.ibss.bssid, ETH_ALEN);
+               build.hdr_len = 24;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+                       /* DA SA BSSID */
+                       build.da_offs = offsetof(struct ieee80211_hdr, addr1);
+                       build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
+                       memcpy(hdr->addr3, sdata->u.mgd.bssid, ETH_ALEN);
+                       build.hdr_len = 24;
+                       break;
+               }
+
+               if (sdata->u.mgd.use_4addr) {
+                       /* non-regular ethertype cannot use the fastpath */
+                       fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
+                                         IEEE80211_FCTL_TODS);
+                       /* RA TA DA SA */
+                       memcpy(hdr->addr1, sdata->u.mgd.bssid, ETH_ALEN);
+                       memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
+                       build.da_offs = offsetof(struct ieee80211_hdr, addr3);
+                       build.sa_offs = offsetof(struct ieee80211_hdr, addr4);
+                       build.hdr_len = 30;
+                       break;
+               }
+               fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
+               /* BSSID SA DA */
+               memcpy(hdr->addr1, sdata->u.mgd.bssid, ETH_ALEN);
+               build.da_offs = offsetof(struct ieee80211_hdr, addr3);
+               build.sa_offs = offsetof(struct ieee80211_hdr, addr2);
+               build.hdr_len = 24;
+               break;
+       case NL80211_IFTYPE_AP_VLAN:
+               if (sdata->wdev.use_4addr) {
+                       fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
+                                         IEEE80211_FCTL_TODS);
+                       /* RA TA DA SA */
+                       memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
+                       memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
+                       build.da_offs = offsetof(struct ieee80211_hdr, addr3);
+                       build.sa_offs = offsetof(struct ieee80211_hdr, addr4);
+                       build.hdr_len = 30;
+                       break;
+               }
+               /* fall through */
+       case NL80211_IFTYPE_AP:
+               fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+               /* DA BSSID SA */
+               build.da_offs = offsetof(struct ieee80211_hdr, addr1);
+               memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
+               build.sa_offs = offsetof(struct ieee80211_hdr, addr3);
+               build.hdr_len = 24;
+               break;
+       default:
+               /* not handled on fast-xmit */
+               goto out;
+       }
+
+       if (sta->sta.wme) {
+               build.hdr_len += 2;
+               fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+       }
+
+       /* We store the key here so there's no point in using rcu_dereference()
+        * but that's fine because the code that changes the pointers will call
+        * this function after doing so. For a single CPU that would be enough,
+        * for multiple see the comment above.
+        */
+       build.key = rcu_access_pointer(sta->ptk[sta->ptk_idx]);
+       if (!build.key)
+               build.key = rcu_access_pointer(sdata->default_unicast_key);
+       if (build.key) {
+               bool gen_iv, iv_spc, mmic;
+
+               gen_iv = build.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV;
+               iv_spc = build.key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE;
+               mmic = build.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC;
+
+               /* don't handle software crypto */
+               if (!(build.key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+                       goto out;
+
+               switch (build.key->conf.cipher) {
+               case WLAN_CIPHER_SUITE_CCMP:
+               case WLAN_CIPHER_SUITE_CCMP_256:
+                       /* add fixed key ID */
+                       if (gen_iv) {
+                               (build.hdr + build.hdr_len)[3] =
+                                       0x20 | (build.key->conf.keyidx << 6);
+                               build.pn_offs = build.hdr_len;
+                       }
+                       if (gen_iv || iv_spc)
+                               build.hdr_len += IEEE80211_CCMP_HDR_LEN;
+                       break;
+               case WLAN_CIPHER_SUITE_GCMP:
+               case WLAN_CIPHER_SUITE_GCMP_256:
+                       /* add fixed key ID */
+                       if (gen_iv) {
+                               (build.hdr + build.hdr_len)[3] =
+                                       0x20 | (build.key->conf.keyidx << 6);
+                               build.pn_offs = build.hdr_len;
+                       }
+                       if (gen_iv || iv_spc)
+                               build.hdr_len += IEEE80211_GCMP_HDR_LEN;
+                       break;
+               case WLAN_CIPHER_SUITE_TKIP:
+                       /* cannot handle MMIC or IV generation in xmit-fast */
+                       if (mmic || gen_iv)
+                               goto out;
+                       if (iv_spc)
+                               build.hdr_len += IEEE80211_TKIP_IV_LEN;
+                       break;
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
+                       /* cannot handle IV generation in fast-xmit */
+                       if (gen_iv)
+                               goto out;
+                       if (iv_spc)
+                               build.hdr_len += IEEE80211_WEP_IV_LEN;
+                       break;
+               case WLAN_CIPHER_SUITE_AES_CMAC:
+               case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+               case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+               case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+                       WARN(1,
+                            "management cipher suite 0x%x enabled for data\n",
+                            build.key->conf.cipher);
+                       goto out;
+               default:
+                       /* we don't know how to generate IVs for this at all */
+                       if (WARN_ON(gen_iv))
+                               goto out;
+                       /* pure hardware keys are OK, of course */
+                       if (!(build.key->flags & KEY_FLAG_CIPHER_SCHEME))
+                               break;
+                       /* cipher scheme might require space allocation */
+                       if (iv_spc &&
+                           build.key->conf.iv_len > IEEE80211_FAST_XMIT_MAX_IV)
+                               goto out;
+                       if (iv_spc)
+                               build.hdr_len += build.key->conf.iv_len;
+               }
+
+               fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+       }
+
+       hdr->frame_control = fc;
+
+       memcpy(build.hdr + build.hdr_len,
+              rfc1042_header,  sizeof(rfc1042_header));
+       build.hdr_len += sizeof(rfc1042_header);
+
+       fast_tx = kmemdup(&build, sizeof(build), GFP_ATOMIC);
+       /* if the kmemdup fails, continue w/o fast_tx */
+       if (!fast_tx)
+               goto out;
+
+ out:
+       /* we might have raced against another call to this function */
+       old = rcu_dereference_protected(sta->fast_tx,
+                                       lockdep_is_held(&sta->lock));
+       rcu_assign_pointer(sta->fast_tx, fast_tx);
+       if (old)
+               kfree_rcu(old, rcu_head);
+       spin_unlock_bh(&sta->lock);
+}
+
+void ieee80211_check_fast_xmit_all(struct ieee80211_local *local)
+{
+       struct sta_info *sta;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sta, &local->sta_list, list)
+               ieee80211_check_fast_xmit(sta);
+       rcu_read_unlock();
+}
+
+void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+               if (sdata != sta->sdata &&
+                   (!sta->sdata->bss || sta->sdata->bss != sdata->bss))
+                       continue;
+               ieee80211_check_fast_xmit(sta);
+       }
+
+       rcu_read_unlock();
+}
+
+void ieee80211_clear_fast_xmit(struct sta_info *sta)
+{
+       struct ieee80211_fast_tx *fast_tx;
+
+       spin_lock_bh(&sta->lock);
+       fast_tx = rcu_dereference_protected(sta->fast_tx,
+                                           lockdep_is_held(&sta->lock));
+       RCU_INIT_POINTER(sta->fast_tx, NULL);
+       spin_unlock_bh(&sta->lock);
+
+       if (fast_tx)
+               kfree_rcu(fast_tx, rcu_head);
+}
+
+static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
+                               struct net_device *dev, struct sta_info *sta,
+                               struct ieee80211_fast_tx *fast_tx,
+                               struct sk_buff *skb)
+{
+       struct ieee80211_local *local = sdata->local;
+       u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+       int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
+       int hw_headroom = sdata->local->hw.extra_tx_headroom;
+       struct ethhdr eth;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
+       struct ieee80211_tx_data tx;
+       ieee80211_tx_result r;
+       struct tid_ampdu_tx *tid_tx = NULL;
+       u8 tid = IEEE80211_NUM_TIDS;
+
+       /* control port protocol needs a lot of special handling */
+       if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
+               return false;
+
+       /* only RFC 1042 SNAP */
+       if (ethertype < ETH_P_802_3_MIN)
+               return false;
+
+       /* don't handle TX status request here either */
+       if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
+               return false;
+
+       if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+               tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+               tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+               if (tid_tx &&
+                   !test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
+                       return false;
+       }
+
+       /* after this point (skb is modified) we cannot return false */
+
+       if (skb_shared(skb)) {
+               struct sk_buff *tmp_skb = skb;
+
+               skb = skb_clone(skb, GFP_ATOMIC);
+               kfree_skb(tmp_skb);
+
+               if (!skb)
+                       return true;
+       }
+
+       ieee80211_tx_stats(dev, skb->len + extra_head);
+
+       /* will not be crypto-handled beyond what we do here, so use false
+        * as the may-encrypt argument for the resize to not account for
+        * more room than we already have in 'extra_head'
+        */
+       if (unlikely(ieee80211_skb_resize(sdata, skb,
+                                         max_t(int, extra_head + hw_headroom -
+                                                    skb_headroom(skb), 0),
+                                         false))) {
+               kfree_skb(skb);
+               return true;
+       }
+
+       memcpy(&eth, skb->data, ETH_HLEN - 2);
+       hdr = (void *)skb_push(skb, extra_head);
+       memcpy(skb->data, fast_tx->hdr, fast_tx->hdr_len);
+       memcpy(skb->data + fast_tx->da_offs, eth.h_dest, ETH_ALEN);
+       memcpy(skb->data + fast_tx->sa_offs, eth.h_source, ETH_ALEN);
+
+       memset(info, 0, sizeof(*info));
+       info->band = fast_tx->band;
+       info->control.vif = &sdata->vif;
+       info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
+                     IEEE80211_TX_CTL_DONTFRAG |
+                     (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
+
+       if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+               *ieee80211_get_qos_ctl(hdr) = tid;
+               hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
+       } else {
+               info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+               hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
+               sdata->sequence_number += 0x10;
+       }
+
+       sta->tx_msdu[tid]++;
+
+       info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
+
+       __skb_queue_head_init(&tx.skbs);
+
+       tx.flags = IEEE80211_TX_UNICAST;
+       tx.local = local;
+       tx.sdata = sdata;
+       tx.sta = sta;
+       tx.key = fast_tx->key;
+
+       if (fast_tx->key)
+               info->control.hw_key = &fast_tx->key->conf;
+
+       if (!(local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) {
+               tx.skb = skb;
+               r = ieee80211_tx_h_rate_ctrl(&tx);
+               skb = tx.skb;
+               tx.skb = NULL;
+
+               if (r != TX_CONTINUE) {
+                       if (r != TX_QUEUED)
+                               kfree_skb(skb);
+                       return true;
+               }
+       }
+
+       /* statistics normally done by ieee80211_tx_h_stats (but that
+        * has to consider fragmentation, so is more complex)
+        */
+       sta->tx_bytes[skb_get_queue_mapping(skb)] += skb->len;
+       sta->tx_packets[skb_get_queue_mapping(skb)]++;
+
+       if (fast_tx->pn_offs) {
+               u64 pn;
+               u8 *crypto_hdr = skb->data + fast_tx->pn_offs;
+
+               switch (fast_tx->key->conf.cipher) {
+               case WLAN_CIPHER_SUITE_CCMP:
+               case WLAN_CIPHER_SUITE_CCMP_256:
+                       pn = atomic64_inc_return(&fast_tx->key->u.ccmp.tx_pn);
+                       crypto_hdr[0] = pn;
+                       crypto_hdr[1] = pn >> 8;
+                       crypto_hdr[4] = pn >> 16;
+                       crypto_hdr[5] = pn >> 24;
+                       crypto_hdr[6] = pn >> 32;
+                       crypto_hdr[7] = pn >> 40;
+                       break;
+               case WLAN_CIPHER_SUITE_GCMP:
+               case WLAN_CIPHER_SUITE_GCMP_256:
+                       pn = atomic64_inc_return(&fast_tx->key->u.gcmp.tx_pn);
+                       crypto_hdr[0] = pn;
+                       crypto_hdr[1] = pn >> 8;
+                       crypto_hdr[4] = pn >> 16;
+                       crypto_hdr[5] = pn >> 24;
+                       crypto_hdr[6] = pn >> 32;
+                       crypto_hdr[7] = pn >> 40;
+                       break;
+               }
+       }
+
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               sdata = container_of(sdata->bss,
+                                    struct ieee80211_sub_if_data, u.ap);
+
+       __skb_queue_tail(&tx.skbs, skb);
+       ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
+       return true;
+}
+
 void __ieee80211_subif_start_xmit(struct sk_buff *skb,
                                  struct net_device *dev,
                                  u32 info_flags)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta;
+       struct sk_buff *next;
 
        if (unlikely(skb->len < ETH_HLEN)) {
                kfree_skb(skb);
@@ -2401,20 +2858,67 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
 
        rcu_read_lock();
 
-       if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
-               kfree_skb(skb);
-               goto out;
+       if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
+               goto out_free;
+
+       if (!IS_ERR_OR_NULL(sta)) {
+               struct ieee80211_fast_tx *fast_tx;
+
+               fast_tx = rcu_dereference(sta->fast_tx);
+
+               if (fast_tx &&
+                   ieee80211_xmit_fast(sdata, dev, sta, fast_tx, skb))
+                       goto out;
        }
 
-       skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
-       if (IS_ERR(skb))
-               goto out;
+       if (skb_is_gso(skb)) {
+               struct sk_buff *segs;
+
+               segs = skb_gso_segment(skb, 0);
+               if (IS_ERR(segs)) {
+                       goto out_free;
+               } else if (segs) {
+                       consume_skb(skb);
+                       skb = segs;
+               }
+       } else {
+               /* we cannot process non-linear frames on this path */
+               if (skb_linearize(skb)) {
+                       kfree_skb(skb);
+                       goto out;
+               }
+
+               /* the frame could be fragmented, software-encrypted, and other
+                * things so we cannot really handle checksum offload with it -
+                * fix it up in software before we handle anything else.
+                */
+               if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       skb_set_transport_header(skb,
+                                                skb_checksum_start_offset(skb));
+                       if (skb_checksum_help(skb))
+                               goto out_free;
+               }
+       }
+
+       next = skb;
+       while (next) {
+               skb = next;
+               next = skb->next;
 
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-       dev->trans_start = jiffies;
+               skb->prev = NULL;
+               skb->next = NULL;
+
+               skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
+               if (IS_ERR(skb))
+                       goto out;
 
-       ieee80211_xmit(sdata, sta, skb);
+               ieee80211_tx_stats(dev, skb->len);
+
+               ieee80211_xmit(sdata, sta, skb);
+       }
+       goto out;
+ out_free:
+       kfree_skb(skb);
  out:
        rcu_read_unlock();
 }
index 7aaf741..915b328 100644 (file)
@@ -698,19 +698,20 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
 EXPORT_SYMBOL(cfg80211_chandef_usable);
 
 /*
- * For GO only, check if the channel can be used under permissive conditions
- * mandated by the some regulatory bodies, i.e., the channel is marked with
- * IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
+ * Check if the channel can be used under permissive conditions mandated by
+ * some regulatory bodies, i.e., the channel is marked with
+ * IEEE80211_CHAN_IR_CONCURRENT and there is an additional station interface
  * associated to an AP on the same channel or on the same UNII band
  * (assuming that the AP is an authorized master).
- * In addition allow the GO to operate on a channel on which indoor operation is
+ * In addition allow operation on a channel on which indoor operation is
  * allowed, iff we are currently operating in an indoor environment.
  */
-static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
+static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
+                                       enum nl80211_iftype iftype,
                                        struct ieee80211_channel *chan)
 {
-       struct wireless_dev *wdev_iter;
-       struct wiphy *wiphy = wiphy_idx_to_wiphy(rdev->wiphy_idx);
+       struct wireless_dev *wdev;
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
        ASSERT_RTNL();
 
@@ -718,32 +719,48 @@ static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
            !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
                return false;
 
+       /* only valid for GO and TDLS off-channel (station/p2p-CL) */
+       if (iftype != NL80211_IFTYPE_P2P_GO &&
+           iftype != NL80211_IFTYPE_STATION &&
+           iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return false;
+
        if (regulatory_indoor_allowed() &&
            (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
                return true;
 
-       if (!(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
+       if (!(chan->flags & IEEE80211_CHAN_IR_CONCURRENT))
                return false;
 
        /*
         * Generally, it is possible to rely on another device/driver to allow
-        * the GO concurrent relaxation, however, since the device can further
+        * the IR concurrent relaxation, however, since the device can further
         * enforce the relaxation (by doing a similar verifications as this),
         * and thus fail the GO instantiation, consider only the interfaces of
         * the current registered device.
         */
-       list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
+       list_for_each_entry(wdev, &rdev->wdev_list, list) {
                struct ieee80211_channel *other_chan = NULL;
                int r1, r2;
 
-               if (wdev_iter->iftype != NL80211_IFTYPE_STATION ||
-                   !netif_running(wdev_iter->netdev))
-                       continue;
-
-               wdev_lock(wdev_iter);
-               if (wdev_iter->current_bss)
-                       other_chan = wdev_iter->current_bss->pub.channel;
-               wdev_unlock(wdev_iter);
+               wdev_lock(wdev);
+               if (wdev->iftype == NL80211_IFTYPE_STATION &&
+                   wdev->current_bss)
+                       other_chan = wdev->current_bss->pub.channel;
+
+               /*
+                * If a GO already operates on the same GO_CONCURRENT channel,
+                * this one (maybe the same one) can beacon as well. We allow
+                * the operation even if the station we relied on with
+                * GO_CONCURRENT is disconnected now. But then we must make sure
+                * we're not outdoor on an indoor-only channel.
+                */
+               if (iftype == NL80211_IFTYPE_P2P_GO &&
+                   wdev->iftype == NL80211_IFTYPE_P2P_GO &&
+                   wdev->beacon_interval &&
+                   !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
+                       other_chan = wdev->chandef.chan;
+               wdev_unlock(wdev);
 
                if (!other_chan)
                        continue;
@@ -784,7 +801,6 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
                             struct cfg80211_chan_def *chandef,
                             enum nl80211_iftype iftype)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        bool res;
        u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
                               IEEE80211_CHAN_RADAR;
@@ -792,13 +808,12 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
        trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
 
        /*
-        * Under certain conditions suggested by the some regulatory bodies
-        * a GO can operate on channels marked with IEEE80211_NO_IR
-        * so set this flag only if such relaxations are not enabled and
-        * the conditions are not met.
+        * Under certain conditions suggested by some regulatory bodies a
+        * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
+        * only if such relaxations are not enabled and the conditions are not
+        * met.
         */
-       if (iftype != NL80211_IFTYPE_P2P_GO ||
-           !cfg80211_go_permissive_chan(rdev, chandef->chan))
+       if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
                prohibited_flags |= IEEE80211_CHAN_NO_IR;
 
        if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
index dd78445..c264eff 100644 (file)
@@ -639,8 +639,8 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
                if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
                    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
                        goto nla_put_failure;
-               if ((chan->flags & IEEE80211_CHAN_GO_CONCURRENT) &&
-                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_GO_CONCURRENT))
+               if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
+                   nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
                        goto nla_put_failure;
                if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
                    nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
@@ -4061,7 +4061,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                        return -EINVAL;
                break;
        case CFG80211_STA_MESH_PEER_USER:
-               if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
+               if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION &&
+                   params->plink_action != NL80211_PLINK_ACTION_BLOCK)
                        return -EINVAL;
                break;
        }
index 0e347f8..d359e06 100644 (file)
@@ -989,8 +989,8 @@ static u32 map_regdom_flags(u32 rd_flags)
                channel_flags |= IEEE80211_CHAN_NO_OFDM;
        if (rd_flags & NL80211_RRF_NO_OUTDOOR)
                channel_flags |= IEEE80211_CHAN_INDOOR_ONLY;
-       if (rd_flags & NL80211_RRF_GO_CONCURRENT)
-               channel_flags |= IEEE80211_CHAN_GO_CONCURRENT;
+       if (rd_flags & NL80211_RRF_IR_CONCURRENT)
+               channel_flags |= IEEE80211_CHAN_IR_CONCURRENT;
        if (rd_flags & NL80211_RRF_NO_HT40MINUS)
                channel_flags |= IEEE80211_CHAN_NO_HT40MINUS;
        if (rd_flags & NL80211_RRF_NO_HT40PLUS)